<span id="7ztzv"></span>
<sub id="7ztzv"></sub>

<span id="7ztzv"></span><form id="7ztzv"></form>

<span id="7ztzv"></span>

        <address id="7ztzv"></address>

            原文地址:http://drops.wooyun.org/tips/13043

            Author:[email protected]

            注:此文章只適合簡單驗證碼,最后也將編寫的工具附上以及關鍵部分代碼和使用說明文檔

            0x00 簡介


            雖然驗證碼發展到如今有許多人類都難以識別的狀態了,但人有部分老系統使用的驗證碼異常的簡單。還有一些網站由于程序員本身的素質或者缺乏相關圖像相關的知識,所以并沒有自己寫驗證碼的生成程序,而是直接在網上隨便復制粘貼一個Demo級別的代碼來用,以達到網站有驗證碼的目的,而忽略了驗證碼的強弱性,導致很多網站的驗證碼都是爆款弱驗證碼

            如:

            p1

            還有更傻缺的比如:

            p2

            直接就能復制的...這種是完全不知道驗證碼的意義或者為了應付而做的驗證碼

            0x01 處理方式


            好吧忽略上面的圖繼續說

            對于那些簡單驗證碼他們的共同點是

            1. 標準字體
            2. 背景單簡單甚至純色沒有背景
            3. 字體并沒有粘貼在一起

            而本文討論的就是這類的驗證碼。對于那種連背景都沒有的純色、標準字體、沒有黏貼的那種再簡單不過了直接就是100%的識別率

            p3

            這種就不討論了 下面來看看wooyun的驗證碼

            Wooyun的驗證碼有兩種狀態

            p4

            一種是白色文字深色背景 一種是黑色文字淺色背景

            如果只有一種無論是那種設定一個閥值都能很好的二值化 但現在的情況卻是有兩種 所以我能想到的最簡單的方式 那好 我就給出兩個閥值 對于黑色文字我就用一個較小一點的閥值 對于白色文字我就用一個較大一點的閥值

            但是這樣還是會出現一個問題 白色文字二值化后背景黑色文字白色 而黑色文字二值化后背景白色文字黑色 就像下面一下

            p5

            可以看出上面我左邊框選區域一切正常 而右邊卻出了問題 那是因為在我寫程序的時候我認為二值化后文字都是黑色背景是白色 所以我就把黑色區域當作文字來框選就看到了如上的效果 所以說這是一個問題 不僅要二值化二值化后還要到底白色是文字還是黑色是文字

            于是我又想到一種辦法 通常情況下一張圖上背景的面積都會大于文字所占用的面積 所以在二值化的同時我還做了一件事情 二值化的同時記錄下黑點個數和白點個數 如果黑點的個數大于了白點的個數那么我就把黑白反色一下讓黑色像素點變成最少 這樣再把黑色像素當作文字處理

            p6

            這樣做還有一個問題就是 我應該怎么知道什么時候應該使用那一個閥值來二值化 當然辦法可以有很多 比如當圖像上深色像素多余淺色像素的時候使用較大閥值 否則相反 不過我并不是這樣做的

            p7

            在工具上我提供了一個框讓用戶輸入驗證碼的字符個數 這樣的話我對體統的閥值挨個遍歷 二值化后去識別區域 如果框出來的區域個數是有問題的 那么就換下一個閥值 如果所有閥值都遍歷完了還是有問題 那么這驗證碼確實也是超出這個工具的范圍了 因為這個工具的目的是通用 對于那些需要單獨寫代碼來識別的不在他的能力范圍內

            在這之前一些驗證碼可能還需要一些處理比如很常見的一些驗證碼有邊框的

            p8

            左邊是沒有裁剪的邊框一起被二值化成為了黑色 然后拆字就悲劇了 右邊是裁剪掉了一個像素的把邊框去掉了 然后就一切正常了 這種情況就不說了 都懂的

            還有一種比較復雜的情況 因為二值化并不是萬能的 并不是說什么驗證碼一進行二值化后文字和背景就出來了 下面這張圖是我以前程序需要做的百度推廣的驗證碼識別

            p9

            上面這張圖不怎么能看到效果 因為都是好幾年前的事情了 驗證碼連接訪問已經是500了 這張圖都是測試的時候的截圖

            我描述一下情況吧 上面的驗證碼 首先有邊框 文字 干擾線 即使能把邊框裁剪掉也找不到一個合適的閥值來把線條和文字分離 很簡單因為他的線條的顏色比文字的顏色深 如果我的閥值太小 那么我的文字就沒有了 只會剩下一些線條在哪里

            p10

            這圖為上面那張圖片上驗證碼的NZ兩個字符在ps中放大的效果(盡管上面圖像原來并非保存的png格式已經失真 但大概還是能看到點什么的) 我也去翻了翻以前的代碼來看 當初我二值化的時候并非直接二值化的 在二值化之前還單獨對RGB進行了判斷 代碼截圖如下

            p11

            別百度推廣的驗證碼是我做的第一個驗證碼識別程序 所以我一直記得很清楚 不是一個二值化就能搞定的 所以說在這個工具中我也加入了同樣可以單獨處理RGB的功能

            由于百度的這個驗證碼已經訪問不了了 所以我找了一個同樣有線條的驗證碼 但是這個驗證碼線條顏色比文字顏色淺 所以我就用默認的127作為閥值 假設二值化無法搞定

            p12

            用127閥值上面線條一起被黑化了 但是圖片中文字顏色接近黑色而線條顏色卻要淺一點 所以判斷的時候 可以認為RGB的平均值大于20的就視為背景 就可以這樣干

            p13

            然后效果就成了這樣

            p14

            這樣線條就被處理掉了 不過這個驗證碼直接設置閥值就能搞定 只是為了說明所以采用127作為閥值 還有一點這個驗證碼和百度的那個 他們線條都是在文字的下方 如果是在文字上方 那么同樣的超出了這個工具的范圍 對于線條在上方的 我想過一些處理方式 假設線條為紅色的時候 我在遍歷的時候遇到一個紅色像素點 我就把紅色像素設置為和他相鄰像素的非紅色的顏色 但是我想了一想這個“相鄰”就涉及了它周圍八個像素點 我應該取那一個像素點的顏色 如果是在背景上還好 他周圍應該都是背景的顏色 那一個都無所謂 可是如果是在線條、背景還有文字的交界處就不好處理了 所以工具里面暫時還沒提供這樣的功能 還有那種很難分離背景或者字黏貼在一起的但是每個文字都是一個顏色的那種 也想過一些處理方式 但是實現起來我感覺都會純在一些小問題 所以就還展示沒有做 就不扯那么多了 等做好了再來扯 才比較有證據

            0x02 拆字和識別


            下面來說說驗證碼識別中的一個難點 -> 拆字

            基本上在我看來 能正確的拆字 那么就已經成功了80%了 因為剩下的就是比對的問題了 我在工具中只提供了兩種方式拆字

            p15

            手動添加就不用說了 我這里的自動識別是最傳統的深度遍歷 從圖像的第一個像素點開始遍歷 因為圖像已經二值化 按照我的工具的理解 就只剩下白色背景和黑色文字 所以遇到一個黑色像素點的時候開始記錄 然后開始深度遍歷 大概效果如下

            這是個GIF_p16

            大概代碼如下

            p17

            對于拆字還有很多其他的方式 這里只是最普通的也是最簡單的一種 對于其他方式這個工具中并沒有提供 因為工具只針對簡單通用的驗證碼 對于那種需要單獨寫代碼的驗證碼不考慮 而且工具上功能附加太多也就變得復雜了 其實重點就是感覺有點付出和回報不成正比 而且對于那些流傳的拆字理論知識 說起來確實簡單 但是實際做的時候才會發現 這些理論其實是存在漏洞的 只會在特定條件下才會成立 而驗證碼卻是變幻多端的 這里也就不扯那么多了

            剩下來的就是識別了 我采用的識別方式比較簡單 就是兩張圖來對比 一張是驗證碼上面截取出來的圖像 一張是已知的樣本圖像

            p18

            調用函數會返回這兩張圖的重疊的像素的個數 這樣我把截取出來的驗證碼字符和我所有的樣本對比一次 取出nCount最高的一個 作為結果 也就是說取出和樣本中重疊率最高的一個出來作為結果 在工具中我有兩種方式提供樣本 一種是使用系統的字體 一種是手動采集

            p19

            如果使用系統字體在文本框內輸入驗證碼可能出現的字符 然后點擊 生成 會彈出系統對話框設置字體從而產生樣本 不過對于一些非標準字體 系統字體就很難搞定了 無論是標準字體還是非標準的字體都建議使用手動采集的方式 因為直接從驗證碼上截取下來的圖怎么說也是原配 重復的圖片工具也只會采集一次不會重復添加降低效率比對 下面就是一個非標準字體

            p20

            理論上來說 樣本采集越多越全 識別率就越高 反正我每次都是使用的手動采集樣本 對了這個工具只是一個配置工具而已 并不能用來做什么其他事情 當一切都配置好了之后就可以點擊工具上的 文件 -> 保存 將這些所有的配置 保存成一個文件 可以保存為兩種后最(.ci和.ci.png) 后者以圖片保存方便電腦上查看

            p21

            而識別是另一個獨立的工具調用 如果是.NET則直接調用提供的dll來識別 之所以這樣設計是因為 我并不知道別人 會用驗證碼識別來做什么事情 所以除了識別以外我也不知道別人想要什么功能 所以把所有東西全部獨立出來共別人調用或者使用 對于識別我提供了一個命令行調用工具供給非.NET平臺的程序調用

            p22

            以python舉例:

            #!python
            # coding: UTF-8
            import os
            result = os.popen('verifytool.exe D:\\woo.ci.png -f D:\\woo-verify.png').readlines()
            print (result)
            

            在我的D盤有這樣一張圖

            p23

            這樣別人就可以自己寫腳本去做自己愛做的事情 不過我還是建議使用-p的方式來調用

            #!python
            # coding: UTF-8
            import urllib2
            from socket import *
            
            h = urllib2.urlopen('http://www.wooyun.org/captcha.php')  
            str = h.read()                      #獲取驗證碼
            s = socket(AF_INET,SOCK_DGRAM);
            s.sendto(str,('localhost',14250))   #將獲取到的驗證碼發送給識別程序
            code = s.recvfrom(65500)            #接受識別出來的驗證碼
            print(code)
            

            p24

            如果程序是.NET平臺編寫 則可直接使用VerifyReader.dll文件 將其添加引用然后:

            #!vb
            CodeInfo ci = CodeInfo.LoadFromFile("D:\\woo.ci.png");
            CodeHelper helper = new CodeHelper(ci);
            string code = helper.GetCodeString(Image.FromFile("D:\\woo-verify.png"));
            

            另外這里還單獨的做了一個賬戶爆破的工具出來

            p25

            以下是用自己測試的結果

            p26

            p27

            雙擊列表即可查看數據

            p28

            0x03 相關鏈接


            全套工具及核心代碼和使用說明下載連接:http://down.future-sec.com/VerifyReader-1.1.zip

            <span id="7ztzv"></span>
            <sub id="7ztzv"></sub>

            <span id="7ztzv"></span><form id="7ztzv"></form>

            <span id="7ztzv"></span>

                  <address id="7ztzv"></address>

                      亚洲欧美在线