关于上传中00截断的理解与分析

前言

今天面试的时候,碰巧面试官问了相关00截断的问题。之前恰巧看到过一篇文章,是专门讲解与分析00截断的,原文地址在这儿。

http://www.admintony.com/%E5%85%B3%E4%BA%8E%E4%B8%8A%E4%BC%A0%E4%B8%AD%E7%9A%8400%E6%88%AA%E6%96%AD%E5%88%86%E6%9E%90.html

虽然看是看过,当时也稍微记录了一些。但是回答起来也不知道是紧张还是什么原因,答得语无伦次。

于是重新再看一遍,再做一次记录。

00截断用在哪儿

初学者刚用00截断的时候,往往会按照网上教程,上传如1.php%00a.jpg这种形式绕过00截断。但有时候会成功,有时候会失败,为什么呢?

先说结论:除了php配置的那个解析漏洞之外,正经使用%00截断绕过应该是放在上传文件路径后,而非文件名处。

再说原理

00截断原理,为什么能做到00截断?

答:0x00是字符串的结束标识符,攻击者通过手动添加字符串标识符的方式,将00后面内容截断。但是00后面的东西又能帮助我们绕过文件检测。

00截断自然是存在限制,要求GPC处于关闭状态,且php版本小于5.3.29才可利用。

为什么00截断用在上传后文件目录

在文件名中构造00截断,比如1.php%001.jpg。在程序提取后缀名的时候,遇到%00就认为结束了。这个时候,他提取到的后缀名还是.php,然后.php被限制上传,所以绕过失败。

附上上传文件后缀名检测的代码

$uploaded_name = $_FILES[ 'file' ][ 'name' ];
$uploaded_ext  = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1); // 提取上传文件后缀
$target_name = md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext; // 对上传文件进行重命名
if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" )) 
{  
    move_uploaded_file($_FILES["file"]["tmp_name"],
    $dir . $target_name); // 将临时文件移动到指定目录
    $result = $dir . $target_name;
    echo "Stored in: $result"; 
}
else{
    echo "Invalid file";
}

正确用法

在数据包中,含有上传后文件目录的情况才可使用。比如在数据包中存在path:/uploads/

这种情况,可以这样上传/uploads/1.php%00

这样一来,程序提取后缀名的时候就会合法,然后拼接路径与文件名。这个时候的拼接结果应该就是:/uploads/1.php%00/xxxxxxxx.php

于是移动文件的时候,就会把00后面的东西视作不存在,结果就变成了/uploads/1.php,从而getshell。

注意点

为什么网上有的%00不用改动,有的却要进行urldecode呢?

因为在上传表单中存在一个enctype的属性,而且在enctype=”multipart/form-data”这里,是不会对表单中的数据进行解码的。

而path(路径)又大多存放在表单中,所以需要对%00进行urldecode

简单粗暴点说,在碰到multipart/from-data的时候,就需要进行urldecode 了。

为什么有的%00不用改动呢?

因为path也有可能直接存在url、cookie里边,在提交数据的时候,浏览器会对数据进行url编码。到服务器,则会对数据进行一次解码操作。

简单些说,path在url、cookie或者上传方式不是multipart/from-data的时候,就不用进行url编码


   转载规则


《关于上传中00截断的理解与分析》 tatsumaki 采用 知识共享署名 4.0 国际许可协议 进行许可。
  目录