网站地图    收藏   

主页 > 后端 > 网站安全 >

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

来源:自学PHP网    时间:2015-04-17 13:03 作者: 阅读:

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

前两天一直想写一篇关于投票系统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给服务器进行校验。知道按键算法后剩下两个二逼问题是:

  1. IP怎么绕过?
  2. 验证码怎么破解?

关于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.pdfhttp://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

自学PHP网专注网站建设学习,PHP程序学习,平面设计学习,以及操作系统学习

京ICP备14009008号-1@版权所有www.zixuephp.com

网站声明:本站所有视频,教程都由网友上传,站长收集和分享给大家学习使用,如由牵扯版权问题请联系站长邮箱904561283@qq.com

添加评论