# KMACTF 2025 ## Sanity - Flag ở announcement ![image](https://hackmd.io/_uploads/H1N3VkJWex.png) ## 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** ![image](https://hackmd.io/_uploads/BJsjH11Zxx.png) - 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. ![image](https://hackmd.io/_uploads/SyZN6y1bex.png) ![image](https://hackmd.io/_uploads/Hk2NaJ1Zex.png) - 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ì. ![image](https://hackmd.io/_uploads/S1skZxkZlx.png) ![image](https://hackmd.io/_uploads/ryuOZxJZgg.png) Và đây là chức năng chính của các hàm đó: - **Function 1**: Nhập flag ![image](https://hackmd.io/_uploads/ryzMfly-le.png) - **Function 2:** Xor flag với key là `KMACTF2025_1 \x00` ![image](https://hackmd.io/_uploads/rkurMly-ll.png) ```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. ![image](https://hackmd.io/_uploads/rkIymlyWel.png) ![image](https://hackmd.io/_uploads/HJfxXx1-xx.png) ```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. ![image](https://hackmd.io/_uploads/BkU_7lyZeg.png) - 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` ![image](https://hackmd.io/_uploads/r17WEgkWgg.png) - Sau khi tải và extract thì ta có được các file: ![image](https://hackmd.io/_uploads/SktMrgkWlg.png) - 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. ![image](https://hackmd.io/_uploads/H17YSl1Wgx.png) - Ta đọc thì thấy nó mã hóa các file với thuật toán sau: ![image](https://hackmd.io/_uploads/B1cE8xyWxe.png) ![image](https://hackmd.io/_uploads/B1GQDe1Zel.png) - Và trong đó subkey sẽ được random và được hash đi. Vì vậy việc tìm lại key là không thể. ![image](https://hackmd.io/_uploads/Hyt_PxkZeg.png) ![image](https://hackmd.io/_uploads/rysYDlJWgg.png) - Ở đâ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. ![image](https://hackmd.io/_uploads/BJj4Fx1Zxl.png) - 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 đó. ![image](https://hackmd.io/_uploads/HJueogJbgg.png) - 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. ![image](https://hackmd.io/_uploads/SJYapx1bxx.png) ![image](https://hackmd.io/_uploads/HkJ3TlkWll.png) ![image](https://hackmd.io/_uploads/SyC36eJWxl.png) ![image](https://hackmd.io/_uploads/HkE1AlkZex.png) - 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. ![image](https://hackmd.io/_uploads/HJ_MLH1bxl.png) - 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. ![image](https://hackmd.io/_uploads/r1OA8ByZeg.png) - 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 ![image](https://hackmd.io/_uploads/rkVrwr1Wee.png) - Để 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. ![image](https://hackmd.io/_uploads/SJlpdH1-xe.png) > 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. ![image](https://hackmd.io/_uploads/Sy18KHJZee.png) - Để dễ phân tích thì ta load file vừa dump được vào IDA ở dạng binary 64-bit. ![image](https://hackmd.io/_uploads/B1ypsB1bgx.png) - 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. ![image](https://hackmd.io/_uploads/rypwarkbll.png) - Sau đó sẽ nhập input và mỗi giá trị sẽ trừ đi 0x30 ![image](https://hackmd.io/_uploads/rJ-3TByWgl.png) - Sau đó là một đoạn shellcode rồi và add thêm các handler xử lý exception. ![image](https://hackmd.io/_uploads/HkzmRSJ-eg.png) - 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. ![image](https://hackmd.io/_uploads/HJQ-y8yWge.png) - Và ứng với giá trị là bao nhiêu thì nó sẽ xử lý ở handler nào. ![image](https://hackmd.io/_uploads/SkwUkU1-ex.png) - 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!` ![image](https://hackmd.io/_uploads/SJtxe8ybll.png) - 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. ![image](https://hackmd.io/_uploads/By5zW8yZxg.png) ![image](https://hackmd.io/_uploads/BkMFbLk-xl.png) - Cuối cùng ta sẽ được các input như sau: ![image](https://hackmd.io/_uploads/B1CkX8JWge.png) 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() ```