Attacking Thick Client Applications
Thick client applications (also called rich or fat clients) are locally installed applications that perform significant processing on the client side rather than relying solely on remote servers. Unlike web applications, they donβt require internet access and can contain significant attack surface including hardcoded credentials, unencrypted communications, and insecure local storage.
Thick Client Architecture
Two-Tier Architecture
βββββββββββββββββββ
β Thick Client β
β (Application) β
ββββββββββ¬βββββββββ
β
β Direct connection
β
βββββββββββββββββββ
β Database β
βββββββββββββββββββ
Risk: Attacker can directly communicate with database; credentials embedded in client.
Three-Tier Architecture
βββββββββββββββββββ
β Thick Client β
β (Application) β
ββββββββββ¬βββββββββ
β
β HTTP/HTTPS
β
βββββββββββββββββββ
β Application β
β Server β
ββββββββββ¬βββββββββ
β
β
β
βββββββββββββββββββ
β Database β
βββββββββββββββββββ
Risk: Better security; database not directly accessible, but application server may be exploitable.
Common Vulnerabilities in Thick Clients
| Vulnerability | Impact | Example |
|---|---|---|
| Hardcoded credentials | Complete compromise | Database password in source code |
| Improper error handling | Information disclosure | Stack traces revealing system paths |
| DLL hijacking | Code execution | Malicious DLL loaded instead of legitimate |
| Buffer overflow | Code execution, DoS | Stack or heap overflow |
| SQL injection | Data breach, code execution | Direct SQL queries to database |
| Insecure storage | Credential theft | Passwords stored in plaintext files |
| Weak session management | Session hijacking | Predictable session tokens |
| Unencrypted communication | MITM attacks, credential theft | HTTP or unencrypted TCP |
Penetration Testing Phases
Phase 1: Information Gathering
Identify application architecture:
- Is it two-tier or three-tier?
- Whatβs the backend server (if any)?
- What database is used?
Identify technologies:
# Use CFF Explorer to analyze PE headers
# Detect It Easy for quick analysis
# Strings utility to find embedded information
strings application.exe | grep -i "version\|database\|server"
Identify entry points:
- User input fields
- File operations
- Network communications
- Registry access
Tools:
- CFF Explorer β PE file analysis
- Detect It Easy β Quick binary analysis
- Process Monitor β Monitor runtime behavior
- Strings β Extract readable text from binaries
Phase 2: Client-Side Attacks
Static Analysis
Reverse-engineer the application to find hardcoded credentials:
# For .NET applications
dnspy application.exe # Decompile and inspect source code
# For Java applications
jd-gui application.jar # Decompile JAR files
# For native binaries
ida application.exe # IDA Pro for advanced analysis
ghidra application.exe # Ghidra (free alternative)
Look for:
- Hardcoded database credentials
- API keys and tokens
- Server URLs and hostnames
- Encryption keys
- Username/password patterns
Dynamic Analysis
Monitor application execution to capture sensitive data:
# Monitor registry access
procmon.exe # Process Monitor (SysInternals)
# Debugging and inspection
x64dbg # 64-bit debugger
ollydbg # 32-bit debugger
radare2 # Portable disassembler/debugger
# Memory analysis
frida # Dynamic instrumentation toolkit
volatility # Memory forensics
Technique: Extract Credentials from Memory
- Attach debugger to running application
- Set breakpoints at authentication functions
- Inspect memory for plaintext passwords/credentials
- Extract and decode Base64/encrypted values
Phase 3: Network-Side Attacks
Analyze network traffic between client and server:
# Capture traffic
wireshark # GUI packet analyzer
tcpdump # Command-line packet capture
netsh trace # Windows native tracing
# Analyze traffic
burp suite # Intercept and analyze HTTP/HTTPS
tcpview # View active TCP/UDP connections
fiddler # HTTP(S) traffic interception
Vulnerability examples:
- Credentials transmitted in cleartext
- No certificate validation (MITM possible)
- Unencrypted database connections
- Predictable request patterns
Phase 4: Server-Side Attacks
Target the application server or database:
# Common server-side attacks
sqlmap # SQL injection testing
burp suite # Web application testing framework
metasploit # Exploitation framework
Attack vectors:
- SQL injection
- Authentication bypass
- Privilege escalation
- Business logic flaws
- API vulnerabilities
Extracting Hardcoded Credentials - Case Study
Scenario: Restart-OracleService.exe
Initial discovery: Application found in SMB NETLOGON share.
Step 1: Identify Hidden Behavior
# Run the application
C:\Apps>.\Restart-OracleService.exe
C:\Apps>
# Use Process Monitor to capture file operations
# Monitor C:\Users\[user]\AppData\Local\Temp
# Look for temporary files created and deleted
Finding: Application creates temporary batch files and deletes them immediately.
Step 2: Prevent File Deletion
Modify TEMP folder permissions to prevent deletion:
C:\Users\[user]\AppData\Local\Temp
β Right-click β Properties β Security β Advanced
β Edit [user] permissions
β Uncheck "Delete subfolders and files" and "Delete"
β Apply
Step 3: Capture Generated Files
Run application again and check TEMP folder:
C:\>dir C:\Users\[user]\AppData\Local\Temp\2
04/03/2023 02:09 PM 1,730,212 6F39.bat
04/03/2023 02:09 PM 0 6F39.tmp
Step 4: Analyze Batch File
@shift /0
@echo off
if %username% == matt goto correcto
if %username% == frankytech goto correcto
if %username% == ev4si0n goto correcto
goto error
:correcto
# Outputs Base64-encoded binary to file
echo TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAA... > c:\programdata\oracle.txt
# More Base64 lines appended...
# PowerShell script to decode Base64
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
Key insight: Application drops and executes a binary, then cleans up traces.
Step 5: Preserve Dropped Files
Modify batch file to prevent deletion:
@shift /0
@echo off
echo TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAA... > c:\programdata\oracle.txt
echo AAAAAAAAAAgAAAAA4fug4AtAnNIbgBTM0hVGhpcyBwcm9ncmFtIGNhbm5vdCBiZSBydW4g >> c:\programdata\oracle.txt
# ... more Base64 lines ...
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
# Comment out deletion commands
REM del c:\programdata\monta.ps1
REM del c:\programdata\oracle.txt
c:\programdata\restart-service.exe
REM del c:\programdata\restart-service.exe
Step 6: Execute Modified Batch
Files now remain in C:\ProgramData\:
C:\>ls C:\ProgramData\
Mode LastWriteTime Length Name
-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
Step 7: Debug the Extracted Binary
Use x64dbg to analyze the executable:
1. Open x64dbg
2. File β Open β select restart-service.exe
3. Options β Preferences β Uncheck all except "Exit Breakpoint"
4. Right-click in CPU view β Follow in Memory Map
5. Look for suspicious memory regions (RW-- protection)
6. Double-click interesting regions (look for MZ magic bytes)
7. Right-click β Dump Memory to File
Step 8: Extract and Analyze Memory Dump
# Run strings on exported dump
strings restart-service_00000000001E0000.bin | grep -i "oracle\|password\|user"
# Output shows .NET Framework references
.NETFramework,Version=v4.0,Profile=Client
.NET Framework 4 Client Profile
Step 9: Deobfuscate .NET Binary
Use de4dot to remove obfuscation:
de4dot restart-service_00000000001E0000.bin
# Outputs: restart-service_00000000001E0000-cleaned.bin
Step 10: Decompile with dnSpy
1. Open dnSpy
2. File β Open β select restart-service_00000000001E0000-cleaned.bin
3. Browse decompiled C# source code
4. Look for hardcoded credentials and business logic
Result: Discover custom runas.exe implementation with hardcoded Oracle service credentials.
Attacking Applications Connecting to Services
Applications that connect to backend services (databases, APIs, message queues) often embed connection strings containing credentials. If these strings arenβt sufficiently protected, they can be extracted through binary examination β either from a native ELF executable using a debugger, or from a .NET assembly using a decompiler. Recovered credentials can be reused directly against the backend service, or tried against other services on the network (password reuse/spraying).
ELF Executable Examination (GDB/PEDA)
Scenario: octopus_checker binary found on a remote Linux host. Running it locally shows it attempts a connection to a database instance:
rnemeth@htb[/htb]$ ./octopus_checker
Program had started..
Attempting Connection
Connecting ...
The driver reported the following diagnostics whilst running SQLDriverConnect
01000:1:0:[unixODBC][Driver Manager]Can't open lib 'ODBC Driver 17 for SQL Server' : file not found
connected
The binary likely builds a SQL connection string containing credentials at runtime. PEDA (Python Exploit Development Assistance for GDB) extends GDB with better register/memory visibility for stepping through the binary.
Step 1 β Load the binary and set the disassembly flavor:
rnemeth@htb[/htb]$ gdb ./octopus_checker
gdb-peda$ set disassembly-flavor intel
gdb-peda$ disas main
Disassembling main reveals a series of call instructions referencing string addresses β these are fragments of the SQL connection string, but out of order and reversed due to endianness (the byte order in which the architecture reads multi-byte values).
Step 2 β Find the call to SQLDriverConnect:
0x00005555555555ff <+425>: mov esi,0x0
0x0000555555555604 <+430>: mov rdi,rax
0x0000555555555607 <+433>: call 0x5555555551b0 <SQLDriverConnect@plt>
0x000055555555560c <+438>: add rsp,0x10
0x0000555555555610 <+442>: mov WORD PTR [rbp-0x4b4],ax
Step 3 β Breakpoint on the call and run:
gdb-peda$ b *0x5555555551b0
Breakpoint 1 at 0x5555555551b0
gdb-peda$ run
When the breakpoint hits, the fully-assembled connection string is visible in a register (here, RDX) since itβs passed as an argument to SQLDriverConnect:
RDX: 0x7fffffffda70 ("DRIVER={ODBC Driver 17 for SQL Server};SERVER=localhost, 1401;UID=username;PWD=password;")
Key insight: Rather than manually reconstructing a reversed/fragmented string from disassembly, breakpoint on the function that consumes the fully-built string (the driver connect call) and read it straight out of the register/stack at that point.
DLL File Examination (dnSpy)
Scenario: MultimasterAPI.dll found on a remote Windows host. Metadata confirms itβs a .NET assembly:
C:\> Get-FileMetaData .\MultimasterAPI.dll
<SNIP>
M .NETFramework,Version=v4.6.1 TFrameworkDisplayName.NET Framework 4.6.1 api/getColleagues
http://localhost:8081*POST
<SNIP>
Since itβs a managed .NET assembly, it can be decompiled directly (no need for a debugger/memory dump as with native binaries).
Step 1 β Open the DLL in dnSpy and browse the namespace/class tree.
Step 2 β Inspect controller classes for hardcoded backend logic. MultimasterAPI.Controllers -> ColleagueController reveals a SQL connection string with a plaintext password embedded directly in the Get/GetColleagues methods.
Key insight: .NET assemblies decompile close to original source (dnSpy reconstructs readable C#/VB), so connection strings and other secrets are often trivially visible without any dynamic analysis β check controllers/data-access classes first.
Takeaways
- Native binaries (ELF/PE) that build connection strings at runtime can still leak the fully-assembled string via a breakpoint at the driver/connect API call β no need to manually reverse fragmented, endian-reversed string constants.
- Managed binaries (.NET, Java) are far easier: decompile with dnSpy/jd-gui and read the connection string directly from source.
- Extracted database credentials should be tested for direct reuse against the backend service, and also tried against other services/accounts on the network (password reuse).
Tools Summary
Static Analysis
| Tool | Purpose | Supported |
|---|---|---|
| IDA Pro | Disassembly and decompilation | EXE, DLL, binaries |
| Ghidra | Free disassembly/decompilation | EXE, DLL, binaries |
| dnSpy | .NET decompilation | EXE, DLL (managed) |
| JADX | Java decompilation | APK, JAR, DEX |
| Radare2 | Portable disassembler | EXE, DLL, binaries |
| Strings | Extract readable text | Any binary |
| CFF Explorer | PE file analysis | EXE, DLL |
| GDB + PEDA | Disassembly, breakpoints, register/memory inspection | ELF binaries |
Dynamic Analysis
| Tool | Purpose |
|---|---|
| Process Monitor | Monitor system calls |
| x64dbg | 64-bit debugging |
| ollydbg | 32-bit debugging |
| WinDbg | Windows debugging |
| Frida | Dynamic instrumentation |
| Volatility | Memory forensics |
Network Analysis
| Tool | Purpose |
|---|---|
| Wireshark | Packet capture and analysis |
| Burp Suite | HTTP(S) interception |
| Fiddler | HTTP proxy |
| tcpdump | CLI packet capture |
| Telerik Fiddler | HTTP debugging |
Hardcoded Credentials Common Locations
In source code/binaries:
- Database connection strings
- API keys and tokens
- Service account credentials
- Encryption keys
- OAuth tokens
In configuration files:
config.ini,config.xml,app.configweb.config(ASP.NET).propertiesfiles (Java)- Registry keys (Windows)
- INI files in program directory
In memory:
- Decrypted passwords during execution
- Session tokens
- Encryption keys
- API responses with sensitive data
In temporary files:
- Batch files created during execution
- Log files with debug output
- Cache files with plaintext data
- Installation files
Assessment Checklist
- Identify application architecture (two-tier/three-tier)
- Perform static analysis (decompile source code)
- Search for hardcoded credentials in binaries
- Check configuration files for sensitive data
- Monitor runtime behavior with Process Monitor
- Capture and analyze network traffic
- Intercept HTTP(S) communications
- Test for SQL injection in local database calls
- Analyze memory dumps for credentials/keys
- Test for DLL hijacking vulnerabilities
- Check for improper error handling
- Test authentication mechanisms
- Document all findings with proof-of-concept
Key Takeaways
- Thick clients are complex: Multiple attack surfaces (client, network, server)
- Hardcoded credentials common: Source code and binaries frequently contain secrets
- Local access dangerous: Full control of the application logic
- Network traffic unencrypted: Monitor for plaintext credentials and data
- Debugging access: Ability to inspect runtime memory and logic
- File extraction: Temporary files may reveal dropped/executed code
- Decompilation possible: .NET and Java applications easily reversible
- Default behaviors exploitable: Many applications designed without security in mind