前两天一直想写一篇关于投票系统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#实现代码
主要过程可以参见我算法课程写的一篇很水的大作业论文: M.T.-Pan_OCR_Pre-Processing.pdf ( http://up.2cto.com/2012/0316/20120316111314792.rar ), 最后这个东西的识别率在90%+,还不错,但是针对性太强了。 使用当中发现Tesseract对于这类文字扭曲不是很大的验证码有比较不错的识别率, 前提是做好去噪、二值化等工作。 其中中值滤波的C#实现代码如下:
查看更多关于浅谈新形势下在线Web投票系统的攻防(1) - 网站安的详细内容...