Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    863102625

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

隨著內核地址空間佈局隨機化(KASLR)被現代系統廣泛採用,獲取信息洩漏是大多數權限升級攻擊的必要組成部分。本文我們將介紹XNU(蘋果macOS使用的內核)的實現細節,它可以消除許多內核漏洞中對專用信息洩露漏洞的需要。

關鍵在於內核Mach-O的__HIB段,它包含系統休眠和底層CPU管理的函數子集和數據結構,總是映射在一個已知的地址。

我們將首先介紹__HIB段以及它可能被濫用的各種方式。使用我們的Pwn2Own 2021內核漏洞作為一個真實的例子,展示如何簡化該漏洞。

1.png

濫用基本操作系統設計可以實現漏洞利用原語

__HIB 段:休眠和內核入口

__HIB段的名字來源於“休眠(hibernation)”,似乎它的主要目的是處理從休眠映像中恢復系統。

它的其他主要功能是處理內核的低級進入和退出,即通過中斷或系統調用。它包含中斷描述符表(IDT) 和相應的中斷處理程序存根。

它同樣包含通過syscall和sysenter指令進入的存根。這些入口點是通過編寫相應的MSR 來設置的:

2.png

這個代碼片段使用DBLMAP宏引用“DBLMAP”中的每個函數的別名。

XNU dblmapdblmap是一個虛擬內存區域,別名為組成__HIB段的相同物理頁。

dblmap在doublemap_init()中初始化,它將虛擬別名插入到構成__HIB段的所有物理頁的頁表中。 dblmap 的基數是用8 位熵隨機化的。

3.png

別名防止了使用sidt指令的瑣碎的KASLR繞過,sidt指令將揭示IDT的內核地址。這個指令不是權限指令,如果在ring3(用戶模式)中執行不會導致異常,除非在處理器上啟用了用戶模式指令保護(UMIP)(不在XNU 中):

用戶模式指令預防(CR4的第11位)設置後,如果CPL 0: SGDT、SIDT、SLDT、SMSW和STR,則不能執行以下指令,如果試圖執行該值,將導致通用保護異常(#GP)。

4.png

由於IDT/GDT/LDT/etc 位於dblmap 別名中,因此知道它們在dblmap 中的地址不會顯示它們在正常內核映射中的地址。但是,它們確實會洩漏dblmap 信息。

緩解失敗dblmap 的一個輔助目的是它起到緩解Meltdown 的作用。各種操作系統採用的常用技術是在執行用戶空間代碼時從頁表中刪除內核映射,然後在進行中斷/系統調用/等時重新映射內核。 Linux 將其實現稱為內核頁表隔離(KPTI),在Microsoft Windows 上,它的對等物被稱為KVA Shadow。

兩種實現方式的相似之處在於,在執行用戶代碼時,只有一小部分內核頁面出現在頁表中。該子集包含處理中斷和系統調用以及在用戶和內核頁表之間來迴轉換所需的代碼/數據。在XNU 的情況下,“小子集”正是dblmap。

5.png

為了進行頁表轉換,中斷調度代碼需要知道正確的頁表地址以進行切換。換句話說,要向cr3寫入什麼值,即保存頂級分頁結構的物理地址的控制寄存器。

這些值駐留在__HIB 段的數據部分之一中的每個CPU 數據結構中:

cpshadows[cpu].cpu_ucr3 : 用於userspace + dblmap;

cpshadows[cpu].cpu_shadowtask_cr3 :用於userspace + full kernel;

從用戶空間進入後,中斷調度代碼會將cr3 切換到cpu_shadowtask_cr3,然後在返回用戶空間之前切換回cpu_ucr3。

由於在執行用戶代碼時dblmap 被映射到頁表中,因此理論上dblmap 中的任何內容都可以使用Meltdown 讀取。這就產生了dblmap 中是否存在任何“敏感”數據的問題。

值得注意的是,有幾個函數指針以數據的形式出現,用於從dblmap跳轉到正常映射的內核函數。洩露其中任何一個都足以確定kernel slide(用於描述隨機內核基址地址的XNU 術語)並破壞KASLR。

有趣的是,KASLR 在Windows 和Linux 上都可以通過Meltdown 進行類似的攻擊:

同樣的策略也適用於運行有漏洞的英特爾硬件的最新版本的macOS。只需使用libkdump從dbblmap讀取即可。簡而言之,Meltdown 可用於在除最後一代基於Intel 的Mac 機型之外的所有設備上破壞KASLR,該機型附帶Ice Lake 處理器,其中包含針對Meltdown 的CPU 級修復。

雖然KASLR 在基於Intel 的Mac 上無疑是一個重要且幾乎普遍的突破,但我們現在將討論dblmap 提供的其他幾個有用的內核利用原語,這些原語適用於包括Ice Lake 在內的所有版本。

LDT——已知內核地址的受控數據從利用的角度來看,也許dblmap 最有趣的工件是它為每個CPU 內核保存LDT,它可以包含幾乎可以從用戶模式控制的任意數據,並且位於dblmap中的固定偏移位置。

LDT/GDTLDT 和GDT 包含許多段描述符。每個描述符要么是系統描述符,要么是標準代碼/數據描述符。

代碼/數據描述符是一個8 字節的結構,描述了具有某些訪問權限(即它是否可讀/可寫/可執行,以及可以訪問它的特權級別)的內存區域(由基地址和限制指定)。這主要是一個32 位保護模式的概念;如果執行64 位代碼,則忽略基地址和限制。描述符可以描述64 位代碼段,但不使用基本/限制。

6.png

系統描述符是特殊的,大多數擴展為16 字節以適應指定64 位地址。它們可以是以下類型之一:

LDT :指定LDT 的地址和大小;

任務狀態段(TSS) :指定TSS 的地址,該結構包含與權限級別切換相關的信息結構;

調用、中斷或陷阱門:指定遠程調用、中斷或陷阱的入口點;

LDT中唯一允許的系統描述符是調用門,我們稍後會探討。

段描述符使用16 位段選擇器引用:

7.png

例如,cs寄存器(代碼段)是一個選擇器,它引用當前正在執行的任何代碼的段。通過在GDT/LDT中為64位和32位代碼設置不同的描述符,操作系統可以通過使用適當的選擇器在受保護模式(32位代碼)和長模式(64位代碼)之間進行用戶空間跳轉。特別是在macOS上,硬編碼的選擇器是:

0x2b:第5個GDT 條目,ring3——64 位用戶代碼;

0x1b:第3個GDT 條目,ring3——32 位用戶代碼;

0x08:第1個GDT 條目,ring0——64 位內核代碼;

0x50:第10個GDT 條目,ring0——32 位內核代碼;

LDT在macOS上的應用進程可以通過調用i386_set_ldt()在其用戶模式的LDT中設置描述符。它調用的對應內核函數是i386_set_ldt_impl()。

此函數對LDT 中允許的描述符類型施加了一些限制。描述符必須為空,或者指定一個用戶空間的32位代碼/數據段:

8.png

就二進制格式而言,這轉換為對每個8字節描述符的以下限制:

字節5 (dp-access):必須是0,1,或者有高nibble0xf(值匹配0xf)。

字節6 (dp-granularity): 位5不能設置(掩碼0x20)。

使用LDT在已知的內核地址創建偽內核對象,這些限制不會太嚴格。唯一真正的問題是能否在這樣的對像中構造有效的內核指針。

為了解決這個問題,我們可以將假對象錯位6 個字節。這將使dp-access 與內核指針的高字節(將為0xff)重疊。唯一的限制是指針的低字節(與dp-granularity 重疊)不能設置位5 。

成功設置LDT描述符將創建一個堆分配的LDT結構,該結構的指針存儲在當前任務結構的task-i386_ldt字段中。

9.png

每當發生上下文切換或手動更新LDT時,內核通過user_ldt_set()將來自該結構的描述符複製到實際的LDT(在dblmap中)。

進程可以使用i386_get_ldt()查詢當前的LDT條目,調用內核函數i386_get_ldt_impl()。這將直接從實際LDT(在dblmap中)複製描述符,而不是從LDT結構體複製描述符。

已知內核地址上的已知代碼在編寫沒有內核代碼地址洩漏的macOS 內核漏洞利用時,__HIB 文本部分中的函數子集可能會用作有用的調用目標。

dblmap 中一些值得注意的函數(在固定偏移處)是:

memcpy(), bcopy();

memset(), memset_word(), bzero();

hibernate_page_bitset()——設置或清除位圖結構中的位;

hibernate_page_bitmap_pin()——可以將32 位int 從第一個結構參數複製到第二個指針參數;

hibernate_sum_page()——從它的第一個參數返回一個32 位int 作為一個數組,使用第二個作為索引;

hibernate_scratch_read(),hibernate_scratch_write()——類似於memcpy,但第一個參數是一個結構;

當控制流被劫持時,這些函數對內核利用的效用將嚴重依賴於特定的上下文。上面列出的大多數內核調用目標需要3個參數。如果一個給定的漏洞允許按順序進行多個受控調用,你還可以使用早期調用來設置寄存器/狀態,以便在以後的調用中使用。

無論情況如何,dblmap通常可以用來將一個簡單的內核控制流劫持原語轉換為同時產生真正內核文本(代碼地址)洩漏的內容。

其他dblmap技巧已知內核地址上真正任意的64位值我們已經介紹了dblmap如何允許我們輕鬆地在LDT中放置幾乎任意的數據。

但是,假設你需要一個真正任意的64位值(可能你需要的函數指針位為5,並且不符合LDT 限制)。當進行系統調用時,調度存根會將rsp(用戶空間堆棧指針)保存在dblmap 的臨時位置(cpshadows[cpu].cpu_uber.cu_tmp)。用戶rsp 值也將放置在dblmap 中的中斷堆棧上(對於cpu 0 的master_sstk 或scdtables[cpu])。

雖然不是其預期用途,但rsp 可以被視為通用寄存器,並分配任意64 位值。除非需要在系統調用之前和之後設置/恢復rsp 給開髮帶來不便,否則這會在已知地址處提供任意64 位值。

將內核指針洩漏到LDTLDT的另一個有用的方面是,它可以用作真正的內核地址洩漏的可寫位置,可以使用i386_get_ldt()從用戶模式查詢和讀取。假設你能夠使用劫持函數調用將任意地址複製到LDT中。將dblmap中的一個函數指針複製到LDT中,然後查詢LDT的適當範圍,將獲得文本洩漏。

或者作為另一個例子,也許你劫持的函數調用的第一個參數是LDT中的假對象,第二個參數是某個有效的c++對象,第三個參數是任何足夠小的整數。調用memcpy() 會將vtable和一些對象的字段複製到LDT。查詢LDT 然後將這些洩漏讀取到用戶空間。

記住,每個CPU核有一個LDT,在macOS上沒有方法將進程固定到任何特定的核上。如果一個線程執行被劫持的函數調用,將洩漏複製到它的LDT中,然後在調用i386_get_ldt()之前被搶占,那麼洩漏實際上將丟失。

在本文中,我們將為讀者詳細介紹在Windows 11內部預覽版中,KUSER_SHARED_DATA結構體發生了哪些新變化。下面,我們開始進入本文的下篇部分!

(接上文)

知道了這些,我們就會明白:在調用nt!MiReservePtes之前,就可以計算出對應於“靜態”的KUSER_SHARED_DATA的PFN數據庫的適當索引。這實質上意味著我們正在從PFN數據庫中檢索相應PFN記錄(一個MMPFN結構)的虛擬地址。

我們可以把它看作是PFN數據庫的基址,在本例中是0xffffc38000000000,它參與了相關操作。而最終的虛擬地址0xffffc380002df8a0(與“靜態”KUSER_SHARED_DATA關聯的PFN記錄的虛擬地址)可以在下面的RBP中看到。將來,它將用作nt!MiMakeProtectionPfnCompatible函數調用的第二個參數。

1.png

我們可以通過將上述虛擬地址解析為MMPFN結構體來驗證這一點,以查看PteAddress成員是否對應於“靜態”KUSER_SHARED_DATA的已知PTE。我們知道,PTE位於0xffffb7fbc0000000。

1.png

由於PFN結構體的PteAddress成員與“靜態”KUSER_SHARED_DATA關聯的PTE的虛擬地址是對齊的,這說明它就是與“靜態”KUSER_SHARED_DATA關聯的PFN記錄。

然後,這個值被用於對nt!MiReservePtes的調用,我們可以通過前面的兩張圖來確認這一點。根據__FastCall調用約定,該函數的第一個參數將進入RCX寄存器。這個參數實際上是一個nt!_MI_SYSTEM_PTE_TYPE結構體。

根據CodeMachine的文章來看,當對nt!MiReservePtes的調用發生時,這個結構體被用來定義如何進行內存分配,以便為正在創建的PTE預留內存。當用nt!MiReservePtes請求分配內存時,可能暗示了從系統PTE區域分配一塊虛擬內存。系統PTE區域被用於內存的映射視圖、內存描述符列表(MDL)和其他內容。有了這一信息,結合我們對兩個虛擬地址是如何被映射到同一物理內存頁的了解,就能確定:系統正在使用內存的不同'視圖'(例如,兩個虛擬地址對應一個物理地址,所以,儘管兩個虛擬地址包含相同的內容,但可能具有不同的權限)。此外,我們可以確認分配的內存來自系統PTE區域,因為nt!_MI_SYSTEM_PTE_TYPE結構體的VaType成員被設置為9,這是一個與MiVaSystemPtes對應的枚舉值。這意味著,在這種情況下,分配的內存將來自系統PTE的內存區域。

1.png

我們可以看到:在調用發生後,返回值是一個內核模式的地址,位於系統PTE區域的同一地址空間內,並且是由BasePte成員定義的。

1.png

此時,OS基本上已經以未填充的PTE結構體的形式從系統PTE區域分配了內存,該區域通常用於映射內存的多個視圖。下一步將是正確配置該PTE,並將其分配給一個內存地址。

之後,將繼續調用nt!MiMakeProtectionPfnCompatible。如前所述,該函數的第二個參數將是來自PFN數據庫的PFN記錄的虛擬地址,該記錄與應用於“靜態”KUSER_SHARED_DATA的PTE相關聯。

傳遞給nt!MiMakeProtectionPfnCompatible的第一個參數是常數4。這個價值從何而來?看一下ReactOS,我們可以看到兩個常數,它們用於描述PTE強制執行的內存權限。

1.png

根據ReactOS的說法,還有一個名為MI_MAKE_HARDWARE_PTE_KERNEL的函數,也利用了這些常數;其原型和定義可以在下文中看到。

1.png

該函數提供了nt!MiMakeProtectionPfnCompatible和nt!MiMakeValidPte(稍後將看到的函數)所公開的功能的組合。而值4或MM_READWRITE實際上是名為MmProtectTopTemask的數組的索引。該數組負責將請求的頁面權限(4,或MM_READWRITE)轉換為與PTE兼容的掩碼。

1.png

我們可以看到,前五個元素為:{0,PTE_READONLY,PTE_EXECUTE,PTE_EXECUTE_READ,PTE_READWRITE}。從這裡我們可以確認,以4作為下標訪問這個數組,就能訪問PTE_READWRITE的PTE掩碼,這正是nt!MmWriteableSharedUserData所期望的內存權限,因為我們知道:這應該是KUSER_SHARED_DATA的“新映射視圖”,它是可寫的。同時,別忘了:與“靜態”KUSER_SHARED_DATA關聯的PFN記錄的虛擬地址是通過RDX在函數調用中使用的。

1.png

在函數調用之後,返回值是一個“與PTE兼容”的掩碼,它表示一個可讀和可寫的內存頁面。

1.png

到目前為止,我們已經掌握了:

1、當前為空的PTE地址;

2、PTE的“骨架”(例如,可提供可讀/可寫的掩碼)

考慮到這一點,現在讓我們將注意力轉向對nt!MiMakeValidPte的調用。

1.png

nt!MiMakeValidPte實際上提供了前面所說的ReactOS函數MI_MAKE_HARDWARE_PTE_KERNEL的“其餘”功能。並且,nt!MiMakeValiePte需要以下信息:

1、 新創建的空PTE的地址(這個PTE將被應用到nt!MmWriteableUserSharedData的虛擬地址);目前這個地址位於RCX中。

2、 一個PFN;目前位於RDX中(例如,不是來自PFN數據庫的虛擬地址,而是原始的PFN“值”)。

3、 一個“兼容PTE的”掩碼(例如,我們的讀/寫屬性);目前位於R8中。

所有這些信息都可以在下面的屏幕截圖中看到。

就“將同一物理內存映射到不同視圖”而言,這裡最重要的組成部分是RDX中的值,它是KUSER_SHARED_DATA的實際PFN值(原始值,而不是虛擬地址)。讓我們首先回憶一下,PFN乘以一個頁面的大小(0x1000字節,或4KB)後,實際上就是一個物理地址。這是真的,特別是在我們的案例中,因為我們正在處理最細化的內存類型:4KB對齊的內存塊。由於沒有更多的分頁結構需要索引——這是PFN最常見的用途,因此,這就意味著:在這種情況下,PFN將被用來獲取最終的、4KB對齊的內存頁。

我們知道,這其實就是在正在執行的函數(nt!MiProtectSharedUserPage)裡面創建了一個PTE(通過nt!MiReservePtes和nt!MiMakeValidPte)。正如我們所知,這個PTE將被應用於一個虛擬地址,並用於將所述虛擬地址映射到一個物理頁面,本質上是通過與PTE相關的PFN實現的。目前,將用於這種映射的PFN被存儲在RDX中。在較低的水平上,RDX中的這個值乘以一個頁面的大小(4KB),就是虛擬地址被映射到的實際物理頁面。

有趣的是,RDX中的這個值(在第二次調用nt!MI_READ_PTE_LOCK_FREE後保留下來的值),就是與KUSER_SHARED_DATA相關的PFN! 換句話說,我們給這個新創建的PTE分配的虛擬地址(最終應該是nt!MmWriteableUserSharedData)將映射到KUSER_SHARED_DATA結構體所在的物理內存,因此,當nt!MmWriteableUserSharedData的內容被更新時,該物理內存也將被更新。由於“靜態”的KUSER_SHARED_DATA(0xfffff78000000000)也位於相同的物理內存中,它也會隨之更新。實際上,即使只讀的“靜態”KUSER_SHARED_DATA不允許執行寫操作,它仍然會收到nt!MmWriteableUserSharedData的更新,也就是說:它是可讀和可寫的。這是因為這兩個虛擬地址都會映射到同一個物理內存,所以,只要對其中一個執行寫操作,另一個也會隨之發生變化!

既然如此,也就沒有很好的理由讓“正常的”KUSER_SHARED_DATA結構地址(例如0xfffff78000000000)不是只讀的,因為現在有另一個內存地址可以用來代替它。這樣做的好處是,可寫的“版本”或“映射”(即nt!MmWriteableUserSharedData)是隨機的!

現在繼續,我們告訴操作系統:我們需要一個有效的、可讀和可寫的PTE,它由KUSER_SHARED_DATA的PFN(用於所有意圖和目的的物理地址)提供支持,並且將被寫入我們已經從系統PTE區域分配的PTE(因為這個內存用於映射“視圖”)。

在執行該函數後,我們可以看到情況就是這樣的!

1.png

下一個函數調用nt!MiPteInShadowRange實際上只是進行邊界檢查,看看我們的PTE是否位於影子空間中。回想一下前面的內容,對於內核虛擬地址影子(KVAS)的實現來說,分頁結構是獨立的:一組用於用戶模式,一組用於內核模式。通常來說,“影子空間”(也稱為用於用戶模式尋址的結構體)是位於nt!MiPteInShadowRange的檢查範圍內的。不過,由於我們處理的是一個內核模式頁面,因此,它所對應的PTE肯定不在“影子空間”內。就我們的目的而言,這並不是我們真正感興趣的東西。

在這個函數調用之後,將會執行mov qword ptr[rdi],rbx指令。這將使用nt!MiMakeValidPte函數所創建的相應位,來更新我們分配的PTE(它之前是空白的)!這樣,我們就得到了一個有效的PTE,並被保存到位於虛擬地址0xFFFF78000000000處的KUSER_SHARED_DATA所在的同一段物理內存中!

1.png

1.png

此時,我們離目標符號nt!MmWriteableUserSharedData僅有幾條指令,該符號剛才用新的ASLR映射的KUser_Shared_Data視圖進行了更新。然後,就可以將“靜態”KUSER_SHARED_DATA設為只讀(回想一下,在加載時,它還是可讀/寫的!)。

1.png

目前,通過RDI,我們就能得到用於新的、可讀/寫的PTE的地址和KUSER_SHARED_DATA的隨機映射視圖(通過nt!MiReservePtes生成)。上面的截圖顯示,會對RDI執行一些位運算,同時,我們可以看到頁表項的基址也會參與運算。這些都是簡單的編譯器優化,用於將一個給定的PTE轉換為PTE所應用的虛擬地址。

這是一個必要的步驟,回顧一下,到此為止,我們已經成功地從系統PTE區域生成了一個PTE,並將其標記為讀/寫,告訴它使用“靜態”的KUSER_SHARED_DATA作為虛擬內存對應的物理內存,但是我們並沒有將其實際應用於虛擬內存地址,該地址將由這個PTE來描述和映射!我們要應用這個PTE的虛擬地址,將是我們要存儲在nt!MmWriteableUserSharedData中的值!

讓我們再次回顧一下把新的PTE轉換為相應虛擬地址的位運算。

1.png

正如我們所知,RDI寄存器存放的就是目標PTE的地址。同時我們還知道,檢索與給定虛擬地址相關的PTE的步驟如下所示(即通過適當的索引訪問PTE數組):

1、 通過將虛擬地址除以一個頁面的大小(在標準Window系統上為0x1000字節),將虛擬地址轉換成虛擬頁面號(VPN)。

2、 用上述數值乘以PTE的大小(在64位系統上為0x8字節)。

3、 把這個值加到頁表條目數組的基址上。

這相當於以PteBaseArray[VPN]方式來訪問PTE數組。由於我們知道如何從虛擬地址轉換為PTE,因此,只要將這些步驟倒過來,就能檢索與給定PTE相關的虛擬地址。

知道PTE後,“反轉”過程如下所示:

1、 將RDI中的PTE(目標PTE)減去PTE數組的基址,以提取PTE數組的索引;

2、 用這個值除以PTE的大小(0x8字節)來獲取虛擬頁面號(VPN);

3、 用這個值乘以一個頁面的大小(0x1000)來檢索虛擬地址。

我們還知道編譯器會生成一條sar rdi,10H指令,對上述步驟生成的值進行算術右移,注意,這個過程其符號並不會發生變化。如果在WinDbg中復現這個過程,我們可以看到,最終值(0x0000A580A4002000)將轉換為地址0xFFFFA580A4002000。

1.png

將計算得到的值與內核生成的值進行比較,我們可以看到,它就是對應於PTE的虛擬地址,該地址將映射到KUSER_SHARED_DATA所在的物理內存,並且兩個地址最多匹配到0xffffa580a4002000!我們可以斷定,這些位運算屬於將PTE轉換為虛擬地址的宏的一部分,這是編譯器優化過的代碼!

1.png

1.png

該功能在ReactOS中以名為mi_write_valid_pte的函數形式提供。正如我們所看到的,它本質上不僅將PTE內容寫入PTE地址(在本例中是通過nt!MiReservePtes從系統PTE區域分配內存),而且還通過函數miptetoaddress獲取與PTE相關聯的虛擬地址。

1.png

太棒了!但是,我們還需要做最後一件事,那就是將“靜態”KUSER_SHARED_DATA的地址轉換為只讀的。我們已經看到,當前正在排隊等待調用nt!MiMakeProtectionPfnCompatible函數。在保存內存權限常量的RCX中,我們可以看到其值為1,或者MM_READONLY的值——還記得之前為KUSER_SHARED_DATA的讀/寫映射創建的兼容PTE的掩碼嗎?換句話說,該頁面所擁有的唯一內存“權限”,就是讀取。

在RDX中,存放的是我們對PFN數組的索引;通過將'靜態'KUSER_SHARED_DATA的PTE的虛擬地址(位於0xffffb7fbc000000的PTE)與位於PFN結構MMPFN中的PTE進行比較,我們可以確定:我們已經得到了與'靜態'KUSER_SHARED_DATA相關聯的PFN,從而得到了一個與PTE兼容的值。

1.png

1.png

與上次一樣,現在只是有了一個只讀頁面,我們還需調用nt!MiMakeValidPte,通過其PTE的虛擬地址(0xFFFFB7C000000000)為“靜態”KUSER_SHARED_DATA分配只讀權限。

1.png

調用成功後,會生成一個PTE,以用於只讀頁面。

1.png

“靜態”KUSER_SHARED_DATA結構體也是通過前面提到的相同方法(ReactOS中提供的方法稱為MI_WRITE_VALID_PTE)進行更新的。

1.png

就我們的目的而言,對於nt!MiProtectSharedUserPage所做的各種事情,我們感興趣的就是這些!我們現在有兩個虛擬地址都映射到KUSER_SHARED_DATA所在的物理內存(一個地址是只讀的,對應於0xfffff78000000000處的'靜態'KUSER_SHARED_DATA結構體,另一個則對應於新的nt!MmWriteableUserSharedData版本,它是隨機化的,並且是可讀/寫的)!

例如,我們現在可以在IDA中看到,KUSER_SHARED_DATA的更新過程,是通過隨機化和可寫的新符號來完成的。下圖取自nt!KiUpdateTime,在這裡我們可以看到KUSER_SHARED_DATA的幾個偏移量被更新了(即變為0x328和0x320)。同樣,在同一張圖中,我們還可以看到,當讀取來自KUSER_SHARED_DATA的成員時,Windows將使用舊的“靜態”硬編碼地址(在本例中,它們是0xfffff78000000008和0xfffff78000000320)。

1.png

小結很明顯,濫用這個代碼洞的原語已不可用,之前被攻擊者利用的靜態結構體現在已經得到了安全加固。然而,對於如今的漏洞利用過程來說,要想實現代碼執行,必須首先設法繞過kASLR機制——儘管這不是非常困難,但是,如果攻擊者無法繞過kASLR,就無法將代碼寫入內存。不言而喻,如果攻擊者能夠在內核加載過程中通過競態條件或其他原語儘早將代碼寫入內存,比如將代碼寫入靜態的0xfffff78000000000+0x800處的KUSER_SHARED_DATA代碼洞中,就能繞過這個障礙,因為我們知道:當內核第一次被映射到內存時,這個結構體仍然是可讀和可寫的。然而,當內核加載完成後,這個區域將變成只讀的。但是,儘管如此,這仍然是可能的,因為初始化發生在內核加載過程中。實際上,有一些已公開的exploit就是利用了這個原語,例如chompie1337的SMBGhost概念驗證就是如此,所以,作為防禦方,不僅需要提高攻擊者的門檻,還需要了解公開exploit的最新動向。雖然本文介紹的內容是一個相當小眾的變動/緩解措施,但我認為它非常有趣,至少在此過程中學到了很多關於系統PTE區域和內存視圖的知識。

如果您有任何意見、疑問、更正或建議,請隨時聯繫我。

最後,祝大家閱讀愉快!

簡介不久前,我看到了一條有趣的推文,其中談到了Windows 11的內部預覽版本中KUSER_SHARED_DATA即將發生的一些變化。

1.png

這引起了我的極大興趣,因為KUSER_SHARED_DATA是一個位於靜態虛擬內存空間的結構體,在傳統的Windows內核中,它位於0xfffff78000000000處。從漏洞利用的角度來看,由於其靜態特性,攻擊者經常通過它來攻擊系統內核,特別是在遠程入侵內核的時候。雖然KUSER_SHARED_DATA結構體既沒有包含指向ntoskrnl.exe的指針,也不可執行,但有一段內存與KUSER_SHARED_DATA結構體位於同一內存頁內,並且該頁中沒有包含任何數據,因此,它可用作具有靜態地址的代碼洞。

撰寫本文時,在最新版本的windows 11 內部預覽版中,KUSER_SHARED_DATA結構體的長度為0x738字節。

1.png

在Windows上,一個給定的內存“頁面”的長度通常為0x1000字節,即4KB。由於KUSER_SHARED_DATA結構體的長度為0x738字節,所以,內存頁中仍有0x8C8字節的內存空間可供攻擊者濫用。因此,這些未使用的字節仍然具有與KUSER_SHARED_DATA結構體其他部分相同的內存權限,即RW,或讀/寫權限。這意味著: “KUSER_SHARED_DATA代碼洞”不僅是一個可讀可寫的代碼洞,而且,還具有靜態地址。實際上,Morten Schenk在BlackHat 2017的演講中早就講過這種技術,我之前也寫過一篇文章,就濫用這種結構體來執行代碼的漏洞進行了簡單介紹。

如果這個代碼洞得到了適當的處理,攻擊者就需要在內存中找到另一個位置來存放其shellcode。另外,具有讀/寫原語的攻擊者可以破壞對應於KUSER_SHARED_DATA的頁表項(PTE),從而使內存頁變為可寫的。然而,為了實現這一點,攻擊者需要繞過kASLR並將一個原語寫入內存——這意味著:攻擊者基本上已經完全控制了系統。緩解這一代碼漏洞的方法,就是迫使攻擊者首先得繞過kASLR,然後,才能將惡意代碼寫入內存,從而提高漏洞利用的門檻。如果攻擊者無法直接寫入靜態地址,則需要定位其他內存區域。因此,我們可以將其歸類為一種更小、更專用的緩解措施。無論如何,我仍然覺得這是一個有趣的研究課題。

最後,在開始之前,本文探討的內容都是在ntoskrnl.exe的上下文中進行的;當啟用基於虛擬化的安全特性(VBS)時,這些內容並不適用於VTL1級別安全內核。正如Saar Amar所指出的,這種結構體的地址,在VTL1中實際上是隨機化的。

0xfffff78000000000現在變為只讀的了對於KUSER_SHARED_DATA可能的變化,我的第一個想法是內存地址最終(不知何故)將被完全隨機化。為了驗證這一點,我將KUSER_SHARED_DATA結構體的靜態地址傳遞給了WinDbg中的dt命令,令我驚訝的是,該結構體在解析後仍然位於0xfffff78000000000處。

1.png

我的下一個想法是,嘗試以0x800為偏移量,對KUSER_SHARED_DATA結構體進行寫入操作,以查看是否發生任何意外行為。執行該操作後,通過檢查PTE,我們發現KUSER_SHARED_DATA現在變成只讀的了。

下面提供的地址0xfffffe7bc0000000是與虛擬地址0xfffff78000000000或KUSER_SHARED_DATA結構體關聯的PTE的虛擬地址。在您的系統上,可以使用Windbg的!pte0xfffff78000000000命令來查找該地址。為了提高可讀性,這裡省略了這些命令,不過,我們將告訴讀者哪些地址對應於哪些結構體,以及如何在自己的系統上面查找這些地址。

1.png

後來,有次跟同事Yarden Shafir聊天,他告訴我KUSER_SHARED_DATA中有一些東西(例如SystemTime成員)會不斷更新,同時,他還鼓勵我繼續深挖,因為很明顯,KUSER_SHARED_DATA結構體肯定是通過只讀PTE進行寫入/更新的。正如我後來發現的那樣,這也是有意義的,因為與KUSER_SHARED_DATA對應的PTE的Dirty位被設置為0,這意味著該內存頁還沒有被寫入。那麼,這到底是怎麼發生的呢?

帶著這些信息,我開始借助IDA尋找任何有趣的東西。

nt!MmWriteableUserSharedData來救場了!在IDA中搜索了0xFFFF78000000000或“usershared”之類的關鍵詞後,我偶然發現了一個我以前從未見過的符號——nt!mmwriteableusershareddata。在IDA中,這個符號似乎被定義為0xFFFF78000000000。

1.png

然而,在查看實時內核調試會話時,我注意到地址似乎有所不同。不僅如此,在重啟之後,這個地址也發生了變化!

1.png

我們還可以看到,0xFFFF78000000000靜態地址和新符號都指向相同的內存內容。

1.png

然而,是否存在這種情況:兩個單獨的內存頁面指向兩個單獨的結構體,並且其中包含相同的內容?或者它們是以某種方式交織在一起的?在查看了這兩個PTE之後,我確認了這兩個虛擬地址雖然不同,但都使用了相同的頁幀號(PFN)。此外,我們可以通過以下命令找到“靜態”KUSER_SHARED_DATA結構體和新符號nt!MmWriteableSharedUserData的PTE:

!pte0xfffff78000000000

!pte poi(nt!MmWriteableSharedUserData)

如上所述,與“靜態”KUSER_SHARED_DATA結構體相對應的PTE的地址是0xfffffe7bc000000。而地址0xffffcc340c47010正好是與nt!MmWriteableSharedUserData的PTE相對應的虛擬地址。

1.png

PFN乘以頁的大小(在Windows上通常為0x1000)將得到相應虛擬地址的物理地址(就PTE而言,它用於獲取4KB對齊頁的“最終”分頁結構)。由於這兩個虛擬地址都包含相同的PFN,這意味著當將PFN轉換為物理地址(本例中為0xfc1000)時,兩個虛擬地址將映射到相同的物理頁面! 我們可以通過查看映射到每個虛擬地址的物理地址的內容以及虛擬地址本身來確認這一點。

1.png

我們這裡有兩個虛擬地址,並且具有不同的內存權限(一個是只讀的,另一個是讀/寫的),它們由一個物理頁面提供支持。換句話說,有兩個虛擬地址具有相同物理內存的不同視圖。這怎麼可能?

內存段圍繞KUSER_SHARED_DATA實現的變動,這裡的“要點”是內存段的概念。這意味著一段內存實際上可以由兩個進程共享(內核也是如此,就像我們的例子一樣)。其工作方式是,相同的物理內存可以映射到一系列虛擬地址。

在本例中,KUSER_SHARED_DATA與nt!MmWriteableUserSharedData(一個虛擬地址)的新隨機讀/寫視圖,由與“靜態”KUSER_SHARED_DATA(另一個虛擬地址)共享同一段物理內存。這意味著,現在這個結構體具有兩個“視圖”,具體如下所示:

1.png

這意味著:只要更新其中一個虛擬地址(例如nt!MmWriteableSharedUserData)的內容,將同時更新另一個虛擬地址(0xfffff78000000000)的內容。這是因為對其中一個虛擬地址處內容的改變將更新物理內存的內容。由於這段物理內存的內容供兩個虛擬地址共享,所以,兩個虛擬地址的內容都將收到更新。這為Windows提供了一種方法:在保持舊的KUSER_SHARED_DATA地址的同時,也允許一個新的映射視圖是隨機的,以“緩解”傳統上在KUSER_SHARED_DATA結構體中發現的靜態讀寫代碼洞。0xfffff78000000000的“舊”地址現在可以被標記為只讀,因為這個內存有一個新的視圖可以用來代替它,這個視圖是隨機的!接下來,我們開始介紹更複雜、更低層次的實現細節。

nt!MiProtectSharedUserPage在繼續分析之前,請允許我介紹兩個術語。當我提到內存地址0xFFFF78000000000(KUSER_SHARED_DATA的靜態映射)時,我將使用術語“static”KUSER_SHARED_DATA。當我提及新的“隨機化映射”時,我將使用符號名nt!MmWriteableSharedUserData。這樣的話,每次都能指出我所談論的'版本'。

在WinDbg中進行了一些動態分析後,我終於搞明白了KUSER_SHARED_DATA的更新到底是如何實現的。為此,我首先在正在加載的ntoskrnl.exe上設置一個斷點。在現有的內核調試會話中,可以使用以下命令來實現這一點:

sxe ld nt

.reboot

在斷點被命中後,我們實際上可以看到新發現的符號nt!MmWriteableUserSharedData指向了“靜態”的KUSER_SHARED_DATA地址。

1.png

這顯然表明,這個符號在加載過程中會進一步更新。

在通過IDA逆向分析的過程中,我注意到在函數nt!MiProtectSharedUserPage中,對nt!MmWriteableSharedUserData有一個交叉引用,這引起了我們的極大興趣。

1.png

當執行仍然處於暫停狀態時,由於ntoskrnl.exe觸發了斷點,我趁機在上述函數nt!MiProtectSharedUserPage上設置了另一個斷點,並發現,在到達新的斷點後,nt!MmWriteableSharedUserData符號仍然指向舊的0xfff78000000000地址。

1.png

更有趣的是,“靜態的”KUSER_SHARED_DATA'在加載過程中的這一時刻仍然是靜態的,可讀的,可寫的! 下面的PTE地址0xffffb7fbc0000000是與虛擬地址0xfff78000000000相關的PTE的虛擬地址。由於我們重新啟動系統,導致ntoskrnl.exe的加載中斷,PTE地址也發生了變化。如前所述,這個地址可以通過命令!pte0xfffff78000000000找到,並且不同的系統,這個地址可能會有所差異:

1.png

因為我們知道0xfffff78000000000,這個“靜態”的KUSER_SHARED_DATA結構體的地址,在某一時刻會變成只讀的,這說明這個函數可能負責改變這個地址的權限,並且動態地填充nt!MmWriteableSharedUserData,特別是基於命名約定。

深入研究nt!MiProtectSharedUserPage的反彙編代碼,我們可以看到nt!MmWriteableSharedUserData這個符號在這個指令執行時被更新為RDI的值。但是這個值是從哪裡來的呢?

1.png

讓我們來看看這個函數的開頭部分。首先引起我們注意的就是內核模式地址和對nt!MI_READ_PTE_LOCK_FREE和nt!Feature_KernelSharedUserDataAaslr__private_IsEnabled的調用(這對我們的目的來說,興趣不大)。

1.png

上圖中內核模式地址0xfffffb7000000000,在WinDbg的反彙編窗口中用紅框標出,實際上是頁表項的基址(例如PTE數組的地址)。第二個值,即常量0x7bc00000000,是用來索引這個PTE數組的值,以獲取與“靜態”的KUSER_SHARED_DATA相關的PTE。這個值(PTE數組的索引)可以通過以下公式得到:

1、將目標虛擬地址(本例中為0xfff78000000000)轉換成虛擬頁號(VPN),方法是用地址除以一個頁面的大小(本例中為0x1000)。

2、將VPN乘以一個PTE的大小(64位系統=8字節)

我們可以用上述公式來處理虛擬地址0xfffff78000000000,得到的值就是PTE數組相應的索引,從而獲得與“靜態”的KUSER_SHARED_DATA結構體相關的PTE。這可以在上面的WinDbg的命令窗口中看到。

這意味著與“靜態”的KUSER_SHARED_DATA結構體相關的PTE將被傳入nt!MI_READ_PTE_LOCK_FREE。上述PTE的地址為0xffffb7fbc0000000。

簡單來說,nt!MI_READ_PTE_LOCK_FREE將解除對PTE內容的引用,並將其返回,同時,還會對作用域內的頁表項進行檢查,看看它們是否位於PML4E數組的已知地址空間內,其中包含用於PML4分頁結構的PML4頁表條目數組。回顧一下,PML4結構是基本分頁結構。所以,換句話說,這確保了所提供的頁表項駐留在分頁結構的某個地方。這可以在下面看到。

1.png

然而,稍有細微差別的是,該函數實際上是在檢查頁表項是否位於“用戶模式分頁結構”中,該結構又稱為“影子空間”。回想一下,在KVA Shadow的實現(即Microsoft的內核頁表隔離(KPTI)實現)中,現在有兩套分頁結構:一套用於內核模式執行,另一套用於用戶模式。這種緩解措施被用於防禦Meltdown漏洞。但是,這個檢查很容易被“繞過”,因為PTE顯然被映射到了內核模式的地址,所以,肯定不是通過“用戶模式分頁結構”來表示的。

如果PTE不在“影子空間”中,則nt!MI_READ_PTE_LOCK_FREE將返回PTE解引用的內容(例如,PTE的各個“比特”)。如果PTE確實位於“影子空間”中,在返回內容之前,還將對PTE進行一些檢查,以確定KVAS是否被啟用。從漏洞利用的角度來看,這對我們關注的整體變化不是太重要,但它仍然是整個“過程”的一部分。

此外,對我們來說nt!Feature_KernelSharedUserDataAslr__private_IsEnabled並不是很有用——利用它,我們只能通過命名規則了解是否走在正確的道路上。這個函數似乎主要是為了收集關於這個功能的指標和遙測數據。

1.png

在第一次調用nt!MI_READ_PTE_LOCK_FREE後,“靜態”的KUSER_SHARED_DATA結構體的PTE的內容將被複製到一個堆棧地址:RSP,其偏移量為0x20。類似的,這個堆棧地址也用於對另一個函數(即nt!MI_READ_PTE_LOCK_FREE)的調用。再說一次,這對我們來說並不是特別重要,但它卻是這個過程的一部分。

1.png

然而,更有趣的是,nt!MI_READ_PTE_LOCK_FREE解除了對PTE內容的引用,並通過RAX返回它們。由於定義內存的屬性/權限的“靜態”的KUSER_SHARED_DATA結構體的PTE“比特”位於RAX中,所以,需要對其進行相應的位運算,以便從“靜態”的KUSER_SHARED_DATA的PTE中提取頁幀號(PFN)。這個值在PTE中的偏移量是0xf52e,其值是0x800

000000000f52e863。

1.png

1.png

這個PFN將在以後調用nt!MiMakeValidPte時用到。現在,讓我們繼續前進。

現在,我們可以將注意力轉向對nt!MiMakeValidPte的調用。

1.png

請允許我簡單介紹一下PFN記錄:PFN的“值”在技術上只是一個抽象的值,當它乘以0x1000(一個頁面的大小),就會得到一個物理內存地址。在內存分頁過程中,它通常是下一個分頁結構的地址,或者,如果被用於“最後一個”分頁表,即PT(page table)時,可以用來計算最後一個4KB對齊的物理內存頁。

除此之外,PFN記錄還被存儲在一個虛擬地址數組中。這個數組被稱為PFN數據庫。這樣做的原因是,內存管理器可以通過線性(虛擬)地址訪問頁表項,這就提高了性能,因為MMU不需要不斷遍歷所有的分頁結構來獲取PFN、頁表項等。實際上,這就為記錄的引用提供了一種簡單的方法,即通過一個索引訪問數組。這適用於所有的“數組”,包括PTE數組。同時,像nt!MiGetPteAddress這樣的函數,也能夠通過索引訪問相應的頁表數組,比如PTE數組(對應於nt!MiGetPteAddress),PDE數組(PDPT條目,通過nt!MiGetPdeAddress進行訪問),等等。

小結在本文中,我們為讀者詳細介紹了在Windows 11內部預覽版中,KUSER_SHARED_DATA結構體發生了哪些新變化。由於篇幅較長,我們分為上下兩篇進行發布。更多精彩內容,敬請期待!

(未完待續!)

我們會在本文中詳細介紹四個在去年被修復的舊漏洞:

CVE-2022-38108;

CVE-2022-36957;

CVE-2022-36958;

CVE-2022-36964;

CVE-2022-38108這個漏洞已經在這篇博客文章中提到了。

簡單來說,幾個SolarWinds服務通過RabbitMQ實例相互通信,該實例可通過端口5671/TCP訪問。雖然訪問它需要憑據,但是高權限用戶可以通過SolarWinds Orion平台提取這些憑據,攻擊者利用CVE-2023-33225,它允許低權限用戶提取這些憑證。

該漏洞針對的是SolarWinds信息服務。為了向信息服務發送AMQP消息,必須將消息的Routing-Key設置為SwisPubSub,RoutingKey就是路由規則,消息對應的隊列。

1.png

AMQP消息中的Routing-Key

現在,讓我們來驗證SolarWinds是如何處理這些消息的,可以從EasyNetQ.Consumer.HandleBasicDeliver方法開始:

在[1]處,代碼檢索AMQP消息的屬性,這些屬性由發送消息的攻擊者控制。

在[2]處,它創建了一個執行上下文,其中包含AMQP消息屬性和消息正文。

在[3]處,它執行一個任務來使用消息。

這就需要Consume方法。

在[1]處,EasyNetQ.DefaultMessageSerializationStrategy.DeserializeMessage被調用,它接受輸入的消息屬性和消息正文。調用名為DeSerialize的方法並返回type類型的輸出,作為輸入,它從消息中接受Type屬性。

我們可以通過AMQP消息屬性控制messageType類型!

在[2]處,它調用BytesToMessage,同時接受攻擊者控制的類型和輸入的消息正文。

在[1]處,消息正文被解碼為UTF-8字符串。它應該包含JSON格式的數據。在[2]處,執行反序列化。我們控制目標類型和序列化負載。在[3]處,可以看到TypeNameHandling反序列化設置被設置為Auto。

現在,我們需要遠超需要實現的遠程代碼。要做到這一點,我們必鬚髮送一個AMQP消息,其中Type屬性設置為危險類型。

2.png

通過AMQP屬性控制反序列化類型

在消息正文中,我們必須傳播相應的JSON.NETgadget(有潛在可以被利用的代碼片段)。本文使用了ysosserial.net中的一個簡單的WindowsPrincipalgadget,它是內部存儲的BinaryFormattergadget的橋樑,JSON反序列化後,RCE將通過底層BinaryFormatter反序列化來實現。

這樣,就可以通過遠程執行惡意代碼來控制目標系統的漏洞!

CVE-2022-36957在之前的漏洞中,我們能夠通過AMQP屬性完全控制目標反序列化類型。當發現這樣的漏洞時,我們需要知道合法消息是什麼樣子?我們經常檢查在典型產品操作過程中反序列化的類型。

我們很快意識到SolarWinds只發送一種類型的信息,即SolarWinds.MessageBus.Models.Indication。

現在我們分析一下這種類型:在[1]和[2]處,我們可以看到兩個類型為SolarWinds.MessageBus.Models.PropertyBag的公共成員。

在[1]處,您可以看到所討論的類的定義,SolarWinds.MessageBus.Models.PropertyBag。

在[2]處,為該類註冊了一個自定義轉換器SolarWinds.MessageBus.Models.PropertyBagJsonConverter。它實現了ReadJson方法,該方法將在反序列化過程中調用。

在[1]處,代碼遍歷JSON屬性;在[2]處,檢索JSON值並將其轉換為jobobject類型;在[3]處,根據存儲在t鍵中的值檢索Type;在[4]處,存儲在v鍵中的對像被反序列化,此時我們再次控制目標反序列化類型。

你可以看到,我們再次控制了反序列化類型,該類型通過JSON鍵傳播,序列化的有效負載通過v鍵傳播。

現在,我們可以獲取任何屬性,例如:IndicationId。然後,我們需要:

1.將t鍵的值設置為惡意類型的名稱。

2.在v鍵的值中放入惡意序列化的有效負載。

由於JSON反序列化設置被設置為TypeNameHandling.Auto。現在,讓我們看一下上面描述的第一個漏洞,CVE-2022-38108,通過將目標反序列化類型硬編碼到SolarWinds.MessageBus.Models.Indication來修復。畢竟,這是唯一需要反序列化的合法類型。

這個修正是不夠的,因為SolarWinds.MessageBus.Models.Indication可以用來傳播一個攻擊者控制類型的內部對象。通過控制類型,我們就可以通過遠程執行惡意代碼來控制目標系統的漏洞!

CVE-2022-36958SolarWinds定義了一些稱為“SWIS動詞”的內部方法/操作。這些動詞可以是:

1.通過API直接調用。

2.通過Orion平台Web UI間接調用(Orion平台內部調用動詞)。

關於SWIS動詞,我們需要了解以下2點:

1.它們是使用XML結構中的有效負載調用的。

2.它們接受預定義類型的參數。

例如,Orion.AgentManagement.Agent.Deploy動詞接受12個參數。下面的屏幕截圖顯示了這些參數及其相應的類型。

33.png

Orion.AgentManagement.Agent.Deploy的參數

參數的處理是通過方法SolarWinds.InformationService.Verb. VerbExecutorContext.UnpackageParameters(XmlElement[], Stream)執行的。

在[1]處,檢索給定動詞參數的Type;在[2]處,使用檢索到的參數類型初始化DataContractSerializer;在[3]和[4]處,參數被反序列化。

這是正在處理一個DataContractSerializer。不過,這樣我們無法控制反序列化類型。

目前已找到了一些可濫用的PropertyBag類,通過進一步分析,有多個SWIS動詞接受名為SolarWinds.InformationService.Addons.PropertyBag類型的參數。我們可以提供任意XML,將其反序列化為這種類型的對象。

在[1]處,定義了ReadXml方法,它將在反序列化期間被調用;在[2]處,代碼遍歷所提供的項;在[3]處,檢索到關鍵元素。如果存在,則繼續執行代碼;在[4]處,檢索type元素的值。人們可以放心地猜測它接下來如何執行;在[5]處,檢索到value元素;在[6]處,調用Deserialize方法,輸入值和類型標記中包含的數據;在[7]處,序列化的有效負載和類型名稱被傳播給SolarWinds.InformationService.Serialization.SerializationHelper.Deserialize方法。

同樣,類型和序列化的有效負載都由攻擊者控制。讓我們檢查一下這個反序列化方法。在[1]處,代碼檢查所提供的類型是否被緩存。如果不是,則從[2]處的字符串中檢索類型。在[3]處,調用靜態的DeserializeFromStrippedXml。靜態的DeserializeFromStrippedXml方法通過調用SerializationHelper.serializerCache.GetSerializer(type)來檢索序列化器對象。然後,它在檢索到的序列化器對像上調用(非靜態)DeserializeFromStrippedXml(string)方法。

如何檢索序列化器在[1]處,代碼嘗試從緩存中檢索序列化器。在緩存缺失的情況下,它通過調用GetSerializerInternal([2])來檢索序列化器,因此我們繼續使用GetSerializerInternal進行調查。

在[3]處,根據攻擊者控制的類型檢索XmlTypeMapping。它沒有執行任何安全措施。它僅用於檢索關於給定類型的一些基本信息。

在[4]處,初始化XmlStrippedSerializer對象。為構造函數提供了四個參數:

1.一個新的XmlSerializer實例,其中序列化器的類型由攻擊者控制。

2.目標類型的XsdElementName,從XmlTypeMapping獲得。

3.該類型的Namespace,也是從XmlTypeMapping獲得的。

4.類型本身。

到目前為止,我們可以發現:

1.我們正在切換反序列化器。使用DataContractSerializer對整個SWIS動詞有效負載和參數進行反序列化。但是,PropertyBag對象最終將使用XmlSerializer進行反序列化。

2.我們完全控制提供給XmlSerializer構造函數的類型,這是利用它的關鍵條件。

似乎我們有它,通過反序列化中的類型控制的另一個RCE。由於XmlSerializer可能會通過ObjectDataProvider被濫用,我們可以將目標反序列化類型設置為以下類型:

3.png

但是,在成功利用漏洞之前,還有必要分析XmlStrippedSerializer.DeserializeFromStrippedXml(String) 。

可以發現,在[1]處,正在創建一個新的XML字符串。它的結構如下:

4.png

綜上所述:

1.攻擊者的XML被一個從傳播的類型派生的標記封裝,請參閱GetSerializerInternal方法。

2.檢索到的Namespace被插入到xmlns屬性中。攻擊者控制最終XML的主要片段並控制類型。然而,由於自定義的XML封裝,ysosserial.netgadget將無法開箱即用。

生成的gadget如下所示:

第一個標記等於ExpandedWrapperOfLosFormatterObjectDataProvider。此標記將由DeserializeFromStripedXml方法自動生成,因此我們需要將其從生成的有效負載中刪除!當我們這樣做時,下面的XML將被傳播給XmlSerializer.Deserialize方法。

當你比較原始的ysosserial.net gadget和我們當前的gadget時,可以發現一個很大的區別:

1.原始gadget在根標記中定義了兩個名稱空間:xsi和xsd。

2.當前gadget僅包含一個空xmlns屬性。

ObjectInstance標記依賴於xsi命名空間。因此,反序列化將失敗。

幸運的是,不必在根標籤(roottag)中專門定義命名空間,RootTag是用於標記React Native 原生根視圖層的不透明標識符(opaque identifier)。因此,我們可以通過在ProjectedProperty0標記中定義這兩個名稱空間來修復gadget。

通過這種方式,我們得到了第三個RCE,這樣,我們就完全控制了目標反序列化類型。

CVE-2022-36964技術層面,該漏洞與CVE-2022-36958相同,但是,它存在於共享ReadXml方法的相同實現的不同類中。在本例中,易受攻擊的類是SolarWinds.InformationService.Contract2.PropertyBag。

TestAlertingAction SWIS動詞接受此類型的參數,因此該漏洞可通過API加以利用。

總結我們在本文介紹了SolarWinds中的四個不同的反序列化漏洞,攻擊者可以使用這些漏洞控制反序列化對象的類型,以及介紹瞭如何通過使用自定義反序列化gadget繞過它們。目前,SolarWinds也對這些繞過進行了修復。

ee02-article-dom_invader_pp_page_article_image.png

當DOM XSS 隱藏在數千行代碼中時,查找DOM XSS 可能會很棘手。我們最近開發了DOM Invader 來幫助解決這個問題,使用組合的動態+手動方法來發現漏洞,並迅速發現了一個影響PayPal 的有趣的Polyglot DOM XSS。在這篇文章中,我們將展示如何使用意外腳本gadget繞過基於允許列表的CSP。大多數現代網站都使用多個JavaScript庫,並且有很多行複雜的壓縮代碼,這使得對DOM XSS的測試變得非常令人頭痛,PortSwigger安全研究部門專門開發了DOM Invader,使對DOM XSS的測試更加容易。 DOM Invader將為你提供一個方便的樹狀視圖,以此來顯示目標的源和匯(不理解別著急,這是BurpSuite的一個定義),這極大地簡化了發現DOM XSS的過程。

首先,我們使用Burp 的嵌入式瀏覽器來導航站點並註入canary以查看每個頁面上使用了哪些源和接收器。當我們遇到一些有趣的接收器時,我們會使用canary一起發送諸如'' 之類的字符探測器,並檢查接收器以查看它們是否被允許。我們沒花多少時間就找到了一個頁面,它以一種不安全的方式反映了我們的探測器。通常這很困難,因為反射是不可見的,但使用DOM Invader就很容易了。

1.png

正如你在上面的截圖中看到的,我們的canary被反映在一個id 屬性中。如果我們發送一個雙引號,則可以看到值如何到達接收器。但是當發送雙引號時,屏幕變為空白。但是,如果我們轉義雙引號,則站點不會中斷,我們可以看到它到達接收器:

2.png

在HTML 中,反斜杠對雙引號沒有影響——所以我們似乎有一個XSS 漏洞。我們需要通過注入其他字符來確認這一點,這將導致JavaScript 執行。在對這個漏洞進行多次探測後,我們注意到注入的值必須是一個有效的CSS 選擇器。所以我們想出了以下向量:

3.png

由於CSP的原因,這一功能最初並沒有發揮作用,但當我們在Burp中禁用這一功能時,我們收到了警報。然後,我們在HackerOne上向PayPal報告了這一情況,以及禁用CSP的說明。讓我們驚訝的是,我們得到了HackerOne 人員的回應:經過審查,您所描述的行為似乎沒有任何安全風險或安全影響。

顯然我們不同意這個評估,於是開始尋找繞過PayPal 政策的方法。

繞過PayPal上的CSP首先,我們研究了CSP,並註意到一些薄弱的部分。在script-src指令中,他們允許某些域,例如*.paypalobjects.com 和*.paypal.com。它們還包括“unsafe-eval”指令,該指令將允許使用eval、Function 構造函數和其他JavaScript 執行接收器:

4.png

查看策略,允許列表和“unsafe-eval”可能是繞過CSP的最佳目標。因此,我們在Burp Suite範圍中添加了這些域。你可以在作用域中使用正則表達式,這非常方便。我們的範圍是這樣的:

5.png

Burp允許你在範圍中選擇特定的協議,由於策略具有“block-all-mixed-content”指令,我們只選擇了HTTPS 協議。

在學習了CSP之後,我們打開了Burp中的嵌入式瀏覽器,開始手動瀏覽網站,這是為了挑選那些擁有大量JavaScript資源的目標。當我們收集了大量的代理歷史記錄後,就可以使用Burp 出色的搜索功能來查找較舊的JavaScript 庫。 Burp允許你只搜索範圍項,所以我們選中了那個框,這允許我們找到繞過CSP的資產。

我們從搜索AngularJS開始,因為用它很容易創建CSP繞過。有對Angular 的引用,但沒有對AngularJS 的引用但我們嘗試的JavaScript文件似乎並沒有加載Angular,也沒有引發異常。所以我們轉向Bootstrap,在請求頭和響應體中進行搜索。出現了幾個Bootstrap 實例,我們發現了一個舊版本(3.4.1)。

接下來,我們研究了Bootstrap gadget。 GitHub 上存在一些XSS 問題,但這些影響了3.4.0 版本。我們查看了Bootstrap代碼一段時間,尋找jQuery的使用情況,但沒有找到合適的gadget。

我們沒有在數據庫中找gadget,而是想到了PayPal gadget。如果PayPal 有一些我們可以利用的不安全JavaScript ,那豈不是更好。這一次,我們沒有搜索特定的庫,而是搜索託管庫的路徑的一部分(例如“/c979c6f780cc5b37d2dc068f15894/js/lib/”)。在搜索結果中,我們注意到一個名為youtube.js 的文件,並立即在其中發現了一個明顯的DOM XSS 漏洞:

6.png

這個文件使用的是jQuery,所以我們所需要做的就是包含jQuery和youtube.js,利用這個漏洞,然後我們繞過了CSP。看看YouTube .js文件,我們看到它使用了一個CSS選擇器來找到YouTube播放器元素:

7.png

因此,我們需要注入一個帶有“youtube-player”類的元素和一個包含jQuery XSS向量的data-id屬性。一旦我們有了通用PayPal CSP繞過的基礎,要做的就是把它與原始注入結合起來。首先,我們注入了一個帶有srcdoc 屬性的iframe。這是因為我們想注入一個外部腳本,但因為這是一個基於DOM 的漏洞,腳本將無法執行。但是有了srcdoc,會發生以下情況:

8.png

請注意,我們需要通過轉義雙引號並為選擇器的值部分分配單引號來確保它是一個有效的選擇器。然後再注入指向jQuery 和YouTube gadget的腳本:

9.png

請注意,我們必須對向量進行HTML 編碼,因為我們不希望它以字符關閉srcdoc屬性。出於同樣的原因,我們避免使用空格。然後我們使用YouTube gadget注入腳本,jQuery 會轉換並執行該腳本。我們再次需要對向量進行HTML 編碼,給它正確的類名,並使用data-id 屬性來注入我們的向量。注意,我們使用了一個編碼的單引號來避免屬性中斷。我們必須對雙引號進行HTML編碼,因為srcdoc將解碼HTML,而data-id屬性將在iframe中呈現時進行解碼,因此雙編碼可確保引號在註入YouTube gadget時存在。最後,我們使用單行註釋進行清理,以確保腳本在註入後忽略任何內容,即用雙引號和單引號完成CSS 選擇器。

10.png

可以在此處找到最終的概念證明。

概念證明這是PoC 的截圖:

11.png

可以看到對所有PayPal 的完整CSP 繞過,但它是必要的嗎?正如我們所見,jQuery是CSP的剋星。它使用“unsafe-eval”指令轉換腳本,並且很樂意使用策略執行它們。看看原始的XSS漏洞,它似乎是一個jQuery選擇器。因此,我們可以注入一個腳本,它將被jQuery轉換。所以不需要單獨的CSP 繞過。因此,我們可以將注入簡化為以下內容:

12.png

完整的概念證明請點此。

總結允許列表策略絕對是不安全的,尤其是當你有大量可能被濫用的腳本/庫時。即使用戶輸入通常不需要,也要修復XSS,這有助於防止意外的腳本gadget。

你永遠不應該僅僅依靠CSP 來保護XSS。 雖然這是你防禦的一部分,但它不是唯一可用的障礙。

憑證數據(URL/用戶名/密碼)以明文格式存儲在Chrome的內存中。除了登錄特定Web應用程序時動態輸入的數據外,攻擊者還可以使瀏覽器將存儲在密碼管理器(“登錄數據”文件)中的所有密碼加載到內存中。

Cookie的數據(cookie的值+屬性)以明文格式存儲在Chrome的內存中(當相關應用程序被急活時),這包括敏感的會話cookie。

這些信息可以通過在本地設備上運行的標準(非提升)進程有效地提取,並直接訪問Chrome的內存(使用OpenProcess+ReadProcessMemoryAPI)。

提取的數據可用於劫持用戶的帳戶,即使它們受到MFA機制的保護(使用“會話cookie”數據)。

Gmail、OneDrive和GitHub的示例會話劫持是“POC-ed”。

在MicrosoftEdge瀏覽器中發現了類似的漏洞(據推測,其他基於Chromium引擎的瀏覽器也會出現)。

本文描述了對瀏覽器的直接內存訪問攻擊。還有其他公開的竊取這些敏感數據的方法。

為什麼這是一個重要問題:如果一個人接受“假設違規”範式,那麼基於Chromium的瀏覽器處理敏感憑證數據的方式中的漏洞都應該被視為主要的安全風險。緩解措施應處理所有這些漏洞。

ProcessHacker工具(由WenJiaLiu編寫)在這項研究中被證明非常有用。如果你懷疑某個特定字符串存儲在進程的內存中,那麼查找它的快速方法是:

在ProcessHacker.exe中打開該進程;

選擇“內存”選項;

激活“字符串”子選項;

選擇“過濾器”選項並在“包含.”框架中輸入你要查找的字符串;

這是我查找已知密碼時生成的輸出示例(為了保密,我更改了它):

1.webp.jpg

ProcessHacker.exe在Chrome內存中識別的已知密碼

如果你返回顯示的內存佈局(當你選擇“內存”選項時),你會發現該字符串位於Private類型的內存部分中:

2.webp.jpg

查找已知密碼存儲在Chrome內存中的內存塊

深入查看該內存塊,密碼存儲在Private:Commit類型的內存部分中:

3.webp.jpg

查找已知密碼存儲在Chrome內存中的特定內存部分

根據MSDN,私有內存(MEMORY_BASIC_INFORMATIONType=MEM_PRIVATE)意味著:

4.webp.jpg

MSDN中的MEM_PRIVATE內存屬性定義

人們可能會認為存儲在此類內存頁面中的數據不能被任何其他進程訪問。令人驚訝的是,這些頁面不能成為“共享內存”的一部分,但其他進程讀取其中的數據沒有問題(通過ReadProcessMemoryAPI)。

可以看到,上述ProcessHacker.exe作為標准進程運行,訪問這些數據沒有問題!

如果這些頁面真的是私有的,那麼這裡描述的攻擊向量將是不可能的。我想知道Chromium的創建者是否(在某些時候)認為敏感數據在存儲在私有內存中時是安全的。

當然,在瀏覽器內存中查找已知字符串並不是什麼大問題。尋找未知字符串怎麼樣?我決定只通過查看進程內存來嘗試找到敏感數據(不嘗試分析程序的開源代碼)。

Chromium內存佈局看起來像是被設計成一個“乾草堆(haystack)”,因此很難找到和“理解”存儲的數據(特別是密碼和cookie值等敏感字符串)。我還遇到了各種蜜罐,它們看起來像是故意創建的,用於生成明文密碼的誤報識別。其中的困難包括:

1.相對大量的瀏覽器進程(例如chrome.exe)。

2.每個進程都分配了大量的虛擬內存(有些超過230GB)。

3.每個進程的內存由許多(有時數百個)“脫節”的小型已提交內存部分組成,這些部分由“保留”部分分隔。

4.大內存“組合”部分,包括許多如上所述的不相交的部分,這些部分實際上是“空的”(不是“真正”使用的)。

5.看起來像密碼或cookie值的字符串(實際字符串的子字符串)。

6.將屬於一個邏輯“記錄”的項目(例如URL+用戶名+密碼)分散到遠程存儲位置。

這可能是所有看起來像是隱藏(“混淆”)的嘗試,而只是正常操作的結果。如上所述,我沒有查看代碼,但我認為他們試圖隱藏敏感數據。

從Chrome內存中提取的明文憑證數據類型

事實證明,通過標準的非特權進程可以很容易地從瀏覽器的內存中有效地提取明文憑證數據。實際上,這意味著:

1.它使用了合理數量的計算機資源(CPU能力、內存)。

2.執行在合理的時間內完成。

3.誤報現象較少。

注意:當描述POC程序的部分時,我知道大多數讀者會期望關鍵功能的技術細節和源代碼片段。由於本博文結尾部分解釋的原因,此信息不會被披露。已開發POC程序以提取以下類型的信息:

1、登錄目標Web應用程序時使用的用戶名+密碼該程序等待用戶登錄特定的Web應用程序(例如Gmail、OneDrive、GitHub等),然後分析捕獲的內存快照以識別用於登錄應用程序的用戶名和密碼。

這有點像一個有效的鍵記錄程序可以實現的功能,但重要的區別是,之前存儲的密碼(例如,在瀏覽器的密碼管理器工具中),它完全繞過了最初定義時沒有運行的鍵記錄程序,將被我們的程序發現。

該程序查看登錄之前和之後立即拍攝的快照之間的差異,並查找僅出現在“after”內快照中並且看起來像潛在的用戶名和密碼字符串的新字符串。

注意:這是本研究中開發的最複雜的POC程序,它產生了相當多的誤報結果,因為相當多的新字符串出現在“after”內存快照中。

排除這些假陽性案例是可能的(例如,通過識別出現在登錄過程中的常見“單詞”),並且如果想要努力,可以不斷改進。具有諷刺意味的是,密碼越強,就越容易從“噪音”假陽性案例中分離出來(例如,由小寫和大寫字符、數字和特殊符號組成的10個字符的字符串比只有小寫字符的7個字符的字符串更有可能是密碼)。

2、URL+用戶名+密碼在瀏覽器啟動時自動加載到內存中當瀏覽器啟動時,“登錄數據”文件(Chromium存儲保存的密碼)中的一些條目會自動加載到內存中。雖然並非“登錄數據”中的所有條目都必須加載,但最近使用的條目是必須加載的。

“登錄數據”數據庫中的密碼是DPAPI加密的,但是當它們“分散”到內存中時,它們會以明文格式保存。

與前一種情況(上面的“a”)不同,這里分析一組快照就足夠了,因為加載的憑證數據靜態地保留在內存中。

我們開發了一個有效的POC程序,可以從內存中提取這些數據。可能會生成少量誤報項目。同樣,過濾掉誤報情況的算法可以得到顯著和持續的改進。

3、登錄數據中存儲的所有URL+用戶名+密碼記錄可以使瀏覽器的密碼管理器功能將其所有存儲的記錄加載到內存中。我們開發的POC程序可以提取所有加載的記錄。在這種情況下,敏感數據以易於識別的結構排列。

因此,程序對提取的數據有很高的信心,並且在大多數情況下,幾乎沒有誤報條目。

在這種情況下,所有保存的密碼記錄都加載到了Chrome的內存中。他還幫助我發現和分析了各種Chromium內存佈局。

4.屬於特定Web應用程序的所有cookie(包括會話cookie)

該程序等待用戶登錄到一個特定的應用程序(例如,Gmail, OneDrive, GitHub等)。當應用程序會話處於活動狀態時,程序可以從Chrome的內存中提取屬於該會話的所有cookie。這些被盜的cookie可以上傳到不同設備上的瀏覽器中,並且會話可以被盜(繞過任何MFA機制)。

當竊取的cookie被用於劫持會話時,典型的應用程序(例如Gmail)無法識別連接是從新設備還是從新位置建立的。這是因為完全繞過了登錄過程。根據cookie的內容,應用程序假定這是先前經過身份驗證的會話的延續。

值得注意的是,某些應用程序鼓勵其用戶不要退出應用程序。例如,Gmail的會話cookie的有效期為自首次生成之日起兩年。同樣,MicrosoftOneDrive最近開始向其網絡用戶建議他們無需退出會話。在這些情況下,竊取會話cookie的攻擊者可能會在很長一段時間內與真正的所有者“共享”該帳戶。

誤判極為罕見。

負責任的披露和供應商響應我於2021年7月29日向Google報告了此問題:

10.webp.jpg

谷歌回應

該報告包括Gmail會話劫持的詳細POC,包括從Chrome內存中提取cookie的程序的源代碼。

Chromium.org的回复(WontFix)很快:

11.webp.jpg

Chromium.org以WontFix狀態關閉問題

這種回應並不令人驚訝,因為其他類似“假設違規”漏洞的報告也收到了類似的回應。

14週後,Chromium公開了我的報告:

12.webp.jpg

谷歌向公眾發布問題細節

總的來說,Chromium.org表示他們不會修復與物理本地攻擊相關的問題,因為Chrome(或任何應用程序)沒有辦法防禦一個以你的身份登錄你的設備的惡意用戶。雖然這種說法總體上可能是正確的(特別是如果你假設攻擊者可以獲得管理員權限),但我相信竊取敏感憑證應該不像今天這樣容易。因此,如上所述,我的下一篇文章將提出幾種緩解技術,使攻擊更難執行。

在披露後大約一個月,我的程序未能提取cookie數據。事實證明,一般內存佈局已被修改(在Chrome和Edge中)。大約兩個月後,它再次失敗。這一次,“敏感”數據的位置已經改變(同樣,同時針對Chrome和Edge)。

最初的POC程序是為Chrome版本91.0.4472.164開發的:

13.webp.jpg

原始POC程序的Chrome版本

演示視頻中的POC程序正在訪問Chrome的96.0.4664.45版本:

14.webp.jpg

演示視頻中用於POC程序的Chrome版本

如上所述,自從我們負責任地披露了這個漏洞以來,已經發現了內存佈局以及cookie值在內存中存儲方式的修改。但是,這些修改非常普遍,並沒有使“憑證竊取”行文變得更加困難。

由於供應商未計劃修復該漏洞,因此共享POC或源代碼不會促進問題的解決,而是可能造成傷害或提升相關威脅。因此,我們決定不發布POC。

1683253145740260.jpeg

0x01 前言距離上一次更新JAVA安全的系列文章已經過去一段時間了,在上一篇文章中介紹了反序列化利用鏈基本知識,並闡述了Transform鏈的基本知識。 Transform鏈並不是一條完整的利用鏈,只是CommonsCollections利用鏈中的一部分。當然並不是所有的CC鏈都需要用Transform鏈。

為了更方便的理解CC鏈,我們並不會按照順序來闡述所有的鏈,而是按照鏈的難易程度,由易到難。

0x02CommonsCollections5鏈CommonsCollections5鍊是整個CC鏈中最簡單的一條鏈,通過BadAttributeValueExpException類的readObject方法觸發反序列化的過程,最終調用Transform鏈來達到命令執行的效果。

在ysoserial的環境中調試CommonsCollections5鏈的方式很簡單,如圖2.1所示。1683253223115330.png

圖2.1 使用ysoserial生成反序列化利用鏈

直接調用就會執行彈出計算器的命令,跟踪run方法可以查看代碼執行邏輯,如圖2.2所示。

1683253284109251.png

圖2.2 在ysoserial中的序列化和反序列化過程

在ysoserial的run方法中既有序列化的過程,也有反序列化的過程。所以調用run方法因為反序列化的過程導致會執行對應的惡意代碼,彈出計算器。

在很多情況下需要保存反序列化對像到文件,可以通過在run方法中添加文件保存方法即可,如圖2.3所示。

1683253318921757.png

圖2.3 保存序列化字節碼對像到文件

通過上面的方式可以直接把生成的序列化字節碼對象保存到文件cc.ser,查看文件內容,如圖2.4所示。文件中開頭的字符是aced0005,符合序列化文件的標準特徵。

1683253357214716.png

圖2.4 通過xxd查看序列化文件保存的內容

通過上面的方式可以利用ysoserial生成標準的CommonsCollections5利用鏈對應的payload,下一步會繼續對CommonsCollections5利用鏈的調用過程進行分析。

通過debug的方式可以查看整個CommonsCollections5利用鏈的棧調用過程,如圖2.5所示。

1683253399115293.png

圖2.5 CommonsCollections5利用鏈的棧調用過程

在圖2.5中,紅框2對應的過程階段是屬於Transform鏈的調用過程,在上一篇文章中已經進行詳述。紅框1對應的過程階段是屬於CommonsCollections5特有的調用過程,也是屬於本文的重點部分內容。

反序列化的起始點是javax.management.BadAttributeValueExpException類的readObject方法,如圖2.6所示。

1683253437177607.png

圖2.6 調用BadAttributeValueExpException類的readObject方法

從圖2.6可以看出readObject方法首先獲取字節流類(也就是本類)對應的val字段,然後基於多個判斷,最終下一步操作是val字段對應的toString方法。這裡有一點需要注意的是判斷邏輯中要求System.getSecurityManager()為null,也就是不能開啟SecurityManager模式。

在下一步的調用棧中是調用了org.apache.commons.collections.keyvalue.TiedMapEntry的toString方法,也就是需要把上一步的val字段類型賦值為TiedMapEntry類。在TiedMapEntry類的toString方法中調用了getValue方法,如圖2.7所示。

1683253474461492.png

圖2.7 TiedMapEntry類的toString方法

繼續跟踪getValue方法,如圖2.8所示。

1683253512120378.png

圖2.8 調用map接口的get方法

從圖2.8可以看出,這裡調用了java.util.Map接口的get方法。所有隻要找到一個繼承自java.util.Map接口的類的get方法中存在惡意調用即可。在CommonsCollections5鏈中找到的惡意類是org.apache.commons.collections.map.LazyMap類,如圖2.9所示。

1683253564192404.png

圖2.9 LazyMap類的get方法調用

從圖2.9可以看出LazyMap類的get方法會調用org.apache.commons.collections.Transformer類的transform方法。在上一篇文章的內容中已經講到在反序列化過程中如果可以調用transform方法,那麼就可以通過transform方法來執行系統命令,也就可以達到RCE的效果。

實際上要編寫真正可利用的EXP遠比基於棧調用來分析更加複雜,因為在編寫EXP的過程中,需要考慮每一步棧調用的過程中的邏輯判斷條件,這並不是一件簡單的事情。

一般來說反序列化利用鏈代碼的編寫是倒著來寫的,首先是transform鏈的構造,如果某個類可以調用transformChain的transform方法,則可以執行命令,如圖2.10所示

1683253595107777.png

圖2.10 通過調用Transformer類的transform方法調用執行命令

註釋transform方法調用,繼續倒序編寫EXP。如果某個類可以調用LazyMap類的get方法,則可以執行系統命令,如圖2.11所示。

1683253640115164.png

圖2.11 通過調用LazyMap類的get方法執行命令

註釋LazyMap的get方法調用,繼續倒序編寫EXP。如果某個類可以調用TiedMapEntry類的toString方法,則可以執行系統命令,如圖2.12所示。

1683253676150771.png

圖2.12 通過調用TiedMapEntry類的toString方法執行系統命令

註釋TiedMapEntry的toString方法調用,繼續倒序編寫EXP。找到javax.management. BadAttributeValueExpException類的readObject方法中存在toString的方法調用,模擬反序列化過程,執行命令,如圖2.13所示。

1683253713138888.png

圖2.13 模擬BadAttributeValueExpException類的反序列化過程執行命令

這樣就完整的複現和分析了CommonsCollections5利用鏈,從圖2.13的payload中可以看出CommonsCollections5利用鏈中沒有復雜的邏輯處理,適合新手入門java反序列化漏洞學習。

0x03CommonsCollections7鏈CommonsCollections7鍊是一條和CommonsCollections5鏈很像的利用鏈,最終的結果都是通過LazyMap的get方法調用Transform鏈來執行命令,調用棧如圖3.1所示。

1683253747166447.png

圖3.1CommonsCollections7利用鏈

如圖3.1所示,其中紅框部分和CommonsCollections5鍊是完全一樣的,區別在於CommonsCollections7鍊是通過Hashtable類readObject方法一步步調用AbstractMap類的equals方法來調用的。

由於分析調用鏈的方式基本相同,所以不再對這條鏈進行分析。

0x04 結論CommonsCollections利用鏈中有多條利用鏈都涉及到Transform鏈,包括CC1、CC5、CC6、CC7,其中的調用過程都非常相似。但是並不是所有的CC鏈都是基於Transform實現的命令執行,在下一篇文章中會講到其他的利用鏈,會有更加複雜的應用方式。

往期推薦1

告別腳本小子系列丨JAVA安全(1)——JAVA本地調試和遠程調試技巧

2

告別腳本小子系列丨JAVA安全(2)——JAVA反編譯技巧

3

告別腳本小子系列丨JAVA安全(3)——JAVA反射機制

4

告別腳本小子系列丨JAVA安全(4)——ClassLoader機制與冰蠍Webshell分析

5

告別腳本小子系列丨JAVA安全(5)——序列化與反序列化

6

告別腳本小子系列丨JAVA安全(6)——反序列化利用鏈(上)

0x01 前言我們通常把反序列化漏洞和反序列化利用鏈分開來看,有反序列化漏洞不一定有反序列化利用鏈(經常用shiro反序列化工具的人一定遇到過一種場景就是找到了key,但是找不到gadget,這也就是在這種場景下沒有可利用的反序列化利用鏈)。如果我們向某個漏洞提交平台提交一個反序列化漏洞,但是不給反序列化利用鏈,那麼平台大概率是不會接受這種漏洞的。

反序列化利用鍊是整個反序列化利用過程中最關鍵的一環,通常反序列化利用鏈需要藉助常用的第三方jar包,其中最有名的就是CommonCollections利用鏈(簡稱CC鏈)。

往期推薦

1、告別腳本小子系列丨JAVA安全(1)——JAVA本地調試和遠程調試技巧

2、告別腳本小子系列丨JAVA安全(2)——JAVA反編譯技巧

3、告別腳本小子系列丨JAVA安全(3)——JAVA反射機制

4、告別腳本小子系列丨JAVA安全(4)——ClassLoader機制與冰蠍Webshell分析

5、告別腳本小子系列丨JAVA安全(5)——序列化與反序列化

0x02反序列化環境準備為了更方便初學者來學習反序列化利用鏈,我們首先要準備當前需要的實驗環境。學習反序列化利用鏈最好的辦法是參考ysoserial(https://github.com/frohoff/ysoserial),ysoserial是一個開源的集成化反序列化利用鏈工具,可以快速生成反序列化利用鏈payload。

如果是不追求細節的小伙伴,可以直接按照參照ysoserial使用文檔來生成payload,如下圖所示。

1656056253110337.png

本文的主要目的是教會小伙伴們告別腳本小子,所以就不直接使用編譯好的jar包,但是我們後面很多利用代碼會參考ysoserial中的代碼,ysoserial中關於反序列化利用鏈的代碼都在ysoserial.payloads包中。

我們的目的是不通過ysoserial框架,自己實現相應的反序列化利用鏈。我們搭建反序列化測試的基礎環境,新建maven項目,添加項目依賴的jar包。

1656056482765667.png

為了模擬序列化和反序列化的過程,編寫兩個公用的靜態方法,這兩個方法將在後面的反序列化利用鏈中被多次使用。其中searialize方法的作用是把對象obj序列化之後保存到文件filename中,unserialize方法的作用是把文件filename中的數據讀出來反序列化為對象。

1656057022119874.png

通過讀寫文件來模擬序列化和反序列化的過程是最直觀的實現方式,但是在實際環境中,我們遇到的都是基於POST輸入的字符輸入流來進行反序列化,如下圖所示。本地讀寫文件的反序列化和基於POST輸入字符的反序列化是完全沒有區別的,所以我們後面在研究反序列化利用鏈的時候都是通過本地文件讀寫的方式來實現,而不會準備專門的WEB漏洞環境。

1656057057835562.png

某系統反序列化漏洞實例

0x03 反序列化利用鏈0x3.1 URLDNS利用鏈URLDNS鍊是JAVA眾多利用鏈中最簡單的一條利用鏈,非常適合初學者研究學習,具有下面的特點:

1)利用鏈只依賴jdk本身提供的類,不依賴其他第三方類,所以具有很高的通用性,可以用於判斷目標是否存在反序列化漏洞。

2)利用鏈本身只能執行域名解析的操作,不能執行系統命令或者其他惡意操作。如果向漏洞提交平台提交反序列化漏洞,但是利用鍊是URLDNS的利用鏈,那麼漏洞提交平台可能會拒絕這個漏洞。

Ysoserial中關於URLDNS鏈的主要代碼如下圖3.1.1,圖3.1.2所示。這裡面有一個很關鍵的點是使用了自定義的SilentURLStreamHandler類,為什麼要使用這個自定義的類,我將在後面說明原因。

1656057124347053.png

圖3.1.1 生成URLDNS利用鏈對象

1656057125681216.png

圖3.1.2 自定義SilentURLStreamHandler類

我們先把ysoserial的代碼搬運到本地,做一名合格的搬運工。直接搬運過來之後運行payload可以查看到DNSLOG的日誌,證明搬運工沒有問題了。搬運過來之後需要去掉ysoserial中的反射調用,我們這裡沒有Reflections類,所以自己寫關於反射調用的代碼,如圖3.1.3所示,運行結果如圖3.1.4所示

1656057492128088.png

圖3.1.3 本地引用URLDNS利用鏈

1656057536210644.png

圖3.1.4 運行之後可以在DNSLOG查看DNS請求日誌

為了理清楚利用鏈的整個流程,我們在java.net. URLStreamHandler類的getHostAddress方法中下斷點調試一下,如圖3.1.5所示。1656057566522110.png

圖3.1.5 下斷點調試URLDNS利用鏈

運行整個payload,根據debug查看棧調用情況,如圖3.1.6所示。其中最關鍵的紅色的框中的部分,可以看出整個利用鏈非常簡單。

1656057604681965.png

圖3.1.6 URLDNS利用鏈的棧調用情況

首先反序列化入口是在HashMap的readObject,在這個方法中會調用本類的hash方法,如圖3.1.7所示。

1656057638166723.png

圖3.1.7 在HashMap的readObject方法中調用HashMap的hash方法

繼續跟進hash方法,在這個方法中會調用key的hashCode方法。 Key對應的值是java.net.URL類的對象,如圖3.1.8所示。

1656057707177043.png

圖3.1.8 通過hash方法調用URL類的hashCode方法

繼續跟進會調用java.net.URL類的hashCode方法,會調用handler字段的hashCode方法。而handler定義來自於URLStreamHandler類,所以會調用URLStreamHandler類的handler方法,如圖3.1.9所示。

1656057735909554.png

圖3.1.9 URL類的hashCode方法調用URLStreamHandler類的hashCode方法

繼續跟進java.net.URLStreamHandler類的hashCode方法,如圖3.1.10所示。這裡可以看出裡面就直接調用了getHostAddress方法,該方法執行之後會進行域名到IP地址的解析請求。

14.png

圖3.1.10 最終調用了域名解析相關的方法getHostAddress方法

到這裡已經看完了整個調用棧的流程,但是還是沒有找到任何理由必須要用自定義的SilentURLStreamHandler類。為了理清楚原因,我們對原來的payload進行修改,去除自定義的SilentURLStreamHandler類,如圖3.1.11所示。

1656057796826844.png

圖3.1.11 修改後的URLDNS利用鏈

還是在java.net. URLStreamHandler類的getHostAddress方法中下斷點。可以看到整個棧調用情況如圖3.1.12所示。可以看出觸發getHostAddress方法的入口點是從generalURLDNS2這個方法,而不是unserialize方法,也就是在生成序列化對象的時候就已經觸發了域名解析的請求。由於JAVA內部對DNS請求存在緩存機制,那麼在反序列化的時候會優先從DNS緩存中查找域名解析記錄,那麼反序列化的時候就收不到正確的DNS請求數據。

1656057822137179.png

圖3.1.12 修改後的URLDNS利用鏈

我們跟一下在生成payload時候觸發getHostAddress的流程,其中最關鍵的是執行HashMap中的put方法,如圖3.1.13所示。

1656057850115774.png

圖3.1.13 URLDNS利用鏈生成對象時調用HashMap的put方法

跟踪put方法的定義,如圖3.1.14所示。裡面會調用hash方法

1656057893998470.png

圖3.1.14 HashMap的put方法會調用本類的hash方法

剩下的流程和上面分析調用棧一樣,最終會導致觸發執行getHostAddress方法。

為了避免在生成payload的時候觸發DNS請求,影響反序列化時DNS請求的執行。有兩種解決辦法。

1)第一種就是像ysoserial代碼中的方式一樣,定義一個類繼承自URLStreamHandler,並且在類中重寫getHostAddress等方法,使得在序列化的時候不會執行getHostAddress方法。

2)第二種辦法是通過通過java.net.URL類中的hashCode方法中的邏輯來避免執行後續的getHostAddress方法。

第一種方法在ysoserial的代碼中已經寫很清楚了,這裡主要再說一下第二種方式。在整個利用鏈中一個很重要的步驟是會調用java.net.URL類中的hashCode方法。如圖3.1.15所示。

1656057973681984.png

圖3.1.15 java.net.URL類中的hashCode方法代碼邏輯

這裡有一個很重要的判斷語句是,如果hashCode不等於-1,則直接返回對應hashCode的值,否則調用hashCode方法計算對應的值。這裡需要特別注意的一點是這裡的hashCode既是java.net.URL類的方法,也是java.net.URL類的字段。所以我們需要

1)第一次put的時候把hashCode字段設置為不是-1的值,避免運行下面的handler.hashCode(this)。

2)生成序列化對象的時候又需要把hashCode字段設置為-1,因為反序列化的時候需要運行下面的handler.hashCode(this)。

所以我們也可以通過反射修改hashCode字段的方式來避免在序列化的時候觸發DNS請求,再次修改後的代碼如圖3.1.16所示。這裡最主要的是增加了通過反射修改hashCode字段的操作。

1656058030110427.png

圖3.1.16 通過控制hashCode字段避免序列化時候觸發DNS請求

這樣之後也能達到和ysoserial代碼一樣的效果。也能正常觸發URLDNS的請求,如圖3.1.17所示。

1656058060623699.png

圖3.1.17 通過修改的payload觸發URLDNS鏈的DNS請求

0x3.2CC鏈CC鍊是最早出現的影響較大的java反序列化利用鏈,原作者一共給出7條利用鏈,但是後來有很多大牛在此基礎上給出了一些改進的利用鏈,對初學者而言,學習CC鍊是屬於學習JAVA反序列化利用鏈的重要基礎。

關於CC鏈的內容很多,限於篇幅有限,這次的文章先開頭對部分CC鏈進行講解,關於CC鏈的更多內容將在下一篇文章中詳述。本次我們主要先講關於CC鏈中的Transform鏈。

在學習Transform鏈之前,首先需要說明JAVA中命令執行的方式。 JAVA中最典型的運行操作系統命令的辦法是通過Runtime類來執行,如圖3.2.1所示。

1656058111625903.png

圖3.2.1 JAVA中執行系統命令的方式

但是在反序列化的過程中不能直接通過Runtime來執行,因為Runtime類沒有繼承Serializable接口,如圖3.2.2所示。

1656058136364167.png

圖3.2.2 Runtime類沒有繼承Serializable接口

但是我們可以通過反射的方式來調用Runtime類執行,並且裡面涉及到的全部類都繼承了Serializable接口,如圖3.2.3所示。這裡有一個坑是,通過反射來執行方法的返回值類型一定是Object類型,需要做強制類型轉換,把Objectl類型轉化為Runtime類型。後續的Transform利用鏈基本上都是通過執行這段代碼來執行系統命令的。

1656058161160001.png

圖3.2.3 通過反射的方式來執行Runtime類的exec方法

嚴格來說Transform鏈屬於整個CC鏈中的Sink點,CC鏈基本上都是通過Transform來最終執行系統命令的。學習Tranform鍊是掌握CC鏈的基礎前提,最典型的Transform鏈如圖3.2.4所示。

1656058185182669.png

圖3.2.4 典型Transform鏈運行情況

直接運行上面的代碼是可以彈出計算器的,多數CC鏈最終也是通過調用類似的代碼來執行系統命令。為了理解Transforml鏈的內容,需要分開來看裡面涉及到的幾個類:InvokerTransformer類、ConstantTransformer類和ChainedTransformer類。

在InvokerTransformer類中,最主要的是transform方法。該方法中通過反射的方式執行任意一個類的方式,如圖3.2.5所示。 Transform執行的方法必須是public修飾符的。

1656058278599022.png

圖3.2.5 通過InvokerTransformer類的transform方法執行任意public方法

InvokerTransformer類的transform方法提供了一種執行任意其他方法的路徑,我們寫一個簡單的例子來幫助大家理解transform方法,如圖3.2.6所示。定義一個類TEST,類中定義一個方法Hello,那麼我們就可以通過tranform方法來執行TEST類的Hello方法。

1656058310116802.png

圖3.2.6 典型的transform方法調用

可能有的小伙伴會疑惑,我要執行Hello,為什麼不直接調用,非要通過transform來調用呢?試想一下,如果我們要執行的是“Runtime.getRuntime()”這樣的方法,但是整個系統中都沒有任何地方直接調用了這個,那麼我們是不是就可以通過transform來間接的執行這個方法呢。

但是現在通過transform來執行方法還有一個很明顯的不足,就是只能執行單個對象的單個方法,不能鍊式調用。形像一點來說明這個問題,我們可以執行”Runtime.getRuntim()”,但是我們不能執行“Runtime.getRuntime().exec(xxxx)”。我們需要找到鍊式調用的方式,幸運的是CommonsCollections中提供了另一個類ChainedTransformer。

ChainedTransformer類中提供了鍊式調用transform方法的辦法,如圖3.2.7所示。 ChainedTransformer類的構造方法是傳入Transformer類型的數組,通過transform方法依次遍歷數組中的每一個元素,上一步的方法調用的輸出作為下一步的方法調用的輸入,完美的鍊式調用解決辦法。

1.jpg

四所美國大學的研究人員在周二發表的一篇論文中演示表明,六家主要供應商的GPU都容易受到一種新發現的攻擊,這種攻擊讓惡意網站可以讀取其他網站顯示的用戶名、密碼及其他敏感的可視化數據。

跨源攻擊允許來自一個域(比如example.com)的惡意網站有效地讀取來自example.org或另一個不同域的網站顯示的像素,然後,攻擊者可以重新構建像素,讓他們可以查看後一個網站顯示的單詞或圖像。這種洩漏違反了一個關鍵的安全原則,該原則構成了保護互聯網的最基本的安全邊界之一,這個原則就叫同源策略(same origin policy),它要求託管在一個網站域上的內容與所有其他網站域隔離開來。

優化帶寬是有代價的GPU.zip(這種概念驗證攻擊的名稱)始於一個惡意網站,該網站將一個指向它想要讀取的某個網頁的鏈接放在iframe中,而iframe是一種常見的HTML元素,允許網站嵌入廣告、圖像或託管在其他網站上的其他內容。通常情況下,同源策略會阻止任何一個網站查看另一個網站的源代碼、內容或最終的可視化產品。研究人員發現,內部GPU和獨立GPU都用來提高性能的數據壓縮充當了側信道,他們可以濫用這條側信道繞過限制,逐個竊取像素。

GPU.zip若要奏效,必須將惡意頁面加載到Chrome或Edge瀏覽器中。當這些瀏覽器處理攻擊頁面時,Firefox和Safari在工作方式方面的底層差異阻止攻擊得逞;另一個要求是,在iframe中鏈接的頁面不能被配置為拒絕被跨源網站嵌入。

當HTML被嵌入到惡意網站上的iframe中時,可能導致安全威脅,這是十多年來公開的秘密。大多數網站通過X-Frame-Options或Content-Security-Policy標頭限制跨源嵌入顯示用戶名、密碼及其他敏感內容的頁面,然而並非所有網站都這麼做。維基百科就是一個例子,它顯示賬戶登錄者的用戶名,如果一個人在訪問一個他不信任的網站時想要保持匿名,而如果該網站包含的iframe含有指向https://en.wikipedia.org/wiki/Main_Page的鏈接,可能會被拒絕。

2.jpg

圖1. 對用戶去匿名化處理的像素竊取概念驗證(PoC),運行時打開的其他標籤播放視頻。 “Ground Truth”是受害者iframe(以“Yingchenw”登錄維基百科)。 “AMD”是在Ryzen 7 4800U上30分鐘後的攻擊結果,準確率為97%。 “Intel”是在i7-8700上215分鐘後的攻擊結果,準確率高達98%。

研究人員表明了GPU.zip如何允許他們為PoC創建的一個惡意網站逐個竊取用戶維基百科用戶名的像素。攻擊適用於蘋果、英特爾、AMD、高通、Arm和英偉達提供的GPU。在AMD的Ryzen 7 4800U上,GPU.zip花了約30分鐘來渲染目標像素,準確率達到了97%,在運行英特爾i7-8700的系統上顯示時,攻擊需要215分鐘才能重建像素。

研究人員分析的所有GPU都使用專有的壓縮形式來優化PC、手機或顯示目標內容的其他設備的內存數據總線中的可用帶寬。壓縮方案因廠商而異,沒有文檔記錄,因此研究人員對每種壓縮方案進行了逆向工程處理,從而獲得的一種方法使用SVG(可縮放矢量圖形)圖像格式,在存在壓縮的情況下最大化黑白目標像素之間的DRAM流量差異。雖然論文討論了GPU.zip,因為它適用於iGPU或內部GPU,但這種技術同樣適用於獨立或離散GPU。

研究人員在論文中寫道:我們演示了攻擊者可以利用基於iGPU的壓縮信道,在使用SVG過濾器的瀏覽器(截至2023年4月的最新版Google Chrome)中執行跨源像素竊取攻擊,即使SVG過濾器是在恆定時間實施的。原因在於,攻擊者可以根據瀏覽器中的單個秘密像素,創建高度冗餘或高度非冗餘的模式,由於這些模式由iGPU處理,它們不同程度的冗餘導致無損壓縮輸出依賴秘密像素,依賴數據的壓縮輸出直接轉換為依賴數據的DRAM流量和依賴數據的緩存佔用。

因此我們表明,即使在最被動的威脅模型下(攻擊者只能使用瀏覽器中的粗粒度計時器觀察模式的粗粒度冗餘信息,並且缺乏自適應選擇輸入的能力),單個像素也可能被洩露。我們的概念驗證攻擊在一系列設備(包括電腦和手機)上得逞,這些設備來自眾多硬件廠商,採用不同的GPU架構(英特爾、AMD、蘋果和英偉達)。令人驚訝的是,我們的攻擊在離散GPU上也得逞了,我們的初步結果表明這些架構上還存在軟件透明壓縮。

現在是個威脅?可能不是,但是……數據壓縮是提高軟硬件性能的一項常見特性。它使用複雜運算來表示文件或數據塊中的冗餘,並縮減其擁有的位數,壓縮也是一種常見的側信道,成為過去十年中幾次攻擊的原因,比如用於解密一些HTTPS流量的CRIME(壓縮比信息洩露變得容易)漏洞,針對HTTPS加密的另一種攻擊BREACH(全稱通過超文本自適應壓縮進行的瀏覽器偵察和洩露),2018年名為VORACLE的攻擊,以及在2021年針對存儲器壓縮的實用時序側信道攻擊。

如前所述,GPU.zip僅在惡意攻擊者網站被加載到Chrome或Edge中時有效。原因是:要使攻擊有效,瀏覽器必須:

1.允許跨源iframe與cookie一同被加載

2.允許在iframe上渲染SVG過濾器

3.將渲染任務委託給GPU

谷歌的代表沒有表明該公司是否計劃改變Chrome的行為以回應研究結果。

與此同時,英特爾的代表在一封電子郵件中表示,這家芯片製造商“評估了研究人員提供的發現結果,確定根本原因不在我們的GPU上,而在第三方軟件上。”

眼下,GPU.zip更多的是一種好奇而不是真正的威脅,但前提是Web開發人員適當地限制敏感頁面不被跨源網站嵌入。如果最終用戶想要檢查頁面是否實施了此類限制,應該查找源頭中的X-Frame-Options或Content-Security-Policy標頭。為此:

1.打開網頁

2.打開開發者控制台

3.重新加載網頁

4.進入到網絡標籤,檢查主文檔請求

5.查看X-Frame-Options或Content-Security-Policy是否在這裡被設置

檢查www.gmail.com可以看到X-Frame-Options被設置為SAMEORIGIN(同源)。

然而,檢查https://en.wikipedia.org/wiki/Main_Page卻發現沒有設置這樣的標頭。

明年5月在舊金山將舉行第45屆IEEE安全與隱私研討會,雖然GPU.zip目前構成的威脅很小,但研究和令人驚訝的發現對設計軟硬件的人來說仍然很重要。

原型污染是一個有趣的漏洞,無論是服務器端還是客戶端。基於應用邏輯,原型污染會導致其他漏洞。例如,posix 引入了一種有趣的技術來在模板引擎中實現RCE,MichałBentkowski 展示了繞過客戶端HTML 清理程序,而William Bowling 使用原型污染在HackerOne 上發現了一個反射型XSS。從RCE 到SQL,任何漏洞都可能與javascript 應用程序中的原型污染有關。

介紹在這項研究中,我們的目標很簡單,即掃描所有漏洞披露程序的原型污染,並找到實現XSS 的腳本小工具。這篇技術文章將涉及我們創建的工具、面臨的挑戰以及整個過程中的案例研究。

我們對Web 應用程序感興趣的兩種情況是檢查它是否容易受到原型污染。

情況1在第一種情況下,我們要檢查應用程序是否正在解析查詢/哈希參數,並檢查它是否在過程中污染原型。我們發現80% 的嵌套參數解析器容易受到原型污染的影響。

讓我們假設Web 應用程序使用canjs-deparam 庫來解析查詢參數。正如你在下面的代碼中看到的,它創建了一個空對象並添加了鍵值對。顯然,如果我們請求的URL 是https://victim.com/#a=b__proto__[admin]=1,這會導致原型污染。

如你所想,通過在location.hash 和location.search 中迭代不同的原型污染有效負載,很容易識別應用程序是否具有易受攻擊的原型污染解析器。

以下是查詢字符串的不同變體,這些變體在解析時可能會導致污染。

4.png

SeleniumBot為了實現自動化,我們編寫了一個seleniumBot,它運行在一個巨大的子域數據庫上,並檢查應用程序是否存在漏洞。

瀏覽器擴展Bot的一個漏洞是我們無法掃描應用程序的目錄和授權終端,因為數據庫變得非常大,掃描需要幾天時間,且大多數程序禁止掃描。為了解決這個漏洞,我們編寫了一個chrome 擴展,其運行邏輯與Bot相同,但它會在用戶訪問chrome 中的特定終端時進行掃描。使用擴展程序,我們可以隨便使用chrome,並在後台掃描原型污染,你可以在這裡找到插件。

情況2在這種情況下,我們要檢查是否有任何功能在客戶端的用戶輸入或某些數據/響應處理導致原型污染,大多數情況下這會導致self-XSS,因為攻擊者無法控制輸入如情況1 中的來自該位置輸入。但它值得掃描,大多數時候self-XSS可以轉換為reflection-XSS。

幸運的是,在這種情況下,自動化有點困難,CodeQL 使事情變得更容易。我們只選擇了收入最高的頂級程序,並轉儲了所有的javascript 文件,創建了一個CodeQL 數據庫,並掃描了導致原型污染的模式。

這樣,我們就能夠找到一個用戶控制的JSON,他可以與另一個導致原型污染的應用程序合併。

識別易受攻擊的庫一旦Bot識別出易受攻擊的應用程序,我們的下一個任務是識別易受攻擊的庫和原型被污染的確切行,並將結果存儲在數據庫中。為了識別,我們使用了幾種不同的技術。

如果應用程序並不復雜,在Chrome 開發者工具中搜索諸如location.hash/decodeURIComponent/location.search 之類的關鍵字將導致找到易受攻擊的實現的確切功能。

在Firefox 中阻止JS 資源請求在Firefox 開發者工具網絡活動中有一個很好的選項叫做Block URL,所以為了找到負責原型污染的js 資源,我們阻止URL 並檢查污染的屬性是否未定義。

setter 上的調試器斷點這種技術比其他技術更簡單,當屬性設置為object .prototype時,我們可以設置一個斷點。

7.png

查找腳本小工具什麼是腳本小工具?在某個屬性被污染後,是否有應用程序邏輯或函數會導致Javascript執行?

讓我們看一個在SwiftType Search庫中找到的腳本小工具的簡單示例。實現XSS的有效負載是https://example.com/#__proto__[xxx]=alert(1)。

下面是一段代碼(腳本小工具)負責彈出警報,$.each 迭代this._userServerConfiguration.install.hooks 對像以及原型上的屬性,這導致我們被污染的屬性xxx 被評估。

8.png

基於這個應用程序,我們使用了不同的技術來查找腳本小工具。

關鍵字搜索和源代碼審查如果應用比較簡單,我們可以搜索srcdoc/innerHTML/iframe/createElement 等關鍵字,查看源代碼,檢查是否導致javascript 執行。有時,提到的技術可能根本找不到小工具。在這種情況下,純源代碼審查會顯示一些不錯的小工具,如下例所示。

BlackFan 通過源代碼審查在jQuery 中發現了這個很酷的小工具。

小工具9.png

這是一段小工具的代碼:

10.png

SecurityMB 的pollute.js我們已經圍繞SecurityMB 的pollute.js 編寫了一個burp 擴展,它將所有JS 資源替換為由pollute.js 生成的修改版本。此外,我們修改了pollute.js,使其僅在某個屬性受到污染時才記錄信息。

pollute.js 的基本思想是它通過在所有屬性訪問周圍添加調試函數來檢測代碼,該函數會記錄訪問Object.prototype 屬性時的確切訪問行。

檢查下面的插件。

注意:插件並不完美,tmp.js 可能會被覆蓋,最好使用一個隨機名稱。

Filedescriptor 的不受信任類型擴展不受信任類型通過濫用可信類型來記錄DOM sink,我們檢查這些DOM sinks是否有任何可能被污染的屬性,進而導致XSS。

如果你在安裝了插件的情況下訪問https://msrkp.github.io/,你會注意到jQuery 中的一個innerHTML sink。其中,wrapMap[tag] 是未定義的,這意味著我們可以用數組污染wrapMap 的“li”屬性,並且第一個或第二個元素將被注入到頁面中。

通過污染“li”屬性導致XSS類似於文件描述符的擴展securitymb的pollution .js記錄類似的堆棧跟踪,我們必須檢查源代碼,並檢查它是否導致手動XSS。

一旦找到這個小工具,我們就向相應的程序報告這個漏洞。

將易受攻擊的庫和小工具存儲在數據庫中我們計劃將所有易受攻擊的小工具和庫存儲在數據庫中。

在構建了易受攻擊的庫和腳本、小工具的數據庫後,可以使用它來促進Prototype Pollution 的搜索和利用。

例如,在某些情況下,JavaScript 代碼中存在易受攻擊的庫,但會在特定條件下執行。為了覆蓋這些變體,可以使用正則表達式檢測庫。由於代碼可以通過縮小修改並組裝成一個大的JS 文件,所以搜索正則表達式不應太嚴格,應該使用在縮小過程中不改變的片段。例如,你可以搜索在查詢字符串處理中使用的正則表達式。

為此,構建了一個規則庫,可以通過使用Burp 的“漏洞消息檢查”或“軟件版本報告器”擴展分析HTTP 響應來檢測被動模式下的易受攻擊的庫。

chrome 擴展中添加了相同的功能,它使用數據庫中提到的導致污染的模式搜索js 資源。

Web 應用程序中的被動搜索記錄jQuery 查詢對象易受攻擊的庫。鏈接到burp 插件:https://github.com/BlackFan/cspp-tools/tree/main/match_rules。

示例研究案例研究1:CodeQL這是我最喜歡的一個漏洞,有一次我試圖使用插件和selenium bot 找到污染。但他們都沒有顯示出任何有趣的結果。所以,我想到了使用CodeQL來掃描這個漏洞,因為程序的範圍非常大,而且有很多JS密集型的應用程序。

於是我只能掃描所有有趣的應用程序並將JS 文件下載到一個文件夾中。然後,我創建了一個CodeQL 數據庫,並在https://github.com/github/codeql 上提供的查詢的幫助下編寫了一個查詢,但我面臨的漏洞是我必須為每個庫的基本deparam 查詢編寫一個易受攻擊的代碼模式,這是不可行的。來自GHSecurity 實驗室的@asgerf 提出了一個通用查詢,其中RemoteFlowSource 或location.{hash,search} 作為源,不安全的屬性分配作為Sink。此查詢的缺點是應該調用解析器函數https://www.google.com/url?q=https%3A%2F%2Fgithub.com%2Fgithub%2Fsecuritylab%2Fdiscussions%2F209%23discussioncomment-145109sa=Dsntz=1usg=AFQjCNFDSqqg5OWJTbhafhqaa4OR2chcjg。無論如何,我在我創建的JS 數據庫上運行這些查詢,並希望找到易受攻擊的合併調用或位置解析器。

令我驚訝的是,它顯示了下載的javascript 文件中存在易受攻擊的合併的結果。然後一位研究人員和我開始努力利用它。由於位置解析中不存在污染,我們必須找出哪些函數污染了原型。

1、污染原型

經過兩天的努力,我們能夠通過將JSON 有效負載發送到保存有效負載的某個終端來污染原型,當客戶端收到相同的有效負載時,原型就會受到污染。

2、尋找小工具

我們花了兩天多的時間才找到合適的小工具,在一個Web Worker中發現了一個javascript代碼的執行。

15.png

由於Web Worker 不能直接操作DOM,所以這個XSS 的影響非常低。經過大量的源代碼審查,我們能夠找到合適的小工具。

3、帳戶接管權限

你可能已經註意到這是一個self XSS,我們必須展示其影響。又過了一天,我們通過在iframes/windows 中打開敏感頁面來升級self XSS 以接管帳戶,並使用SAML 登錄我們的帳戶並讀取敏感頁面中的數據以接管帳戶。

案例研究2:Jira Service Management 4.16.0 上的原型污染我們使用selenium bot 掃描了HackerOne、Bugcrowd 和Intigriti 中的所有私有和公共程序。有許多具有位置解析功能的應用程序會導致污染,而且大多數情況下漏洞在於第三方分析服務或使用易受攻擊的庫。我們注意到一個易受攻擊的網站,其域為jira.random.com/servicedesk/customer/user/requests?__proto__.x=11111。出於好奇,我們尋找了各個公司的Jira 服務管理。

污染的根本原因:Jira服務管理使用的骨干查詢參數容易受到原型污染的影響。

XSS腳本小工具:Posix想出了下面這個小工具,它可以在所有Jira網站上使用。

Gadget:__proto__.isFresh=xxx__proto__.onmousemove=alert(1)//__proto__.onmousemove=1

腳本:

16.png

下面是使用文件描述符的不受信任類型找到的其他一些小工具。

17.png

jira.mozilla.com 上的XSS

其中一個使用Jira的Mozilla域也有同樣的漏洞,我們把這個漏洞提交給了Mozilla,得到了2000美元的獎勵。

URL:

18.png

我們最初認為這是用戶安裝的模塊漏洞,但後來意識到該漏洞存在於所有自託管的4.16.0 版以下的Jira網站中。

Jira 通過將__proto__, constructor和prototype項列入黑名單來修復該漏洞,但是如果你清楚地註意到_setParamValue 函數,字符[] 將從項中刪除,這意味著我們可以使用像__pro[]to__ 這樣的項繞過修復。

19.png

繞過:https://local:8080/servicedesk/customer/user/signup?__pro[]to__.div=1__pro[]to__.div=%3Cimg%20src%20onerror=alert(document.domain)%3E__pro[]to__.div=1

案例研究3:使用Rahul 和Harsh 的chrome 擴展程序發現apple.com 上的XSS1、發現漏洞

Rahul 和Harsh最終確定了創建可用於這些終端的chrome 擴展。他們編寫了一個基本的chrome 擴展,基本上用原型污染有效載荷更改location.search/location.hash 並檢查原型是否被污染。

當時,他們已經在研究蘋果的計劃。所以,他們做的第一件事就是開始瀏覽apple.com的網頁來測試這個插件。該擴展程序在https://www.apple.com/shop/buy-watch/apple-watch 彈出了存在原型污染的通知。有那麼一瞬間,我們都認為這是一個誤報,但原型確實被污染了。

2、尋找小工具

在BlackFan 的幫助下,我們很快找到了一個小工具。最終的URL 是,https://www.apple.com/shop/buy-watch/apple-watch?__proto__[src]=image__proto__[onerror]=alert(1)

污染位於蘋果用來解析位置的canJS-deparam 庫中。

最初,蘋果通過檢查__proto__ 是否在屬性中來修復該漏洞,因為你可能已經知道這可以使用[constructor][prototype] 繞過,因此最終繞過URL 將是https://www.apple.com/shop /buy-watch/apple-watch?a[constructor][prototype]=imagea[constructor][prototype][onerror]=alert(1)。

我們提交了繞過修復,蘋果通過完全刪除位置解析修復了這個漏洞。

案例研究4:HubSpot 分析HubSpot 容易受到原型污染的影響,它在解析查詢字符串(location.search)的js 文件中使用了deparam。 HubSpot 被超過121000 家公司使用。我們發現,由於HubSpot使用的第三方分析,許多應用程序容易受到XSS的攻擊。

1、第一種繞過方法

Hubspot通過將__proto__ key列入黑名單來修復這個漏洞,因此它可以被構造函數[prototype][taint]=contamination繞過,我們報告了這個繞過,他們通過創建一個空Object來修復這個繞過。

20.png

2、第二種繞過方法:通過Nikita Stupin 繞過

Nikita Stupin 使用以下有效載荷找到了一個很酷的繞過方法:

?__proto__=0[taint]=polluted

如果__proto_, constructor, prototype 存在於項中,他們通過將小寫更改為大寫來修復繞過。

22.png

案例研究5:Masato Kinugawa 的細分分析污染Segment Analytics 使用容易受到原型污染的組件查詢字符串。這是一個有趣的原型污染,只有當屬性為Number 時才會發生污染。

23.png

這是造成污染的代碼。

24.png

找到一個只有數字污染的小工具是非常困難的。我們發現許多使用組件查詢字符串或分段分析的漏洞賞金網站仍然容易受到污染,但沒有小工具,就沒有任何影響。我們無法在任何易受此漏洞影響的應用程序中實現XSS。

Trello 就是這個漏洞的一個例子,你可以注意到Object.prototype[123] 被污染了:https://trello.com/?__proto__[123]=xx

在knockout.js中,securityymb找到了一個使用數字的小工具,如果易受攻擊的網站使用knockout.js,那你就太幸運了。

25.png

緩解措施1.在合併兩個對像或解析位置並將其轉換為對象時,請確保使用包含以下__proto__、prototype、constructor 的屬性的拒絕列表,確保在將屬性添加到對象之前進行拒絕列表檢查,並且不要像Jira 那樣犯錯誤。

2.如果應用程序是Node.js,你可以使用命令行選項--disable-proto 禁用Object.prototype.__proto__ 屬性。

區塊鏈攻擊向量:最安全技術的漏洞(上)

3. 智能合約攻擊Apriorit 擁有從事智能合約開發和區塊鏈測試的團隊。我們已經積累了豐富的基於以太坊、EOS、NEO平台的智能合約漏洞分析和規避經驗。與智能合約相關的主要區塊鏈安全問題涉及源代碼、網絡虛擬機、智能合約運行時環境以及區塊鏈本身中的錯誤。讓我們看看這些攻擊向量中的每一個。

合約源代碼漏洞如果智能合約的源代碼存在漏洞,就會對簽署合約的各方構成風險。例如,2016 年以太坊合約中發現的錯誤使其所有者損失了8000 萬美元。 Solidity 中的一個常見漏洞提供了一種可能性,可以將控制權委託給其他智能合約中不受信任的功能,稱為重入攻擊。在此攻擊期間,合約A 從合約B 調用具有未定義行為的函數。反過來,合約B 可以調用合約A 的函數並將其用於惡意目的。

虛擬機中的漏洞以太坊虛擬機(EVM) 是一種基於分佈式堆棧的計算機,其中執行基於以太坊的區塊鏈的所有智能合約。 EVM 最常見的漏洞如下:

不可變缺陷——區塊鏈塊本質上是不可變的,這意味著智能合約一旦創建,就無法更改。但是,如果智能合約在其代碼中包含任何錯誤,它們也無法修復。網絡犯罪分子有可能發現並利用代碼漏洞來竊取Ether 或創建新的分叉,就像DAO 攻擊一樣。

加密貨幣在轉移過程中丟失——如果以太幣被轉移到一個沒有任何所有者或合同的孤立地址,這是可能的。

訪問控制中的錯誤——以太坊智能合約中存在一個遺漏修改器錯誤,允許黑客訪問合約中的敏感功能。

短地址攻擊——這是可能的,因為EVM 可以接受錯誤填充的參數。黑客可以通過向潛在受害者發送特製地址來利用此漏洞。例如,在2017 年對Coindash ICO 的一次成功攻擊中,對Coindash 以太坊地址的修改使受害者將他們的以太幣發送到黑客的地址。

此外,黑客可以通過應用其他典型的破壞區塊鏈技術的方法來破壞智能合約,包括DDoS、eclipse 和各種低級別攻擊。

然而,Cardano 和Zilliqa 等較年輕的區塊鏈使用不同的虛擬機:IELE、KEVM 等。這些新的區塊鏈聲稱在其協議中保證智能合約的安全性。

4.交易驗證機制攻擊與金融機構不同,區塊鏈只有在網絡中的所有節點都達成一致後才能確認交易。在包含交易的區塊被驗證之前,該交易被歸類為未驗證。然而,驗證需要一定的時間,這為網絡攻擊創造了一個完美的載體。

雙花是一種利用交易驗證機制的常見區塊鏈攻擊。區塊鏈上的所有交易都需要用戶驗證才能被確認為有效,這需要時間。攻擊者可以利用這種延遲來獲得優勢,並誘使系統在多個交易中使用相同的硬幣或代幣。

image.png

圖2. 雙花攻擊

以下是基於利用交易發起和確認之間的中間時間的最常見攻擊類型。

芬尼襲擊當一筆交易被預挖到一個區塊中,並且在該預挖區塊被釋放到網絡之前創建了一個相同的交易,從而使第二個相同的交易無效時,Finney 攻擊是可能的。

種族攻擊當攻擊者創建兩個相互衝突的交易時,就會執行競態攻擊。第一筆交易被發送給受害者,受害者無需等待交易確認即可接受付款(例如發送產品)。同時,將向攻擊者返回相同數量的加密貨幣的衝突交易被廣播到網絡,最終使第一筆交易無效。

矢量76Vector76 是之前兩次攻擊的組合。在這種情況下,惡意礦工創建兩個節點,其中一個僅連接到交換節點,另一個連接到區塊鍊網絡中連接良好的對等節點。之後,礦工創建兩筆交易,一筆高價值和一筆低價值。然後,攻擊者預挖並從交換服務中扣留一個包含高價值交易的區塊。在區塊公告之後,攻擊者迅速將預挖區塊直接發送到交易所服務。它與一些礦工一起將預挖區塊視為主鏈並確認此交易。因此,這種攻擊利用了這樣一個事實,即網絡的一部分看到攻擊者已包含在塊中的交易,而網絡的另一部分看不到該交易。

交易所服務確認大額交易後,攻擊者向主網發送小額交易,主網最終拒絕大額交易。結果,攻擊者的賬戶被記入了高價值交易的金額。儘管這種類型的攻擊成功的可能性很高,但它並不常見,因為它需要一個託管的電子錢包,該電子錢包在一次確認後接受付款,並需要一個節點來處理傳入的交易。

替代歷史攻擊另一種歷史攻擊——也稱為區塊鏈重組攻擊——即使在多次確認的情況下也可能發生,但需要黑客提供大量的計算能力。在這種情況下,惡意用戶向收件人發送交易,同時使用返回相同代幣的另一筆交易挖掘替代分叉。例如,即使接收方在n 次確認後認為交易有效並發送產品,如果攻擊者釋放更長的鏈並取回硬幣,接收方也可能會損失金錢。

最新的一次區塊鏈重組攻擊發生在2020 年8 月的Ethereum Classic上,當時一名礦工使用舊軟件並在挖礦時暫時無法訪問互聯網。當兩個版本的區塊鏈競爭網絡中節點的有效性並導致插入大約3000 個區塊時,重組就發生了。

51% 或多數攻擊當黑客控制了51% 的網絡哈希率並創建一個最終優先於現有分叉的替代分叉時,多數攻擊是可能的。這種攻擊最初是唯一已知的區塊鏈漏洞,在不久的過去似乎不切實際。然而,至少有五種加密貨幣——Verge 、 ZenCash、Monacoin、Bitcoin Gold 和Litecoin Cash——已經遭受了51% 的攻擊。在每一種情況下,網絡罪犯都收集了足夠的哈希算力來破壞網絡並賺取數百萬美元。

最近在2020 年8 月發生的對以太坊經典(ETC) 的51% 攻擊導致價值約560 萬美元的ETC 加密貨幣被雙花。顯然,黑客非常了解ETC 協議,並在四天內設法挖掘了4,280 個區塊,直到平台發現攻擊。事件發生僅五天后,ETC 就遭遇了第二次51% 攻擊,其中一名礦工進行了4000 個區塊的網絡重組。

image.png

圖3. 多數攻擊

不幸的是,所有小型加密貨幣仍面臨多數攻擊的風險。由於這些加密貨幣吸引的礦工較少,攻擊者只需租用計算能力即可獲得網絡的大部分份額。 Crypto51的開發人員試圖提醒人們注意破解較小加密貨幣的潛在風險。他們的網站顯示了對各種區塊鏈進行51% 攻擊的預期成本。

防止雙花攻擊的可能措施包括在監聽期間監控收到的交易、轉發雙花嘗試、插入其他節點以觀察交易以及拒絕直接傳入連接。

此外,還有一項稱為閃電網絡的創新技術,旨在解決交易驗證機制中的漏洞利用問題。該網絡允許用戶通過雙向支付渠道網絡即時驗證交易,而無需委託資金保管。但是,它仍然容易受到DDoS 攻擊,其中一次已經發生在2018 年3 月。

5、礦池攻擊對於像比特幣這樣的主要加密貨幣,個體礦工已經不可能賺取利潤,因此礦工通過創建礦池來統一他們的算力。這使他們能夠開採更多的區塊,並且每個人都能獲得一份獎勵。目前,最大的比特幣礦池是BTC.com、AntPool 和ViaBTC。根據Blockchain.com 的數據,它們加起來佔比特幣網絡總哈希率的52% 以上。

礦池是一個不錯的目標。惡意礦工試圖通過利用區塊鏈共識機制中常見的Web 應用程序漏洞來控制內部和外部的礦池。

以下是對礦池最常見的攻擊。

自私挖礦自私挖礦是指惡意礦工試圖通過在一段時間內不向網絡廣播挖出的區塊然後一次釋放幾個區塊,使其他礦工失去他們的區塊來增加他們的獎勵份額。防止此類攻擊的可能措施是將礦工隨機分配到礦池的各個分支,優先選擇時間戳較新的區塊,並在最大可接受時間內生成區塊。這種類型的攻擊也稱為塊扣留。

image.png

圖4. 自私挖礦攻擊

由於2014 年對Eligius礦池的自私挖礦攻擊,礦工損失了300 BTC。自私挖礦有很高的成功機會,並且可能發生在所有加密貨幣上。針對自私挖礦的可能預防措施包括只註冊受信任的礦工,並對現有的比特幣協議進行更改以隱藏部分工作量證明和完整工作量證明之間的差異。

預扣後分叉預扣後分叉(FAW) 是自私挖礦的一種變體,事實證明它對攻擊者更有利可圖。在FAW 攻擊期間,惡意礦工隱藏一個獲勝的區塊,然後丟棄它或稍後釋放它以創建一個分叉,具體取決於情況。由Ujin Kwon 領導的一組研究人員明確描述了這種攻擊的概念。

結論儘管區塊鏈的受歡迎程度仍在上升,但越來越多的針對區塊鏈的網絡攻擊可能對其聲譽產生負面影響。了解最常見的區塊鏈漏洞和攻擊類型對於關注區塊鏈安全並想知道首先要保護什麼的每個人來說都是必須的。

區塊鏈攻擊向量:最安全技術的漏洞(上)

3. 智能合約攻擊Apriorit 擁有從事智能合約開發和區塊鏈測試的團隊。我們已經積累了豐富的基於以太坊、EOS、NEO平台的智能合約漏洞分析和規避經驗。與智能合約相關的主要區塊鏈安全問題涉及源代碼、網絡虛擬機、智能合約運行時環境以及區塊鏈本身中的錯誤。讓我們看看這些攻擊向量中的每一個。

合約源代碼漏洞如果智能合約的源代碼存在漏洞,就會對簽署合約的各方構成風險。例如,2016 年以太坊合約中發現的錯誤使其所有者損失了8000 萬美元。 Solidity 中的一個常見漏洞提供了一種可能性,可以將控制權委託給其他智能合約中不受信任的功能,稱為重入攻擊。在此攻擊期間,合約A 從合約B 調用具有未定義行為的函數。反過來,合約B 可以調用合約A 的函數並將其用於惡意目的。

虛擬機中的漏洞以太坊虛擬機(EVM) 是一種基於分佈式堆棧的計算機,其中執行基於以太坊的區塊鏈的所有智能合約。 EVM 最常見的漏洞如下:

不可變缺陷——區塊鏈塊本質上是不可變的,這意味著智能合約一旦創建,就無法更改。但是,如果智能合約在其代碼中包含任何錯誤,它們也無法修復。網絡犯罪分子有可能發現並利用代碼漏洞來竊取Ether 或創建新的分叉,就像DAO 攻擊一樣。

加密貨幣在轉移過程中丟失——如果以太幣被轉移到一個沒有任何所有者或合同的孤立地址,這是可能的。

訪問控制中的錯誤——以太坊智能合約中存在一個遺漏修改器錯誤,允許黑客訪問合約中的敏感功能。

短地址攻擊——這是可能的,因為EVM 可以接受錯誤填充的參數。黑客可以通過向潛在受害者發送特製地址來利用此漏洞。例如,在2017 年對Coindash ICO 的一次成功攻擊中,對Coindash 以太坊地址的修改使受害者將他們的以太幣發送到黑客的地址。

此外,黑客可以通過應用其他典型的破壞區塊鏈技術的方法來破壞智能合約,包括DDoS、eclipse 和各種低級別攻擊。

然而,Cardano 和Zilliqa 等較年輕的區塊鏈使用不同的虛擬機:IELE、KEVM 等。這些新的區塊鏈聲稱在其協議中保證智能合約的安全性。

4.交易驗證機制攻擊與金融機構不同,區塊鏈只有在網絡中的所有節點都達成一致後才能確認交易。在包含交易的區塊被驗證之前,該交易被歸類為未驗證。然而,驗證需要一定的時間,這為網絡攻擊創造了一個完美的載體。

雙花是一種利用交易驗證機制的常見區塊鏈攻擊。區塊鏈上的所有交易都需要用戶驗證才能被確認為有效,這需要時間。攻擊者可以利用這種延遲來獲得優勢,並誘使系統在多個交易中使用相同的硬幣或代幣。

image.png

圖2. 雙花攻擊

以下是基於利用交易發起和確認之間的中間時間的最常見攻擊類型。

芬尼襲擊當一筆交易被預挖到一個區塊中,並且在該預挖區塊被釋放到網絡之前創建了一個相同的交易,從而使第二個相同的交易無效時,Finney 攻擊是可能的。

種族攻擊當攻擊者創建兩個相互衝突的交易時,就會執行競態攻擊。第一筆交易被發送給受害者,受害者無需等待交易確認即可接受付款(例如發送產品)。同時,將向攻擊者返回相同數量的加密貨幣的衝突交易被廣播到網絡,最終使第一筆交易無效。

矢量76Vector76 是之前兩次攻擊的組合。在這種情況下,惡意礦工創建兩個節點,其中一個僅連接到交換節點,另一個連接到區塊鍊網絡中連接良好的對等點。之後,礦工創建兩筆交易,一筆高價值和一筆低價值。然後,攻擊者預挖並從交換服務中扣留一個包含高價值交易的區塊。在區塊公告之後,攻擊者迅速將預挖區塊直接發送到交易所服務。它與一些礦工一起將預挖區塊視為主鏈並確認此交易。因此,這種攻擊利用了這樣一個事實,即網絡的一部分看到攻擊者已包含在塊中的交易,而網絡的另一部分看不到該交易。

交易所服務確認大額交易後,攻擊者向主網發送小額交易,主網最終拒絕大額交易。結果,攻擊者的賬戶被記入了高價值交易的金額。儘管這種類型的攻擊成功的可能性很高,但它並不常見,因為它需要一個託管的電子錢包,該電子錢包在一次確認後接受付款,並需要一個節點來處理傳入的交易。

替代歷史攻擊另一種歷史攻擊——也稱為區塊鏈重組攻擊——即使在多次確認的情況下也可能發生,但需要黑客提供大量的計算能力。在這種情況下,惡意用戶向收件人發送交易,同時使用返回相同代幣的另一筆交易挖掘替代分叉。例如,即使接收方在n 次確認後認為交易有效並發送產品,如果攻擊者釋放更長的鏈並取回硬幣,接收方也可能會損失金錢。

最新的一次區塊鏈重組攻擊發生在2020 年8 月的Ethereum Classic上,當時一名礦工使用舊軟件並在挖礦時暫時無法訪問互聯網。當兩個版本的區塊鏈競爭網絡中節點的有效性並導致插入大約3000 個區塊時,重組就發生了。

51% 或多數攻擊當黑客控制了51% 的網絡哈希率並創建一個最終優先於現有分叉的替代分叉時,多數攻擊是可能的。這種攻擊最初是唯一已知的區塊鏈漏洞,在不久的過去似乎不切實際。然而,至少有五種加密貨幣——Verge 、 ZenCash、Monacoin、Bitcoin Gold 和Litecoin Cash——已經遭受了51% 的攻擊。在每一種情況下,網絡罪犯都收集了足夠的哈希算力來破壞網絡並賺取數百萬美元。

最近在2020 年8 月發生的對以太坊經典(ETC) 的51% 攻擊導致價值約560 萬美元的ETC 加密貨幣被雙花。顯然,黑客非常了解ETC 協議,並在四天內設法挖掘了4,280 個區塊,直到平台發現攻擊。事件發生僅五天后,ETC 就遭遇了第二次51% 攻擊,其中一名礦工進行了4000 個區塊的網絡重組。

image.png

圖3. 多數攻擊

不幸的是,所有小型加密貨幣仍面臨多數攻擊的風險。由於這些加密貨幣吸引的礦工較少,攻擊者只需租用計算能力即可獲得網絡的大部分份額。 Crypto51的開發人員試圖提醒人們注意破解較小加密貨幣的潛在風險。他們的網站顯示了對各種區塊鏈進行51% 攻擊的預期成本。

防止雙花攻擊的可能措施包括在監聽期間監控收到的交易、轉發雙花嘗試、插入其他節點以觀察交易以及拒絕直接傳入連接。

此外,還有一項稱為閃電網絡的創新技術,旨在解決交易驗證機制中的漏洞利用問題。該網絡允許用戶通過雙向支付渠道網絡即時驗證交易,而無需委託資金保管。但是,它仍然容易受到DDoS 攻擊,其中一次已經發生在2018 年3 月。

5、礦池攻擊對於像比特幣這樣的主要加密貨幣,個體礦工已經不可能賺取利潤,因此礦工通過創建礦池來統一他們的算力。這使他們能夠開採更多的區塊,並且每個人都能獲得一份獎勵。目前,最大的比特幣礦池是BTC.com、AntPool 和ViaBTC。根據Blockchain.com 的數據,它們加起來佔比特幣網絡總哈希率的52% 以上。

礦池是一個不錯的目標。惡意礦工試圖通過利用區塊鏈共識機制中常見的Web 應用程序漏洞來控制內部和外部的礦池。

以下是對礦池最常見的攻擊。

自私挖礦自私挖礦是指惡意礦工試圖通過在一段時間內不向網絡廣播挖出的區塊然後一次釋放幾個區塊,使其他礦工失去他們的區塊來增加他們的獎勵份額。防止此類攻擊的可能措施是將礦工隨機分配到礦池的各個分支,優先選擇時間戳較新的區塊,並在最大可接受時間內生成區塊。這種類型的攻擊也稱為塊扣留。

image.png

圖4. 自私挖礦攻擊

由於2014 年對Eligius礦池的自私挖礦攻擊,礦工損失了300 BTC。自私挖礦有很高的成功機會,並且可能發生在所有加密貨幣上。針對自私挖礦的可能預防措施包括只註冊受信任的礦工,並對現有的比特幣協議進行更改以隱藏部分工作量證明和完整工作量證明之間的差異。

預扣後分叉預扣後分叉(FAW) 是自私挖礦的一種變體,事實證明它對攻擊者更有利可圖。在FAW 攻擊期間,惡意礦工隱藏一個獲勝的區塊,然後丟棄它或稍後釋放它以創建一個分叉,具體取決於情況。由Ujin Kwon 領導的一組研究人員明確描述了這種攻擊的概念。

結論儘管區塊鏈的受歡迎程度仍在上升,但越來越多的針對區塊鏈的網絡攻擊可能對其聲譽產生負面影響。了解最常見的區塊鏈漏洞和攻擊類型對於關注區塊鏈安全並想知道首先要保護什麼的每個人來說都是必須的。

區塊鏈並不像我們想像的那麼安全。儘管安全性貫穿於所有區塊鏈技術,但即使是最強大的區塊鏈也會受到現代網絡犯罪分子的攻擊。 Apriorit 專家已經分析了針對Coincheck、Verge和Bancor交易所的攻擊,這些攻擊極大地損害了區塊鏈本身的聲譽。

區塊鏈可以很好地抵抗傳統的網絡攻擊,但網絡犯罪分子正在想出專門針對區塊鏈技術的新方法。在本文中,我們描述了針對區塊鏈技術的主要攻擊媒介,並了解了迄今為止最重大的區塊鏈攻擊。

網絡犯罪分子已經設法濫用區塊鏈來執行惡意操作。如果攻擊者沒有收到加密貨幣獎勵,像WannaCry和Petya這樣的勒索軟件攻擊就不會如此大規模。現在,看起來黑客正在考慮利用區塊鏈安全漏洞作為他們的主要收入來源。

2019 年3 月,白帽黑客在短短30 天內在各種區塊鍊和加密貨幣平台中發現了43 個漏洞。他們甚至在Coinbase、EOS和Tezos等著名平台中發現了漏洞。

然而,弱點通常很難檢測到,因為它們可能隱藏在不顯眼的地方。例如,Parity 多重簽名錢包是通過破壞其中具有提取功能的庫而被黑客入侵的。攻擊者設法將庫本身初始化為錢包,並聲稱擁有它的所有者權利。結果,573 個錢包受到影響,價值3000 萬美元的加密貨幣被盜,另外被白帽黑客組織救出的1.8 億美元後來歸還給了合法所有者。

通過攻擊比特幣和以太坊等龐大的網絡,網絡犯罪分子表明他們足夠聰明,可以反駁區塊鏈安全的神話。讓我們考慮五個最常見的區塊鏈攻擊向量:

image.png

五個區塊鏈攻擊向量

1.區塊鍊網絡攻擊區塊鍊網絡包括創建和運行交易並提供其他服務的節點。例如,比特幣網絡由發送和接收交易的節點以及將批准的交易添加到區塊的礦工組成。網絡罪犯尋找網絡漏洞並通過以下類型的攻擊利用它們。

分佈式拒絕服務分佈式拒絕服務(DDoS) 攻擊很難在區塊鍊網絡上執行,但它們是可能的。

當使用DDoS 攻擊區塊鍊網絡時,黑客打算通過大量請求消耗其所有處理資源來關閉服務器。 DDoS 攻擊者旨在斷開網絡的礦池、電子錢包、加密貨幣交易所和其他金融服務。區塊鏈也可以使用DDoS 殭屍網絡在其應用程序層受到DDoS 攻擊。

2017 年,Bitfinex 遭受了大規模的DDoS 攻擊。這對IOTA 基金會來說尤其不方便,IOTA 基金會在Bitfinex 通知用戶此次攻擊的前一天就在平台上發布了他們的IOTA 代幣。三年後,即2020 年2 月,在OKEx 加密貨幣交易所注意到類似攻擊的一天后, Bitfinex又經歷了一次DDoS 攻擊。

交易延展性攻擊交易延展性攻擊旨在誘使受害者支付兩次。在比特幣網絡中,每筆交易都有一個散列,即交易ID。如果攻擊者設法更改交易的ID,他們可以嘗試將更改後的哈希值的交易廣播到網絡,並在原始交易之前確認它。如果成功,發送方將認為初始交易失敗,而資金仍將從發送方的賬戶中提取。如果發件人重複交易,相同的金額將被扣除兩次。一旦這兩筆交易被礦工確認,這次黑客攻擊就成功了。

比特幣交易所Mt. Gox在2014 年因延展性攻擊而破產。然而,比特幣似乎通過引入隔離見證(SegWit) 流程解決了這個問題,該流程將簽名數據與比特幣交易分開,並用對每個簽名的不可延展的哈希承諾。

時間劫持時間劫持利用了比特幣時間戳處理中的一個理論漏洞。在時間劫持攻擊期間,黑客更改節點的網絡時間計數器並強制節點接受替代區塊鏈。當惡意用戶使用不准確的時間戳將多個虛假對等點添加到網絡時,就可以實現這一點。但是,可以通過限制接受時間範圍或使用節點的系統時間來防止時間劫持攻擊。

路由攻擊路由攻擊可以影響單個節點和整個網絡。這種黑客攻擊的想法是在將交易推送給同行之前篡改交易。其他節點幾乎不可能檢測到這種篡改,因為黑客將網絡劃分為無法相互通信的分區。路由攻擊實際上包括兩個獨立的攻擊:

分區攻擊,將網絡節點分成不同的組

延遲攻擊,篡改傳播消息並將它們發送到網絡

女巫攻擊通過將多個標識符分配給同一節點來安排女巫攻擊。區塊鍊網絡沒有可信節點,每個請求都會發送到多個節點。

image.png

圖1. 女巫攻擊

在Sybil 攻擊期間,黑客控制了網絡中的多個節點。然後受害者被關閉所有交易的假節點包圍。最後,受害者對雙花攻擊持開放態度。 Sybil 攻擊很難檢測和預防,但以下措施可能有效:增加創建新身份的成本,需要某種類型的信任才能加入網絡,或根據聲譽確定用戶權力。

蝕攻擊eclipse 攻擊需要黑客控制大量IP 地址或擁有分佈式殭屍網絡。然後攻擊者覆蓋受害者節點“已嘗試”表中的地址並等待受害者節點重新啟動。重啟後,受害者節點的所有出站連接都將被重定向到攻擊者控制的IP地址。這使得受害者無法獲得他們感興趣的交易。波士頓大學的研究人員對以太坊網絡發起了一次日食攻擊,並設法僅使用一兩台機器就完成了攻擊。

對權益證明網絡的遠程攻擊遠程攻擊針對使用股權證明(PoS) 共識算法的網絡,在該算法中,用戶可以根據持有的硬幣數量來挖掘或驗證區塊交易。

這些攻擊可以分為三類:

簡單- 當節點不檢查塊時間戳時,權益證明協議的簡單實現

事後腐敗——試圖在給定時間範圍內鑄造比主鏈更多的區塊

Stake bleeding——將交易從誠實維護的區塊鏈複製到攻擊者維護的私有區塊鏈

在進行遠程攻擊時,黑客使用購買或竊取的私鑰,該私鑰具有相當大的代幣餘額,該私鑰過去已經用於驗證。然後,黑客可以生成區塊鏈的替代歷史並根據PoS 驗證增加獎勵。

2. 用戶錢包攻擊實際上,在人們與它們互動之前,區塊鍊和網絡安全就像鹽和胡椒一樣在一起。這聽起來可能令人驚訝,但區塊鏈用戶構成了最大的安全威脅。人們了解區塊鏈在網絡安全中的用途,往往會高估區塊鏈的安全性而忽視其弱點。用戶錢包憑證是網絡犯罪分子的主要目標。

為了獲取錢包憑證,黑客嘗試使用網絡釣魚和字典攻擊等傳統方法以及尋找加密算法弱點等新的複雜方法。以下是攻擊用戶錢包的最常見方法的概述。

網絡釣魚2018 年,IOTA 錢包發起了一次攻擊,發起人是iotaseed.io(現已下線),這是一個虛假的在線種子生成器。黑客利用這項服務進行了網絡釣魚活動,並收集了帶有秘密種子的日誌。結果,2018 年1 月,黑客成功從受害者的錢包中竊取了價值超過400 萬美元的IOTA。

字典攻擊在這些攻擊中,黑客試圖通過嘗試普通密碼(如password1)的哈希值來破解受害者的加密哈希和鹽。通過將明文密碼轉換為加密哈希,攻擊者可以找到錢包憑證。

易受攻擊的簽名區塊鍊網絡使用各種加密算法來創建用戶簽名,但它們也可能存在漏洞。例如,比特幣使用ECDSA 密碼算法自動生成唯一的私鑰。然而,看起來ECDSA 的熵不足,這可能導致多個簽名中出現相同的隨機值。 IOTA 還面臨著其舊的Curl 哈希函數的密碼學問題。

有缺陷的密鑰生成利用密鑰生成中的漏洞,被稱為Johoe 的黑客在2014 年12 月獲得了Blockchain.info 提供的私鑰。這次攻擊的發生是由於代碼更新期間出現的錯誤導致生成公共輸入的隨機性差用戶密鑰。儘管此漏洞很快得到緩解,但ECDSA 算法仍然可能存在該漏洞。

對冷錢包的攻擊硬件錢包或冷錢包也可能被黑客入侵。例如,研究人員利用Nano S Ledger 錢包中的漏洞發起了Evil Maid 攻擊。由於這次黑客攻擊,研究人員獲得了私鑰以及受害者的PIN、恢復種子和密碼。

最近的一次冷錢包攻擊發生在2019 年,當時UPbit加密貨幣交易所正在將資金轉移到冷錢包。當您預計會受到網絡攻擊時,這是凍結加密貨幣的常用方法。黑客設法竊取了342,000 ETH,顯然是因為他們知道交易的時間。

對熱錢包的攻擊熱錢包是用於存儲私人加密密鑰的聯網應用程序。儘管加密貨幣交易所的所有者聲稱他們將錢包中的用戶數據與網絡斷開連接,但2018 年針對Coincheck 的5 億美元攻擊證明這並非總是如此。

2019 年6 月,對GateHub 的攻擊導致數十個原生XRP錢包的未經授權訪問和加密資產被盜。由於系統漏洞,新加坡加密貨幣交易所Bitrue也幾乎同時遭遇了熱錢包攻擊。結果,黑客設法竊取了價值超過450 萬美元的XRP 和237,500 美元的ADA 資金。

區塊鏈並不像我們想像的那麼安全。儘管安全性貫穿於所有區塊鏈技術,但即使是最強大的區塊鏈也會受到現代網絡犯罪分子的攻擊。 Apriorit 專家已經分析了針對Coincheck、Verge和Bancor交易所的攻擊,這些攻擊極大地損害了區塊鏈本身的聲譽。

區塊鏈可以很好地抵抗傳統的網絡攻擊,但網絡犯罪分子正在想出專門針對區塊鏈技術的新方法。在本文中,我們描述了針對區塊鏈技術的主要攻擊媒介,並了解了迄今為止最重大的區塊鏈攻擊。

網絡犯罪分子已經設法濫用區塊鏈來執行惡意操作。如果攻擊者沒有收到加密貨幣獎勵,像WannaCry和Petya這樣的勒索軟件攻擊就不會如此大規模。現在,看起來黑客正在考慮利用區塊鏈安全漏洞作為他們的主要收入來源。

2019 年3 月,白帽黑客在短短30 天內在各種區塊鍊和加密貨幣平台中發現了43 個漏洞。他們甚至在Coinbase、EOS和Tezos等著名平台中發現了漏洞。

然而,弱點通常很難檢測到,因為它們可能隱藏在不顯眼的地方。例如,Parity 多重簽名錢包是通過破壞其中具有提取功能的庫而被黑客入侵的。攻擊者設法將庫本身初始化為錢包,並聲稱擁有它的所有者權利。結果,573 個錢包受到影響,價值3000 萬美元的加密貨幣被盜,另外被白帽黑客組織救出的1.8 億美元後來歸還給了合法所有者。

通過攻擊比特幣和以太坊等龐大的網絡,網絡犯罪分子表明他們足夠聰明,可以反駁區塊鏈安全的神話。讓我們考慮五個最常見的區塊鏈攻擊向量:

image.png

五個區塊鏈攻擊向量

1.區塊鍊網絡攻擊區塊鍊網絡包括創建和運行交易並提供其他服務的節點。例如,比特幣網絡由發送和接收交易的節點以及將批准的交易添加到區塊的礦工組成。網絡罪犯尋找網絡漏洞並通過以下類型的攻擊利用它們。

分佈式拒絕服務分佈式拒絕服務(DDoS) 攻擊很難在區塊鍊網絡上執行,但它們是可能的。

當使用DDoS 攻擊區塊鍊網絡時,黑客打算通過大量請求消耗其所有處理資源來關閉服務器。 DDoS 攻擊者旨在斷開網絡的礦池、電子錢包、加密貨幣交易所和其他金融服務。區塊鏈也可以使用DDoS 殭屍網絡在其應用程序層受到DDoS 攻擊。

2017 年,Bitfinex 遭受了大規模的DDoS 攻擊。這對IOTA 基金會來說尤其不方便,IOTA 基金會在Bitfinex 通知用戶此次攻擊的前一天就在平台上發布了他們的IOTA 代幣。三年後,即2020 年2 月,在OKEx 加密貨幣交易所注意到類似攻擊的一天后, Bitfinex又經歷了一次DDoS 攻擊。

交易延展性攻擊交易延展性攻擊旨在誘使受害者支付兩次。在比特幣網絡中,每筆交易都有一個散列,即交易ID。如果攻擊者設法更改交易的ID,他們可以嘗試將更改後的哈希值的交易廣播到網絡,並在原始交易之前確認它。如果成功,發送方將認為初始交易失敗,而資金仍將從發送方的賬戶中提取。如果發件人重複交易,相同的金額將被扣除兩次。一旦這兩筆交易被礦工確認,這次黑客攻擊就成功了。

比特幣交易所Mt. Gox在2014 年因延展性攻擊而破產。然而,比特幣似乎通過引入隔離見證(SegWit) 流程解決了這個問題,該流程將簽名數據與比特幣交易分開,並用對每個簽名的不可延展的哈希承諾。

時間劫持時間劫持利用了比特幣時間戳處理中的一個理論漏洞。在時間劫持攻擊期間,黑客更改節點的網絡時間計數器並強制節點接受替代區塊鏈。當惡意用戶使用不准確的時間戳將多個虛假對等點添加到網絡時,就可以實現這一點。但是,可以通過限制接受時間範圍或使用節點的系統時間來防止時間劫持攻擊。

路由攻擊

路由攻擊可以影響單個節點和整個網絡。這種黑客攻擊的想法是在將交易推送給同行之前篡改交易。其他節點幾乎不可能檢測到這種篡改,因為黑客將網絡劃分為無法相互通信的分區。路由攻擊實際上包括兩個獨立的攻擊:

分區攻擊,將網絡節點分成不同的組

延遲攻擊,篡改傳播消息並將它們發送到網絡

女巫攻擊通過將多個標識符分配給同一節點來安排女巫攻擊。區塊鍊網絡沒有可信節點,每個請求都會發送到多個節點。

image.png

圖1. 女巫攻擊

在Sybil 攻擊期間,黑客控制了網絡中的多個節點。然後受害者被關閉所有交易的假節點包圍。最後,受害者對雙花攻擊持開放態度。 Sybil 攻擊很難檢測和預防,但以下措施可能有效:增加創建新身份的成本,需要某種類型的信任才能加入網絡,或根據聲譽確定用戶權力。

蝕攻擊eclipse 攻擊需要黑客控制大量IP 地址或擁有分佈式殭屍網絡。然後攻擊者覆蓋受害者節點“已嘗試”表中的地址並等待受害者節點重新啟動。重啟後,受害者節點的所有出站連接都將被重定向到攻擊者控制的IP地址。這使得受害者無法獲得他們感興趣的交易。波士頓大學的研究人員對以太坊網絡發起了一次日食攻擊,並設法僅使用一兩台機器就完成了攻擊。

對權益證明網絡的遠程攻擊遠程攻擊針對使用股權證明(PoS) 共識算法的網絡,在該算法中,用戶可以根據持有的硬幣數量來挖掘或驗證區塊交易。

這些攻擊可以分為三類:

簡單- 當節點不檢查塊時間戳時,權益證明協議的簡單實現

事後腐敗——試圖在給定時間範圍內鑄造比主鏈更多的區塊

Stake bleeding——將交易從誠實維護的區塊鏈複製到攻擊者維護的私有區塊鏈

在進行遠程攻擊時,黑客使用購買或竊取的私鑰,該私鑰具有相當大的代幣餘額,該私鑰過去已經用於驗證。然後,黑客可以生成區塊鏈的替代歷史並根據PoS 驗證增加獎勵。

2. 用戶錢包攻擊實際上,在人們與它們互動之前,區塊鍊和網絡安全就像鹽和胡椒一樣在一起。這聽起來可能令人驚訝,但區塊鏈用戶構成了最大的安全威脅。人們了解區塊鏈在網絡安全中的用途,往往會高估區塊鏈的安全性而忽視其弱點。用戶錢包憑證是網絡犯罪分子的主要目標。

為了獲取錢包憑證,黑客嘗試使用網絡釣魚和字典攻擊等傳統方法以及尋找加密算法弱點等新的複雜方法。以下是攻擊用戶錢包的最常見方法的概述。

網絡釣魚2018 年,IOTA 錢包發起了一次攻擊,發起人是iotaseed.io(現已下線),這是一個虛假的在線種子生成器。黑客利用這項服務進行了網絡釣魚活動,並收集了帶有秘密種子的日誌。結果,2018 年1 月,黑客成功從受害者的錢包中竊取了價值超過400 萬美元的IOTA。

字典攻擊在這些攻擊中,黑客試圖通過嘗試普通密碼(如password1)的哈希值來破解受害者的加密哈希和鹽。通過將明文密碼轉換為加密哈希,攻擊者可以找到錢包憑證。

易受攻擊的簽名區塊鍊網絡使用各種加密算法來創建用戶簽名,但它們也可能存在漏洞。例如,比特幣使用ECDSA 密碼算法自動生成唯一的私鑰。然而,看起來ECDSA 的熵不足,這可能導致多個簽名中出現相同的隨機值。 IOTA 還面臨著其舊的Curl 哈希函數的密碼學問題。

有缺陷的密鑰生成利用密鑰生成中的漏洞,被稱為Johoe 的黑客在2014 年12 月獲得了Blockchain.info 提供的私鑰。這次攻擊的發生是由於代碼更新期間出現的錯誤導致生成公共輸入的隨機性差用戶密鑰。儘管此漏洞很快得到緩解,但ECDSA 算法仍然可能存在該漏洞。

對冷錢包的攻擊硬件錢包或冷錢包也可能被黑客入侵。例如,研究人員利用Nano S Ledger 錢包中的漏洞發起了Evil Maid 攻擊。由於這次黑客攻擊,研究人員獲得了私鑰以及受害者的PIN、恢復種子和密碼。

最近的一次冷錢包攻擊發生在2019 年,當時UPbit加密貨幣交易所正在將資金轉移到冷錢包。當您預計會受到網絡攻擊時,這是凍結加密貨幣的常用方法。黑客設法竊取了342,000 ETH,顯然是因為他們知道交易的時間。

對熱錢包的攻擊熱錢包是用於存儲私人加密密鑰的聯網應用程序。儘管加密貨幣交易所的所有者聲稱他們將錢包中的用戶數據與網絡斷開連接,但2018 年針對Coincheck 的5 億美元攻擊證明這並非總是如此。

2019 年6 月,對GateHub 的攻擊導致數十個原生XRP錢包的未經授權訪問和加密資產被盜。由於系統漏洞,新加坡加密貨幣交易所Bitrue也幾乎同時遭遇了熱錢包攻擊。結果,黑客設法竊取了價值超過450 萬美元的XRP 和237,500 美元的ADA 資金。

區塊鏈攻擊向量:區塊鏈技術的主要漏洞(上)

區塊鏈攻擊向量有數百種可能的區塊鏈攻擊針對應用程序的不同部分。讓我們看一下關鍵向量和攻擊示例:

image.png

點對點攻擊點對點(P2P)網絡使區塊鏈成為分佈式賬本。它包括合作處理交易、管理用戶和管理區塊鏈的所有網絡參與者。

對於去中心化應用程序(dApp)和加密錢包,主要的網絡要求是與可信的區塊鏈節點提供商建立安全連接。此外,錢包和dApp 之間需要安全連接,並且必須能夠處理其他方的不當行為。

常見P2P攻擊示例:

Sybil攻擊是通過向同一節點分配多個標識符來安排的。區塊鍊網絡沒有可信節點,每個請求都會發送到多個隨機節點。在女巫攻擊期間,黑客控制多個網絡節點。然後受害者就會被假節點包圍,關閉他們的所有交易。最後,受害者容易受到雙花攻擊。

Eclipse 攻擊需要黑客控制大量IP 地址或擁有分佈式殭屍網絡。然後攻擊者覆蓋受害節點的tried表中的地址,並等待受害節點重新啟動。重啟後,受害節點的所有傳出連接將被重定向到攻擊者控制的IP地址。這使得受害者無法獲得他們感興趣的交易。

時間劫持利用了區塊鏈時間戳處理中的理論上的漏洞。黑客改變節點的網絡時間計數器並迫使節點接受替代區塊鏈。當惡意用戶將多個具有不准確時間戳的虛假對等點添加到網絡時,就可以實現這一點。

Apriorit 針對保護P2P 網絡的建議:

使用HTTPS 連接並驗證SSL 證書。這些措施允許網絡節點建立安全連接並加密傳輸中的數據。這可以保護數據免遭盜竊和劫持。

驗證資源真實性。創建執行惡意操作的流行資源的精確副本是一種常見的黑客技術。您可以通過驗證資源名稱等方式來驗證可信資源。

提高用戶的可信度。在純粹的對等網絡中,所有實體都是平等的,但您可以更改這一點以向值得信賴的用戶授予更多權限。例如,您可以增加創建新身份的成本,需要某種類型的信任證明才能加入網絡,並根據聲譽確定用戶的權力。

遠程過程調用協議攻擊基於遠程過程調用(RPC)協議的節點促進區塊鏈中網絡元素之間的通信。特別是,RPC 節點允許檢索交易歷史等數據、執行智能合約、傳達新交易以及維護網絡共識。

對RPC 節點的攻擊旨在破壞或劫持此通信。此類攻擊的常見示例:

分佈式拒絕服務(DDoS) 攻擊允許黑客通過重複請求消耗所有處理資源來癱瘓網絡節點。 DDoS 攻擊者的目標是斷開網絡的礦池、電子錢包、數據交換和其他元素。

竊聽似乎不會停止節點操作,但它允許惡意行為者監聽節點的通信。黑客可以注入惡意代碼或利用後門來獲得對節點數據、網絡路由和通過節點傳輸的敏感信息的未經授權的訪問。根據這些信息,黑客可以找到區塊鏈中的漏洞併計劃下一次攻擊。

網絡釣魚是一種普遍存在的社會工程攻擊,黑客通過讓用戶點擊惡意鏈接或將數據提交到虛假網站來竊取用戶的敏感信息。通過這種方式,黑客可以獲取用戶與區塊鏈節點通信的信息,進行模仿,從而獲得對用戶錢包的訪問權限。

Apriorit 針對保護PRC 節點的建議:

運行驗證器。驗證器在將新交易添加到區塊鏈之前根據網絡規則和網絡安全標準檢查新交易。驗證可能會減慢交易處理速度,但它減少了將欺詐或惡意交易永久記錄到區塊鏈的機會

實施用戶身份驗證和訪問控制。所有用戶在訪問區塊鍊網絡之前都應確認自己的身份。他們還應該能夠僅訪問他們需要的元素。此類訪問限制可減少黑客未經授權訪問用戶帳戶時的攻擊面。

共識攻擊共識機制意味著大多數網絡節點必須就區塊鏈系統的狀態以及系統的任何更改達成一致。共識機制有多種,其中關鍵的有:

工作量證明(PoW),參與者競爭解決複雜的數學難題。第一個解決難題的人有權向區塊鏈添加新區塊,並獲得加密貨幣獎勵。

權益證明(PoS),根據加密貨幣的所有權或權益選擇新區塊的創建者。擁有較高權益的參與者有更大的機會被選擇來驗證交易並創建新區塊。 PoS 被認為比PoW 更節能,因為它不需要相同水平的計算工作。

這些機制通過防止惡意行為者操縱系統來幫助維護區塊鏈的完整性和安全性。黑客可以嘗試通過以下類型的攻擊來操縱網絡共識:

遠程攻擊針對使用PoS 共識算法的網絡,用戶可以根據自己持有的代幣數量來挖掘或驗證區塊交易。在遠程攻擊中,黑客使用購買或竊取的具有相當大代幣餘額的私鑰,該私鑰過去已用於驗證。然後,黑客可以生成區塊鏈的替代歷史記錄,並根據PoS 驗證增加獎勵。

當黑客控制51% 的網絡哈希率並創建一個最終優先於現有分叉的替代分叉時,就有可能發生51%或多數攻擊。所有小型加密貨幣都面臨著多數攻擊的風險。由於這些加密貨幣吸引的礦工較少,攻擊者只需租用計算能力即可獲得網絡的大部分份額。

當攻擊者創建兩個衝突的交易時,就會執行競爭攻擊。第一個交易被發送給受害者,受害者接受付款(例如發送產品),而無需等待交易確認。與此同時,向攻擊者返回相同數量的加密貨幣的衝突交易被廣播到網絡,最終使第一筆交易無效。

Apriorit 確保區塊鏈共識的建議

落實處罰制度。這樣的系統應該檢測有害活動並向負責任的節點分配懲罰。例如,這可以通過鎖定一些治理參與者並擁有一組隨機的見證人來驗證每個操作來完成。

延遲區塊鏈確認。許多針對共識算法的攻擊需要在網絡節點捕獲惡意活動之前快速執行。您可以手動減慢交易確認速度,以便有更多時間來檢測有害操作。

加密攻擊加密算法幫助區塊鏈保護數據和交易免遭窺探。惡意行為者可以針對依賴薄弱協議或在加密實現中存在錯誤的網絡。此類攻擊可幫助黑客竊取數據或資金,或獲取有關網絡的更多信息以準備下一次攻擊。

常見的加密攻擊:

哈希衝突是哈希函數錯誤,它會為任何大小的輸入生成固定大小的數組。當兩個不同的輸入生成相同的輸出時,就會發生哈希衝突。如果新交易與現有交易具有相同的哈希值,這可能是一個嚴重的問題。

私鑰預測是嘗試猜測或暴力破解與特定用戶或實體關聯的私鑰。此類預測可以基於字典攻擊、鍵盤記錄、社會工程和其他攻擊向量。

Apriorit 對區塊鏈加密的建議

使用可信且強大的加密算法。您可以實施TLS、RSA、SHA-256 或任何其他加密算法來保護您的交易。請務必研究您選擇的算法並遵循實施最佳實踐,以降低創建漏洞的風險。

實施多重簽名錢包。這種類型的錢包需要至少兩個私鑰來簽署交易。這樣,即使黑客獲得了合法用戶的私鑰,也無法利用它來竊取用戶的資金或數據。

交易攻擊惡意行為者通常以區塊鍊網絡內的交易為目標。他們的目的是損害交易的完整性、保密性或可用性。此類攻擊針對的是智能合約、網絡設計以及管理網絡內交易的實施算法中的漏洞。黑客可以通過以下方式攻擊交易:

交易延展性攻擊,旨在誘騙受害者支付兩次。例如,在比特幣網絡中,每筆交易都有一個哈希值,即交易ID。如果攻擊者設法更改交易的ID,他們可以嘗試將具有更改後的哈希值的交易廣播到網絡,並在原始交易之前對其進行確認。如果成功,發送者將認為初始交易失敗,而資金仍將從發送者的帳戶中提取。

驗證攻擊旨在濫用交易驗證過程。所有區塊鏈交易都需要經過用戶驗證才能被認定為有效,這需要時間。攻擊者可以利用這種延遲來欺騙系統在多個交易中使用相同的硬幣或代幣。

時間鎖定交易攻擊允許黑客利用與時間鎖定交易相關的漏洞,這些交易在未來特定時間或滿足某些條件之前無法添加到區塊鏈中。

Apriorit 對區塊鏈交易的建議

防止雙重支出。像Vector 76這樣的雙花攻擊是共識算法濫用的常見結果,即用戶在看似相同的交易中花費了兩次代幣。您可以通過在偵聽期間監控收到的交易、轉發雙花嘗試、插入其他節點來觀察交易以及拒絕直接傳入連接來防止此問題。

使用時間鎖智能合約。這種類型的智能合約為交易添加了各種基於時間的約束。時間鎖智能合約通常會強制執行一段時間延遲,在此期間用戶無法執行指定的操作。這使得網絡節點有時間做出決策和檢測可疑交易。

結論儘管區塊鏈的受歡迎程度仍在上升,但越來越多的針對區塊鏈的網絡攻擊可能會對這項技術的聲譽產生負面影響。雖然存在多種可能的攻擊和濫用漏洞,但了解核心區塊鏈安全威脅和攻擊向量使您有機會實施可靠的安全措施。能夠抵禦主要的區塊鏈攻擊可以幫助您提高對產品的信任並避免被黑客攻擊的負面後果。

區塊鏈不再是炒作;它是一種廣泛且可靠的財務和數據管理技術。許多組織投資區塊鏈,使用它們來存儲和共享數據,並在其業務流程中實施它們。但區塊鏈也吸引了網絡犯罪分子的大量關注,他們的目標是敏感的企業數據和加密資產。

保護區塊鍊網絡免受黑客攻擊需要不斷審核和研究新的漏洞和潛在的攻擊媒介。在本文中,我們概述了關鍵的區塊鏈安全漏洞,探討了常見的攻擊媒介,並分享了我們關於減輕允許這些攻擊的風險的知識。

本文對於正在考慮開發或採用基於區塊鏈的應用程序並正在尋找檢查和確保其安全性的方法的企業非常有用。

為什麼黑客經常攻擊區塊鏈?隨著區塊鏈技術在處理數據和財務方面變得司空見慣,對基於區塊鏈的應用程序和網絡的成功攻擊經常出現在新聞中。讓我們看一下區塊鏈受到攻擊的關鍵原因:

image.png

信息處理不安全。許多企業使用區塊鏈不是為了管理財務和代幣,而是為了存儲數據:健康相關信息、供應鏈記錄、商業秘密,甚至投票詳細信息。如果未加密或以其他方式保護,此類記錄總是會吸引惡意行為者,因為它們可用於惡意活動:在暗網上出售數據、勒索組織、實施欺詐等。

大量且無法追踪的加密貨幣。加密貨幣和交易平台成為投資、資金處理和國際交易的常見工具,使其成為黑客攻擊的目標。 2022 年,黑客從加密相關服務中竊取了超過38 億美元。按照設計,區塊鍊網絡內的交易很難追踪到特定的人,這使得加密貨幣竊賊能夠逍遙法外。

將黑客繩之以法的挑戰。調查區塊鏈攻擊需要面臨許多技術和法律挑戰。區塊鏈交易是匿名且加密的,這意味著調查人員需要大量時間才能將欺詐交易追溯到黑客。此外,攻擊者及其受害者通常生活在不同的國家,並受不同的區塊鏈相關立法(如果有)管轄,這進一步使調查變得複雜。

區塊鏈實施的安全性差。儘管區塊鍊網絡和應用程序如雨後春筍般湧現,但並非所有開發它們的組織都對安全性給予足夠的重視。例如,由於Rab13s 漏洞,超過280 個包含價值250 億美元加密貨幣的網絡面臨遭受攻擊的風險。缺乏保護措施實際上是對網絡犯罪分子的邀請。

修復能力有限。作為去中心化的解決方案,區塊鏈應用程序及其核心邏輯通常由開源代碼管理。如果在該代碼中發現漏洞,每個人都會知道它。此外,修復區塊鏈代碼具有挑戰性,有時甚至是不可能的,因為它一旦發布就不可更改。

缺乏防止攻擊的網絡安全人才。保護區塊鏈應用程序免受攻擊不僅涉及安全設計和實施,還涉及定期安全審核和修復新發現的漏洞。此類工作需要許多組織所不具備的網絡安全專業知識。

儘管區塊鏈在網絡安全中的用例很多,但我們不斷看到成功的區塊鏈攻擊。攻擊次數也逐年增加。跟踪加密貨幣盜竊案的Comparitect 報告稱,2021 年成功發生了136 起加密貨幣盜竊案,2022 年發生了199 起,2023 年1 月至11 月期間發生了220 起。

讓我們來看看2023 年以來針對區塊鏈的幾起毀滅性攻擊:

image.png

歐拉金融遭遇一系列閃貸攻擊,導致超過1.95 億美元被盜。攻擊者濫用了平台協議中的一個漏洞,該漏洞允許他們從Euler 的存款池借錢,而無需抵押資產。歐拉與黑客協商歸還大部分被盜資金,並啟動了對其平台的獨立審計。

Bonq的智能合約遭遇了甲骨文黑客攻擊,攻擊者可以操縱某些加密貨幣的交易價格。由於這次黑客攻擊,Bonq 失去了大部分投資者。他們暫停了被利用協議的使用,但無法追回被盜資金。

Mixin Network損失了價值2 億美元的主網資產。該網絡使用託管在雲中的集中式數據庫。攻擊者破壞了該數據庫並獲得了對主網的未經授權的訪問。被盜資金並未歸還,但Mixin Network 承諾退還用戶損失的50%。

正如您所看到的,即使是擁有數百萬美元的區塊鍊網絡也不夠安全,無法確保保護用戶的財務。讓我們看一下惡意行為者可以利用的關鍵潛在漏洞。

區塊鏈安全威脅的主要來源了解可能的漏洞是保護應用程序安全的第一步。以下是導致常見類型區塊鏈攻擊成為可能的漏洞的主要來源:

image.png

聯網網絡是區塊鏈系統的核心方面之一,它由多個相互通信的節點組成。區塊鏈節點應該可以被其他節點發現、同步並且能夠抵禦攻擊和數據包丟失。底層網絡邏輯由以下各項管理:

一種網絡協議,負責在節點之間傳輸事務和塊。可發現性是該協議的重要組成部分,因為它可能會影響節點接收的數據。

共識協議,決定大多數網絡參與者都同意的網絡當前狀態。

節點之間保護不善的網絡可能會導致攻擊者破壞或修改通信。

密碼學加密算法允許區塊鏈使用公私密鑰對加密消息並驗證簽名。在去中心化平台中實施此類算法消除了第三方頒發私鑰的需要。相反,任何人都可以使用必要的軟件和正確實現加密算法來生成密鑰。

一般來說,密碼學有助於保護區塊鏈交易免遭未經授權的訪問。但如果實施不當,它可能會創建後門並授予惡意行為者訪問權限。

貯存區塊鏈依賴於去中心化存儲來包含用戶和錢包詳細信息以及交易記錄等數據。區塊鏈平台不僅在節點之間同步數據,還檢查每筆交易中使用的輸入是否唯一。當網絡增長到數十萬個區塊時,這可能需要很多時間。為了提高效率,區塊鏈平台使用處理塊和事務的索引器來提供對數據的快速訪問。

建立存儲和設計索引器需要謹慎的方法,因為它可能會引入雙重支出或依賴未經確認的交易等問題。

治理儘管區塊鏈技術具有許多安全優勢,但基於區塊鏈的平台仍然由人管理。通常,所有網絡參與者都成為利益相關者,網絡的任何變化都需要利益相關者達成共識。比特幣經典就是此類網絡的一個例子。公共治理可以保護網絡免受可疑更改和襲擊嘗試的影響,但如果未經大多數節點批准,它也會阻止有意義的改進。

一些區塊鏈平台與鏈上去中心化治理相集成,例如Tezos及其自我修正協議。這種方法使集成改進成為一個順利的過程,並降低了網絡分裂的風險。

應用代碼開發錯誤可能會導致區塊鏈應用程序出現意外行為。如果編程語言使用不當,甚至會導致程序崩潰。考慮到區塊鏈系統的去中心化性質,如果由於特定交易而發生崩潰,則可能會停止所有節點。

如果應用程序存在邏輯錯誤,它將無法處理所有負面的使用場景。例如,函數在處理餘額時可能會正確運行,直到傳遞了不正確的負值。

在下一節中,我們將概述惡意內部人員經常用來利用這些區塊鏈漏洞的攻擊。我們還研究了對您的網絡有用的區塊鏈攻擊向量和預防技術。

FortiGuard實驗室每兩週收集一次感興趣的勒索軟件變體的數據,並發布有關報告,旨在讓讀者了解不斷發展的勒索軟件形勢以及抵禦這些變體的緩解措施,本文要講的是Retch和S.H.O勒索軟件。

受影響的平台:Microsoft Windows;

受影響方:Microsoft Windows用戶;

影響:加密和洩露受害者的文件,並要求贖金解密文件;

嚴重性級別:高;

Retch勒索軟件概述Retch是2023年8月中旬首次發現的一種新的勒索軟件變體,它在受攻擊設備上加密文件,並留下兩張勒索信,要求受害者支付贖金來解密文件。

攻擊媒介雖然目前無法獲得有關Retch勒索軟件攻擊者使用的攻擊媒介的信息,但是它可能與已知其他勒索軟件組織有顯著關聯。

目前,來自以下國家的Retch勒索軟件樣本已提交給公共文件掃描服務:

美國

伊朗

德國

俄羅斯

法國

哥倫比亞

韓國

義大利

一旦勒索軟件運行,它就會查找並加密具有以下文件擴展名的文件:

1.png

以下目錄不支持文件加密:

'Windows'

'Program Files'

'Program Files (x86)'

勒索軟件為加密文件添加了“.Retch”擴展名。

2.png

由Retch勒索軟件加密的文件

然後,它會在每個加密文件的文件夾中放上一條標記為“Message.txt”的勒索信。

3.png

Retch勒索軟件釋放的勒索信

在勒索信中,攻擊者要求受害者支付價值300歐元的比特幣來解密文件,由於贖金要求較低,Retch勒索軟件的攻擊目標很可能是一般消費者而不是企業。如下圖所示,贖金信息有法語和英語兩種版本,這使我們相信Retch勒索軟件主要針對法國用戶。然而,進一步的調查顯示,情況並非如此。

研究人員還發現,放在桌面上的勒索信與“Message.txt”不同。留在桌面上的勒索信標有“HOW TO RECOVER YOUR FILES.txt”,並要求受害者支付價值1000美元的比特幣進行文件解密。這份勒索信有一個不同的聯繫電子郵件地址,其中包括攻擊者的比特幣錢包地址。

4.png

Retch勒索軟件在桌面上留下的勒索信標有“HOW TO RECOVER YOUR FILES.txt”

事實證明,Retch勒索軟件是基於一個公開的勒索軟件源代碼開發的,該源代碼聲稱用於教育目的,似乎是基於一款著名的開源勒索軟件“HiddenTear”。默認情況下,開源勒索軟件的勒索信如下圖所示,攻擊者似乎只在桌面上定制了只有英文的勒索信,而其他所有位置的勒索信都沒有受到影響,這表明Retch勒索軟件並沒有像最初想像的那樣針對法國用戶。如上所述,向公共文件掃描服務提交文件的國家很普遍,這進一步表明研究人員的懷疑是正確的。

在我們進行調查時,攻擊者的比特幣錢包沒有記錄任何交易。

S.H.O勒索軟件概述攻擊媒介目前還沒有關於S.H.O勒索軟件攻擊者使用的攻擊媒介的信息,不過,它可能與已知其他勒索軟件組織有顯著關聯。

S.H.O勒索軟件樣本已提交給以下國家的公共文件掃描服務:

美國;

加拿大;

勒索軟件執行勒索軟件運行後,會對受攻擊設備上的文件進行加密,並添加五個隨機字母和數字作為文件擴展名。

5.png

S.H.O勒索軟件加密的文件

S.H.O嘗試使用以下擴展名加密文件:

6.png

以下文件被排除在所有目錄外:

7.png

排除加密的文件列表

這些目錄也被排除在加密內容之外:

8.png

排除加密的目錄列表

S.H.O使用RSA公鑰和Microsoft“Rijndael Managed”C#庫對每個文件進行加密。

9.png

文件加密例程

在完成加密後,它會用自己的壁紙替換桌面壁紙,要求受害者找到並閱讀文件“readme.txt”,這是一封勒索信。

10.png

被S.H.O勒索軟件取代的壁紙

FortiGuard實驗室發現了兩種S.H.O勒索軟件變體,它們留下了不同的勒索信,儘管勒索信上有屬於攻擊者的不同比特幣地址,但贖金費用始終保持在200美元。

11.png

S.H.O勒索軟件變體留下的勒索信

12.png

另一個S.H.O勒索軟件變體留下的勒索信

贖金信息恐嚇受害者支付贖金,在調查時,這兩個比特幣錢包都不可用。

Fortinet客戶已經通過其AntiVirus和FortiEDR服務受到保護,免受這些惡意軟件變體的影響,如下所示:

FortiGuard實驗室檢測到具有以下殺毒軟件簽名的Retch勒索軟件樣本:

1.MSIL/Filecoder.AK!tr.ransom:

FortiGuard實驗室檢測的S.H.O勒索軟件樣本具有以下反病毒簽名。

2.MSIL/Filecoder.APU!tr.ransom:FortiGuard防病毒服務包括FortiGate、FortiMail、forticclient和FortiEDR。運行當前防病毒更新的Fortinet EPP客戶也受到保護。

IOC 13.png

緩解措施1.由於易受干擾、日常運營受攻擊、對組織聲譽的潛在影響,以及個人身份信息(PII)的不必要破壞或發布等,保持所有AV和IPS簽名的最新性至關重要。

2.由於大多數勒索軟件都是通過網絡釣魚傳播的,組織應考慮利用Fortinet解決方案來培訓用戶了解和檢測網絡釣魚威脅。

3.FortiFish網絡釣魚模擬服務使用真實世界的模擬來幫助組織測試用戶對網絡釣魚威脅的意識和警惕性,並在用戶遇到有針對性的網絡釣魚攻擊時培訓和加強正確的做法。

4.增加內部培訓,幫助最終用戶學習如何識別和保護自己免受各種類型的網絡釣魚攻擊,並可以輕鬆添加到內部培訓計劃中。

5.組織需要對數據備份的頻率、位置和安全性進行根本性的更改,以有效應對勒索軟件不斷演變和迅速擴大的風險。再加上數字供應鏈的攻擊和員工遠程辦公進入網絡,攻擊可能來自任何地方,這是一個真正的風險。

6.基於雲的安全解決方案,如SASE,用於保護離網設備,高級終端安全,如EDR(終端檢測和響應)解決方案,可以在攻擊中期中斷惡意軟件,以及零信任訪問和基於策略和上下文限制,對應用程序和資源的訪問的網絡分段策略,都應該進行調查,以最大限度地降低風險並減少成功勒索軟件攻擊的影響。

作為業界領先的完全集成安全結構的一部分,Fortinet還提供了廣泛的技術和基於人工的即服務產品組合,為你的安全生態系統提供本地協同和自動化。

7.CISA、NCSC、FBI和HHS等組織警告勒索軟件受害者不要支付贖金,部分原因是贖金並不能保證文件會被找回。

abstract-binary-code-ok-signed-sl-1200.jpg

2022年7月17日,阿爾巴尼亞新聞媒體報導了一次大規模網絡攻擊,該攻擊影響了阿爾巴尼亞政府的電子政務系統。後來經過調查,這些網絡攻擊是一個威脅活動的一部分,其目的可能是癱瘓該國的計算機系統。 2022年9月10日,阿爾巴尼亞當地新聞報導了針對阿爾巴尼亞TIMS、ADAM和MEMEX系統的第二波網絡攻擊。

大約在同一時間,我們發現了勒索程序和擦除程序樣本與第一波中使用的類似,儘管有一些有趣的修改,可能允許規避安全控制和提高攻擊速度。在這些變化中,最主要的是嵌入一個原始磁盤驅動程序,在惡意程序內部提供了直接的硬盤訪問,修改了元數據,並使用Nvidia洩露的代碼簽名證書對惡意程序進行簽名。

在這篇文章中,我們介紹了:

1.用於針對阿爾巴尼亞個機構的第一波和第二波勒索程序和擦除式惡意程序,並詳細說明了與之前已知的ROADSWEEP勒索程序和ZEROCLEARE變體的聯繫。

2.攻擊者使用英偉達(Nvidia)和科威特電信公司(Kuwait Telecommunications Company)的證書來簽署他們的惡意程序,前者已經洩露,但我們不確定他們是如何得到後者的。

3.我們發現了使用不同語言的不同攻擊組織之間的潛在合作關係,以及可能使用AnyDesk作為啟動勒索程序/擦除攻擊感染的初始入口點。

4.在第二波攻擊中實現自動化和加速擦拭的變化讓人想起中東臭名昭著的Shamoon擦除攻擊攻擊。

下面,我們將比較和討論第一波和第二波勒索程序和擦除式惡意程序之間的區別。

初始感染——不同攻擊組織之間合作關係和使用AnyDesk實用程序的證據雖然我們無法在分析的攻擊中確定攻擊者的初始入口點,但在第二波攻擊後的幾天,我們注意到有攻擊者可以訪問另一個非政府但重要的阿爾巴尼亞機構的AnyDesk帳戶,並建議說波斯語的黑客使用它來部署勒索程序或清除惡意程序。由此我們推測,第二波攻擊的初始入口點是通過合法的遠程訪問程序(如AnyDesk),特別是使用的擦除攻擊修改僅限在驅動程序安裝時自動執行,由於時間/訪問窗口有限,可能需要緊急執行。攻擊者和訪問提供者似乎屬於不同的攻擊組織,使用不同的語言。

使用科威特電信公司簽名證書的勒索程序如下所示:

1.png

第二波樣本與第一波樣本具有相同的簽名證書參數,該樣本與科威特電信公司有關。目前尚不清楚攻擊者如何能夠使用科威特電信公司的證書籤署其惡意程序,但我們懷疑它是被盜的。在本文發佈時,該證書已不再有效並已被撤銷。

2.png

在初始執行後,第二波勒攻擊中使用的索程序檢查攻擊者提供的任意六個或更多參數,而第一波樣本則檢查五個參數或更多,這是一個有助於防禦逃避檢測的小修改。然而,在一台受影響的計算機上進行的攻擊分析表明,在第二波攻擊中,攻擊者在提供類似於第一波攻擊的七位數時,沒有使用BAT文件調用勒索程序,而是使用六個零“000000”從命令行立即調用第二波攻擊中使用的勒索程序。如果由於沒有提供正確的參數而導致勒索程序執行失敗,則第二波攻擊示例將顯示與第一波攻擊不同的消息,第二波攻擊消息類似於由PDF到DOC轉換器顯示的錯誤消息。

3.png

第一波攻擊示例,執行失敗後的消息

4.png

第二波攻擊示例,執行失敗後的不同消息

第二波攻擊勒索程序樣本繼續執行並檢查互斥鎖Screenlimitsdevices#77!這個值與第一波攻擊樣本的互斥鎖不同:

abcdefghijklmnoklmnopqrstuvwxyz01234567890abcdefghijklmnopqrstuvwxyz01234567890

儘管我們根據其行為將這種惡意程序稱為勒索程序,但加密文件實際上是無法恢復的。當比較第二波勒索程序樣本和第一波勒索程序樣本時,我們注意到兩者都有相同的,並且都使用CreateFile和WriteFile api來覆蓋文件。在執行過程中,第二波攻擊勒索程序試圖解密並執行嵌入式腳本、惡意程序設置或API函數名。在第一波攻擊和第二波攻擊中使用的加密算法都是RC4。但是,在第二波中用於解密的RC4密鑰已被更改,這是另一種逃避檢測的嘗試。

第一波攻擊中的RC4密鑰:8C E4 B1 6B 22 B5 88 94 AA 86 C4 21 E8 75 9D F3

第二波攻擊中的RC4密鑰:F0 B4 ED D9 43 F5 C8 43 C9 D0 A2 4F 22 9B BC 3A

值得注意的是,在這兩波攻擊中,RC4解密方法都使用CryptoAPI (CryptDecrypt)而不是通常的S盒方法。在密碼學中,S盒(Substitution-box)是對稱密鑰算法執行置換計算的基本結構。 S盒用在分組密碼算法中,是唯一的非線性結構,其S盒的指標的好壞直接決定了密碼算法的好壞。對第二波分析表明,勒索程序可能是通過內部網絡部署的,可能來自另一台受感染的設備。在勒索程序執行之前,我們沒有看到任何其他東西被刪除或執行,並且勒索程序可執行文件名稱是隨機生成的,這可能是由攻擊者用來通過網絡部署它的工具(例如Mellona.exe)生成的。

儘管在第二波勒索程序與第一波攻擊中的完全不同,但勒索信的功能仍然保持了下來,包括反映阿爾巴尼亞和伊朗之間地緣政治緊張局勢的政治信息。

5.png

第一波和第二波勒索程序中的勒索信

使用Nvidia簽名證書的擦除攻擊6.png

與第二波攻擊勒索程序樣本類似,攻擊者對第二波攻擊擦除程序進行了幾次修改,可能是為了逃避檢測。變化主要有三個:

修改的惡意程序簽名;

在擦除程序中嵌入EldoS RawDisk驅動程序;

驅動安裝後自動擦除命令;

在2019年的ZEROCLEARE(ZeroCleare和惡意程序Shamoon同宗,都是出自伊朗資助的頂級黑客組織之手)和DUSTMAN(該程序以刪除設備的數據為目的,瞄準的是中東的能源和工業部門)事件中,擦除程序和原始磁盤驅動程序均沒有簽名,因此無法直接訪問原始磁盤進行快速數據擦除。因此,擦除攻擊器必須使用第三方加載器,如TDL(用於無簽名驅動程序的簽名加載器)來安裝無簽名原始磁盤驅動程序,允許擦除程序直接訪問原始磁盤,使用DeviceControl API方法擦除數據。然而,在針對阿爾巴尼亞的第一波攻擊中,攻擊者使用科威特電信公司的證書對第一波攻擊擦除攻擊進行了簽名,從而消除了對第三方加載器的需求。速度和自動化的改進讓我們想起了之前在中東的Shamoon攻擊。

由於第一波攻擊使用的擦除程序是在2022年7月被曝光的,而且可能會避免靜態檢測,攻擊者在2022年9月使用英偉達洩露的簽名證書對第二波攻擊使用的擦除程序進行了簽名,再次取消了對原始磁盤驅動程序的第三方加載器的需求。

7.png

在第一波攻擊中,擦除程序希望在執行目錄或系統目錄中找到原始磁盤驅動程序。但驅動程序並沒有被擦除,攻擊者可能用了其他方法。相反,在第二波攻擊中,攻擊者將簽名的原始磁盤驅動程序嵌入到擦除攻擊可執行文件中,先刪除它,然後安裝。此外,第二波中攻擊者使用的驅動程序似乎複製了微軟的diskdump.sys崩潰轉儲驅動程序(版本10.0.19041.682)中的元數據和一些函數,作為避免檢測的另一種方法。驅動程序安裝命令後擦除活動自動啟動,與第一波攻擊擦除攻擊不同,安裝是第一步,執行擦拭是第二步。

不過在大多數情況下,第一波攻擊和第二波攻擊的擦除程序是一樣的,包括依賴相同的身份驗證密鑰來訪問原始磁盤驅動程序,以及使用相同的DeviceControl API方法,但有一個例外,如下所示。值得注意的是,IOCTL_DISK_GET_LENGTH_INFO方法僅適用於講波斯語的APT攻擊。

8.png

我們懷疑攻擊第二波攻擊目標是阿爾巴尼亞的執法機構,因為它與2022年7月網絡攻擊浪潮中針對阿爾巴尼亞政府的網絡攻擊一致。

總結我們在本文討論了針對阿爾巴尼亞各機構的第二波勒索和擦除攻擊樣本的變化,其最終目的都是逃避檢測並造成最大損失。

除了在第二波中為逃避檢測所做的更改外,我們懷疑攻擊者需要一個自動和快速的擦除攻擊執行。在第二波攻擊中,原始磁盤驅動程序被嵌入到惡意程序中,並且在驅動程序安裝後立即啟動擦除程序,這與第一波攻擊的過程相反。

最後,對於防御者來說應從以下兩方面入手進行防禦:

監控遠程程序活動(如AnyDesk)情況,以防未經授權使用;

始終尋找和監控過期或洩露的簽名證書,因為攻擊者可以使用它們來加載和執行惡意程序。

abstract-code-1200x600.jpeg

發起網絡釣魚的攻擊者希望他們設計的虛假釣魚頁面盡可能花費最少的成本來產生盡可能多的收入,所以他們會傾向使用各種工具和技術來逃避檢測,以節省時間和成本,比如使用網絡釣魚工具包或Telegram木馬的自動化。另一種深受釣魚者歡迎的策略是攻擊網站並在其中註入惡意內容,而不是註冊新域名。除了在他們攻擊的網站中植入釣魚頁面外,攻擊者還可以竊取服務器上的所有數據,並完全攻擊網站的運行。

哪些網站最容易被攻擊者攻擊缺乏維護的網站經常會被攻擊者利用,缺乏維護和安全修復意味著它們很容易被已知的漏洞所攻擊。此外,在一個長期被忽視的網站上,網絡釣魚頁面可以停留很長一段時間,因為沒有人監控發布的內容,這正是詐騙者所尋找的。

但是,這並不意味著攻擊者不會攻擊經常維護的網站。那些訪問量很小的小型網站也會經常受到攻擊威脅。他們的所有者可能沒有能力在信息安全上花費足夠的資金或僱傭安全專業人員,他們可能不熟悉安全設置,或者他們可能相信他們的網站太小,攻擊者不會感興趣。然而,對於網絡釣魚者來說,網站是否可以被攻擊比其受歡迎程度更重要,因為詐騙頁面的鏈接很可能通過電子郵件或即時通訊平台發送。因此,即使是較小的網站也是被攻擊的目標。

根據W3Techs(一個網絡技術調查網站,提供關於互聯網不同技術的運用信息)的數據,互聯網上43.1%的網站是由WordPress內容管理系統提供支持的。有大量的第三方插件被設計用來擴展這個流行平台的功能。攻擊者經常會在插件和WordPress本身中發現新的漏洞。本文的其餘部分將處理由WordPress提供支持的攻擊者網站上的網絡釣魚頁面。

破解WordPress網站大多數時候,攻擊者通過利用安全漏洞攻擊WordPress網站。攻擊成功後,攻擊者會上傳一個WSOwebshell ,並使用它來訪問網站控制面板,從而繞過身份驗證。這將向所有人打開控制面板權限,允許任何人進行任何更改。在2023年5月,安全研究人員發現了超過350個可以開放訪問控制面板的獨特域名。也就是說,實際數量要比350高得多,因為一個受攻擊的控制面板可能不會一直被公眾訪問。

1.png

被攻擊網站的控制面板

還有一種情況是,攻擊者可能通過強制使用弱密碼或使用洩露的憑證來劫持網站管理員的帳戶。在這種情況下,他們不需要任何額外的軟件來訪問控制面板。他們所要做的就是登錄被攻擊的賬戶,然後開始發布虛假頁面。

有時,攻擊者在發佈網絡釣魚頁面時會保留網站的主要功能,這樣訪問者永遠不會意識到這個網站被攻擊客攻擊了,攻擊者則將他們的惡意內容隱藏在無法從主網站菜單訪問的新目錄中。

2.png

被攻擊網站的主頁

然而,大多數被攻擊的網站都攻擊了主頁上其他部分的鏈接,因為攻擊者刪除了原始目錄,取而代之的是網絡釣魚內容。

3.png

攻擊者網站上的釣魚頁面

如果訪問者在虛假頁面上輸入數據,如網站憑證、包括CVV在內的銀行卡詳細信息或其他個人信息,這些數據將存儲在控制面板中。如果網站也植入了web shell,則任何人都可以訪問其內容,那麼受害者的數據對任何人都是可見的。

4.png

用戶數據被盜的頁面

攻擊者可能會在暗網上出售竊取的數據,或者利用這些數據從受害者的銀行賬戶中盜取資金。此外,他們可能會利用他們收集的信息,使他們未來的騙局看起來更可信。

WordPress網站被攻擊的痕蹟有幾個相當明顯的痕跡可能表明,你正在查看一個託管在受感染網站上的網絡釣魚頁面。頁面URL包含“/wp-Config/”、“/wp-content/”、“/wp-admin/”、“/wp-includes/”等文件夾,目標目錄包含一個PHP文件。以.php為擴展名的網頁可以在合法網站上看到,但如果與上述目錄名結合使用,則肯定是網絡釣魚的標誌。

5.png

網絡釣魚頁面:URL顯示/wp-content/,頁面名稱為login.php

主頁上的內容顯然與網絡釣魚頁面無關。下面顯示的一個關於目標設備的中文網站包含一個目錄,裡面有一個針對法國銀行客戶的網絡釣魚頁面。

6.png

被攻擊的中文網站主頁

7.png

在同一網站的新目錄中有法語釣魚頁面

URL包含攻擊者試圖模仿的服務的正確(或修改過的)名稱,但該名稱與網站本身的名稱無關。

8.png

放置在“Netflix”目錄中並模仿Netflix登錄表單的網絡釣魚頁面

被攻擊WordPress網站的統計數據卡巴斯基實驗室已將被攻擊者攻擊網站的典型特徵添加到其網絡威脅檢測規則中,這樣就能夠識別和阻止這種類型的網絡釣魚。接下來所介紹的內容包含使用該新功能檢測到的網站的統計信息。

從2023年5月15日到7月31日,研究人員發現了22400個被攻擊者攻擊的WordPress網站,這些網站被用來創建網絡釣魚頁面。這一數字既包括在檢測時對控制面板開放訪問的受攻擊網站,也包括未經身份驗證的用戶無法訪問控制面板的受攻擊網站。

9.png

2023年5月15日至7月31日檢測到的被攻擊WordPress網站的數量

在同一時期,用戶共嘗試訪問受感染網站上的虛假頁面200 213次。

10.png

2023年5月15日至7月31日,試圖訪問被攻擊的WordPress網站上的釣魚頁面的次數

Netflix、銀行和流行的快遞網站經常成為被攻擊的對象。

總結經驗豐富的攻擊者通過攻擊合法網站,在其中設置網絡釣魚頁面來達到持久攻擊的目的。長期被忽視和維護的網站都可能成為攻擊目標。特別是,攻擊者傾向於攻擊一些小型網站。

由WordPress提供支持的網站通常存在漏洞,允許詐騙者使用特殊腳本輕鬆訪問控制面板並發布惡意內容。另外,攻擊者還可以暴力破解管理員的憑證或使用被盜的密碼。網站管理員應該使用強大的、唯一的密碼和多因素認證來保護他們的賬戶不被劫持,定期更新服務器軟件,並停用不使用的插件。

雖然攻擊者努力在偽造熱門網站,但用戶也可以在被攻擊的網站上識別出網絡釣魚的痕跡。特別要注意以下幾點:

马云惹不起马云URL中出現的WordPress目錄的默認名稱;

马云惹不起马云出現在其中一個目錄名稱中的仿冒名稱;

马云惹不起马云 與網站其他部分無關的頁面內容;

Laravel 是一個廣泛使用的開源PHP Web 框架。它可用於相對輕鬆地創建複雜的Web 應用程序,並在許多流行的項目中使用。

在最近對該應用程序的滲透測試中,我們獲得了對框架環境文件的訪問權限。該文件包含許多敏感的Laravel 配置設置,包括應用程序APP_KEY 。

APP_KEY 用於多個與安全相關的任務,在過去,APP_KEY的信息是獲得遠程代碼執行的可靠方法,因為它用於對(序列化的)XSRF令牌簽名。了解APP_KEY的攻擊者能夠創建惡意的XSRF令牌,然後使用已知的小工具鏈,通過不安全的反序列化(CVE-2018-15133)導致RCE。

由於Lavel 5.6.30 默認禁用cookie 序列化。因此,APP_KEY不再授予一個有保證的RCE,攻擊者需要在攻擊路徑上更有創意一點。在這篇文章中,我們會重點介紹攻擊者可以利用洩露的環境文件利用的一些替代攻擊媒介。

APP_KEY 基礎知識Laravel 期望它的環境文件.env 在應用程序的根文件夾中。該文件包含幾個Laravel 配置設置,包括APP_KEY、數據庫憑據和常規設置等機密信息。文件內容的洩露(例如通過任意文件讀取漏洞)會產生嚴重影響,因為洩露的信息可能會以多種方式被濫用。

最顯著的秘密是APP_KEY,它經常可以被濫用來獲得RCE。使用APP_KEY 的最值得注意的函數是:

1.Laravel 的默認“encrypt()”和“decrypt()”函數。如果開發人員想要加密或解密任何值或對象,那麼他們很可能會使用這些函數。它們也被用來加密Laravel的會話cookie,從而進行篡改保護。

2.Laravel 還具有創建防篡改簽名URL 的內置功能。此外,大多數簽名函數使用應用程序APP_KEY 作為機密。

3.在復雜的Web 應用程序中,你可能會看到需要對時間不敏感的任務進行排隊(例如發送提醒郵件)。這樣的任務可以通過Laravel 隊列來處理。由於隊列對象可能存儲在外部,它們也使用APP_KEY 進行簽名。

我們將簡要討論過去利用APP_KEY的方式和原因,以及當前最常用的利用方式。然後,我們將詳細討論通過Laravel隊列提供程序進行攻擊的情況,它允許攻擊者利用Laravel實例,甚至不需要APP_KEY。

Laravel隊列可以通過各種隊列提供程序實現,如Amazon SQS,Redis,local等,在我們的示例中,我們將重點討論如何利用在Amazon SQS中實現的隊列。

過去的攻擊媒介讓我們首先快速了解一下過去Laravel是如何通過不安全的反序列化被利用的。在5.6.30版本之前,Laravel默認對Laravel會話cookie進行序列化和反序列化。與許多其他語言一樣,這為反序列化攻擊打開了大門。

一旦攻擊者獲得對APP_KEY 的訪問權限,他們還可以將任意對象簽名或加密為cookie。攻擊者可以簡單地使用已知的PHP 小工具鏈(例如PHPGGC)創建一個惡意序列化對象,對惡意對象進行簽名,然後將其發送到會話cookie 的位置。 Laravel 試圖反序列化惡意製作的會話cookie,並觸發了小工具鏈的安全相關副作用(通常是RCE)。

在2018 年8 月發布的Laravel v5.6.30 之前,這種利用路徑是可能的。

負責解密cookie的代碼(Laravel 5.4)可以在以下中間軟件代碼片段中找到。中間軟件提取cookie,並將它們發送到加密器類進行解密。

1.png

乍一看,這段代碼似乎還不錯。然而,decrypt()函數有第二個默認參數unserialize=true(請參閱Laravel API 文檔),它定義了在解密過程中必須對傳遞的(加密的)值進行反序列化。

2.png

可以看到,解密後Laravel 嘗試反序列化攻擊者控制的cookie(惡意序列化對象),這會觸發PHPGGC 小工具鏈的安全相關副作用。現在cookie 處理行為已經改變,Laravel調用解密函數時無需對內容進行反序列化。這可以防止先前已知的帶有洩露APP_KEY 的簡單利用路徑:

3.png

目前的利用由於現在的利用並不那麼簡單,我們需要一些其他的攻擊媒介。

濫用其他不安全的“decrypt()”調用在理想的攻擊場景中,易受攻擊的Laravel 應用程序仍然會簡單地反序列化一個用戶控制的對象,該對象受APP_KEY 的篡改保護。當我們分析一些流行的Laravel 應用程序和擴展時,我們注意到一些開發人員犯了與Laravel 的會話cookie 相同的錯誤。因為“decrypt(…)”函數默認反序列化對象,所以開發人員很容易忽略將攻擊者控制的加密內容輸入其中,即使他們並不期望得到PHP對象。

例如,Laravel Package 的OPcache 就是這種情況,這是一個幫助開發人員處理PHP OPcache 的插件。該軟件包安裝了一個中間軟件控制器,用於處理對laravel-opcache 的所有請求。 opcache 處理程序通過提取和解密密鑰URL 參數來執行授權檢查。這是通過使用默認的“解密”函數而不禁用值的反序列化來完成的。在以下代碼片段的第13 行中,可以看到如何使用默認值$unserialize=true 解密密鑰值。

4.png

如果攻擊者知道APP_KEY ,他們可以通過以下方式利用易受攻擊的Laravel 實例:

1.創建惡意的序列化PHP對象;

2.使用洩漏的APP_KEY加密對象;

3.將有效負載發送到易受攻擊的opcache處理程序:https://

4.應用程序將嘗試不安全地解密攻擊者控制的對象。

利用Laravel 隊列以下漏洞利用路徑在Laravel 8 和Laravel 9.2.0 上進行了測試。

按照設計,Laravel 隊列需要在(外部)隊列提供程序中臨時存儲任務和對象。為了防止在靜止時被篡改,這些對象的部分簽名都是使用APP_KEY的。

在研究中,我們發現Laravel 在簽名驗證檢查之前不安全地處理隊列對象。這允許任何可以訪問配置隊列(例如AWS SQS 訪問)的攻擊者獲得遠程代碼執行,即使不知道APP_KEY。

要理解這個問題,我們需要對隊列對象結構有一個大致的了解。通常,隊列對象包含以下(對我們來說很重要)元素:

job -將作業排隊的類;

data -保存我們將執行的實際隊列命令的數據對象;

data.commandName -命令的名稱;

data.command -作為序列化對象的實際命令;

data.command.hash - data.command 的簽名,防止篡改。

5.png

命令對象包含一個哈希,它確保序列化的對像沒有被篡改。但是,由於哈希是序列化PHP 對象的一部分,因此只能在對象未序列化後執行此檢查。

因此,在執行對命令對象的非序列化調用時沒有事先進行任何驗證,這導致了不安全的反序列化漏洞。

隊列命令的不安全反序列化攻擊者可以通過將惡意作業注入Laravel 隊列來利用命令對象的不安全反序列化。

我們使用Laravel 框架本身實現了一個PoC 漏洞利用,這樣我們就可以輕鬆地重用該功能而無需大量複製粘貼。在Laravel 中,你可以使用dispatch 函數將對象分派到隊列中,如下面的代碼片段所示。

6.png

隊列對像在Illuminate 類Illuminate\Queue\Queue 中處理。此類處理隊列對象的創建,該隊列對象將被序列化並稍後發送到隊列中。出於利用目的,我們可以修復createObjectPayload() 函數。在修復的函數中,我們將合法的命令對象替換為惡意製作的序列化對象。

7.png

在示例中,我們使用了來自PHP 反序列化庫PHPGGC 的PendingBroadcast Gadget 鏈(Laravel/RCE9)。

特別是,我們使用了這個鏈,因為它在所有最近的Laravel版本中都有效,並且在鏈中使用了魔術方法__destruct。基於__toString 魔術方法的小工具鏈不起作用,因為Queue 處理程序從不將我們的惡意Queue 對像作為字符串處理,因此不會觸發這些鏈。

如果我們現在看一下作業對象,我們將在命令部分看到我們的反序列化小工具。因為我們以一種非常快速和不方便的方式替換了命令對象,所以對像沒有使用哈希簽名。然而,這無關緊要,因為一旦命令被反序列化,目標就會被利用。

微信截图_20220921100706.png

此時我們只需要等到目標處理隊列中的惡意作業即可。在此過程中,應用程序將嘗試通過從作業對像中反序列化命令對象來獲取命令對象。以下代碼片段顯示瞭如何在作業命令上調用反序列化函數。

請注意,Laravel 還允許用戶使用加密的命令對象。如前所述,加密或解密需要有效的APP_KEY 才能利用。但是,只要我們的命令以字符串O: 開頭(表示序列化PHP 對像中的“對象”),Laravel 將始終嘗試以明文形式反序列化我們的攻擊者控制的命令(第4-6 行)。

9.png

攻擊者控制的命令成功反序列化後,隊列例程繼續。稍後,Laravel 注意到命令對像沒有預期的格式。應用程序將拋出異常,然後嘗試清理無效的惡意對象。在清理過程中,我們的小工具鏈的魔術方法__destroy 被調用,攻擊者控制的命令touch /tmp\/pwnedThroughQueue 被執行。

10.webp.jpg

總而言之,Laravel 在調用對象的反序列化之前不會驗證隊列作業中的命令對象。因此,有權訪問隊列(SQS、Redis 等)的攻擊者可以在不知道APP_KEY 的示例中獲得RCE。如果攻擊者通過不公開APP_KEY 的漏洞獲得對隊列的訪問權限,則這種攻擊場景特別有趣。 (例如,隊列連接的硬編碼或易於猜測的憑據,或洩露的AWS 訪問令牌)。

利用由於隊列閉包的任意作用域此漏洞利用路徑也適用於Laravel 隊列閉包。閉包是“需要在當前請求週期之外執行的簡單任務”,它們允許攻擊者通過隊列執行任意PHP 代碼。

然而,在本例中,攻擊者需要訪問隊列和APP_KEY。如果Laravel 環境文件被公開,則通常會滿足這些條件,因為該文件包含所有必要的信息。與前面的示例不同,這種方法不依賴於反序列化,因此如果沒有可用的小工具鏈可用,它也可以工作。

如下所示,可以使用以下代碼片段將閉包分派到隊列中:

11.png

我們首先假設隊列閉包通常期望在用戶定義的類上運行,在用戶定義的作用域內,例如Podcast 類或Newsletter 類。此外,我們認為隊列閉包中的函數需要實際存在。然而,這兩個假設都是錯誤的。只要隊列關閉作業中的作用域存在,攻擊者就可以執行任意PHP 代碼。

作為概念證明,我們修改了現有的供應商類(在我們的攻擊者環境中)Illuminate\Cookie\Middleware\EncryptCookies 以包含我們的惡意sendMaliciousClosure() 函數。 EncryptCookies 類應該存在於所有Laravel 項目中,因此作用域應該始終存在。請注意,我們也可以通過反射手動更改前面提到的作業對象內的作用域。

首先,我們更改EncryptCookies 類,如以下代碼片段(第11-18 行)所示。這樣,我們定義了一個閉包,它只是調用shell_exec 來執行任意操作系統命令。然後這個閉包作為作業被分派到配置的Laravel 隊列中。

12.png

我們的惡意關閉可以通過我們自己的Laravel Artisan 命令發送,如以下代碼片段所示。請注意,我們在EncryptCookies 作用域內靜態調用函數sendMaliciousClosure。這很重要,因為此作用域也需要存在於目標應用程序中。

13.png

在作業調度期間,隊列閉包被創建並使用洩露的APP_KEY 簽名。下面我們可以看到存儲在隊列中的序列化作業。我們的SerializableClosure 可以在命令對像中找到。

當我們向隊列發送一個閉包時,所有需要的函數定義都包含在閉包中:

14.png

同樣,一旦目標應用程序檢索到隊列對象,它就會嘗試(不安全地)反序列化命令對象。完成此操作後,Laravel 使用APP_KEY 驗證哈希。驗證哈希後,Laravel 將嘗試解析作用域App\Http\Middleware\EncryptCookies。如果此作用域存在,則執行攻擊者控制的閉包或代碼。這可以立即得到驗證,因為攻擊者控制的echo 是從目標隊列工作人員的上下文中調用的。

15.webp.jpg

特別是考慮到閉包,值得一提的是,Laravel並不期望通過隊列接受什麼。開發人員唯一需要的設置是Laravel Queue的配置。一旦配置了這個隊列,Laravel就不會檢查它應該處理哪些隊列功能,而是Laravel 會嘗試處理它通過隊列提供的所有內容。該代碼不區分用於處理排隊閉包的隊列或應該只處理Newsletter 類對象的隊列。

開發工具包/測試環境為了驗證這些漏洞,我們創建了一個小型Laravel 測試和利用環境。

你可以按照以下步驟設置環境:

複製測試環境存儲庫:

16.png

手動安裝composer 依賴項(這應該不需要,但我們過去遇到了一些問題):

17.png

設置測試環境:

laravel_victim_app 和laravel_exploit_scope_app 需要有相同的APP_KEY;

laravel_queue_exploit_client_laravel_exploit_1 會有一個隨機的APP_KEY;

你可以在相應的.env 文件中編輯APP_KEY 變量;

所有三個環境文件都需要設置相同的AWS SQS。可以在此處找到有關如何設置的教程。

18.png

為了利用目標,應用程序需要監聽/工作配置的隊列。這可以使用以下命令完成:

微信截图_20220921100325.png

然後可以使用漏洞利用客戶端發送有效負載。以下命令會將作業發送到隊列中,這將利用命令的不安全反序列化:

微信截图_20220921100351.png

下一個命令將通過隊列閉包執行任意PHP 代碼:

微信截图_20220921100414.png

你將看到目標定期處理傳入隊列。成功的利用應該在目標文件系統的/tmp/目錄中創建文件:

22.png

如果你想檢查哪些代碼片段已更改,可以使用grep 查找字符串“惡意更改”(Malicious Changes),該字符串表示在客戶端中更改的代碼段。

23.png

創建惡意簽名URL另一個不太嚴重的利用場景可能是創建簽名URL。使用簽名URL,開發人員可以驗證請求的URL 是否未被篡改。這可以用於各種示例。 Laravel 在官方文檔中描述的一個示例是將簽名URL 用於“取消訂閱”鏈接。在本示例中,簽名鏈接通過驗證防篡改URL的簽名來防止用戶取消訂閱其他鏈接。

大多數示例中,與其他APP_KEY 攻擊向量相比,創建簽名URL 的影響相對較小。但是,讓開發人員依賴簽名URL 來彌補輸入驗證的不足也是可行的,例如防止SQL 注入或IDOR 漏洞。

從以下代碼示例中可以看出,簽名URL 創建過程非常簡單,可以在Laravel Artisan 命令中輕鬆創建:

24.png

總結雖然獲得對洩露的APP_KEY 的訪問權限不再是代碼執行的保證,但仍有許多攻擊場景可以將此目標存檔。

大多數示例中,洩露的APP_KEY 本身不足以利用應用程序。攻擊者總是需要額外的錯誤

2021年10月,我們的研究人員發現了一個安全漏洞,並在2021年11月舉行的Pwn2Own 2021大賽中成功利用了該漏洞。今年一月,Lexmark公司發布了該漏洞(CVE-2021-44737)的安全補丁。

最初,我們是打算以Lexmark MC3224i打印機為目標的,然而,由於該型號的打印機到處缺貨,所以,我們決定買一台Lexmark MC3224dwe打印機作為其替代品。它們的主要區別在於:Lexmark MC3224i型號提供了傳真功能,而Lexmark MC3224dwe型號則缺乏該功能。從漏洞分析的角度來看,這意味著兩者之間可能有一些差異,至少我們很可能無法利用某些功能。於是,我們下載了兩個型號的固件更新,發現它們竟然完全一樣,所以,我們決定繼續考察Lexmark MC3224dwe——反正我們也沒有選擇的餘地。

就像Pwn2Own所要求的那樣,該漏洞可被遠程利用,無需經過身份驗證,並存在於默認配置中。利用該漏洞,攻擊者就能以該打印機的root用戶身份遠程執行代碼。

關於該漏洞的利用過程,具體如下所示:

1、利用臨時文件寫入漏洞(CVE-2021-44737),對ABRT鉤子文件執行寫操作

2、通過遠程方式,令進程發生崩潰,以觸發ABRT的中止處理

3、中止處理將導致ABRT鉤子文件中的bash命令被執行

實際上,臨時文件寫入漏洞位於Lexmark特有的hydra服務(/usr/bin/hydra)中,該服務在Lexmark MC3224dwe打印機上是默認運行的。 hydra服務的二進製文件非常大,因為它需要處理各種協議。該漏洞存在於打印機工作語言(PJL)命令中,更具體地說,是在一個名為LDLWELCOMESCREEN的命令中。

我們已經分析並利用了CXLBL.075.272/CXLBL.075.281版本中的漏洞,但舊版本也可能存在該漏洞。在這篇文章中,我們將詳細介紹針對CXLBL.075.272的分析過程,因為CXLBL.075.281是在去年10月中旬發布的,並且我們一直在研究這個版本。

注意:Lexmark MC3224dwe打印機是基於ARM(32位)架構的,但這對漏洞的利用過程並不重要,只是對逆向分析有點影響。

由於該漏洞先是觸發了一個ABRT,隨後又中止了ABRT,所以,我們將其命名為“MissionAbrt”。

逆向分析您可以從Lexmark下載頁面下載Lexmark固件更新文件,但是,這個文件是加密的。如果您有興趣了解我們的同事Catalin Visinescu是如何使用硬件黑客技術來獲取該固件文件的,請參閱本系列的第一篇文章。

漏洞詳細信息背景知識正如維基百科所說:

打印機作業語言(PJL)是Hewlett-Packard公司開發的一種方法,用於在作業級別切換打印機語言,以及在打印機和主機之間進行狀態回讀。 PJL增加了作業級別控制,如打印機語言切換、作業分離、環境、狀態回讀、設備考勤和文件系統命令。

PJL命令如下所示:

@PJLSETPAPER=A4

@PJLSETCOPIES=10

@PJLENTERLANGUAGE=POSTSCRIPT眾所周知,PJL對攻擊者來說是非常有用的。過去,一些打印機曾經曝光過允許在設備上讀寫文件的漏洞。

PRET是這樣一款工具:借助於該軟件,我們就能在各種打印機品牌上使用PIL(以及其他語言),但它不一定支持所有的命令,因為每個供應商都提供了自己的專有命令。

找到含有漏洞的函數雖然hydra服務的二進製文件沒有提供符號,卻提供了許多日誌/錯誤函數,其中包含一些函數名。下面顯示的代碼是通過IDA/Hex-Rays反編譯的代碼,因為尚未找到該二進製文件的開放源代碼。其中,許多PJL命令由地址為0xFE17C的setup_pjl_commands()函數註冊的。這裡,我們對LDLWELCOMESCREEN PJL命令非常感興趣,因為它好像是Lexmark專有的,並且沒有找到相應的說明文檔。

int__fastcallsetup_pjl_commands(inta1)

{

//[COLLAPSEDLOCALDECLARATIONS.PRESSKEYPADCTRL-'+'TOEXPAND]

pjl_ctx=create_pjl_ctx(a1);

pjl_set_datastall_timeout(pjl_ctx,5);

sub_11981C();

pjlpGrowCommandHandler('UEL',pjl_handle_uel);

.

pjlpGrowCommandHandler('LDLWELCOMESCREEN',pjl_handle_ldlwelcomescreen);

.當接收到PJL LDLWELCOMESCREEN命令後,0x1012f0處的pjl_handle_ldlwelcomescreen()函數將開始處理該命令。我們可以看到,這個命令使用一個表示文件名的字符串作為第一個參數:

int__fastcallpjl_handle_ldlwelcomescreen(char*client_cmd)

{

//[COLLAPSEDLOCALDECLARATIONS.PRESSKEYPADCTRL-'+'TOEXPAND]

result=pjl_check_args(client_cmd,'FILE','PJL_STRING_TYPE','PJL_REQ_PARAMETER',0);

if(result=0)

returnresult;

filename=(constchar*)pjl_parse_arg(client_cmd,'FILE',0);

returnpjl_handle_ldlwelcomescreen_internal(filename);

}然後,0x10a200處的pjl_handle_ldlwelcomescreen_internal()函數將嘗試打開該文件。請注意,如果該文件存在,該函數並不會打開它,而是立即返回。因此,我們只能寫還不存在的文件。此外,完整的目錄層次結構必須已經存在,以便我們創建文件,同時,我們還需要具有寫文件的權限。

unsignedint__fastcallpjl_handle_ldlwelcomescreen_internal(constchar*filename)

{

//[COLLAPSEDLOCALDECLARATIONS.PRESSKEYPADCTRL-'+'TOEXPAND]

if(!filename)

return0xFFFFFFFF;

fd=open(filename,0xC1,0777);//open(filename,O_WRONLY|O_CREAT|O_EXCL,0777)

if(fd==0xFFFFFFFF)

return0xFFFFFFFF;

ret=pjl_ldwelcomescreen_internal2(0,1,pjl_getc_,write_to_file_,fd);//goeshere

if(!retpjl_unk_functionpjl_unk_function(filename))

pjl_process_ustatus_device_(20001);

close(fd);

remove(filename);

returnret;

}下面我們開始考察pjl_ldwelcomescreen_internal2()函數,但請注意,上面的文件最後會被關閉,並然後通過remove()調用完全刪除文件名。這意味著我們似乎只能暫時寫入該文件。

文件寫入原語現在,讓我們分析0x115470處的pjl_ldwelcomescreen_internal2()函數。由於使用了flag==0選項,因此,pjl_handle_ldlwelcomescreen_internal()函數最終將調用pjl_ldwelcomescreen_internal3()函數:

unsignedint__fastcallpjl_ldwelcomescreen_internal2(

intflag,

intone,

int(__fastcall*pjl_getc)(unsigned__int8*p_char),

ssize_t(__fastcall*write_to_file)(int*p_fd,char*data_to_write,size_tlen_to_write),

int*p_fd)

{

//[COLLAPSEDLOCALDECLARATIONS.PRESSKEYPADCTRL-'+'TOEXPAND]

bad_arg=write_to_file==0;

if(write_to_file)

bad_arg=pjl_getc==0;

if(bad_arg)

return0xFFFFFFFF;

if(flag)

returnpjl_ldwelcomescreen_internal3bis(flag,one,pjl_getc,write_to_file,p_fd);

returnpjl_ldwelcomescreen_internal3(one,pjl_getc,write_to_file,p_fd);//goeshereduetoflag==0

}我們花了一些時間,來逆向分析0x114838處的pjl_ldwelcomescreen_internal3()函數,以理解其內部機制。這個函數不僅很大,通過反編譯得到的代碼可讀性不是太高,但邏輯仍然很容易理解。

基本上,這個函數負責從客戶端讀取附加數據,並將其寫入前面打開的文件。

客戶端數據似乎是由另一個線程異步接收的,並保存到分配給pjl_ctx結構體的內存中。因此,pjl_ldwelcomescreen_internal3()函數每次從pjl_ctx結構體中讀取一個字符,並填充0x400字節的堆棧緩衝區。

1、如果接收到0x400字節數據,並且堆棧緩衝區已滿,則最終會將這些0x400字節寫入以前打開的文件中。然後,它重置堆棧緩衝區,並開始讀取更多數據以重複該過程。

2、如果接收到PJL命令的頁腳(“@PJL END data”),它將丟棄頁腳部分,然後將接收的數據(大小0x400字節)寫入文件,最後退出。

unsignedint__fastcallpjl_ldwelcomescreen_internal3(

intwas_last_write_success,

int(__fastcall*pjl_getc)(unsigned__int8*p_char),

ssize_t(__fastcall*write_to_file)(int*p_fd,char*data_to_write,size_tlen_to_write),

int*p_fd)

{

unsignedintcurrent_char_2;//r5

size_tlen_to_write;//r4

intlen_end_data;//r11

inthas_encountered_at_sign;//r6

unsignedintcurrent_char_3;//r0

intret;//r0

intcurrent_char_1;//r3

ssize_tlen_written;//r0

unsignedintret_2;//r3

ssize_tlen_written_1;//r0

unsignedintret_3;//r3

ssize_tlen_written_2;//r0

unsignedintret_4;//r3

intwas_last_write_success_1;//r3

size_tlen_to_write_final;//r4

ssize_tlen_written_final;//r0

unsignedintret_5;//r3

unsignedintret_1;//[sp+0h][bp-20h]

unsigned__int8current_char;//[sp+1Fh][bp-1h]BYREF

_BYTEdata_to_write[1028];//[sp+20h][bp+0h]BYREF

current_char_2=0xFFFFFFFF;

ret_1=0;

b_restart_from_scratch:

len_to_write=0;

memset(data_to_write,0,0x401u);

len_end_data=0;

has_encountered_at_sign=0;

current_char_3=current_char_2;

while(1)

{

current_char=0;

if(current_char_3==0xFFFFFFFF)

{

//getonecharacterfrompjl_ctx-pData

ret=pjl_getc(current_char);

current_char_1=current_char;

}

else

{

//apreviouscharacterwasalreadyretrieved,let'susethatfornow

current_char_1=(unsigned__int8)current_char_3;

ret=1;//success

current_char=current_char_1;

}

if(has_encountered_at_sign)

break;//exittheloopforever

//isitan'@'signforaPJL-specificcommand?

if(current_char_1!='@')

gotob_read_pjl_data;

len_end_data=1;

has_encountered_at_sign=1;

b_handle_pjl_at_sign:

//fromhere,current_char=='@'

if(len_to_write+130x400)//?

{

if(was_last_write_success)

{

len_written=write_to_file(p_fd,data_to_write,len_to_write);

was_last_write_success=len_to_write==len_written;

current_char_2='@';

ret_2=ret_1;

if(len_to_write!=len_written)

ret_2=0xFFFFFFFF;

ret_1=ret_2;

}

else

{

current_char_2='@';

}

gotob_restart_from_scratch;

}

b_read_pjl_data:

if(ret==0xFFFFFFFF)//error

{

if(!was_last_write_success)

returnret_1;

len_written_1=write_to_file(p_fd,data_to_write,len_to_write);

ret_3=ret_1;

if(len_to_write!=len_written_1)

return0xFFFFFFFF;//error

returnret_3;

}

if(len_to_write0x400)

__und(0);

//appenddatatostackbuffer

data_to_write[len_to_write++]=current_char_1;

current_char_3=0xFFFFFFFF;//resettoenforcereadinganothercharacter

//atnextloopiteration

//reached0x400bytestowrite,let'swritethem

if(len_to_write==0x400)

{

current_char_2=0xFFFFFFFF;//resettoenforcereadinganothercharacter

//atnextloopiteration

if(was_last_write_success)

{

len_written_2=write_to_file(p_fd,data_to_write,0x400);

ret_4=ret_1;

if(len_written_2!=0x400)

ret_4=0xFFFFFFFF;

ret_1=ret_4;

was_last_write_success_1=was_last_write_success;

if(len_written_2!=0x400)

was_last_write_success_1=0;

was_last_write_success=was_last_write_success_1;

}

gotob_restart_from_scratch;

}

}//endofwhile(1)

//wereachhereifweencounteredan'@'sign

//let'scheckitisavalid'@PJLENDDATA'footer

if((unsigned__int8)aPjlEndData[len_end_data]!=current_char_1)

{

len_end_data=1;

has_encountered_at_sign=0;//resetsowereaditagain?

gotob_read_data_or_at;

}

if(len_end_data!=12)//len('PJLENDDATA')=12

{

++len_end_data;

b_read_data_or_at:

//willgobacktothewhile(1)loopbutexitatthenext

//iterationdueto'break'andhas_encountered_at_sign==1

if(current_char_1!='@')

gotob_read_pjl_data;

gotob_handle_pjl_at_sign;

}

//wereachhereifall'PJLENDDATA'wasparsed

current_char=0;

pjl_getc(current_char);//read'\r'

if(current_char=='\r')

pjl_getc(current_char);//read'\n'

//writealltheremainingdata(len0x400),exceptthe'PJLENDDATA'footer

len_to_write_final=len_to_write-0xC;

if(!was_last_write_success)

returnret_1;

len_written_final=write_to_file(p_fd,data_to_write,len_to_write_final);

ret_5=ret_1;

if(len_to_write_final!=len_written_final)

return0xFFFFFFFF;

returnret_5;

}位於0xFEA18處的pjl_getc()函數,用於從pjl_ctx結構體中

JSON 語法自2012 年開始作為新特性被各類SQL 數據庫支持,目前所有主流數據庫都已支持JSON 語法,但目前的主流WAF並沒有做相應跟進,從而可以被繞過。

Team82開發了一種通用的繞過行業領先的web應用程序防火牆(WAF)的方法。 攻擊技術包括將JSON語法附加到WAF無法解析的SQL注入有效負載。

主要的WAF供應商在他們的產品中缺乏JSON支持,儘管大多數數據庫引擎已經支持了十年。 大多數WAF可以很容易地檢測到SQLi攻擊,但是將JSON前置SQL語法使WAF無法檢測到這些攻擊。

使用這種技術的攻擊者將能夠繞過WAF的保護,並使用其他漏洞來竊取數據。

簡介Web應用防火牆(WAF)旨在保護基於Web的應用程序和API免受惡意外部HTTPs流量的影響,尤其是跨站腳本和SQL注入攻擊,這些攻擊危險似乎還未解除。

WAF的引入在很大程度上是為了應對這些編碼錯誤。 WAF現在是保護存儲在數據庫中的組織信息的關鍵防線,這些信息可以通過web應用程序訪問。 WAF也越來越多地用於保護基於雲的管理平台,這些管理平台監督連接的嵌入式設備,如路由器和接入點。

能夠繞過WAF的流量掃描和攔截功能的攻擊者通常可以直接訪問敏感的業務和客戶信息。值得慶幸的是,這樣的繞過並不常見,而且針對特定供應商的實現是一次性的。

目前,Team82引入了一種攻擊技術,它是業界領先供應商銷售的多個web應用程序防火牆的第一個通用繞過。該繞過適用於五個主要供應商銷售的WAF: Palo Alto, F5, Amazon Web Services, Cloudflare和Imperva。目前,所有受影響的供應商都承認Team82的披露,並實施了修復,將JSON語法支持添加到其產品的SQL檢查過程中。

Team82的技術首先依賴於理解WAF如何識別和標記惡意SQL語法,然後找到WAF看不到的SQL語法。這是JSON。 JSON是一種標準的文件和數據交換格式,通常用於將數據從服務器發送到web應用程序。

在SQL數據庫中引入JSON支持可以追溯到大約10年前。現在的數據庫引擎默認支持JSON語法、基本搜索和修改,以及一系列JSON函數和操作符。雖然JSON支持是數據庫引擎的標準,但WAF卻並非如此。供應商在添加JSON支持方面一直進展緩慢,這使得Team82能夠創建新的SQL注入有效負載,其中包括繞過WAF提供的安全性的JSON。

使用這種新技術的攻擊者可以訪問後端數據庫,並使用額外的漏洞,通過直接訪問服務器或通過雲竊取信息。

這對於已經轉向基於雲的管理和監控系統的運行和物聯網平台尤為重要。 WAF提供了來自云的額外安全性的承諾,能夠繞過這些保護的攻擊者可以廣泛地訪問系統。

Team82在去年開發了這項技術,當時他們正在對Cambium Networks的無線設備管理平台進行不相關的研究,包括其內部或云端銷售的cnMaestro無線網絡管理器。

1.png

Cambium Networks無線接入點

2.png

Cambium的cnMaestro雲架構允許用戶從雲端遠程配置和控制他們的AP Wi-Fi設備

為了了解平台是如何構建的,以及它的許多內部API和路由,Team82從Cambium的網站下載了cnMaestro內部部署的開放虛擬化格式虛擬機。

Team82了解到cnMaestro是由許多不同的NodeJS後端服務構建的,這些服務處理用戶對特定路由的請求。這些服務都有輕微的混淆,使得研究平台變得困難。為了將每個請求代理到正確的服務,Nginx被用來通過所請求的URL來傳遞請求。

cnMaestro提供了兩種不同的部署類型:

本地部署:創建一個由用戶託管和管理的專用cnMaestro服務器。

雲部署:位於Cambium Networks雲基礎設施上的cnMaestro服務器,cnMaestro的所有此類實例都以多租戶架構託管在Cambium組織下的Amazon AWS雲上。

雲部署託管在亞馬遜AWS上的cnMaestro雲部署包括一個cnMaestro的主要實例(託管在https://cloud.cambiumnetworks.com上),它處理登錄、設備部署,並將大部分平台數據保存在主數據庫中。

任何註冊到cnMaestro Cloud應用程序的用戶都會獲得一個個人Amazon AWS實例,其中包含個人URL (Cambium主雲的子域)和組織標識符。這有助於在多租戶設計中分離不同的用戶。為了訪問你的cnMaestro實例,將按照以下方案生成一個唯一的URL:https://us-e1-sXX-XXXXXXXXXX.cloud.cambiumnetworks.com

在Team82對Cambium cnMaestro的研究結束時,他們發現了7個不同的漏洞,可以在這里和Team82的披露儀表板上看到。然而,一個特別的漏洞讓Team82陷入了一個巨大的兔子洞,導致Team82發現並開發了這項新技術。

很難利用的零日漏洞Team82發現的一個特殊的Cambium漏洞被證明更難利用:CVE-2022-1361。該漏洞的核心是一個簡單的SQL注入漏洞,但實際的開發過程需要Team82跳出思維定式,創建一個全新的SQL技術。利用這個漏洞,Team82能夠竊取用戶的會話、SSH密鑰、密碼哈希、令牌和驗證碼。

此漏洞的核心問題是,在這種特殊情況下,開發人員沒有使用準備好的語句將用戶提供的數據附加到查詢中。他們沒有使用將用戶參數附加到SQL查詢並清除輸入的安全方法,而是直接將其附加到查詢中。

3.png

Team82在CVE-2022-1361中濫用的SQL注入匯點

正如我們在上面的匯點中看到的,應用程序接受用戶提供的數據(在本例中為a.serialNo或a.mac),並將其附加到SQL查詢中。我們使用此漏洞的目的是過濾存儲在數據庫中的敏感數據。然而,雖然這看起來很簡單,但在快速分析了該漏洞後,我們意識到它有三個關鍵漏洞/限制:

Team82只能檢索作為返回行的整數;

返回的行按隨機順序返回;

在每個請求中,Team82只能返回有限數量的行。

讓我們深入分析這些限制。

限制1:Team82只能檢索整數第一個限制只返回整數,而不返回字符串。由於原始請求返回整數,我們將使用的任何联合語句也必須返回整數。在SQL中,如果執行聯合操作,則必須確保兩列的類型相同,並且由於一方獲取整數,因此我們也必須返回整數。由於我們要過濾的數據很可能是字符串(會話令牌、SSH密鑰等),因此我們必須以某種方式獲得過濾字符串的能力。

通過將想要過濾的任何字符串轉換為整數數組,並將每個字符作為單獨的行返回,可以輕鬆克服這一限制。為此,Team82使用了stringarray和ASCIISQL函數。

4.1.png

4.2.png

一個SQL查詢,返回字符串作為其字符的整數列表

限制2:返回的行按隨機順序返回第二個限制是,當Team82返回多行時,web服務器將以隨機順序返回給Team82。當Team82查看漏洞後執行的代碼時,Team82看到對於SQL查詢返回的每一行,服務器將執行一些其他異步操作(這可以通過調用async.parale函數看到)。這意味著返回行的原始順序將不會被保留,相反,該順序將是異步操作完成的順序。

這意味著,如果Team82將字符串作為整數數組進行過濾,就會丟失字符順序,從而使過濾變得無關緊要。

Team82通過添加行索引來克服這一限制,行索引使用row_number SQL函數將字符串中字符的索引轉換為返回的整數。因為Team82只返回ASCII字符,所以每個字符的值被限制為128。通過將索引號乘以1000 (i * 1000)並將其附加到結果中,Team82總是可以通過簡單的除法和模塊操作來確定字符索引。

5.1.png

5.2.png

一個SQL有效負載,返回字符串中每個字母的ascii值,加上字符的索引乘以1000

在檢索到過濾的數據之後,Team82可以簡單地將每個返回行除以1000,以了解字符索引。 Team82還可以通過對返回值使用模塊操作來恢復原始字符ASCII值。

限制3:在每個請求中只能返回有限數量的行最後一個限制是最難克服的:超時問題。對於返回的每一行,服務器都執行了一些其他操作,包括另一個SQL查詢和數據操作。當我們試圖檢索大量行時,請求超時。更糟糕的是,API端點相當慢,因此每次檢索一行非常耗時。

Team82的解決方案實際上非常高級,Team82不是為每個字符返回一行,而是從許多行中構造一個整數。這是可能的,因為整數和字符之間的字節大小不同。在PostgreSQL中,一個整數是4字節長,而Team82試圖過濾的字符是1字節長(只要是ascii字符)。這意味著通過執行簡單的字節操作,Team82可以在每個整數中容納四個不同的字符。此外,如果Team82在union命令中將整數轉換為BIGINT,這在PostgreSQL中是可能做到的,Team82可以將每行擴展為8字節。

6.png

PostgreSQL類型大小

這意味著,如果要為Team82過濾的每個字符附加8個字節,並將其附加到BIGINT中,Team82可以在每個請求中過濾7倍多的字符(1個字節保留給字符索引)。

7.1.png

7.2.png

一個SQL查詢,它接受一個字符串,並每隔幾個字符創建一個BIGINT

使用這種方法,Team82能夠在每個請求中提取多達8倍的數據。這減少了Team82竊取大量數據所需的時間,並使攻擊場景變得可信。

構建有效負載在Team82繞過所有三個限制之後,Team82就得到了一個大的有效負載,允許提取任何Team82選擇的數據:

8.png

事實上,當Team82使用這個有效負載時,Team82設法竊取了存儲在數據庫中的敏感信息,從會話cookie到令牌,SSH密鑰和哈希密碼。

9.png

使用SQLi有效負載提取的數據示例

雲端漏洞在成功利用了雲部署漏洞後,下一步是在Cambium的雲端嘗試相同的漏洞。很快,Team82就找到了相應的雲路由,並成功確認它也容易受到同樣的漏洞的攻擊。然後Team82嘗試了一個安全版本的有效負載,並收到了這樣的響應。

10.png

對SQL注入漏洞的響應,可以看到Team82的請求被釋放了,返回一個403 Forbidden

接下來,我們注意到了包含awselb/2.0的HTTP服務器,這意味著,應用程序並沒有停止Team82的請求,而是AWS WAF釋放了Team82的請求,因為它可能將其標記為惡意請求。

對AWS WAF的研究為了研究AWS WAF,我們首先創建了自己的設置,在其中控制所有的活動部件:應用程序、客戶端和WAF設置和日誌。我們在AWS雲上創建了一個簡單的設備,並設置了AWS WAF來保護應用程序免受惡意請求(Team82設置了WAF)。

11.png

用於配置WAF規則集的界面

然後,Team82創建了一個帶有SQLi漏洞的web應用程序,並將其託管在AWS上。

12.png

Team82創建的易受攻擊的Flask web應用程序

最後,Team82開始發送數百個自定義的請求,試圖分析WAF是如何將請求標記為惡意的。

13.png

被WAF標記為惡意的請求被阻止,在這個請求中,Team82傳遞一個通用的SQLi有效負載,它由WAF標記

WAF通常有兩種方法將請求標記為惡意:

搜索黑名單單詞:WAF可以搜索它並將其識別為SQL語法的單詞,如果請求中存在太多匹配項,它會將該請求標記為惡意SQLi嘗試。

從請求中解析SQL語法:WAF可以嘗試使用請求的不同部分解析有效的SQL語法,如果WAF成功識別SQL語法,它將標記該請求為惡意SQLi嘗試。

雖然大多數WAF除了使用WAF特有的方法外,還會使用這兩種方法的組合,但它們都有一個共同的漏洞:它們需要WAF識別SQL語法。這引發了Team82的興趣:如果Team82能夠找到WAF無法識別的SQL語法,該怎麼辦?

SQL JSON目前,JSON已經成為數據存儲和傳輸的主要形式之一。為了支持JSON語法,並允許開發人員以類似於在其他應用程序中與數據交互的方式與數據交互,SQL中需要JSON支持。

目前,所有主要的關係數據庫引擎都支持原生JSON語法,這包括MSSQL, PostgreSQL, SQLite和MySQL。此外,在最新版本中,所有數據庫引擎默認啟用JSON語法,這意味著它在今天的大多數數據庫設置中很普遍。

開發人員選擇在SQL數據庫中使用JSON特性,原因有很多,首先是更好的性能和效率。由於許多後端已經使用JSON數據,因此在SQL引擎本身執行所有數據操作和轉換可以減少所需的數據庫調用數量。此外,如果數據庫可以使用JSON數據格式(後端API很可能也會使用JSON數據格式),那麼所需的數據預處理和後處理就會更少,從而允許應用程序立即使用它。

通過在SQL中使用JSON,應用程序可以在SQL API中獲取數據、從數據庫中組合多個數據源、執行數據修改並將其轉換為JSON格式。然後,應用程序可以接收json格式的數據並立即使用它,而不需要處理數據。

14.png

在SQL中使用JSON的數據流,允許開發人員在SQL中使用JSON API更好地與數據交互

雖然每個數據庫都選擇了不同的實現和JSON解析器,但每個數據庫都支持不同範圍的JSON函數和操作符。此外,它們都支持JSON數據類型和基本的JSON搜索和修改。

15.png

對每個主要數據庫的JSON支持級別

然而,儘管所有的數據庫引擎都增加了對JSON的支持,但並不是所有的安全工具都增加了對這個“新”特性的支持。安全工具中缺乏支持可能會導致安全工具(在Team82的例子中是WAF)和實際數據庫引擎之間的原語解析不匹配,並導致SQL語法錯誤識別。

The New ‘ or ‘a’=’a

使用JSON語法,可以創建新的SQLi有效負載。由於這些有效負載不為人所知,它們可以繞過許多安全工具。使用來自不同數據庫引擎的語法,Team82能夠在SQL中編譯以下真實語句列表:

16.png

使用JSON語法

從Team82對WAF如何將請求標記為惡意的理解中,可以得出結論,Team82需要找到WAF無法理解的SQL語法。如果Team82可以提供一個SQLi有效負載,WAF不會將其識別為有效SQL,但數據庫引擎會解析它,Team82實際上就可以實現繞過。

事實證明,JSON正是WAF解析器和數據庫引擎之間的這種不匹配。當Team82傳遞使用不太流行的JSON語法的有效SQL語句時,WAF實際上並沒有將請求標記為惡意請求。

17.png

下面是一個惡意的SQLi有效負載,包含JSON語法。正如Team82所看到的,WAF並沒有將該請求標記為惡意請求,也沒有釋放它

這個簡單的JSON運算符,在本例中是@,它檢查右邊的JSON是否包含在上面左邊的JSON中,它將WAF放入一個循環中,並允許Team82提供惡意的SQLi有效負載,從而允許Team82繞過WAF。通過簡單地在請求的開頭預先添加簡單的JSON語法,Team82就能夠在雲上使用SQLi漏洞竊取敏感信息!

18.png

利用雲上的SQL注入漏洞

常見的WAF繞過上述繞過的核心問題是數據庫引擎和SQLi檢測解決方案之間缺乏一致性,這是因為SQL中的JSON並不是一個流行和廣為人知的特性,而且它的語法沒有添加到WAF解析器中。

然而,Team82認為這個問題可能不僅僅與這個WAF供應商有關,可能其他供應商也沒有添加對JSON語法的支持。所以Team82採用了易受攻擊的web應用程序,並在大多數主要WAF供應商上創建了一個設置。幾天后,Team82發現JSON語法可以繞過他們檢查過的大多數供應商:

Palo-Alto下一代防火牆

F5 Big-IP

Amazon AWS ELB

Cloudflare

Imperva

19.png

Team82使用JSON語法繞過的WAF供應商和產品列表

Team82成功地繞過了這麼多大型WAF產品,如果Team82的有效負載有任何變化,這意味著Team82有一個通用的WAF繞過。這意味著即使不知道Team82和目標之間的WAF是什麼,Team82仍然可以利用SQL注入漏洞,繞過WAF的保護。

自動化流程為了研究這種WAF繞過的危害有多大,Team82決定在最大的開源開

ghostbuster.png

當你在AWS上部署基礎設施時,你可以啟動EC2實例,這些實例有一個與它們相關的IP。當你創建指向這些IP的DNS記錄,但在EC2實例被賦予一個新IP或被銷毀後忘記刪除DNS記錄時,你很容易受到子域劫持攻擊。

研究人員已經創建了一個名為Ghostbuster的工具,它的工作原理是枚舉與你擁有的每個AWS 賬戶關聯的所有彈性/公共IP,然後檢查是否有任何DNS 記錄指向你不擁有的任何彈性IP AWS 賬戶。請務必注意,此工具要求你完全覆蓋你的AWS 賬戶,以避免誤報。

關於如何設置和使用該工具的進一步說明可以在Github repo的README文件中找到。

在過去的十年裡,很多公司都切實採用了AWS、Azure和GCP等雲服務提供商,快速構建基礎設施,以滿足不斷增長的業務需求。遷移到雲原生架構給採用它的組織帶來了許多挑戰,從雲攻擊面的可見性到雲特定的安全漏洞。

雖然主要的雲服務提供商確實提供了許多安全方面的好處,但當涉及到安全時,它們都是在“共享責任”的模式下運行的。研究人員已經在AWS中看到了大量的配置錯誤漏洞,包括Route53 劫持、Cloudfront 劫持、ELB 劫持,以及現在的Elastic IP 劫持。這些錯誤配置被認為是屬於共享責任模型的客戶方,雖然AWS最終在其平台上部署了Route53、Cloudfront和ELB劫持的緩解措施,但這些漏洞被利用了好幾年。

值得注意的是,AWS並不是唯一一個在這些漏洞上存在漏洞的公司,微軟Azure和谷歌云平台在其基於雲的產品中也面臨著這一漏洞,許多其他雲提供商也是如此。

隨著雲攻擊面的快速擴展和流動性的增加,很難獲得對這些風險的可見性,尤其是在規模上。再加上雲提供商在部署緩解他們認為應該是共享責任模型中客戶方面的漏洞時行動緩慢,許多組織都在努力控制這些錯誤的配置漏洞。

為此安全公司Assetnote開源一個名為Ghostbuster的工具,Ghostbuster 是一款自動化瀏覽器測試工具,基於phantomjs,意味著你得到一個真正的瀏覽器,一個真正的DOM,仿真測試環境,可用於修復AWS環境中潛在的懸掛彈性IP(dangling elastic IP)漏洞。

什麼是懸掛彈性IP漏洞?當你將基礎設施部署到AWS 時,你可能會啟動具有關聯IP 的EC2 實例。當你創建指向這些IP 的DNS 記錄,但在EC2 實例被賦予新IP 或被銷毀後忘記刪除DNS 記錄時,你很容易受到子域劫持攻擊。

關於彈性IP劫持已經做了大量的研究,攻擊者可能會不斷地聲稱彈性IP,直到他們獲得與目標公司的子域名相關聯的IP。

雖然AWS經常會禁止試圖執行這種攻擊模式的賬戶,但AWS還沒有發布修復方案。

懸掛彈性IP子域劫持攻擊的影響比典型的子域劫持更嚴重,在子域劫持中,你只能控制所服務的內容。通過懸掛的彈性IP劫持,攻擊者可能還會進行如下操作:

通過ACME TLS 質詢為子域申請SSL 證書;

監聽所有端口上的流量(可能發現敏感信息仍在發送到子域);

運行具有竊取HTTPOnly cookie 能力的服務器端腳本,當cookie 範圍為*.domain.com 時,通常會導致一鍵式帳戶劫持攻擊;

研究人員並不是第一個注意到這個漏洞的人,最早關於彈性IP劫持的文章可以追溯到2015年,作者是Matthew Bryant。

自2015年以來,許多人嘗試了與Matthew類似的解決方案,他們堅持使用彈性IP分配和釋放的方法,直到他們找到目標公司使用的彈性IP。

其他PoC包括EIP Fish和Flying a False Flag - Cloud Racoon。

值得注意的是,一些漏洞賞金獵人對懸掛彈性ip的漏洞進行了大量研究。除了通過漏洞獎勵計劃或購買像安全平台(能夠主動檢測此漏洞)這樣的產品的公司之外,對於這些攻擊,研究人員唯一的保護措施就是AWS禁止他們認定的執行彈性IP劫持的賬戶。不幸的是,禁止賬戶並不是一個可行的解決方案。

AWS是如何處理這個漏洞的?研究人員已經與AWS的各個團隊就這個漏洞進行了多次討論,並試圖構建工具,以幫助該企業找到並緩解懸掛彈性IP劫持。

從歷史上看,AWS採取的方法是將這種行為有效地視為對其公共API 的濫用,並簡單地禁止那些分配或釋放彈性IP 過快的賬戶,或者AWS認為是濫用的模式。雖然這在一定程度上(特別是在規模上)提高了攻擊的門檻,但這並不是有效的長期緩解根本漏洞的辦法。

AWS表示,他們正在努力緩解這一漏洞,但這項緩解措施的具體細節和實施表仍不清楚。

就目前而言,這些技術仍然可行。

使用Ghostbuster緩解Ghostbuster是一款自動化瀏覽器測試工具,基於phantomjs,意味著你得到一個真正的瀏覽器,一個真正的DOM,仿真測試環境。

這個漏洞普遍存在,受此攻擊載體影響的組織數量不斷增加,因為公司繼續將更多的服務遷移到公共雲,特別是AWS。在關閉EC2實例後沒有刪除DNS記錄,這是一個很容易被引用的漏洞,並且由於自動配置而變得更加嚴重。

在AWS發布任何官方修復之前,研究人員建議你查看其新發布的開源工具Ghostbuster,它可以用來檢測潛在的懸掛彈性ip。

你可以通過運行:pip3 install ghostbuster 來安裝該工具,然後通過使用ghostbuster 命令來使用該工具。

該工具的工作原理是枚舉與你擁有的每個AWS帳戶相關的所有彈性/公共ip,然後檢查是否有任何DNS記錄指向你的任何AWS帳戶中不擁有的彈性ip。需要注意的是,該工具要求你完全覆蓋你的AWS帳戶,以避免誤報。

該工具對用戶非常友好,並使用你的.aws/config和.aws/憑據文件來遍歷每個配置的帳戶並執行處理。

此外,如果你使用Cloudflare 而不是Route53 來管理你的DNS,該工具還與Cloudflare 集成,以提取區域和關聯的DNS 記錄以進行分析。

如果你不使用Route53或Cloudflare來管理你的DNS區域,你可以向該工具(CSV)提供手動輸入。也可以配置Slack的webhook,以便該工具在檢測到潛在的劫持時發送通知。

該工具的設計方式使其可以頻繁地作為cron 作業運行,從而通知你隨時可能出現的潛在彈性IP劫持。

使用該工具時可以使用以下選項:

1.png

該工具的輸出如下所示:

2.png

關於如何設置和使用該工具的更多說明可以在我們的Github repo for Ghostbuster中的README 文件中找到。

總結大規模管理雲架構的安全性可能很困難,公司在EC2資源被破壞後留下DNS記錄是非常普遍的。

與僅能控制頁面內容的典型子域劫持攻擊不同,彈性IP劫持的風險要高得多,攻擊者能夠聲稱SSL證書,偵聽流量,並在海量cookie範圍的情況下執行帳戶劫持攻擊。

AWS 的預期緩解措施的細節及其發布的時間表仍不清楚。與此同時,你可以使用Ghostbuster在AWS環境中獲取懸掛的彈性ip。

在本文中,我們將介紹如何使用Frida繞過一些應用程序實現的反調試技術的實際示例。

FridaFrida是一個動態代碼檢測工具包。換句話說,它是一組允許代碼插裝的工具,提供給我們一些API,使我們能夠在執行過程中攔截、分析和修改Windows、macOS、GNU/Linux、iOS、Android和QNX應用程序的部分代碼。本質上,Frida允許在運行時對即將執行的操作進行操作。比如,當我們從一個簡單的c++程序開始,該程序使用一個函數將兩個值相加並返回結果。我們想要操作的函數聲明為Add(int,int)。首先,我們將更改其中一個int參數,然後,更改返回的結果。編譯完代碼後,我們需要通過分析可執行代碼來定位Add函數的偏移量。在本例中,我們使用IDA Pro來分析代碼,但也可以使用允許我們分析可執行代碼的任何其他方法或應用程序。我們在偏移量0x00401000處確定函數,並且我們知道可執行文件的基址是0x00400000,因此,函數的偏移量是0x00001000。

1.jpg

然後,我們可以攔截函數調用並使用Frida修改其行為。我們將開發一個小Javascript腳本來完成這項工作。首先,我們需要確定程序在執行時被加載的位置、它的基址,然後,我們可以通過將這個基址和之前獲得的偏移量(base +0x00001000)相加來定位Add函數的偏移量。現在,我們可以使用帶有函數地址的Interceptor來在函數執行之前或之後添加一些代碼。我們使用Frida Javascript API 來完成這一切。

2.jpg

因此,當我們以' 1 '和' 2 '作為參數執行應用程序時,我們期望結果是' 1 + 2=3 '。但是,如果我們取消註釋第一行(args[0]=ptr(' 100 ');)在函數執行之前,我們將變量op1的值替換為100,得到的結果為' 1 + 2=102 '。另一方面,如果取消註釋第二行(retval.replace(' 3210 ')) ,我們會在函數Add 執行之後但在返回結果之前替換返回值,得到'1 + 2=3210'。

3.jpg

基於系統調用的技術在這個檢測結果中,我們考慮使用Windows API的函數來獲取與調試器存在相關的信息的技術。有很多函數可以用於這個目標:從像IsDebuggerPresent這樣的函數,它返回一個布爾值,這個值取決於應用程序是否被調試(True或False),到像FindWindow這樣的函數,它告訴我們是否存在一個帶有知名調試器(IDA、Ollydbg、Inmunity 調試器等)名稱的窗口。

基於內存檢查的技術應用程序對內存中的某些標誌進行顯式驗證的方法,這些標誌顯示進程是否正在調試。可以用於此目的的一些標誌是IsDebugged 標誌、Heap標誌或NTGlobalFlag。這些標誌是Windows 為每個進程維護的結構的成員,其中包含有關它們的信息。

基於時間的技術這個檢測結果包括使用與時間相關的計算來確定是否正在調試進程的方法,當一個進程正在被調試時,執行同一組指令所花費的時間要比未被調試時多。這種時差通常是很明顯的。出於這個原因,應用程序可以檢查一組指令執行開始和結束的時間,如果它花費的時間超過一個既定的閾值,它可以很有可能確定該過程是正在調試。

基於異常的技術最後,我們根據觸發異常對一組方法進行分組,以確定進程是否正在被調試。在調試進程和未調試進程時,系統處理異常的方式是不同的。程序可以利用這一事實來確定是否附加了調試器。

設置測試環境為了實現我們的設置,我們將使用Windows 10虛擬機,我們最初將在其中安裝Python 3.8.6rc1。

然後我們安裝Frida,它可以直接從GitHub下載,或者使用Python pip工具安裝。我們使用pip是因為它比其他方法更簡單。

4.jpg

我們還安裝了Visual Studio Community 2019來開發示例程序,在示例程序中我們實現了一些反調試技術來展示它是如何工作的。這些程序將被用來測試繞過這些反調試技術的不同方法。 Frida 的使用方式有很多種:我們可以直接使用包中包含的可執行文件(每個可執行文件都有特定的功能),也可以使用包中也包含的Python 模塊來開發我們自己的接口。

我們選擇了第二種方法,開發了一個小接口,允許我們生成新的進程或附加到現有進程中,注入一個或多個提供某些功能的腳本。我們選擇這種方式是因為我們希望能夠根據特定的需求定制接口,這些需求將在以後的文章中詳細介紹。

接下來,我們將討論基於以下系統調用的技術:IsDebuggerPresent、NtQueryInformationProcess 和CreateToolhelp32Snapshot。所有這些都使我們能夠了解如何以不同的方式使用Frida,以繞過這些控制。

IsDebuggerPresent我們將嘗試繞過的第一個檢查是基於系統調用IsDebuggerPresent 的方法。正如Microsoft 文檔中所指出的,此函數不接收任何參數,並根據進程是否正在調試返回一個布爾值:返回值“True”表示正在調試進程,“False”表示相反。為了說明這個方法,我們開發了一個使用這個系統調用執行調試檢測的簡單程序:

5.png

在第一個控制台中,我們看到當我們從Visual Studio執行應用程序時,應用程序如何指示它正在被調試。但是,如果應用程序是直接從終端執行的,則表明它沒有被調試。檢查這個事實的另一種方法是從像x64dbg 這樣的調試器中執行它。唯一用來做決定的是函數IsDebuggerPresent 返回的值,因此,我們應該用Frida 開發一個腳本,攔截這個調用並修改返回值,總是返回False (0x0)。下面的腳本是為了完成所有這些而開發的:

首先,它使用Module.findExportByName(第3 行)定位函數“IsDebuggerPresent”的地址。

一旦獲得這個地址,它就會使用Interceptor.attach(.) 攔截這個調用(第8 行)。

最後,它在函數結束之前(第13 行)將返回值替換為0x0 (False)。

6.png

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 獲取父進程的名稱,並將其與眾所周知的調試器名稱列表進行檢查。

7.png

如上所述,我們開發了一個小型C++ 應用程序,展示了這種技術的一個示例。為了逃避這些檢查,我們必須使用Frida 開發一個必須執行以下操作的腳本:

首先,它必須使用Module.findExportByName 定位函數“NtQueryInformationProcess”的地址。

然後,它必須使用Interceptor.attach(.) 攔截函數調用。

每次調用函數“NtQueryInformationProcess”(OnEnter)時,腳本必須執行以下操作:

保存參數ProcessInformationClass,允許我們選擇必須修改哪些返回信息(第40 行)。

保存指向返回參數ProcessInformation 的指針(第44、48、52 和57 行)。

還要保存每種情況下所需的參數。

8.png

最後,就在函數結束之前(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。

9.png

要使用Frida 獲取進程“explorer.exe”的PID,我們可以使用Windows API 調用,例如函數GetShellWindow 和GetWintowThreadProcessId。我們可以使用NativeFunction del API de Frida 通過Javascript 聲明這些函數,一旦它們被聲明,我們就可以使用它們來獲取進程PID,如下所示:

10.png

使用Visual Studio調試器執行這個示例程序,我們得到如下結果:

11.png

如果我們使用相同的調試器執行相同的應用程序,但注入之前描述的Frida 腳本,我們會得到另一個結果:

12.png

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):

驗證列出的所有線程都有一個相關聯的進程,試圖檢測隱藏的進程;

驗證應用程序線程數;

驗證我的應用程序中沒有引用禁止模塊的任何線程。

13.png

可見,使用此函數的應用程序可以驗證必須在它們之間保持一致的不同內容。因此,要繞過這些檢查,我們的任務必須是找到一種變通方法,允許我們繞過所有這些檢查,並保持列表的一致性。帶著這個目標,我們研究了這個函數究竟返回了哪些信息,以及我們如何操作它。

函數CreateToolhelp32Snapshot 返回一個SECTION 類型的HANDLE。如果我們分析HANDLE 指向的內存部分,我們可以找到一個未記錄的結構,其中包含以下部分:

14.png

我們可以使用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 來獲取此信息。將此查詢獲得的信息與與禁止模塊關聯的內存進行比較,我們可以確定是否應該從列表中刪除線程。

15.png

本文介紹了在Chrome、Edge和Safari中實現可靠的DNS重綁定的新技術,並討論了繞過本地網絡限制的技術。通過分析慢緩存的根本原因,提出了新的解決技術。本文研究了利用DNS重綁定在Chrome、Edge和Safari中實現瞬間DNS重綁定的攻擊技術。

本文是關於DNS重新綁定係列文章中的第二篇。第一篇文章介紹了一個使用DNS重新綁定後攻擊的案例。在這篇文章中,我介紹了在IPv6可用時在Chrome, Edge和Safari中實現可靠的,瞬間DNS重新綁定的新技術,以及一種繞過本地網絡限制的技術,該技術適用於基於Chrome的瀏覽器的獲取API。

瀏覽器中的DNS重綁定傳統上被視為攻擊者通過誘騙受害者加載惡意網站來訪問內部網絡服務的一種方式,但隨著許多現代web應用程序現在在其部分功能上驅動無頭瀏覽器,它已成為攻擊web應用程序的有用工具。無頭瀏覽器,即Headless Browser,是一種沒有界面的瀏覽器。它擁有完整的瀏覽器內核,包括JavaScript 解析引擎、渲染引擎等。與普通瀏覽器最大的不同是,無頭瀏覽器執行過程中看不到運行的界面,但是我們依然可以用GUI 測試框架的截圖功能截取它執行中的頁面。在上一篇文章中,我介紹了一個使用可能是最簡單的重新綁定方法的例子。在這種情況下,我有很長的時間讓漏洞運行,但這在許多web應用程序中不太可能,需要更快的技術。

緩慢的緩存簡單的DNS重綁定技術依賴於對相同主機名的連續查找返回不同的DNS記錄。對於這些攻擊,所花費的最小時間是瀏覽器執行兩次連續DNS查找之間的時間。這有時可以通過刷新瀏覽器緩存來加快速度,生成大量DNS查找以填充可用的緩存空間,並導致舊條目在過期之前被清除,從而使瀏覽器更快地對相同的主機名執行第二次查找。

當它工作時,它仍然需要大約10秒的時間,而且通常這種技術不會起作用,因為中間緩存不能像瀏覽器的緩存那樣容易地被清除。例如,在測試期間,我發現在一個新創建的Ubuntu EC2實例上,由於系統解析的緩存,我只能每5分鐘為同一域獲得不同的響應。在VPN上,我看到DNS響應在默認解析器上至少緩存30分鐘。讓用戶將頁面打開這麼長時間以允許攻擊者實現DNS重新綁定漏洞,通常是一件很困難的事情,更不用說將無頭瀏覽器作為web應用程序的一部分驅動了。

為了加速漏洞利用,2010年Craig Heffner提出了通過在相同響應中回復同一域的多個A記錄來執行DNS重新綁定的想法,Gerald Doussot和Roger Meyer在2019年的singularity 中使用了這種技術。 Singularity是一個開放源碼容器平台,旨在簡化、快速和安全。 Singularity 是針對EPC 和HPC 工作負載進行優化的,允許不受信任的用戶以可信的方式運行不受信任的容器。

返回的兩條記錄是攻擊者控制的公共服務器的IP地址和目標服務器的(通常是私有的)IP地址。

只有當瀏覽器試圖首先與公共服務器通信並加載攻擊者的惡意頁面時,攻擊才會起作用。然後,攻擊者的web服務器開始阻止來自受害者瀏覽器的流量,導致瀏覽器退回到將所有請求發送到目標服務器。在這種情況下,攻擊者頁面中的JavaScript將能夠向同一來源下的目標IP地址發送請求。

1.png

這種技術確實繞過了緩存問題,因為瀏覽器只需要執行一次DNS查找,儘管在我的測試期間,所有主要瀏覽器都會始終嘗試在公共IP地址之前與私有IP地址通信,這意味著這些技術不起作用。雖然我不相信這種行為是為了防止DNS重新綁定,但它可以有效的阻止這種技術。

這種新行為促使我研究新的技術,可以用來在Safari和基於chrome的瀏覽器中實現瞬間DNS重新綁定。這些技術的關鍵是找到新的方法,使瀏覽器最初使用公共IP,然後在加載網站時切換到使用私有IP。打開Wireshark,我注意到在現代瀏覽器中加載網站時,會同時發送A和AAAA查詢。我開始調查這種行為是否可以用來可靠地執行DNS重新綁定。

攻擊Safari:延遲DNS響應當你在通過IPv6訪問互聯網的主機上加載Safari網頁時,分別為IPv4和IPv6地址發送A和AAAA DNS查詢。當返回多個IP地址時,Safari將優先考慮私有IP地址而不是公共IP地址。

當A或AAAA響應延遲時,Safari中允許快速DNS重新綁定的有趣行為會發生。在這種情況下,Safari不會等待所有DNS響應,而是在接收到第一個DNS響應後立即發送HTTP請求。當收到延遲的DNS響應時,此響應中的IP地址將被添加到IP地址池中,Safari可以在將來請求該域時使用該IP地址池。

這意味著,如果第一個DNS響應是針對公共IP地址的,而延遲的DNS響應是針對私有IP地址的,Safari將向公共IP地址發送第一個請求,直到接收到延遲的DNS響應,此時它將開始向私有IP地址發送請求。

2.png

這提供了一種在Safari中使用自定義DNS服務器實現DNS重新綁定的簡單方法,該服務器可處理*.r.inded.es的查詢:

1.加載目標瀏覽器http://safari.r.intrud.es,觸發safari.r.intrud.es的A和AAAA查找。

2.讓DNS服務器立即返回AAAA記錄,其中包含互聯網上攻擊者控制的web服務器的IPv6地址。暫時不要返回A響應。

3.一旦收到AAAA響應,Safari將向攻擊者的web服務器發出第一個請求。從攻擊者的web服務器返回一個帶有JavaScript的頁面來重複請求http://safari.r.intrud.es/secret.txt。

4.從DNS服務器發送包含本地網絡上目標服務器的IP地址的A響應。

5.Safari現在將對http://safari.r.intrud.es/secret.txt的請求發送到本地網絡上的目標服務器。從攻擊者的服務器加載的頁面可以讀取這些請求的響應,而不會違反同源策略。

為了實現這一點,我編寫了一個小型DNS服務器,可以使用命令行參數延遲DNS響應。在實踐中,我發現將A響應延遲100毫秒幾乎總是足夠的,儘管可以使用200毫秒或更長時間的延遲來使該技術更加可靠。可以在這裡https://github.com/intruder-io/dns-delay-server找到這個服務器以及設置它的說明。

我用來利用它的PHP腳本會將用戶重定向到r.introd.es的隨機子域,以避免中間緩存干擾利用。它還將JavaScript直接包含在頁面中,以避免另一個資源負載。你可以在這裡找到使用的代碼。

該腳本在操作中的視頻請點此,從本地web服務器檢索文件的內容:

3.jpg

我在iOS上的Safari和Brave上進行了測試,發現同樣的技術也可以用於訪問內部網絡上的服務。

攻擊Chrome:使用AAAA優先級Chrome將優先加載本地網絡上的頁面,而不是互聯網上的頁面,但在可用的情況下,它會優先加載IPv6而不是IPv4上的頁面。所以首要任務是:

1.本地IPv6(最高優先級);

2.公共IPv6;

3.當地IPv4;

4.公共IPv4(最低優先級);

這裡的關鍵部分是Chrome會優先考慮公共IPv6地址而不是私有IPv4地址。此外,當Chrome知道一個域的多個IP地址時,一旦服務器重置連接,它就會嘗試不同的IP地址。

4.png

這給出了一個針對Chrome的快速DNS重綁定計劃:

1.加載http://chrome.r.intrud.es,這將觸發A和AAAA查找chrome.r.intrud.es。

2.讓DNS服務器返回指向本地網絡上目標web服務器的A記錄和指向公共互聯網上攻擊者控制的web服務器的AAAA記錄。

3.Chrome將優先考慮IPv6地址,並從攻擊者控制的web服務器發出第一個加載頁面的請求,該服務器返回JavaScript以重複向http://chrome.r.intrud.es/secret.txt發出請求。

4.關閉攻擊者控制的服務器,以便重置所有連接。 Chrome現在將把所有請求發送到本地網絡上的目標服務器。

5.讓加載的頁面向http://chrome.r.intrud.es/secret.txt發出請求。可以在不違反同源策略的情況下讀取對這些請求的響應。

這個計劃幾乎成功了。從互聯網加載的頁面上的JavaScript試圖向本地網絡上的目標發出請求,但這些請求被阻止,並在控制台中顯示以下錯誤:

Accesstofetchat'http://chrome.r.intrud.es/secret.txt'fromorigin'http://chrome.r.intrud.es'hasbeenblockedbyCORSpolicy:Therequestclientisnotasecurecontextandtheresourceisinmore-privateaddressspace`local`.出現此錯誤是因為Chrome部分實現了私有網絡訪問(PNA)https://wicg.github.io/private-network-access/規範中描述的保護。

繞過PNAPrivate Network Access(以前稱為CORS-RFC1918 )限制了網站向私有網絡上的服務器發送請求的能力。根據規範,此類請求只允許來自安全上下文。另外,該規範擴展了跨域資源共享(CORS)協議,因此網站現在必須在允許發送任意請求之前,必須顯式請求私有網絡上服務器的許可。

私有網絡是指目標服務器的IP地址比從其獲取請求服務器的IP地址更私有的請求。例如,從公共網站(https://example.com)向私有網站(http://router.local)的請求,或從私有網站向localhost 的請求。

PNA保護阻止通過普通HTTP從公共互聯網加載的頁面向私有網絡發出請求。在Chrome中,這些保護是為fetch請求實現的,但還沒有為iframe實現。不完整的實現以及DNS重新綁定允許繞過對獲取請求的PNA限制。

我們可以重複利用到上面的步驟4,其中公共web服務器已經關閉,所有對http://chrome.r.intrud.es的請求現在都被定向到本地網絡上的目標服務器。加載的首頁不能向本地網絡發出請求,因為它是通過HTTP從公共互聯網加載的,但是我們可以在iFrame中加載http://chrome.r.intrud.es。這個iFrame中的頁面將從目標web服務器加載。由於此服務器位於本地網絡上,因此允許在iFrame中加載的頁面向本地網絡發出請求。

iFrame中的頁面也與頂部頁面處於相同的起源,這使得頂部頁面可以完全控制框架頁面的DOM。這包括注入腳本,使獲取請求進入框架頁面。這些腳本可以用來訪問目標web服務器並洩露數據,就像如果PNA根本沒有實現的話,它們可以從首頁獲取數據一樣。

6.png

所以,把這些放在一起,我們最終得到了一個完整的步驟:

1.加載http://chrome.r.intrud.es,這將觸發A和AAAA查找chrome.r. imports .es。

2.讓DNS服務器返回一條A記錄,指向本地網絡中的目標web服務器,並返回一條AAAA記錄,指向公網上攻擊者控制的web服務器。

3.Chrome將首先請求從攻擊者的web服務器加載頂部頁面,該服務器返回一個頁面以執行以下步驟。

4.關閉攻擊者控制的服務器,以便重置所有連接嘗試。 5.Chrome現在將把所有請求發送到本地網絡上的目標服務器。

6.從首頁,將一個腳本注入框架頁面以請求http://chrome.r.intrud.es/secret.txt並將響應發送到攻擊者的web服務器。

這可以在Chrome中實現瞬間DNS重新綁定。

7.jpg

為了幫助實現這個漏洞,我編寫了一個小型web服務器,當它接收到/block請求時將停止。你可以在這裡找到運行它的源代碼和說明。

當攻擊自動瀏覽器時,你通常想要在頁面中包含一個iFrame,這需要一些時間來加載。這將阻止瀏覽器認為頁面已完全加載,直到iFrame已加載,並確保漏洞利用腳本有足夠的時間運行。下面的演示顯示,當gowitness被用來從啟用了IPv6的EC2上截取惡意網站的截圖時,這個漏洞被用來從AWS元數據服務中提取憑證:

8.jpg

或者對於更可能在web應用程序中發現的場景,使用無頭Chromium將網頁轉換為PDF:

9.jpg

這種繞過Chrome的PNA限制的行為通過他們的問題跟踪器報告給了Chrome團隊。他們確定這不是安全問題,因為PNA的限制仍在實施過程中。

總結DNS重新綁定是攻擊web應用程序的一個武器。在本系列的第一篇文章中,我試圖展示如何在不太複雜的情況下實現針對web應用程序的重新綁定漏洞。在這篇文章中,我提供了一些工具和技術來構建可靠的漏洞攻擊驅動自動瀏覽器的web應用程序,即使它們只加載頁面很短的時間。