---
# System prepended metadata

title: VSL Internal CTF 2025
tags: ["Reverse Engineering\_"]

---

# VSL Internal CTF 2025

## EasyXor
> A Simple Application for Data Processing Using XOR, Developed by Me

Ở đây mình sử dụng `JADX` để đọc mã nguồn
Sau khi đọc qua chương trình thì mình thấy rằng đây chỉ là một phép `XOR` giữa `flag` với `Password`
![image](https://hackmd.io/_uploads/HJvz3bVP1l.png)
![image](https://hackmd.io/_uploads/Hyst2ZNP1l.png)
Nếu `Password` đúng thì sẽ bắt đầu hoạt động

![image](https://hackmd.io/_uploads/ryYypb4w1e.png)
![image](https://hackmd.io/_uploads/Sy8BBzEvJx.png)
![image](https://hackmd.io/_uploads/HkG7T-NDJx.png)
Phần này sẽ thực hiện mã hóa `flag` bằng phép `XOR` với `Password`

```python=
from pwn import *
s = '0018195b0b55312a2601472675220310134c4b6231206514161037563c361a081815132206515d0018195b0b55312a2601472675220310134c4b6231206514161037563c361a081815132206515d0018195b0b55312a2601472675220310134c4b6231206514161037563c361a081815132206515d0018195b0b55312a2601472675220310134c4b6231206514161037563c361a081815132206515d0018195b0b55312a2601472675220310134c4b6231206514161037563c361a081815132206515d0018195b0b55312a2601472675220310134c4b6231206514161037563c361a081815132206515d0018195b0b55312a2601472675220310'
enc = bytes.fromhex(s)
pas = b"VKU Security Lab - VSL"
print(xor(enc, pas))
```

## 404
![image](https://hackmd.io/_uploads/S1-7IWVPJx.png)
Bài này chỉ đơn giản là thực hiện phép cộng giữa `offset c` và `offset a`, sau đó đem `XOR` với `0xA9` và lưu lại vào `offset c`

```py=
c = [0xF1, 0xF5, 0xF8, 0xD7, 0x95, 0xE9, 0x91, 0xCE, 0xC4, 0x95, 
  0x93, 0x9A, 0x90, 0xCE, 0x91, 0xC1, 0xCE, 0xD9, 0xCF, 0x94, 
  0xCA, 0xCF, 0xC0, 0xC4, 0xD9, 0xCE, 0x91, 0x92, 0x9E, 0xC2, 
  0xC0, 0xC6, 0xEB, 0xCD, 0x9F, 0xCD, 0x2D]

a = [0x02, 0x09, 0x05, 0x03, 0x0A, 0x07, 0x08, 0x01, 0x09, 0x04, 
  0x02, 0x02, 0x03, 0x01, 0x08, 0x07, 0x03, 0x0A, 0x02, 0x0A, 
  0x01, 0x05, 0x08, 0x0A, 0x0A, 0x06, 0x05, 0x04, 0x03, 0x07, 
  0x05, 0x09, 0x09, 0x01, 0x06, 0x02, 0x07]

key = 0xa9

for i in range(len(c)):
    flag = (c[i] ^ key) - a[i]
    print(chr(flag), end='')
```

## MyBot
> An advanced chatbot application that I took the initiative to create on my own, meticulously crafting every feature to align perfectly with my personal requirements and aspirations.

Mình khá tiếc vì đã không làm được bài này
Mặc dù mình đã tìm được `secret key` dưới dạng là một chuỗi `sha1` nhưng mình lại không xem kĩ và không biết nó là `sha1`

![image](https://hackmd.io/_uploads/S1gd0bEwye.png)
Tài khoản để đăng nhập sẽ nằm ở phần `main_loginHandler` 
![image](https://hackmd.io/_uploads/ryR2AZ4PJg.png)
-> `admin/123456`

![image](https://hackmd.io/_uploads/SJeeJzEvke.png)
Khi nhập `flag` thì sẽ được yêu cầu nhập `secret key`

Tìm kiếm trong phần `main_sendMessageHandler` 
![image](https://hackmd.io/_uploads/S13H1fEv1e.png)
Chương trình gọi tới `main_chatBotRespone` với `secret key` sẽ là `main_secret` đã bị mã hóa `sha1`
![image](https://hackmd.io/_uploads/rJs9xMNvJx.png)
Sử dụng [CrackStation](https://crackstation.net/) -> `querty`
![image](https://hackmd.io/_uploads/HJfFgM4w1e.png)

![image](https://hackmd.io/_uploads/SJzxWM4Dyl.png)


## EasyRev
Đây là lần đầu mình gặp dạng này nên mình đã không tìm được hướng giải quyết cho bài này
Thử thách này là `nuitka`, là một trình biên dịch Python sang mã máy. Vì vậy mà khi phân tích bằng `IDA` thì sẽ không tìm thấy được mã nguồn của nó

Tác giả có gợi ý `hexdump` nên mình đã sử dụng `HxD` để kiểm tra. Tuy nhiên nếu mình kiên nhẫn thì đã có thể tìm ra
![image](https://hackmd.io/_uploads/HyzrtMEw1l.png)
Phần này yêu cầu ta nhập vào `flag`
Sau đó `flag` sẽ được so sánh với giá trị của phép `XOR` giữa `XOR_KEY` và `encoded_flag`

```py=
from pwn import *
xor_key = bytes.fromhex('1bbd886460827015e5d605ed44252251')
encoded_flag = bytes.fromhex('4D EE C4 1F 02 E6 43 22 DC E4 31 8E 7C 10 14 61 7D 8F B9 05 59 B3 49 20 84 E0 64 D4 20 10 1B 30 7A DC BB 5D 1D')
print(xor(xor_key, encoded_flag))
```

## Atomix
**Công cụ ở đây mình dùng là IDA**

![image](https://hackmd.io/_uploads/HkUVm9mvJx.png)
Tìm trong `main_loginHandler` chúng ta có được tài khoản để đăng nhập
```c=
void __golang main_loginHandler(net_http_ResponseWriter w, net_http_Request *r)
{
  .........
  if ( &byte_7EA4E6 == (const uint8 *)5
    && (v16 = v46, *(_DWORD *)v46 == 'imda')
    && v46[4] == 'n'
    && &byte_7EA4EE == (const uint8 *)0xB
    && (*(_QWORD *)&v6[8] = 'drowssap', *(_QWORD *)v15 == 'drowssap')
    && *(_WORD *)(v15 + 8) == '21'
    && *(_BYTE *)(v15 + 10) == '3' )
  {
    ..........
  }
  else
  {
    v52 = *((_QWORD *)&v4 + 1);
    v53 = v4;
    v54 = v4;
    v.len = (int)"Đăng Nhập - Atomix Nuclear Power Plant";
    v49 = 42LL;
    v50 = "Tên đăng nhập hoặc mật khẩu không chính xác.";
    v51 = 58LL;
    v72.str = (uint8 *)&byte_7E79AB;
    v72.len = 5LL;
    html_template_New(v72, (html_template_Template *)"Tên đăng nhập hoặc mật khẩu không chính xác.");
    ..........
  }
}
```
--> `admin/password123`

Sau khi đăng nhập vào, ta cần điều chỉnh các lò phản ứng cho phù hợp để có thể lấy được flag
![image](https://hackmd.io/_uploads/BkMqEcQv1x.png)
![image](https://hackmd.io/_uploads/SkA5Vqmvke.png)

Mình tìm được trạng thái của các lò lần lượt là `Medium`, `High`, `Low`, `Medium`, `High`, `Low` tương ứng từ 1 -> 6
![image](https://hackmd.io/_uploads/ryhupc7Dyx.png)


Các thông số còn lại sẽ được tạo ở phần `main_init`
```c=
// main.init
void __golang main_init()
{
  ..........
  main_sessions = v7;
  runtime_makemap_small((runtime_hmap_0 *)v7);
  h = v9;
  runtime_mapassign_fast64((internal_abi_MapType *)&RTYPE_map_int_float64, v9, 1uLL, v3);
  *v10 = _f64_407f400000000000;
  runtime_mapassign_fast64((internal_abi_MapType *)&RTYPE_map_int_float64, h, 2uLL, v3);
  *v11 = _f64_4087700000000000;
  runtime_mapassign_fast64((internal_abi_MapType *)&RTYPE_map_int_float64, h, 3uLL, v3);
  *v12 = _f64_406f400000000000;
  runtime_mapassign_fast64((internal_abi_MapType *)&RTYPE_map_int_float64, h, 4uLL, v3);
  *v13 = _f64_4082c00000000000;
  runtime_mapassign_fast64((internal_abi_MapType *)&RTYPE_map_int_float64, h, 5uLL, v3);
  *v14 = _f64_4089000000000000;
  runtime_mapassign_fast64((internal_abi_MapType *)&RTYPE_map_int_float64, h, 6uLL, v3);
  *v15 = _f64_4072c00000000000;
  if ( *(_DWORD *)&runtime_writeBarrier.enabled )
  {
    runtime_gcWriteBarrier2();
    v16 = (hash<int_comma_float64> *)h;
    *v17 = h;
    v17[1] = (runtime_hmap_0 *)main_energyMap;
  }
  else
  {
    v16 = (hash<int_comma_float64> *)h;
  }
  main_energyMap = v16;
  runtime_makemap_small((runtime_hmap_0 *)v16);
  ha = v18;
  runtime_mapassign_fast64((internal_abi_MapType *)&RTYPE_map_int_float64, v18, 1uLL, v3);
  *v19 = _f64_4000000000000000;
  runtime_mapassign_fast64((internal_abi_MapType *)&RTYPE_map_int_float64, ha, 2uLL, v3);
  *v20 = _f64_4008000000000000;
  runtime_mapassign_fast64((internal_abi_MapType *)&RTYPE_map_int_float64, ha, 3uLL, v3);
  *v21 = _f64_3ff0000000000000;
  runtime_mapassign_fast64((internal_abi_MapType *)&RTYPE_map_int_float64, ha, 4uLL, v3);
  *v22 = _f64_4004000000000000;
  runtime_mapassign_fast64((internal_abi_MapType *)&RTYPE_map_int_float64, ha, 5uLL, v3);
  *v23 = _f64_400c000000000000;
  runtime_mapassign_fast64((internal_abi_MapType *)&RTYPE_map_int_float64, ha, 6uLL, v3);
  *v24 = _f64_3ff8000000000000;
  if ( *(_DWORD *)&runtime_writeBarrier.enabled )
  {
    runtime_gcWriteBarrier2();
    v25 = (hash<int_comma_float64> *)ha;
    *v26 = ha;
    v26[1] = (runtime_hmap_0 *)main_pressureMap;
  }
  else
  {
    v25 = (hash<int_comma_float64> *)ha;
  }
  main_pressureMap = v25;
  runtime_makemap_small((runtime_hmap_0 *)v25);
  hb = v27;
  runtime_mapassign_fast64((internal_abi_MapType *)&RTYPE_map_int_float64, v27, 1uLL, v3);
  *v28 = _f64_4054000000000000;
  runtime_mapassign_fast64((internal_abi_MapType *)&RTYPE_map_int_float64, hb, 2uLL, v3);
  *v29 = _f64_4059000000000000;
  runtime_mapassign_fast64((internal_abi_MapType *)&RTYPE_map_int_float64, hb, 3uLL, v3);
  *v30 = _f64_404e000000000000;
  runtime_mapassign_fast64((internal_abi_MapType *)&RTYPE_map_int_float64, hb, 4uLL, v3);
  *v31 = _f64_4056800000000000;
  runtime_mapassign_fast64((internal_abi_MapType *)&RTYPE_map_int_float64, hb, 5uLL, v3);
  *v32 = _f64_405b800000000000;
  runtime_mapassign_fast64((internal_abi_MapType *)&RTYPE_map_int_float64, hb, 6uLL, v3);
  *v33 = _f64_4051800000000000;
  if ( *(_DWORD *)&runtime_writeBarrier.enabled )
  {
    runtime_gcWriteBarrier2();
    v34 = (hash<int_comma_float64> *)hb;
    *v35 = hb;
    v35[1] = (runtime_hmap_0 *)main_massMap;
  }
  else
  {
    v34 = (hash<int_comma_float64> *)hb;
  }
  main_massMap = v34;
  runtime_makemap_small((runtime_hmap_0 *)v34);
  hc = v36;
  runtime_mapassign_fast64((internal_abi_MapType *)&RTYPE_map_int_float64, v36, 1uLL, v3);
  *v37 = _f64_4062c00000000000;
  runtime_mapassign_fast64((internal_abi_MapType *)&RTYPE_map_int_float64, hc, 2uLL, v3);
  *v38 = _f64_4069000000000000;
  runtime_mapassign_fast64((internal_abi_MapType *)&RTYPE_map_int_float64, hc, 3uLL, v3);
  *v39 = _f64_4059000000000000;
  runtime_mapassign_fast64((internal_abi_MapType *)&RTYPE_map_int_float64, hc, 4uLL, v3);
  *v40 = _f64_4065e00000000000;
  runtime_mapassign_fast64((internal_abi_MapType *)&RTYPE_map_int_float64, hc, 5uLL, v3);
  *v41 = _f64_406c200000000000;
  runtime_mapassign_fast64((internal_abi_MapType *)&RTYPE_map_int_float64, hc, 6uLL, v3);
  *v42 = _f64_405f400000000000;
  if ( *(_DWORD *)&runtime_writeBarrier.enabled )
  {
    runtime_gcWriteBarrier2();
    v43 = (hash<int_comma_float64> *)hc;
    *v44 = hc;
    v44[1] = (runtime_hmap_0 *)main_temperatureMap;
  }
  else
  {
    v43 = (hash<int_comma_float64> *)hc;
  }
  main_temperatureMap = v43;
}
```

Các thông số lần lượt là 
`main_energyMap`, `main_pressureMap`, `main_massMap` và `main_temperatureMap`

Để tìm được các giá trị trên chúng ta cần hiểu về cách biểu diễn số thực dấu phẩy động trên máy tính
Ta có các giá trị ở đây là số dấu phẩy động 64-bit (double precision)
![image](https://hackmd.io/_uploads/HktM26QD1l.png)
Ví dụ với giá trị: `407F400000000000h`
Chuyển sang nhị phân: 
```0 
0 10000000111 1111010000000000000000000000000000000000000000000000
bit đầu sẽ là bit dấu (Sign)
-> S = 0
11 bits số mũ tiếp theo (Exponent)
-> E = 10000000111
52 bits phần định trị (Mantissa): biểu diễn giá trị phần sau dấu phẩy
-> M = 1111010000000000000000000000000000000000000000000000
```
![image](https://hackmd.io/_uploads/H1IssTQPJe.png)
Sau khi biến đổi sang nhị phân ta sẽ chuyển đổi theo công thức như trên hình

* E != 0 -> $(-1)^S*(1+M)*2^{E-1023}$
* E == 0 -> $(-1)^S*M*2^{-1022}$

```0
Trước tiên chuyển E và M về thập phân:
E = 1031
M = 0.953125 

Vì E != 0 -> Value = 500.0
```

Ở đây mình chỉ giải thích để cho các bạn hiểu đại khái về cách biểu diễn số thực dấu phẩy động
Thay vì tính toán như trên thì ta chỉ cần dùng `struct` trong python

```python=
import struct

def hex_to_float(hex_str):
    byte_data = bytes.fromhex(hex_str)
    return struct.unpack('>d', byte_data)[0]

energyMap = [
    '407f400000000000',
    '4087700000000000',
    '406f400000000000',
    '4082c00000000000',
    '4089000000000000',
    '4072c00000000000'
]

pressureMap = [
    '4000000000000000',
    '4008000000000000',
    '3ff0000000000000',
    '4004000000000000',
    '400c000000000000',
    '3ff8000000000000'
]

massMap = [
    '4054000000000000',
    '4059000000000000',
    '404e000000000000',
    '4056800000000000',
    '405b800000000000',
    '4051800000000000'
]

temperatureMap = [
    "4062c00000000000", 
    "4069000000000000", 
    "4059000000000000", 
    "4065e00000000000", 
    "406c200000000000", 
    "405f400000000000"  
]

for i in range(len(energyMap)):
    print(f'Lo phan ung {i+1}: ')
    print(hex_to_float(temperatureMap[i]))
    print(hex_to_float(massMap[i]))
    print(hex_to_float(pressureMap[i]))
    print(hex_to_float(energyMap[i]))
    print('\n')
```

Đến đây ta chỉ cần điền giá trị và nhận phần thưởng của mình

![image](https://hackmd.io/_uploads/ry3xUAmDyg.png)
![image](https://hackmd.io/_uploads/HyKmLA7P1e.png)

## MyNote
> I’m working on developing my personal note-storage application, but I’ve run into an issue where I can’t log in, even though I’m sure the username and password are correct. It seems like the secret key for the app might be stored somewhere, and I need to figure out how to retrieve it. All I remember is that the email used for the account is bin.cracker@reverselab.dev, and the password was once exposed on GitHub. Can you help me recover the secret key?

