寒假任务二

寒假任务二

php特性靶场

前置内容

preg_match:

具体查阅:[preg_match_preg_match('/.*([\w\]|\|*|(|~|`|\?|\/| |||&-CSDN博客](preg_match_preg_match('/^.*([\w]|\^|\*|\(|\~|\`|\?|\/| |\||\&-CSDN博客

preg_match 函数用于执行一个正则表达式匹配。

语法: preg_match(string $pattern, string $subject, array &$matches);

pattern:要搜索的模式串,字符串类型

subject:输入的字符串,字符串类型

matches:可选,用来存放搜索结果,$matches[0]存放所有匹配的字符串,$matches[1]用来存放第一个匹配的字符串,$matches[2]用来存放第三个匹配的字符串,以此类推

返回值:如果没有匹配,返回值为0;如果有匹配,返回值为1

绕过方式:

1.加号绕过:比如题目所求flag对应的变量的值为1000,但是该代码中变量大于999时无输出,这时我们就可以用加号绕过,即将目标变量的值从1000改为999+1(注意在url里传参时+要编码为%2B)

2.数组绕过(参考web89):一般有三种格式

$a[]='flag.php';
 
$a=array('flag.php');
 
$a=['flag.php'];

3.回溯次数绕过

4.换行绕过(参考web91):换行符%0a

5.preg_match_all()绕过

intval:
intval — 获取变量的整数值

它的具体格式和解释如下:

int intval( var,base)
//var指要转换成 integer 的数量值,base指转化所使用的进制 
Note: 
如果 base 是 0,通过检测 var 的格式来决定使用的进制: 
◦ 如果字符串包括了 "0x" (或 "0X") 的前缀,使用 16 进制 (hex);否则,  
◦ 如果字符串以 "0" 开始,使用 8 进制(octal);否则,  
◦ 将使用 10 进制 (decimal)。

1.

这里这个Note对我们来说就尤为重要了,没有声明base参数时,字符串首字母是0则视为8进制,是0X则视为16进制,具体可以看官方给出的例子:

?php
echo intval(042);                     // 34
echo intval(0x1A);                    // 2
?> 

此时就可以看出它的一个利用方式了,当过滤某个数字时,我们可以利用它的进制转换来绕过。

2.**

返回值
成功时返回 var 的 integer 值,失败时返回 0。空的 array 返回 0,非空的 array 返回1

这时候就可以看出另一个利用方式了,如果是一个弱比较a==b我们输入a[]=1b[]=2,此时这两个是不同的,但还都会返回1,此时也就实现了一种绕过,这是第二种绕过思路。

3.

echo intval(42);                      // 42
echo intval(4.2);                     // 4

我们可以发现小数点后的数字会直接舍去,所以当过滤4的时候,我们可以输入4.2来绕过,这是第三种绕过思路。

4.

echo intval(1e10);                    // 1410065408
echo intval('1e10');                  // 1

我们发现单引号传值的时候,它只识别字母前面的一部分,当我们进行get传参时,我们其实就是默认加单引号的,所以这是第四种绕过方式。

strpos:

strpos用于查找字符串首次出现的位置

函数形式: mixed strpos( string $haystack, mixed $needle[, int $offset = 0] )
意为: 返回 `needle` 在 `haystack` 中首次出现的数字位置。

haystack:在该字符串中进行查找。

needle:如果 needle 不是一个字符串,那么它将被转换为整型并被视为字符的顺序值。

offset:如果提供了此参数,搜索会从字符串该字符数的起始位置开始统计。如果是负数,搜索会从字符串结尾指定字符数开始。

返回值:返回 needle 存在于 haystack 字符串起始的位置(独立于 offset)。同时注意字符串位置是从0开始,而不是从1开始的。

如果没找到 needle,将返回 FALSE

md5:

PHP md5()函数详解,PHP计算MD5,md5()绕过,md5()漏洞原理剖析-CSDN博客

语法:string md5( $str, raw)

str:需要计算的字符串

raw:指定十六进制或二进制输出格式

返回值:计算成功,就返回MD5值;计算失败,就返回false

1.基础使用

平时使用最多的就是「计算MD5」

实例:

echo md5('hello');        

输出:

5d41402abc4b2a76b9719d911017c592
2.输出格式

raw 参数控制输出的「格式」:

  • true :16个字符的「二进制格式」

  • false :(默认)32个字符的十六进制格式

如果你在项目中遇到MD5「加密结果不一致」的问题,可以观察两个加密结果的长度是否相同,比如一个结果是16位,而另一个结果是32位,这种情况就可以考虑更换输出格式来解决。

实例:

var_dump(md5('hello', true));        
var_dump(md5('hello', false));       

输出:

string(16) "]A@*�K*v�q��Œ"
string(32) "5d41402abc4b2a76b9719d911017c592"
3.0e绕过

md5() 遇到「公式」,会先「运算」,再对运算结果「计算」MD5。

由于0和任何数相乘都等于0,所以0e开头的任何数,其MD5都是相同的。

比如 md5('0e1234'),会先运算成 md5(0),再计算MD5值。

补充:

0e是科学计数法,大小写等价,即 0e 和 0E 的结果相同。 科学记数法是一种记数的方法。把一个数表示成a与10的n次幂相乘的形式。 格式为:aEb=a×10^b,即a乘以10的b次幂。

实例:

echo md5(0).PHP_EOL;
echo md5(0e123).PHP_EOL;
echo md5(0e456).PHP_EOL;
echo md5(0E456);

输出:

cfcd208495d565ef66e7dff9f98764da
cfcd208495d565ef66e7dff9f98764da
cfcd208495d565ef66e7dff9f98764da
cfcd208495d565ef66e7dff9f98764da

绕过思路1:遇到弱比较(md5(a)==md5(b))时,可以使用 0e绕过。

实例:

var_dump(md5(0e123) === md5(0e456));
var_dump(md5(0e123) == md5(0e456));

输出:

bool(true)
bool(true)

绕过思路2:遇到若比较( md5(a)==0 ),可以传入QNKCDZO等绕过。

实例:

echo md5('QNKCDZO').PHP_EOL;
var_dump(md5('QNKCDZO') == 0);

输出:

0e830400451993494058024219903391
bool(true)
4.数组绕过

md5() 不能处理数组,数组都返回null。同时会报一个Warning,不影响执行,不用管。

实例:

var_dump(md5([1,2]));
var_dump(md5([3,4]));

输出:

Warning: md5() expects parameter 1 to be string,
NULL
Warning: md5() expects parameter 1 to be string,
NULL

绕过思路:遇到强比较(a===b)时,可以使用数组绕过。GET传参时,以 a[]=1&b[]=2 这种形式传递数组。

实例:

$a = array(1,2,3);
$b = array(4,5,6);
​
var_dump(md5($a)===md5($b));

输出:

Warning: md5() expects parameter 1 to be string,
Warning: md5() expects parameter 1 to be string,
bool(true)

三元运算(?:)

三元运算符是软件编程中的一个固定格式,语法是“条件表达式? 表达式1:表达式2”。条件表达式成立,就是1的的值,反之,则是2的值

实例:

2>1?ture:false
相当于
if(2>1)
    return ture;
 else return false;
<?php
$action = (empty($_POST['action'])) ? 'default' : $_POST['action']
?>
相当于
<?php
if (empty($_POST['action'])) {
    $action = 'default';
} else {
    $action = $_POST['action'];
}
?>

is_numeric

is_numeric 用来 检测变量是否为数字或数字字符串

语法: bool is_numeric( mixed $var)

返回值:如果 var 是数字和数字字符串则返回 TRUE,否则返回 FALSE

1)web89
代码:
<?php
​
include("flag.php");
highlight_file(__FILE__);
​
if (isset($_GET['num'])) {
    $num = $_GET['num'];
    if (preg_match("/[0-9]/", $num)) {
        die("no no no!");
    }
    if (intval($num)) {
        echo $flag;
    }
}
分析:

该代码要求GET一个变量'num',并对此进行判断

如果num中含有数字0-9,则输出"no no no!"

preg_match()可以完成字符串的匹配规则。 //中的内容为匹配内容,后面为匹配的变量,如果变量中包含//中的内容,preg_match() 函数返回 1,否则返回 0

如果num为整数,则输出$flag

因为preg_match() 函数无法识别数组,所以我们可以通过数组绕过preg_match() 函数直接进行判断整数环节。所以我们可以输出?num[]=1来尝试,即可得到flag{You have successfully completed web89!}

2)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===4476(强类型比较),则die"no no no!",所以我们输入的num不能等于4476

但是,后面进行intval判断,如果num===4476,则echo $flag,否则echo num。所以我们输入的num要等于4476

经过前面的分析,我们似乎有点不知道变量能不能等于4476。

但是要注意,intval函数是支持不同进制的,而这里的base为0,所以我们可以直接使用八进制和十六进制

因为intval取的是我们所输入内容开头的整数,也就是说我们传入含有字符的字符串,所得结果为去除字符部分的整数

所以本题可输入:?num=010574 ?num=0x117c ?num=4467a (注意:八进制中10574和010574是相等的,十六进制中117c和0x117c是相等的,因为题目中base为0所以如此写)

3)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';
} nonononono
分析:
/i 表示匹配的时候不区分大小写
/m 表示多行匹配,什么是多行匹配呢?就是匹配换行符两端的潜在匹配。影响正则中的^$符号

首先对第一个preg_match函数进行判断,如果变量进行多行匹配到php,则进行第二个preg_match函数的判断,否则ceho 'nonononono'

对第二个preg_match函数进行判断,如果变量单行匹配到php,则echo 'hacker',否则echo $flag

所以这道题要求我们的变量是多行的,且第一行中不能有php。所以这道题我们要使用grep_match()的换行绕过

输入?cmd=%0aphp,即可得到flag{You have successfully completed web91!} (%0a为换行符)

换行绕过的具体解析:

%0aphp在文本形式的匹配中会显示如下:(CRLF是隐藏的字符)

那么进行多行匹配的时,一定会匹配到第二行的php,然后就会进入第二个preg_match函数中进行单行匹配,但第一行是隐藏的换行字符,是无法匹配到php的,所以便会输出flag。

4)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);
    }
}
分析:

本题与web90类似,但要注意的是web90属于强类型比较( === ) ,web92属于弱类型( == )

而在弱类型比较中4476和4476a是相等的,所以本题可以使用十六进制0x117c或者八进制010574

5)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);
    }
}
分析:

与web92类似,但本题匹配的内容为[a-z]:[a-z] 字符范围。匹配指定范围内的任意字符。例如,“[a-z]”可以匹配“a”到“z”范围内的任意小写字母字符。注意:只有连字符在字符组内部时,并且出现在两个字符之间时,才能表示字符的范围; 如果出现在字符组的开头,则只能表示连字符本身

也就是说本题变量中不能含有字母a-z,同时因为是/i无视大小写,所以变量中不能有任何字母,所以我们只能用八进制015074

6)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函数,该函数为查找0在num中首次出现的位置,并且该函数前有!,!意为取反,所以该句判断的是变量中含有0且首位不能为0

同时根据其他三处判断,本题应该使用的是八进制

所以本题可以使用换行绕过加八进制组合、空格绕过加八进制组合、特殊符号绕过加八进制组合、小数点绕过

换行绕过:%0a010574 空格绕过:%20010574 特殊符号绕过:+010574 小数点绕过:4476.0

7)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;
    }
}
分析:

本题与web94类似,但是多了一个\.的匹配,也就是说本题的变量中不能含有.,所以我们不能使用小数点绕过了

因此本题可采用空格绕过、换行绕过、特殊符号绕过

8)web96
代码:
<?php
​
highlight_file(__FILE__);
​
if(isset($_GET['u'])){
    if($_GET['u']=='flag.php'){
        die("no no no");
    }else{
        highlight_file($_GET['u']);
    }
}
分析:

我们可以看到本题的判断是一个关于文件的弱比较

当变量u==flag.php时,die("no no no");否则会高亮显示变量u

因此本题需要我们通过路径来实现变量和flag.php文件的弱比较

一说到路径我们便能想到绝对路径相对路径这两种,我们也将从这两方面解决问题

首先我们先随便输入一个值,就可以得到本题的目录

这里的\phpstudy_pro\WWW\web96\便是文件的所在目录,那么我们便能得到答案了

绝对路径:?u=\phpstudy_pro\WWW\web96\flag.php 相对路径:?u=./flag.php

9)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.';
}
?>
分析:

本题有两个变量a和b,要求a的内容不能等于b,且a要强等于b才能echo $flag。

根据我们最上方的函数参考,当md5函数中有强比较时,我们可以采取数组绕过的方式。

所以本题的答案为a[]=1&b[]=2(注意:数组的数字是无所谓的,因为只要是数组md5函数就无法识别)

10)web98

php函数的传值与传址(引用)详解-php手册-PHP中文网

php三元运算符与if的详解-php教程-PHP中文网

代码:
<?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传参,则使用POST传参来代替

第二行:如果GET传参flag的值=flag则将COOKIE的值代替flag中的值

第三行:如果GET传参flag的值=flag则将SERVER的值代替flag中的值

第四行:如果GET传参 HTTP_FLAG=flag,就执行highlight_file(flag),否则执行highlight_file(FILE)

整体分析来看,我们需要将POST传参设为HTTP_FLAG=flag,同时因为使用POST传参的前提时有GET传参,所以我们也得设一个GET传参

所以本题答案为:GET传参:?a=1

POST传参:HTTP_FLAG=flag

11)web100
代码:
<?php
​
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");
        }
    }
}
分析:

前面没什么好说的,我们主要从$v0那一句开始看。

is_numeric函数是用来检测变量是否为数字的函数,也就是说要想使下面的v0判断成立,那么函数括号中的变量就得是数字。

同时,因为and和or的优先级是低于“=”的,所以这句话中v0只与v1有关,与v2、v3是否为数字并没有关系。

接下来我们看后面的eval函数,eval函数是将字符串作为php代码执行的函数,所以这里的v2应该是代码,并且根据上面的preg_match函数可知v2还不能含有“;”

v3必须有“;”

要注意,代码中提示我们v2的值应该与‘ctfshow’有关,所以v2应该是var_dump($ctfshow)

所以本题答案为 ?v1=1&v2=var_dump($ctfshow)&v3=;

  • 54
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值