Flash CTF – License to Rev

This is a Reverse Engineering challenge. We’re given a binary (an executable file) and told:

We were trying to get the flag from this binary we purchased a few months ago, but we lost the license, maybe you can help?

Let’s take a look.

We can use file to determine that it’s a Linux executable (ELF), so if you don’t have a Linux host or VM, you’ll want to grab one. Use chmod +x license_to_rev to make it executable, then ./license_to_rev to run it (for safety, it’s best to do this in a container or VM with untrusted binaries).

$ ./license_to_rev 
Usage: ./license_to_rev <license-file>

A license file is required to use this product.
Each copy is individually licensed. Please provide the path to your
license file. Without a valid license, the program cannot continue.

Well, that was anticlimactic. Can we just give it a blank file?

$ touch license
$ ./license_to_rev license
That is not the correct license. Invalid license.

Bummer. We’ll have to actually reverse it. Let’s start with strings, and as usual, look near the middle of the output:

It doesn’t look like a very complex program – the output isn’t much longer than this. It looks like it expects a license.txt file at some point. Interestingly, there’s a mention of EMBEDDED_ZIP and ENCRYPTED_MESSAGE, but not much more. (The eagle-eyed might spot that sneaky PK near the middle…)

Let’s try looking at it in Ghidra. The main() function, while lengthy, isn’t too complicated:

Interestingly, after some conditionals (probably reading in the license file), it’s calling functions like inflateInit2() and inflate(). A quick search hints these are zlib functions, and ldd confirms that the zlib library is used:

$ ldd license_to_rev 
        linux-vdso.so.1 (0x0000755399730000)
        libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007553996e2000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x0000755399400000)
        /lib64/ld-linux-x86-64.so.2 (0x0000755399732000)

Finally, we also see this line near the bottom:

We could keep reversing to try to figure out what it’s decompressing, or we could take all the hints the code is giving us (remember EMBEDDED_ZIP from earlier) and check for embedded archives within the binary. A tool like binwalk is perfect for this.

$ binwalk license_to_rev     

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             ELF, 64-bit LSB shared object, AMD x86-64, version 1 (SYSV)
8736          0x2220          Zip archive data, at least v2.0 to extract, compressed size: 264, uncompressed size: 341, name: license.txt
9098          0x238A          End of Zip archive, footer length: 22

There is indeed a Zip archive hiding in there! We can use binwalk -e to extract it. It gives us a file, license.txt.

$ cat license.txt 
# License to Reverse - License Certificate
# Skillbit (formerly known as MetaCTF)

LICENSE_TYPE=Professional
SERIAL=MCT-4XHA-GKNA-5F1E
LICENSED_TO=Terrance Troutt
ISSUE_DATE=2025-07-01
EXPIRY_DATE=2026-02-01
ACTIVATION_ID=MNZHOM7YMY63DQBG1GTW

TERMS=This license is non-transferable. Each copy is individually licensed.

--- END LICENSE ---

And yet…

$ ./license_to_rev license.txt 
This license has expired. Please contact support for a new license.

Looks like it checks the expiry date. Can we just change it, say to expire in 2027?

$ ./license_to_rev license.txt 
That is not the correct license. Invalid license.

Dang. It’s probably doing some kind of integrity check.

We could try to RE how this works and defeat it, or patch out the check. Or… Ghidra shows that localtime is used. Could we just make the program think it’s still, say, 2025?

We could actually change our clock (and this does work), or we can use a tool like https://github.com/wolfcw/libfaketime. It’s apt installable on Ubuntu.

$ faketime '1 year ago' ./license_to_rev license.txt 
MetaCTF{y0u_g0t_@_g0ld3n_ey3_4_r3v}

And there’s our flag!