Nginx Proxy Manager v2.11.3 RCE
写在前面
该漏洞并非是 NPM 项目的代码存在漏洞,而是 NPM Docker 环境的默认配置存在缺陷,在 NPM 用户拥有 Hosts
的 Manage
权限的情况下,可以获取容器内的 Shell 。
搭建环境
Nginx Proxy Manager (NPM) 基于 Ubuntu + Nginx 容器化部署。
创建一个空目录,创建 docker-compose.yml
文件,内容:
1 |
|
在该目录下执行以下命令,以启动容器:
1 |
|
访问 http://localhost:81/login 以进行操作。
初始用户密码:
1 |
|
具体细节参考: quick-setup
用户登录后可以设置反向代理、重定向等功能。
这些功能基本上都是基于修改 nginx.conf
文件实现的,因此以下的内容本质上都是 nginx.conf
配置安全漏洞,只不过由于该项目允许用户在前端编辑和加载配置文件而能够被利用。
当然了,搞来搞去也就是在容器里而已,没啥意思,管好用户权限就行了。
从文件写入到 RCE
允许 PUT 方式上传
首先新建一个 Proxy Host
:
图中 Domain Names
可以写该反代服务器的 IP 或域名,总之能够通过这个地址访问到这个容器里的反代端口即可,我们假设为 npm.example.com
。其余字段随便写应该都不影响。
然后通过高级设置,自定义 nginx.conf
配置文件以允许 PUT
方式上传。
1 |
|
现在我们可以通过向 URL http://npm.example.com/gupload/filename
发送 PUT
请求来将文件上传到 /etc/
目录,上传后的文件名应该为 filename
。
1 |
|
可以看到文件能够被上传到容器内:
关于 ld.so.preload 劫持
理论上我可以通过 写 SSH 私钥
、写 Crontab
的方式来实现命令执行,但是为什么要用 ld.so.preload
方式呢?
首先,这是个容器环境,没有 ssh 服务,所以写私钥没意义。
其次,这个容器基于 Ubuntu
,尽管我们通过 dav_access user:rw;
指定了文件权限为 0600
,但是这容器没开 cron
服务,执行不了命令。
而 ld.so.preload
方案则非常通用。我们不需要给上传的运行库文件设置什么权限,同时 ld.so.preload
文件中允许指定任意位置的 so
。最重要的是,大部分进程在执行的时候都会预加载这个 so
,十分甚至九分地好用。
编译 Preload.so
源码: preload.c
文件
1 |
|
编译:
1 |
|
上传 Preload.so
依次执行以下两个命令
1 |
|
执行后,preload.so
和 ld.so.preload
文件应该被会上传到 /etc/
路径下。
执行
成功上传后,理论上此时执行任何二进制程序,都会导致恶意 .so
被执行。
开启监听端口:
1 |
|
根据项目代码,在 WebUI
中,保存配置、禁用和启用配置会造成执行 nginx
命令:
项目代码:
所以只要禁用配置,就可以执行 nginx
程序,同时造成执行恶意 so
文件以及里面的反弹 Shell
命令。
文件读取
相对于 RCE,这个功能显得不是很危险。
同样的修改 nginx.conf
配置文件。
1 |
|
这样我们就可以通过访问 http://npm.example.com/ggimgs
来下载容器内的 database.sqlite
文件。
这个文件是 npm
的数据库,里面保存了用户密码。同理也可以下载别的文件(也没别的什么有用的文件了)。