Exciting news! Our chief scientists found a way to do frequency analysis on binary files. Surprinsingly it isn’t just changing the file ending to
.mp3
and putting it into Audacity. Have a try for yourself below!Note: The binary
/catflag
prints the flag
Category: misc
Solver: linaScience, MarDN, t0b1
Flag: GPNCTF{L00ks_l1k3_y0u_h1t_th3_r1ght_tun3}
Writeup
In this challenge we have no source code :( and are only presented with the following simple website:
From the challenge description we know that we have a catflag
binary which prints the flag, so we somehow need to execute that.
Initial Analysis
As we also guessed from the challenge description, this challenge has something to do with binary files.
We assume that this means ELF executables, so let’s upload /bin/cat
🐈 and see what we get:
Apparently, the server did some “binary frequency analysis” on our binary and produced the graph above. It looks rather random but has three major peaks labelled:
/lib64/ld-linux-x86-64.so.2
linux-vdso.so.1
libc.so.6
With a bit of knowledge in Linux and how ELF executables work, we quickly recognize that those are shared objects (as identified by the .so
suffix).
Since /bin/cat
is a dynamically linked binary, it doesn’t include all function implementations (like printf
, strncmp
, etc.) itself and instead relies on a dynamic linker and shared libraries to provide those (see A look at dynamic linking (lwn.net) for more detailed insights into that process).
Hence, the libraries shown are likely the ones /bin/cat
requires, most notably the libc.so.6
which contains most of the standard library C functions from the GLIBC.
How did the server extract this from our uploaded binary? Since we don’t have the source code, we don’t know for sure and have to guess.
LDD
A tool that is commonly used to inspect the dependencies of an executable is ldd
.
If you’ve followed the xz backdoor initial reporting and/or analysis, you’ve probably seen a command similar to ldd $(which sshd)
to check whether liblzma
is mentioned in the output and thus your sshd
version might be vulnerable.
To find out what it does, let’s look at the man
-page of ldd
:
ldd prints the shared objects (shared libraries) required by each program or shared object specified on the command line.
That’s what we want!
We can quickly check this by running ldd /bin/cat
ourselves:
$ ldd /bin/cat
linux-vdso.so.1 (0x00007fff9b55b000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f0096f07000)
/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007f0097151000)
And indeed, the output contains the three libraries present in the “binary analysis” we got from the server, so we might be right that this is what the server parses.
Continuing in the man-page we get a glimpse at how it works:
In the usual case,
ldd
invokes the standard dynamic linker (see ld.so(8)) with theLD_TRACE_LOADED_OBJECTS
environment variable set to 1. This causes the dynamic linker to inspect the program’s dynamic dependencies, and find (according to the rules described in ld.so(8)) and load the objects that satisfy those dependencies.
So it turns out that ldd
actually executes the linker and additionally sets the LD_TRACE_LOADED_OBJECTS
environment to signal that it shouldn’t run the program but only show the loaded shared objects.
By running file
on an ELF binary, we can see the configured interpreter (linker):
$ file /bin/cat
/bin/cat: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=9165f3848a294fb8792125cf0696891ff84aba02, for GNU/Linux 4.4.0, stripped
This is /lib64/ld-linux-x86-64.so.2
for most ELF binaries on my system. We can simulate the behavior of ldd
by running the linker on the /bin/cat
binary:
$ LD_TRACE_LOADED_OBJECTS=1 /lib64/ld-linux-x86-64.so.2 /bin/cat
linux-vdso.so.1 (0x00007ffd99967000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007fcb128e5000)
/lib64/ld-linux-x86-64.so.2 (0x00007fcb12b2f000)
And again, we get the three shared libraries, this time without even running ldd
.
In fact, ldd
is simply a shell script which you can examine via cat $(which ldd)
.
You’ll see that it does a bit more than only setting the environment variable but that’s the core concept.
Exploitation
The man-page of ldd
also states something important about the security:
Be aware that in some circumstances (e.g., where the program specifies an ELF interpreter other than ld-linux.so), some versions of ldd may attempt to obtain the dependency information by attempting to directly execute the program, which may lead to the execution of whatever code is defined in the program’s ELF interpreter, and perhaps to execution of the program itself.
Depending on the ldd
version, it may simply execute the interpreter specified in the program!
But the challenge could also just mimic the functionality of ldd
by figuring out the interpreter of the bianry and calling it with the LD_TRACE_LOADED_OBJECTS
to obtain the dependency information.
In either case, let’s create a copy of cat
and change the interpreter:
cp /bin/cat .
patchelf --set-interpreter /catflag ./cat
If we now run file ./cat
, we’ll see that the interpreter has changed:
$ file ./cat
./cat: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /catflag, BuildID[sha1]=9165f3848a294fb8792125cf0696891ff84aba02, for GNU/Linux 4.4.0, stripped
We can now try to run ./cat
but it won’t work any longer - the /catflag
interpreter doesn’t exist on my system so the system doesn’t know how the file should be interpreted.
Nevertheless, it exists on the challenge host, so let’s upload the binary and hope that the server executes the interpreter to perform the frequency analysis.
And indeed, we got the flag!