没人真的喜欢验证码——那些需要你找出并输入抽象字符的图片,仿佛是一个学霸看到试卷上出现“1+1=”的题目。通常情况分为两类,不是太简单了:
就是复杂得让人无从下手:
为了让服务器相信你是一个人而非机器,验证码一度被视为“反人类”的存在。我们跳过“验证码的前世今生”,直接进入最惊动人心的“破解”吧!
本文编译自《How to break a CAPTCHA system in 15 minutes with Machine Learning 》,作者 Adam Geitgey。
Adam 选择了一款在 WordPress 上安装量超过 100 万的验证码插件,名为“Really Simple CAPTCHA”。
最棒的地方在于它有源代码,而这些就是直接生成验证码的代码,让破解变得更加容易。为了让增加挑战难度,Adam 自设了一个时间限制:看看能否在 15 分钟内完成破解。
我们的破解之旅就要启程啦!
开始挑战
先了解一下 “Really Simple CAPTCHA”生成的验证码样本:
也就是说,每张图包含 4 个字母,我们查看 PHP 源码验证一下:
没有错,它随机产生四种不同字体的字母验证码。我们还能看出它没有使用字母“O”和“I”、数字“0”和“1”这类容易混淆的字符,因此就有 32 个可以用来被识别的字母和数据。就这么简单!
当前用时:2 分钟
盘点工具箱
在进一步研究前,我们要了解一下会用到的工具:
Python 3
Python是一种有趣的编程语言,包含很多非常棒的机器学习以及计算机视觉的库。
OpenCV
OpenCV 是一款用于处理计算机视觉和图像的框架,十分常见。我们用 OpenCV 来处理验证码图片。它有一个 Python API,因此我们可以在 Python 调用 OpenCV。
Keras
Keras 是由 Python 编写的深度学习框架。它让定义、训练、使用深度神经网络变得更为简介。
TensorFlow
TensorFlow 是一个 Google 开发维护的开源软件库,用于各种感知和语言理解任务的机器学习。我们将在 Keras 中编代码,但是 Keras 超级慢等原因,便需要 TensorFlow 来进行充当后端。
建立数据库
训练任何机器学习系统都需要数据。破解一个验证码系统,我们当然希望训练数据是这个样子的:
既然我们已经有了 WordPress 验证码插件的源代码,我们便能够生成 10000 张包含答案的验证码。
几分钟之后,我便有了一个包含 10000 张 PNG 以及正确文件名的文件夹:
全文唯有这一步骤我不会直接提供代码哦!我只是想在此分享思路,并非鼓励大家真的去破解 WordPress 网站上的验证码。文末,我还是会给大家我生成的这 10000 张图片文件,你可以继续完成我的实验。
当前用时:5 分钟
简化问题
好了,现在我们有了可以直接用来训练的数据集:
有了充足的数据后,这项工作基本能够进行了——但是我还想让问题更加简化一些。更少的数据,更少的算力,能解决相同的问题吗?
毕竟我只有 15 分钟呀!
有趣的是这个验证码只有四个字符。如果我们把验证码图片拆开,每个字母都是一张独立的图像,那么我们只需要让神经网络识别每次识别一个字符:
我当然没有时间看完所有 10000 张训练样本并用 PS 把它们一一分成独立的图片。那会需要好几天时间,可现在我只剩下 10 分钟了。我们还不能把图片平均拆分为等大的四部分,因为验证码每个字符的位置也是随机的:
然而,我们仍然可以让这一切自动起来!
在处理图像时,我们经常需要检测像素“污点”是否具有相同的颜色。位于边缘的连续像素被称为“轮廓”。OpenCV 内置了 findContours()函数来检测那些连续的区域。
现在拿一个未经过处理的验证码图片:
然后我们把图像转为黑白(又称阈值),这样就更容易找到连续区域了:
使用 OpenCV 的 findContours() 函数检测图像中包含的带有相同颜色的独立区域:
接着只需把每个独立字符保存成文件。我们知道每个图片都包含四个字符,顺序都是从左至右,我们就能够标记每个保存的字符。只要我们是按照顺序进行保存的,我们便能够用正确的字符命名每一张图片。
哦,等一下——我发现了一个问题,有时候会出现字符重叠的验证码:
这意味着我们不能直接提取独立字符进行保存,因为会出现多个字符被划分在一起的情况:
如果我们不能解决这个问题,便会得到糟糕的训练数据。
那么,如何解决它?
一个简单的办法,我们可以设想当一个区域的“宽”远远高于它的“高”,那可能出现两个字符被分割在一起了。我们便可以把这个区域一分为二,成为两个独立字符:
现在我们有一个提取独立字符的方法了,那就让验证码图像跑起来吧!我们的目标是为了获得每个字符的不同变体,就能把每个字符分别放入不同的文件夹中。
这里是我的“W”文件夹,里面有 1147 个不同 “W”:
当前用时:10 分钟
构建神经网络
既然我们只需要识别出每一个独立字母或者数字,就不用那种特别复杂的神经网络。识别出一个字母当然要比认识猫或者狗这样的复杂图像要容易得多啦。
我们只需要使用一个简单的卷积神经网络(CNN),两个卷积层(convolutional layers)和两个全连通层(fully-connected layers):
我们将不在此赘述卷积神经网络是如何工作的。定义这个神经网络只需要用 Keras 写几行代码就可以完成:
开始训练起来吧!
在一段训练之后,我们的准确率已经逼近 100% 了。这样我们的神经网络应该能够自动通过验证码程序了。
停止计时:15 分钟(正好!)
神经网络模型 PK 验证码
现在我们有了一个经过训练的神经网络,用它来破解验证码简直轻而易举:
1、 抓取一个真实的验证码图片,切记一定要是使用了这个插件的验证码;
2、 把验证码图片分为四个独立的字符图片,使用的手段就和我们刚才制造训练数据集的一样;
3、 让神经网络为每个字符进行独立预测;
4、 使用四个预测结果作为验证码的答案;
5、 迎接胜利!
下图就是我们的模型正在破解真正的验证码:
顺便展示一下代码:
在 GeekPwn 硅谷站上,李伟、沈里、焦晓瑾三位安全研究员仅用时 20 秒便自动破解谷歌图像验证码系统,斩获 20000 美元奖金。更多干货分享,持续关注 GeekPwn!
GeekPwn 公众号菜单可以看比赛视频啦!
回复“极客沙龙”,获取嘉宾分享 PPT
极客沙龙 |
嵌入式安全利器——JTAG 调试实战
极客沙龙 |MacOS/iOS 我的学习和成长之路
极客沙龙 |如何用二维码钓出你的支付信息
极客沙龙 |DEFCON25 杂谈——一场 CTF 奇幻之旅
领取专属 10元无门槛券
私享最新 技术干货