Skip to content

Commit 3946c22

Browse files
Merge branch 'master' into pomo/service-ark
2 parents 71a1412 + 0e2c2b5 commit 3946c22

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+53283
-1
lines changed
+170
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
import struct
2+
3+
OP_NOP = 0
4+
OP_ADD = 1
5+
OP_SUB = 2
6+
OP_MUL = 3
7+
OP_DIV = 4
8+
OP_MOD = 5
9+
OP_XOR = 6
10+
OP_AND = 7
11+
OP_OR = 8
12+
OP_RSH = 9
13+
OP_LSH = 10
14+
OP_MOV = 11
15+
OP_NEG = 12
16+
OP_INV = 13
17+
OP_CMP = 14
18+
OP_JMP = 15
19+
OP_RJMP = 16
20+
OP_LDR8 = 17
21+
OP_LDR16 = 18
22+
OP_LDR32 = 19
23+
OP_LDR64 = 20
24+
OP_STR8 = 21
25+
OP_STR16 = 22
26+
OP_STR32 = 23
27+
OP_STR64 = 24
28+
OP_SYSCALL = 25
29+
OP_HLT = 26
30+
31+
32+
CMP_EQ = 0
33+
CMP_NEQ = 1
34+
CMP_ULT = 2
35+
CMP_UGT = 3
36+
CMP_ULEQ = 4
37+
CMP_UGEQ = 5
38+
CMP_SLT = 6
39+
CMP_SGT = 7
40+
CMP_SLEQ = 8
41+
CMP_SGEQ = 9
42+
43+
SYSCALL_READ = 0
44+
SYSCALL_WRITE = 1
45+
46+
47+
def parse_reg(reg):
48+
reg = int(reg[1:])
49+
assert 0 <= reg <= 255
50+
return bytes([reg])
51+
52+
53+
def parse_value(val):
54+
if isinstance(val, str):
55+
return parse_reg(val)
56+
if isinstance(val, int):
57+
if val <= 0:
58+
return bytes([0xFF]) + struct.pack("q", val)
59+
return bytes([0xFF]) + struct.pack("Q", val)
60+
raise ValueError(f"unkown operand type {type(val)}")
61+
62+
63+
def nop():
64+
return bytes([OP_NOP])
65+
66+
67+
def add(r, arg):
68+
return bytes([OP_ADD]) + parse_reg(r) + parse_value(arg)
69+
70+
71+
def sub(r, arg):
72+
return bytes([OP_SUB]) + parse_reg(r) + parse_value(arg)
73+
74+
75+
def mul(r, arg):
76+
return bytes([OP_MUL]) + parse_reg(r) + parse_value(arg)
77+
78+
79+
def div(r, arg):
80+
return bytes([OP_DIV]) + parse_reg(r) + parse_value(arg)
81+
82+
83+
def mod(r, arg):
84+
return bytes([OP_MOD]) + parse_reg(r) + parse_value(arg)
85+
86+
87+
def xor(r, arg):
88+
return bytes([OP_XOR]) + parse_reg(r) + parse_value(arg)
89+
90+
91+
def band(r, arg):
92+
return bytes([OP_AND]) + parse_reg(r) + parse_value(arg)
93+
94+
95+
def bor(r, arg):
96+
return bytes([OP_OR]) + parse_reg(r) + parse_value(arg)
97+
98+
99+
def rsh(r, arg):
100+
return bytes([OP_RSH]) + parse_reg(r) + parse_value(arg)
101+
102+
103+
def lsh(r, arg):
104+
return bytes([OP_LSH]) + parse_reg(r) + parse_value(arg)
105+
106+
107+
def mov(r, arg):
108+
return bytes([OP_MOV]) + parse_reg(r) + parse_value(arg)
109+
110+
111+
def neg(r):
112+
return bytes([OP_NEG]) + parse_reg(r)
113+
114+
115+
def inv(r):
116+
return bytes([OP_INV]) + parse_reg(r)
117+
118+
119+
def ldr8(r, arg):
120+
return bytes([OP_LDR8]) + parse_value(r) + parse_value(arg)
121+
122+
123+
def ldr16(r, arg):
124+
return bytes([OP_LDR16]) + parse_value(r) + parse_value(arg)
125+
126+
127+
def ldr32(r, arg):
128+
return bytes([OP_LDR32]) + parse_value(r) + parse_value(arg)
129+
130+
131+
def ldr64(r, arg):
132+
return bytes([OP_LDR64]) + parse_value(r) + parse_value(arg)
133+
134+
135+
def str8(r, arg):
136+
return bytes([OP_STR8]) + parse_value(r) + parse_value(arg)
137+
138+
139+
def str16(r, arg):
140+
return bytes([OP_STR16]) + parse_value(r) + parse_value(arg)
141+
142+
143+
def str32(r, arg):
144+
return bytes([OP_STR32]) + parse_value(r) + parse_value(arg)
145+
146+
147+
def str64(r, arg):
148+
return bytes([OP_STR64]) + parse_value(r) + parse_value(arg)
149+
150+
151+
def syscall():
152+
return bytes([OP_SYSCALL])
153+
154+
155+
def hlt():
156+
return bytes([OP_HLT])
157+
158+
159+
def cmp(r, tp, a, b):
160+
return (
161+
bytes([OP_CMP]) + parse_reg(r) + bytes([tp]) + parse_value(a) + parse_value(b)
162+
)
163+
164+
165+
def jmp(cond, val):
166+
return bytes([OP_JMP]) + parse_value(cond) + parse_value(val)
167+
168+
169+
def rjmp(cond, val):
170+
return bytes([OP_RJMP]) + parse_value(cond) + parse_value(val)

checkers/aquarius/aquarius_lib.py

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from pwn import *
2+
import base64
3+
from typing import Optional, List, Tuple
4+
from checklib import *
5+
6+
context.log_level = "CRITICAL"
7+
8+
PORT = 7117
9+
10+
DEFAULT_RECV_SIZE = 4096
11+
TCP_CONNECTION_TIMEOUT = 5
12+
TCP_OPERATIONS_TIMEOUT = 7
13+
14+
15+
class CheckMachine:
16+
17+
def __init__(self, checker: BaseChecker):
18+
self.c = checker
19+
self.port = PORT
20+
21+
def connect(self) -> remote:
22+
io = remote(self.c.host, self.port, timeout=TCP_CONNECTION_TIMEOUT)
23+
io.settimeout(TCP_OPERATIONS_TIMEOUT)
24+
return io
25+
26+
def exit(self, io: remote) -> None:
27+
io.sendlineafter(b"> ", b"3")
28+
29+
def upload_vm(
30+
self,
31+
io: remote,
32+
rom: bytes,
33+
status: Status,
34+
) -> str:
35+
io.sendlineafter(b"> ", b"1")
36+
io.sendlineafter(b"base64 encoded rom> ", base64.b64encode(rom))
37+
io.recvuntil(b"id: ")
38+
return io.recvline().strip().decode()
39+
40+
def run_vm(self, io: remote, id: string, status: Status) -> Tuple[int, bytes]:
41+
io.sendlineafter(b"> ", b"2")
42+
io.sendlineafter(b"id> ", id.encode("ascii"))

checkers/aquarius/checker.py

+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
#!/usr/bin/env python3
2+
3+
import sys
4+
import time
5+
import copy
6+
7+
from checklib import *
8+
9+
argv = copy.deepcopy(sys.argv)
10+
11+
from pwn import *
12+
from aquarius_lib import *
13+
import aquarius_assembler as asm
14+
15+
16+
def machine_with_known_output(output: bytes) -> bytes:
17+
code = b""
18+
for i, c in enumerate(output):
19+
code += asm.str8(i, c)
20+
21+
code += asm.mov("r0", asm.SYSCALL_WRITE)
22+
code += asm.mov("r1", 0)
23+
code += asm.mov("r2", len(output))
24+
code += asm.syscall()
25+
return code
26+
27+
28+
def machine_with_password(output: bytes, password: bytes) -> bytes:
29+
password_promt = machine_with_known_output(b"password: ")
30+
wrong_password = machine_with_known_output(b"wrong password\n") + asm.hlt()
31+
output_data = machine_with_known_output(output) + asm.hlt()
32+
code = b""
33+
code += password_promt
34+
code += asm.mov("r0", asm.SYSCALL_READ)
35+
code += asm.mov("r1", 0)
36+
code += asm.mov("r2", len(password))
37+
code += asm.syscall()
38+
code += asm.mov("r1", 1)
39+
for i, c in enumerate(password):
40+
code += asm.ldr8("r3", i)
41+
code += asm.cmp("r2", asm.CMP_EQ, "r3", c)
42+
code += asm.band("r1", "r2")
43+
code += asm.rjmp("r1", len(wrong_password))
44+
code += wrong_password
45+
code += output_data
46+
return code
47+
48+
49+
class Checker(BaseChecker):
50+
vulns: int = 1
51+
timeout: int = 5
52+
uses_attack_data: bool = True
53+
54+
def __init__(self, *args, **kwargs):
55+
super(Checker, self).__init__(*args, **kwargs)
56+
self.mch = CheckMachine(self)
57+
58+
def action(self, action, *args, **kwargs):
59+
try:
60+
super(Checker, self).action(action, *args, **kwargs)
61+
except (pwnlib.exception.PwnlibException, EOFError):
62+
self.cquit(Status.DOWN, "got connect error", "got pwntools connect error")
63+
except UnicodeDecodeError:
64+
self.cquit(Status.MUMBLE, "got unicode error", "got unicode error")
65+
66+
def check(self):
67+
with self.mch.connect() as io:
68+
output = rnd_string(32).encode()
69+
rom = machine_with_known_output(output + b"\n") + asm.hlt()
70+
machine_id = self.mch.upload_vm(io, rom, Status.MUMBLE)
71+
self.mch.run_vm(io, machine_id, Status.MUMBLE)
72+
res = io.recvline()
73+
# raise ValueError(rom)
74+
self.assert_eq(
75+
res.strip(), output, f"invalid flag on {rom}", Status.CORRUPT
76+
)
77+
self.cquit(Status.OK)
78+
79+
self.cquit(Status.OK)
80+
81+
def put(self, flag_id: str, flag: str, vuln: str):
82+
with self.mch.connect() as io:
83+
password = rnd_string(32)
84+
rom = machine_with_password(flag.encode() + b"\n", password.encode())
85+
machine_id = self.mch.upload_vm(io, rom, Status.MUMBLE)
86+
self.mch.exit(io)
87+
self.cquit(Status.OK, f"{machine_id}", f"{machine_id}:{password}")
88+
89+
def get(self, flag_id: str, flag: str, vuln: str):
90+
machine_id, password = flag_id.split(":")
91+
with self.mch.connect() as io:
92+
self.mch.run_vm(io, machine_id, Status.CORRUPT)
93+
io.recvuntil(b"password: ")
94+
io.send(password)
95+
res = io.recvline()
96+
self.assert_eq(res.strip(), flag.encode(), "invalid flag", Status.CORRUPT)
97+
self.cquit(Status.OK)
98+
99+
100+
if __name__ == "__main__":
101+
# import base64
102+
#
103+
# print(base64.b64encode(machine_with_password(b"kek", b"lol")))
104+
# print(asm.cmp("r2", asm.CMP_EQ, "r3", 1337))
105+
# exit(0)
106+
c = Checker(argv[2])
107+
108+
try:
109+
c.action(argv[1], *argv[3:])
110+
except c.get_check_finished_exception():
111+
cquit(Status(c.status), c.public, c.private)

0 commit comments

Comments
 (0)