add easyH5ai

This commit is contained in:
Layton Chen
2020-11-05 20:45:32 +08:00
parent cf16bf678a
commit 8ea970574b
15 changed files with 2178 additions and 2 deletions
Vendored
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
@@ -1,6 +1,6 @@
# 超安全的代理服务器
本地源代码在 (src)[./src/smart_proxy] 文件夹下。
本地源代码在 src 文件夹下。
## 考察内容
@@ -23,7 +23,7 @@
### Method 1. 使用 Wireshark 抓包分析
一种很直观的查看方式是直接抓取原始流量进行分析,但是困难在于 h2 内容 大多经过 TLS 协议加密,因此直接查看只能看到加密后的内容。解决方法是提取浏览器中的 TLS 会话秘钥,就可以进行抓包和解密了。具体细节参见:[这一篇文章](https://cloud.tencent.com/developer/article/1416948)
我们使用类似下面的命令可以启动浏览器并导出 TLS 秘钥,并使用 Wireshark 可以抓取到加密的 HTTP2 流量,我们观察到有 Promise Push 的内容,具体是一个 URL。我们访问这个 URL 即可得到**代理凭证 secret** 和第一个**flag**
我们使用类似下面的命令可以启动浏览器并导出 TLS 秘钥,并使用 Wireshark 可以抓取到加密的 HTTP2 流量,我们观察到有 PUSH_PROMISE 的内容,具体是一个 URL。我们访问这个 URL 即可得到**代理凭证 secret** 和第一个**flag**
![pic/pic_1.png](pic/pic_1.png)
### Method 2. 使用 nghttp2 工具调试 HTTP2
Binary file not shown.
@@ -1 +1,48 @@
# 超简易的网盘服务器
本题的源代码在 src 文件夹下(其实本题的大部分关键代码已经在题目中给出了)。
## 解法
其实题目文案说了那么多话,关键的提取出如下信息:
1. 本题是使用开源项目 [h5ai](https://larsjung.de/h5ai/) 搭建的网盘
2. flag 就在网盘的根目录下
3. 但是网盘根目录使用 Basic Auth 进行了访问控制
4. `/Public/` 目录却是公开的(没有访问控制)
具体怎么做的呢? 通过阅读 `dockerfile``nginx.conf` 配置文件,我们就可以知道服务是如何进行部署的了。`dockerfile` 告诉我们,`/Public` 目录下的 h5ai 是根目录下的一个软连接。nginx.conf 告诉我们 / 设置了 Basic Auth 而 `/Public` 并没有。
这时候顶级黑客的同学们可能以为小 C 找到了一个未披露的 h5ai 项目的0day 并开始对 h5ai 进行代码审计了(似乎确实有顶级黑客!)。且慢,我们再多看一眼 `nginx.conf`
```
location / {
auth_basic "easy h5ai. For visitors, please refer to public directory at `/Public!`";
auth_basic_user_file /etc/nginx/conf.d/htpasswd;
}
location /Public {
allow all;
index /Public/_h5ai/public/index.php;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
```
我们的访问控制漏掉了什么!Nginx 软件对于 location 指令匹配的优先级规则中,`location ~ \.php$` 规则比 `location /` 有更高的优先级!似乎 PHP 的 fastcgi 相关的代码并没有被访问控制所限制!我们可以直接执行根目录下受限的 PHP 代码,因此只需要调用 h5ai 项目中的“下载” api 即可!
具体获取下载的 api 其实有很多方法,直接的方法是直接审计 h5ai 的源代码,还有就是既然 Public 是开放的,直接点击下载`nginx.conf`并观察其 HTTP Request 并加以改造即可。最终构造的 EXP 和 flag 输出如下:
```
$ curl -X POST http://202.38.93.111:10120/_h5ai/public/index.php -d "action=download&as=Public.tar&type=php-tar&baseHref=%2F&hrefs=&hrefs%5B0%5D=%2Fflag.txt" -o -
flag.txt0000755000000000000000000000003013744647043007466 0ustar00flag{super_secure_cloud}
```
### 题外话:
1. 这题改编自小 C 亲身经历,经过了戏剧化处理!其实小 C 就用类似的配置搭建过网盘,并被众所周知代号为“单位虚数”同学指出了其中错误!这个事情提醒了小 C,哪怕自认为再熟悉 Nginx 和 PHP,对待安全问题还是要保持敬畏之心。
2. 小 C 同学注意到某讨论群里有“狐狸”同学说`“这题只是小 C 同学脑子不太好使(”`。这令小 C 非常不开心,并企图决定取消该同学本题得分!最终“单位虚数”同学驳回了小 C 的该提案。
3. h5ai 是一个非常好用的开源目录系统,本题大概有不少同学对其最新版本进行了审计。有发现新漏洞或者有其他功能建议意见的同学可以到[原项目](https://github.com/lrsjng/h5ai)下提PR。原项目是 MIT 协议开源的,因本题导致的相关安全风险,小 C 毫不知情、毫无关系,无任何道德义务、直接或者间接的法律责任。
Binary file not shown.
@@ -0,0 +1,33 @@
server{
# Docker 内部的地址,无关紧要
listen 8080;
server_name _;
root /var/www/html;
index index.php index.html /_h5ai/public/index.php;
# _h5ai/private 文件夹下的内容是不可直接访问的,设置屏蔽
location ~ _h5ai/private {
deny all;
}
# 根目录是私有目录,使用 basic auth 进行认证,只有我(超极致的小 C)自己可以访问
location / {
auth_basic "easy h5ai. For visitors, please refer to public directory at `/Public!`";
auth_basic_user_file /etc/nginx/conf.d/htpasswd;
}
# Public 目录是公开的,任何人都可以访问,便于我给大家分享文件
location /Public {
allow all;
index /Public/_h5ai/public/index.php;
}
# PHP 的 fastcgi 配置,将请求转发给 php-fpm
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
@@ -0,0 +1,15 @@
version: '3.2'
services:
h5ai:
build: .
ports:
- 10120:10120
volumes:
- type: volume
source: cloud
target: /var/www/html
read_only: true
restart: always
volumes:
cloud:
@@ -0,0 +1,28 @@
FROM alpine:latest
EXPOSE 10120
WORKDIR /var/www/html
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
&& apk add nginx supervisor php7-fpm php7-session php7-json php7-gd php7-exif git wget unzip zip\
&& mkdir -p /var/www/html/Public \
&& wget https://release.larsjung.de/h5ai/h5ai-0.29.2.zip \
&& unzip h5ai-0.29.2.zip \
&& cp -rp /var/www/html/_h5ai /var/www/html/Public/_h5ai \
&& rm h5ai-0.29.2.zip \
&& mkdir /run/nginx
ADD ./supervisord.conf /etc/supervisor/conf.d/supervisord.conf
ADD ./nginx.conf /etc/nginx/nginx.conf
ADD ./php.ini /etc/php7/php.ini
RUN rm /etc/nginx/conf.d/default.conf
RUN chown -R nobody.nobody /var/www/html && \
chown -R nobody.nobody /run && \
chown -R nobody.nobody /var/lib/nginx && \
chown -R nobody.nobody /var/log/nginx && \
chown -R nobody.nobody /var/log/php7
USER nobody
ADD --chown=nobody ./flag.txt /var/www/html/
ADD --chown=nobody ./dockerfile ./nginx.conf /var/www/html/Public/
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
@@ -0,0 +1 @@
flag{super_secure_cloud}
@@ -0,0 +1 @@
h5ai:$apr1$hzUYny/A$/p0/ZFcTOxeFtO97llMN41
@@ -0,0 +1,81 @@
worker_processes 1;
error_log stderr warn;
pid /run/nginx.pid;
user nobody;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
# Define custom log format to include reponse times
log_format main_timed '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'$request_time $upstream_response_time $pipe $upstream_cache_status';
access_log /dev/stdout main_timed;
error_log /dev/stderr notice;
keepalive_timeout 65;
server_tokens off;
# Write temporary files to /tmp so they can be created as a non-privileged user
client_body_temp_path /tmp/client_temp;
proxy_temp_path /tmp/proxy_temp_path;
fastcgi_temp_path /tmp/fastcgi_temp;
uwsgi_temp_path /tmp/uwsgi_temp;
scgi_temp_path /tmp/scgi_temp;
server{
# Docker 内部的地址,无关紧要
listen 10120;
server_name _;
root /var/www/html;
index index.php index.html /_h5ai/public/index.php;
# _h5ai/private 文件夹下的内容是不可直接访问的,设置屏蔽
location ~ _h5ai/private {
deny all;
}
# 根目录是私有目录,使用 basic auth 进行认证,只有我(超极致的小 C)自己可以访问
location / {
auth_basic "easy h5ai. For visitors, please refer to public directory at `/Public!`";
auth_basic_user_file /etc/nginx/conf.d/htpasswd;
}
# Public 目录是公开的,任何人都可以访问,便于我给大家分享文件
location /Public {
allow all;
index /Public/_h5ai/public/index.php;
}
# PHP 的 fastcgi 配置,将请求转发给 php-fpm
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\. {
log_not_found off;
deny all;
}
}
gzip on;
gzip_proxied any;
gzip_types text/plain application/xml text/css text/js text/xml application/x-javascript text/javascript application/json application/xml+rss;
gzip_vary on;
gzip_disable "msie6";
# Include other server configs
include /etc/nginx/conf.d/*.conf;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,7 @@
# "/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"
# mkdir -p /run/nginx && touch /run/nginx/nginx.pid
# /usr/sbin/php-fpm7
# /usr/sbin/nginx -c /etc/nginx/nginx.conf -g 'daemon off;'
chmod 777 /run /var/lib/nginx /var/log/nginx /var/log/php7 /tmp
/usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
@@ -0,0 +1,23 @@
[supervisord]
nodaemon=true
logfile=/dev/null
logfile_maxbytes=0
pidfile=/run/supervisord.pid
[program:php-fpm]
command=/usr/sbin/php-fpm7 -F
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autorestart=true
startretries=0
[program:nginx]
command=/usr/sbin/nginx -c /etc/nginx/nginx.conf -g 'daemon off;'
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autorestart=true
startretries=0