In this Sherlock challenge, players will investigate an Android data dump and reverse-engineer a malicious APK to uncover the malware’s functionality and identify what data was stolen.
A phishing SMS pointed the victim at a fake banking app. Chrome downloaded the APK and the victim sideloaded it roughly 43 minutes after the message arrived. The app was granted a handful of runtime permissions, SMS among them, and used the SMS read operation within minutes of the download. Static analysis of the APK’s dex string table showed it checking a hard-coded HTTP server for liveness before posting harvested data, with a Discord webhook held as the fallback. Payloads were AES-encrypted with a key embedded in the app, so the same strings decrypted the captured traffic and exposed the stolen payment card details.
HookFlare.dd → ext4 image. Pull the data tree out with debugfs, then read the SQLite databases with sqlite3 and the XML state files with a text editorHookFlare.pcap → tshark/data/app → no decompiler needed, the classes.dex string table gives up the URLs and the keyTimestamp note: Android stores times as epoch milliseconds and Chrome uses its own epoch. Convert everything to UTC and drop the milliseconds before answering in
YYYY-MM-DD hh:mm:ss.
Extract the userdata tree from the image, then open the telephony provider database mmssms.db. The sms table holds one inbound message from 14356951192 carrying the lure link. Its date column is epoch milliseconds (1738426832000), which converts to the answer in UTC.
debugfs -R "rdump /android-9.0-r2/data work/x" evidence/HookFlare.dd
sqlite3 mmssms.db "select address, date, body from sms"
Gotcha:
rdumpon ext4 prints a pile ofchownerrors when run unprivileged. The files are still extracted.
The lure led to a browser download, so the Chrome History database is the artifact. In the downloads table, the S1rBank.apk row carries a start_time that converts to the answer, about 43 minutes after the SMS from Q1.
sqlite3 History "select target_path, start_time from downloads"
Gotcha: The Android download manager’s
downloads.dbshows alastmodtwo seconds later. The question asks when the download started, so Chrome’sstart_timeis the one that matches.
A sideloaded app leaves a directory under /data/app named after its package, and the same name appears in the package manager state. That ties it to the S1rBank.apk download from Q2.
ls work/x/data/app
Search runtime-permissions.xml for the Q3 package. The entry lists each runtime permission with a granted flag; count the ones set to true.
grep -A12 s1rbank runtime-permissions.xml
appops.xml records per-package app-op usage. Under the Q3 package, op 14 is the SMS read operation. Its tt attribute (last access time) is 1738429638041, which converts to the answer, about four minutes after the download started.
grep -A20 s1rbank appops.xml
Without a decompiler, a small Python parser over classes.dex dumps the string table, and the URLs stand out. The capture confirms the choice: the infected phone POSTs to /api/data on s1rbank.net over port 80.
python3 -I dexstr.py classes.dex | grep -i http
tshark -r HookFlare.pcap -Y http.request -T fields -e http.request.method -e http.host -e http.request.uri
The same tshark listing from Q6 shows a lightweight request to the server ahead of each exfiltration POST. That request is the liveness probe.
tshark -r HookFlare.pcap -Y http.request -T fields -e frame.time -e http.request.method -e http.request.uri
The dex string dump holds a second endpoint beside the primary one: a Discord webhook. The fallback never shows in the capture because the primary server answered the probe, so the APK is the only place it appears.
python3 -I dexstr.py classes.dex | grep -i discord
The POST bodies in the capture are opaque, but the dex strings contain a 32-character key-like string, the right length for AES-256. That reasoning is the evidence here: the key was picked by length and then proven by use, not read from a labelled field. Trying it as an AES-256-ECB key against the POST bodies (base64-decoded, then hex-decoded) produced readable text on the first attempt, which confirms both the key and the scheme.
python3 -I dexstr.py classes.dex | awk 'length($0)==32'
Tip: The answer’s format mask is 32 characters wide. Next to an app that encrypts its traffic, that points straight at AES-256.
Pull the first captured POST body and decrypt it with the Q9 key. The plaintext is a multi-line block of payment details, and its second line is the card number line.
tshark -r HookFlare.pcap -Y 'http.request.method==POST' -T fields -e http.file_data
| Phase | Action |
|---|---|
| Initial Access | Phishing SMS delivers a link to a fake banking app |
| Initial Access | Chrome downloads S1rBank.apk |
| Execution | App installed as com.s1rx58.s1rbank and granted four runtime permissions |
| Collection | App performs an SMS read about four minutes after the download starts |
| Command and Control | App probes s1rbank.net with HEAD before sending data |
| Exfiltration | AES-encrypted payloads POSTed to /api/data; Discord webhook held as fallback |
| Collection | Payment card details harvested and sent |
| Type | Value |
|---|---|
| Package | com.s1rx58.s1rbank |
| File | S1rBank.apk |
| Phishing sender | 14356951192 |
| URL (primary) | hxxp[://]s1rbank[.]net:80/api/data |
| URL (fallback) | hxxps[://]discord[.]com/api/webhooks/1334648260610097303/-Lkxr0eZRO_fb_SaumBbBMZyANM3lyeCkR-E1NXXRASPbtRdNksQSzx4pY1ZGQkFR2H8 |
| AES key | 0x_S1r_x58!@#53cuReK371337!$%^&* |
| Technique | ID | Description |
|---|---|---|
| Phishing | T1660 | Smishing message with a link to the fake banking app |
| Protected User Data: SMS Messages | T1636.004 | App uses the SMS read operation after install |
| Application Layer Protocol: Web Protocols | T1437.001 | HEAD and POST to the C2 over HTTP |
| Fallback Channels | T1008 | Discord webhook used when the primary server is down |
| Encrypted Channel: Symmetric Cryptography | T1521.001 | AES-256-ECB with a hard-coded key |
| Exfiltration Over C2 Channel | T1646 | Stolen data POSTed to /api/data |
| Exfiltration Over Webhook | T1567.004 | Discord webhook as the alternate exfiltration path |
Sideloading from a browser download should be blocked or flagged. The app arrived as an APK fetched by Chrome from an SMS link. Blocking installs from unknown sources, or alerting on them through mobile device management, removes the whole delivery path.
An SMS read by a freshly installed banking app is a red flag. The app used the SMS read operation within minutes of the download. Review permission grants on apps from outside the official store, and watch app-op usage for SMS access.
Cleartext HTTP exfiltration is visible even when the payload is encrypted. The HEAD-then-POST pattern to an unknown host on port 80 stands out in network logs. Egress filtering and DNS reputation would have flagged it.
Hard-coded keys make the encryption worthless against the responder. The AES key sat in the dex strings, so the whole stolen payload was recoverable from a packet capture. The same strings expose fallback infrastructure such as the Discord webhook, which can be reported for takedown.
A single smishing link put a fake banking app on the phone, and payment card data left it within minutes. Because the app’s key and both exfiltration endpoints sat in its strings, the APK plus a packet capture were enough to reconstruct exactly what was stolen.