stardust (stardust_at_xfocus.org)
對入侵檢測防護産品的評測中,我們經常需要對它們的漏洞攻擊檢測能力做出評價,其中涉及漏洞的覆寫面即是能力的一方面,那麼如何去評價?以什麼名額去衡量才能得到相對客觀公平且有說服力的結果呢?這個文章中我們來讨論一下這個問題,在此提出一個可操作的量化名額。
1. 名額的設計
1.1 CVE漏洞條目數量名額
最簡單的方案是顯而易見的,通過統計IDS/IPS所能檢測的利用漏洞攻擊種數來進行比較。目前多數主流的IDS/IPS産品都提供了CVE名的支援,每個CVE名對應一個獨立的安全漏洞,雖然CVE名字表不可能包含所有的已知安全漏洞,但至少包括了其中的大多數重要條目。是以通過統計産品相關的CVE條目數量可以大緻了解IDS/IPS的漏洞攻擊檢測覆寫面。我們最原始的評價名額可以是産品相關的CVE漏洞條目個數。
1.2 CVSS漏洞威脅評分修正
上面的漏洞數量名額存在一個問題,因為它假設了每個漏洞有相同的威脅級别,而事實情況并非如此,是以我們在評價過程中必須考慮漏洞本身的威脅等級。感謝CVSS漏洞威脅評分項目的工作成果,它為每個CVE漏洞條目按威脅程度的高低打了分,最高威脅級别的漏洞為10分,從NVD的網站上可以輕易地擷取漏洞基本威脅評分的資料。由此,我們的名額可以修正為産品涉及到的CVE漏洞條目的CVSS評分的總和。
1.3 時間因素上的修正
考慮了漏洞威脅級别的高低,無疑使我們的名額更具準确性和可比較性,但上面的名額還是有可以改進的地方。在這裡我們需要引入時間因素,因為當漏洞被披露以後,随着時間的推移,由于軟體新版本的更新,有意或無意的漏洞修補,存在漏洞的系統越來越少,相對來說漏洞的威脅呈現一個越來越小的趨勢,也就是說,同樣CVSS威脅基本評分為8的2000年與2006年的漏洞在2006年評價時現實的威脅程度是很不一樣的。其實,CVSS漏洞威脅評分系統的設計考慮了威脅評分随時間及布署狀況的修正,一個漏洞的CVSS威脅評分涉及三個層次:基本評分、生命周期因素修正、環境因素修正。基本評分是根據漏洞本身固有特性所可能造成的影響評價得到的分值,生命周期因素修正就是基于時間程序的修正,環境因素即是基于布署情況的修正。NVD提供了CVE條目的基本評分,環境因素取決于組織受漏洞影響産品布署狀況,生命周期因素修正需要跟蹤每個漏洞的更新檔釋出情況,工作量巨大,一個單獨的組織是無法完成的,是以NVD也未給出相應的資料。
對于我們的評價名額,我們簡單地采用一個極粗糙的威脅随年數增加線性遞減的算法:
漏洞的目前威脅評分 = CVSS基本評分* (8-(2006-漏洞釋出的年))/8
這樣一個線性算法與事實情況并不一緻,事實情況是漏洞在公布的一兩年内威脅程度迅速下降,之後幾年内的下降則非常的小,是以,基本上線性遞減隻是一個聊勝于無的計算方法,考慮到每個漏洞的情況并不那麼一緻而且名額隻用于作相對的比較,這樣的算法也是可接受的。
到此評價名額修正為所有CVE相關的漏洞目前威脅評分的總和。
2. 如何操作及幾個常見産品的名額分析
2.1 擷取每個CVE條目對應的CVSS評分
從NVD網站下載下傳CVE評分資料檔案,檔案為XML格式,每年一個單獨的檔案,它包含了每個CVE條目的詳細資訊,使用所附的 extract-cve-score.pl 腳本将其中CVE名和相應的CVSS評分提取出來,把列印出來的資料重定向的檔案中,并将多年的資料整合到一個檔案中,這個即是我們以後會使用到的CVE名和對應CVSS評分的對照表。
2.2 擷取評測産品的涉及到的CVE條目資訊
以幾個能從公開管道擷取資訊的IDS産品為例:
Snort
-----
Snort的規則資訊索引檔案(sid-msg.map)中每個與CVE漏洞相關的檢測都列出了相應的CVE名,我們隻要使用類似 extract-snort-cve.pl 的簡單腳本将其提取出來即可。
RealSecure 7
------------
RealSecure 7的每個檢測子產品更新封包件中包含了一個名為 issues.csv 的索引檔案,檔案中并不直接包含每個檢測條目對應的CVE名資訊,但包含了對應于ISS網站上詳細說明資訊的ID号,在詳細說明中包含有CVE名。處理這種情況稍稍複雜一些,我們必須把檢測條目相關的詳細資訊從網站上下載下傳回來,這可以通過 get-iss-content.pl 腳本實作,它讀取 issues.csv 檔案中的檢測條目ID号從ISS的網站下載下傳每個條目的詳細資訊,每個條目一個檔案,然後用 extract-iss-cve.pl 腳本提取檢測條目涉及到的CVE名。
IDP
---
IDP的規則檔案是可公開下載下傳的,也未做加密,規則檔案中包含了涉及到CVE名資訊,與處理Snort規則索引檔案類型,使用類似 extract-idp-cve.pl 的腳本将其提取出來。
對于其他産品一般通過分析其檢測條目詳細資訊說明文檔,都應該是可以得到相關的CVE條目資訊的。
2.3 計算漏洞覆寫面的評分名額
有了CVE名到相應CVSS評分的對應表和産品涉及到的CVE名,使用 caculate-score.pl 腳本即可得到評分。
上述幾個産品的分析結果比較:
CVE條目數 總威脅得分 CVE條目平均CVSS評分 時間因素修正後的總威脅得分
RealSecure 7 979 6000.7 6.1 2694.3
Snort 550 3454.3 6.3 1476.9
IDP 311 1947.3 6.3 796.6
由以上的資料,産品相關漏洞覆寫面的高下就很明顯了。
3. 結論
事實上,由于威脅得分的計算是面向漏洞的,是以所有以漏洞處理為核心的安全産品比如漏洞資料庫、安全評估、入侵檢測類産品都,可以用計算“時間因素修正後的總威脅得分”名額的方法來評價。
附,評分計算相關的腳本工具:
extract-cve-score.pl
--------------------------------- 8< --------------------------------------
#!/usr/bin/perl
my $data = "";
my @cve_names = ("");
my @cve_scores = ("");
my $cve_name = "";
$data = readDBcontent($ARGV[0]);
$data =~ s/<entry //n<entry /gi;
@cve_names = $data =~ m|<entry type="CVE" name="(CVE-/d/d/d/d-/d/d/d/d)" seq="/d/d/d/d-/d/d/d/d" published="/d/d/d/d-/d/d-/d/d" modified="/d/d/d/d-/d/d-/d/d" severity=".+" CVSS_score="/d{1,2}/./d" |g;
@cve_scores = $data =~ m|<entry type="CVE" name="CVE-/d/d/d/d-/d/d/d/d" seq="/d/d/d/d-/d/d/d/d" published="/d/d/d/d-/d/d-/d/d" modified="/d/d/d/d-/d/d-/d/d" severity=".+" CVSS_score="(/d{1,2}/./d)" |g;
for (my $i=0;$i<=$#cve_names;$i++) {
print $cve_names[$i]."/t".$cve_scores[$i]."/n";
}
sub readDBcontent {
my ($table) = @_;
my $dbcon = "";
open(TBL,"<$table")||die($table);
while (<TBL>) {
$dbcon .= $_ ;
}
close(TBL);
return ($dbcon);
}
--------------------------------- 8< --------------------------------------
extract-snort-cve.pl
--------------------------------- 8< --------------------------------------
#!/usr/bin/perl
#
my @issues = ("");
readDBcontent($ARGV[0],/@issues);
for (my $i=0;$i<@issues;$i++) {
my $issuetext = $issues[$i];
if ($issuetext =~ m//|/| cve,(/d{4}-/d{4}) /) {
print "CVE-".$1."/n";
}
}
sub readDBcontent {
my ($table,$dbcon)[email protected]_;
my $count=0;
open(TBL,"<$table")||die($table);
@{$dbcon}=<TBL>;
close(TBL);
for(my $i=0;$i<@{$dbcon};$i++) {
chomp(${$dbcon}[$i]);
if(${$dbcon}[$i] ne "") { $count++; }
}
return ($count);
}
--------------------------------- 8< --------------------------------------
get-iss-content.pl
--------------------------------- 8< --------------------------------------
#!/usr/bin/perl
#
my $flag = 0;
my $program = "lynx -source ";
my $url_b = "http://xforce.iss.net/xforce/xfdb/";
my @issues = ("");
$|++;
readDBcontent($ARGV[0],/@issues);
for (my $i=0;$i<@issues;$i++) {
my $issuetext = $issues[$i];
my ($aa,$bb,$cc,$vul_id) = split (',',$issuetext);
if ($vul_id =~ m/^/d+/) {
my $iss_vuln = "$vul_id.txt";
# print $iss_vuln."/n";
if (!(-e $iss_vuln) || (-z $iss_vuln)) {
my $content = "";
$url = $url_b."${vul_id}";
$content = getSection();
open (DATAFILE,">$iss_vuln") or die ("$iss_vuln/n");
print DATAFILE $content;
close (DATAFILE);
}
}
}
sub getSection {
my @page;
my $section_con = "";
my $last = 0;
getPage("$url",/@page);
$section=uc("$section");
for ($i=0;$i<@page;$i++) {
if ($page[$i] =~ m/^<p>The information within this database may change without notice/) {$flag = 0};
if ($flag) {
$page[$i] = removeHtmltag ("$page[$i]");
if($page[$i] eq "") {
if(!$last) { $section_con .= "/n"; $last = 1;}
} else {
$section_con .= "$page[$i]/n";
$last = 0;
}
}
if ($page[$i] =~ m/X-Force Database Results/) {$flag = 1};
}
return $section_con;
}
sub getPage {
my ($url_section,$page_con) = @_;
open (EXECFILE, "$program '$url_section' |");
@{$page_con} = <EXECFILE>;
close (EXECFILE);
}
sub removeHtmltag {
my ($string)[email protected]_;
$string =~ s//t//g;
$string =~ s//n//g;
$string =~ s/ / /g;
$string =~ s/"/"/g;
$string =~ s/<br><br>//n/g;
$string =~ s/<br>//n/g;
$string =~ s/<BR>//n/g;
$string =~ s/<p>//n/g;
$string =~ s/<P>//n/g;
$string =~ s/<//P>//n/g;
$string =~ s/<//p>//n/g;
$string =~ s/<li>/---/g;
$string =~ s/<LI>/---/g;
$string =~ s/—/-/g;
$string =~ s/<//OPTION>//n/g;
$string =~ s/<[^<]*>//g;
$string =~ s/</</g;
$string =~ s/>/>/g;
$string =~ s/&/&/g;
$string =~ s/"/"/g;
$string =~ s//015//g;
$string =~ s/^/s*/n*//;
# $string =~ s//s*/n*$//;
return $string;
}
sub readDBcontent {
my ($table,$dbcon)[email protected]_;
my $count=0;
open(TBL,"<$table")||die($table);
@{$dbcon}=<TBL>;
close(TBL);
for(my $i=0;$i<@{$dbcon};$i++) {
chomp(${$dbcon}[$i]);
if(${$dbcon}[$i] ne "") { $count++; }
}
return ($count);
}
--------------------------------- 8< --------------------------------------
extract-iss-cve.pl
--------------------------------- 8< --------------------------------------
#!/usr/bin/perl
#
my @issues = ("");
readDBcontent($ARGV[0],/@issues);
for (my $i=0;$i<@issues;$i++) {
my $issuetext = $issues[$i];
my ($aa,$bb,$cc,$vul_id) = split (',',$issuetext);
if ($vul_id =~ m/^/d+/) {
my $iss_vuln = "$vul_id.txt";
if ((-e $iss_vuln) && !(-z $iss_vuln)) {
my @contents = ("");
readDBcontent($iss_vuln,/@contents);
for (my $j=0;$j<@contents;$j++) {
if ($contents[$j] =~ m/^---(CVE-/d{4}-/d{4})/) {
print $1."/n";
}
}
}
}
}
sub readDBcontent {
my ($table,$dbcon)[email protected]_;
my $count=0;
open(TBL,"<$table")||die($table);
@{$dbcon}=<TBL>;
close(TBL);
for(my $i=0;$i<@{$dbcon};$i++) {
chomp(${$dbcon}[$i]);
if(${$dbcon}[$i] ne "") { $count++; }
}
return ($count);
}
--------------------------------- 8< --------------------------------------
extract-idp-cve.pl
--------------------------------- 8< --------------------------------------
#!/usr/bin/perl
#
my @issues = ("");
readDBcontent($ARGV[0],/@issues);
for (my $i=0;$i<@issues;$i++) {
my $issuetext = $issues[$i];
if ($issuetext =~ m/:cve /((CVE-/d{4}-/d{4})/)/) {
print $1."/n";
}
}
sub readDBcontent {
my ($table,$dbcon)[email protected]_;
my $count=0;
open(TBL,"<$table")||die($table);
@{$dbcon}=<TBL>;
close(TBL);
for(my $i=0;$i<@{$dbcon};$i++) {
chomp(${$dbcon}[$i]);
if(${$dbcon}[$i] ne "") { $count++; }
}
return ($count);
}
--------------------------------- 8< --------------------------------------
caculate-score.pl
--------------------------------- 8< --------------------------------------
#!/usr/bin/perl
if(scalar(@ARGV) < 2){
print "Usage: $0 CVES-LIST-FILE CVE-SCORE-PAIR-LIST-FILE/n";
exit 1;
}
my %cve_name_score = ();
my @score_data = ("");
readDBcontent($ARGV[1],/@score_data);
my $cur_name = "";
my $cur_score = 0.0;
foreach (@score_data) {
$_ =~ m/(.+)/t(.+)/;
$cur_name = $1;
$cur_score = $2;
$cve_name_score{$cur_name} = $cur_score;
}
my @cves = ("");
readDBcontent($ARGV[0],/@cves);
my $score = 0.0;
my $score1 = 0.0;
my $cve_count = 0;
my $year = 0;
my $score_modified = 0;
foreach (@cves) {
if ($_ ne "") {
if (defined($cve_name_score{$_})) {
$score += $cve_name_score{$_};
$cve_count++;
$_ =~ m/(/d/d/d/d)-/d/d/d/d/;
$year = $1;
$score_modified = $cve_name_score{$_} * ((8-(2006-$year))/8);
$score1 += $score_modified;
}
}
}
my $average = $score/$cve_count;
printf "%d/t%.1f/t%.1f/t%.1f", $cve_count,$score,$average,$score1;
sub readDBcontent {
my ($table,$dbcon)= @_;
my $count= 0;
open(TBL,"<$table")||die($table);
@{$dbcon}=<TBL>;
close(TBL);
for(my $i=0;$i<@{$dbcon};$i++) {
chomp(${$dbcon}[$i]);
if(${$dbcon}[$i] ne "") { $count++; }
}
return ($count);
}
--------------------------------- 8< --------------------------------------
資源連結:
通用弱點評價體系(CVSS)簡介
http://www.xfocus.net/releases/200602/a850.html
NVD/CVE XML Data Files
http://nvd.nist.gov/download.cfm
CVSS Draft
http://www.first.org/cvss/draft/
RealSecure Network Sensor XPUs
http://www.iss.net/db_data/xpu/RSNS.php
Snort Rules
http://www.snort.org/rules/
IDP Rule
https://services.netscreen.com/idpupdates/updateInfo.dat