好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

浅谈新形势下在线Web投票系统的攻防(1) - 网站安

前两天一直想写一篇关于投票系统IP绕过和验证码破解的文章,因为时间的原因最后还是拖到了现在。近来一年,做过好几个投票系统的刷票了,也攒了一点经验,分享如下:

 

案例1:

http://wzgg.zjol.com.cn/05wzgg/11zt/kfc/index_zdl.shtml 2011年4月

这个投票系统是我见过最弱的, 没有IP限制 , 没有验证码 , 没有登录 。用户一次投票后就不能再投了。我猜测是后台对session进行了类似如下的 限制:   帮助 //如果本次会话投过票了就不准投了   if( true == session.isPosted )   canPost = false; 但是对刷票专业户来说这个太轻松了,在C#中新建一次HttpRequest即可绕过   帮助  (HttpWebRequest)WebRequest.Create("POST或GET的目标url"); *要注意的是,在伪造html表单进行post操作不要忘了设置Http请求头重的Content Types字段为 application/x-www-form-urlencoded ,关于这个的解释,可以参见 这里 。

当时帮朋友刷这个的时候没有写多线程,当时竞争对手似乎也开了不合法的刷票工具,但是速度好像不及我的块,每秒才3票,我们多台电脑开了多个程序最后每秒有23票左右的刷票速度了。据说在最后关头,票数快到1万了,还有其他组最低只有700票的样子,看着数字有点奇怪,那帮家伙就活生生帮他们刷到了7000票。禽兽啊……

案例2:

地址 点此 可见 2011年5月

这个案例2太有吐槽的价值了。没错,这是本校社团联盟的投票系统截图, 但是后来发现页面下部的版权信息居然是杭电的。 当时有点偏执想不通啊,工大懂计算机的就没人能弄个投票系统啦? 蒙羞啊!加上当时认识的几个辅导员和社团部长都有这个需求, 那时候我就暗暗下决心:一定要干掉这个系统!

在确认这个站没有我这种二脚猫能钻进去的SQL注入漏洞之后, 我和MatRush开始了漫长的刷票探索之路。 不得不承认的是这个系统做得相当得诡异!比如:

 

投票的勾(checkbox)的命名,name是一个随机的9位数字+字母字符:

验证码是要手工按键的

对于第一个问题,因为字符长度是固定的,可以通过使用html代码, 找到相应字符位置就能找到这个checkbox的name了,如果字符长度不固定, 那最好的方式自然是使用正则表达式解析html代码了,你可以点 这里 了解更多。

对于第二个问题,老毛子曾经说过:

一切反动派都是纸老虎。

All the reactionaries are the Papertiger.

——1946年8月6日,毛泽东在和美国记者安娜·斯特朗的谈话

在任何花哨的前端都是纸老虎,决不能退缩!来,我们来抓包!最方便的工具当然是firefox下的firebug啦! 更专业的抓包工具还有大名鼎鼎的 WireShark ,两者都是跨平台的利器。 回到正题,在firebug下可以看到code是被加密过的:

通过查看网页源代码可以发现每按一下验证码处的数字(i)键都会调用 javascript:keyinput(i); 页面js对该函数的实现为:

  function keyinput(i)   {   var input_key = new Array();   input_key[0] = "B2YHNwBgCDhVZwAwDDVUb1BvBjQFZgVkWWBRNwI2UzFVYVU1AGYBYlM3A2VRNlVjD28FOwI9D2xdZFUyV2IHYgd5B2E%3D";   input_key[1] = "UDEKaApqBDFXY1dlUWMCNQFmATYCZ1M%2BCDUGZlQ9BTMCMFVnCmoJPlBlVmYAOAFvU2MGZ1VlBmdcawBnAWkAZlAuCm0%3D";   input_key[2] = "AWAKZFRmBDVZbgQ2U2pSOVdoBWZTYAA3DTBWYwJlVmEBNQo6UWIAYlhvAWcDOgcxVzJVMQUzBmYJPgJnVzQAZwF%2FCm4%3D";   input_key[3] = "VTJSZwtrBDIAYwA4BTNTOVNhA2ZbaQcwXDYEZVFmUzJXZ1E%2FVmYGYldvCmwCZwI0VzdWYwVjBGcIZQAyBTJVYlUrUjc%3D";   input_key[4] = "XD8KZFdjVGZSNAs9DDoEMg5pBjMCY1I1WjADZwFhAmIHPAtsV2wDZgRlBTMDNQdqDz4CMFppUzUAPg5vAWJTNFwiCmg%3D";   input_key[5] = "XDtXNQJlBTAFNgBiV2EHblA0VjNRNVFgCTQAYFE0BDVTNQprCj4BYlRmBmRUZQ82AjMDMFE3DmkPMVM4Cz5XZlwiVzQ%3D";   input_key[6] = "VWYAYFdjUj8ENFNqV2cAbAQ3BGJSbQ5iAT4DNgY2VjRVYVFhCmtUNQdiCjwHNg45UGFSMFs%2BDmsNYAZnAzZRNlUrAGA%3D";   input_key[7] = "BjxQYAMxCGhYPQo%2BAzdTOgNmVDZVNwI3AD5TNgZgVzJXYAYxUGBVN1QwB2IMaVc8BjRVMFAyADVbZgdhUDUFMgZ4UDE%3D";   input_key[8] = "BmcKZVA1BmJTNVBoBz8PNQVlAmdRb1E9C2UAMQRsUmcBNlI9BmNVNAQ1UTcEYQU6BjIAPlRkBTRaZ1MzC2wCYgZ4CmQ%3D";   input_key[9] = "XWsKaVQ0B2cAOAtoBmQCaFdjAGIANVFhCjIANQU2AGBWMVZhU2FUYQJkVzQNOVNtBWBUZAZiAWMJZw45UDNUZl0jCmU%3D";   objid = document.getElementById("keyinputid");   objid2 = document.getElementById("hiddenid");   if (i == -1)   {   objid.value = "";   objid2.value = "";   }   else   {   objid.value += i;   objid2.value = objid2.value + input_key[i] + '|';   }   } 综合其他一些信息得出结论,这个验证码就是对数字进行了简单加密,比如0123加密成   var code = input_key[0]+'|' + input_key[1] + '|'   + input_key[2] + '|' + input_key[3] + '|';

最后把code post给服务器进行校验。知道按键算法后剩下两个二逼问题是:

IP怎么绕过? 验证码怎么破解?

关于IP绕过的问题,谁当年没二逼过啊!那个时候我们用的是按键精灵模拟闪讯联网断网换IP实现的, 这种吊丝用的方法具体细节就不解释,更优雅的高富帅的方法我会在接下去的日志中讲解。 下面谈谈 验证码识别 :

关于常规验证码破解与识别,如下是我找的网络上一些比较好的文章和资源:

http://www.crazycoder.cn/YanZhengMa/Index.html http://www.2cto.com/kf/201203/123439.html http://www.2cto.com/kf/201203/123442.html http://www.2cto.com/kf/201203/123441.html http://www.2cto.com/kf/201203/123440.html http://code.google.com/p/tesseract-ocr/ http://www.pixel-technology.com/freeware/tessnet2/

本案例中使用了tessnet2 OCR库进行验证码识别,但是发现识别率并不太好,于是进行了一些处理:

上图是一个本案例中遇到的验证码,可以看到影响识别的主要因素是

外部有灰框 一些黑色噪音和噪线

外部有灰框: 直接把灰框置白,下面是C#实现代码

public static Bitmap setBoundWhite(Bitmap bmap)//简单去边框   {   Bitmap image = new Bitmap(bmap); int i, Height = image.Height,Width =image.Width; //去边框 for (i = 0; i < Width; i++) { image.SetPixel(i, 0, Color.White); image.SetPixel(i, Height - 1, Color.White); } //去边框 for (i = 0; i < Height; i++) { image.SetPixel(0, i, Color.White); image.SetPixel(Width - 1, i, Color.White); } return image; 一些黑色噪音和噪线: 对于噪点,用Photoshop打开后发现噪点和噪线是同一个RGB色值的, 起初尝试也把这些噪点置白,后来发现这样的效果并不是很好,因为这样一来特征数字被点和线截断了, 于是使用了 中值滤波 为主的一些算法进行了处理,其中在阈值上做了些优化,灰度化第一步, 二值化放在预处理操作的最后一步。

主要过程可以参见我算法课程写的一篇很水的大作业论文: M.T.-Pan_OCR_Pre-Processing.pdf ( http://up.2cto.com/2012/0316/20120316111314792.rar ), 最后这个东西的识别率在90%+,还不错,但是针对性太强了。 使用当中发现Tesseract对于这类文字扭曲不是很大的验证码有比较不错的识别率, 前提是做好去噪、二值化等工作。 其中中值滤波的C#实现代码如下:

 

//仅对灰度处于dgGrayValue~dgGrayValue2的点进行处理   public static Bitmap medianFilter(Bitmap bmp, int dgGrayValue, int dgGrayValue2) //均值滤波优化   { Bitmap bmpobj = new Bitmap(bmp); int x, y; byte[] p = new byte[9]; //最小处理窗口3*3 byte s; int i, j; for (y = 1; y < bmpobj.Height - 1; y++) //排除边框 { for (x = 1; x < bmpobj.Width - 1; x++) { if (!(bmpobj.GetPixel(x, y).R >= dgGrayValue && bmpobj.GetPixel(x, y).R <= dgGrayValue2)) continue; //取9个点的值 p[0] = bmpobj.GetPixel(x - 1, y - 1).R; p[1] = bmpobj.GetPixel(x, y - 1).R; p[2] = bmpobj.GetPixel(x + 1, y - 1).R; p[3] = bmpobj.GetPixel(x - 1, y).R; p[4] = bmpobj.GetPixel(x, y).R; p[5] = bmpobj.GetPixel(x + 1, y).R; p[6] = bmpobj.GetPixel(x - 1, y + 1).R; p[7] = bmpobj.GetPixel(x, y + 1).R; p[8] = bmpobj.GetPixel(x + 1, y + 1).R; //计算中值 for (j = 0; j < 5; j++) { for (i = j + 1; i < 9; i++) { if (p[j] > p[i]) { s = p[j]; p[j] = p[i]; p[i] = s; } } } bmpobj.SetPixel(x, y, Color.FromArgb(p[4], p[4], p[4])); //中值p4 } } return bmpobj; } 案例二中涉及的验证码识别的 整个工程代码 (Win7+VS2010/C#)我已经放到Google Code上提供免费下载。 那个投票系统已经关掉了,那站点的站长好心给了我代码方便我研究, 其中的 验证码生成的php代码 我也放在Google Code上了。feel free to use 摘自 McKelvin's Blog

查看更多关于浅谈新形势下在线Web投票系统的攻防(1) - 网站安的详细内容...

  阅读:47次