抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

在一个偶然的机会下,一位美女黑客向我询问有关php验证码的问题,我才知道一个叫三叶草的安全组织正在举行信息安全技术大赛。
于是我看了一下题目,难度还是挺高的,由于比赛期间不能泄漏答案,于是等到今天才写出一些题目的攻略。

打开http://code1.myclover.org/Default.aspx,可以看到以下界面:
This is a picture without description

这道题要求在60秒内提交60次验证码,我看了一下,发现还是有点难度的,最后用了一个比较特殊的方法完成。
打开firebug,点击go按钮,跳转到提交验证码的页面:
This is a picture without description

这时看一下firebug捕获的请求:
This is a picture without description

可以看到点击按钮后向Default.aspx提交(POST)了一次数据,还有获取(GET)了Match.aspx和Code.aspx页面的数据。

1、首先看一下Default.aspx提交的参数。
This is a picture without description

提交的参数用php可以写成:

1
2
3
4
5
$post = array(
'Button1' => 'Go!',
'__EVENTVALIDATION' => '/wEWAgLyjPLGBgKM54rGBmPDqObMucxXxtsHOLHUVmjnku17WnTdivWFADL9ShD4',
'__VIEWSTATE' => '/wEPDwUKMjA0OTM4MTAwNGRkkuXw0Thu//c7r9Pfb1F+JxSPHeM6sKURi786gPIAgNE='
);

其中'Button1'的值是固定的'Go!',那么'__EVENTVALIDATION''__VIEWSTATE'是从哪里获取的呢? 查看Default.aspx的网页源码,可以发现源码里有两个隐藏域:

1
2
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEWAgLyjPLGBgKM54rGBmPDqObMucxXxtsHOLHUVmjnku17WnTdivWFADL9ShD4" />
<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="/wEPDwUKMjA0OTM4MTAwNGRkkuXw0Thu//c7r9Pfb1F+JxSPHeM6sKURi786gPIAgNE=" />

所以提交数据之前要先获取Default.aspx的源码,匹配出这两个隐藏域,再提交数据。

2、查看Default.aspx提交数据后服务器的响应头信息:
This is a picture without description

我们感兴趣的是Set-Cookie信息:

1
2
3
Set-Cookie
ASP.NET_SessionId=ynb5mevekohm00ow0wszmrfo; path=/; HttpOnly
Star=1HrpUk4vFyGyGBLmqVg1BNWvnTsr/N8A8NB6ih4u/fI=; path=/

其中ASP.NET_SessionId值是用户与页面会话的标识。
Star值相当于标识了用户点击Go!按钮的时间。
用户点击了Go!按钮,服务器会记录点击的时间,正确提交60个验证码后,服务器会判断开始时间和最后提交的时间差,如果时间差小于60秒,就会显示过关的key。

3、获取Match.aspx页面的源码。
网页源码中也有同样的隐藏域,提交验证码时要用到:

1
2
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUJMjYxMjUwMDUwZGS8D8v8uuSQ6rLtNG29gJP//sHvMScyfWHzWAIAiuZDlQ==" />
<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="/wEWAwKK29znBwLs0bLrBgKM54rGBu8AlJPAD4CBCYKKKwuQqrQBlSp5MkeP+9MlpGQSykvw" />

4、获取Code.aspx的信息。
This is a picture without description

可以看到页面返回一张验证码图片,而且响应头信息中有Set-Cookie"CheckCode"字段是该验证码图片的唯一标识:

1
2
Set-Cookie
CheckCode=E033FDB11F1FAAD86C9A492D4696EC31; path=/

5、填写验证码后点击SUBMIT按钮,发现是向Match.aspx提交数据,查看提交的参数:
This is a picture without description

提交的参数用php可以写成:

1
2
3
4
5
6
$post = array(
'Button1' => 'SUBMIT',
'TextBox1' => '5191',
'__EVENTVALIDATION' => '/wEWAwKK29znBwLs0bLrBgKM54rGBu8AlJPAD4CBCYKKKwuQqrQBlSp5MkeP+9MlpGQSykvw',
'__VIEWSTATE' => '/wEPDwUJMjYxMjUwMDUwZGS8D8v8uuSQ6rLtNG29gJP//sHvMScyfWHzWAIAiuZDlQ=='
);

其中’Button1’的值是固定的’SUBMIT’,’TextBox1’是验证码,隐藏域的值是在第3步中获取的。

综上所述,要完成验证码提交,需要完成以下步骤:
1、获取首页Default.aspx的源码,匹配出隐藏域的值。
2、模拟点击Go!按钮提交数据。
3、获取Match.aspx网页源码的隐藏域的值。
4、访问Code.aspx,获得验证码图片,自动识别成验证码数字。
识别验证码可以参考这篇文章:《php实现验证码的识别(初级篇)》
5、模拟点击SUBMIT按钮提交验证码。
6、重复步骤456,一共重复60次。
7、注意每次请求都要发送和保存cookie。

但是由于我的网速和代码执行速度比较慢,所以每次都要执行60秒以上:
This is a picture without description

由于代码是php写的,但php又没有多线程,所以时间总是超过60秒,最后用了一种方法来模拟多线程。方法就是开两个页面来跑php代码,把代码分成3个文件:
This is a picture without description

submit.php : 用来模拟提交验证码,验证码图片保存到valid.gif,cookie保存到cookie.txt。
submit2.php : 和submit.php差不多,验证码图片保存到valid2.gif,cookie保存到cookie2.txt。
go.php : 用来模拟点击Go!按钮,然后把cookie保存到cookie.txt,然后复制一份为cookie2.txt。

这样执行go.php后,cookie.txtcookie2.txt有相同的ASP.NET_SessionId值和star值。
再同时执行submit.phpsubmit2.php,这两个脚本获取的验证码图片和验证码cookie都会保存在不同的文件里,所以不会互相干扰。

每个页面执行了40多秒,于是成功地获取了过关的key:
This is a picture without description

源码下载

活动结束后,出题者的话:
我的code.aspx在OnLoad时间里面会生成验证码并md5存cookie。
只要你们通过发包的形式。只请求一次code.aspx。后面都同样的验证码即可。

看来以后做题前还是要多分析思考。

评论