作者:張漢東
原文鏈接:https://mp.weixin.qq.com/s/RsfEKl7FAGs2L9vXKC0rWQ
相關閱讀:
Rust生態安全漏洞總結系列 | Part 1
Rust生態安全漏洞總結系列 | Part 2

本系列主要是分析RustSecurity 安全數據庫庫[1]中記錄的Rust生態社區中發現的安全問題,從中總結一些教訓,學習Rust安全編程的經驗。

本期分析了下面十一個安全問題:

  • RUSTSEC-2021-0110: Vulnerability in wasmtime[2]

  • RUSTSEC-2021-0098: Vulnerability in openssl-src[3]

  • RUSTSEC-2021-0082: Unsoundness in vec-const[4]

  • RUSTSEC-2021-0093: Vulnerability in crossbeam-deque[5]

  • RUSTSEC-2021-0077: Vulnerability in better-macro[6]

  • RUSTSEC-2021-0106: Vulnerability in bat[7]

  • RUSTSEC-2021-0073: Vulnerability in prost-types[8]

  • RUSTSEC-2021-0078: Vulnerability in hyper[9]

  • RUSTSEC-2021-0072: Vulnerability in tokio[10]

  • RUSTSEC-2021-0070: Vulnerability in nalgebra[11]

  • CVE-2021-31162: Vulnerability in std[12]

看是否能給我們一些啟示。

RUSTSEC-2021-0110: Vulnerability in wasmtime[13]

在 Wasmtime 中發現多個代碼缺陷。包括 UAF(use-after-free)、越界讀寫等。

漏洞描述:

  • 漏洞類型:Vulnerability
  • 漏洞分類:memory-corruption/ memory-exposure
  • CVE 編號:CVE-2021-39216[14]、CVE-2021-39219[15]、CVE-2021-39218[16]
  • 詳細:https://rustsec.org/advisories/RUSTSEC-2021-0110.html
  • 補丁:>=0.30.0
  • 關鍵字:use-after-free / out-of-bounds read /out-of-bounds write / Wasm/ garbage collection

漏洞分析

背景:externref 是 WebAssembly 引用類型(Reference Types)中引入的概念,用于表示 Host 引用。

Use after free passing externrefs to Wasm in Wasmtime[17]

當從 Host 傳遞給 Guest externrefs 時會引發 UAF 。滿足下列條件之一可觸發此 Bug :

  1. 同時明確地從Host傳遞多個 externrefswasm 實例
  2. 通過將多個 externrefs 作為參數從 Host 代碼傳遞給 wasm函數
  3. 從Host定義的多值返回函數中返回多個 externrefswasm

如果 WasmtimeVMExternRefActivationsTable在傳入第一個externref后容量被填滿,那么傳入第二個externref可能會觸發垃圾回收。然而,在把控制權傳給Wasm之前,第一個externref是沒有根(root)的,因此,如果沒有其他東西持有對它的引用或以其他方式保持它的live,就會被GC回收。然后,當控制權在垃圾收集后被傳遞給Wasm時,Wasm可以使用第一個externref,但這時它已經被釋放了。

Out-of-bounds read/write and invalid free with externrefs and GC safepoints in Wasmtime[18]

Wasmtime運行使用externrefsWasm時,存在一個無效釋放和越界讀寫的錯誤。

要觸發這個錯誤,Wasmtime需要運行使用externrefsWasm,Host 創建非空的externrefsWasmtime執行一個垃圾收集(GC),并且堆棧上必須有一個Wasm幀,它處于GC Safepoint(安全點就是指代碼運行到這個地方,它的狀態是確定的, GC就可以安全的進行一些操作),在這個安全點上沒有 Live 的引用,這種情況下 Wasmtime 會錯誤地使用 GC Stack map 而非 安全點。這就會導致釋放一些不應該釋放的內存,以及潛在的越界讀寫。

Wrong type for Linker-define functions when used across two Engines[19]

Engine,是在 wasmtime 中被用于跨線程管理wasm模塊的全局上下文。Linker,是用于支持模塊鏈接的結構。

Linker::func_* 安全函數中發現了一個問題。wasmtime 不支持函數的跨 engine 使用,這可能導致函數指針的類型混亂,導致能夠安全地調用一個類型錯誤的函數。這種情況應該 panic!

RUSTSEC-2021-0098: Vulnerability in openssl-src[20]

openssl-src[21] 是用于構建 OpenSSL 給 openssl-sys 庫使用的。OpenSSL 最近又發現了很多新的安全缺陷,也記錄到這里了。

具體這個漏洞是指 處理ASN.1字符串時的讀取緩沖區超限問題。

漏洞描述:

漏洞分析

ASN.1字符串在OpenSSL內部被表示為一個ASN1_STRING結構,它包含一個容納字符串數據的緩沖區和一個容納緩沖區長度的字段。這與普通的C語言字符串不同,后者表示為一個字符串數據的緩沖區,以NUL(0)字節結束。

雖然不是嚴格的要求,但使用OpenSSL自己的 "d2i "函數(和其他類似的解析函數)解析的ASN.1字符串,以及任何用ASN1_STRING_set()函數設置值的字符串,都會在ASN1_STRING結構中以NUL結束字節數。

然而,應用程序有可能直接構建有效的ASN1_STRING結構,通過直接設置ASN1_STRING數組中的 "data "和 "length "字段,不以NUL方式終止字節數組。這也可以通過使用ASN1_STRING_set0()函數來實現。

許多打印ASN.1數據的OpenSSL函數被認為ASN1_STRING字節數組將以NUL結尾,盡管這對直接構建的字符串來說是不保證的。如果應用程序要求打印一個ASN.1結構,而該ASN.1結構包含由應用程序直接構建的ASN1_STRING,而沒有以NUL結束 "data "字段,那么就會發生讀取緩沖區超限。

如果一個惡意行為者可以使一個應用程序直接構建一個ASN1_STRING,然后通過受影響的OpenSSL函數之一處理它,那么這個問題可能會被擊中。這可能導致崩潰(造成拒絕服務攻擊,DOS)。它還可能導致私人內存內容(如私人密鑰或敏感明文)的泄露。

其他 OpenSSL 問題

OpenSSL 缺陷列表:https://rustsec.org/packages/openssl-src.html

RUSTSEC-2021-0082: Unsoundness in vec-const[22]

vec-const試圖從一個指向常量切片的指針構造一個Vec

漏洞描述:

漏洞分析

這個crate 違反了Rust的規則,使用起來會有危害。你不應該使用這個crate。這個crate不應該存在。它創建了不健全的抽象,允許不安全的代碼偽裝成安全代碼。

這個crate聲稱要構造一個長度和容量都不為零的const Vec,但這是做不到的,因為這樣的Vec需要一個來自分配器(allocator)的指針。參見:https://github.com/rust-lang/const-eval/issues/20

RUSTSEC-2021-0093: Vulnerability in crossbeam-deque[23]

crossbeam-deque中發生了數據競爭。

漏洞描述:

漏洞分析

在受影響的版本中,隊列的一個或多個任務會被彈出兩次,如果在堆上分配,會導致 dobule free 和 內存泄漏。如果不是堆上分配,則會引起邏輯錯誤。

修復PR :https://github.com/crossbeam-rs/crossbeam/pull/726

問題是因為任務竊取相關條件判斷錯誤導致的,是邏輯 Bug。

RUSTSEC-2021-0077: Vulnerability in better-macro[25]

better-macro 是一個假的 crate,它在 "證明一個觀點",即proc-macros可以運行任意的代碼。這是一個特別新穎或有趣的觀察。

它目前打開的https://github.com/raycar5/better-macro/blob/master/doc/hi.md,似乎沒有任何惡意的內容,但不能保證會一直如此。

這個 crate 沒有任何有用的功能,不應該被使用。

#[proc_macro]
pub fn println(input: TokenStream) -> TokenStream {
    if let Ok(_) = Command::new("xdg-open").arg(URL).output() {
    } else if let Ok(_) = Command::new("open").arg(URL).output() {
    } else if let Ok(_) = Command::new("explorer.exe").arg(URL).output() {
    }
    let input: proc_macro2::TokenStream = input.into();
    let out = quote! {::std::println!(#input)};
    out.into()
}

RUSTSEC-2021-0106: Vulnerability in bat[26]

bat[27] 中存在不受控制的搜索路徑元素,可能會導致非預期代碼執行。

0.18.2之前的windows系統中的bat會從當前工作目錄中執行名為less.exe的程序。

漏洞描述:

漏洞分析

修復 PR:https://github.com/sharkdp/bat/pull/1724

對傳入的 Path 進行了合法驗證。使用的庫是 grep_cli

RUSTSEC-2021-0073: Vulnerability in prost-types[29]

prost_types::TimestampSystemTime的轉換可能導致溢出和恐慌。

漏洞描述:

漏洞分析

prost-types 0.7.0中,從TimestampSystemTime的轉換使用UNIX_EPOCH上的+-運算符。如果輸入的Timestamp是不被信任的,這可能會溢出和恐慌,造成拒絕服務的漏洞。因為 SystimeTime 內部實現的 +- 使用 checked_add/checked_sub會發生 panic。

use prost_types::Timestamp;
use std::time::SystemTime;

SystemTime::from(Timestamp {
    seconds: i64::MAX,
    nanos: 0,
}); // panics on i686-unknown-linux-gnu (but not x86_64) with default compiler settings

SystemTime::from(Timestamp {
    seconds: i64::MAX,
    nanos: i32::MAX,
}); // panics on x86_64-unknown-linux-gnu with default compiler settings

另外,轉換涉及到調用Timestamp::normalize,它使用了+-運算符。這可能會引起恐慌或環繞(wrap around,取決于編譯器設置),如果應用程序被編譯為溢出時恐慌,也會產生拒絕服務的漏洞。

解決問題的思路是:

Timestamp::normalize可能應該使用 saturating_{add,sub}[31] 方法,如果時間戳的nanos字段超出了范圍,這可能會默默地改變時間戳,最多3秒,但這樣的時間戳可以說是無效的,所以這可能是好的。

SystemTime 沒有Saturating_{add,sub}方法,也沒有MINMAX常數,應該再次使用 SystemTime::checked_{add,sub} 進行轉換。

修復 PR:https://github.com/tokio-rs/prost/pull/439

RUSTSEC-2021-0078: Vulnerability in hyper[32]

對Content-Length進行寬松的 header 解析,可能會使請求被偷渡(走私,smuggling)。

背景:請求偷渡 不合法的請求被夾雜在合法請求中被得到處理。需要通過 content-lengthTransfer-Encoding 兩個header 來構造攻擊。

漏洞描述:

漏洞分析

hyper的HTTP/1服務器代碼存在一個缺陷,即錯誤地解析和接受帶有前綴加號的Content-Length頭的請求,而這一請求本應作為非法請求被拒絕。這與上游HTTP代理不解析這種Content-Length頭而轉發的情況相結合,可能導致 "請求偷渡("request smuggling) "或 "去同步攻擊(desync attacks)"。

修復代碼:https://github.com/hyperium/hyper/commit/06335158ca48724db9bf074398067d2db08613e7

需要判斷 content-lenght 是不是可以正常轉換為有效數位。

RUSTSEC-2021-0072: Vulnerability in tokio[33]

當用JoinHandle::abort中止一個任務時,對于 LocalSet上生成的任務不正確, 容易導致競態條件。

漏洞描述:

>=1.5.1, <1.6.0 >=1.6.3, <1.7.0 >=1.7.2, <1.8.0 >=1.8.1

漏洞分析

當用JoinHandle::abort中止一個任務時,如果該任務當前沒有被執行,那么在調用abort的線程中,Future會被 Drop。這對于在LocalSet上生成的任務是不正確的。

這很容易導致競態條件,因為許多項目在它們的Tokio任務中使用RcRefCell以獲得更好的性能。

修復 PR:https://github.com/tokio-rs/tokio/pull/3934

RUSTSEC-2021-0070: Vulnerability in nalgebra[34]

nalgebra 庫中VecStorageDeserialize實現沒有保持元素數量必須等于nrows * ncols的不變性。對特制的輸入進行反序列化時,可能會允許超出向量分配的內存訪問。

漏洞描述:

漏洞分析

這個缺陷是在v0.11.0(086e6e)中引入的,因為為MatrixVec增加了一個自動派生(derive)的Deserialize實現。MatrixVec后來在v0.16.13(0f66403)中被改名為VecStorage,并繼續使用自動派生的Deserialize實現。

修復 PR :https://github.com/dimforge/nalgebra/pull/889

在反序列化的過程中,對 nrows.value() * ncols.value() == data.len()進行校驗。

CVE-2021-31162: Vulnerability in std[35]

在 Rust 1.52.0之前的Rust標準庫中,如果釋放元素時出現panic ,在Vec::from_iter函數中會出現 double free。

漏洞描述:

漏洞分析

漏洞復現代碼:

use std::iter::FromIterator;

#[derive(Debug)]
enum MyEnum {
    DroppedTwice(Box<i32>),
    PanicOnDrop,
}

impl Drop for MyEnum {
    fn drop(&mut self) {
        match self {
            MyEnum::DroppedTwice(_) => println!("Dropping!"),
            MyEnum::PanicOnDrop => {
                if !std::thread::panicking() {
                    panic!();
                }
            }
        }
    }
}

fn main() {
    let v = vec![MyEnum::DroppedTwice(Box::new(123)), MyEnum::PanicOnDrop];
    Vec::from_iter(v.into_iter().take(0));
}

// Output : free(): double free detected in tcache 2

因為枚舉MyEnum在 析構的時候panic,導致資源泄漏,而引發了雙重 free 的問題。

修復 PR:https://github.com/rust-lang/rust/pull/84603

Vec::from_iter 中執行 forget_allocation_drop_remaining,即,忘記已經被drop的src的元素分配的內存,即便 drop 發生了 panic,也不會泄漏資源。

參考資料

[1]RustSecurity 安全數據庫庫: https://rustsec.org/advisories/

[2]RUSTSEC-2021-0110: Vulnerability in wasmtime: https://rustsec.org/advisories/RUSTSEC-2021-0110.html

[3]RUSTSEC-2021-0098: Vulnerability in openssl-src: https://rustsec.org/advisories/RUSTSEC-2021-0098.html

[4]RUSTSEC-2021-0082: Unsoundness in vec-const: https://rustsec.org/advisories/RUSTSEC-2021-0082.html

[5]RUSTSEC-2021-0093: Vulnerability in crossbeam-deque: https://rustsec.org/advisories/RUSTSEC-2021-0093.html

[6]RUSTSEC-2021-0077: Vulnerability in better-macro: https://rustsec.org/advisories/RUSTSEC-2021-0077.html

[7]RUSTSEC-2021-0106: Vulnerability in bat: https://rustsec.org/advisories/RUSTSEC-2021-0106.html

[8]RUSTSEC-2021-0073: Vulnerability in prost-types: https://rustsec.org/advisories/RUSTSEC-2021-0073.html

[9]RUSTSEC-2021-0078: Vulnerability in hyper: https://rustsec.org/advisories/RUSTSEC-2021-0078.html

[10]RUSTSEC-2021-0072: Vulnerability in tokio: https://rustsec.org/advisories/RUSTSEC-2021-0072.html

[11]RUSTSEC-2021-0070: Vulnerability in nalgebra: https://rustsec.org/advisories/RUSTSEC-2021-0070.html

[12]CVE-2021-31162: Vulnerability in std: https://rustsec.org/advisories/CVE-2021-31162.html

[13]RUSTSEC-2021-0110: Vulnerability in wasmtime: https://rustsec.org/advisories/RUSTSEC-2021-0110.html

[14]CVE-2021-39216: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-39216

[15]CVE-2021-39219: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-39219

[16]CVE-2021-39218: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-39218

[17]Use after free passing externrefs to Wasm in Wasmtime: https://github.com/bytecodealliance/wasmtime/security/advisories/GHSA-v4cp-h94r-m7xf

[18]Out-of-bounds read/write and invalid free with externrefs and GC safepoints in Wasmtime: https://github.com/bytecodealliance/wasmtime/security/advisories/GHSA-4873-36h9-wv49

[19]Wrong type for Linker-define functions when used across two Engines: https://github.com/bytecodealliance/wasmtime/security/advisories/GHSA-q879-9g95-56mx

[20]RUSTSEC-2021-0098: Vulnerability in openssl-src: https://rustsec.org/advisories/RUSTSEC-2021-0098.html

[21]openssl-src: https://crates.io/crates/openssl-src

[22]RUSTSEC-2021-0082: Unsoundness in vec-const: https://rustsec.org/advisories/RUSTSEC-2021-0082.html

[23]RUSTSEC-2021-0093: Vulnerability in crossbeam-deque: https://rustsec.org/advisories/RUSTSEC-2021-0093.html

[24]CVE-2021-32810: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-32810

[25]RUSTSEC-2021-0077: Vulnerability in better-macro: https://rustsec.org/advisories/RUSTSEC-2021-0077.html

[26]RUSTSEC-2021-0106: Vulnerability in bat: https://rustsec.org/advisories/RUSTSEC-2021-0106.html

[27]bat: https://rustsec.org/packages/bat.html

[28]CVE-2021-36753: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-36753

[29]RUSTSEC-2021-0073: Vulnerability in prost-types: https://rustsec.org/advisories/RUSTSEC-2021-0073.html

[30]CVE-2021-36753: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-36753

[31]saturating_{add,sub}:https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.saturating_add

[32]RUSTSEC-2021-0078: Vulnerability in hyper: https://rustsec.org/advisories/RUSTSEC-2021-0078.html

[33]RUSTSEC-2021-0072: Vulnerability in tokio: https://rustsec.org/advisories/RUSTSEC-2021-0072.html

[34]RUSTSEC-2021-0070: Vulnerability in nalgebra: https://rustsec.org/advisories/RUSTSEC-2021-0070.html

[35]CVE-2021-31162:Vulnerability in std: https://rustsec.org/advisories/CVE-2021-31162.html


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/1731/