0x00前言
文件上传漏洞如果利用的好就是一个getshell,往往取得的成果比sql注入要大
它的原理是未对文件名或后缀或者内容进行良好的处理,所导致能够使后台语言调用系统命令的函数被攻击者可控导致的
但是写shell到文件中不仅仅是有个上传按钮的地方能控制文件内容,看过cms代码审计相关文章就知道还有些函数把传入的参数进行写入文件的操作
能够进行文件写入的常见函数有
move_uploaded_file(string filename, string path)
这个函数是文件上传的主要执行的函数,filename文件地址,path文件保存的路径
fwrite(file,string[,length])
file为fopen打开的文件变量且该文件要可写,string为写入内容
file_put_contents ( filename , data [, flags = 0 [, context ]] )
filename文件路径+名字,data写入的内容,如果flag=FILE_APPEND,那么就是在文件后面追加内容
如果文件不存在会创建个新的
fwrite的限制比较大,但是只要写入可控,那么还是有一定可能性写入后面代码的
0x01文件上传的检验方式
原理
文件上传这个功能按钮的实现只有move_uploaded_file这个函数,它传递是用$_FILES这个全局变量数组来实现的,只要把文件上传表单提交到目标页面就能获取相应的信息
- $_FILES["file"]["name"] - 上传文件的名称
- $_FILES["file"]["type"] - 上传文件的类型
- $_FILES["file"]["size"] - 上传文件的大小,以字节计
- $_FILES["file"]["tmp_name"] - 存储在服务器的文件的临时副本的名称
- $_FILES["file"]["error"] - 由文件上传导致的错误代码
php文件上传功能首先是将文件上传到tmp文件夹下(可以在php.ini里面设置upload_tmp_dir参数为tmp文件夹类型,linux下是默认/tmp文件夹,windows下是默认C:\Users\运行用户名\AppData\Local\Temp\)
然后调用file_uploaded_move函数将tmp下的临时文件传到指定路径下
最后php会自动把默认路径下的文件删除
验证方式
在可用的5个参数里面,能够达到验证文件合法性的效果是$_FILES['file']['name']和$_FILES['file']['type']这2个,他们实质是检查文件名和文件内容,但是无法检查文件的内容。
$_FILES['file']['type']的检验是取Content-Type对应的值,这个值在http请求头的地方是可控的,因此该检验方法是存在绕过的
而$_FILES['file']['name']的处理一般是取后缀进行白名单或者黑名单检验
0x02常见处理和绕过方式
处理方式一般为(当然有其他情况可能绕过)
$ext = end(explode('.', $filename));
白名单一般只能上传jpg,png等图片文件,一般绕不过
黑名单会现在php,phtml,php5等后缀文件,但是如果考虑不周到会导致一些可行的后缀没被过滤到,因此白名单更加的安全
过滤如果利用in_array()会造成如果在后面加个空格则会使其不能完全匹配,而达到绕过
常见的php后缀
php.pht.phtml.php3,php4,php5,php6,php7
php的后缀文件名,位于apache里面的apache2/mods-available/phpx.x.conf中有详细的正则规则,一般服务器不会改,因此上面的可能存在没过滤严格导致的绕过
有时会有将存储文件给随机化,但是如果知道随机的范围和上传的路径,可以通过暴力破解的方式获取
所谓的%00截断,是指在写入file_uploaded_move写入文件的时候把%00后面的内容给截取掉,达到“合法”的绕过前面的检查,但是在上传的时候保存成我们恶意的文件类型
仅5.3版本及以下可用