# KMACTF 2025
## Sanity
- Flag ở announcement

## Mobius
- Ta kiểm tra file thì thấy nó được pack bằng **Pyinstaller** nên ta dùng [pyinstxtractor_ng](https://github.com/pyinstxtractor/pyinstxtractor-ng/blob/main/pyinstxtractor_ng.py) để extract và có được file **proc.pyc**

- File **proc.pyc** là **bytecode python** nên ta sử dụng [pylingual.io](https://pylingual.io/) để decompile và có được source code:
```py==
"""
...
AAEQEX8AARARfwJAEBDPAAAQEM8AABAQzwBgAJCtgICtgICdgICdgICdgICdgICdgIDfARCAcPgAPwEhoBHPAAGgEc8AAaARzwABoBHPAAGgEc8QAaARz0ABoBHPAAGgEc8DgABguAVYg+0QUa1AUagALYBAWAQYFDhEOAAfACAwEM2AQFh0OCQ4gCgUeER4BHgEeAR/jwAgEBDNgECIBEiBGBR4RHgEeAR4BHgEf4+PhzDAAAAMEqFUIBAMIBDUIRAw==
"""
import marshal
from base64 import b64decode as _6d
exec(marshal.loads(_6d(globals()['__doc__'])))
```
- Ta đọc code thì thấy nó sẽ giải mã đoạn base64 và thực thi bytecode được giải mã. Để có thể decompile được, ta sẽ thêm header vào trước bytecode rồi ghi vào một file và dùng [pylingual.io](https://pylingual.io/) để decompile tiếp.
```py=
import marshal, dis
from base64 import b64decode as _6d
code = _6d(globals()['__doc__'])
header = open("./proc.pyc", "rb").read(16)
with open("./chall.pyc", "wb") as f:
f.write(header+code)
```
- Tuy nhiên khi decompile thì nó không đúng hoàn toàn đoạn code nên ta sẽ disassembly đoạn bytecode rồi vừa đọc vừa dùng AI để sửa. Đây là code hoàn chỉnh:
disasm.py
```py=
import marshal, dis
from base64 import b64decode as _6d
print(dis.dis(marshal.loads(_6d(globals()['__doc__']))))
```
proc.py
```py=
from sys import exit
class S:
def __init__(self, ms=4294967295):
self.s = list()
self.ms = ms
self.size = len(self.s)
def sh(self, ue):
if self.size < self.ms:
self.s.append(ue)
self.ud()
def p(self):
if self.size > 0:
self.s.pop()
self.ud()
def ud(self):
self.size = len(self.s)
FM = {'zero': 1}
class R:
def __init__(self):
self._1 = 0
self._2 = 0
self._3 = 0
self._4 = 0
self.r = (self._1, self._2, self._3, self._4)
self.fs = 0
def gt(self, ix):
if ix == 0:
ue = self._1
elif ix == 1:
ue = self._2
elif ix == 2:
ue = self._3
elif ix == 3:
ue = self._4
else:
exit(0)
return ue
def st(self, ix, ue):
if ix == 0:
self._1 = ue
elif ix == 1:
self._2 = ue
elif ix == 2:
self._3 = ue
elif ix == 3:
self._4 = ue
else:
exit(0)
self.r = (self._1, self._2, self._3, self._4)
def sfz(self, ue):
if ue is True:
self.fs |= FM['zero']
else:
self.fs &= ~FM['zero']
def m(v, o):
tg = (o >> ((v.sz - 2) * 4)) & 15
if tg < 0 or tg >= len(v.r.r):
exit(0)
ir = (o >> ((v.sz - 3) * 4)) & 15
if ir == 0:
ue = o & ((1 << ((v.sz - 3) * 4)) - 1)
elif ir == 1:
ix = (o >> ((v.sz - 4) * 4)) & 15
if ix < 0 or ix >= len(v.r.r):
exit(0)
ue = v.r.gt(ix)
else:
exit(0)
v.r.st(tg, ue)
def sh(v, o):
if v.s.size >= v.s.ms:
exit(0)
ir = (o >> ((v.sz - 2) * 4)) & 15
if ir == 0:
ue = o & ( (1 << ((v.sz - 2) * 4)) - 1)
elif ir == 1:
tg = (o >> ((v.sz - 3) * 4)) & 15
ue = v.r.gt(tg)
else:
exit(0)
v.s.sh(ue)
def p(v, o):
if v.s.size < 1:
exit(0)
tg = (o >> ((v.sz - 2) * 4)) & 15
if tg < 0 or tg >= len(v.r.r):
exit(0)
ue = v.s.s[-1]
v.r.st(tg, ue)
v.s.p()
def a(v, o):
tg = (o >> ((v.sz - 2) * 4)) & 15
if tg < 0 or tg >= len(v.r.r):
exit(0)
ir = (o >> ((v.sz - 3) * 4)) & 15
if ir == 0:
ue = o & ((1 << ((v.sz - 3) * 4)) - 1)
elif ir == 1:
ix = (o >> ((v.sz - 4) * 4)) & 15
if ix < 0 or ix >= len(v.r.r):
exit(0)
ue = v.r.gt(ix)
else:
exit(0)
tt = v.r.gt(tg) + ue
v.r.st(tg, tt)
def b(v, o):
tg = (o >> ((v.sz - 2) * 4)) & 15
if tg < 0 or tg >= len(v.r.r):
exit(0)
ir = (o >> ((v.sz - 3) * 4)) & 15
if ir == 0:
ue = o & ((1 << ((v.sz - 3) * 4)) - 1)
elif ir == 1:
ix = (o >> ((v.sz - 4) * 4)) & 15
if ix < 0 or ix >= len(v.r.r):
exit(0)
ue = v.r.gt(ix)
else:
exit(0)
tt = v.r.gt(tg) - ue # OR operation
v.r.st(tg, tt)
def z(v, o): # Assumed XOR, no bytecode provided
tg = (o >> ((v.sz - 2) * 4)) & 15
if tg < 0 or tg >= len(v.r.r):
exit(0)
ir = (o >> ((v.sz - 3) * 4)) & 15
if ir == 0:
ue = o & ((1 << ((v.sz - 3) * 4)) - 1)
elif ir == 1:
ix = (o >> ((v.sz - 4) * 4)) & 15
if ix < 0 or ix >= len(v.r.r):
exit(0)
ue = v.r.gt(ix)
else:
exit(0)
tt = v.r.gt(tg) ^ ue # XOR operation
v.r.st(tg, tt)
def c(v, o):
tg = (o >> ((v.sz - 2) * 4)) & 15
if tg < 0 or tg >= len(v.r.r):
exit(0)
ir = (o >> ((v.sz - 3) * 4)) & 15
if ir == 0:
ue = o & ((1 << ((v.sz - 3) * 4)) - 1)
elif ir == 1:
ix = (o >> ((v.sz - 4) * 4)) & 15
if ix < 0 or ix >= len(v.r.r):
exit(0)
ue = v.r.gt(ix)
else:
exit(0)
v.r.sfz(v.r.gt(tg) == ue)
def _exit(self):
exit(0)
ino = (m, sh, p, a, b, c, z, _exit)
class V:
def __init__(self):
self.s = S()
self.r = R()
self.sz = 8
def x(self, cd):
if len(cd)!= 51:
print('Wrong!')
exit(0)
hv = [hex(ord(i))[2:].zfill(5) for i in cd]
cd = f"60100000000{hv[0]}6000001130000539600000164000000C600000005000057961110000010{hv[1]}6100001131000539610000164100000C610000015100059062120000020{hv[2]}6200001132000539620000164200000C620000025200056363130000030{hv[3]}6300001133000539630000164300000C630000035300059260100000000{hv[4]}6000001130000539600000164000000C60000004500005ad61110000010{hv[5]}6100001131000539610000164100000C610000055100055962120000020{hv[6]}6200001132000539620000164200000C620000065200059e63130000030{hv[7]}6300001133000539630000164300000C630000075300054660100000000{hv[8]}6000001130000539600000164000000C600000085000057661110000010{hv[9]}6100001131000539610000164100000C610000095100054862120000020{hv[10]}6200001132000539620000164200000C6200000a5200058f63130000030{hv[11]}6300001133000539630000164300000C6300000b5300054860100000000{hv[12]}6000001130000539600000164000000C6000000c5000058d61110000010{hv[13]}6100001131000539610000164100000C6100000d5100058862120000020{hv[14]}6200001132000539620000164200000C6200000e5200053263130000030{hv[15]}6300001133000539630000164300000C6300000f5300058a60100000000{hv[16]}6000001130000539600000164000000C600000105000057061110000010{hv[17]}6100001131000539610000164100000C61000011510005ba62120000020{hv[18]}6200001132000539620000164200000C620000125200056e63130000030{hv[19]}6300001133000539630000164300000C630000135300058b60100000000{hv[20]}6000001130000539600000164000000C600000145000055461110000010{hv[21]}6100001131000539610000164100000C61000015510005b762120000020{hv[22]}6200001132000539620000164200000C620000165200059363130000030{hv[23]}6300001133000539630000164300000C630000175300057660100000000{hv[24]}6000001130000539600000164000000C600000185000058c61110000010{hv[25]}6100001131000539610000164100000C610000195100055a62120000020{hv[26]}6200001132000539620000164200000C6200001a5200056663130000030{hv[27]}6300001133000539630000164300000C6300001b5300058360100000000{hv[28]}6000001130000539600000164000000C6000001c5000055d61110000010{hv[29]}6100001131000539610000164100000C6100001d5100056362120000020{hv[30]}6200001132000539620000164200000C6200001e5200052163130000030{hv[31]}6300001133000539630000164300000C6300001f5300059a60100000000{hv[32]}6000001130000539600000164000000C600000205000056361110000010{hv[33]}6100001131000539610000164100000C610000215100058362120000020{hv[34]}6200001132000539620000164200000C62000022520005a763130000030{hv[35]}6300001133000539630000164300000C630000235300051f60100000000{hv[36]}6000001130000539600000164000000C60000024500005a161110000010{hv[37]}6100001131000539610000164100000C61000025510005af62120000020{hv[38]}6200001132000539620000164200000C62000026520005bd63130000030{hv[39]}6300001133000539630000164300000C630000275300055960100000000{hv[40]}6000001130000539600000164000000C600000285000057461110000010{hv[41]}6100001131000539610000164100000C610000295100055662120000020{hv[42]}6200001132000539620000164200000C6200002a5200051663130000030{hv[43]}6300001133000539630000164300000C6300002b530005bf60100000000{hv[44]}6000001130000539600000164000000C6000002c500005a961110000010{hv[45]}6100001131000539610000164100000C6100002d5100057062120000020{hv[46]}6200001132000539620000164200000C6200002e5200056e63130000030{hv[47]}6300001133000539630000164300000C6300002f5300055160100000000{hv[48]}6000001130000539600000164000000C60000030500005a461110000010{hv[49]}6100001131000539610000164100000C61000031510005bd62120000020{hv[50]}6200001132000539620000164200000C6200003252000595"
os = []
ct = 0
for i in range(0, len(cd), 8):
os.append('0x' + cd[i:i + 8])
for i in range(len(os)):
o = int(os[i], 16)
if o > 0 and o <= 16**self.sz - 1:
op = (o - 1) >> (4 * (self.sz - 1))
ino[op](self, o)
else:
exit(0)
ct += v.r.fs
if ct == 401:
print('Correct!')
else:
print('Wrong!')
ip = input('Enter Flag: ')
v = V()
v.x(ip)
```
- Ta thấy nó sẽ check len flag có bằng 51 không và thực hiện đoạn vm và tính ct, sau đó sẽ kiểm tra ct có bằng 401 không.
- Khi kiểm tra sự thay đổi của ct với mỗi input khác nhau thì ta thấy rằng nếu input đúng thì ct sẽ lớn nhất.


- Như vậy ta có dễ dàng brute force flag.
solve.py
```py=
from sys import exit
class S:
def __init__(self, ms=4294967295):
self.s = list()
self.ms = ms
self.size = len(self.s)
def sh(self, ue):
if self.size < self.ms:
self.s.append(ue)
self.ud()
def p(self):
if self.size > 0:
self.s.pop()
self.ud()
def ud(self):
self.size = len(self.s)
FM = {'zero': 1}
class R:
def __init__(self):
self._1 = 0
self._2 = 0
self._3 = 0
self._4 = 0
self.r = (self._1, self._2, self._3, self._4)
self.fs = 0
def gt(self, ix):
if ix == 0:
ue = self._1
elif ix == 1:
ue = self._2
elif ix == 2:
ue = self._3
elif ix == 3:
ue = self._4
else:
exit(0)
return ue
def st(self, ix, ue):
if ix == 0:
self._1 = ue
elif ix == 1:
self._2 = ue
elif ix == 2:
self._3 = ue
elif ix == 3:
self._4 = ue
else:
exit(0)
self.r = (self._1, self._2, self._3, self._4)
def sfz(self, ue):
if ue is True:
self.fs |= FM['zero']
else:
self.fs &= ~FM['zero']
def m(v, o):
tg = (o >> ((v.sz - 2) * 4)) & 15
if tg < 0 or tg >= len(v.r.r):
exit(0)
ir = (o >> ((v.sz - 3) * 4)) & 15
if ir == 0:
ue = o & ((1 << ((v.sz - 3) * 4)) - 1)
elif ir == 1:
ix = (o >> ((v.sz - 4) * 4)) & 15
if ix < 0 or ix >= len(v.r.r):
exit(0)
ue = v.r.gt(ix)
else:
exit(0)
v.r.st(tg, ue)
def sh(v, o):
if v.s.size >= v.s.ms:
exit(0)
ir = (o >> ((v.sz - 2) * 4)) & 15
if ir == 0:
ue = o & ( (1 << ((v.sz - 2) * 4)) - 1)
elif ir == 1:
tg = (o >> ((v.sz - 3) * 4)) & 15
ue = v.r.gt(tg)
else:
exit(0)
v.s.sh(ue)
def p(v, o):
if v.s.size < 1:
exit(0)
tg = (o >> ((v.sz - 2) * 4)) & 15
if tg < 0 or tg >= len(v.r.r):
exit(0)
ue = v.s.s[-1]
v.r.st(tg, ue)
v.s.p()
def a(v, o):
tg = (o >> ((v.sz - 2) * 4)) & 15
if tg < 0 or tg >= len(v.r.r):
exit(0)
ir = (o >> ((v.sz - 3) * 4)) & 15
if ir == 0:
ue = o & ((1 << ((v.sz - 3) * 4)) - 1)
elif ir == 1:
ix = (o >> ((v.sz - 4) * 4)) & 15
if ix < 0 or ix >= len(v.r.r):
exit(0)
ue = v.r.gt(ix)
else:
exit(0)
tt = v.r.gt(tg) + ue
v.r.st(tg, tt)
def b(v, o):
tg = (o >> ((v.sz - 2) * 4)) & 15
if tg < 0 or tg >= len(v.r.r):
exit(0)
ir = (o >> ((v.sz - 3) * 4)) & 15
if ir == 0:
ue = o & ((1 << ((v.sz - 3) * 4)) - 1)
elif ir == 1:
ix = (o >> ((v.sz - 4) * 4)) & 15
if ix < 0 or ix >= len(v.r.r):
exit(0)
ue = v.r.gt(ix)
else:
exit(0)
tt = v.r.gt(tg) - ue # OR operation
v.r.st(tg, tt)
def z(v, o): # Assumed XOR, no bytecode provided
tg = (o >> ((v.sz - 2) * 4)) & 15
if tg < 0 or tg >= len(v.r.r):
exit(0)
ir = (o >> ((v.sz - 3) * 4)) & 15
if ir == 0:
ue = o & ((1 << ((v.sz - 3) * 4)) - 1)
elif ir == 1:
ix = (o >> ((v.sz - 4) * 4)) & 15
if ix < 0 or ix >= len(v.r.r):
exit(0)
ue = v.r.gt(ix)
else:
exit(0)
tt = v.r.gt(tg) ^ ue # XOR operation
v.r.st(tg, tt)
def c(v, o):
tg = (o >> ((v.sz - 2) * 4)) & 15
if tg < 0 or tg >= len(v.r.r):
exit(0)
ir = (o >> ((v.sz - 3) * 4)) & 15
if ir == 0:
ue = o & ((1 << ((v.sz - 3) * 4)) - 1)
elif ir == 1:
ix = (o >> ((v.sz - 4) * 4)) & 15
if ix < 0 or ix >= len(v.r.r):
exit(0)
ue = v.r.gt(ix)
else:
exit(0)
v.r.sfz(v.r.gt(tg) == ue)
def _exit(self):
exit(0)
ino = (m, sh, p, a, b, c, z, _exit)
class V:
def __init__(self):
self.s = S()
self.r = R()
self.sz = 8
def x(self, cd):
if len(cd)!= 51:
print('Wrong!')
exit(0)
hv = [hex(ord(i))[2:].zfill(5) for i in cd]
cd = f"60100000000{hv[0]}6000001130000539600000164000000C600000005000057961110000010{hv[1]}6100001131000539610000164100000C610000015100059062120000020{hv[2]}6200001132000539620000164200000C620000025200056363130000030{hv[3]}6300001133000539630000164300000C630000035300059260100000000{hv[4]}6000001130000539600000164000000C60000004500005ad61110000010{hv[5]}6100001131000539610000164100000C610000055100055962120000020{hv[6]}6200001132000539620000164200000C620000065200059e63130000030{hv[7]}6300001133000539630000164300000C630000075300054660100000000{hv[8]}6000001130000539600000164000000C600000085000057661110000010{hv[9]}6100001131000539610000164100000C610000095100054862120000020{hv[10]}6200001132000539620000164200000C6200000a5200058f63130000030{hv[11]}6300001133000539630000164300000C6300000b5300054860100000000{hv[12]}6000001130000539600000164000000C6000000c5000058d61110000010{hv[13]}6100001131000539610000164100000C6100000d5100058862120000020{hv[14]}6200001132000539620000164200000C6200000e5200053263130000030{hv[15]}6300001133000539630000164300000C6300000f5300058a60100000000{hv[16]}6000001130000539600000164000000C600000105000057061110000010{hv[17]}6100001131000539610000164100000C61000011510005ba62120000020{hv[18]}6200001132000539620000164200000C620000125200056e63130000030{hv[19]}6300001133000539630000164300000C630000135300058b60100000000{hv[20]}6000001130000539600000164000000C600000145000055461110000010{hv[21]}6100001131000539610000164100000C61000015510005b762120000020{hv[22]}6200001132000539620000164200000C620000165200059363130000030{hv[23]}6300001133000539630000164300000C630000175300057660100000000{hv[24]}6000001130000539600000164000000C600000185000058c61110000010{hv[25]}6100001131000539610000164100000C610000195100055a62120000020{hv[26]}6200001132000539620000164200000C6200001a5200056663130000030{hv[27]}6300001133000539630000164300000C6300001b5300058360100000000{hv[28]}6000001130000539600000164000000C6000001c5000055d61110000010{hv[29]}6100001131000539610000164100000C6100001d5100056362120000020{hv[30]}6200001132000539620000164200000C6200001e5200052163130000030{hv[31]}6300001133000539630000164300000C6300001f5300059a60100000000{hv[32]}6000001130000539600000164000000C600000205000056361110000010{hv[33]}6100001131000539610000164100000C610000215100058362120000020{hv[34]}6200001132000539620000164200000C62000022520005a763130000030{hv[35]}6300001133000539630000164300000C630000235300051f60100000000{hv[36]}6000001130000539600000164000000C60000024500005a161110000010{hv[37]}6100001131000539610000164100000C61000025510005af62120000020{hv[38]}6200001132000539620000164200000C62000026520005bd63130000030{hv[39]}6300001133000539630000164300000C630000275300055960100000000{hv[40]}6000001130000539600000164000000C600000285000057461110000010{hv[41]}6100001131000539610000164100000C610000295100055662120000020{hv[42]}6200001132000539620000164200000C6200002a5200051663130000030{hv[43]}6300001133000539630000164300000C6300002b530005bf60100000000{hv[44]}6000001130000539600000164000000C6000002c500005a961110000010{hv[45]}6100001131000539610000164100000C6100002d5100057062120000020{hv[46]}6200001132000539620000164200000C6200002e5200056e63130000030{hv[47]}6300001133000539630000164300000C6300002f5300055160100000000{hv[48]}6000001130000539600000164000000C60000030500005a461110000010{hv[49]}6100001131000539610000164100000C61000031510005bd62120000020{hv[50]}6200001132000539620000164200000C6200003252000595"
os = []
ct = 0
for i in range(0, len(cd), 8):
os.append('0x' + cd[i:i + 8])
for i in range(len(os)):
o = int(os[i], 16)
if o > 0 and o <= 16**self.sz - 1:
op = (o - 1) >> (4 * (self.sz - 1))
ino[op](self, o)
else:
exit(0)
ct += v.r.fs
# print(ct,end=' ')
return ct
# if ct == 401:
# print('Correct!')
# else:
# print('Wrong!')
import string
char = string.ascii_letters + string.digits + string.punctuation
flag = ""
for j in range(51):
list_ct = []
for i in range(len(char)):
ip = flag + char[i]
ip += "1"*(51-len(ip))
v = V()
list_ct.append(v.x(ip))
max_ct = max(list_ct)
idx = list_ct.index(max_ct)
flag += char[idx]
print(flag)
# KCSC{Th3r3_1s_4_Pyth0n_Sl1th3r5_1n_4_VirTu4l_W0rlD}
```
- Flag : `KCSC{Th3r3_1s_4_Pyth0n_Sl1th3r5_1n_4_VirTu4l_W0rlD}`
## hẹ hẹ hẹ anh Hùng benj
- Ta load vào IDA để đọc thì thấy ở main sẽ call 4 hàm. Và ở mỗi hàm loạt các tính toán đó và cuối cùng sẽ nhảy đến một hàm khác nên ta chỉ cần đặt breakpoint và xem nó nhảy đến cái gì.


Và đây là chức năng chính của các hàm đó:
- **Function 1**: Nhập flag

- **Function 2:** Xor flag với key là `KMACTF2025_1 \x00`

```py=
key = b"KMACTF2025_1 \x00"
key = list(key)
for i in range(len(cipher)):
cipher[i] = key[i % len(key)] ^ cipher[i]
```
- **Function 3:** thực hiện mã hóa theo từng khối.


```py=
def return_sbox(x):
global sbox
v1 = sbox[__ROL1__(x, 2) ^ 0x2B]
v2 = sbox[((v1 >> 6) + 4 * (v1 & 0x3F)) ^ 0x2B]
v3 = sbox[((v2 >> 6) + 4 * (v2 & 0x3F)) ^ 0x2B]
v4 = sbox[((v3 >> 6) + 4 * (v3 & 0x3F)) ^ 0x2B]
v5 = sbox[((v4 >> 6) + 4 * (v4 & 0x3F)) ^ 0x2B]
v6 = sbox[((v5 >> 6) + 4 * (v5 & 0x3F)) ^ 0x2B]
v7 = sbox[((v6 >> 6) + 4 * (v6 & 0x3F)) ^ 0x2B]
v8 = sbox[((v7 >> 6) + 4 * (v7 & 0x3F)) ^ 0x2B]
v9 = sbox[((v8 >> 6) + 4 * (v8 & 0x3F)) ^ 0x2B]
v10 = sbox[((v9 >> 6) + 4 * (v9 & 0x3F)) ^ 0x2B]
v11 = sbox[((v10 >> 6) + 4 * (v10 & 0x3F)) ^ 0x2B]
v12 = sbox[((v11 >> 6) + 4 * (v11 & 0x3F)) ^ 0x2B]
v13 = sbox[((v12 >> 6) + 4 * (v12 & 0x3F)) ^ 0x2B]
v14 = sbox[((v13 >> 6) + 4 * (v13 & 0x3F)) ^ 0x2B]
v15 = sbox[((v14 >> 6) + 4 * (v14 & 0x3F)) ^ 0x2B]
v16 = sbox[((v15 >> 6) + 4 * (v15 & 0x3F)) ^ 0x2B]
v17 = sbox[((v16 >> 6) + 4 * (v16 & 0x3F)) ^ 0x2B]
v18 = sbox[((v17 >> 6) + 4 * (v17 & 0x3F)) ^ 0x2B]
v19 = sbox[((v18 >> 6) + 4 * (v18 & 0x3F)) ^ 0x2B]
v20 = sbox[((v19 >> 6) + 4 * (v19 & 0x3F)) ^ 0x2B]
v21 = sbox[((v20 >> 6) + 4 * (v20 & 0x3F)) ^ 0x2B]
v22 = sbox[((v21 >> 6) + 4 * (v21 & 0x3F)) ^ 0x2B]
return sbox[((v22 >> 6) + 4 * (v22 & 0x3F)) ^ 0x2B]
key_xor = b"Cust0mS3rp3ntK3y"
key_xor = list(key_xor)
for i in range(len(cipher)):
cipher[i] = key_xor[i % len(key_xor)] ^ cipher[i]
for i in range(len(cipher)):
cipher[i] = return_sbox(cipher[i])
for i in range(0,len(cipher), 16):
part = cipher[i:i+16]
v0 = part[0] | (part[1] << 8) | (part[2] << 16) | (part[3] << 24)
v1 = part[4] | (part[5] << 8) | (part[6] << 16) | (part[7] << 24)
v2 = part[8] | (part[9] << 8) | (part[10] << 16) | (part[11] << 24)
v3 = part[12] | (part[13] << 8) | (part[14] << 16) | (part[15] << 24)
v8 = __ROR4__(v0, 19)
v9 = __ROR4__(v2, 29)
v10 = v9 ^ v3 ^ ((8 * v8) & 0xffffffff)
v11 = __ROR4__(v9 ^ v8 ^ v1, 31)
v1 = v11
v12 = __ROR4__(v10, 25)
v3 = v12
v0 = __ROR4__(v12 ^ v11 ^ v8, 27)
v2 = __ROR4__(v12 ^ v9 ^ ((v11 << 7) & 0xffffffff), 10)
part[0] = v0 & 0xFF
part[1] = (v0 >> 8) & 0xFF
part[2] = (v0 >> 16) & 0xFF
part[3] = (v0 >> 24) & 0xFF
part[4] = v1 & 0xFF
part[5] = (v1 >> 8) & 0xFF
part[6] = (v1 >> 16) & 0xFF
part[7] = (v1 >> 24) & 0xFF
part[8] = v2 & 0xFF
part[9] = (v2 >> 8) & 0xFF
part[10] = (v2 >> 16) & 0xFF
part[11] = (v2 >> 24) & 0xFF
part[12] = v3 & 0xFF
part[13] = (v3 >> 8) & 0xFF
part[14] = (v3 >> 16) & 0xFF
part[15] = (v3 >> 24) & 0xFF
cipher[i:i+16] = part
```
- **Function 4:** print cipher dưới dạng hex.

- Và ta có thể giải mã nó như sau:
```py=
from z3 import *
def __ROR4__(value, n):
return LShR(value, n) | ((value << (32 - n)) & 0xffffffff)
cipher = bytes.fromhex("4A137B78476860B7D3BB4BEF617B1E8C21EBEC915969390122D557E3DF9554313A1C32B50BF54AC2673DD222181A9ADA6662676C7D3C5BBCF3CFC74395283C1B65D583C58D1DECA05EB94CE874A544F8145155396A696CD03899F0E3283B828D")
# cipher = bytes.fromhex("CC5BEBD408222951F2F7594D757F58550A76840BFAC316C10CFD7985B89B39358AE4F3E8863A9236101D86325E71FE88")
cipher = list(cipher[0:len(cipher)-16])
for i in range(0,len(cipher), 16):
# part = cipher[i:i+16]
part = cipher[i:i+16]
_v0 = part[0] | (part[1] << 8) | (part[2] << 16) | (part[3] << 24)
_v1 = part[4] | (part[5] << 8) | (part[6] << 16) | (part[7] << 24)
_v2 = part[8] | (part[9] << 8) | (part[10] << 16) | (part[11] << 24)
_v3 = part[12] | (part[13] << 8) | (part[14] << 16) | (part[15] << 24)
s = Solver()
v0_in = BitVec('v0_in', 32)
v1_in = BitVec('v1_in', 32)
v2_in = BitVec('v2_in', 32)
v3_in = BitVec('v3_in', 32)
v8 = __ROR4__(v0_in, 19)
v9 = __ROR4__(v2_in, 29)
v10 = v9 ^ v3_in ^ ((8 * v8) & 0xffffffff)
v11 = __ROR4__(v9 ^ v8 ^ v1_in, 31)
v12 = __ROR4__(v10, 25)
v0_out = __ROR4__(v12 ^ v11 ^ v8, 27)
v1_out = v11
v2_out = __ROR4__(v12 ^ v9 ^ ((v11 << 7) & 0xffffffff), 10)
v3_out = v12
s.add(v0_out == _v0)
s.add(v1_out == _v1)
s.add(v2_out == _v2)
s.add(v3_out == _v3)
if s.check() == sat:
m = s.model()
v0_val = m[v0_in].as_long()
v1_val = m[v1_in].as_long()
v2_val = m[v2_in].as_long()
v3_val = m[v3_in].as_long()
for idx, val in enumerate([v0_val, v1_val, v2_val, v3_val]):
for shift in range(4):
cipher[i + idx*4 + shift] = (val >> (8 * shift)) & 0xff
else:
print("UNSAT")
for i in range(len(cipher)):
for k in range(0xff):
x = return_sbox(k)
if x == cipher[i]:
cipher[i] = k
break
key_xor = b"Cust0mS3rp3ntK3y"
key_xor = list(key_xor)
for i in range(len(cipher)):
cipher[i] = key_xor[i % len(key_xor)] ^ cipher[i]
key = b"KMACTF2025_1 \x00"
key = list(key)
for i in range(len(cipher)):
cipher[i] = key[i % len(key)] ^ cipher[i]
print(bytes(cipher))
# https://drive.google.com/drive/folders/1de_FmF8CzPu7iSYNDumaB9pAhjN-ST_d?usp=sha
```
- Sau khi giải mã thì ta có được một link drive: `https://drive.google.com/drive/folders/1de_FmF8CzPu7iSYNDumaB9pAhjN-ST_d?usp=sha`

- Sau khi tải và extract thì ta có được các file:

- Trong đó file **Antivirus.exe.sc** là file được viết bằng .NET nên ta sẽ bỏ vào **dnspy** để phân tích.

- Ta đọc thì thấy nó mã hóa các file với thuật toán sau:


- Và trong đó subkey sẽ được random và được hash đi. Vì vậy việc tìm lại key là không thể.


- Ở đây ta chú ý vào cách file bị mã hóa thì thấy mỗi byte sẽ xor với một số khác nhau. Cộng thêm việc đề có cho một số file bị mã hóa nên nếu ta có được một file trước khi mã hóa thì ta có thể decrypt các file còn lại.

- Ta chú ý vào file `VSCodeUserSetup-x64.exe` nếu ta có thể tìm được đúng version mà user này đã cài đặt thì hoàn toàn có thể giải mã được các file còn lại. Và `C.txt` là file chứa danh sách các file ở các thư mục của user này nên ta có thể tìm trong đó.

- Sau khi đã biết được version thì ta sẽ lên mạng download về và giải mã các file.
- Đây là nội dung hai file đã được decrypt:
hehe.txt
```=
Host Name: DESKTOP-NEU8R5D
OS Name: Microsoft Windows 10 Enterprise
OS Version: 10.0.19045 N/A Build 19045
OS Manufacturer: Microsoft Corporation
OS Configuration: Standalone Workstation
OS Build Type: Multiprocessor Free
Registered Owner: vnd
Registered Organization:
Product ID: 00329-00000-00003-AA061
Original Install Date: 3/12/2025, 12:05:26 PM
System Boot Time: 4/19/2025, 5:47:08 AM
System Manufacturer: VMware, Inc.
System Model: VMware7,1
System Type: x64-based PC
Processor(s): 2 Processor(s) Installed.
[01]: Intel64 Family 6 Model 141 Stepping 1 GenuineIntel ~2688 Mhz
[02]: Intel64 Family 6 Model 141 Stepping 1 GenuineIntel ~2688 Mhz
BIOS Version: VMware, Inc. VMW71.00V.18452719.B64.2108091906, 8/9/2021
Windows Directory: C:\Windows
System Directory: C:\Windows\system32
Boot Device: \Device\HarddiskVolume1
System Locale: en-us;English (United States)
Input Locale: en-us;English (United States)
Time Zone: (UTC-08:00) Pacific Time (US & Canada)
Total Physical Memory: 2,047 MB
Available Physical Memory: 393 MB
Virtual Memory: Max Size: 5,360 MB
Virtual Memory: Available: 1,168 MB
Virtual Memory: In Use: 4,192 MB
Page File Location(s): C:\pagefile.sys
Domain: WORKGROUP
Logon Server: \\DESKTOP-NEU8R5D
Hotfix(s): 11 Hotfix(s) Installed.
[01]: KB5054978
[02]: KB5056578
[03]: KB5049613
[04]: KB5011048
[05]: KB5015684
[06]: KB5055518
[07]: KB5014032
[08]: KB5028380
[09]: KB5050111
[10]: KB5052916
[11]: KB5054682
Network Card(s): 2 NIC(s) Installed.
[01]: Intel(R) 82574L Gigabit Network Connection
Connection Name: Ethernet0
DHCP Enabled: Yes
DHCP Server: 192.168.68.254
IP address(es)
[01]: 192.168.68.144
[02]: fe80::6fa8:5416:6323:625e
[02]: Bluetooth Device (Personal Area Network)
Connection Name: Bluetooth Network Connection
Status: Media disconnected
Hyper-V Requirements: A hypervisor has been detected. Features required for Hyper-V will not be displayed.
Volume Serial Number: 6CCF-75D6
```
huh.txt
```=
59c37f9a34712e1c569c116986c945780dd458324f403be0a206898b382d2ef9
```
- Sau đó ta giải nén file `find_the_pass.7z` với password là `59c37f9a34712e1c569c116986c945780dd458324f403be0a206898b382d2ef9` và có được file `final.exe`.
- Ta load vào IDA đọc thì thấy flag sẽ được mã hóa `AES_CBC` với key là sha256 của `computer name`, iv là số serial number.




- Ta có thể dễ dàng decrypt flag với thông tin trong file `hehe.txt`.
solve.py
```py=
from Crypto.Cipher import AES
import hashlib
cipher = open("./flag.txt", "rb").read()
key = "DESKTOP-NEU8R5D"
key = hashlib.sha256(key.encode()).digest()
serial_number = "6CCF-75D6"
iv = bytes.fromhex("6C CF 75 D6 6C CF 75 D6 6C CF 75 D6 6C CF 75 D6 ")
p = AES.new(key, AES.MODE_CBC, (iv))
cipher = p.decrypt(cipher)
print(cipher)
# KMACTF{anh_hung`_benj_nun`_na'_na`_na_anh_tran_manh_hung`}
```
- Flag: ```KMACTF{anh_hung`_benj_nun`_na'_na`_na_anh_tran_manh_hung`}```
## packer
- Ta kiểm tra file bằng `die` thì có thể thấy file đã bị pack.

- Load vào IDA đọc, ta có thấy nó thực hiện check đang chạy trên máy ảo không.

- Sau đó thực hiện unpack hai section `.pack0` và `.pack1` sửa lại các phần trong một PE file. Với `.pack0` đóng vai trò là phần header còn `.pack1` là phần section

- Để dump file ra thì ta sẽ debug khi nó thực hiện xong `fixup_stage` và dựa vào `signature` là `MZ` để dump ra.

> Nhưng có vẻ khi mình dump các giá trị header vẫn bị sai gì đó mình cũng không biết nên mình dump để dễ đọc hơn thôi còn debug vẫn debug file đề cho.
- Và sau đó nó sẽ check chương trình có đang bị debug không, nếu không sẽ thực thi tại entrypoint của file ta vừa dump.

- Để dễ phân tích thì ta load file vừa dump được vào IDA ở dạng binary 64-bit.

- Sau đó thực hiện rebase lại giống đoạn code ta đang debug. Thêm nữa là rename lại biến tương ứng với địa chỉ các hàm winapi trong file ta đang debug.
- Đọc đoạn code mới ta có thấy là nó sẽ check debug ở hàm main.

- Sau đó sẽ nhập input và mỗi giá trị sẽ trừ đi 0x30

- Sau đó là một đoạn shellcode rồi và add thêm các handler xử lý exception.

- Khi debug ta trích xuất shellcode thì có thể dễ dàng nhận biết là ứng với mỗi input (giá trị đã bị trừ) thì sẽ có hai giá trị `0xf, 0xb` phía trước để gây ra exception.

- Và ứng với giá trị là bao nhiêu thì nó sẽ xử lý ở handler nào.

- Và ở handler thứ 5 sẽ in ra giá trị ở `arr[index]` và sẽ kiểm tra size của arr có bằng `0xc` không. Nếu bằng sẽ so sánh arr với `KMA CTF 2025` và bằng tiếp sẽ in ra `Correct!`

- Như vậy ta phải làm cách nào để arr phải có giá trị là `KMA CTF 2025` thì trong handler thứ 6 sẽ lấy một giá trị từ ta nhập và handler thứ 1 sẽ tăng index lên một.


- Cuối cùng ta sẽ được các input như sau:

solve.py
```py=
from pwn import *
key = b"KMA CTF 2025"
flag = "540"*len(key)
p = remote("188.166.230.213",4444)
# p = process("./packed.exe")
p.sendline(flag.encode())
p.sendline(key)
p.interactive()
```