This is a barebones writeup of the Disobey 2023 hacker badge challenge and the journey to solve it
General chain of breadcrumbs
- Twitter post that kouvosto telecom has made some opsec mistakes
- Google queries, find Seppo Aapakka as a kt employee
- Find seppo’s FB posts and the saboten group aka saboten biomedical
- Find the MRI image
- Read the barcodes on the image / find the tweet from saboten biomedical
- Go to saboten.kouvostotele.com and find the correct firmware binary
- Realize that the correct stuff to reverse engineer is the last 64kb of the binary
- Reverse the x86 real mode stuff, get new url
- Fetch the invoice pdf from files.kouvostotele.com
- Notice the forensics.uxin.fi link and go there
- Notice the news about secure-files.uxin.fi
- Figure out a way to access that virtual host
- Find secure-files.uxin.fi/backup/users/timi/.git
- Retrieve the whole git repository
- Find the private gpg key from the repository
- Crack the password on the key
- Decrypt the secure uxin password file
- Use the http basic auth on secure-files.uxin.fi
- Use quic and http basic auth on secure-files.uxin.fi
- Get the iphone disk image
- Extract the iphone image with dar
- Dig around the image, find emails
- Get the packet capture from email attachments and the password from the email
- Analyze the packet capture, get the data submission domain name, DNS server, submission url and dns update key name and the key
- Do dynamic dns update on crunch.kt.3g.re domain and listen on port 80
- Get the “sensitive data”
- Base64 decode and hex decode and get the store link for the hacker badge
MRI picture
Aztec code
- Did some manipulation on the image, mainly adjusted the gamma curve to get the code to scan.
- Contents of the code are:
Saboten Biomedical
NX-H128 S/N 000000001
FCC ID: KRJFSICIIFJEIRKS
- Nothing really here, the FCC id just seems like random keyboard smashing
- EDIT: FCC ID is base32 for “TRY HARDER”
dotcode
- Getting this to work was little challenging, no image manipulation seemed to work.
- In the end I redrew the code by hand on another layer, and that worked
- We get a URL, lets go
ftp://saboten.kouvostotele.com/prod/sb-ihv/firmware/NX-H128/0-00-3.1/bin/bin.7z
Alternative route
After solving the challenge I was made aware that there was a alternative route to the next stage. That involved finding a tweet from the Saboten Biomedical user, which contains a link to the root of the ftp. Unless one has been able to scan at least one of the barcodes from the image this route requires finding the correct firmware image among all of the crap on the site.
ftp.saboten.kouvostotele.com
- A story .odt file and bunch of compressed firmware images
- Seems like that only the one pointed by the URL contains real data
- The file is a ELF, with bunch of extra data on the end
- Loading it into ghidra it is just freebsd “sleep” command
- There are some strings refering to PCI and A padding in the end
- Looking with binwalk entropy graph there is a entropy edge at almost the start of last 64kb of the file
- There are some interesting strings refering to credentials xored with A on the part
- file doesn’t recognize it
- After a while it seems to be real mode x86 binary, the special 16bit(ish) execution mode of a x86 used for initialization on boot
- Load it into ghidra and start digging in
- Parts of the program seem to be
- Initialize a heap allocator
- Enumerate pci devices and save their config registers
- Doesn’t look for PCI bridges and busses behind them, sloppy!
- Execute a function that fails to decompile initially, due to polymorphic code
- Use ghidras bytes window to patch the bytes, decompile and recreate the function
- Does some xors and copys, add the xor region as ghidra overlay
- xor the key mask and the checked input to get
ftp://kt:bl4de_runn3r@files.kouvostotele.com
files.kouvostotele.com
Only one pdf here, a invoice for iphone forensics done by https://forensics.uxin.fi
forensics.uxin.fi
- Browse the web and run ffuf on it
- Nothing hidden found on the main domain
- There is a news entry announcing
secure-files.uxin.fi
but that domain points to localhost
secure-files.uxin.fi
- Accessed by passing the “Host: secure-files.uxin.fi” header to requests to forensics.uxin.fi.
- Index is asking for http basic auth
- Start ffufing to see if there is anything to be found:
ffuf -w ~/wordlists/common.txt -H "Host: secure-files.uxin.fi" -u https://forensics.uxin.fi/FUZZ -fc 401
- Basic ffuf finds
backups/users
dir. - Construct a wordlist from all the names from the main uxin website
- We find
backups/users/timi/.git
- No directory listings enabled
- Get
.git/config
and then.git/refs/heads/master
- Start walking the objects with the aid of git cat-file
- Get the whole bare repository in this manner
- Later I found out that there would have been utilities like https://github.com/WangYihang/GitHacker
- Didn’t test the utilities myself, there weren’t that many objects to fetc
- Exploring the git timi made some mistakes with his gpg keys
- first commit has
.backup/public.key
that is actually a private key- it has a passphrase
- Try to crack it with john
- Success with rockyou wordlist, passphrase is
iloveyou!
- Success with rockyou wordlist, passphrase is
- there are some encrypted files in
.password_store
-
uxin/secure/timi.gpg
contains a high-entropy string- Works for the basic auth
-
- first commit has
Basic auth
curl -v -L -u "timi:{/w8P;;}aED,{8s$" -H "Host: secure-files.uxin.fi" https://forensics.uxin.fi/
- Has a UDP joke image in the root
- ffuf around and find another image
- Another UDP meme…
- Portscan the site for open udp ports, find nada
- Do some googling around, like “http udp” to see if there are any udp http clients around
- http/3 aka QUIC is UDP!
- try with browser, no dice
- wireshark packet capture reveals we need draft-27 - draft-29 support
- curl has experimental support for QUIC, not enabled by default…
- try and try and try to compile it from few different instructions, all using various git heads and written 1+ year ago…
- No dice, but find a docker container: https://github.com/yurymuski/curl-http3
- try and try and try to compile it from few different instructions, all using various git heads and written 1+ year ago…
- Get the index, a message telling us to analyze a iphone dump and a 3Gb 7z archive
- The docker curl gets only around 1Mb of data per invocation before the connection dies…
- Just try harder and wrap the curl into a loop with -m 3 to limit execution to 3 seconds and -C - to continue previous transfer
-
while ! curl -m 3 -C - --http3 -v -L -u "timi:{/w8P;;}aED,{8s$" -H "Host: secure-files.uxin.fi" https://forensics.uxin.fi/KT_Forensics_iPhone_image.7z --output KT_Forensics_iPhone_image.7z; do echo retrying; done
- Experiment with the timeout values to get the best performance out of your potato
- After one afternoon we have data to analyze!
-
- Just try harder and wrap the curl into a loop with -m 3 to limit execution to 3 seconds and -C - to continue previous transfer
iphone dump
- Heaps of data
- A mysterious dar extension for the filesystem image
- a nice article was found by google: https://abrignoni.blogspot.com/2020/03/so-you-have-dar-file.html by search “iphone dar forensics”
- extract the dar file with dar, doh
- Try APOLLO, get bunch of useless timeline stuff
- Try KAPE, can’t get it to execute at all
- Try iLeap, https://github.com/abrignoni/iLEAPP, not having high hopes
- Actually works and gives nice html to explore
- Only Whatsapp and mail have been really used on the phone
- Whatsapp messages have memes and story stuff
- Mail has few interesting messages
- iLeap only shows partial contents and not the attachments, but shows a GUID
- find that GUID on the extracted data with find
-
private/var/mobile/Library/Mail/CEAB6F3D-B8DC-47DD-863F-F21B818B0064/INBOX.imapmbox
is where the good stuff lies - More story stuff and also
lb.zip
and the password for it in the mail,hunteR2
- Additional digging around reveals that the checkra1n jailbreak/rootkit has been installed on the phone, in
private/var/checkra1n.dmg
- Probably used for creating the image
lb.zip
- The packet capture leads to
http://94.237.108.204/submit/
submissions are made with POST requests - Interesting ips:
- 94.237.108.204 - submission server and DNS server for kt.3g.re
- 53/tcp open domain (unknown banner: Kouvosto Telecom DNS server v0.01 beta - in scope)
- 94.237.109.63 - some host, SSH and 8089 open
- 94.237.108.204 - submission server and DNS server for kt.3g.re
- domain crunch.kt.3g.re is used for the data submission, has TTL of 2
- a dynamic update on that domain is done on the packet capture
- dynamic dns key name:
updatekey.
from packet capture- the dot is important for tools, needs to be fully qualified…
- if we could update it we could get a connection of the sensitive data…
- dynamic dns key name:
- Some tries with CVE-2017-3143 exploits, didn’t lead to anywhere…
- Things just didn’t work at all due to me not having the dot expected by the libraries in the key name…
- Was using the wrong hmac function at the start, needed to have sha512, had sha256
- But in the end the exploit didn’t seem to work, not sure if I had wrong payload sizes due to different hmac
- Took another look into the packet capture from a nudge of my sparring partner
- There is a kouvosto keyserver transaction hidden in the TCP control packets
- Wireshark → right click on packet → view flow → tcp FTW
- We have the update key
- There is a kouvosto keyserver transaction hidden in the TCP control packets
- Modify and hack the exploit PoC, get a working dns update
- do the dns update && sudo nc -l 80
- get the sensitive data from the field
Sensitive data
POST / HTTP/1.1
Host: crunch.kt.3g.re
User-Agent: Kouvosto Telecom sensitive data submission agent (military grade)
Transfer-Encoding: chunked
Content-Type: application/ktson
Accept-Encoding: gzip
379
{
"beacon_name": "chipper",
"beacon_ip_address": "172.16.104.32",
"beacon_model": "KVR-L200",
"beacon_firmware": "0.7.1b.83340",
"beacon_serial": "80860600021",
"beacon_location": "Saboten Biomaterial Factory #7",
"timestamp": 2718658601,
"meta_data":
{
"datatype": "KTBBD",
"version": "0.7a"
},
"events": [
{
"rssi": "-42",
"data": "aHR0cHM6Ly9ob2x2aS5jb20vc2hvcC9EaXNvYmV5L3Byb2R1Y3QvNTgyODkxZDU3YjcwZDEyOWYwN2NkZjJjNzNlMzg4NTMv",
"srData": "I29pc2pvaGFja2VyYmFkZ2U=",
"timestamp": 2718658599,
"device_ktid": "5468616e-6b20-796f-7520-666f72207472-79696e672068-617264657221"
},
{
"rssi": "-36",
"data": "SXQncyBkYW5nZXJvdXMgdG8gZ28gYWxvbmUhIEhlcmUsIHRha2UgdGhpczo=",
"timestamp": 2718658594,
"device_ktid": "5468616e-6b20-796f-7520-666f72207472-79696e672068-617264657221"
}
]
}
- Obvious base64 encoded stuff, also a quite obvious hex string
- Cyberchef to quickly process them
- It’s dangerous to go alone! Here, take this:
- https://holvi.com/shop/Disobey/product/582891d57b70d129f07cdf2c73e38853/
- #oisjohackerbadge
- “Thank you for trying harder!”
- Cyberchef to quickly process them
- Got there!
Feedback
- The start requiring selling ones soul to Zuckenberg sucks
- The QUIC part was made hard and annoying just by the lack of good easily available tools
- Finding the real binary and the correct offset in the firmware blob was annoying and required quesswork
- Little bummed out that the TSIG bypass exploit didn’t work, would have been nice different path on that part