MASTG-DEMO-0134: Custom URL Scheme Handler Without Input Validation
Download MASTG-DEMO-0134 IPA Open MASTG-DEMO-0134 Folder Build MASTG-DEMO-0134 IPA
Sample¶
The app registers a custom URL scheme (mastgtest://).
The URL handler reads a query parameter value from URLs targeting the transfer action and uses it directly as a string without converting it to a numeric type or checking its value against any bounds. Any app on the device can open a URL such as mastgtest://transfer?amount=9999999, and the handler will accept the supplied value and use it in the transfer flow without validating that it is a valid, bounded amount.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | |
Steps¶
- Use Exploring the App Package to extract the relevant binaries from the app package, which in this case is
./Payload/MASTestApp.app/MASTestApp. - Use Static Analysis on iOS to locate the URL handler and check for input validation. Run the r2 script with the
-ioption.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | |
1 2 | |
Observation¶
The output shows the handleURL method symbol, an empty result for Int conversion references, the onOpenURL registration, and focused disassembly of the handler covering URL parsing and query value extraction.
| output.txt | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | |
Evaluation¶
The test case fails because the handler uses the URL query value directly without any type conversion or bounds checking. The disassembly reveals the following flow:
- At
0x100004348, the handler callsURLComponents.init(url:resolvingAgainstBaseURL:)to parse the incoming URL. - At
0x10000434c, it callsURL.hostto read the URL host, which represents the action, and compares it against the"transfer"string literal loaded at0x1000043ac. - At
0x100004510, it callsURLQueryItem.valueto extract the rawString?value from a query item. - At
0x100004538, acbzinstruction checks whether the value isnil. Ifnil, the fallback"0"string literal is loaded at0x100004550. If nonnil, the raw string value is used as is. - At
0x100004594, the value (either the raw string or the"0"fallback) is passed directly toDefaultStringInterpolation.initto build the"Transferring ... units"output string at0x1000045a4.
Between URLQueryItem.value (0x100004510) and DefaultStringInterpolation (0x100004594) there is no call to Int.init or any other visible type conversion or validation function. This is further confirmed by the empty === References to Int conversion (input validation) === section. The handler therefore accepts an arbitrary string value from the URL query and uses it directly in the transfer related output, instead of validating that the value is numeric and within an expected range.
Exploitation¶
You can use xcrun to launch the app on a connected iOS device with an arbitrary custom URL scheme payload.
First, list the connected devices and copy the device identifier:
xcrun devicectl list devices
Then launch the app with a crafted mastgtest:// URL:
xcrun devicectl device process launch \
--device <DEVICE_IDENTIFIER> \
--payload-url "mastgtest://transfer?amount=9999999" \
org.owasp.mastestapp.MASTestApp-iOS
After the app opens, tap Start in the demo app to process the stored URL. The result is observable in the app output:
Transferring 9999999 units
Repeat the command with a non-numeric value:
xcrun devicectl device process launch \
--device <DEVICE_IDENTIFIER> \
--payload-url "mastgtest://transfer?amount=not-a-number" \
org.owasp.mastestapp.MASTestApp-iOS
After tapping Start, the app output shows:
Transferring not-a-number units
This confirms at runtime that the handler accepts attacker-controlled URL input and uses it directly in the transfer output without numeric conversion or bounds checking.