## I. Introduction
- TEAM: `KCSC`
> Giải thứ 2 chơi cùng nhà RE, mình bú win được các anh.
## II. Writeups
### 1. Back_to_the_past
- File thực thi là một file ELF, đi kèm với một file data `flag.enc`. Bài thuộc thể loại quay ngược quá khứ, tức là chall có gen ra seed sử dụng `time(0)` và mã hóa `flag`. Với bài này, điều quan trọng nhất cần lưu ý là các hàm `srand` và `rand` đã bị customed:


- Mô phỏng hai hàm này, kết hợp với thông tin của chall:

mình có được script giải:
```python=
import ctypes
def rand():
global seed
seed = ctypes.c_uint64(6364136223846793005 * seed + 1).value
return seed >> 33
seed = 1715198477
f = open("flag.enc", "rb").read()
msg = ""
seed = seed - 1
for i in range(len(f)):
v11 = ctypes.c_int(rand()).value
msg += chr(f[i] ^ (v11 % 127))
print(msg)
```
- Số seed kia mình lấy từ [đây](https://www.epochconverter.com/):

> ~~`PWNME{4baf3723f62a15f22e86d57130bc40c3}`~~
### 2. C4-License
- Chall được viết theo phong cách khá dị - sử dụng Qt5, thông tin thêm có thể đọc tại [đây](https://doc.qt.io/qt-5/index.html). Đi kèm với file thực thi còn có một file `license-Noa` bên cạnh, và khi đem chuỗi trong file đi decode thì mình được:

- Bằng suy đoán và dựa vào description của chall

- Mình nghĩ bài sẽ bằng cách nào đó gen key sử dụng user, sau đó viết chuỗi hex vào serial rồi đóng gói lại thành json. File ELF đề cho thực chất là một con check key, mình cần code ra keygen rồi dùng chall để check. Vậy thì cần tìm cơ chế check. Lục trong đống String thì mình thấy:

- Xref theo thì tới được hàm khá sú ở đây:

- Đây là hàm `checker`:
::: spoiler checker
```c=
__int64 __fastcall checker(__int64 *a1, const QByteArray *a2)
{
__int64 v3; // rdx
__int64 v4; // rsi
unsigned int v5; // eax
int v6; // ebx
volatile signed __int32 *v7; // rdi
signed __int32 v8; // et0
volatile signed __int32 **v9; // r13
unsigned int v10; // edx
_BYTE *v11; // rax
unsigned __int64 v12; // rsi
__int64 v13; // rax
volatile signed __int32 *v14; // rdi
__int64 v15; // r12
signed __int32 v16; // et0
volatile signed __int32 *v17; // rdi
signed __int32 v18; // et0
volatile signed __int32 *v19; // rdi
signed __int32 v20; // et0
volatile signed __int32 *v22; // [rsp+8h] [rbp-160h] BYREF
volatile signed __int32 *v23; // [rsp+10h] [rbp-158h] BYREF
volatile signed __int32 *v24; // [rsp+18h] [rbp-150h] BYREF
char v25[276]; // [rsp+20h] [rbp-148h] BYREF
unsigned __int8 v26[4]; // [rsp+134h] [rbp-34h] BYREF
unsigned __int64 v27; // [rsp+138h] [rbp-30h]
v3 = *((unsigned int *)a1 + 2);
v4 = *a1;
v27 = __readfsqword(0x28u);
v5 = crc32(0LL, v4, v3);
srand(v5);
v6 = rand();
*(_DWORD *)v26 = _byteswap_ulong(rand() % 0xFFFF * (v6 % 0xFFFF));
RC4::RC4((RC4 *)v25, v26);
QByteArray::fromHex((QByteArray *)&v24, a2);
RC4::decrypt(&v22, v25, &v24);
v7 = v24;
if ( !*v24 || *v24 != -1 && (v8 = _InterlockedSub(v24, 1u), v7 = v24, !v8) )
QArrayData::deallocate(v7, 1LL, 8LL);
v9 = &v23;
QCryptographicHash::hash(&v23, &v22, 2LL);
QByteArray::toHex((QByteArray *)&v24);
v10 = *((_DWORD *)v24 + 1);
if ( v10 )
{
v11 = (char *)v24 + *((_QWORD *)v24 + 2);
v12 = 0LL;
while ( *v11 )
{
v12 = (unsigned int)(v12 + 1);
++v11;
if ( v10 == (_DWORD)v12 )
{
v12 = v10;
break;
}
}
}
else
{
v12 = 0LL;
}
v13 = QString::fromAscii_helper((QString *)((char *)v24 + *((_QWORD *)v24 + 2)), (const char *)v12, v10);
v14 = v24;
v15 = v13;
if ( !*v24 || *v24 != -1 && (v16 = _InterlockedSub(v24, 1u), v14 = v24, !v16) )
QArrayData::deallocate(v14, 1LL, 8LL);
v17 = v23;
if ( !*v23 || *v23 != -1 && (v18 = _InterlockedSub(v23, 1u), v17 = v23, !v18) )
QArrayData::deallocate(v17, 1LL, 8LL);
LOBYTE(v9) = (unsigned int)QString::compare_helper(
v15 + *(_QWORD *)(v15 + 16),
*(unsigned int *)(v15 + 4),
"b039d6daea04c40874f80459bff40142bd25b995",
0xFFFFFFFFLL,
1LL) == 0;
if ( !*(_DWORD *)v15 || *(_DWORD *)v15 != -1 && !_InterlockedSub((volatile signed __int32 *)v15, 1u) )
QArrayData::deallocate(v15, 2LL, 8LL);
v19 = v22;
if ( !*v22 || *v22 != -1 && (v20 = _InterlockedSub(v22, 1u), v19 = v22, !v20) )
QArrayData::deallocate(v19, 1LL, 8LL);
return (unsigned int)v9;
}
```
:::
- Hàm `checker` sẽ nhận vào hai tham số lần lượt là `(user, serial)`. Và luồng check sẽ như sau:
```
Tính toán CRC32 của user
Seed CRC32(user)
Gen key from seed
Khởi tạo RC4(key)
Decrypt serial bằng RC4(key)
Hash SHA1 chuỗi decrypted serial
So sánh với chuỗi mẫu trong bài
```
- Chuỗi mẫu có giá trị `b039d6daea04c40874f80459bff40142bd25b995`. Vậy để có được một chương trình gen key hợp lệ, mình sẽ lợi dụng valid key được cho ngay từ đầu trong bài để tìm lại chuỗi thỏa `sha1(decrypted serial) == b039d6daea04c40874f80459bff40142bd25b995`, sau đó làm lần lượt như sau:
```
Tính toán CRC32(user)
Seed CRC32(user) -> key -> RC4(key)
Encrypt decrypted serial
Hợp thành key
```
- Code giải của mình sẽ như sau:
```python=
from Crypto.Util.number import long_to_bytes
from Crypto.Cipher import ARC4
from base64 import b64encode, b64decode
from json import loads, dumps
from binascii import crc32
from hashlib import sha1
from pwn import *
import ctypes
libc = ctypes.CDLL("libc.so.6")
context.log_level = "Debug"
def find_rc4_serial():
valid_key = open("license-Noa", "r").read().strip()
valid_key = loads(b64decode(valid_key).decode())
_user, _serial = valid_key["user"], bytes.fromhex(valid_key["serial"])
crc32_user = crc32(_user.encode())
libc.srand(crc32_user)
random_key = (libc.rand() % 0xFFFF) * (libc.rand() % 0xFFFF)
random_key = random_key.to_bytes(4, "big")
rc4 = ARC4.new(random_key)
rc4_serial = rc4.decrypt(_serial)
assert sha1(rc4_serial).hexdigest() == "b039d6daea04c40874f80459bff40142bd25b995"
return rc4_serial
def from_user_to_key(user, rc4_serial):
crc32_user = crc32(user.encode())
libc.srand(crc32_user)
random_key = (libc.rand() % 0xFFFF) * (libc.rand() % 0xFFFF)
random_key = random_key.to_bytes(4, "big")
rc4 = ARC4.new(random_key)
_serial = rc4.encrypt(rc4_serial)
valid_key = {"user": user, "serial": bytes.hex(_serial)}
valid_key = b64encode(dumps(valid_key).encode()).decode()
return valid_key
rc4_serial = find_rc4_serial()
user = "Noa"
valid_key = from_user_to_key(user, rc4_serial)
assert valid_key == open("license-Noa", "r").read().strip()
io = process(["./checker.py", "python3"])
for _ in range(100):
io.recvuntil(b"Your license for ")
_user = io.recvuntil(b" user :", drop=True).strip().decode()
_key = from_user_to_key(_user, rc4_serial)
io.sendline(_key.encode())
io.recvuntil(b"License key valid !")
io.interactive()
```

- Do mình viết script giải sau khi giải end, platform sập, phải chạy qua process.
> ~~`PWNME{8d0f21d2a2989b739673732d8155022b}`~~
### 3. Flattened_Vyper
- Bài rất đơn giản, đây là desc:

- Smart contract của bài nằm trong file `.bin`, nội dung như sau:
```
0x6003361161001843405d6106b4576106ac43405d6106b4565b5f3560e01c346106b043405d6106b4576301002b1f81186106aa43405d6106b457608436106106b043405d6106b45760243560040160408135116106b043405d6106b4578035602082018181606037508060405250507f1b47819435df544ae4e6a35d3c2d0eb2900cab1460ec254d464c1d82d70db60a7fe4b87e6bca20abb51b195ca36f2af2f5438b8a072af4f6f657b9a8304e8d36910133186106b043405d6106b4577f400000000000000000000000000000000000000000000000000000000000000060a0527f100000000000000000000000000000000000000000000000000000000000000060c0527f6d1cd107e7ef14bc558622a86cb621d9f18c50764e98df43777f3b33164b87dd7f42e0da5ae4babe43a564859fc944bb6033a02fb2741ff60444793a962b5ccf627fa2b11742daceaab03c583a6aa15e32d664450c3eb36da7897f6ce121490078597f8d4d1c1fd99b004fccba9d5d04aca86fa66973fa89ea8ece4c6ae08474173fa6181803517f781d48306de91b1cbdc32a7036761292d1c1cf57e84fe74689f7583d7e24c64f7f781d48306de91b1cbdc32a7036761292d1c1cf57e84fe74689f7583d7e24c6ef18517f0512bd13110722311710cf5327ac435a7a97c643656412a9b8a1abcd1a6916c77f459142deccea264542a00403ce80c4b0a4042bb3d4341aad06905269ed6f0b097f4083ffcddded047455b0cb50e92c87eade93edf0b1500804be31f9a4f7061dc2180335181861069f43405d6106b4577f805d92843fa8a2a28a4c797f73b9b4d5a4d8fd4f515d4e8cdfc2c303969081497f4c45d48945056a0c8203311b215240ed84ad80e70629f350834b13c2c0f510d47f0768ff01e42043ef7236fc833ca34516c059f32dce8faaa7c3085cb73a85b9df18037fadaf670881744dc7aa596a2d1eb68dbc21fef929481f4bc6ec75331d53acbd2e7f61ec705ea65e9bbf5b5a26cc5fa4f55ad1074377dce1ffbc52d65a8816af56a47f9c1a44f72090b2084eff4360bf11986150f7b5b16b3d4c0a999ed8953cfd668a010360e05260207f5a589468edfec83b6b027d7dc5bb900ed2921f1620aae0da1aa294cc3ef1dd717fa5a76b97120137c494fd82823a446ff12d6de0e9df551f25e55d6b33c10e236f01a17f101aa2511b4501cd6f4bedff54bee2f014409dfdf0c34e4a64b6f4f4e72d12a17f6aaf1061dc80372e146e902c25be0914f9997523a728f840c73791d7d1c5554e7fed7a429f015e2d1de96ca3ecadf167436726c87d156b2102064cdc2db8a65eba7f8a0afd773820c30d4395e19e96c0e921f3358da90bb44eb99631bbcc1afc52d27f2933690f7726bee93b2fb03b006b8c4f0cd1d2602dd08d3884e88cb07c9985557ff498467872da19bd835f3a0d95241a369f38625609e70acb1761497dddfe741101010101516060201861069f43405d6106b4577f7d32a137160083987c5b53f4a7153ac04f8d6c93569d179ad4df3963572af76b7f9650daf8bc6e9af151f6c7125f922329197841d23a7933641b5c2b5a836f208d7f0d973dfa900ec9b8498e449d6a71d2eed81d94c326c4acc325db9c6420acc6bd01037fc86afc4c1f60387b16cce4e4b7c47baf30b9fc18389a2563b2afbe90f43b938b7f9de848aa2e1f7fadbc76fdeb1e6d86e23f62c033260728029884a9e1533cf0907f4535f7c4dddcbd2e353778b864f7e5aadeb48786211942f0066b5715f41e13447fcd1941de2602e740c239ec7184cd0608b8cebb856e7243bca25b386695fc5d4f7f11fea6990cda43a993f3c8cb366da2c23305d78b65ad90ea8578bc704a1b53617f81385805084428d13c1994377979238f1c9f574353e344bf9674b56f2380894f031818010160e0527fb861afb70639f08b7f0a674d3ce0216ce6746772b2c753574d99d19c2507759b7f479e5048f9c60f7480f598b2c31fde93198b988d4d38aca8b2662e63daf88a85017f5a589468edfec83b6b027d7dc5bb900ed2921f1620aae0da1aa294cc3ef1dd717fa5a76b97120137c494fd82823a446ff12d6de0e9df551f25e55d6b33c10e236f01a1610a286002604435181861069f43405d6106b4577f6751ff9969e5beee7bb9fd6731aba2e2a213bd96a1f54b0a24d11452a915ab967fa3f4105dff5270ad5b285974bd7f411880965825ce709ecdb52d7d484df31bfd7f493267cb0f8113a9bd75b52869d3344723cd0d18ac091431f0c8c0557d4d69c37f8a7d2dab1437a704175dec5cd4ac755fa35b553d62798afc45e5bd1d30be723e180360e052602060e0a1600160e052602060e06106a843405d6106b4565b5f60e052602060e05bf35b505b5f5ffd5b5f80fd5b43405c8081181856
```
- Vì là smart contract, mình sẽ đem nó đi decompile trên [trang này](https://ethervm.io/decompile), nhận được:
::: spoiler code
```solidity=
label_0000:
// Inputs[3]
// {
// @0002 msg.data.length
// @0007 block.number
// @0008 block.blockHash(block.number)
// }
0000 60 PUSH1 0x03
0002 36 CALLDATASIZE
0003 11 GT
0004 61 PUSH2 0x0018
0007 43 NUMBER
0008 40 BLOCKHASH
0009 5D 5D
// Stack delta = +3
// Outputs[3]
// {
// @0003 stack[0] = msg.data.length > 0x03
// @0004 stack[1] = 0x0018
// @0008 stack[2] = block.blockHash(block.number)
// }
// Block terminates
000A 61 PUSH2 0x06b4
000D 57 *JUMPI
000E 61 PUSH2 0x06ac
0011 43 NUMBER
0012 40 BLOCKHASH
0013 5D 5D
0014 61 PUSH2 0x06b4
0017 56 *JUMP
0018 5B JUMPDEST
0019 5F 5F
001A 35 CALLDATALOAD
001B 60 PUSH1 0xe0
001D 1C SHR
001E 34 CALLVALUE
001F 61 PUSH2 0x06b0
0022 43 NUMBER
0023 40 BLOCKHASH
0024 5D 5D
0025 61 PUSH2 0x06b4
0028 57 *JUMPI
0029 63 PUSH4 0x01002b1f
002E 81 DUP2
002F 18 XOR
0030 61 PUSH2 0x06aa
0033 43 NUMBER
0034 40 BLOCKHASH
0035 5D 5D
0036 61 PUSH2 0x06b4
0039 57 *JUMPI
003A 60 PUSH1 0x84
003C 36 CALLDATASIZE
003D 10 LT
003E 61 PUSH2 0x06b0
0041 43 NUMBER
0042 40 BLOCKHASH
0043 5D 5D
0044 61 PUSH2 0x06b4
0047 57 *JUMPI
0048 60 PUSH1 0x24
004A 35 CALLDATALOAD
004B 60 PUSH1 0x04
004D 01 ADD
004E 60 PUSH1 0x40
0050 81 DUP2
0051 35 CALLDATALOAD
0052 11 GT
0053 61 PUSH2 0x06b0
0056 43 NUMBER
0057 40 BLOCKHASH
0058 5D 5D
0059 61 PUSH2 0x06b4
005C 57 *JUMPI
005D 80 DUP1
005E 35 CALLDATALOAD
005F 60 PUSH1 0x20
0061 82 DUP3
0062 01 ADD
0063 81 DUP2
0064 81 DUP2
0065 60 PUSH1 0x60
0067 37 CALLDATACOPY
0068 50 POP
0069 80 DUP1
006A 60 PUSH1 0x40
006C 52 MSTORE
006D 50 POP
006E 50 POP
006F 7F PUSH32 0x1b47819435df544ae4e6a35d3c2d0eb2900cab1460ec254d464c1d82d70db60a
0090 7F PUSH32 0xe4b87e6bca20abb51b195ca36f2af2f5438b8a072af4f6f657b9a8304e8d3691
00B1 01 ADD
00B2 33 CALLER
00B3 18 XOR
00B4 61 PUSH2 0x06b0
00B7 43 NUMBER
00B8 40 BLOCKHASH
00B9 5D 5D
00BA 61 PUSH2 0x06b4
00BD 57 *JUMPI
00BE 7F PUSH32 0x4000000000000000000000000000000000000000000000000000000000000000
00DF 60 PUSH1 0xa0
00E1 52 MSTORE
00E2 7F PUSH32 0x1000000000000000000000000000000000000000000000000000000000000000
0103 60 PUSH1 0xc0
0105 52 MSTORE
0106 7F PUSH32 0x6d1cd107e7ef14bc558622a86cb621d9f18c50764e98df43777f3b33164b87dd
0127 7F PUSH32 0x42e0da5ae4babe43a564859fc944bb6033a02fb2741ff60444793a962b5ccf62
0148 7F PUSH32 0xa2b11742daceaab03c583a6aa15e32d664450c3eb36da7897f6ce12149007859
0169 7F PUSH32 0x8d4d1c1fd99b004fccba9d5d04aca86fa66973fa89ea8ece4c6ae08474173fa6
018A 18 XOR
018B 18 XOR
018C 03 SUB
018D 51 MLOAD
018E 7F PUSH32 0x781d48306de91b1cbdc32a7036761292d1c1cf57e84fe74689f7583d7e24c64f
01AF 7F PUSH32 0x781d48306de91b1cbdc32a7036761292d1c1cf57e84fe74689f7583d7e24c6ef
01D0 18 XOR
01D1 51 MLOAD
01D2 7F PUSH32 0x0512bd13110722311710cf5327ac435a7a97c643656412a9b8a1abcd1a6916c7
01F3 7F PUSH32 0x459142deccea264542a00403ce80c4b0a4042bb3d4341aad06905269ed6f0b09
0214 7F PUSH32 0x4083ffcddded047455b0cb50e92c87eade93edf0b1500804be31f9a4f7061dc2
0235 18 XOR
0236 03 SUB
0237 35 CALLDATALOAD
0238 18 XOR
0239 18 XOR
023A 61 PUSH2 0x069f
023D 43 NUMBER
023E 40 BLOCKHASH
023F 5D 5D
0240 61 PUSH2 0x06b4
0243 57 *JUMPI
0244 7F PUSH32 0x805d92843fa8a2a28a4c797f73b9b4d5a4d8fd4f515d4e8cdfc2c30396908149
0265 7F PUSH32 0x4c45d48945056a0c8203311b215240ed84ad80e70629f350834b13c2c0f510d4
0286 7F PUSH32 0x0768ff01e42043ef7236fc833ca34516c059f32dce8faaa7c3085cb73a85b9df
02A7 18 XOR
02A8 03 SUB
02A9 7F PUSH32 0xadaf670881744dc7aa596a2d1eb68dbc21fef929481f4bc6ec75331d53acbd2e
02CA 7F PUSH32 0x61ec705ea65e9bbf5b5a26cc5fa4f55ad1074377dce1ffbc52d65a8816af56a4
02EB 7F PUSH32 0x9c1a44f72090b2084eff4360bf11986150f7b5b16b3d4c0a999ed8953cfd668a
030C 01 ADD
030D 03 SUB
030E 60 PUSH1 0xe0
0310 52 MSTORE
0311 60 PUSH1 0x20
0313 7F PUSH32 0x5a589468edfec83b6b027d7dc5bb900ed2921f1620aae0da1aa294cc3ef1dd71
0334 7F PUSH32 0xa5a76b97120137c494fd82823a446ff12d6de0e9df551f25e55d6b33c10e236f
0355 01 ADD
0356 A1 LOG1
0357 7F PUSH32 0x101aa2511b4501cd6f4bedff54bee2f014409dfdf0c34e4a64b6f4f4e72d12a1
0378 7F PUSH32 0x6aaf1061dc80372e146e902c25be0914f9997523a728f840c73791d7d1c5554e
0399 7F PUSH32 0xed7a429f015e2d1de96ca3ecadf167436726c87d156b2102064cdc2db8a65eba
03BA 7F PUSH32 0x8a0afd773820c30d4395e19e96c0e921f3358da90bb44eb99631bbcc1afc52d2
03DB 7F PUSH32 0x2933690f7726bee93b2fb03b006b8c4f0cd1d2602dd08d3884e88cb07c998555
03FC 7F PUSH32 0xf498467872da19bd835f3a0d95241a369f38625609e70acb1761497dddfe7411
041D 01 ADD
041E 01 ADD
041F 01 ADD
0420 01 ADD
0421 51 MLOAD
0422 60 PUSH1 0x60
0424 20 SHA3
0425 18 XOR
0426 61 PUSH2 0x069f
0429 43 NUMBER
042A 40 BLOCKHASH
042B 5D 5D
042C 61 PUSH2 0x06b4
042F 57 *JUMPI
0430 7F PUSH32 0x7d32a137160083987c5b53f4a7153ac04f8d6c93569d179ad4df3963572af76b
0451 7F PUSH32 0x9650daf8bc6e9af151f6c7125f922329197841d23a7933641b5c2b5a836f208d
0472 7F PUSH32 0x0d973dfa900ec9b8498e449d6a71d2eed81d94c326c4acc325db9c6420acc6bd
0493 01 ADD
0494 03 SUB
0495 7F PUSH32 0xc86afc4c1f60387b16cce4e4b7c47baf30b9fc18389a2563b2afbe90f43b938b
04B6 7F PUSH32 0x9de848aa2e1f7fadbc76fdeb1e6d86e23f62c033260728029884a9e1533cf090
04D7 7F PUSH32 0x4535f7c4dddcbd2e353778b864f7e5aadeb48786211942f0066b5715f41e1344
04F8 7F PUSH32 0xcd1941de2602e740c239ec7184cd0608b8cebb856e7243bca25b386695fc5d4f
0519 7F PUSH32 0x11fea6990cda43a993f3c8cb366da2c23305d78b65ad90ea8578bc704a1b5361
053A 7F PUSH32 0x81385805084428d13c1994377979238f1c9f574353e344bf9674b56f2380894f
055B 03 SUB
055C 18 XOR
055D 18 XOR
055E 01 ADD
055F 01 ADD
0560 60 PUSH1 0xe0
0562 52 MSTORE
0563 7F PUSH32 0xb861afb70639f08b7f0a674d3ce0216ce6746772b2c753574d99d19c2507759b
0584 7F PUSH32 0x479e5048f9c60f7480f598b2c31fde93198b988d4d38aca8b2662e63daf88a85
05A5 01 ADD
05A6 7F PUSH32 0x5a589468edfec83b6b027d7dc5bb900ed2921f1620aae0da1aa294cc3ef1dd71
05C7 7F PUSH32 0xa5a76b97120137c494fd82823a446ff12d6de0e9df551f25e55d6b33c10e236f
05E8 01 ADD
05E9 A1 LOG1
05EA 61 PUSH2 0x0a28
05ED 60 PUSH1 0x02
05EF 60 PUSH1 0x44
05F1 35 CALLDATALOAD
05F2 18 XOR
05F3 18 XOR
05F4 61 PUSH2 0x069f
05F7 43 NUMBER
05F8 40 BLOCKHASH
05F9 5D 5D
05FA 61 PUSH2 0x06b4
05FD 57 *JUMPI
05FE 7F PUSH32 0x6751ff9969e5beee7bb9fd6731aba2e2a213bd96a1f54b0a24d11452a915ab96
061F 7F PUSH32 0xa3f4105dff5270ad5b285974bd7f411880965825ce709ecdb52d7d484df31bfd
0640 7F PUSH32 0x493267cb0f8113a9bd75b52869d3344723cd0d18ac091431f0c8c0557d4d69c3
0661 7F PUSH32 0x8a7d2dab1437a704175dec5cd4ac755fa35b553d62798afc45e5bd1d30be723e
0682 18 XOR
0683 03 SUB
0684 60 PUSH1 0xe0
0686 52 MSTORE
0687 60 PUSH1 0x20
0689 60 PUSH1 0xe0
068B A1 LOG1
068C 60 PUSH1 0x01
068E 60 PUSH1 0xe0
0690 52 MSTORE
0691 60 PUSH1 0x20
0693 60 PUSH1 0xe0
0695 61 PUSH2 0x06a8
0698 43 NUMBER
0699 40 BLOCKHASH
069A 5D 5D
069B 61 PUSH2 0x06b4
069E 56 *JUMP
069F 5B JUMPDEST
06A0 5F 5F
06A1 60 PUSH1 0xe0
06A3 52 MSTORE
06A4 60 PUSH1 0x20
06A6 60 PUSH1 0xe0
06A8 5B JUMPDEST
06A9 F3 *RETURN
06AA 5B JUMPDEST
06AB 50 POP
06AC 5B JUMPDEST
06AD 5F 5F
06AE 5F 5F
06AF FD *REVERT
06B0 5B JUMPDEST
06B1 5F 5F
06B2 80 DUP1
06B3 FD *REVERT
06B4 5B JUMPDEST
06B5 43 NUMBER
06B6 40 BLOCKHASH
06B7 5C 5C
06B8 80 DUP1
06B9 81 DUP2
06BA 18 XOR
06BB 18 XOR
06BC 56 *JUMP
```
:::
- Đây là các bytecode của code solidity đã được dịch ra, mình sẽ sử dụng [doc](https://ethervm.io/#opcodes) để đọc opcode và cố gắng reverse nó. Sử dụng web gen ra [graph](https://bytegraph.xyz/bytecode/63fa04cb66e21595dd28556cc567fd11/list), mình có được:

- Được biết, các hàm `LOG` sẽ giúp chúng ta thực thi các `event`:

- Bên cạnh đó, flag được chia thành 3 phần như trong desc, vì vậy mình sẽ đọc tất cả các code trước mỗi `LOG1` và suy luận. Nhận ra trước mỗi `LOG1` đều có `*JUMPI` nên mình sẽ ném code lên trang [này](https://www.evm.codes/playground) để kiểm tra stack state:
- [Part 1](https://www.evm.codes/playground?fork=cancun&unit=Wei&codeType=Mnemonic&code='t805d92843fa8a2a28a4c797f73b9b4d5a4d8fd4f515d4e8cdfc2c30396908149~4c45d48945056a0c8v3311b215240ed84ad80e70629f350834b13c2c0f510d4~0768ff01e4v43ef7236fc833ca34516c059f32dce8faaa7c3085cb73a85b9dfzXORzSUB~adaf670881744dc7aa596a2d1eb68dbc21fef929481f4bc6ec75331d53acbd2e~61ec705ea65e9bbf5b5a26cc5fa4f55ad1074377dce1ffbc52d65a8816af56a4~9c1a44f7v90bv84eff4360bf11986150f7b5b16b3d4c0a999ed8953cfd668auSUBse0zMSTOREsv~5a589468edfec83b6b027d7dc5bb900ed2921f16vaae0da1aa294cc3ef1dd71~a5a76b971v137c494fd82823a446ff12d6de0e9df551f25e55d6b33c10e236fuLOG1'~ztz%5Cny%200xwPUSHv20uzADDztw32yszw1y%01stuvwyz~_)

- [Part 2](https://www.evm.codes/playground?fork=cancun&unit=Wei&codeType=Mnemonic&code='w7dma13s60083987c5btf4astac04f8d6c93569d179ad4df3963572q76b~9650dqvc6e9q15o6cs25f92u29197841dua7933641b5c2b5a836f208d~0d973dfa900ec9b8498e449d6asd2eed81drcm6c4accm5db9c6420acc6bdyi~c86qc4co60l7b16cce4e4b7c47bq30b9fc18l9a2563b2qbe90f43b93v~9de848aa2eo7fadbc76fdeb1e6d86euf62c03m60728029884a9e1t3cf090~4t5f7c4dddcbd2e3t77v864f7e5aadeb48786211r2f0066b5s5f41e1344~cd1r1de2602ep0cu9ecs84cd060v8cebb856e7243bca25bl6695fc5d4f~1oea6990cda43a993f3c8cb366da2cu305d7v65ad90ea857vc704a1bt61~81l5805084428d13c19r377979u8f1c9f5p3te344bf96pb56fu808rfihhyyzj1ke0zMSTORE~b861qb70639f0v7f0a6pd3ce0216ce6p6772b2c7t5pd99d19c2507759b~479e5048f9c60fp80f59v2c3ode9319v988d4dlacav2662e63dq88a85y~5a58r68edfec83b6b027d7dc5bb900ed292o1620aae0da1aa2rcc3ef1dds~a5a76b9s20137c4rfd828ua446ff12d6de0e9df55o25e55d6b33c10eu6fyzLOG1'~zwz%5CnyzADDwjmkv8bu23t53s71r94qafp74o1fm32l38k%200xjPUSHizSUBhzXOR%01hijklmopqrstuvwyz~_)

- [Part 3](https://www.evm.codes/playground?fork=cancun&unit=Wei&codeType=Mnemonic&code='uw6751ff9969e5beee7bb9fd6731aba2e2a213bd96a1f54b0a24d11452a915ab96~wa3f4105dff5270ad5b285974bd7f411880965825ce709ecdb52d7d484df31bfd~w493267cb0f8113a9bd75b52869d3344723cd0d18ac091431f0c8c0557d4d69c3~w8a7d2dab1437a704175dec5cd4ac755fa35b553d62798afc45e5bd1d30be723eyXORySUBvMSTORE~1z20vLOG1'~yuz%200xy%5Cnw32zv~1ze0yuPUSH%01uvwyz~_)

- Đây là state trước mỗi `LOG1`, mình sẽ trích lấy data của mem và thực hiện theo logic của từng `LOG1`
```python=
from base58 import b58decode
from pwn import xor
flag1 = "50574e4d457b0000000000000000000000000000000000000000000000000000"
flag2 = "4d684c674e377772326f42757963660000000000000000000000000000000000"
flag3 = "1f5b3a021c6444004f0000000000000000000000000000000000000000000000"
flag1 = bytes.fromhex(flag1).strip(b"\x00")
flag2 = bytes.fromhex(flag2).strip(b"\x00")
flag3 = bytes.fromhex(flag3).strip(b"\x00")
flag = flag1 + b58decode(flag2) + xor(flag3, flag2)
print(flag)
```
> ~~`PWNME{SuCh_4_M3t4R3veRS3r}`~~
### 4. Mimirev
- Bài khá lạ, solved bởi anh `neziRzz`. File attached là một con compiler, mình thử ném vào IDA Pro cũ nhưng bị stripped hết, vì vậy mình sẽ đưa vào IDA Free phiên bản mới hơn :face_with_cowboy_hat:. Tuy nhiên mình chưa hiểu luồng nên sẽ viết bài này sau.
### 5. Super Secure Network
- Chall khá trôn và dị, file attached gồm có 2 file, một file `.pcapng` và một file `.ko`. Định dạng file `.ko` này khá lạ, theo mình tìm hiểu được thì nó được sử dụng cho `Kernel Modules` ở một số distro Linux. Theo [nguồn này](https://fileinfo.com/extension/ko) thì nó chứa code để chạy các chức năng của Linux kernel. Khi đưa vào IDA thì mình không tìm được `main`. Tuy nhiên, theo [Geeksforgeeks về linux kernel](https://www.geeksforgeeks.org/linux-kernel-module-programming-hello-world-program/), khi lập trình với linux kernel, có hai module cần chú ý là `init_module()` và `cleanup_module()`:

- Vậy mình sẽ phân tích bắt đầu từ `init_module`:
```c=
__int64 init_module()
{
__int64 v1[5]; // [rsp+0h] [rbp-58h] BYREF
__int64 v2; // [rsp+28h] [rbp-30h] BYREF
__int64 v3; // [rsp+30h] [rbp-28h] BYREF
int v4; // [rsp+3Ch] [rbp-1Ch]
__int64 v5; // [rsp+40h] [rbp-18h]
__int64 v6; // [rsp+48h] [rbp-10h]
unsigned int v7; // [rsp+54h] [rbp-4h]
v7 = 0;
v6 = 0LL;
l1111l11l11l111l = l111lll11l1ll11l(60);
get_random_bytes(&lll1ll1l111l111l, 8LL);
v2 = 2LL;
v1[4] = 1LL;
v1[1] = &l1111l11l11l111l;
v1[2] = &v2;
v3 = lll1l11l1l1l1111(2uLL, lll1ll1l111l111l, l1111l11l11l111l);
v1[0] = &v3;
v1[3] = 0x800000008LL;
v7 = crypto_dh_key_len(v1);
if ( v7 )
{
v5 = v7;
v4 = 17301536;
v6 = _kmalloc(v7, 17301536LL);
if ( v6 )
{
if ( !crypto_dh_encode_key(v6, v7, v1) && lll1llll111ll1l1(0xC0A8013C, 3333) >= 0 )
{
qword_B5C0 = sub_E0A;
byte_B5D8 = 2;
dword_B5DC = 0;
dword_B5E0 = 0x80000000;
qword_B600 = sub_104E;
byte_B618 = 2;
dword_B61C = 4;
dword_B620 = 0x80000000;
if ( !nf_register_net_hook(&init_net, &qword_B5C0) && !nf_register_net_hook(&init_net, &qword_B600) )
llll1l1ll1lll1l1(l1ll111lll11lll1, v6, v7);
}
}
}
return 0LL;
}
```
- Trong này, các hàm obfuscated khá khó chịu, thầy `SonVH` cũng có đổi tên hàm cho mọi người trong team RE dễ đọc nhưng vì mục đích học tập, mình sẽ tự phân tích và đổi tên lại.
- Dưới đây là một số hàm quan trọng mình đã đổi tên:
::: spoiler init_module
```c=
__int64 init_module()
{
__int64 dh_params[5]; // [rsp+0h] [rbp-58h] BYREF
__int64 generator; // [rsp+28h] [rbp-30h] BYREF
__int64 v3; // [rsp+30h] [rbp-28h] BYREF
int v4; // [rsp+3Ch] [rbp-1Ch]
__int64 v5; // [rsp+40h] [rbp-18h]
__int64 key_buffer; // [rsp+48h] [rbp-10h]
unsigned int key_length; // [rsp+54h] [rbp-4h]
key_length = 0;
key_buffer = 0LL;
prime = generate_safe_prime(60);
get_random_bytes(&private_exponent, 8LL);
generator = 2LL;
dh_params[4] = 1LL;
dh_params[1] = ′
dh_params[2] = &generator;
v3 = modular_exponentiation(2uLL, private_exponent, prime);
dh_params[0] = &v3;
dh_params[3] = 0x800000008LL;
key_length = crypto_dh_key_len(dh_params);
if ( key_length )
{
v5 = key_length;
v4 = 0x1080020;
key_buffer = _kmalloc(key_length, 0x1080020LL);
if ( key_buffer )
{
if ( !crypto_dh_encode_key(key_buffer, key_length, dh_params)
&& create_tcp_socket_connection(0xC0A8013C, 0xD05) >= 0 )
{
inbound_hook_hook = process_encrypted_packet;
inbound_hook_pf = 2;
inbound_hook_hooknum = 0;
inbound_hook_priority = 0x80000000;
outbound_hook_hook = process_network_packet;
outbound_hook_pf = 2;
outbound_hook_hooknum = 4;
outbound_hook_priority = 0x80000000;
if ( !nf_register_net_hook(&init_net, &inbound_hook_hook)
&& !nf_register_net_hook(&init_net, &outbound_hook_hook) )
{
send_socket_message(command_socket, key_buffer, key_length);
}
}
}
}
return 0LL;
}
```
:::
::: spoiler process_encrypted_packet
```c=
__int64 __fastcall process_encrypted_packet(__int64 a1, __int64 a2)
{
int v2; // eax
__int64 v3; // rax
int v5; // [rsp+1Ch] [rbp-4Ch] BYREF
unsigned __int64 *v6; // [rsp+20h] [rbp-48h]
__int64 packet_data; // [rsp+28h] [rbp-40h]
int v8; // [rsp+34h] [rbp-34h]
__int64 v9; // [rsp+38h] [rbp-30h]
__int64 new_skb; // [rsp+40h] [rbp-28h]
unsigned int v11; // [rsp+4Ch] [rbp-1Ch]
__int64 packet_end; // [rsp+50h] [rbp-18h]
__int64 tcp_header; // [rsp+58h] [rbp-10h]
packet_end = 0LL;
v11 = 0;
new_skb = 0LL;
v9 = 0LL;
v5 = 0;
tcp_header = get_tcp_header(a2);
if ( tcp_header )
{
v8 = *(a2 + 120);
packet_data = get_packet_data(a2);
v6 = (4 * (*(tcp_header + 12) >> 4) + tcp_header);
packet_end = get_packet_end(a2);
v11 = packet_end - v6;
if ( packet_end != v6 )
{
v2 = *(v6 + v11 - 4);
if ( v2 == 0x86E35DE5 )
{
initialize_encryption_key(v6);
}
else if ( v2 == 0x89E35DE5 )
{
if ( lll1ll1111l111ll )
{
v11 -= 4;
encrypt_data_with_counter(v6, v11 - 16, (v6 + v11 - 16));
v11 -= 16;
new_skb = allocate_skb(v11 + 96, 0x1080020u);
if ( new_skb )
{
reserve_skb_header(new_skb, 96);
v3 = skb_put(new_skb, v11);
csum_partial_copy_from_user(v6, v3, v11, 0LL, &v5);
*(new_skb + 184) = 8;
*(new_skb + 186) = 0;
*(new_skb + 190) = 0;
update_packet_metadata(new_skb);
*(new_skb + 16) = *(a2 + 16);
v9 = verify_packet_data(new_skb);
if ( v9 )
netif_rx(new_skb);
}
}
}
}
}
return 1LL;
}
```
:::
::: spoiler process_network_packet
```c=
__int64 __fastcall process_network_packet(__int64 a1, __int64 a2)
{
char *dest; // [rsp+28h] [rbp-28h]
void *src; // [rsp+30h] [rbp-20h]
unsigned int n; // [rsp+3Ch] [rbp-14h]
__int64 tcp_header; // [rsp+48h] [rbp-8h]
if ( !a2 )
return 1LL;
if ( !verify_packet_data(a2) )
return 1LL;
tcp_header = get_tcp_header(a2);
if ( !tcp_header )
return 1LL;
if ( __ROL2__(*(tcp_header + 2), 8) == 3333 )
return 1LL;
if ( !lll1ll1111l111ll )
return 1LL;
n = *(a2 + 120);
src = get_packet_data(a2);
dest = _kmalloc(n + 20, 0x1080020LL);
if ( !dest )
return 1LL;
memcpy(dest, src, n);
get_random_bytes(&dest[n], 16LL);
encrypt_data_with_counter(dest, n, &dest[n]);
*&dest[n + 16] = 0x89E35BE5;
if ( !send_socket_message(res, dest, n + 20) )
return 1LL;
kfree(dest);
kfree_skb(a2);
return 2LL;
}
```
:::
::: spoiler encrypt_data_with_counter
```c=
unsigned __int64 __fastcall encrypt_data_with_counter(__int64 a1, unsigned __int64 a2, __int64 *a3)
{
__int64 v4; // rdx
unsigned __int64 result; // rax
__int64 v6; // [rsp+18h] [rbp-30h] BYREF
__int64 v7; // [rsp+20h] [rbp-28h]
__int64 v8[2]; // [rsp+28h] [rbp-20h] BYREF
unsigned __int64 j; // [rsp+38h] [rbp-10h]
unsigned __int64 i; // [rsp+40h] [rbp-8h]
v8[0] = 0LL;
v8[1] = 0LL;
v6 = 0LL;
v7 = 0LL;
j = 0LL;
v4 = a3[1];
v6 = *a3;
v7 = v4;
for ( i = 0LL; ; i += 16LL )
{
result = i;
if ( i >= a2 )
break;
call_object_method(l1l1llll1l1ll11l, v8, &v6);
for ( j = 0LL; j <= 0xF && a2 > i + j; ++j )
*(j + i + a1) ^= *(v8 + j);
for ( j = 15LL; !++*(&v6 + j); --j )
;
}
return result;
}
```
:::
- Do không thể debug nên mình chỉ có thể dự đoán luồng chương trình như sau:
```
- Khởi tạo giao thức Diffie-Hellman
- Thiết lập TCP tại địa chỉ IP 0xC0A8013C <-> 192.168.1.60 (đổi được từ hex <-> IP)
- Gửi thông tin khóa DH của giao thức - là thông tin đầu tiên được gửi đi - dòng đầu tiên
- Tùy theo magic number mà thông tin được gửi sẽ khác nhau:
- 0x86E35DE5: gửi thông tin khóa AES-CTR
- 0x89E35DE5 và 0x89E35BE5: giao tiếp giữa client và server
```

- Trace theo file pcap, mình thấy dòng đầu tiên chính là khởi tạo khóa DH, dòng thứ hai là khởi tạo khóa AES-CTR, cả hai thông tin đều rõ ràng nên mình có thể decrypt toàn bộ giao tiếp giữa `client` và `server` ở dưới.
- Với dòng đầu tiên, mình phân tích thành:



- Trong đó, các thông tin có thể lấy được, dựa vào code
```python=
key_size = 0x00000008
p_size = 0x00000008
g_size = 0x00000001
g = 0x02
p = 0x152e2145482f156b
key = 0x0c982d0ca5314f5c
```
- Do số khá bé nên mình có thể sử dụng `discrete_log` trong sage để giải:

- Có được `a = 0x1275e27a22626694`, mình sẽ đi tính lại `shared_secret = pow(B, a, p)`. Trong đó, số `B` có thể lấy được từ dòng 2:


- Ở đây, biến `v6 = B` và nó là 8 bytes đầu trước `0x86E35DE5`, vậy:
```python=
B = 0x0498d077987c0265
shared_secret = pow(B, a, p)
```
- Tính được:

- Theo luồng, `shared_secret` sẽ được đem đi hash SHA256 để tạo `CTR_key` cho bước AES-CTR tiếp theo:

- Lấy lại được `CTR_key` bằng [Cyberchef](https://gchq.github.io/CyberChef/#recipe=From_Hex('Auto')SHA2('256',64,160)&input=MzQ2NDNCNTNERjNFM0IwMA&oeol=CRLF):

- Từ đó, mình đem đi giải mã toàn bộ file pcap, với `CTR_IV` được thay đổi theo từng message:
```python=
from scapy.all import *
from Crypto.Cipher import AES
from Crypto.Util import Counter
from Crypto.Util.Padding import *
pp = PcapNgReader("capture.pcapng")
for p in pp:
if TCP in p:
payload = raw(p[TCP].payload)
if len(payload) < 36:
continue
print(payload)
sig = payload[-4:]
IV = payload[-20:-4]
enc = payload[:-20]
print(f"IV: {IV.hex()}, Enc: {enc.hex()}, Sig: {sig.hex()}\n")
key = bytes.fromhex('bf98795c03cdbce091b8986cc599628ea6ba2d91b8e50443c4bb144477ce982b')
ctr = Counter.new(128, initial_value=int.from_bytes(IV, byteorder='big'))
cipher = AES.new(key, AES.MODE_CTR, counter=ctr)
plaintext = cipher.decrypt(enc)
print(plaintext.hex())
print(plaintext)
print()
```
- Code mình ăn cắp của thầy `noobmannn`, yêu anh :fire:.

- Lục trong đống message rác, mình tìm được `flag`:
> ~~`PWNME{Crypt0_&_B4ndwidth_m4k3s_m3_f33l_UN83474813!!!}`~~