来看源码
首先是弱比较(不能等于4476)然后是正则比较不能出现大小写的字母最后就是等于4476;
过滤了字母,所以不能用16进制,可以用8进制或者小数绕过
/?num=010574 或 /?num=4476.1
来看源码
函数分析:
strpos()函数返回匹配的字符位置,默认从0开始
strpos(string,find,start)
string 必需。规定要搜索的字符串。
find 必需。规定要查找的字符串。
start 可选。规定在何处开始搜索。
if(!strpos($num, "0")){ die("no no no!"); }
如果不出现0的话会返回-1,第一个为0的话会返回0,都会die
过滤了0-9,意味着不能再用进制过滤了,发现第一个判断句if中的“4476”是个字符,而在intval函数里,4476.0会被转换成int,所以会相等.那么我们就使用num=4476.0来绕过
来看源码
发现点也被过滤了,那么我们就不能使用小数绕过
根据intval()的特性可以通过8进制绕过但是前面必须多加一个字节,几个payload:
?num= 010574
?num=%0a010574
?num=%20010574
?num=+010574
这题很简单,highlight_file
里面表示的是文件路径,参数不能等于flag.php
可以用./
表示当前目录,或者用绝对路径,或者使用php伪协议
u=./flag.php 相对路径
u=/var/www/html/flag.php 绝对路径,猜
u=php://filter/resource=flag.php php伪协议
看源码要求POST提交的a和b的值不相等,但是md5加密后的值相等
三个=号,是属于强碰撞
md5()
函数无法处理数组,如果传入的值为数组,会返回NULL,所以两个数组经过加密后得到的都是NULL,也就是强相等的
使用POST提交 a[]=1&b[]=2
&是引用符号,意思是:不同的名字访问同一个变量内容。php的引用是在变量或者函数、对象等前面加上&符号,PHP 的引用允许你用两个变量来指向同一个内容
三元运算符
条件表达式?表达式1:表达式2
条件表达式为true时调用表达式1,为false时调用表达式2
$_GET
=&$_POST
就相当于$_GET
指向了$_POST
的地址,如果$_GET
改变了$_POST
也要跟着变,同理,$_POST
变了$_GET
也会跟着变。关键的就是HTTP_FALG=flag,这样才就能回显flag了
第一句存在变量覆盖的效果,所以GET请求不管给什么东西都会被POST请求覆盖掉
直接GET型提交flag会被flag的COOKIE
、SERVER
覆盖,但最后需要GET型提交HTTP_FLAG=flag
GET传参:/? //随便传,不能没有
POST传参:HTTP_FLAG=flag
array_push() 函数向第一个参数的数组尾部添加一个或多个元素
rand() 函数返回随机整数
isset() 函数用于检测变量是否已设置并且非 NULL
in_array()函数搜索数组中是否存在指定的值
file_put_contents() 函数把一个字符串写入文件中。如果文件不存在,将创建一个文件;如果成功,该函数将返回写入文件中的字符数。如果失败,则返回 False。
重点是array_push()
将随机数(必定有1)添加到数组$allow
中
in_array()
函数搜索数组中是否存在指定的值
$array数组里面的是int,我们传入的是字符串,在php字符串和int比较,字符串会被转换成int,因为是弱类型转换,所以 字符串中数字后面的字符串会被忽略
由于in_array没有设置type,我们可以输入1.php,转换之后也就是1,肯定是in_array的,满足条件
利用in_array()
的弱比较类型,构造?n=1.php
同时POST:content=
访问1.php即可
或者?n=1.php content=
访问1.php一步一步来即可
is_numeric()
用来检测变量是否为数字或数字字符串。如果指定的变量是数字和数字字符串则返回 TRUE,否则返回 FALSE,注意浮点型返回空值,即 FALSE
$v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3);
因为是用and
连接,所以只要一个为true,v0就为true。如果用&&
连接,必须都为true,v0才为true
所以只需要v1为数字就行
看过滤$v2
不能有;
但是$v3
要有;
eval("$v2('ctfshow')$v3");
字符串拼接,然后用eval执行构造
?v1=1&v2=var_dump($ctfshow)&v3=;
仔细看看,里面有个0x2d,对应ASCII码就是-
,我们替换一下成功提交flag
eval()执行里有一段
('ctfshow')
,可以用/**/
注释掉,或者--
注释所以注释掉v3也可以
?v1=1&v2=var_dump($ctfshow)/*&v3=*/;
var_dump()
用于判断一个变量的类型与长度,并输出变量的数值
PHP反射机制 - 知乎 (zhihu.com)
在web100的基础上,增加了更多的过滤
这里我们用到了类反射
PHP Reflection API是PHP5才有的新功能,它是用来导出或提取出关于类、方法、属性、参数等的详细信息,包括注释
$class = new ReflectionClass('Person'); // 建立 Person这个类的反射类
$instance = $class->newInstanceArgs($args);// 相当于实例化Person 类
利用ReflectionClass建立ctfshow类的反射类,new ReflectionClass($class)获得class的反射对象(包含了元数据信息)。反射返回的对象是class的元数据对象(包含class的所有属性/方法的元数据信息)。
payload:?v1=1&v2=echo new Reflectionclass&v3=;
call_user_func()
— 把第一个参数作为回调函数调用也就是说v1是被调用的回调参数,s是回调参数的参数
file_put_contents()
函数把一个字符串写入文件中,如果成功,该函数将返回写入文件中的字符数。如果失败,则返回 False
分析源码,v2必须是数字;call_user_func($method,$a)
调用的参数是,v2第3位及之后的数字。那么我们需要在后面的数字着手,必须满足数字,科学计数e是唯一可以在is_numeric中不会影响判断数字的字符,所以可选字符只有0-9和e。
利用进制转换,hex2bin可以把十六进制值转换为 ASCII 字符。我们要写入这串十六进制
file_put_content();
可以写入文件,根据已有内容,不能直接写php语句,因为<
不能用,那么就需要编码,以实现写入php语句。所以v3的内容是利用伪协议写入,编码形式采取base64。
=
是echo() 的快捷用法,它会把结果输出出来
直接用cat *
把当前目录下的文件都输出
所以最后的思路是v1是hex2bin;v2里先加上两个随意的数字,如11,然后加上php语句的base64转16进制的内容;v3是php伪协议语句。
$a='=`cat *`;';
$b=base64_encode($a); // PD89YGNhdCAqYDs=
$c=hex2bin($b); //等号在base64中只是起到填充的作用,不影响具体的数据内容,直接用去掉,=和带着=的base64解码出来的内容是相同的。
输出 5044383959474e6864434171594473
带e的话会被认为是科学计数法,可以通过is_numeric检测。
因为是从下标为2的位置取的字符串,所以要在前面加两个数字(随意)
GET:
v2=115044383959474e6864434171594473&v3=php://filter/write=convert.base64- decode/resource=1.php
POST:v1=hex2bin
#访问1.php后查看源代码获得flag
增加了preg_match()
,我们上个题用的是短标签,而且是用*
全部输出,并不影响,所以和上题的payload一样
来看源码,v1和v2的sha1值要相等,并且没有判断v1和v2
sha1与md5类似。都无法处理数组,所以可以用数组绕过
get : v2[]=0 post: v1[]=1
也可以找加密后0e开头的即可。
aaK1STfY ==>0e76658526655756207688271159624026011393
aaO8zKZF ==>0e89257456677279068558073954252716165668
并且这里没有判断v1和v2,两个参数输入同样的值也是可以的。 直接构造POST:v1=a
GET:v2=a