打开链接是PHP源码
代码审计:
include "flag.php";
表示文件中包含flag.php文件,即根目录下存在flag.php
$a = @$_REQUEST['hello'];
命名一个变量a来接收超全局变量$_REQUEST(接收表单’hello’数据,请求一个为hello的参数)
if(!pre_match('/^\w*$/',$a))
pre_match函数用于对变量$a执行正则表达式,/^\w*$/为匹配的正则表达式,用/作为开头和结尾,^匹配输入字符的开始位置,$匹配输入字符串的结尾位置,\w匹配字母、数字、下划线,*匹配前面的子表达式零次或多次。
eval("var_dump($$a);");
eval()内执行php代码
var_dump()输出变量相关信息,$$a为可变变量
show_source(__FILE__);
就是highlight_file()的别名,对文件进行高亮语法显示
我们已经知道flag就存在于某一个变量中,于是可使用超全局变量$GLOBALS
显示出所有未知的变量且通过var_dump()打印出来。
由于 $_REQUEST变量包含$_GET、$_POST和$_COOKIE的内容,$_REQUEST变量可以用来通过“GET”和“POST”这两个方法发送到表单数据,所以这里使用post和get传参都是可以的。
payload:
post:hello=GLOBALS 或 ?hello=GLOBALS
拿到 flag{fcdd8495-cd84-42a9-929e-724a80405627}
后面是关于前面涉及知识的详细介绍
eval() 函数
把字符串按照 PHP 代码来计算,该字符串必须是合法的 PHP 代码,且必须以分号结尾。
<?php
$string = "beautiful";
$time = "winter";
$str = 'This is a $string $time morning!';
echo $str. PHP_EOL;
eval("\$str = \"$str\";");
echo $str;
?>
PHP_EOL是PHP的一个换行常量
var_dump() 函数
用于输出变量的相关信息
var_dump() 函数显示关于一个或多个表达式的结构信息,包括表达式的类型与值
数组将递归展开值,通过缩进显示其结构
<?php
$a = array(1, 2, array("a", "b", "c"));
var_dump($a);
?>
可变变量
可变变量是一种PHP独特的变量,它允许动态改变一个变量的名称
一个可变变量获取了一个普通变量的值作为这个可变变量的变量名
使用可变变量就是在变量的前面多加一个美元符号“$”
<?php
$a = 'hello'; //声明一个普通变量
?>
<?php
$$a = 'world'; //使用两个美元符号($)后,就可以作为一个可变变量的变量了
?>
<?php
echo "$a {$$a}".PHP_EOL;
echo "$a $hello"; //两个变量都被定义了:$a 的内容是“hello”并且 $hello 的内容是“world”
?>
它们都会输出:hello world。
要将可变变量用于数组,必须解决一个模棱两可的问题。这就是当写下 $$a[1] 时,解析器需要知道是想要 $a[1] 作为一个变量呢,还是想要 $$a 作为一个变量并取出该变量中索引为 [1] 的值。
解决此问题的语法是,对第一种情况用 ${$a[1]},对第二种情况用 ${$a}[1]。
包含文件:include 和 require
在服务器执行 PHP 文件之前在该文件中插入一个文件的内容
include和require的区别:除了处理错误的方式不同,其他方面都是相同的
当include所包含的文件不存在时,生成一个警告(E_WARNING),但脚本会继续执行
而require引用的文件如果不存在,会生成一个致命错误(E_COMPILE_ERROR)且脚本终止运行
PHP 超级全局变量
PHP中预定义了几个超级全局变量(superglobals) ,它们在一个脚本的全部作用域中都可用,不需要特别说明,就可以在函数及类中使用。
PHP超级全局变量包括九个:
$GLOBALS ;$_SERVER ;$_REQUEST ;$_POST $_GET
$_FILES ;$_ENV ;$_COOKIE ;$_SESSION
$GLOBALS 是PHP的一个超级全局变量组
包含了全部变量的全局组合数组,变量的名字就是数组的键
<?php
$x = 75;
$y = 25;
function addition()
{
$GLOBALS['z'] = $GLOBALS['x'] + $GLOBALS['y'];
}
addition();
echo $z;
?>
其中z 是$GLOBALS数组中的一个超级全局变量,所以可以在函数外访问
$_SERVER 是一个包含了诸如头信息(header)、路径(path)
以及脚本位置(script locations)等信息的数组
$_GET、$_POST和$_REQUEST变量被称为表单变量,作用是获取网页表单的信息,并把获取的信息传递给相应的页面进行处理。
$_REQUEST 用于收集HTML表单提交的数据,$_POST 和 $_GET也是用于收集表单数据。
$_REQUEST变量包含$_GET、$_POST和$_COOKIE的内容,$_REQUEST变量可以用来通过“GET”和“POST”这两个方法发送到表单数据。
preg_match 函数
用于执行一个正则表达式匹配,每段正则表达式必须要有一对定界符,我们一般使用 / 为定界符。
比如:
<?php
//模式分隔符后的"i"标记这是一个大小写不敏感的搜索
if (preg_match("/php/i", "PHP is the web scripting language of choice.")) {
echo "查找到匹配的字符串 php。";
} else {
echo "未发现匹配的字符串 php。";
}
?>
正则表达式
(1)基本模式匹配规则
模式,是正则表达式最基本的元素,它们是一组描述字符串特征的字符。模式可以很简单,由普通的字符串组成,也可以非常复杂,往往用特殊的字符表示一个范围内的字符、重复出现,或表示上下文。例如:^once
这个模式包含一个特殊的字符 ^,表示该模式只匹配那些以 once 开头的字符串,例如该模式与字符串 "once upon a time" 匹配,与 "There once was a man from NewYork" 不匹配。
正如^ 符号表示开头一样,$ 符号用来匹配那些以给定模式结尾的字符串。
比如:bucket$
这个模式与 "Who kept all of this cash in a bucket" 匹配,与 "buckets" 不匹配。
字符 ^ 和 $ 同时使用时,表示精确匹配。
例如:^bucket$
只匹配字符串 "bucket"。
如果一个模式不包括 ^ 和 $,那么它与任何包含该模式的字符串匹配。
例如模式:once
与字符串 There once was a man from NewYork Who kept all of his cash in a bucket.是匹配的。
在该模式中的字母 (o-n-c-e) 是字面的字符,也就是说,他们表示该字母本身,数字也是一样的。其他一些稍微复杂的字符,如标点符号和白字符(空格、制表符等),要用到转义序列。所有的转义序列都用反斜杠 \ 打头。制表符的转义序列是 \t。所以如果我们要检测一个字符串是否以制表符开头,可以用这个模式:^\t
(2)字符簇
用一种更自由的描述我们要的模式的办法----字符簇。要建立一个表示所有元音字符的字符簇,就把所有的元音字符放在一个方括号里:
[AaEeIiOoUu] 这个模式与任何元音字符匹配,但只能表示一个字符。 用连字号可以表示一个字符的范围,如: [a-z] // 匹配所有的小写字母 [A-Z] // 匹配所有的大写字母 [a-zA-Z] // 匹配所有的字母 [0-9] // 匹配所有的数字 [0-9\.\-] // 匹配所有的数字,句号和减号 [ \f\r\t\n] // 匹配所有的白字符
(3)PHP正则表达式的内置通用字符簇表
字符簇 | 描述 |
---|---|
[[:alpha:]] | 任何字母 |
[[:digit:]] | 任何数字 |
[[:alnum:]] | 任何字母和数字 |
[[:space:]] | 任何空白字符 |
[[:upper:]] | 任何大写字母 |
[[:lower:]] | 任何小写字母 |
[[:punct:]] | 任何标点符号 |
[[:xdigit:]] | 任何16进制的数字,相当于[0-9a-fA-F] |
(4)单个字符匹配
正则表达式中,\d 表示匹配一个数字字符。等价于 [0-9]
相反,正则表达式中,\D 则表示匹配一个非数字字符。等价于 [^0-9]
+ 匹配前面的子表达式一次或多次(大于等于1次),\d+ 则表示匹配多个数字
此外:
\s 匹配空白(空格、tab)
\S 匹配非空白
\w 匹配非特殊字符(a-z、A-Z、0-9、_、汉字)
\W 匹配特殊字符(非字母、非数字、非下划线、非汉字)
(5)其他常见正则表达式符号
^ 匹配输入字行首
$ 匹配输入行尾
* 匹配前面的子表达式任意次
+ 匹配前面的子表达式一次或多次(大于等于1次)
? 匹配前面的子表达式零次或一次
x|y 匹配x或y
[xyz] 字符集合,匹配所包含的任意一个字符
[^xyz] 负字符集合,匹配未包含的任意字符
(6)正则表达式中常用的模式修正符
修饰符 | 含义 | 描述 |
---|---|---|
i | ignore - 不区分大小写 | 将匹配设置为不区分大小写,搜索时不区分大小写: A 和 a 没有区别。 |
g | global - 全局匹配 | 查找所有的匹配项。 |
m | multi line - 多行匹配 | 使边界字符 ^ 和 $ 匹配每一行的开头和结尾,记住是多行,而不是整个字符串的开头和结尾。 |
s | 特殊字符圆点 . 中包含换行符 \n | 默认情况下的圆点 . 是匹配除换行符 \n 之外的任何字符,加上 s 修饰符之后, . 中包含换行符 \n。 |
(7)其他
开头的 ^ 和结尾的 $ 让PHP从字符串开头检查到结尾,假使没有 $,仍会匹配到末尾。
尽管 [a-z] 代表 26 个字母的范围,但在这里它只能与第一个字符是小写字母的字符串匹配。
前面曾经提到^表示字符串的开头,但它还有另外一个含义。当在一组方括号里使用 ^ 时,它表示"非"或"排除"的意思,常常用来剔除某个字符。比如我们要求第一个字符不能是数字: ^[^0-9][0-9]$,这个模式与 "&5"、"g7"及"-2" 是匹配的,但与 "12"、"66" 是不匹配的。