]> git.somenet.org - pub/jan/ctf-seminar.git/blob - writeups/superwayne/otw2019/vm-chal.py
Update my writeup.
[pub/jan/ctf-seminar.git] / writeups / superwayne / otw2019 / vm-chal.py
1 import binascii
2 import re
3
4 from pwn import *
5
6 context.log_level = "debug"
7
8 instructions_before = """
9 #### create literal as a function
10
11 21      # 0x80 ^ 0xa1
12 80      # 0xa1 is on->data
13 """
14
15 instructions_to_encode = """
16 89
17 """
18
19 #00      # end instructions  # bottom of the stack
20
21 instructions_after = """
22 01      # index of function
23 a0      # upon detection of a0, the index is popped as well (= 0x01), everything is copied into the function stack until 0xa1 is reached on ->data, then ->data is empty
24
25 #### print 0x21, 0x80
26
27 21
28 b0      # print 0x21
29
30 # avoid 00 by encoding it as 0x11 0x11 and XORing it
31 11      # 0x11 is on ->data
32 11      # 0x11 0x11 is on ->data
33 84      # 0x00 is on ->data
34 80      # 0x80 is on ->data
35 b0      # print 0x80
36
37 # copy literal from function stack to ->data (i.e. call the function)
38 # literal must end with 0x00 for the print ping pong
39
40 #### print the encoded instructions with a print ping pong
41
42 c1      # the whole literal function is pushed to ->code; if the function only contains instructions < 0x80, they will be copied to ->data
43
44 # ping
45
46 21
47 80      # 0xa1 is on ->data (end of function)
48
49 63
50 80      # 0xe3 is on ->data (call function 3)
51
52 30
53 80      # 0xb0 is on ->data (print)
54
55 11
56 80      # 0x91 is on ->data (duplicate)
57
58 02
59 a0      # create function (i.e. print and call 0xe3; if 0x00 was popped [which was duplicated], function is not called)
60
61 # pong
62
63 21
64 80      # 0xa1 is on ->data (end of function)
65
66 62
67 80      # 0xe2 is on ->data (call function 2)
68
69 30
70 80      # 0xb0 is on ->data (print)
71
72 11
73 80      # 0x91 is on ->data (duplicate)
74
75 03
76 a0      # create function (i.e. print and call 0xe2; if 0x00 was popped [which was duplicated], function is not called)
77
78 # print encoded instructions
79
80 c2      # call the print function (prints everything until and including 0x00 in vm->data)
81
82 #### decode the instructions and print them with a print ping pong
83
84 c1      # the whole literal function is pushed to ->code; if the function only contains instructions < 0x80, they will be copied to ->data
85
86 # ping
87
88 21
89 80      # 0xa1 is on ->data (end of function)
90
91 65
92 80      # 0xe5 is on ->data (call function 5)
93
94 11
95 80      # 0x91 is on ->data (duplicate)
96
97 04
98 a0      # create function (i.e. print and call 0xe5; if 0x00 was popped [which was duplicated], function is not called)
99
100 # pong
101
102 21
103 80      # 0xa1 is on ->data (end of function)
104
105 44
106 80      # 0xc4 is on ->data (call function 4)
107
108 30
109 80      # 0xb0 is on ->data (print)
110
111 04
112 80      # 0x84 is on ->data
113
114 01
115 80      # 0x81 is on ->data
116
117 04
118 80      # 0x84 is on ->data
119
120 05
121 a0      # create function (i.e. print and call 0xe4; if 0x00 was popped [which was duplicated], function is not called)
122
123 # decode and print instructions
124
125 c4
126 """
127
128 def assemble(instructions):
129     # print(instructions)
130     # remove comments
131     instructions = re.sub(r"#.*", "", instructions)
132     # remove whitespaces
133     instructions = re.sub(r"\s+", "", instructions)
134     # print(instructions)
135     return binascii.unhexlify(instructions)
136
137
138 def encode(bytecode):
139     result = bytearray()
140
141     for b in bytecode:
142         if b == 0:
143             raise ValueError("0x00 is not supported!")
144         elif b < 0x80:
145             result.append(0x01)
146             result.append(0x10)
147             result.append(b)
148         else:
149             result.append(0x11)
150             result.append(0x11)
151             result.append(b ^ 0xff)
152
153     result.append(0x00)  # end of encoded sequence
154
155     return bytes(result)
156
157
158 bytecode = (
159     assemble(instructions_before)
160     + encode(assemble(instructions_after))
161     #+ encode(assemble(instructions_to_encode))
162     + assemble(instructions_after)
163 )
164 import binascii
165 print(binascii.hexlify(bytecode))
166
167 #vm = process("./vm-chal")
168 vm = remote('3.93.128.89', 1214)
169 vm.recvuntil("Length of")
170 vm.sendline(str(len(bytecode)))
171 vm.recvuntil("Enter your")
172 vm.write(bytecode)
173 vm.recvline()
174 vm.recvline()
175 vm.recvline()
176 vm.recvline()
177 vm.close()
178
179 #with open("bytecode.bin", "wb") as f:
180 #    f.write(bytecode)
181 #
182 #with open("input.bin", "wb") as f:
183 #    f.write(p32(len(bytecode)))
184 #    f.write(bytecode)