阅读:2603回复:0
本是同根生,相煎何太急-用Google语音识别API破解reCaptcha验证码
from:http://www.debasish.in/2014/04/attacking-audio-recaptcha-using-googles.html
◆0 背景 关于验证码和验证码破解的入门,请看:http://drops.wooyun.org/tips/141 什么是reCaptcha? reCaptchas是由Google提供的基于云的验证码系统,通过结合程序生成的验证码和较难被OCR识别的图片,来帮助Google数字化一些书籍,报纸和街景里的门牌号等。 图片:2014091811544862206.png reCaptcha同时还有声音验证码的功能,用来给盲人提供服务。 ◆1 细节 中心思想: 用Google的Web Speech API语音识别来破解它自己的reCaptcha声音验证码. 图片:2014091811544862206.png 下面来看一下用来语音识别的API Chrome浏览器内建了一个基于HTML5的语音输入API,通过它,用户可以通过麦克风输入语音,然后Chrome会识别成文字,这个功能在Android系统下也有。如果你不熟悉这个功能的话这里有个demo: https://www.google.com/intl/en/chrome/demos/speech.html 我一直很好奇这个语音识别API是如何工作的,是通过浏览器本身识别的还是把音频发送到云端识别呢? 通过抓包发现,好像的确会把语音发送到云端,不过发送出去的数据是SSL加密过的。 于是我开始翻Chromium项目的源码,终于我找到了有意思的地方: http://src.chromium.org/viewvc/chrome/trunk/src/content/browser/speech/ 实现过程非常简单,首先从mic获取音频数据,然后发送到Google的语音识别Web服务,返回JSON格式的识别结果。 用来识别的Web API在这里: https://www.google.com/speech-api/v1/recognize 比较重要的一点是这个API只接受flac格式的音频(无损格式,真是高大上)。 既然知道了原理,写一个利用这个识别API的程序就很简单了。 #!bash ./google_speech.py hello.flac 源代码: #!python ''' Accessing Google Web Speech API using Pyhon Author : Debasish Mandal ''' import httplib import sys print '[+] Sending clean file to Google voice API' f = open(sys.argv[1]) data = f.read() f.close() google_speech = httplib.HTTPConnection('www.google.com') google_speech.request('POST','/speech-api/v1/recognize?xjerr=1&client=chromium&lang=en-US',data,{'Content-type': 'audio/x-flac; rate=16000'}) print google_speech.getresponse().read() google_speech.close() 研究了一下reCaptcha的语音验证码后,你会发现基本上有两种语音验证码,一种是非常简单的,没有加入很多噪音,语音也很清晰。另外一种是非常复杂的,故意加了很多噪音,连真人很难听出来。这种验证码里面估计加了很多嘶嘶的噪声,并且用很多人声作为干扰。 关于这个语音验证码的细节可以参考这里https://groups.google.com/forum/#!topic/recaptcha/lkCyM34zbJo 在这篇文章中我主要写了如何解决前一种验证码,虽然我为了破解后一种复杂的验证码也做了很多努力,但是实在是太困难了,即使是人类对于它的识别率也很低。 用户可以把recaptcha的语音验证码以mp3格式下载下来,但是Google语音识别接口只接受flac格式,所以我们需要对下载回来的mp3进行一些处理然后转换成flac再提交。 我们先手工验证一下这样行不行: 首先把recaptcha播放的音频下载成mp3文件。 然后用一个叫Audacity的音频编辑软件打开,如图 图片:2014091811544862206.png 把第一个数字的声音复制到新窗口中,然后再重复一次,这样我们把第一位数字的声音复制成连续的两个相同声音。 比如这个验证码是76426,我们的目的是把7先分离出来,然后让7的语音重复两次。 图片:2014091811544862206.png 最后把这段音频保存成wav格式,再转换成flac格式,然后提交到API。 #!bash debasish@debasish ~/Desktop/audio/heart attack/final $ sox cut_0.wav -r 16000 -b 16 -c 1 cut_0.flac lowpass -2 2500 debasish@debasish ~/Desktop/audio/heart attack/final $ python send.py cut_0.flac 图片:2014091811544862206.png 很好,服务器成功识别了这段音频并且返回了正确的结果,下面就需要把这个过程自动化了。 在自动提交之前,我们需要了解一下数字音频是处理什么原理。 这个stackoverflow的问题是个很好的教程: http://stackoverflow.com/questions/732699/how-is-audio-represented-with-numbers 把一个wav格式的文件用16进制编辑器打开: 图片:2014091811544862206.png 用Python WAVE模块处理wav格式的音频: wave模块提供了一个很方便接口用来处理wav格式: #!python import wave f = wave.open('sample.wav', 'r') print '[+] WAV parameters ',f.getparams() print '[+] No. of Frames ',f.getnframes() for i in range(f.getnframes()): single_frame = f.readframes(1) print single_frame.encode('hex') f.close() getparams()函数返回一个元组,内容是关于这个wav文件的一些元数据,例如频道数量,采样宽度,采样率,帧数等等。 getnframes()返回这个wav文件有多少帧。 运行这个python程序后,会把sample.wav的每一帧用16进制表示然后print出来 [+] WAV parameters (1, 2, 44100, 937, 'NONE', 'not compressed') [+] No. of Frames 937 [+] Sample 0 = 62fe -359 [+] Sample 2 = c1ff -> -63 [+] Sample 3 = 9000 -> 144 [+] Sample 4 = 8700 -> 135 [+] Sample 5 = b9ff -> -71 [+] Sample 6 = 5cfe -> -420 [+] Sample 7 = 35fd -> -715 [+] Sample 8 = b1fc -> -847 [+] Sample 9 = f5fc -> -779 [+] Sample 10 = 9afd -> -614 [+] Sample 11 = 3cfe -> -452 [+] Sample 12 = 83fe -> -381 [+] Sample 13 = 52fe -> -430 [+] Sample 14 = e2fd -> -542 这样是不是更明白了?下面用python的matplotlib画图模块把这些数值画出来: #!python import wave import struct import matplotlib.pyplot as plt data_set = [] f = wave.open('sample.wav', 'r') print '[+] WAV parameters ',f.getparams() print '[+] No. of Frames ',f.getnframes() for i in range(f.getnframes()): single_frame = f.readframes(1) sint = struct.unpack(' |
|