WSJT-X SuperFox Verification is flawed: Part 2
isomer reached out on Discord that they smelt something funny about the SuperFox verification system. They were investigating the system in hopes of creating an open source implementation. The usual red flags presented themselves - closed binaries, very few bits, hardcoded magics. I originally assumed this system was just using TOTP like some of the other dxpeditions in the past, but in a more automated / online fashion, but it seemed not.
I was in quite a bit of pain and struggling to sleep due to running a half marathon with patellofemoral pain syndrome (do not recommend, the recovery sucks) so an opportunity struck.
isomer: WHY AREN’T YOU ASLEEP
One of the first things I like to do is poke around Git for clues. Commit messages, changed files, accidental additions. Commit 8b6744
stood out.
Replace executables for Windows and Linux by stripped versions.
This was a good start. While it wasn’t strictly required to make progress is certainly helped to quickly validate some findings later on. Opening foxchk
in Ghidra revealed a lot of isomers initial findings. A hashing algorithm along with some bitwise shifts and xors. The initial focus was on foxchk
as it was much smaller surface area to start with. Running foxchk
directly it was able to produce output without any sort of external key/cert input so magic was happening entirely inside the foxchk
app.
Rather than just trying to guess what the inputs and outputs were meant to be for foxchk
I decided to focus on generating some end to end test data so that each part could be monitored with tools like strace
to ensure our assumptions on how things worked was valid. This is when I shifted to looking at sftx
.
The SuperFox mode requires keys which are provisioned by a third party. Without a key that matches your callsign the modulator will not modulate. Since I wanted to generate test data I needed to know what my SuperFox key would be. This is why I switched to looking at sftx
- how was it validating the key?
From what we learnt in foxchk
it was easy to pick out the hashing / signature functions also present in sftx
. It was also pretty easy to follow the program flow with Ghidra, noting where arguments were passed and used. What stood out the most was a _memcmp
between the provided key and one that’s generated. So we now know that sftx
can validate the key - and it does so by generating one. At this point I knew that it didn’t matter if we never worked out how foxchk
algo worked or how the signature was formed as it was likely we could just generate SuperFox keys using the application itself.
As a proof of concept I started poking in gdb and ended up with the below. This runs the sftx
app and breaks when it performs the comparison. It then prints out the SuperFox key.
# Will only work on wsjtx_2.7.0-rc6_amd64.deb
# shasum ./usr/bin/sftx
#c7f5171efca080ee98718ce977391f9d69fb8dae ./usr/bin/sftx
gdb -batch-silent \
-ex "set logging file /dev/stdout" \
-ex "b _gfortran_getarg_i4" \
-ex "run" \
-ex "finish" \
-ex "delete" \
-ex "b *(\$pc+117)" \
-ex "continue" \
-ex "set logging enabled on" \
-ex "printf \"%.9s\n\", (char[9])*\$rdi" \
--args ./usr/bin/sftx "sfox_1.dat" N0CALL 123-456 # don't worry about the code here - its just a placeholder
I actually really like this GDB solution because it’s sort of a “no code” approach to obtaining the SuperFox key.
GDB also served helpful for validating our assumptions on how the hashing algorithm worked. We discovered that the hashing is done using Bob Jenkins lookup3
hashing function. This isn’t a secure hashing function. After which some scrambling is performed. A very clever puppy will likely have a write up on exactly how the scrambling works on their cohost.
It wasn’t too hard to figure out the process from reverse engineering with the help of Ghidra then write a replacement foxchk
app. Made even easier by nhash.c
being included in wsjt-x source code. The crew has since made rust, and javascript versions. The problem however was that a replacement open source foxchk
essentially had to reveal how the signature/key was generated….
The options seemed a bit like:
- Start releasing open source versions of SuperFox components so they can be packaged in Debian during the RC phase
- Reveals how SuperFox works - would likely cause change prior to stable release making the work pointless
- Wait until stable release, have open source versions ready to go
- Still reveals how SuperFox works - makes the signature pointless but less likely to have last minute changes
- Communicate that its flawed without exposing how prior for a period of time
- It seemed like a lot of the SuperFox mode was focusing around Jaris Island dxpeditition
- Release a keygen with funky midi beats
- Pretend we didn’t see anything
- This reverse engineering happening is a semi-public space so I don’t think this would fly long term
Decision was made to try to keep the details a secret until after Jarvis Island dxpedition. We knew however there would be a risk that others would likely start looking (if not already) and could easily replicate what we did. I have the assumption that the people with the skills to do this sort of reverse engineering likely wouldn’t do so in bad faith.
We also want to demonstrate that we had successfully cracked SuperFox, which is why we generated and displayed the SuperFox key for N0CALL.
It was also important for us to provide useful suggestions on better methods. Shout out to everyone involved here as this turned out to be a lot more work than I anticipated. There’s not many bits to play with in a transmission and coming up with a suitable solution is very tricky. Given the increase in processing speeds and memory size/speed I suspect we are right on the edge of viable security options using key signing for a low data mode like SuperFox. These suggestions have been sent to Joe directly.
The crack
The way the SuperFox key was generated and validated reminded me of all the old software cracking. Firing up your favorite x86 debugger and stepping through code. Because of this I spent far too much time (mostly on/off in between things) and effort building my own “keygen” style webpage. Enjoy my SuperFox crack.
Not the first?
During writing of this post I checked in on wsjt-devel mailing list to find some discussion around HH2AA call using SuperFox. Checking dx spotting websites many spots list that SuperFox mode was used. It turns out that this station didn’t apply or was issued with a SuperFox key. To be clear I, nor any of group involved with this post or previous post were involved in generating a SuperFox key for this station - or providing details into how to do it. It’s not surprising that others would be looking into this.