zoukankan      html  css  js  c++  java
  • SQL 注入原理

    SQL 注入原理

    sql 注入的原因是应用程序对用户输入的数据没有进行合法判断,并且直接将数据传给数据库进行查询。

    流程如下:

    • 【 P 】:「用户输入」数据 P
    • 【 Q = X + P 】:「应用程序」将 P 与其他数据拼接
    • 【 Q --> R 】:「数据库 」将 Q 作为 SQL语句执行,返回结果 R
    • 【 R 】:「应用程序」接收数据 R,将 R 返回给用户

    基于查询注入

    如果应用程序会直接返回查询的结果,那么我们将可以使用基于查询的注入方法。

    联合查询法:

    • 【 P 】:「用户输入」数据 P = -1' union select @@version -- [1]
    • 【 Q = X + P 】:「应用程序」拼接数据 Q = SELECT sc FROM score WHERE id='-1' union select @@datadir -- '[2]
    • 【 Q --> R 】:「数据库 」将 Q 作为 SQL 语句执行,返回结果 R = /var/sql/233.db
    • 【 R 】:「应用程序」接收数据 R,将 R 返回给用户

    基于报错注入

    应用程序不返回查询结果,反而返回 sql 数据库的报错信息。其流程如下:

    • 【 P 】:「用户输入」:P = ' and updatexml(1,concat(1,database()),1)#
    • 【 Q = X + P 】:「应用程序」:Q = SELECT sc FROM score WHERE id='' and updatexml(1,concat(1,database()),1)#'[3]
    • 【 Q --> R 】:「数据库 」:Q --> R = updatexml 执行错误的信息,其中带有 concat(1,database()) 的执行结果。
    • 【 R 】:「应用程序」:将 R 返回给用户

    基于布尔注入

    应用程序不会返回查询结果,而是会返回一个状态。比如:

    • 0 , 1
    • 真, 假
    • 高,中,低(当然三种状态)

    其中前两个只有两种状态的信息被称为布尔值。流程如下:

    • 【 P 】:「用户输入」:P = 1' and length((select @@version)) > 0 #[4]
    • 【 Q = X + P 】:「应用程序」:Q = SELECT sc FROM score WHERE id='1' and length((select @@version)) > 0 #'
    • 【 Q --> R 】:「数据库 」:Q --> R =「真」 或 「假」
    • 【 R 】:「应用程序」:将 R 返回给用户

    基于时间注入

    应用程序仅返回一种状态,意为当前查询结束。但是没有返回任何数据或者其他状态。流程如下:

    • 【 C 】:「计时程序」用户开始计时 C
    • 【 P 】:「用户输入」P = 1' and length((select @@version))>0 and sleep(5) #
    • 【 Q = X + P 】:「应用程序」Q = SELECT sc FROM score WHERE id='1' and length(version()) and sleep(5) > 0 #'
    • 【 Q --> R 】:「数据库 」Q --> R =「sleep(5),并返回数据」 或 「不执行,返回数据」
    • 【 R 】:「应用程序」将 R 返回给用户
    • 【 C 】:「计时程序」结束计时 C

    可以看出,时间注入与布尔注入本质相同。只是前者返回的是 「无延迟,查询结束」与「延迟 5 秒,查询结束」这两种特殊的状态。

    二次注入

    之前的注入都是一次输入,一次输出式的。而二次注入,则是两次输入,两次输出。

    用一个 web 应用程序举例,假设它的业务逻辑为:

    • 【 P 】:「用户输入」数据 P
    • 【 P --> P' 】:「应用程序」将 P 中的特殊字符进行转义,得到 P'
    • 【 Q = X + P' 】:「应用程序」将 P' 与其他数据拼接
    • 【 Q --> R 】:「数据库 」Q 执行后,P' 将转换[5]为 P 并保存。同时返回一个结果信息 R
    • 【 R 】:「应用程序」将 R 返回给用户
    • 第二次查询
    • 【 R 】:「用户输入」数据 R
    • 【 R --> R' 】:「应用程序」将 R 中特殊字符转义,得到 R'
    • 【 Q2 = X2 + R' 】:「应用程序」将 R' 与其他数据拼接
    • 【 Q2 --> P 】:「数据库 」Q2 执行后,返回结果信息 P[6]
    • 【 Q3 = X3 + P 】:「应用程序」将 P 与其他数据拼接(注意:数据 P 特殊字符没有被转义!)
    • 【 Q3 --> R2 】:「数据库 」Q3 执行后,返回 R2
    • 【 R2 】:「应用程序」将 R2 返回给用户

    从业务看出,第二查询的过程中,应用程序在拼接数据 P 时没有对 P 进行转义。这意味着我们可以在第一次查询时,将注入语句 P 保存进数据库,在第二次查询执行含有 P 的语句。来成功注入。


    1. 两个减号之后是有一个空格的。如果这数据通过 url 传输的话。需要将空格等价替换成 + 再传输。 ↩︎

    2. 可以观察到数据 P 在 Q 末尾的 WHERE 中,这不是必然,而是常见情况。特殊状态下,P 可能在 SELECT、GROUP BY 等之中。 ↩︎

    3. updatexml 函数需要三个参数,因此 concat(1,database()) 前后的 1 只是占位置的参数。 ↩︎

    4. 如果这里 select @@version 不加括号,将会被 length 认为是变量名。引发语法错误。 ↩︎

    5. 数据库在存储数据时,会自动去掉数据中的转义符号。 ↩︎

    6. 这里的结果 P 就是第一次访问时保存的数据 P。 ↩︎

  • 相关阅读:
    未在本地计算机上注册“Microsoft.Jet.OleDb.4.0”提供程序
    GridView选中行变色
    GridView 添加/删除行
    Session、Cookie、Application、ViewState和Cache 这四者的区别
    后台动态给textbox的字体颜色赋值
    JS来判断文本框内容改变事件
    gridview JS控件赋值后如何取值
    c#如何把8位字符串转换成日期格式
    从今天起,热爱生活
    杂得得杂
  • 原文地址:https://www.cnblogs.com/shiwai/p/14172157.html
Copyright © 2011-2022 走看看