Fork me on GitHub


Last evening I settled on SecOS from PaulSec as I'm currently stuck working on Hell still and needed a win after not making much progress on Hell in a few days. SecOS was enjoyable and I was able to knock it over in an hour or so. Let's get into it!

I fired up nmap to see what's running, and received this:

Nmap scan report for
Host is up (0.000066s latency).
Not shown: 998 closed ports
22/tcp open ssh (protocol 2.0)
8081/tcp open http Node.js (Express middleware)

A web server running Node, not something I've run into yet! Looks like a pretty basic site with not a whole lot going on aside from a login/signup system (Figure 1).


My first instinct was to check the page source. There have been plenty of occasions in the offsec labs where checking out a page's source HTML has been helpful in finding any hidden clues or other identifiable information to help me progress. Sure enough, there's an HTML comment with a link to /hint. Following through, another page loads up with a taunting message. Again, viewing the source was key (Figure 2).


Okay, so now we know that an administrator checks out this site and that a CSRF vulnerability might be the way to escalate to an admin level user. I went and registered on the site and after logging in, was presented with three new navigation options, 'Messages', 'Users' and 'Change Password'. Inspecting both forms didn't really reveal anything more than simple PHP forms, and no CSRF tokens were present to complicate things. The Users page listed all registered users on the system and I also discovered that user 'spiderman' was an administrator.

For the sake of being thorough, I wanted to find out what sort of browser spiderman was using to view the site so I fired up a netcat listener and sent him a message with a hidden iframe pointing back to my box. Within a minute, I received my answer:

connect to [] from (UNKNOWN) [] 46958
GET / HTTP/1.1
User-Agent: Mozilla/5.0 (Unknown; Linux i686) AppleWebKit/534.34 (KHTML, like Gecko) PhantomJS/1.9.7 Safari/534.34
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Connection: Keep-Alive
Accept-Encoding: gzip
Accept-Language: en-US,*

PhantomJS... a headless WebKit browser. Good to know, but not key to my engagement.

The fact that I was able to create messages with HTML code seemed like a promising advantage staying true to the hints discovered earlier. I tried a number of XSS/CSRF techniques to gather any session info in cookies or other useful information, all of which yielded nothing useful. What I needed to have happen was to dupe spiderman into changing his password to something I determined without him knowing what happened. This is possible by creating a form who's action pointed to /change-password on the site, and since there is no CSRF tokens present, it should be cut and dry. I had earlier tried to do this by sending spiderman a message with a form field, but that didn't work properly. My next step was to save that form HTML to my attacking system and inject that URL into a message directed towards spiderman. The code for this is as follows:

<body onload="document.forms[0].submit()">
<form action="" method="post"> 
    <input type="hidden" name="username" value="spiderman"> 
    <input type="hidden" name="password" value="moo"> 
    <input type="submit" value="changeit"> 

Once this HTML was loaded, some simple Javascript to submit the malicious form sent the password change request on behalf of spiderman. Tailing my apache logs, I saw that my malicious form was requested and went to log in as spiderman. Success!!

Now that I was logged in as spiderman's user, I checked out his messages and saw that user 'pirate' had apparently discovered spiderman's password (Figure 3).


Now that I was already logged in to the system as spiderman, that message wasn't going to be very helpful unless spiderman used the same password for his SSH credentials. Let's see... (Figure 4).


SSH access, nice. After enumerating running processes and open connections I found a listening connection on TCP 9000 which was only available internally (Figure 5). I set up an SSH tunnel to access whatever was being served internally. Once the tunnel was hooked up, I found out what was being served (Figure 6).

ยป ssh -f -N -D spiderman@



An IP ping tool, seems pretty straightforward. I've abused things like this before ;). To confirm my suspicions, I dug around the file system for the code that's behind this application. I found the code when I enumerated the processes running on the box earlier. Inspecting internalServer.js, I was able to confirm that this application was vulnerable to unsanitized user input and would allow additional commands to be run via the exec() method call (Figure 7).


Since this application was being executed by root, it was all too easy to capture the flag (Figure 8)!

-c1 && cat /root/flag.txt


And that's all there is to it! Thanks to PaulSec for coming up with a fun little challenge, looking forward to the next one!