php特性靶场89-100关

第89关

代码
<?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;
    }
}
代码分析:include包含了一个flag.php的文件,在执行echo $flag的时候会调用文件里的flag并输出
if判断:isset:判断括号里通过get传的参数num是否为null,若不为null,则输出正,反之则输出负,这里我们要求不为null即可,第二个判断函数里是preg_match函数,这个函数要求其中被匹配的参数是一个字符串,判断这个字符串有没有0-9的数字,若有,则终止代码并且输出nonono,若无则接着进行下一个判断,这里我们运用数组,preg_match会判断为非字符串直接执行false,也就是下一个if语句判断,intval函数会判断num是否可以转换为整数,如果能转化为整数则输出true,也就是flag,
如果 $num 转换后的值大于 0,intval($num) 返回的结果将为 true,因此 if 语句会执行,输出 $flag 的值。

关于intval函数值得一提的是,他在转化后判断能否转换为整数,只会返回相应的判断值而不会改变原本参数的值,还有一点就是果 $num 是一个负数,无论是以字符串形式还是整数形式提供给 intval 函数,intval 会将其转换为相应的负整数。在布尔上下文中,任何非零的整数都被视为 true,包括负数。

因此,如果 $num 是负数,intval($num) 将返回一个负整数,if 语句的条件会评估为 true,并且会执行 echo $flag; 这行代码,输出 $flag 的值。

以下是几个例子:

  1. 负整数:如果 $num-123intval($num) 会返回 -123if 语句会执行。

  2. 负数值字符串:如果 $num'-123'intval($num) 同样会返回 -123if 语句会执行。

在所有这些情况下,只要 $num 不是 0 或者是空值(null、空字符串 ''、未定义等),if 语句中的条件都会被认为是 true,并且 $flag 会被输出。
这边用/?num[]=1进行传参即可

第90关

 代码
<?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);
    }
}

代码分析:include包含了一个flag.php的文件,在执行echo $flag的时候会调用文件里的flag并输出
if判断:isset:判断括号里通过get传的参数num是否为null,若不为null,则输出正,反之则输出负,这里我们要求不为null即可,
接下来的判断是一个===强等于,不能要求值相等,而且要求数据类型相等,我们要求输出false,这很好实现,接下来的判断是一个intval函数,括号中的第一个num是要被转化为整数的数,而第二个参数是基数,假如是8,就会把num视为一个8进制的数,然后转化为10进制,这里的基数是0,代表会自动检测是多少进制的,自动检测的规则是

十进制(Decimal):首先,intval 会尝试将字符串解析为十进制数。如果字符串以数字开头,并且只包含数字字符,则会被解析为十进制数。
八进制(Octal):如果字符串以 0 开头(且不是 0 后面紧跟着 0-7 之外的数字,否则会被识别为十进制),则会被解析为八进制数。
十六进制(Hexadecimal):如果字符串以 0x 或 0X 开头,后面跟着十六进制数字(0-9, a-f, A-F),则会被解析为十六进制数。

这边在补充一点就是intval函数对于字符串的转化规则是ntval 函数用于将一个字符串或数字值转换为整数。当处理字符串时,intval 会从字符串的左边开始,一直读取直到遇到非数字字符为止。这意味着它会忽略字符串中的任何非数字字符,并只将连续的数字字符转换为整数。
以下是 intval 函数处理字符串并将其转换为整数的规则:
纯数字字符串:如果字符串只包含数字(0-9),intval 会将整个字符串转换为相应的整数。
数字和非数字字符:如果字符串包含数字和非数字字符,intval 会忽略非数字字符,并只将连续的数字字符转换为整数。
负数:如果字符串以负号(-)开头,intval 会将整个字符串视为负数,并转换为相应的负整数。
空字符串或非数字字符串:如果字符串为空或不包含任何数字字符,intval 会返回 0。
科学记数法:如果字符串包含科学记数法(例如 "1e3"),intval 会忽略指数部分,只转换数字部分。
前导零:如果字符串以一个或多个零开头,这些零会被忽略,除非字符串是八进制数(以0开头)或十六进制数(以0x或0X开头)。
intval函数输出的返回值是转换为整数后的数值,包括数组,字符串等,但是不会改变参数原本的值,这里我们用?num=0x117c进行传递参数发现成功,但是0x117c是十六进制,转化为10进制是4472,显然不满足4476,这是什么原因呢?intval 函数在这里的行为取决于 PHP 的版本。在某些 PHP 版本中,intval 函数会忽略前缀 "0x" 并将其视为普通的字符串,这意味着它不会将 "0x117c" 识别为十六进制数,而是会将其视为一个包含十六进制表示的字符串。
由于 intval 在这种情况下将 "0x117c" 视为字符串,并且字符串中包含数字,它会将这些数字视为十进制数并返回它们的整数值。因此,"0x117c" 中的数字 "117c" 被转换为十进制数 4476。
由于 intval($num, 0) 返回了 4476,这满足了 if (intval($num, 0) === 4476) 条件,因此脚本输出了 $flag。将 0x117c 视为十进制数并返回整数值 4476 的原理实际上是一个误解。在 PHP 中,intval 函数不会将包含 0x 前缀的字符串视为十六进制数。相反,它将整个字符串视为十进制数。
当 intval 函数接收到字符串 "0x117c" 时,它不会解释 0x 为十六进制的前缀。相反,它从字符串的开头开始,将每个字符视为十进制数的一部分,直到遇到一个非数字字符。在这种情况下,字符串 "0x117c" 被解释为十进制数 "0117c",其中:
0 是十进制的 0,
1 是十进制的 1,
1 是十进制的 1,
7 是十进制的 7,
c 是十进制的 12(因为 c 在十进制中是 12)。
因此,"0117c" 被解释为十进制数 1 * 10^4 + 1 * 10^3 + 7 * 10^1 + 12 * 10^0,计算结果为:
1∗10000+1∗1000+7∗10+12∗1=10000+1000+70+12=110721∗10000+1∗1000+7∗10+12∗1=10000+1000+70+12=11072
然而,这个解释是错误的。正确的解释应该是 "0x117c" 被解释为十进制数 "117c",其中:
1 是十进制的 1,
1 是十进制的 1,
7 是十进制的 7,
c 是十进制的 12。
因此,"117c" 被解释为十进制数 1 * 10^3 + 1 * 10^2 + 7 * 10^1 + 12 * 10^0,计算结果为:
1∗1000+1∗100+7∗10+12∗1=1000+100+70+12=44761∗1000+1∗100+7∗10+12∗1=1000+100+70+12=4476
这就是为什么 intval("0x117c", 0) 返回 4476 的原因。这个行为是 PHP 的一个特性,它将 0x 后的字符串视为十进制数,而不是十六进制数。在最新的 PHP 版本中,intval 函数确实会将以 "0x" 或 "0X" 开头的字符串视为十六进制数,并将其转换为十进制整数。这一点在 PHP 官方文档中有明确说明:
如果 base 是 0,通过检测 value 的格式来决定使用的进制:
如果字符串包括了 "0x" (或 "0X") 的前缀,使用 16 进制 (hex);否则,
如果字符串以 "0b" (或 "0B") 开头,使用 2 进制 (binary);否则,
如果字符串以 "0" 开始,使用 8 进制(octal);否则,
将使用 10 进制 (decimal)。
因此,当你使用 intval 函数处理字符串 "0x117c" 时,PHP 会识别出 "0x" 前缀,并将其作为十六进制数处理,转换为相应的十进制整数。具体来说,十六进制数 0x117c 会被转换为十进制数 4472
另外再补充一个关于强等于===的特性,在 PHP 中,使用 === 运算符进行比较时,它不仅会比较两个值是否相等,还会检查它们的数据类型是否相同。这意味着,如果两个值的类型不同,即使它们的值在某种转换后可能相等,=== 也会返回 false。
对于进制不同的数值,=== 会比较它们的整数值,而不是它们表示的数值。例如,如果一个值是十六进制表示的,而另一个值是十进制表示的,即使它们在数值上相等,但由于它们的类型(进制)不同,=== 也会返回 false。
至于这道题用十六进制来躲过===强等于的类型判定而不用数组的原因是在 PHP 中,intval 函数用于将变量转换为整数类型。当处理数组时,intval 函数遵循以下规则:
空数组:如果传入的数组为空,intval 函数返回 0。
非空数组:如果传入的数组非空,intval 函数返回 1,不关心数组中的内容

这意味着,无论数组中包含什么元素,只要数组非空,intval 函数就会返回 1。如果数组为空,即使数组的元素在逻辑上可以转换为整数,intval 函数也会返回 0。也就是说,处理数组的话,返回的不是0就是1,而处理数字的话,则会返回处理化为整数后的值。

第91关        

代码
<?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';
}
代码分析:include包含了一个flag.php的文件,在执行echo $flag的时候会调用文件里的flag并输出
这里要通过get传递cmd的参数给a,进入第一个判断语句,如果a没有在开头或者结尾匹配上php,那么就会输出nonononono,如果在开头和结尾都匹配上php了,那么进入下一级判断,这里im应该是判断a字符串的开头和结尾,其中i是整体,m是开头和结尾,接下来的判断是i,就是对a整个字符串进行php匹配判断,这里要求整个字符串都是php,如此便会输出hacker,如果不是整体都是php则输出flag,这里我们采用
/?cmd=php%0a123来获得flag,在 URL 中使用 ?cmd=php%0a123 进行 GET 请求时,cmd 参数的值是经过 URL 编码的。在这个例子中,%0a 是一个 URL 编码,代表换行符(LF,Line Feed)。
当这个参数被传递到服务器端的 PHP 脚本时,cmd 的值将是解码后的字符串,即 php 后面跟着一个换行符,然后是 123。所以,cmd 的值将是:
php
123
在 PHP 脚本中,你可以通过 $_GET['cmd'] 来获取这个值。如果你打印这个值,你会看到:
php
echo $_GET['cmd']; // 输出 php\n123
这里的 \n 是换行符的转义序列。如果你想在 PHP 脚本中执行这个值,你需要考虑到换行符可能会导致命令被分割成多行。在某些情况下,这可能会被用于注入攻击,尤其是当参数被用于系统命令或代码执行的上下文中时。因此,对用户输入进行适当的过滤和转义是非常重要的安全措施。
这个php%0a123能在第一个preg_match判断为true的原因是php%0a123在uri编码之后会翻译成php/n123,这相当于一整个字符串,而m代表的是多行模式,所以换行字符就会发生作用变成
php
123
而'/^php$/im'中的^代表着匹配每一行的开头,$代表匹配每一行的结尾,如此一来,在第一行中就会发现php的字符串的开始和结尾都是php从而输出true因此,正则表达式 /^php$/im 在多行模式下匹配了第一行的内容 "php",而忽略了第二行的内容 "123"。
所以,第一个 preg_match 判定为真的原因是它在多行模式下匹配了 "php" 这一行,而不是整个字符串 "php\n123"。这里的关键是理解 m 修饰符如何改变了 ^ 和 $ 的行为,使得它们在多行文本中匹配每一行的开始和结束,而不是整个字符串的开始和结束。
而在第二个判断语句中判断整体是不是严格等于php,因为有123,所以输出为false从而输出flag^ 匹配字符串的开始。
php 匹配文本 "php"。
$ 匹配字符串的结束。
i 修饰符表示不区分大小写。
m 修饰符表示多行模式
这边要纠正的是i不代表整体,而是preg_match这个函数会自动匹配整个字符串,在m的作用下变成多行/n发生作用,这里的i仅代表不区分大小写,下面讲述一些i,m以及其它同类型的一些代表含义修饰符 i:
i 代表“不区分大小写”(case-insensitive)。
当在正则表达式中使用 i 修饰符时,所有的字符都会被视为小写或大写,这取决于正则表达式中指定的字符。例如,模式 /php/i 会匹配 "PHP"、"php"、"Php" 等。
修饰符 m:
m 代表“多行模式”(multiline)。
在多行模式下,^ 和 $ 锚点不仅匹配整个字符串的开始和结束,还匹配每一行的开始和结束。这对于处理多行文本特别有用。
例如,在多行模式下,模式 /^php$/m 会匹配每一行开头是 "php" 且该行只有 "php" 的行。
其他修饰符:
s(单行模式):在单行模式下,. 匹配包括换行符在内的任何单个字符。
x(扩展模式):允许在正则表达式中使用空格和注释,使得正则表达式更易于阅读和编写。
A(开始锚点):确保匹配必须从字符串的开始进行。
Z(结束锚点):确保匹配必须在字符串的结束进行,等同于 $,但不会匹配字符串末尾的换行符。
D(美元结束锚点):匹配字符串的结束,等同于 $,但可以匹配字符串末尾的换行符。
U(非贪婪模式):反转贪婪量词的匹配,使得匹配尽可能少的字符。
组合修饰符:
修饰符可以组合使用,例如 /pattern/ims 会创建一个不区分大小写、多行、单行模式的正则表达式。
在 PHP 中使用修饰符:
在 PHP 中,修饰符可以在正则表达式中直接使用,如 /pattern/ims。
也可以在函数调用中作为参数传递,如 preg_match('/pattern/', $subject, $matches, PREG_OFFSET_CAPTURE, 0, 'ims')。

第92关

代码
<?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);
    }
}
代码分析:这题和90关有很大的相似,唯一不同的地方在于==是弱比较,只比较值而不比较类型,网上有人说4476abc可以获得flag,很显然不可能,因为弱比较类型的原因会将4476abc转化为4476来和4476比较值,很明显相等并且会输出nonono这里采用
/?num=4476.1来进行,与4476值不相等,但是在转化为整数后与4476相等并且会输出flag

第93关

代码
<?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);
    }
这里的知识前面都讲过,这里直接
/?num=4476.1获得flag

第94关

代码
<?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,
在 PHP 中,strpos 函数用于查找字符串中第一次出现另一个字符串的位置。如果找到指定的字符串,则返回它的第一个字符的位置(从 0 开始计数)。如果没有找到,则返回 false
int strpos ( string $haystack , mixed $needle [, int $offset = 0 ] )

  • 如果找到 $needle,则返回它在 $haystack 中第一次出现的位置(从 0 开始计数)。
  • 如果没有找到 $needle,则返回 false
    strpos 是区分大小写的。如果你想进行不区分大小写的搜索,可以使用 stripos 函数。
    如果 $needle 是空字符串(""),strpos 将始终返回 0,因为空字符串被认为是在每个位置开始的。
    如果 $haystack 是空字符串,strpos 将返回 false。
    这边通过/?num=4476.0加个0满足strope,又因为前面有!所以输出false,接下来继续intval转化为4476输出flag
    那么问题来了,既然strpos是从0开始计数并返回字符串第一次出现位置的值,那么假如第一位就是出现的位置的值,那么就会返回值为0,那么就会输出false。这样的话显然与预期的情况不符,那么是什么原因呢?在php中,有一种类型叫做布尔类型,它只有true和false,在 PHP 中,if 语句会根据表达式的值来决定是否执行其内部的代码。对于 if 语句中的条件表达式,PHP 会进行类型强制转换,将值转换为布尔类型以进行真假判断。
    当 strpos 返回 0 时,虽然在整数类型中它是 0,但在 if 语句中,0 会被转换为布尔值 false。因此,if 语句中的条件会被评估为 false,并且不会执行 if 代码块中的代码,而是执行 else 部分(如果存在)。这里我们采用的是4476.0,strpos返回值是5,那么我们用0x4476来测验一下,因为php的版本比较低(前面的题测试过),strpos会将0x4476视作一个字符串,也就是返回值为0,因为后两步判断因为有字符x我们无法分辨是哪个步骤导致的输出nonono,这里我们改一下源代码来探究一下这个问题,即将第二步判断删掉,看是否满足第三条判断语句,结果发现就是不满足第三条判断,这说明在if判断语句中的strpos确实会将输出值转化为由整形转化为布尔类型进行判断

第95关

代码

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

代码分析:
在if(preg_match(“/[a-z]|./i”, $num)){
die(“no no no!!”);}语句中也禁用了.,但我们只需要让八进制前面没有0即可绕过得到flag,f($num==4476){...}:这个条件检查 $num 是否严格等于整数 4476。由于 +010574 是一个字符串,这个条件不成立,所以不会执行 die("no no no!");。
if(preg_match("/[a-z]|\./i", $num)){...}:这个条件使用正则表达式检查 $num 是否包含任何小写字母(/[a-z]/)或大写字母(由于 i 修饰符,也包括 [A-Z])或者点号(.)。由于 +010574 不包含任何字母或点号,这个条件不成立,所以不会执行 die("no no no!!");。
if(!strpos($num, "0")){...}:这个条件检查 $num 中是否不包含字符 "0"。由于 +010574 包含 "0",strpos 函数会返回一个非 false 的值(具体是 "0" 出现的位置),所以 !strpos($num, "0") 为假,不会执行 die("no no no!!!");。
if(intval($num,0)===4476){...}:这个条件将 $num 转换为整数。由于 +010574 是一个八进制数,intval 函数在基数为 0 时会自动识别其为八进制,并将其转换为十进制整数。+010574 转换为十进制确实是 4476,因此这个条件成立,执行 echo $flag; 输出 $flag。
综上所述,num=+010574 能够通过所有检查并得到 $flag,因为它不包含任何禁止的字符,包含数字 "0",并且当作为八进制数解释时,转换为十进制后等于 4476。
值得补充的就是+010574也可以更改成 010574或者是%2B010574,+, ,%2B在uri编码中会编译成空格,它的作用是让0不在第一位,这个原因在上一道题已经讲过了,至于0的作用是以0开头的会被认为是8进制从而解析这道题用+010574或者 010574或者%2B010574即可进行绕过
在旧版本的php中(特别是 PHP 5.4 之前的版本)以0开头的会被认为是8进制,而0x开头的会被认为是个字符串处理而不是16进制处理

第96关

代码
<?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 实际上请求的是当前目录下的 flag.php 文件。
由于代码中的比较是弱比较(==),它只比较值,不比较数据类型。$_GET['u'] 的值是一个字符串,而在 PHP 中,'./flag.php' 和 'flag.php' 是两个不同的字符串,因为前者包含了一个额外的 ./ 前缀。
因此,$_GET['u'] 的值 './flag.php' 不等于 'flag.php',所以 if($_GET['u']=='flag.php') 这个条件为假,不执行 die("no no no")。
由于条件为假,代码执行 else 分支,调用 highlight_file($_GET['u']);,这将高亮显示当前目录下的 flag.php 文件。./:表示当前目录(folder)。在文件路径中使用 ./ 可以明确指出某个文件或目录位于当前工作目录中。例如,如果你的当前工作目录是 /home/user,那么 ./myfile.txt 就是指 /home/user/myfile.txt。
..:表示上级目录(parent directory)。用于指向当前目录的上一级目录。例如,如果你的当前工作目录是 /home/user/documents,那么 ../ 会指向 /home/user。如果你尝试访问 ../../,它会指向 /home
这里用./flag.php即可得到flag,那么问题来了,./flag.php在弱等于中与flag.php进行比较中./去哪了?在highlight_file又去哪了?在 PHP 中,使用 == 进行弱比较时,如果两个值的类型不同,PHP 会尝试将它们转换为相同的类型,然后再进行比较。然而,对于字符串类型的比较,PHP 会直接比较字符串的内容。
当您使用 /?u=./flag.php 作为请求时,$_GET['u'] 的值是字符串 ./flag.php。在弱比较 == 中,$_GET['u'] 的值 ./flag.php 会直接与字符串 'flag.php' 进行比较。由于 ./ 是当前目录的表示,它在文件系统中是一个有效的路径组成部分,但在字符串内容比较中,它不会被忽略或自动转换。因此,./flag.php 和 'flag.php' 在字符串层面上是不同的,因为前者有一个额外的 ./ 前缀。
所以,当执行以下代码时:
php
if($_GET['u'] == 'flag.php'){
    die("no no no");
}
由于 $_GET['u'] 的值实际上是 ./flag.php,这与 'flag.php' 不相等,所以条件判断为 false,不会执行 die("no no no"); 语句。因此,else 分支被执行,highlight_file($_GET['u']); 被调用,显示了 ./flag.php 文件的内容。
这就是为什么使用 /?u=./flag.php 能够绕过检查并显示 flag.php 文件内容的原因。在这个例子中,./ 在字符串比较中被视为 ./flag.php 字符串的一部分,没有被自动忽略或转换,导致了弱比较的成功绕过。在 PHP 中,highlight_file 函数用于输出文件的内容,并以 HTML 格式进行语法高亮显示。当您传递一个文件路径给 highlight_file 函数时,它会直接使用这个路径来访问文件系统。
在您的例子中,当您通过 URL 参数传递 /?u=./flag.php 时,$_GET['u'] 的值是字符串 ./flag.php。这里的 ./ 表示当前目录,所以 ./flag.php 指的是当前目录下的 flag.php 文件。
当 highlight_file 函数被调用时,它会尝试打开并读取 ./flag.php 文件的内容。在文件系统中,./ 前缀是有意义的,它告诉系统查找当前目录下的文件。因此,highlight_file 函数会正确地找到并显示 flag.php 文件的内容,而不会因为 ./ 前缀而受到影响。
这是因为在文件路径中,./ 是一个标准的路径组成部分,用于指定当前目录。操作系统和 PHP 的文件处理函数都能够识别并正确处理这个前缀。所以,即使在 if 语句的比较中 ./ 前缀导致了条件判断失败,但在 highlight_file 函数中,这个前缀被正确地解释为当前目录,从而允许函数访问并显示 flag.php 文件的内容。
总结来说,在 highlight_file 函数中,./ 前缀没有“消失”,而是被用来正确地定位当前目录下的 flag.php 文件。这就是为什么即使在 if 语句中 ./ 前缀导致了条件判断失败,highlight_file 函数仍然能够正确地显示 flag.php 文件内容的原因。
也就是说在弱比较中,./算作字符串不会消失,但是在hightlight_file中会将括号里的作为一个文件路径进行查询,./从而有意义,一个是视作字符串,一个视作文件路径

第97关

代码
<?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.';
}
?>
代码分析:利用hackbar进行post输入,这边强调一个地方就行,hackbar虽然是post提交的,但是也有可能依然是get传参的,这边用bp抓一下包放出来就肯定是post了,
a[]=1&b[]=2这道题就能解出来了,原理是MD5编码需要的是一个字符串,如果想要对数组进行编码的话,应该先用serilize序列化变为字符串然后进行MD5编码,而直接对数组编码就会导致发出警告而且===表达式直接为true,这边还有一个想法是,既然是md5编码前不相等,编码后相等的话,找两个0e开头的让它识别为指数,然后为0的值也是满足条件的,那这是为什么呢?md5编码出来的是字符串,而不是数值,它会先判断是那种类型,如果是数字类型的话,会判断是8进制还是科学计数法

第98关

代码
<?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存在,get的值等于post,如果是flag先被cookie覆盖,然后被server覆盖,最后判断get传参的HTTP_FLAG如果等于flag就高亮输出。
我们先?1随便给一个get值然后HTTP_FLAG=flag通过POST传给GET最后HTTP_FLAG等于flag高亮输出flag.php中的flag

第100关

代码

<?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");
        }
    }
}
代码分析

?v1=1&v2=var_dump($ctfshow)/*&v3=0*/;

既然eval会将括号里的字符串作为一个php代码去实现,我们想要表现的是ctfshow里的flag-

给v2赋值var_dump并且用/*将后面的v3注释掉从而输出ctfshow,该函数可以输出值和类型,而is_numeric是判断一个数据是否是数字或者是数字字符串,v1是一个布尔值,很明显符合条件,v2输出的是ctfshow的值,所以也能通过判断,v3含有0也能通过判断并且v2不含有;并且v3含有;

eval() 函数会将字符串作为 PHP 代码来执行。在这里,eval() 将执行字符串 "$v2('ctfshow')$v3" 中的代码。

这行代码的作用是执行由变量 $v2 指定的函数,并将字符串 'ctfshow' 作为参数传递给这个函数,然后执行变量 $v3 中的内容

### SQL注入实验平台SQLi-Labs第1至65解题思路 #### 实验环境搭建 为了顺利进行SQLi-Labs的学习,需先下载并安装好该实验平台。通常情况下,在Web应用安全测试环境中部署PHP和MySQL服务即可运行此项目。 #### 第一阶段:基础SQL注入练习(Less-1 到 Less-8) 对于早期的基础题目,主要目的是让学习者熟悉如何通过URL参数中的`id`字段来执行简单的布尔型盲注攻击以及基于错误消息返回的数据泄露漏洞利用方法[^1]。 例如,在第一中提到的payload `?id=1" AND IF(ASCII(SUBSTR((SELECT database()),1,1))>109,sleep(10),1)--+` 就是用来探测当前使用的数据库名称的第一个字符是否大于字母'm' 的 ASCII 值;如果条件成立,则触发延迟响应以确认猜测正确性。 #### 第二阶段:Union Select 注入技巧(Less-9 至 Less-17) 这一系列挑战侧重于掌握使用UNION SELECT语句组合多个查询结果集的能力。这允许攻击者从其他表甚至不同模式下的数据源提取敏感信息。像这样构造请求可以用来找出页面上显示的内容对应着哪几列被选出来展示给用户:`http://example.com/vuln.php?id=-1' UNION SELECT 1,2,3--` [^3]. #### 中级难度提升(Less-18 至 Less-34) 随着级别的升高,会遇到更多复杂的场景,比如时间延迋试探法、堆叠查询等高级技术的应用。这些技能有助于绕过某些防护措施或者当直接反馈机制不可用时仍能完成渗透操作。 #### 高阶挑战(Less-35 及以上) 最后几个级别涉及到了更深层次的知识点,如子查询嵌套、正则表达式匹配等功能强大的特性。同时也会引入一些防御手段作为障碍,促使玩家思考对策。 #### 特殊案例分析(Less-6 类似情况) 特定条件下可采用非常规手法解决问题,例如第四条参考资料里给出的例子展示了怎样借助XML解析器函数extractvalue()实现带外通道的信息窃取:`http://localhost/lab/Less-6/?id=1" AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT GROUP_CONCAT(TABLE_NAME) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='target_db'),0x7e))--+` [^4]. 这种方式能够有效规避传统过滤规则的影响。 ```sql -- Example of a payload using extractvalue to retrieve table names. AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT GROUP_CONCAT(TABLE_NAME) FROM information_schema.tables WHERE table_schema = 'database_name'), 0x7e)) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值