Reverse engineering for bug bounties is a thrilling adventure, often leading down rabbit holes of code and unexpected discoveries. My recent journey involved the Spotify installer, a quest to uncover a potential DLL hijacking vulnerability. This post will walk you through the process, the tools, the roadblocks, and the ultimate conclusions, highlighting key lessons learned along the way.
Understanding DLL Hijacking: The Goal
At its core, DLL (Dynamic Link Library) hijacking is a common vulnerability where an application attempts to load a legitimate DLL, but a malicious one is loaded instead. This often happens because applications search for DLLs in a specific order (e.g., current directory first, then system directories). If a malicious DLL with the expected name is placed in an earlier search path, the application loads it, allowing an attacker to execute arbitrary code within the application's context.
Tools of the Trade
Our investigation relied on a suite of powerful tools:
- Ghidra: For static analysis (disassembling and decompiling the binary).
- Process Monitor (ProcMon): For dynamic analysis (observing file system and registry activity).
- x64dbg: A powerful debugger for runtime analysis and setting breakpoints.
- Visual Studio Code (VS Code) & Microsoft Visual C++ (MSVC) Compiler: For developing our Proof-of-Concept (PoC) DLL.
Phase 1: Static Analysis with Ghidra – The Initial Recon
I started by loading SpotifySetup.exe
into Ghidra. My initial exploration took me into security_init_cookie
, a function often related to exploit mitigations like Stack Canaries. While interesting, it led me to a more promising avenue: LoadLibraryExA
calls.
LoadLibraryExA
is a Windows API function used to load DLLs. Its third parameter, dwFlags
, is critical for DLL hijacking.
- A
dwFlags
value of0x800
(equivalent toLOAD_LIBRARY_SEARCH_DEFAULT_DIRS
) is considered secure, as it tells the system to search standard secure directories (likeSystem32
) before the application's current directory. - A
dwFlags
value of0
(or0x000
,0x0
) implies a less secure search order, often including the current directory first, which is ripe for hijacking.
My deep dive into LoadLibraryExA
references revealed a prime candidate at 140084e31
. This particular call looked like:
hLibModule = LoadLibraryExA(local_60,(HANDLE)0x0,0)
The key here was the 0
flag – a potential red flag for DLL hijacking! What was local_60
? Static analysis showed local_60
was dynamically assigned: local_60 = IMAGE_DOS_HEADER_140000000.e_magic + param_1[1];
. This meant the DLL name was constructed at runtime, making dynamic analysis essential.
Phase 2: Dynamic Analysis with Process Monitor – Fishing for Clues
With a potential vulnerable function identified, Process Monitor became my best friend. I set filters to observe SpotifySetup.exe
's file operations, specifically looking for CreateFile
events with a Result
of NAME NOT FOUND
in the installer's current directory (my Downloads folder).
This revealed several DLLs that the installer sought but didn't initially find in its own directory:
Bcrypt.dll
(my initial target)profapi.dll
CRYPTBASE.DLL
TextShaping.dll
ncrypt.dll
NTASN1.dll
MSASN1.dll
DPAPI.DLL
winnlsres.dll
These "NAME NOT FOUND" results were exciting, suggesting that the installer might then fall back to loading these from less secure paths, creating an opportunity for a hijack.
Phase 3: Building a Proof-of-Concept (PoC) DLL
To confirm the hijack, I needed a malicious DLL that would signal its execution. My PoC was a simple C++ DLL (MaliciousBcryptDLL.cpp
) that displayed a MessageBoxA
pop-up in its DllMain
function.
However, getting it to compile with MSVC in VS Code had its own set of challenges:
cl.exe
not found / Environment Variables: The MSVC compiler (cl.exe
) wasn't in my system's PATH.- Fix: Always launch VS Code from the "Developer Command Prompt for VS 2022" (as administrator). This correctly sets all necessary environment variables.
- Path Quoting Issues & Linker Errors: My initial
tasks.json
struggled with spaces in file paths, leading to errors likeunrecognized source file type
andcannot open input file 'dllmain.cpp'
.- Fix: While moving the project to a path without spaces is ideal, the
tasks.json
was refined to use escaped double quotes (\"
) around all paths inargs
and correctly order compiler arguments (source file before/link
). Theuser32.lib
library also needed to be explicitly linked forMessageBoxA
.
- Fix: While moving the project to a path without spaces is ideal, the
- ASLR & Breakpoints: Setting breakpoints in
x64dbg
using static addresses resulted in errors due to ASLR.- Fix: Instead of
bp 140084E31
, use module-relative breakpoints:bp SpotifySetup.exe+84E31
. This offsets the breakpoint from the executable's dynamically loaded base address.
- Fix: Instead of
Phase 4: Testing the PoC & The Twist
With the Bcrypt.dll
compiled, I tried copying it (renamed to profapi.dll
for one test, for example) into the Downloads
folder alongside SpotifySetup.exe
. My expectation was a glorious pop-up.
But... no pop-up.
Process Monitor also stopped showing "NAME NOT FOUND" for Bcrypt.dll
or profapi.dll
in the Downloads
directory. This was a critical clue: it implied these DLLs were now being loaded securely before the potentially vulnerable fallback could occur.
Adding another twist, the Spotify installer explicitly prompted to run it "using a normal account and not admin." This meant debugging had to be done without administrator privileges, limiting the potential impact of any hijack.
Phase 5: Definitive Debugging with x64dbg – The Ultimate Answer
The only way to know for sure was to confirm if the vulnerable LoadLibraryExA
call was ever actually reached.
- I launched x64dbg as a normal user (not as administrator).
- Opened
SpotifySetup.exe
. - Set the module-relative breakpoint:
bp SpotifySetup.exe+84E31
. - Ran the installer.
The Result: The breakpoint was NEVER HIT.
Conclusion: No Hijack Here (For This Path)
The debugger provided the definitive answer: the specific LoadLibraryExA
call at SpotifySetup.exe+84E31
is never executed during the normal installation process. This means that, for this version of the Spotify installer and its execution flow, the identified vulnerable code path is not exploited. The installer likely manages to load all its necessary DLLs through secure methods (e.g., using LOAD_LIBRARY_SEARCH_DEFAULT_DIRS
flags or explicit full paths) before ever falling back to the less secure search order that would allow a DLL hijack.
Key Takeaways from the Hunt
- Static vs. Dynamic Analysis: Static analysis (Ghidra) gives you potential leads, but dynamic analysis (ProcMon, x64dbg) is crucial for confirming if those leads are actually reachable and exploitable in a live environment.
- The Devil is in the Details: Flags (like
0x800
vs0
inLoadLibraryExA
), execution flow, and even environment privileges (admin vs. normal user) profoundly impact exploitability. - Debugging Challenges: Be prepared for ASLR, path quoting complexities, and compiler environment setups. It's a journey of continuous problem-solving.
- Persistence Pays Off: Even when a specific vulnerability doesn't pan out, the process of investigating builds invaluable skills.
This journey, though not ending in a reported bug for Spotify, was a comprehensive exercise in understanding and applying reverse engineering and vulnerability research techniques. It's a testament to the iterative nature of security work – every attempted exploit teaches you something new.
Follow me at:
X - @HaqSec
Instagram - haq_sec
Comments
Post a Comment