Serverless目錄掃描實現
? 首先創建一個云函數,這里以騰訊云舉例。
? 然后選擇自定義創建,運行環境選擇python3.6,函數名隨意,地域則隨便選一個即可,會隨機分配該地域下的IP作為我們的出口IP地址,配置與云函數上線CS的方式相同。
云函數代碼為以下,無論是云函數還是域前置或者反向代理等手段,本質都是流量轉發,所以我們在云函數上編寫的核心代碼就是實現了單次掃描返回信息的功能,剩下的控制代碼則由我們本地編寫的代碼執行。
# -*- coding: utf8 -*-
import requests
def main_handler(event, context):
headers=event["headers"]
url=event["queryString"]["url"]
path = event["queryString"]["path"]
crake_url=str(url+path)
try:
r = requests.get(crake_url,timeout=5,headers=headers,verify=False)
status = r.status_code
except Exception:
status = None
pass
return status,crake_url
? 配置好云函數代碼后,繼續進入?觸發管理?選項。
? 觸發器配置如圖所示,注意取消勾選集成響應。
? 編輯API配置中,將路徑設置為?/?,然后點擊?立即完成
? 然后得到了兩個API網關的公網域名,這時我們就已經完成了基本配置??梢酝ㄟ^這兩個公網域名實現對我們上面編寫的云函數功能的觸發實現。
? 這里進一步編寫一個簡單的Demo,在本地實現了一個目錄掃描的功能,通過對獲取的公網地址傳參,實現以云函數服務對指定站點目錄掃描,這里我傳遞了要掃描的url地址以及字典,代碼如下:
? 在我們本地執行代碼進行掃描,會得到響應給我們并輸出掃描結果。
? 通過微步情報可以發現確為,騰訊云—廣州的IDC服務器
? 但是大家注意看?Apache access.log日志中?header頭中的User-Agent為python-requests/2.26.0,存在了很明顯的特征,這時我們繼續修改本地控制代碼。
? 我們創建一個 get_ua-header.py文件,其中創建了一個UA數組,存放了大量不同的User-Agent。
? 這里導入我們剛才創建的UA數組,然后在第二個箭頭所指處設置header的User-Agent每次都隨機獲取UA數組中的值,再在發送請求中指定header,當然這里僅為了演示,如果真實場景下,可以將header頭自定義設置更多選項讓它看起來更像是一個合法的請求。
? 這里云函數中獲取到了我們本地請求API網關域名的headers然后在轉發時將它的header替換為我們本地請求包中的header從而實現了自定義header的效果,修改后的掃描情形如下圖所示:
? 發現在Apache日志中,User-Agent已經為我們本地請求的隨機信息,那么通過繼續自定義本地控制代碼中的header信息讓他看起來更加合理,就可以實現更加隱匿的掃描啦。
? 繼續我們重復上面的操作,創建一個一模一樣的云函數,API網關也為相同配置,但是需要注意的是選擇的地域要為不同的地方,因為?單個用戶在某個地域只能有5個隨機出口IP,也就是說如果這五個IP均被封禁了那么我們的掃描就無法繼續進行了,但是攻防本身就是對等的,那么有什么辦法能夠繞過呢?
? 我們增加了兩個一模一樣的云函數配置,僅為選擇的地域不同,也是為了繞過上面這一限制,修改我們的代碼添加另一個API網關域名地址對字典進行分工掃描,兩個云函數分別截取字典的部分內容進行掃描,這里我選擇的地域是廣州和上海,然后開始目錄掃描。
? 現在繼續查看access.log日志,發現多出了一些上海的IP地址,是不是更加迷惑了呢?而在目標業務系統中每天面對大量的請求使用中,以往的排查溯源思路都是過濾頻繁訪問或者進行可疑操作的IP地址,但是對于這種情況,通常會被一些正常的請求混雜其中,防守方進行日志審計時往往就會認為這些是正常的HTTP請求。
? 關于這里分批掃描的實現思路在?拓展延伸?會繼續深入講解。
Serverless端口掃描實現
? 然后我們繼續來實現端口掃描器的實現,云函數的配置及API網關配置這里就不多做贅述了,與上面講到的一樣,這里我們僅關注云函數代碼和本地控制代碼的實現。
? 云函數代碼如下:
# -*- coding: utf8 -*-
from socket import *
def main_handler(event, context):
IP=event["queryString"]["ip"]
port=event["queryString"]["port"]
try:
conn=socket(AF_INET,SOCK_STREAM)
res=conn.connect_ex((str(IP),int(port)))
conn.send('Hello,World!'.encode("utf8"))
results=conn.recv(25)
if res==0:
conn.close()
return port
except Exception as err:
print(err)
finally:
print("")
conn.close()
return None
? 同樣這里云函數僅需要實現簡單的單次端口掃描,我們的控制代碼如下:
? 可以看到,這里同樣應用了上面的講到的分批掃描,如果說上面講到的是通過對字典中的路徑區分使用兩個不同的云函數API網關域名,那么這里的端口掃描則為通過端口來區分。
? 因為端口掃描會慢一些,所以這里我使用了協程的方式,掃描速度會更快,使用了grequests模塊。
? 這里執行一下本地掃描腳本,成功的得到了目標主機端口的開放情況,但這不是重點。
? 這里使用Hfish來展示態勢感知中的端口掃描情況
? 可以看到,對這些端口掃描的IP均為騰訊云的隨機IP,是不是無從下手呢?
? 通過Kunyu對這些IP進行批量查詢發現,發現所在地均為中國上海和成都兩地,也證實了攻擊IP為我們云函數的出口IP地址,并且這些數據的Time時間均比較早,而在威脅情報中看到這些IP為IDC服務器,也輔助說明了這些IP為已經回收目前應用于云函數進行請求的云服務器的IP地址,這里的時間因素也是我們后續判斷溯源這種攻擊方式的關鍵所在。
? 歡迎大家來了解一下Kunyu,是一個很好用的空間測繪數據分析工具,其中亮點滿滿哦~ 非常適合大家在紅藍對抗的工作中進行信息收集或者溯源等工作,不同于其他工具的是,Kunyu的設計更貼合數據分析的工作而不僅僅只是IP導出。
下載地址:https://github.com/knownsec/Kunyu
拓展延伸
上面講到了?單個用戶在某個地域只能有5個隨機出口IP?那么在更大流量的掃描下,單次如果僅僅只是5個掃描的IP地址,依舊非常容易被排查出來從而封禁IP。那么為了解決這一問題,我們可以通過分批次的方式進行掃描,如果是端口掃描,我們就可以創建多個云函數且為不同地域分工掃描不同端口,在態勢感知來看就是這n*5個IP地址在進行掃描,也就解決了單個地域只能有5個IP的窘境。
? 同樣進一步思考,我們也可以在相同的云函數下創建多個地域的云函數,再創建其他廠商的云函數,實現了IP地址的多元化,在這個基礎上再創建不同地域,理論上可以這樣一直疊加,實現單兵大流量掃描。
? 對于大集團目標,通常每天態勢感知都會有很大的掃描流量,那么在這種情況下,如果給我們的云函數掃描再加上一定程度的隨機延時掃描,那么在態勢列表中看到的就是一堆不連續的單次請求,如果是目錄掃描則會直接認為是正常的請求,因為IP的隨機性以及請求包的合法性、不連續性根本無法聯想這是一次掃描事件,更不要談溯源的問題了,根本無法還原攻擊鏈,這樣的攻擊只會比C2隱匿反彈更難纏。
? 整個實現過程思維導圖如下:
? 各位小伙伴也可以在我所講的基礎上,更進一步將請求包完善的盡量合理化,這樣面對防火墻等設備,面對大量的IP掃描也無法通過IP頻繁請求的方式從而封禁IP,導致封無可封,更別談溯源的問題了。而本地的控制代碼可以幫助我們更好的對整個掃描進行控制處理,讓整個掃描更加個性化,云函數代碼只進行單次流量轉發掃描,而本地代碼則負責了通過什么樣的方式掃描的問題。
? 但是面向藍隊成員來講也不需要太過恐慌,畢竟有攻就有防,針對這種掃描,如果找出可疑流量直接封禁IP即可,這種情況下就會導致紅隊掃描結果的不準確,某個IP被封禁了,那么他的后續通過這個IP的請求都將掃描失敗。
? 再退到紅隊的角度,面對上面的應對方式,我們可以通過思維導圖中講到的分工掃描,多個云函數交替重復相同的掃描任務防止封禁,這樣某個IP被封禁也不用怕掃描的失效,當然一般來講封禁IP也都是掃描結束后的事情了,通常防守方根本沒那么快的響應速度。
? 我一直認為攻防對抗雙方是對等的立場,各自都有自己的優勢,而如何利用自身的這種優勢實現目標就是需要思考的問題了,在檢驗企業安全的同時也在磨練技術人員的技術水平,這也是紅藍對抗的意義所在。所以大家在思考攻擊或者防守問題時一定要站在對立的角度去想,思考對方的應對手段才能找到問題的突破點。
? 上面提到的代碼均已上傳至Github,感興趣的師傅可以自行下載,也可以自己編寫。
??下載地址:https://github.com/wikiZ/ServerlessScan
轉載在安全客:https://www.anquanke.com/post/id/261551