[*] '/home/ubuntu/Datas/rop-emporium/ret2win/ret2win' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
发现开启了 NX 和 Partial RELRO
NX、Partial RELRO 等是什么?
NX:不可执行栈,即栈上的数据不可执行,防止栈溢出往栈上注入 shellcode 执行
RELRO:全称 Relocation Read-Only,即只读重定位,防止 GOT 覆盖攻击
Full RELRO:所有重定位表都是只读的,包括 PLT 和 GOT
Partial RELRO:只有 PLT 是只读的,GOT 是可写的
No RELRO:所有重定位表都是可写的
再使用 Ghidra 反编译分析源码,容易找到存在栈溢出的函数 pwnme():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
voidpwnme(void)
{ undefined local_28 [32]; memset(local_28,0,0x20); puts( "For my first trick, I will attempt to fit 56 bytes of user input into 32 bytes of stack buffe r!" ); puts("What could possibly go wrong?"); puts( "You there, may I have your input please? And don\'t worry about null bytes, we\'re using read ()!\n" ); printf("> "); read(0,local_28,56); // 存在栈溢出 puts("Thank you!"); return; }
{ undefined local_2c [40]; memset(local_2c,0,0x20); puts( "For my first trick, I will attempt to fit 56 bytes of user input into 32 bytes of stack buffe r!" ); puts("What could possibly go wrong?"); puts( "You there, may I have your input please? And don\'t worry about null bytes, we\'re using read ()!\n" ); printf("> "); read(0,local_2c,56); puts("Thank you!"); return; }
[*] '/home/ubuntu/Datas/rop-emporium/split/split' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
发现开启了 NX 和 Partial RELRO
再反编译分析源码,同样容易找到存在栈溢出的函数 pwnme():
1 2 3 4 5 6 7 8 9 10 11 12 13
voidpwnme(void)
{ undefined local_28 [32]; memset(local_28,0,0x20); puts("Contriving a reason to ask user for data..."); printf("> "); read(0,local_28,0x60); puts("Thank you!"); return; }
这一次没有了可以直接获取 flag 的函数,但是在 .got.plt 表中发现有 system 函数:
.got.plt 是什么?
.got.plt: This is the GOT for the PLT. It contains the target addresses (after they have been looked up) or an address back in the .plt to trigger the lookup. Classically, this data was part of the .got section.
{ undefined local_2c [40]; memset(local_2c,0,0x20); puts("Contriving a reason to ask user for data..."); printf("> "); read(0,local_2c,0x60); puts("Thank you!"); return; }
[*] '/home/ubuntu/Datas/rop-emporium/callme/callme' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) RUNPATH: b'.'
发现开启了 NX 和 Partial RELRO
再反编译源码,同样容易找到存在栈溢出的函数 pwnme():
1 2 3 4 5 6 7 8 9 10 11 12 13
voidpwnme(void)
{ undefined local_28 [32]; memset(local_28,0,0x20); puts("Hope you read the instructions...\n"); printf("> "); read(0,local_28,0x200); puts("Thank you!"); return; }
Thank you! [DEBUG] Received 0x1e bytes: b'callme_one() called correctly\n' callme_one() called correctly [*] Process '/home/ubuntu/Datas/rop-emporium/callme/callme' stopped with exit code 0 (pid 10210) [DEBUG] Received 0x3f bytes: b'callme_two() called correctly\n' b'ROPE{a_placeholder_32byte_flag!}\n' callme_two() called correctly ROPE{a_placeholder_32byte_flag!}
x86
程序分析
32 位程序的缓冲区大小略有不同:
1 2 3 4 5 6 7 8 9 10 11 12
voidpwnme(void)
{ undefined local_2c [40]; memset(local_2c,0,0x20); puts("Hope you read the instructions...\n"); printf("> "); read(0,local_2c,0x200); puts("Thank you!"); return; }
[DEBUG] Received 0x6f bytes: b'callme_two() called correctly\n' b'Hope you read the instructions...\n' b'\n' b'> Thank you!\n' b'ROPE{a_placeholder_32byte_flag!}\n' callme_two() called correctly Hope you read the instructions... > Thank you! ROPE{a_placeholder_32byte_flag!}