8KSec - TrustFall
My solution for TrustFall iOS application exploitation challenge

8KSec - TrustFall
TrustFall is a secure iOS workspace app that uses deep linking to load trusted content inside an embedded browser. It claims to only open links from approved domains, but its defenses aren’t as strong as they seem. Direct access to untrusted domains is blocked unless you find a loophole.
1. Info.plist Investigation
After investigating the .plist file, the deeplink entry is trustfall://

2. Binaries Investigation
By investigate the binaries looking for some methods related to the deeplinking, the app is using onOpenURL method.

3. Reverse Engineering
After analyzing and searching, I found this method
void _$s9TrustFall11ContentViewV17handleIncomingURLyy10Foundation0G0VF which contains the following logic:
The app extracts a target URL from the deep link query parameters and passes it if either of the following conditions is met:
URL.absoluteString.hasPrefix("https://8ksec.io")URL.host.contains("8ksec.io")

/* WARNING: Removing unreachable block (ram,0x00009634) */
void _$s9TrustFall11ContentViewV17handleIncomingURLyy10Foundation0G0VF
(undefined8 param_1,long param_2)
{
byte *pbVar1;
int iVar2;
undefined1 *puVar3;
code *pcVar4;
undefined *puVar5;
long lVar6;
char *pcVar7;
long lVar8;
ulong uVar9;
char **ppcVar10;
long lVar11;
undefined8 *puVar12;
undefined8 *puVar13;
undefined8 uVar14;
long extraout_x8;
long extraout_x8_00;
long unaff_x20;
undefined1 auStack_400 [12];
uint local_3f4;
undefined1 *local_3f0;
undefined1 *local_3e8;
undefined8 local_3e0;
uint local_3d4;
long local_3d0;
undefined8 local_3c8;
char *local_3c0;
char **local_3b8;
undefined8 *local_3b0;
undefined8 local_3a8;
undefined8 local_3a0;
undefined8 local_398;
uint local_38c;
char **local_388;
ulong *local_380;
uint local_374;
uint local_370;
uint local_36c;
ulong local_368;
long local_360;
ulong local_358;
long local_350;
long local_348;
long local_340;
long local_338;
uint local_32c;
long local_328;
long local_320;
long local_318;
long local_310;
long local_308;
long local_300;
long local_2f8;
long local_2f0;
long local_2e8;
long local_2e0;
long local_2d8;
long local_2d0;
undefined *local_2c8;
long local_2c0;
long local_2b8;
long local_2b0;
long local_2a8;
undefined4 local_29c;
long local_298;
long local_290;
uint local_284;
undefined8 local_280;
char *local_278;
long local_270;
undefined8 local_268;
long *local_260;
uint local_258;
uint local_254;
char *local_250;
long local_248;
undefined8 *local_240;
long local_238;
uint local_22c;
undefined8 local_228;
char *local_220;
undefined8 *local_218;
undefined8 *local_210;
undefined8 *local_208;
uint local_200;
uint local_1fc;
undefined8 local_1f8;
long local_1f0;
undefined *local_1e8;
ulong local_1e0;
undefined1 *local_1d8;
ulong local_1d0;
long local_1c8;
ulong local_1c0;
long local_1b8;
ulong local_1b0;
long local_1a8;
long local_1a0;
long local_198;
ulong local_190;
long local_188;
ulong local_180;
long local_178;
undefined8 local_138;
undefined8 *local_130;
undefined8 local_128;
undefined8 local_120;
char *local_118;
undefined8 local_110;
ulong local_108;
long local_100;
byte local_f1;
char *local_f0;
undefined8 local_e8;
undefined8 local_e0;
undefined8 local_d8;
undefined8 local_d0;
undefined1 local_c1;
undefined1 local_c0 [8];
undefined8 local_b8;
undefined1 local_aa;
byte local_a9;
long local_a8;
long local_a0;
long local_98;
long local_90;
long local_88;
undefined8 *local_80;
char *local_78;
long local_70;
undefined8 local_68;
long local_60;
char *local_58;
undefined8 *local_50;
undefined8 local_48;
undefined8 local_40;
long local_38;
local_38 = 0;
local_40 = 0;
local_48 = 0;
local_90 = 0;
local_1f0 = 0;
local_a8 = 0;
local_a0 = 0;
puVar5 = &_$s7SwiftUI5StateVy10Foundation3URLVSgGMD;
local_1f8 = param_1;
___swift_instantiateConcreteTypeFromMangledName();
local_1e0 = *(long *)(*(long *)(puVar5 + -8) + 0x40) + 0xfU & 0xfffffffffffffff0;
local_1e8 = puVar5;
(*(code *)PTR____chkstk_darwin_000180e0)();
lVar11 = -local_1e0;
puVar5 = &_$s10Foundation3URLVSgMD;
local_1d8 = auStack_400 + lVar11;
___swift_instantiateConcreteTypeFromMangledName();
local_1d0 = *(long *)(*(long *)(puVar5 + -8) + 0x40) + 0xfU & 0xfffffffffffffff0;
(*(code *)PTR____chkstk_darwin_000180e0)();
lVar11 = (long)(auStack_400 + lVar11) - local_1d0;
local_1c0 = extraout_x8 + 0xfU & 0xfffffffffffffff0;
local_1c8 = lVar11;
(*(code *)PTR____chkstk_darwin_000180e0)();
lVar11 = lVar11 - local_1c0;
local_1b0 = extraout_x8_00 + 0xfU & 0xfffffffffffffff0;
local_1b8 = lVar11;
(*(code *)PTR____chkstk_darwin_000180e0)();
lVar11 = lVar11 - local_1b0;
lVar6 = 0;
local_1a8 = lVar11;
_$s10Foundation3URLVMa();
local_198 = *(long *)(lVar6 + -8);
local_190 = *(long *)(local_198 + 0x40) + 0xfU & 0xfffffffffffffff0;
local_1a0 = lVar6;
(*(code *)PTR____chkstk_darwin_000180e0)();
lVar11 = lVar11 - local_190;
puVar5 = &_$s10Foundation12URLQueryItemVSgMD;
local_188 = lVar11;
local_38 = lVar11;
___swift_instantiateConcreteTypeFromMangledName();
local_180 = *(long *)(*(long *)(puVar5 + -8) + 0x40) + 0xfU & 0xfffffffffffffff0;
(*(code *)PTR____chkstk_darwin_000180e0)();
lVar11 = lVar11 - local_180;
puVar5 = &_$s10Foundation13URLComponentsVSgMD;
local_178 = lVar11;
___swift_instantiateConcreteTypeFromMangledName();
lVar6 = *(long *)(*(long *)(puVar5 + -8) + 0x40);
(*(code *)PTR____chkstk_darwin_000180e0)(unaff_x20);
lVar11 = lVar11 - (lVar6 + 0xfU & 0xfffffffffffffff0);
local_40 = param_1;
_$s10Foundation3URLV6schemeSSSgvg();
_swift_bridgeObjectRetain();
pcVar7 = "trustfall";
puVar12 = (undefined8 *)((long)&mach_header_00000000.cpusubtype + 1);
_$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC("trustfall",9,1);
_swift_bridgeObjectRetain();
local_68 = param_1;
local_60 = param_2;
local_58 = pcVar7;
local_50 = puVar12;
if (param_2 == 0) {
puVar13 = puVar12;
if (puVar12 != (undefined8 *)0x0) goto LAB_00009070;
_$sSSSgWOh(&local_68);
local_1fc = 1;
}
else {
puVar13 = &local_138;
_$sSSSgWOc(&local_68);
if (local_50 == (undefined8 *)0x0) {
_$sSSWOh(&local_138);
LAB_00009070:
_$sSSSg_AAtWOh(&local_68);
local_1fc = 0;
}
else {
local_228 = local_138;
local_210 = local_130;
_swift_bridgeObjectRetain();
local_208 = &local_68;
local_220 = local_58;
local_218 = local_50;
_swift_bridgeObjectRetain();
uVar14 = local_228;
puVar13 = local_210;
_$sSS2eeoiySbSS_SStFZ(local_228,local_210,local_220,local_218);
local_200 = (uint)uVar14;
_swift_bridgeObjectRelease(local_218);
_swift_bridgeObjectRelease(local_210);
_swift_bridgeObjectRelease(local_218);
_swift_bridgeObjectRelease(local_210);
_$sSSSgWOh(local_208);
local_1fc = local_200;
}
}
local_22c = local_1fc;
_swift_bridgeObjectRelease(puVar12);
_swift_bridgeObjectRelease();
if ((local_22c & 1) == 0) {
return;
}
_$s10Foundation3URLV4hostSSSgvg();
local_248 = param_2;
local_240 = puVar13;
_swift_bridgeObjectRetain();
pcVar7 = "open";
lVar6 = 4;
_$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC("open",4,1);
local_250 = pcVar7;
local_238 = lVar6;
_swift_bridgeObjectRetain();
local_88 = local_248;
local_80 = local_240;
local_78 = local_250;
local_70 = local_238;
if (local_240 == (undefined8 *)0x0) {
if (local_238 == 0) {
_$sSSSgWOh(&local_88);
local_254 = 1;
goto LAB_000091bc;
}
}
else {
_$sSSSgWOc(&local_88,&local_128);
if (local_70 != 0) {
local_280 = local_128;
local_268 = local_120;
_swift_bridgeObjectRetain();
local_278 = local_78;
local_260 = &local_88;
local_270 = local_70;
_swift_bridgeObjectRetain();
uVar14 = local_280;
_$sSS2eeoiySbSS_SStFZ(local_280,local_268,local_278,local_270);
local_258 = (uint)uVar14;
_swift_bridgeObjectRelease(local_270);
_swift_bridgeObjectRelease(local_268);
_swift_bridgeObjectRelease(local_270);
_swift_bridgeObjectRelease(local_268);
_$sSSSgWOh(local_260);
local_254 = local_258;
goto LAB_000091bc;
}
_$sSSWOh(&local_128);
}
_$sSSSg_AAtWOh(&local_88);
local_254 = 0;
LAB_000091bc:
local_284 = local_254;
_swift_bridgeObjectRelease(local_238);
_swift_bridgeObjectRelease(local_240);
if ((local_284 & 1) != 0) {
local_29c = 1;
_$s10Foundation13URLComponentsV3url23resolvingAgainstBaseURLACSgAA0G0Vh_SbtcfC
(lVar11,local_1f8,0);
lVar8 = 0;
_$s10Foundation13URLComponentsVMa();
local_290 = *(long *)(lVar8 + -8);
lVar6 = lVar11;
local_298 = lVar8;
(**(code **)(local_290 + 0x30))(lVar11,local_29c);
if ((int)lVar6 == 1) {
_$s10Foundation13URLComponentsVSgWOh(0,lVar11);
local_2a8 = 0;
}
else {
_$s10Foundation13URLComponentsV10queryItemsSayAA12URLQueryItemVGSgvg();
local_2b0 = lVar6;
(**(code **)(local_290 + 8))(lVar11,local_298);
local_2a8 = local_2b0;
}
lVar11 = local_1f0;
local_2b8 = local_2a8;
if (local_2a8 != 0) {
local_2c0 = local_2a8;
local_2d0 = local_2a8;
local_90 = local_2a8;
local_98 = local_2a8;
puVar5 = &_$sSay10Foundation12URLQueryItemVGMD;
___swift_instantiateConcreteTypeFromMangledName();
local_2c8 = puVar5;
_$sSay10Foundation12URLQueryItemVGSayxGSTsWl();
_$sSTsE5first5where7ElementQzSgSbADKXE_tKF
(local_178,
_$s9TrustFall11ContentViewV17handleIncomingURLyy10Foundation0G0VFSbAE12URLQueryItem VXEfU_
,0,local_2c8,puVar5);
if (lVar11 != 0) {
/* WARNING: Does not return */
pcVar4 = (code *)SoftwareBreakpoint(1,0x98b0);
(*pcVar4)();
}
lVar6 = 0;
_$s10Foundation12URLQueryItemVMa();
local_2d8 = *(long *)(lVar6 + -8);
lVar8 = 1;
lVar11 = local_178;
local_2e0 = lVar6;
(**(code **)(local_2d8 + 0x30))();
if ((int)lVar11 == 1) {
_$s10Foundation12URLQueryItemVSgWOh(0,local_178);
local_2f0 = 0;
local_2e8 = 0;
}
else {
_$s10Foundation12URLQueryItemV5valueSSSgvg();
local_300 = lVar11;
local_2f8 = lVar8;
(**(code **)(local_2d8 + 8))(local_178,local_2e0);
local_2f0 = local_300;
local_2e8 = local_2f8;
}
local_310 = local_2e8;
local_308 = local_2f0;
if (local_2e8 == 0) {
_swift_bridgeObjectRelease(local_2d0);
}
else {
local_320 = local_2f0;
local_318 = local_2e8;
local_328 = local_2e8;
local_a8 = local_2f0;
local_a0 = local_2e8;
_$s10Foundation3URLV6stringACSgSSh_tcfC(local_1a8);
lVar11 = local_1a8;
(**(code **)(local_198 + 0x30))(local_1a8,1,local_1a0);
if ((int)lVar11 == 1) {
_$s10Foundation3URLVSgWOh(0,local_1a8);
_swift_bridgeObjectRelease(local_328);
_swift_bridgeObjectRelease(local_2d0);
}
else {
lVar11 = local_188;
lVar6 = local_1a8;
(**(code **)(local_198 + 0x20))(local_188,local_1a8,local_1a0);
_$s10Foundation3URLV14absoluteStringSSvg();
local_32c = 0x142e0;
lVar8 = 0x10;
local_348 = lVar11;
local_338 = lVar6;
_$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC
("https://8ksec.io",0x10,1);
local_340 = lVar8;
_$sSS9hasPrefixySbSSF();
_swift_bridgeObjectRelease(local_340);
_swift_bridgeObjectRelease(local_338);
puVar3 = local_1d8;
uVar9 = (ulong)local_32c;
if ((local_32c & 1) == 0) {
_$s10Foundation3URLV4hostSSSgvg();
local_358 = uVar9;
local_350 = lVar8;
if (lVar8 == 0) {
local_36c = 2;
}
else {
local_380 = &local_108;
pcVar7 = "8ksec.io";
uVar14 = 8;
local_374 = 1;
local_368 = uVar9;
local_360 = lVar8;
local_108 = uVar9;
local_100 = lVar8;
_$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC("8ksec.io",8,1)
;
local_388 = &local_118;
local_118 = pcVar7;
local_110 = uVar14;
_$sS2SSysWl();
ppcVar10 = local_388;
_$sSy10FoundationE8containsySbqd__SyRd__lF
(local_388,PTR__$sSSN_000185f8,PTR__$sSSN_000185f8,pcVar7);
local_370 = (uint)ppcVar10;
_$sSSWOh(local_388);
_$sSSWOh(local_380);
local_36c = local_370 & local_374;
}
local_aa = (undefined1)local_36c;
local_a9 = 1;
iVar2 = (local_36c & 0xff) - 2;
if ((iVar2 == 0) || (_$sSbSgWOc(iVar2,&local_aa,&local_f1), local_a9 == 2)) {
local_38c = 0;
}
else {
local_38c = (uint)((local_f1 & 1) == (local_a9 & 1));
}
puVar3 = local_1d8;
if (local_38c != 0) {
(**(code **)(local_198 + 0x10))(local_1b8,local_188,local_1a0);
local_3d4 = 1;
(**(code **)(local_198 + 0x38))(local_1b8,0,1,local_1a0);
_$s7SwiftUI5StateVy10Foundation3URLVSgGWOc(unaff_x20,puVar3);
_$s10Foundation3URLVSgWOc(local_1b8,local_1c8);
_$s7SwiftUI5StateV12wrappedValuexvs(local_1c8,local_1e8);
_$s7SwiftUI5StateVy10Foundation3URLVSgGWOh(local_1d8);
_$s10Foundation3URLVSgWOh(local_1b8);
lVar11 = 0;
_$s9TrustFall11ContentViewVMa();
pbVar1 = (byte *)(unaff_x20 + *(int *)(lVar11 + 0x14));
local_3f4 = (uint)*pbVar1;
local_3e0 = *(undefined8 *)(pbVar1 + 8);
local_3d0 = lVar11;
_swift_retain();
_swift_retain(local_3e0);
local_3e8 = local_c0;
local_c0[0] = (undefined1)local_3f4;
local_b8 = local_3e0;
local_3f0 = &local_c1;
local_c1 = 1;
puVar5 = &_$s7SwiftUI5StateVySbGMD;
___swift_instantiateConcreteTypeFromMangledName(&_$s7SwiftUI5StateVySbGMD);
_$s7SwiftUI5StateV12wrappedValuexvs(local_3f0,puVar5);
_$s7SwiftUI5StateVySbGWOh(local_3e8);
_swift_release(local_3e0);
pcVar7 = "CTF{bad_url_sanitization}";
uVar14 = 0x19;
_$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC
("CTF{bad_url_sanitization}",0x19,local_3d4 & 1);
puVar12 = (undefined8 *)(unaff_x20 + *(int *)(local_3d0 + 0x18));
local_3c8 = *puVar12;
local_3a8 = puVar12[1];
local_3a0 = puVar12[2];
local_3c0 = pcVar7;
local_398 = uVar14;
_swift_bridgeObjectRetain();
_swift_retain(local_3a0);
_swift_bridgeObjectRetain(local_3a8);
_swift_retain(local_3a0);
local_3b0 = &local_e0;
local_e0 = local_3c8;
local_d8 = local_3a8;
local_d0 = local_3a0;
_swift_bridgeObjectRetain(local_398);
local_3b8 = &local_f0;
local_f0 = local_3c0;
local_e8 = local_398;
puVar5 = &_$s7SwiftUI5StateVySSSgGMD;
___swift_instantiateConcreteTypeFromMangledName(&_$s7SwiftUI5StateVySSSgGMD);
_$s7SwiftUI5StateV12wrappedValuexvs(local_3b8,puVar5);
_$s7SwiftUI5StateVySSSgGWOh(local_3b0);
_swift_bridgeObjectRelease(local_3a8);
_swift_release(local_3a0);
_swift_bridgeObjectRelease(local_398);
}
}
else {
(**(code **)(local_198 + 0x10))(local_1b8,local_188,local_1a0);
(**(code **)(local_198 + 0x38))(local_1b8,0,1,local_1a0);
_$s7SwiftUI5StateVy10Foundation3URLVSgGWOc(unaff_x20,puVar3);
_$s10Foundation3URLVSgWOc(local_1b8,local_1c8);
_$s7SwiftUI5StateV12wrappedValuexvs(local_1c8,local_1e8);
_$s7SwiftUI5StateVy10Foundation3URLVSgGWOh(local_1d8);
_$s10Foundation3URLVSgWOh(local_1b8);
}
(**(code **)(local_198 + 8))(local_188,local_1a0);
_swift_bridgeObjectRelease(local_328);
_swift_bridgeObjectRelease(local_2d0);
}
}
}
}
return;
}
4. Attack Execution
To trigger the exploit, we leverage flawed sanitization logic within the application's deep link handler. The application attempts to validate the target URL using a strict string prefix check, which can be bypassed using URL Basic Authentication syntax (RFC 3986).

Exploit Payload:
trustfall://open?url=https://8ksec.io@engbaselabutaleb.com
Execution Steps:
- The crafted payload is triggered on the target device by entering the URL directly into the Safari address bar and accepting the prompt to open the application.
- The application intercepts the custom scheme and parses the
urlparameter. - The internal validation logic evaluates the nested URL. The payload abuses the URI credential syntax (
user@host). Because the string explicitly begins withhttps://8ksec.io, the validation check passes. - When passed to the WebView, the network stack interprets
8ksec.ioas authentication credentials and routes the traffic directly to the attacker controlled host:engbaselabutaleb.com. - The application transitions into the trusted state, loading the external domain and successfully rendering the hidden flag in memory:
CTF{bad_url_sanitization}.