外部程式通常被系統調用來完成某種需要的功能。這是一種重用的形式,也被認為是一種簡單基于元件的軟體工程方法。在應用沒有淨化非受信的輸入并且在執行外部程式時使用這種資料,就會導緻産生指令和參數注入漏洞。
每一個java應用都有一個唯一的runtime類的執行個體,通過它可以提供一個應用和應用運作環境的接口。目前的runtime對象可以通過runtime.getruntime()方法獲得。runtime.getruntime()的語義定義并不嚴格,是以最好僅僅使用它的那些必要的行為,然而,在通常情況下,它應當被指令直接調用,而不應通過shell來調用。如果需要使用shell來調用它,可以在posix中使用/bin/sh或者在windows平台中使用cmd.exe的方式。作為exec()的另一種形式,它會使用stringtokenizer來分隔從指令行讀入的字元串。在windows平台中,在處理這些符号時,它們會被連接配接成一個單一的參數字元串。
因而,除非顯式地調用指令行解釋器,否則是不會産生指令行注入攻擊的。然而,當參數中包含那些以空格、雙引号或者其他以- /開頭的用來表示分支的字元時,就可能發生參數注入攻擊。
這條規則是規則ids00-j的特例。任何源于程式受信邊界之外的字元串資料,在目前平台作為指令來執行之前,都必須經過淨化。
該代碼示例使用dir指令列出目錄清單。這是通過runtime.exec()?方法調用windows的dir指令來實作的。
因為runtime.exec()方法接受源于運作環境的未經淨化的資料,是以這些代碼會引起指令注入攻擊。
攻擊者可以通過以下指令利用該程式:
該指令實際上執行的是兩條指令:
第一條指令會列出并不存在的dummy檔案夾,并且在控制台上輸出bad。
這一個代碼示例的功能與2.8.1節介紹的類似,隻是它使用了posix中的ls指令。與windows版本的唯一差別在于傳入runtime.exec()的參數。
攻擊者可以通過使用與上例中一樣的指令取得同樣的效果。這個指令實際執行的是:
符合規則的方案會對非受信的使用者輸入進行淨化,這種淨化隻允許一小組列入白名單的字元出現在參數中,并傳給runtime.exec()方法,其他所有的字元都會被排除掉。
盡管這是一個符合規則的方案,這個淨化方案會拒絕合法的目錄。同時,因為指令行解釋器調用是依賴于系統的,是以很難有一個方案可以應付所有java程式可以運作的平台上的指令行注入。
這個符合規則的方案通過隻向runtime.exec()方法輸入那些受信的字元串來防止指令注入。當使用者可以控制使用哪一個字元串時,使用者就可以不向runtime.exec()方法直接提供字元串資料。
這個方案将可能羅列出的目錄直接寫出來了。
如果有許多可用目錄這個方案很快會變得不好管理。一個更富可伸縮性的方案是從一個屬性檔案中讀取所有允許的目錄至java.util.properties對象中。
當通過執行系統指令可以完成的任務可以用其他方式完成時,最好避免用執行系統指令的方式。這個符合規則的方案使用file.list()方法來提供目錄清單,進而消除了指令或參數注入攻擊發生的可能性。
向?runtime.exec()?方法傳遞非受信的、未經淨化的資料會導緻指令和參數注入攻擊。
相關漏洞