因为截断条件是php版本小于5.3.4,php的magic_quotes_gpc为OFF状态,所以得先在相应的php版本目录下找到配置文件php.ini,然后把magic_quotes_gpc的状态修改为OFF,修改完之后重启一下服务就可以了。
用Burp Suite代理构造sava_path=/upload/ok.php%00,然后再filename处修改文件拓展名为png(或jpg、gif)
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$ext_arr = array('jpg','png','gif');
$file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1);
if(in_array($file_ext,$ext_arr)){
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else{
$msg = "只允许上传.jpg|.png|.gif类型文件!";
}
}
这里使用了白名单过滤,只允许上传.jpg|.png|.gif类型文件,而且文件保存的方式是上传路径+随机数+时间+截取的文件拓展名,就是说上传的文件会被重命名为一个随机数+时间的字符串,所以不能再从filename那里下手了,得在保存文件的时候下手。因为$img_path是直接拼接的,可以考虑对sava_path下手,在save_path后面加上文件名并且在文件名后面加上%00,这样保存文件的时候就会用加上去的文件名,又因为在后面加了%00,move_uploaded_file函数遇到%00就会认为已经结束,从而忽略了后面的随机数和时间以及拓展名。
相关函数:
move_uploaded_file($temp_file,$img_path) 函数把上传的文件($temp_file)移动到新位置($img_path)。如果成功该函数返回 TRUE,如果失败则返回 FALSE。
参考链接:https://www.runoob.com/php/func-filesystem-move-uploaded-file.html
还是和上一关一样,用Burp Suite代理构造sava_path=/upload/ok.php%00,然后再filename处修改文件拓展名为png(或jpg、gif),由于这一关不能对%00进行自动解码,所以还需要在二进制中进行修改,把ok.php对应的二进制数后面一位改成00。
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$ext_arr = array('jpg','png','gif');
$file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1);
if(in_array($file_ext,$ext_arr)){
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = $_POST['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
} else {
$msg = "上传失败";
}
} else {
$msg = "只允许上传.jpg|.png|.gif类型文件!";
}
}
这里的源码基本和pass 11一样,唯一的不同就是,这里的save_path参数通过POST方式传递的,pass 11的save_path参数通过GET方式传递的,因为POST不会像GET对%00进行自动解码,所以这里需要在二进制中进行修改。
制作图片木马,在文件头部加上GIF文件的头部标识(GIF89a),当服务器检测文件头时,检测到GIF89a即判定该文件为GIF文件。再写入一句话木马,将文件保存为GIF格式,上传。
图片文件头标识参考链接:https://blog.csdn.net/qq_37414405/article/details/84660148
上传文件后在响应包中可以找到文件上传的路径,以便后面访问。
因为直接访问GIF格式图片不能正常解析里面的php代码,所以这里得结合文件包含漏洞利用。用下面代码写一个include.php的文件放在靶场的WWW\upload-labs\upload\下面。
##include.php
通过文件包含漏洞访问GIF文件,其中的php被成功解析。
function getReailFileType($filename){
$file = fopen($filename, "rb");
$bin = fread($file, 2); //只读2字节
fclose($file);
$strInfo = @unpack("C2chars", $bin);
$typeCode = intval($strInfo['chars1'].$strInfo['chars2']);
$fileType = '';
switch($typeCode){
case 255216:
$fileType = 'jpg';
break;
case 13780:
$fileType = 'png';
break;
case 7173:
$fileType = 'gif';
break;
default:
$fileType = 'unknown';
}
return $fileType;
}
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$temp_file = $_FILES['upload_file']['tmp_name'];
$file_type = getReailFileType($temp_file);
if($file_type == 'unknown'){
$msg = "文件未知,上传失败!";
}else{
$img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").".".$file_type;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
} else {
$msg = "上传出错!";
}
}
}
这里相对之前的代码,多了个文件内容检测,即通过读文件的前2个字节判断文件类型,因此想通过文件名绕过检测上传木马已经行不通了,但可以在内容里面加上图片文件的头标识,这样当服务器检测到添加图片文件头标识时,就会判定该文件为图片格式,成功绕过内容检测。
方法同pass 13一样
function isImage($filename){
$types = '.jpeg|.png|.gif';
if(file_exists($filename)){
$info = getimagesize($filename);
$ext = image_type_to_extension($info[2]);
if(stripos($types,$ext)>=0){
return $ext;
}else{
return false;
}
}else{
return false;
}
}
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$temp_file = $_FILES['upload_file']['tmp_name'];
$res = isImage($temp_file);
if(!$res){
$msg = "文件未知,上传失败!";
}else{
$img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").$res;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
} else {
$msg = "上传出错!";
}
}
}
这里还是和上一关一样,对文件做了内容检测。但这里用的是getimagesize() 函数判断文件类型,该函数作用是获取图像大小及相关信息,成功返回一个数组,失败则返回 FALSE 并产生一条 E_WARNING 级的错误信息。
getimagesize() 函数参考链接:https://www.runoob.com/php/php-getimagesize.html
绕过方法和pass 13 一样,但这关需要开启php_exif模块才能正常运行。
开启php_exif模块方法:
1.在php.ini文件中找到;extension=php_exif.dll,去掉前面的分号
2.在php.ini文件中找到;extension=php_mbstring.dll,去掉前面的分号,并将此行移动到extension=php_exif.dll之前,使之首先加载*。
3.找到[exif]段,把下面语句的分号去掉。
;exif.encode_unicode = ISO-8859-15
;exif.decode_unicode_motorola = UCS-2BE
;exif.decode_unicode_intel = UCS-2LE
;exif.encode_jis =
;exif.decode_jis_motorola = JIS
;exif.decode_jis_intel = JIS
4.重启php服务
参考链接:https://www.cnblogs.com/cookies9/p/9209252.html
function isImage($filename){
//需要开启php_exif模块
$image_type = exif_imagetype($filename);
switch ($image_type) {
case IMAGETYPE_GIF:
return "gif";
break;
case IMAGETYPE_JPEG:
return "jpg";
break;
case IMAGETYPE_PNG:
return "png";
break;
default:
return false;
break;
}
}
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$temp_file = $_FILES['upload_file']['tmp_name'];
$res = isImage($temp_file);
if(!$res){
$msg = "文件未知,上传失败!";
}else{
$img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").".".$res;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
} else {
$msg = "上传出错!";
}
}
}
这里基本和前面2关一样,绕过方法也一样,不同的是这里用到php_exif模块来判断文件类型。
exif_imagetype函数参考:https://www.cnblogs.com/phpBigbin/p/7945273.html
制作图片木马,在cmd命令下执行copy 1.gif/b + ok.php/a 2.gif,将1.gif的图片文件和ok.php的木马合并成2.gif。
一句话木马被插入到gif图片中。
上传2.gif,上传的图片都经过了二次渲染,我们用16进制编辑器将经过二次渲染和正常的图片打开进行对比。看那一部分没被覆盖,然后将代码插入到该地方。再次上传重新制作的木马图片,结合文件包含漏洞即可访问木马。
具体参考:https://xz.aliyun.com/t/2657#toc-2
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])){
// 获得上传文件的基本信息,文件名,类型,大小,临时文件路径
$filename = $_FILES['upload_file']['name'];
$filetype = $_FILES['upload_file']['type'];
$tmpname = $_FILES['upload_file']['tmp_name'];
$target_path=UPLOAD_PATH.'/'.basename($filename);
// 获得上传文件的扩展名
$fileext= substr(strrchr($filename,"."),1);
//判断文件后缀与类型,合法才进行上传操作
if(($fileext == "jpg") && ($filetype=="image/jpeg")){
if(move_uploaded_file($tmpname,$target_path)){
//使用上传的图片生成新的图片
$im = imagecreatefromjpeg($target_path);
if($im == false){
$msg = "该文件不是jpg格式的图片!";
@unlink($target_path);
}else{
//给新图片指定文件名
srand(time());
$newfilename = strval(rand()).".jpg";
//显示二次渲染后的图片(使用用户上传图片生成的新图片)
$img_path = UPLOAD_PATH.'/'.$newfilename;
imagejpeg($im,$img_path);
@unlink($target_path);
$is_upload = true;
}
} else {
$msg = "上传出错!";
}
}else if(($fileext == "png") && ($filetype=="image/png")){
if(move_uploaded_file($tmpname,$target_path)){
//使用上传的图片生成新的图片
$im = imagecreatefrompng($target_path);
if($im == false){
$msg = "该文件不是png格式的图片!";
@unlink($target_path);
}else{
//给新图片指定文件名
srand(time());
$newfilename = strval(rand()).".png";
//显示二次渲染后的图片(使用用户上传图片生成的新图片)
$img_path = UPLOAD_PATH.'/'.$newfilename;
imagepng($im,$img_path);
@unlink($target_path);
$is_upload = true;
}
} else {
$msg = "上传出错!";
}
}else if(($fileext == "gif") && ($filetype=="image/gif")){
if(move_uploaded_file($tmpname,$target_path)){
//使用上传的图片生成新的图片
$im = imagecreatefromgif($target_path);
if($im == false){
$msg = "该文件不是gif格式的图片!";
@unlink($target_path);
}else{
//给新图片指定文件名
srand(time());
$newfilename = strval(rand()).".gif";
//显示二次渲染后的图片(使用用户上传图片生成的新图片)
$img_path = UPLOAD_PATH.'/'.$newfilename;
imagegif($im,$img_path);
@unlink($target_path);
$is_upload = true;
}
} else {
$msg = "上传出错!";
}
}else{
$msg = "只允许上传后缀为.jpg|.png|.gif的图片文件!";
}
}
这里判断了后缀名以及Content-Type,然后再用imagecreatefrom[gif|png|jpg]函数判断是否是图片格式,如果是图片的话再用image[gif|png|jpg]函数对其进行二次渲染,经过二次渲染的文件有可能会把我们添加进去的内容覆盖掉,所以绕过方法是把内容添加在不会被覆盖的地方。
观察结果可以发现有一小部分访问成功。
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$ext_arr = array('jpg','png','gif');
$file_name = $_FILES['upload_file']['name'];
$temp_file = $_FILES['upload_file']['tmp_name'];
$file_ext = substr($file_name,strrpos($file_name,".")+1);
$upload_file = UPLOAD_PATH . '/' . $file_name;
if(move_uploaded_file($temp_file, $upload_file)){
if(in_array($file_ext,$ext_arr)){
$img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext;
rename($upload_file, $img_path);
$is_upload = true;
}else{
$msg = "只允许上传.jpg|.png|.gif类型文件!";
unlink($upload_file);
}
}else{
$msg = '上传出错!';
}
}
这里是条件竞争,先将文件上传到服务器,然后判断文件后缀是否在白名单里,如果在则重命名,否则删除,因此我们可以上传木马文件,只需要在它删除之前访问即可,可以利用burp的intruder模块不断上传,然后利用burp的intruder模块不断访问木马文件,有部分访问是成功的。
方法与pass 17一样
这里先用move函数将上传的文件保存,再用renameFile函数重命名。所以也存在条件竞争,绕过方法和上面Pass-17差不多。
上传文件ok.php,保存文件那里填ok.php.jpg,上传,用burp将save_name那里的ok.php.jpg中php后面的点的十六进制(2e)改为00
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess");
$file_name = $_POST['save_name'];
$file_ext = pathinfo($file_name,PATHINFO_EXTENSION);
if(!in_array($file_ext,$deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH . '/' .$file_name;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
}else{
$msg = '上传出错!';
}
}else{
$msg = '禁止保存为该类型文件!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
这里利用了黑名单过滤,发现这里img_path可控(通过post sava_name),所以可以利用move_uploaded_file的\x00截断(save_name=ok.php%00jpg)绕过。
pass 11、12、19 是利用00截断绕过,主要原理是在文件拓展名后面加上00(表示字符串结束),当函数读取到00的时候就会截断
pass 13-15 主要是在文件内添加图片头文件标识,以此绕过服务器对内容的检测
pass 16 是绕过二次渲染,通过对比找出二次渲染后没有被覆盖的部分,然后在该部分出入木马
pass 17-18是条件竞争,通过Burp suite的intuder模块进行大量的上传请求及访问请求,以求文件被删除之前访问
参考链接:https://www.jianshu.com/p/aabc1e7408d5