注意,本文讨论的仅仅是如何绕过禁止规则进入 cgi 。
nginx fastcgi/fpm 禁止上传目录 php 执行 因为上传目录是具备写入权限的,写入权限很恐怖。
1.最常见的,完全错误的方法 来源,百度下最常见的
location ~ ^/upload/.*\.(php|php5)$
{
deny all;
}
正则解释
^/upload/.*.(php|php5)$
开头匹配^
中间任意匹配.*
点匹配\.
(php|php5)php
扩展名选择器 结尾匹配$
绕过方法, 1.php 可以是个目录 /1.php/3038714494.png
2.Nginx 下多站点正确限制目录 php 执行权限 来源 http://www.freebuf.com/articles/system/49428.html
location ~ /(ups)/.*\.(php|php5)?$
{
deny all;
}
正则解释
比上面的多了一个?
问号,问号代表零次或一次。
绕过方式,同上 /1.php/3038714494.png
3.nginx+cgi 解析 php 容易出现的漏洞 来源 http://www.nginx.cn/316.html
location ~* ^/upload/.*.(php|php5)($|/)
{
deny all;
}
正则解释
^/upload/.*.(php|php5)($|/)
开始匹配^
匹配任意多字符.*
匹配任意字符请输入代码
.(怀疑此处其实他想匹配点,但是正则中的点代表任意字符) 结束或者目录符号($|/)
此方式解决了上面的绕过问题
缺点,封杀太严格,目录中包含 php 三个字母就会封杀 /php/3038714494.png
4.关于 lnmp 目录禁止执行的绕过与正确方法 来源地址 http://zone.wooyun.org/content/16213 谷歌缓存 http://webcache.googleusercontent.com/search?q=cache:g3B4qj-SGXgJ:zone.wooyun.org/content/16213+&cd=1&hl=zh-CN&ct=clnk&gl=cn
location ^~ /upload/ {
default_type text/plain;
expires 30d;
}
解释,这不是正则,却更加有趣 ^~表示匹配一次,不再让其他 location 处理,从而不会匹配到 cgi 中 这种方式需要的判断最少,是非常好的方式
他只有一点点瑕疵
,那就是源码泄漏
如果 config.php 文件被复制到这个目录下,源码一览无余。因为这个方法只是不让 php 进入 cgi ,但是却没有禁止他的解析。
5.我的方法 当你看完上面的内容,相信你已经有了自己的方法了 我这里稍微修改下第三种方法,就是括号里的部分
location ~ (/usr/uploads/|/admin/).*\.(php|php5)($|/) {
deny all;
}
增加的部分 location ~ (/usr/uploads/|/admin/).*\
.(php|php5)($|/)
将从匹配任意字符调整为匹配点,这样就不会拦截包含 php 字符的目录了,但是依然会拦截
如果出现.php
目录,我们可以默认认为他是黑客行为。
小提示,注意(/usr/uploads/|/admin/)和(/usr/uploads|/admin)
的区别
1
falcon05 2016-07-29 13:40:14 +08:00
第 3 条的 规则并不会 “封杀目录中包含 php 三个字母的文件如 /php/3038714494.png ” ,
正则解释 ^/upload/.*.(php|php5)($|/) 开始匹配^ 匹配任意多字符.* 匹配任意字符请输入代码.(怀疑此处其实他想匹配点,但是正则中的点代表任意字符) 结束或者目录符号($|/) nginx 的 “.” 单独用的话它就是代表 “.” ,不用转义。 |
2
strwei 2016-07-29 13:55:34 +08:00 via iPhone
建议还是用 apache 跑 php
|
3
lhbc 2016-07-29 14:58:17 +08:00 via Android 1
正确的做法不是 try_files 吗?
|
4
tntsec OP @falcon05 测试会封杀,再次测试依然被封杀
不转移, nginx 仅仅识别一个目录下而不能识别目录的目录下 /php/3038714494.png 404 /1/php/3038714494.png 403 |
6
ryd994 2016-07-29 18:37:25 +08:00
问题是……对于 nginx 来说,只要没有 fastcgi
|
7
ryd994 2016-07-29 18:43:26 +08:00
问题是……对于 nginx 来说,只要没有 fastcgi_pass 就不会交给 php 来处理
于是你为什么要给上传目录加 fastcgi_pass 呢? 只需要用^~ 防止上传路径被匹配到 php 的 block 里就可以了 同时,对于 php 的 block ,用 try_files 检查文件是否存在 或者用 fastcgi_split_path_info 代替 php 自己的 path_info 检测 这些都是性能很好而且简单清晰的解法 |
9
ysc3839 2016-07-29 18:49:27 +08:00 via Android
我之前配置过一个,是把全部都重写到 index.php 的,也不知道怎么配置的,上传目录里面 php 那些全都不能执行,访问的话就变文件下载
|
11
ryd994 2016-07-29 20:31:54 +08:00
|
12
falcon05 2016-07-29 20:51:47 +08:00
@tntsec 我不知道你怎么测试的,还会有 404 的?
然后我写了一个,打开浏览器: <https://www.cellmean.com/upload/hello.php> 403 <https://www.cellmean.com/upload/php/a.jpg> 200 事实上我觉得用第一条就可以了,后面的几条包括你给的反而画蛇添足,把 php 的目录也排过滤掉了,比如网站头像图片存在 /usr/uploads/用户名目录下,当注册用户恰好叫 php ,如果用你那一条,那这个用户的头像 /usr/uploads/php/avatar.jpg 就无法显示了。 你举的反例我觉得很奇怪。 “绕过方法, 1.php 可以是个目录 /1.php/3038714494.png ” 绕过了什么? nginx 在这里并不是用来阻止上传文件上传到 /1.php 这个目录的,你要证明的是这个 png 会被当成 php 文件执行。 |
13
falcon05 2016-07-29 20:57:28 +08:00
|
14
z5864703 2016-07-30 00:30:09 +08:00
上传文件不放公开目录,必须通过程序转发直接输出下载。
不过好像楼主说的是通过 nginx 正则...文不对题了... |
15
tntsec OP @ryd994 /etc/passwd 受 chroot 限制,不会越出网站目录,顶多访问 tmp 和网站根目录。当然 chroot 是自己配的
需要考虑,但是在目前只能称他为瑕疵,因为改后缀名就变得不好考虑了 很低是有多低,很高效又是多高效 |
18
kiwi95 2016-07-30 09:47:11 +08:00
后面的正则确实太过复杂,效率太低,其实防止上传的文件保存为 .php 后缀到 upload 文件夹就没事了,将上传的文件 hash 一下不带后缀或者后缀检查
nginx 配置讲究简洁高效,程序和 nginx 配合做到高效安全就好了 |
19
aprikyblue 2016-07-30 09:52:12 +08:00 via Android
这是在讨论正则吗。。
|
20
jarlyyn 2016-07-30 09:52:44 +08:00 via Android
理论上述说,还是代码和其他文件分开比较好
|
22
tntsec OP @aprikyblue 那里不是正则?
|
23
kiwi95 2016-07-30 09:57:35 +08:00
我觉得第一条就是最直观最好的方法,后面确实是吹毛求疵,不知道文章种说的第一条绕过方法有什么问题,且不说一般不会用 .php 作为文件夹名,就算用 .php 做文件夹名也不会有什么问题
|
25
tntsec OP |