# **FPTU SECATHON 2024**
# Summary
- Reverse Engineering
- [RE1](#RE1)
- [RE2](#RE2)
- [RE3](#RE3)
- [Horrible childhood memories](#Horrible-childhood-memories)
- [MiniSteg](#MiniSteg)
- [Nothing there](#Nothing-there)
- [Mov](#Mov)
- Forensics
- [No suspicious](#No-suspicious)
# Reverse Engineering
## RE1
### Description

### Solution
Sau khi mình nhận được file và kiểm tra thì biết đây là 1 file ELF64

Sau đó, mình đã sử dụng decompiler để decompile file này. Tại hàm main, mình có thấy 2 array cùng với đoạn check đáng chú ý này (Câu if bên trên chỉ là kiểm tra độ dài của ký tự bên trong 2 dấu ngoặc nhọn thôi)

Tại hàm check, mình thấy được sẽ có việc lấy từng phần tử của dãy đầu trừ đi từng phần tử dãy sau

Nên mình đã viết nhanh 1 đoạn script bằng Python để tìm ra license key
```python!
v7 = [168,193,122,172,158,108,206,153,175,175,194,189,141,127,101,202,208,116,149,160,146,179,114,143,187,159,126,109,174,156,185,120,164,189,112,120,123,145]
v8 = [53,87,22,73,48,1,91,53,58,62,89,74,35,28,1,92,99,17,41,45,29,79,10,44,68,58,11,12,72,38,83,2,67,74,12,5,23,45]
for i in range(len(v7)):
print(chr(v7[i] - v8[i]), end = "")
## OUTPUT
sjdcnksduqisjcdnmclsudhcwesafvfvasdsdd
```
Nghi ngờ rằng đoạn mình nhận được bị sai, nên mình có kiểm tra lại và nó lại là đúng

Flag: `FUSec{sjdcnksduqisjcdnmclsudhcwesafvfvasdsdd}`
## RE2
### Description

### Solution
Sau khi nhận được file và kiểm tra, mình biết được đây là 1 file ELF64

Mình đã load file vào decompiler để xem có những gì. Sau khi load xong, mình có thấy 1 hàm để check debug nên nghĩ chắc bài này cần debug rồi

Sau khi check debug, sẽ đến đoạn modify lại key và tiếp đến là compare. Tại hàm modifyString, mình có thấy việc sẽ đảo ngược lại ký tự bên trong 2 dấu ngoặc nhọn

Sau khi modifyString xong, sẽ đến đoạn compare

Tại hàm compare này, có việc tạo ra 1 cái Serial, tham số truyền vào hàm tạo ra Serial chính là username. Tại hàm generateSerial, mình thấy có 1 hàm scrambleData, và sẽ truyền username sau khi thêm 'youfoundme' vào hàm này

Hàm scrambleData này thực chất chỉ thực hiện việc XOR từng giá trị 1 với 171. Tiếp theo sau khi thực hiện xong sẽ chuyển giá trị từ bytes -> string.
Ví dụ:
```
byte: 0xcd -> 2 chars: cd (bytes: 0x63,0x64)
```
Sau đó, chương trình sẽ thực hiện việc kiểm tra nội dung bên trong `FUSec{` và `}` với string vừa lấy được

Đề bài yêu cầu username là fpt, nên mình đã viết nhanh 1 đoạn script để lấy key
```python!
username = 'fptyoufoundme'
key = ""
for c in username:
key += hex(ord(c) ^ 171)[2:]
key = "FUSec{" + key[::-1] + "}"
print(key)
## OUTPUT
FUSec{ec6cfc5ced4cdced4c2dfdbddc}
```
Sau đó mình chạy thử lại với chương trình để kiểm tra và thành công lấy được flag (Trong lúc làm bài này, debugger của mình như bị quỷ đớ nhập ý, nó bị abcxyz ngay từ lúc bắt đầu load file vào decompiler, phải tắt đi bật lại ạ)

Flag: `FUSec{ec6cfc5ced4cdced4c2dfdbddc}`
## RE3
### Description

### Solution
Sau khi nhận được file, mình kiểm tra và nhận ra file bị pack bởi UPX và là file ELF64

Unpack xong, mình sử dụng decompiler để xem file này có những gì

Tại hàm main, mình có thấy sẽ truyền vào 1 arg là get_flag và có thêm 1 arg nữa, tuy nhiên khi truyền vào là get_flag thì sẽ đến bước decrypt_flag và mình xem trong này có gì

Trong này, sẽ lấy arg thứ 2 và kiểm tra với secretflagkey, nếu đúng thì sẽ thực hiện in flag còn sai thì thôi. Giờ việc mình làm chỉ là chạy chương trình với 2 arg là `get_flag` và `secretflagkey` rồi lấy flag ( 🤡 Bài này hề vc)

Flag: `FUSec{Y0ugotm2friendscongrat}`
## Horrible childhood memories
### Description

### Solution
Sau khi extract ra, mình sort lại theo thời gian để xem file nào được chỉnh sửa gần nhất và biết được đó là file EOSClient.exe

Tiếp theo, mình kiểm tra thì biết được đây là file PE32 được viết bằng .NET

Mình sử dụng dnSpy cho tiết mục này. Tại Program, mình có thấy gọi AuthenticateForm()

Và mình đã xem bên trong AuthenticateForm có gì

Hơ cái gì đây, tại btnLogin_Click lại có flag bị encode base64 à

Trong Base64Encoding, mình có thấy gọi đến SixBitToChar

Đơn giản thì cái này nó chỉ là 1 cái dict không hơn không kém. Nên mình sử dụng CyberChef cho tiết mục lấy flag (Cơ mà char map bị thay đổi nên cần lấy theo char map ở trong file này)

Flag: `FUSec{IAM101_n0w_try_the_Re4L_0n3}`
## MiniSteg
### Description

### Solution
Sau khi kiểm tra file nhận được, mình biết đây là 1 file PE64.

Vì vậy nên mình đã load vào trình decompile để xem nó làm gì. Nhìn qua thì khá giống với Golang và file có vẻ đã bị strip hay gì gì đấy 🙂

Bằng vài lần nghịch ngu nên mình đã nhanh chóng xác định được hàm main của cái này. Hàm main của nó đây, cái được bôi vàng ý

Tại hàm này, sẽ thực hiện việc gì gì đó mà cần truyền vào 1 arg

Sau khi có được arg đó thì sẽ đến hàm xử lý (mình nghĩ là đoạn giấu gì đó vào file ảnh thôi). Tại đây, mình thấy khá nghi ngờ cái v4 này và nó chỉ được truyền vào `sub_4019d4`

Tại hàm `sub_4019d4` có thực hiện tính toán gì đó với cái này

Mình đã viết nhanh 1 đoạn script để xem kết quả và tđn lấy luôn được flag
```python!
v4 = [0xE7,0xF6,0xF4,0x06,0x04,0x1C,0xEF,0xD1,0x18,0x00,0xFA,0xD1,0x16,0x00,0xEC,0x0F,0xD1,0x18,0x00,0xE9,0xD1,0x18,0x00,0xF5,0xD1,0x00,0xE9,0xD2,0xE5,0xE6,0x00,0xEA,0xD7,0xD7,0x1E,0x23]
for i in v4:
print(chr((i - 5793) % 256), end = "")
## OUTPUT
FUSec{N0w_Y0u_Kn0w_H0w_T0_H1DE_I66}
```
Flag: `FUSec{N0w_Y0u_Kn0w_H0w_T0_H1DE_I66}`
## Nothing there
### Description

### Solution
Sau khi kiểm tra file, mình biết file này đã bị pack và là file PE32

Mình đã quyết định học nhanh 1 khóa unpack ASPack tại [Youtube](https://www.youtube.com/watch?v=Oejq7_mH3IM&ab_channel=UrielKosayev). Sau khi Unpack xong, mình có thấy tại hàm main sẽ có Inject gì đó vào tiến trình
- Tại hàm main:

- Đoạn inject:

Thấy có sử dụng dữ liệu tại `&unk_2C8F58` cùng với cái chỗ này không bị encrypt nên mình lấy ra luôn xem nó có những gì. Và đây là kết quả

Có kết nối ra bên ngoài, có nhận dữ liệu từ bên ngoài, có việc so sánh dữ liệu và in ra (Mình đã khá tốn thời gian vì chỉ chăm chăm vào việc kiểm tra mà không để ý cái in ra). Nó sẽ có in v16 và v16 là kết quả của `sub_5D12CB()` và trong cái hàm đó sẽ trả về 1 array và nhìn nhanh thì cũng biết là chữ cái đọc được (hàm `sub_5D90B0` được gọi trong `sub_5D12CB` )

Mình lấy thử đống đấy ra đọc thử thì thấy có 1 đoạn hex khá đáng ngờ. Mình có viết nhanh 1 script để thực hiện việc này (Trông dài thế thôi chứ chả có gì)
```python!
result = [0] * 0xf8
result[20] = 53
result[99] = 121
result[66] = 105
result[21] = 102
result[91] = 99
result[41] = 51
result[83] = 118
result[22] = 54
result[52] = 54
result[62] = 0
result[8] = 54
result[0] = 52
result[104] = 118
result[33] = 50
result[32] = 55
result[70] = 107
result[123] = 118
result[94] = 117
result[67] = 111
result[57] = 51
result[68] = 99
result[114] = 115
result[12] = 54
result[88] = 115
result[85] = 118
result[120] = 104
result[36] = 55
result[76] = 99
result[115] = 107
result[72] = 112
result[111] = 100
result[16] = 54
result[40] = 51
result[25] = 102
result[55] = 51
result[121] = 118
result[65] = 99
result[96] = 107
result[11] = 98
result[46] = 55
result[113] = 98
result[7] = 53
result[44] = 53
result[14] = 55
result[29] = 51
result[48] = 55
result[10] = 55
result[35] = 49
result[56] = 55
result[116] = 106
result[95] = 103
result[31] = 55
result[81] = 107
result[51] = 48
result[82] = 99
result[117] = 106
result[87] = 100
result[86] = 122
result[1] = 54
result[53] = 51
result[23] = 49
result[2] = 53
result[71] = 110
result[101] = 121
result[73] = 122
result[105] = 106
result[45] = 102
result[28] = 51
result[74] = 121
result[77] = 122
result[100] = 106
result[27] = 50
result[118] = 99
result[119] = 97
result[60] = 55
result[47] = 48
result[39] = 52
result[92] = 102
result[13] = 52
result[84] = 120
result[3] = 53
result[18] = 55
result[34] = 51
result[109] = 104
result[107] = 121
result[54] = 51
result[63] = 117
result[49] = 50
result[102] = 110
result[19] = 48
result[4] = 53
result[78] = 118
result[43] = 101
result[93] = 109
result[112] = 115
result[89] = 105
result[122] = 109
result[79] = 118
result[97] = 107
result[9] = 51
result[90] = 116
result[103] = 103
result[98] = 119
result[80] = 122
result[42] = 54
result[24] = 53
result[61] = 100
result[75] = 117
result[38] = 55
result[37] = 52
result[6] = 54
result[106] = 108
result[110] = 117
result[15] = 53
result[50] = 51
result[69] = 120
result[5] = 51
result[108] = 112
result[30] = 55
result[59] = 51
result[17] = 100
result[64] = 121
result[58] = 55
result[26] = 55
for i in result:
print(chr(i), end = "")
```
Output:

Sau khi ném đống hex này lên CyberChef thì mình lấy được flag

Flag: `FUSec{dump_a_r3wr1tt3n_pr0c3ss}`
## Mov
### Description

### Solution
Sau khi lấy được file, mình có kiểm tra xem đây là file gì và biết là file ELF32

Tiếp theo, mình load vào decompiler để xem có những gì và caideogiday,caigithenay

Vâng, mình kéo 1 lượt, toàn `mov` với `mov`, chỉ có `mov` thôi. Bên cạnh đó, khi xem hàm `dispatch` và `sub_8049000` cùng 1 số loc ở gần đó thì thấy có lệnh `jmp`

Đầu mình kiểu "Thôi xong rồi, ơ nhưng toàn lệnh mov như này thì không biết nó chạy sẽ thế nào". Mình quyết định chạy thử file và ahshiet, nó chạy bình thường như bình thường.

Ngay lúc này mình nhận ra: "Thôi thì ốm đòn với việc debug rồi". Không để mất thời gian, mình bắt đầu setup ngay cho việc debug.

Sau 1 thời gian debug, mình biết được cách hoạt động của cái file này. Mình có xem các hàm được import vào file.

Đầu tiên, file sẽ import 1 sig sa_dispatch và 1 sig sa_loop (Mục đích làm gì hồi sau sẽ rõ)

Tiếp theo sẽ chạy hết 1 lượt từ _start -> read_string -> check -> main
Sẽ không có gì xảy ra cả vì cuối hàm này là lệnh mov và đầu hàm kia là lệnh mov.

Tuy nhiên, tại cuối hàm main thì lại có 2 bytes 0x8E và 0xC8

Quay lại các hàm đã import vào file, thì làm sao để có thể gọi được các hàm đó. Khi mình chạy debug lần đầu, chạy đến đoạn mov offset của `malloc` vào external

Sau khi chạy đến `mov eax, [eax]`, ngay lúc đó tại thanh ghi eax đang là giá trị 0x0

Khi chạy tiếp, sẽ nhảy vào exception.

`Pass to app`, mình sẽ nhảy vào dispatch và jump đến offset được lưu trong external

Tiếp tục thì mình đã vào được thư viện và thực thi hàm đó

Thực thi xong, giá trị sẽ được trả về như mình sử dụng hàm 1 cách bình thường

Vậy là mình cũng đã rõ được cách mà file gọi các hàm để thực thi. 2 giá trị `on` và `fault` sẽ đánh dấu xem hàm được load vào external có được thực thi hay không, nếu có thì sẽ nhảy vào exception do lệnh `mov eax, [eax]` tạo ra.
Nhưng 1 điều là nếu như chạy hết hàm main rồi thì làm sao để có thể thực hiện tiếp các bước tiếp theo như nhập giá trị. Thì khi chạy đến đây, mình lại gặp exception tiếp

Khi thực hiện tiếp, mình đã nhảy về master_loop, ngay bên dưới việc load sig

Mình đã suy ra được rằng file này sẽ chạy trong 1 vòng lặp vô hạn cho đến khi lệnh exit được thực hiện. Một vài lần chạy thử nữa được diễn ra, mình nhận ra rằng sau khi nhập 1 string vào, file sẽ kiểm tra độ dài với 0x23 (35 ký tự)

Để biết được việc kiểm tra độ dài được diễn ra tại đâu, hãy đọc cái [docs](https://kirschju.re/docs/jonischkeit-2016-demovfuscator.pdf) này. Mình tìm được khi tìm thấy repo [demovfuscator](https://github.com/leetonidas/demovfuscator) (Mình có thử tool này rồi nma sau khi chạy xong mình thấy code nó khó đọc hơn nên thôi mình quyết định làm việc với file ban đầu)
Flow của file này sẽ là
```
-> Malloc
-> Lấy input
-> Check độ dài input
-> Check từng ký tự của input
-> Output
```
Biết được độ dài string là 35 ký tự, mình truyền vào đúng 35 ký tự và tiếp tục công cuộc debug. Thì việc kiểm tra flag sẽ diễn ra tại hàm `check`. Mình bắt đầu nhận ra có điều gì đó khá là lạ khi thấy các giá trị ở trong `c_array` sẽ được load trước chứ không phải các ký tự mình nhập vào.

Và đây chính là các giá trị trong `c_array`

Debug thêm 1 lúc, mình khá chắc rằng đoạn check này sẽ giống với đoạn pseudocode mình viết bằng python bên dưới
```python3!
res = True
for i in range(35):
if(input[i] != (c_array[i] - i)):
res = False
return res
```
Để kiểm tra, mình có viết nhanh 1 đoạn python để chạy và lấy được kết quả
```python3!
c_array = [0x42,0x34,0x4E,0x34,0x37,0x7B,0x6B,0x66,0x75,0x3C,0x69,0x78,0x3C,0x83,0x74,0x84,0x83,0x74,0x46,0x87,0x44,0x87,0x75,0x48,0x8B,0x78,0x88,0x4C,0x83,0x85,0x92,0x8C,0x54,0x93,0x55]
for i in range(35):
print(chr(c_array[i] - i), end = "")
## OUTPUT
B3L13ve_m3_m0vfusc4t0r_1s_n1ghtm4r3
```
Mình kiểm tra lại với file thực thi và thành công lấy được flag (Btw, mình thấy được rằng mình guessing khá nhiều ở bài này cũng như vẫn tồn tại lỗ hổng kiến thức về các registor, chạy debug và các thứ các thứ)

Flag: `FUSec{B3L13ve_m3_m0vfusc4t0r_1s_n1ghtm4r3}`
# Forensics
## No suspicious
### Description

### Solution
Sau khi lấy được file pcap, mở lên và đọc, mình có lấy được 1 file ELF là `treasure`

Extract file này và kiểm tra, mình biết được đây là 1 file ELF64

Tiếp theo, mình sử dụng decompiler để kiểm tra xem bên trong cái này có gì. Tại hàm main, mình có thấy việc có kết nối đến ip `4.236.191.192` port `443`. Có cả nhận dữ liệu, thực hiện shell và gửi dữ liệu đi

Mình có thấy hàm `rc2` được gọi với key, có vẻ như là cho việc decrypt message được gửi tới cũng như encrypt message gửi đi. Trong hàm này sẽ thực hiện việc mã hóa cũng như giải mã. Tại hàm `rc2` này có thêm 2 hàm là `ksa` và `prga`

Hàm `ksa` phục vụ cho việc tạo key từ 16 bytes key được truyền vào

Hàm `prga` phục vụ cho việc mã hóa cũng như giải mã

Được rồi, flow của cái `treasure` này là:
```
-> Command bị mã hóa gửi đến
-> Giải mã
-> Thực hiện Command
-> Mã hóa kết quả của command
-> Gửi đi
```
Mình đã viết lại 1 cái script thực hiện lại 2 công việc encrypt cũng như decrypt (Tôi xin lỗi vì code ngu được chưa 🙂)
```python!
from Crypto.Util.number import long_to_bytes
key = [0x79,0xE1,0x0A,0x5D,0x87,0x7D,0x9F,0x46,0x49,0x41,0x2E,0x11,0x65,0xAC,0xE3,0x25]
plain = long_to_bytes(<lừa>)
plain = list(plain)
s = list()
for i in range(0xff+1):
s.append(i)
j = 0
for i in range(0xff+1):
j = (s[i] + j + key[i % len(key)]) & 0xff
#swap
tmp = s[i]
s[i] = s[j]
s[j] = tmp
i_0 = 0
j_0 = 0
for n in range(len(plain)):
i_0 = (i_0 + 1) % 256
j_0 = (j_0 + s[i_0]) % 256
tmp = s[i_0]
s[i_0] = s[j_0]
s[j_0] = tmp
print(chr(s[(s[i_0] + s[j_0]) & 0xff] ^ (plain[n])), end = "")
```
Quay trở lại file pcap, mình chắc chắn đã capture được quá trình nhận dữ liệu và gửi dữ liệu. Trước đó, khi phân tích file `treasure` mình đã lấy được ip nên mình sẽ filter ip này để tìm ra các package có dính líu đến ip này

Và giờ chỉ cần lấy dữ liệu ra xem thôi, mình đã thử với package có độ dài lớn nhất và kết quả là
- Package có độ dài lớn nhất:

- Kết quả sau khi decrypt:

Và ok rồi đấy, giờ thử các package khác thôi, sau 1 hồi tìm tòi thì mình có tìm được flag
- Package chứa flag:

- Decrypt:

Flag: `FUSec{f4k3_TLS_1s_s0m3th1ng_bruuhhh}`