• 面试中常问的SQL注入题



    在这里插入图片描述

    SQL注入的原理和危害

    1.攻击方式

    对用户输入数据的合法性没有判断和处理,导致攻击者可以在 Web 应用程序中事先定义好的 SQL 语句中添加额外的 SQL 语句将恶意代码写入数据库,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步获取到数据信息。

    2.漏洞原因

    1.未审计的数据输入框
    2.使用网址直接传递变量
    3.未过滤的特殊字符
    4.SQL 错误回显

    3.漏洞利用

    分为两类:危害数据库里的数据、直接危害到网站的权限(需要满足条件)

    1. 攻击者未经授权可以访问数据库中的数据,盗取用户的隐私以及个人信息,造成用户的信息泄露。
    2. 网页篡改:登陆后台后发布恶意内容
    3. 网站挂马 : 当拿到webshell时或者获取到服务器的权限以后,可将一些网页木马挂在服务器上,去攻击别人
    4. 数据库被恶意操作:私自添加系统账号修改数据库数据。
    5. 服务器被远程控制:读写文件获取webshell,植入后门

    4.如何防御

    对于 SQL 注入,我们可以采取适当的预防措施来保护数据安全。下面是避免 SQL 注入的一些方法。
    1.过滤输入内容,校验字符串
    过滤输入内容就是在数据提交到数据库之前,就把用户输入中的不合法字符剔除掉。可以使用编程语言提供的处理函数或自己的处理函数来进行过滤,还可以使用正则表达式匹配安全的字符串。

    如果值属于特定的类型或有具体的格式,那么在拼接 SQL 语句之前就要进行校验,验证其有效性。比如对于某个传入的值,如果可以确定是整型,则要判断它是否为整型,在浏览器端(客户端)和服务器端都需要进行验证。
    2. 参数化查询(使用预编译语句)
    参数化查询目前被视作是预防 SQL 注入攻击最有效的方法。参数化查询是指在设计与数据库连接并访问数据时,在需要填入数值或数据的地方,使用参数(Parameter)来给值。
    MySQL 的参数格式是以“?”字符加上参数名称而成,如下所示:

    UPDATE myTable SET c1 = ?c1, c2 = ?c2, c3 = ?c3 WHERE c4 = ?c4
    
    • 1

    在使用参数化查询的情况下,数据库服务器不会将参数的内容视为 SQL 语句的一部分来进行处理,而是在数据库完成 SQL 语句的编译之后,才套用参数运行。因此就算参数中含有破坏性的指令,也不会被数据库所运行。
    3. 安全测试、安全审计
    除了开发规范,还需要合适的工具来确保代码的安全。我们应该在开发过程中应对代码进行审查,在测试环节使用工具进行扫描,上线后定期扫描安全漏洞。通过多个环节的检查,一般是可以避免 SQL 注入的。

    有些人认为存储过程可以避免 SQL 注入,存储过程在传统行业里用得比较多,对于权限的控制是有一定用处的,但如果存储过程用到了动态查询,拼接 SQL,一样会存在安全隐患。

    下面是在开发过程中可以避免 SQL 注入的一些方法。
    1. 避免使用动态SQL
    避免将用户的输入数据直接放入 SQL 语句中,最好使用准备好的语句和参数化查询,这样更安全。
    2. 不要将敏感数据保留在纯文本中
    加密存储在数据库中的私有/机密数据,这样可以提供了另一级保护,以防攻击者成功地排出敏感数据。
    3. 限制数据库权限和特权
    将数据库用户的功能设置为最低要求;这将限制攻击者在设法获取访问权限时可以执行的操作。
    4. 避免直接向用户显示数据库错误
    攻击者可以使用这些错误消息来获取有关数据库的信息。
    参考文献: http://c.biancheng.net/view/8283.html.

    SQL注入有哪些类型

    SQL注入根据注入点可以分为数值型注入字符型注入

    根据注入方式可以分为联合注入,报错注入,布尔盲注,时间盲注,二次注入,堆叠注入,宽字节注入HTTP Header注入

    根据注入的位置可以分为:GET数据注入(提交数据方式为GET,大多存在地址栏)、POST数据注入(提交数据方式为POST,大多存在输入框中)

    其中HTTP Header注入又分 Referer注入 , Cookie注入User-agent注入

    时间盲注又有一种替代方式,叫DNSlog注入,也叫带外注入

    如何判断一个网站有SQL注入点

    $id参数左右有数字型(无)、单引号、双引号、括号等方式组成闭合;

    最为经典的单引号判断法: 在参数后面加上单引号,比如:

      http://xxx/abc.php?id=1'
    
    • 1

    如果页面返回错误,则存在 Sql 注入。 原因是无论字符型还是整型都会因为单引号个数不匹配而报错。

    通常 Sql 注入漏洞分为 2 种类型:

    1. 数字型

    2. 字符型

    数字型判断:
      当输入的参 x 为整型时,通常 123.php 中 Sql 语句类型大致如下: select * from <表名> where id = x 这种类型可以使用经典的 and 1=1 和 and 1=2 来判断:

    Url 地址中输入 http://xxx/abc.php?id= x and 1=1 页面依旧运行正常,继续进行下一步。

    Url 地址中继续输入 http://xxx/abc.php?id= x and 1=2 页面运行错误,则说明此 Sql 注入为数字型注入。

    原因如下: 当输入 and 1=1时,后台执行 Sql 语句:

      select * from <表名> where id = x and 1=1
    
    • 1

    没有语法错误且逻辑判断为正确,所以返回正常。

    当输入 and 1=2时,后台执行 Sql 语句:

      select * from <表名> where id = x and 1=2
    
    • 1

    没有语法错误但是逻辑判断为假,所以返回错误。 我们再使用假设法:如果这是字符型注入的话,我们输入以上语句之后应该出现如下情况:

      select * from <表名> where id = 'x and 1=1' select * from <表名> where id = 'x and 1=2'
    
    • 1

    查询语句将 and 语句全部转换为了字符串,并没有进行 and 的逻辑判断,所以不会出现以上结果,故假设是不成立的。

    字符型判断:
      当输入的参 x 为字符型时,通常 123.php 中 SQL 语句类型大致如下: select * from <表名> where id = ‘x’ 这种类型我们同样可以使用 and ‘1’='1 和 and ‘1’='2来判断:

    Url 地址中输入 http://xxx/abc.php?id= x' and '1'='1 页面运行正常,继续进行下一步。

    Url 地址中继续输入http://xxx/abc.php?id= x' and '1'='2 页面运行错误,则说明此 Sql 注入为字符型注入。同理

    SQL注入中报错注入的函数有哪些

    floor()函数:
    利用rand()函数与group()函数的相互冲突
    
    语法结构:username=admin' and (select 1 from (select count(*), concat(floor(rand(0)*2),0x23,编写SQL语句)x from information_schema.tables group by x )a) and '1' = '1
    
    extractvalue()函数:
    语法结构:extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit 1)))
    
    concat中添加要查询的语句
    
    updatexml()函数:
    语法结构:and 1=(updatexml(1,concat(0x3a,(select user())),1))
    
    exp()函数:
    语法结构:and exp(~(select * from(select user())a))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    若还想了解更多报错函数可以查看这篇文章: https://www.jianshu.com/p/bc35f8dd4f7c.

    如何提高手工盲注的效率

    我们通常会使用DNSlog注入,dnslog注入也可以称之为dns带外查询,是一种注入姿势,可以通过查询相应的dns解析记录,来获取我们想要的数据。

    DNSlog注入原理
    首先需要有一个可以配置的域名,比如:ceye.io,然后通过代理商设置域名 ceye.io 的 nameserver 为自己的服务器 A,然后再服务器 A 上配置好 DNS Server,这样以来所有 ceye.io 及其子域名的查询都会到 服务器 A 上,这时就能够实时地监控域名查询请求了。DNS在解析的时候会留下日志,咱们这个就是读取多级域名的解析日志,来获取信息。简单来说就是把信息放在高级域名中,传递到自己这,然后读取日志,获取信息

    为什么要使用DNSlog注入
    因为一般情况下,在我们无法通过联合查询直接获取数据的情况下,我们只能通过盲注,来一步步的获取数据,但是,使用盲注,手工测试是需要花费大量的时间的,可能会想到使用sqlmap直接去跑出数据,但在实际测试中,使用sqlmap跑盲注,有很大的几率,网站把ip给封掉,这就影响了我们的测试进度,也许你也可以使用代理池。。

    mysql的网站注入,5.0 以上和 5.0 以下有什么区别?

    5.0以下没有information_schema这个系统表,无法列表名等,只能暴力跑表名。

    5.0以下是多用户单操作,5.0以上是多用户多操做。

    SQL注入如何获取Webshell

    前提

    1.MYSQL用secure_file_priv这个配置项来完成对数据导入导出的限制,
    如果secure_file_priv=NULL,MYSQL服务会禁止导入和导出操作。
    如果secure_file_priv=/tmp/,MYSQL服务只能在/tmp/目录下导入和导出
    如果secure_file_priv="" ,MYSQL服务导入和导出不做限制
    通过命令查看secure-file-priv的当前值,确定是否允许导入导出以及导出文件路径
    
    2.MYSQL中root用户拥有所有权限,但写入webshell并不需要一定是root用户权限,比如数据库用户只要拥有FILE权限就可以执行select into outfile操作
    
    3.当secure_file_priv文件导出路径与web目录路径重叠,写入webshell才可以被访问到
    简单点说就是
    1.select into outfile方法可用(允许导出文件)
    2.我们需要知道网站所在的绝对路径(根目录,或则是根目录往下的目录都行)
    3.我们要有足够的权限
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    union select写入

    outfile方法是mysql提供的一个用来写入文件的函数,当我们可以控制输入的文件和文件的保存路径时,就可以达到传入webshell的目的。当我们可以使用union查询时,就可以构造一个如下的语句:

    union select '' into outfile 'web目录';
    
    • 1

    分隔符写入

    当union无法使用时,还可以利用分隔符写入:

    ?id=1 INTO OUTFILE '物理路径' lines terminated by ()#
    
    ?id=1 INTO OUTFILE '物理路径' fields terminated by ()#
    
    ?id=1 INTO OUTFILE '物理路径' columns terminated by ()#
    
    ?id=1 INTO OUTFILE '物理路径' lines starting by ()#
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    log写入

    新版本的mysql在my.ini中设置了导出文件的路径,无法再使用select into outfile来写入一句话木马,这时我们可以通过修改MySQL的log文件来获取webshell。

    show variables like '%general%';                     #查看配置
    
    set global general_log = on;                         #开启general log模式
    
    set global general_log_file = '网站目录/shell.php';   #设置日志目录为shell地址
    
    select ''                #写入shell
    
    set global general_log=off;                          #关闭general log模式
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    然后就可以在网站目录下创建一个shell.php,里边有我们写入的一句话木马。

    当然也可以通过sqlmap等工具来进行写入,但我将在后期写sqlmap工具使用相关文章上写出。
    参考文献: https://www.csdn.net/tags/MtTaIg0sOTg5MTc2LWJsb2cO0O0O.html.

    了解宽字节注入吗

    什么是宽字节?
    如果一个字符的大小是一个字节的,称为窄字节;如果一个字符的大小是两个字节的,成为宽字节

    像GB2312、GBK、GB18030、BIG5、Shift_JIS等这些编码都是常说的宽字节,也就是只有两字节
    英文默认占一个字节,中文占两个字节

    什么是宽字节注入?
    原理:宽字节注入发生的位置就是PHP发送请求到MYSQL时字符集使用character_set_client设置值进行了一次编码。在使用PHP连接MySQL的时候,当设置“character_set_client = gbk”时会导致一个编码转换的问题,也就是我们熟悉的宽字节注入

    宽字节注入是利用mysql的一个特性,mysql在使用GBK编码(GBK就是常说的宽字节之一,实际上只有两字节)的时候,会认为两个字符是一个汉字(前一个ascii码要大于128,才到汉字的范围)

    GBK首字节对应0×81-0xFE,尾字节对应0×40-0xFE(除0×7F),例如%df和%5C会结合;GB2312是被GBK兼容的,它的高位范围是0xA1-0xF7,低位范围是0xA1-0xFE(0x5C不在该范围内),因此不能使用编码吃掉%5c

    常见转义函数与配置:addslashes、mysql_real_escape_string、mysql_escape_string、php.ini中magic_quote_gpc的配置

    宽字节注入条件
    1.数据库为GBK编码
    2.使用了转义函数,将、POGETST、cookie传递的参数进行过滤,将单引号、双引号、null等敏感字符用转义符 \ 进行转义
    宽字节注入方式

    root %df' or 1=1 #
    
    • 1

    原理:在GBK编码中,反斜杠的编码是%5c,在输入%df后,使得添加反斜杠后形成%df%5c,而%df%5c是繁体字“連”,单引号成功逃逸,爆出Mysql数据库的错误

  • 相关阅读:
    I/O设备管理
    shell编程4-shell嵌套循环及随机数
    软件测试分类
    两万字详细解读AQS,你真的了解它吗?
    Fluent Facede Pattern(外观模式)
    Lambda的使用场景
    【 C++ 】map、multimap的介绍和使用
    【NGINX--1】基础知识
    《Python+Kivy(App开发)从入门到实践》自学笔记:高级UX部件——VideoPlayer视频播放
    深度学习入门(三十七)计算性能——硬件(TBC)
  • 原文地址:https://blog.csdn.net/m0_46467017/article/details/126443469