吹毛求疵还是精益求精?再谈 nginx fastcgi/fpm 正则禁止上传目录 php 执行 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
tntsec
V2EX    NGINX

吹毛求疵还是精益求精?再谈 nginx fastcgi/fpm 正则禁止上传目录 php 执行

  •  
  •   tntsec 2016-07-29 11:55:57 +08:00 6800 次点击
    这是一个创建于 3436 天前的主题,其中的信息可能已经有所发展或是发生改变。

    注意,本文讨论的仅仅是如何绕过禁止规则进入 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)的区别

    28 条回复    2016-07-30 10:28:02 +08:00
    GG668v26Fd55CP5W
        1
    GG668v26Fd55CP5W  
       2016-07-29 13:40:14 +08:00
    第 3 条的 规则并不会 “封杀目录中包含 php 三个字母的文件如 /php/3038714494.png ” ,

    正则解释 ^/upload/.*.(php|php5)($|/) 开始匹配^ 匹配任意多字符.* 匹配任意字符请输入代码.(怀疑此处其实他想匹配点,但是正则中的点代表任意字符) 结束或者目录符号($|/)

    nginx 的 “.” 单独用的话它就是代表 “.” ,不用转义。
    strwei
        2
    strwei  
       2016-07-29 13:55:34 +08:00 via iPhone
    建议还是用 apache 跑 php
    lhbc
        3
    lhbc  
       2016-07-29 14:58:17 +08:00 via Android   1
    正确的做法不是 try_files 吗?
    tntsec
        4
    tntsec  
    OP
       2016-07-29 17:38:19 +08:00
    @falcon05 测试会封杀,再次测试依然被封杀
    不转移, nginx 仅仅识别一个目录下而不能识别目录的目录下
    /php/3038714494.png 404
    /1/php/3038714494.png 403
    tntsec
        5
    tntsec  
    OP
       2016-07-29 17:38:51 +08:00
    @lhbc 啥?
    ryd994
        6
    ryd994  
       2016-07-29 18:37:25 +08:00
    问题是……对于 nginx 来说,只要没有 fastcgi
    ryd994
        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 检测

    这些都是性能很好而且简单清晰的解法
    ryd994
        8
    ryd994  
       2016-07-29 18:44:48 +08:00
    @Livid Duplicate with: /t/295225
    ysc3839
        9
    ysc3839  
       2016-07-29 18:49:27 +08:00 via Android
    我之前配置过一个,是把全部都重写到 index.php 的,也不知道怎么配置的,上传目录里面 php 那些全都不能执行,访问的话就变文件下载
    tntsec
        10
    tntsec  
    OP
       2016-07-29 19:06:29 +08:00
    @ryd994 你这跟第四种方法有啥不一样的吗?
    ryd994
        11
    ryd994  
       2016-07-29 20:31:54 +08:00
    @tntsec 天……那我是不是可以说我把 /etc/passwd 拷贝到任意文件夹下会泄漏?
    是不是还要考虑 config.php 复制后被改名?
    你知道 regex 很低效么?
    GG668v26Fd55CP5W
        12
    GG668v26Fd55CP5W  
       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 文件执行。
    GG668v26Fd55CP5W
        13
    GG668v26Fd55CP5W  
       2016-07-29 20:57:28 +08:00
    z5864703
        14
    z5864703  
       2016-07-30 00:30:09 +08:00
    上传文件不放公开目录,必须通过程序转发直接输出下载。
    不过好像楼主说的是通过 nginx 正则...文不对题了...
    tntsec
        15
    tntsec  
    OP
       2016-07-30 09:34:25 +08:00
    @ryd994 /etc/passwd 受 chroot 限制,不会越出网站目录,顶多访问 tmp 和网站根目录。当然 chroot 是自己配的
    需要考虑,但是在目前只能称他为瑕疵,因为改后缀名就变得不好考虑了
    很低是有多低,很高效又是多高效
    tntsec
        16
    tntsec  
    OP
       2016-07-30 09:40:42 +08:00
    @falcon05 禁止上传目录 php 执行,不是禁止上传
    tntsec
        17
    tntsec  
    OP
       2016-07-30 09:41:24 +08:00
    @z5864703 禁止上传目录 php 执行 请连起来看
    kiwi95
        18
    kiwi95  
       2016-07-30 09:47:11 +08:00
    后面的正则确实太过复杂,效率太低,其实防止上传的文件保存为 .php 后缀到 upload 文件夹就没事了,将上传的文件 hash 一下不带后缀或者后缀检查

    nginx 配置讲究简洁高效,程序和 nginx 配合做到高效安全就好了
    aprikyblue
        19
    aprikyblue  
       2016-07-30 09:52:12 +08:00 via Android
    这是在讨论正则吗。。
    jarlyyn
        20
    jarlyyn  
       2016-07-30 09:52:44 +08:00 via Android
    理论上述说,还是代码和其他文件分开比较好
    tntsec
        21
    tntsec  
    OP
       2016-07-30 09:53:02 +08:00
    @kiwi95 并不是为了防止.php 后缀,而是为了防止图片马用.php 前缀绕过
    tntsec
        22
    tntsec  
    OP
       2016-07-30 09:53:52 +08:00
    @aprikyblue 那里不是正则?
    kiwi95
        23
    kiwi95  
       2016-07-30 09:57:35 +08:00
    我觉得第一条就是最直观最好的方法,后面确实是吹毛求疵,不知道文章种说的第一条绕过方法有什么问题,且不说一般不会用 .php 作为文件夹名,就算用 .php 做文件夹名也不会有什么问题
    tntsec
        24
    tntsec  
    OP
       2016-07-30 09:58:02 +08:00
    @jarlyyn 现在的一些基于 tp 的网站,连根目录都必须有写入权限,已经不明白他怎么想的了
    tntsec
        25
    tntsec  
    OP
       2016-07-30 10:01:40 +08:00
    @kiwi95 http://www.2cto.com/Article/201502/378373.html
    第一种方法是典型的解析漏洞
    jarlyyn
        26
    jarlyyn  
       2016-07-30 10:03:02 +08:00 via Android
    @tntsec

    所以我一直觉得 PHP 程序的部署是很难的
    kiwi95
        27
    kiwi95  
       2016-07-30 10:18:32 +08:00
    @tntsec try_files 加 =404 就好了,并且现在 cgi.fix_pathinfo 配置都是(推荐)关掉的,并且现在的 php-fpm 的默认配置应该也能避免它;总之这种漏洞很容易用其他方法避免
    tntsec
        28
    tntsec  
    OP
       2016-07-30 10:28:02 +08:00
    @kiwi95 那就请看文章第一句话
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3513 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 44ms UTC 04:24 PVG 12:24 LAX 20:24 JFK 23:24
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86