seteuid0's blog
Themed by Diary.
cvechecker实现原理分析

cvechecker是由Sven Vermeulen编写的可以用来扫描检查系统软件cve情况的软件,在SF上的下载量非常高。自己在fedora上使用了下,对比yum的信息发现存在比较严重的漏报和误报,抽空分析了下其实现方式,总结如下 。 使用过cvechecker的用户都会猜测使用的是nist的cve(Common Vulnerabilities and Exposures)[1]信息获取软件的cve列表,但是怎么和系统上的软件联系在一起呢? 各个发行版都有自己的软件包管理系统,如redhat系列的rpm、yum。redhat、fedora负责维护rhel和fedora上各个软件包的cve信息,当执行软件包升级时,使用新的软件包替换存在cve的软件包。基于deb包的ubuntu和debian类似。因此,在特定的发行版中,只需要通过包管理器便可知道软件包的版本号,再辅以发行版提供的漏洞信息或者直接使用类似yum update的方式升级便可知道当前版本的CVE信息。 cvechecker是怎么做的呢?Sven没有依赖于包版本管理器,而是直接通过查找软件包的版本号,然后构造CPE(Common Platform Enumeration)[2]信息,通过在cve数据库中查找给CPE信息来提取CVE信息。 每个软件包都包含了众多的软件,如ls和cat都属于coreutils,那么如何从系统软件列表差找到软件包列表及版本号便是Sven方法的关键所在。通过查看代码发现,Sven自己维护了一个软件包和各个命令的映射关系表。(https://raw.github.com/sjvermeu/cvechecker/master/versions.dat)内容类似与:

,perlivp,1,perlivp$,# perlivp v([0-9][0-9]*(\.[0-9]+)+),a,perl,perl,\1,,, ,libvorbis.so,1,libvorbis.so.*,Xiph.Org libVorbis ([0-9][0-9]*(\.[0-9]+)+),a,xiph,libvorbis,\1,,,

看过cvechecker帮助文档的用户都知道,用户自己也可以定义添加这种映射表,而默认的映射表是由Sven自己维护的,默认只有650条,因此这里就是漏报的一处主要原因。 这个隐射表解决了从命令到软件包的映射,但怎么获取软件包的版本号呢?继续看代码:

/** * Here is where the various version extraction methods are supported. * We currently still only support a single method (1, which is the * “strings -n 3 ” command execution) but now we can see if we can * support additional methods as well. */ if (filetype == 1) { char buffer[BUFFERSIZE]; int ret; zero_string(buffer, BUFFERSIZE); ret = strings_extract_version(ws, &preg, pmatch, &cpe_data); if (ret == 0) { add_to_sqlite_database(ws, cpe_data); cpe_to_string(buffer, BUFFERSIZE, cpe_data); fprintf(stdout, " - Found match for %s/%s:\t%s\n", ws->currentdir, ws->currentfile, buffer); }; } else { fprintf(stderr, " ! %s/%s: The sqlite3 implementation currently doesn’t support file type %d\n", ws->currentdir, ws->currentfile, filetype); };

原来是通过strings读取二进制程序中的标示,然后通过正则表达式来提取其中的版本信息。系统中的软件多种多样,尽管有默认的编程约定,但不同的开发者肯定会使用不同的声明方式,难免会无法找到或找错版本信息。此外,各个发行版本在发现CVE时往往采用backporting策略,因此即使CVE已经修复,软件包的大版本号也不会发生变化,这也是引起误报的主要原因。 到此,cvechecker已经获取了系统软件包列表以及软件包对应的版本号,将该信息处理成CPE信息,在CVE列表中查找即可。 cvechecker虽然无法准确的查询出当前系统的cve信息,但是很好的解决了不同Linux版本中包管理器差异的问题,底层依赖较少。 cvechecker处理中涉及到众多的映射信息,如程序和软件包的映射表、CVE列表,默认会下载当前所有的CVE信息 ,有510M之多,单纯的文本文件有这么大,可见一斑。cvechecker使用数据库来组织这些映射信息,再用正则表达式进行数据处理,当前支持的数据库有sqlite和mysql。 到此处,cvechecker分析总结完毕,怎么样,是不是也下载下来跑一次呢? 参考:

  1. cve:http://cve.mitre.org/
  2. cpe:http://cpe.mitre.org/
  3. backporting:https://access.redhat.com/site/security/updates/backporting/