如何利用Docker構建命令控制伺服器

一、前言

在紅藍對抗中,紅方成功突破對手防線是再正常不過的一件事情。許多經驗證明(根據我的團隊工作經驗),如果想不斷擴大規模、緊跟經驗豐富的安全運營中心(security operations center,SOC)的發展步伐,那就必須緊抓自動化處理流程這個關鍵因素。結合我過去的操作經驗來看,這一點在許多情況下是一個不爭的事實。需要注意的是,「先人一步」不一定意味著我們就可以成功贏得市場。實際情況中我們的確會面臨各種各樣的挑戰,但在許多情況下,手頭上擁有精心策劃的一個產品能起到事半功倍的效果。基於這個原因,我希望我們團隊能夠更有效地設計及部署C2伺服器,我也會在本文中分享一些個人經驗。

二、Docker介紹

如果有些人對與Docker了解甚少,這裡我們來介紹下一些基礎知識以及簡單的專業術語(如果你對此比較了解可以直接跳過這一部分)。Docker是一個容器化平台,開發者及運營團隊可以在Docker的支持下輕鬆構建及部署軟體環境,並且Docker支持幾乎所有的系統平台,兼容性非常好。在深入了解相關知識之前,你需要先熟悉以下幾個名詞:

1、Dockerfile:該文件用來指導如何創建docker鏡像,創建(build)過程通常是一個自動化處理過程。

2、Docker鏡像(Image):該鏡像由docker build文件生成,其地位類似於操作系統鏡像(如Ubuntu 16.04鏡像)。

3、Docker容器(Container):鏡像其實並不是一個單獨的文件,而是具有層級結構,多層容器可以組成一個完整的鏡像,這也是Docker強大的地方所在。想想一下,如果我們想構建5個Ubuntu鏡像,這幾個鏡像彼此僅在ENV(環境變數)上有點區別。那麼首先我們需要從頭開始構建一個鏡像,但隨後只需要簡單修改一層後,就能得到一個新的「鏡像」。之所以能這麼做,原因在於這些鏡像只是基礎鏡像的快照而已。

4、Docker數據卷(Volume):與掛載的驅動器類似,Volume是一個存儲容器,可以支持數據的持久化存儲。

三、Docker及C2

Docker最主要的一個優點是採用了分層容器系統,這樣一來,多個Image可以使用不同的volume以及不同的Container。這種方案有如下幾點明顯的優勢:

1、大小:減少部署不同的環境或鏡像時所佔的空間大小。

2、成本:減少所需的VPS基礎設施的數量。

3、資源:通常情況下,我們幾乎不會達到可利用資源的極限值,使用Docker後,我們可以在成本為5美元的Digital Ocean虛擬機實例上運行5個Empire伺服器。

4、集中控制:我討厭同時維護多個實例,採用埠映射的Docker網路解決方案後,我們可以在一台伺服器上同時維護長期、短期以及備份用途的C2伺服器。

5、安全性:可以避免容器之間通信。Docker容器與LXC容器非常類似,這兩者具有相似的安全特性(均使用內核命名空間來操作)。

6、數據集成:掛載Volume後,你可以將C2數據存放在一個地方,不同C2數據之間可以相互隔離。如果出現問題,別人也只能拿到其中一部分數據。

7、管理:安裝一次性工具的主要問題之一在於這些工具的支持及依賴問題不是那麼好解決,畢竟許多都是黑客們熱衷的工具,不考慮易用性問題。在Docker方案中,宿主OS可以充當基礎鏡像(Base Image)角色,然後我們可以在Base Image中解決掉所有依賴問題。

四、Empire Docker

現在Empire官方支持使用Docker作為操作平台。目前這一方案仍處於dev分支中,但我們已經可以在Docker Hub上找到這個鏡像。對Dockerfile的分析並不在本文討論範圍內,我準備在將來再討論自動化方面內容。如果你想深入了解Dockerfile的代碼,可以訪問此處了解相關細節,該文件需要與release.shbuild.sh腳本配合使用。

首先你需要獲取Empire最新的版本,具體命令為:docker pull empireproject/empire。如果想要運行Empire,只需要一條簡單的命令即可:ocker run -ti empireproject/empire。Empire運行起來後,你可以輸入其他命令行參數。

你可能會注意到,Empire會運行reset.sh以創建資料庫及秘鑰。這是一種安全特性,屬於正常操作,Empire團隊通過這種方法避免為所有的Docker鏡像創建相同的秘鑰。

Docker中非常強大的一種用法就是--entrypoint參數,這個參數可以覆蓋鏡像中內置的ENTRYPOINT(入口點)。你需要進入容器中,像正常操作那樣運行Empire。為了進入容器,你可以使用如下命令替換ENTRYPOINT:

alexanders-MacBook-Pro:~ alexanderrymdeko-harvey$ docker run -ti --entrypoint bash empireproject/empire nroot@cc4ca15ed8ab:/opt/Empire# lsnDockerfile LICENSE README.md VERSION changelog data empire lib plugins setupnroot@cc4ca15ed8ab:/opt/Empire#n

在生產環境中,這麼做無法正常工作,最主要的問題是存儲問題。每當我們運行及重啟鏡像時,除非我們提交變更(commit),否則鏡像都會恢復到基礎狀態。為了實現持久性存儲,我們可以使用Docker Volume,以便將改動掛載到鏡像中的特定位置。在這個案例中,我們只需要掛載到Empire數據目錄,就可以維護我們的資料庫以及證書,具體命令為:docker create -v /opt/Empire --name data empireproject/empire。最後,我們可以使用--volumes-from標識,將之前的data卷掛載到我們的安裝目錄中,命令為docker run -ti --volumes-from data empireproject/empire。這些操作的運行結果如下所示:

alexanders-MacBook-Pro:~ alexanderrymdeko-harvey$ docker create -v /opt/Empire --name data empireproject/empiren5cae53e19681b4d97646c79ff1673218a421cf689046fcdfa2fdbd4602dd24aenalexanders-MacBook-Pro:~ alexanderrymdeko-harvey$ docker volume lsnDRIVER VOLUME NAMEnlocal cbb254a5d09b2c0ee828509a67dab0697bdbe5f901a71aa24a565433d6f4a854nalexanders-MacBook-Pro:~ alexanderrymdeko-harvey$ docker run -ti --volumes-from data empireproject/empiren[*] Loading stagers from: /opt/Empire//lib/stagers/n[*] Loading modules from: /opt/Empire//lib/modules/n[*] Loading listeners from: /opt/Empire//lib/listeners/n<SNIP>n

最後,我們需要將我們的Docker容器對宿主網路環境開放,我們可以使用多種方法完成這一任務,但我發現使用publish參數可以有效解決這種應用場景。這個功能可以讓我們「將容器的埠開放給主機網路」。我們可以在-p參數後面帶上<HOST-IP>:<HOST-PORT-TO-EXPOSE>:<GUEST-PORT-TO-EXPOSE>。這樣操作後,我們可以綁定埠,將流量直接轉到Docker容器中,即使我們使用了不同的外部埠也沒有問題。

alexanders-MacBook-Pro:~ alexanderrymdeko-harvey$ docker run -ti --volumes-from data -p 10.0.0.207:80:80 empireproject/empirenn<SNIP>nn================================================================n [Empire] Post-Exploitation Frameworkn================================================================n [Version] 2.3 | [Web] https://github.com/empireProject/Empiren================================================================nn _______ .___ ___. .______ __ .______ _______n | ____|| / | | _ | | | _ | ____|n | |__ | / | | |_) | | | | |_) | | |__n | __| | |/| | | ___/ | | | / | __|n | |____ | | | | | | | | | | ----.| |____n |_______||__| |__| | _| |__| | _| `._____||_______|nnn 282 modules currently loadednn 0 listeners currently activenn 0 agents currently activennn(Empire) > listenersn[!] No listeners currently active n(Empire: listeners) > uselistener httpn(Empire: listeners/http) > infonn Name: HTTP[S]nCategory: client_servernnAuthors:n @harmj0ynnDescription:n Starts a http[s] listener (PowerShell or Python) that uses an GET/POST approach.nnHTTP[S] Options:nn Name Required Value Descriptionn ---- -------- ------- -----------n SlackToken False Your SlackBot API token to communicate with your Slack instance.n ProxyCreds False default Proxy credentials ([domain]username:password) to use for request (default, none, or other).n KillDate False Date for the listener to exit (MM/dd/yyyy).n Name True http Name for the listener.n Launcher True powershell -noP -sta -w 1 -enc Launcher string.n DefaultDelay True 5 Agent delay/reach back interval (in seconds).n DefaultLostLimit True 60 Number of missed checkins before exitingn WorkingHours False Hours for the agent to operate (09:00-17:00).n SlackChannel False #general The Slack channel or DM that notifications will be sent to.n DefaultProfile True /admin/get.php,/news.php,/login/ Default communication profile for the agent.n process.php|Mozilla/5.0 (Windowsn NT 6.1; WOW64; Trident/7.0;n rv:11.0) like Geckon Host True http://172.17.0.2:80 Hostname/IP for staging.n CertPath False Certificate path for https listeners.n DefaultJitter True 0.0 Jitter in agent reachback interval (0.0-1.0).n Proxy False default Proxy to use for request (default, none, or other).n UserAgent False default User-agent string to use for the staging request (default, none, or other).n StagingKey True G:IfjvH;Z#J|]FSs9XU~},D{[)8yuR2n Staging key for initial agent negotiation.n BindIP True 0.0.0.0 The IP to bind to on the control server.n Port True 80 Port for the listener.n ServerVersion True Microsoft-IIS/7.5 Server header for the control server.n StagerURI False URI for the stager. Must use /download/. Example: /download/stager.phpnnn(Empire: listeners/http) > executen[*] Starting listener httpn[+] Listener successfully started!n(Empire: listeners/http) >n

了解這些命令後,我們基本上就可以啟動並運行目標環境了。Docker中還有一些高級功能,我們會在接下來的CobaltStrike內容中加以介紹。

五、CobaltStrike Docker

紅方通常會使用CS(CobaltStrike)作為首選的工具/植入程序。因此我決定使用Dockerfile來構建一個基礎鏡像。最近CS在Docker Hub上的許可/試用方案有了些變化,這也是我為什麼不使用官方鏡像的原因所在。不過不用擔心,在本地構建一個Docker鏡像並沒有那麼複雜。我已經公開了相關的Dockerfile,大家可以訪問此處了解具體內容。整個過程中需要注意一些關鍵步驟,不過最重要的是構建過程中需要將CS許可秘鑰傳遞給Dockerfile。

首選,我們需要clone這個Dockerfile。

git clone https://github.com/killswitch-GUI/CobaltStrike-ToolKit.gitn

接下來我們開始構建鏡像,將cskey替換為我們自己的許可秘鑰。這個過程中會下載一些文件,我們需要稍等片刻,放鬆一下。

docker build --build-arg cskey="xxxx-xxxx-xxxx-xxxx" -t cobaltstrikecs .n

像往常一樣,在Dockerfile中,我將ENTRYPOINT設置為teamserver,接下來你可以在鏡像字元串後傳入所需的參數:

docker run -d -p 192.168.2.238:50050:50050 --name "war_games" cobaltstrikecs 192.168.2.238 passwordn

這裡我們使用了兩個新的概念:

1、-d:守護模式,這樣我們就可以後台啟動這個容器。

2、--name:命名這個容器,這樣我們可以在容器啟動後使用這個名稱來引用該容器。

啟動容器後,我們可以查看日誌,監控CS實例的運行狀態,具體命令為:docker logs -f "war_games"

alexanders-MacBook-Pro:Dockerfiles alexanderrymdeko-harvey$ docker logs -f "war_games"n[*] Generating X509 certificate and keystore (for SSL)n[+] Team server is up on 50050n[*] SHA256 hash of SSL cert is: 2013748909fd61ff687711688e5dc4306d0fb1c3afa8ece4f30630c31ba1557cn

如果想要訪問該實例,我們可以使使用exec命令,如下所示:

alexanders-MacBook-Pro: Dockerfiles alexanderrymdeko-harvey$ docker exec -ti war_games bashnroot@bb7d339b3699:/opt/cobaltstrike#n

如果要終止該容器,使用如下這條命令即可:

docker kill war_gamesn

CS Volume

對了,別忘了為CS實例創建一個容器,否則我們會丟失掉所有的數據:

docker create -v /opt/cobaltstrike --name cs-data cobaltstrikecsn

接下來,我們可以使用這個volume來啟動該實例:

docker run -d --volumes-from cs-data -p 192.168.2.238:50050:50050 --name "war_games" cobaltstrikecs 192.168.2.238 password n

推薦閱讀:

CIA如何追蹤目標的真實地理位置?掃描附近公共WiFi
黑客銀行大劫案:弄丟了誰的老婆本,圓滿了誰的暴富夢?
我們有一個回饋活動,你來搞么?
威脅情報在安全運營環節的應用(DEFCON GROUP 010)
【philippica】sql injection--忘掉我就吃掉你

TAG:服务器 | 互联网 | 网络安全 |