注意,本文讨论的仅仅是如何绕过禁止规则进入 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)
的区别
第 3 条的 规则并不会 “封杀目录中包含 php 三个字母的文件如 /php/3038714494.png ” ,
正则解释 ^/upload/.*.(php|php5)($|/) 开始匹配^ 匹配任意多字符.* 匹配任意字符请输入代码.(怀疑此处其实他想匹配点,但是正则中的点代表任意字符) 结束或者目录符号($|/)
nginx 的 “.” 单独用的话它就是代表 “.” ,不用转义。
建议还是用 apache 跑 php
正确的做法不是 try_files 吗?
测试会封杀,再次测试依然被封杀
不转移, nginx 仅仅识别一个目录下而不能识别目录的目录下
/php/3038714494.png 404
/1/php/3038714494.png 403
啥?
问题是……对于 nginx 来说,只要没有 fastcgi
问题是……对于 nginx 来说,只要没有 fastcgi_pass 就不会交给 php 来处理
于是你为什么要给上传目录加 fastcgi_pass 呢?
只需要用^~ 防止上传路径被匹配到 php 的 block 里就可以了
同时,对于 php 的 block ,用 try_files 检查文件是否存在
或者用 fastcgi_split_path_info 代替 php 自己的 path_info 检测
这些都是性能很好而且简单清晰的解法
Duplicate with: /t/295225
我之前配置过一个,是把全部都重写到 index.php 的,也不知道怎么配置的,上传目录里面 php 那些全都不能执行,访问的话就变文件下载
你这跟第四种方法有啥不一样的吗?
天……那我是不是可以说我把 /etc/passwd 拷贝到任意文件夹下会泄漏?
是不是还要考虑 config.php 复制后被改名?
你知道 regex 很低效么?
我不知道你怎么测试的,还会有 404 的?
然后我写了一个,打开浏览器:
403
200
事实上我觉得用第一条就可以了,后面的几条包括你给的反而画蛇添足,把 php 的目录也排过滤掉了,比如网站头像图片存在 /usr/uploads/用户名目录下,当注册用户恰好叫 php ,如果用你那一条,那这个用户的头像 /usr/uploads/php/avatar.jpg 就无法显示了。
你举的反例我觉得很奇怪。
“绕过方法, 1.php 可以是个目录 /1.php/3038714494.png ”
绕过了什么? nginx 在这里并不是用来阻止上传文件上传到 /1.php 这个目录的,你要证明的是这个 png 会被当成 php 文件执行。
回复好像不支持 markdown ?
https://www.cellmean.com/upload/hello.php
https://www.cellmean.com/upload/php/a.jpg
上传文件不放公开目录,必须通过程序转发直接输出下载。
不过好像楼主说的是通过 nginx 正则...文不对题了...
/etc/passwd 受 chroot 限制,不会越出网站目录,顶多访问 tmp 和网站根目录。当然 chroot 是自己配的
需要考虑,但是在目前只能称他为瑕疵,因为改后缀名就变得不好考虑了
很低是有多低,很高效又是多高效
禁止上传目录 php 执行,不是禁止上传
禁止上传目录 php 执行 请连起来看
后面的正则确实太过复杂,效率太低,其实防止上传的文件保存为 .php 后缀到 upload 文件夹就没事了,将上传的文件 hash 一下不带后缀或者后缀检查
nginx 配置讲究简洁高效,程序和 nginx 配合做到高效安全就好了
这是在讨论正则吗。。
理论上述说,还是代码和其他文件分开比较好
并不是为了防止.php 后缀,而是为了防止图片马用.php 前缀绕过
那里不是正则?
我觉得第一条就是最直观最好的方法,后面确实是吹毛求疵,不知道文章种说的第一条绕过方法有什么问题,且不说一般不会用 .php 作为文件夹名,就算用 .php 做文件夹名也不会有什么问题
现在的一些基于 tp 的网站,连根目录都必须有写入权限,已经不明白他怎么想的了
http://www.2cto.com/Article/201502/378373.html
第一种方法是典型的解析漏洞
所以我一直觉得 PHP 程序的部署是很难的
try_files 加 =404 就好了,并且现在 cgi.fix_pathinfo 配置都是(推荐)关掉的,并且现在的 php-fpm 的默认配置应该也能避免它;总之这种漏洞很容易用其他方法避免
那就请看文章第一句话