软件成分分析(SCA,Software Composition Analysis)是一种对二进的安全漏洞或者潜在的许可证授权问题,把这些风险排查在应用系统投产之前,也适用于应用系统运行中的诊断分析。在开源软件日益盛行的今天,开源安全威胁成为企业组织无法回避的话题,与此同时,应用交付规模和频率的正在快速增长制软件的组成部分进行识别、分析和追踪的技术。专门用于分析开发人员使用的各种源码、模块、框架和库,以识别和清点开源软件(OSS)的组件及其构成和依赖关系,并识别已知,软件成分分析对于安全合规风险管控和安全态势感知都是必不可少的能力。
镜像结构
01
镜像文件系统
镜像里面是一层层的文件系统,叫做 Union FS(联合文件系统),联合文件系统,可以将几层目录挂载(叠)到一起,形成一个虚拟文件系统,每一层文件系统叫做一层 layer,layer都是只读的,构建镜像的时候,从一个最基本的操作系统开始,每个构建提交的操作都相当于做一层的修改,增加了一层文件系统,一层层往上叠加,上层的修改会覆盖底层该位置的可见性。
02
镜像包结构
镜像可以通过docker save命令存储为一个tar包,其中的文件结构如下(以Ubuntu:latest)为例:
mainfest.json
这个文件存储了镜像结构和基础信息的描述文件,可以看到里面主要存储了Layers的哈希值和镜像的tags。
${hash}.json
这个文件存储了启动容器的配置,如启动命令,镜像ID,历史记录等。
${layer hash}/json
在镜像规范的v1版本中定义的描述该层(Layer)信息的元数据,但在 v1.2 版本中不需要依赖此文件。
${layer hash}/layer.tar
存储该层(Layer)文件系统的变更记录的归档包。
${layer hash}/VERSION
指定json文件内容的格式规范。
SCA本质
我觉得可以类比各类的AST(Application Security Test,应用安全测试)。如果说在运行中的容器中执行诸如apt list
, dpkg-query -l
的命令是DAST(动态应用程序安全测试),那么SCA实际上是SAST(Static Application Security Testing,静态应用程序安全测试)。SCA落到最本质的技术实际上就是分析文件,从文件中解析出容器/镜像中存在的软件成分。
下面举几个简单的例子:
1、apt/dpkg
以debian系的apt/dpkg为例,实际上通过这些命令安装的包信息会存储在/var/lib/dpkg/status
或/var/lib/dpkg/status.d/*
中,一个简单的例子:
Package: curl
Status: install ok installed
Priority: optional
Section: web
Installed-Size: 443
Maintainer: Ubuntu Developers <[email protected]>
Architecture: amd64
Multi-Arch: foreign
Version: 7.81.0-1ubuntu1.10
Depends: libc6 (>= 2.34), libcurl4 (= 7.81.0-1ubuntu1.10), zlib1g (>= 1:1.1.4)
Description: command line tool for transferring data with URL syntax
curl is a command line tool for transferring data with URL syntax, supporting
DICT, FILE, FTP, FTPS, GOPHER, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3,
POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, TELNET and TFTP.
.
curl supports SSL certificates, HTTP POST, HTTP PUT, FTP uploading, HTTP form
based upload, proxies, cookies, user+password authentication (Basic, Digest,
NTLM, Negotiate, kerberos...), file transfer resume, proxy tunneling and a
busload of other useful tricks.
Homepage: https://curl.haxx.se
Original-Maintainer: Alessandro Ghedini <[email protected]>
可以看到这个文件存储可读的文本,其中包含了通过dpkg
命令安装的包信息:包名,版本,依赖,描述等。
2、apk
通过alpine系的apk
命令安装的包基本相同,其包信息会存储在/lib/apk/db/installed
中,一个简单的例子:
C:Q1i+1SpSpyplqn9ztFds6RP7eIv8U=
P:curl
V:8.1.2-r0
A:x86_64
S:139967
I:241664
T:URL retrival utility and library
U:https://curl.se/
L:curl
o:curl
m:Natanael Copa <[email protected]>
t:1685465048
c:e8990bc463779592e3fb62eae7aacc48ed8abb3f
D:libcurl=8.1.2-r0 so:libc.musl-x86_64.so.1 so:libcurl.so.4 so:libz.so.1
p:cmd:curl=8.1.2-r0
F:usr
F:usr/bin
R:curl
a:0:0:755
Z:Q1L2dyojkjpAQ7JazurYSkGNQZFTk=
这里面同样包含了安装的包信息:包名,版本,依赖,描述等。
SCA流程
初步成果
(想看详细代码实现的师傅请查看:https://github.com/yaklang/yaklang/pull/149 👍)
为yak提供了一个新的标准库:sca
,这个标准库主要提供了以下功能:
// 主要函数
ScanDockerImageFromContext(imageID string, opts ...dockerContextOption) (pkgs []*Package, err error) // 根据镜像id扫描镜像
ScanDockerContainerFromContext(containerID string, opts ...dockerContextOption) (pkgs []*Package, err error) // 根据容器id扫描容器
ScanDockerImageFromFile(path string, opts ...dockerContextOption) ([]*Package, error) // 根据文件路径扫描镜像,路径是docker save命令导出的tar文件路径
// 选项/Option
endPoint(endpoint string) dockerContextOption // 设置docker的endpoint
scanMode(mode ScanMode) dockerContextOption // 设置扫描模式,默认使用所有分析器进行扫描
concurrent(n int) dockerContextOption // 设置并发数量
analayzers(a ...TypAnalyzer) dockerContextOption // 设置使用的分析器,默认使用所有的分析器进行扫描
// 扫描模式
ALL_MODE // 所有分析器
PKG_MODE // 所有包管理器的分析器
LANGUAGE_MODE // 所有语言的分析器
// 所有分析器
DPKG_ALALYZER
RPM_ALALYZER
APK_ALALYZER
RUBY_BUNDLER_ANALYZER
RUST_CARGO_ANALYZER
RUBY_GEMSPEC_ANALYZER
PYTHON_POETRY_ANALYZER
PYTHON_PIPENV_ANALYZER
PYTHON_PIP_ANALYZER
PYTHON_PACKAGING_ANALYZER
PHP_COMPOSER_ANALYZER
NODE_YARN_ANALYZER
NODE_PNPM_ANALYZER
NODE_NPM_ANALYZER
JAVA_POM_ANALYZER
JAVA_GRADLE_ANALYZER
JAVA_JAR_ANALYZER
GO_MOD_ANALYZER
GO_BINARY_ANALYZER
CLANG_CONAN_ANALYZER
扫描结束后返回了一个结构体指针数组,其结构如下所示:
type Package struct {
Name string
Version string
IsVersionRange bool // Version is a version range
FromFile []string
FromAnalyzer []string
Verification string
License []string
UpStreamPackages map[string]*Package
DownStreamPackages map[string]*Package
// 这里存储临时数据,不准确,不要访问这里这个结构体成员
DependsOn PackageRelationShip
Potential bool
}
简单用法
扫描镜像
pkgs = sca.ScanImageFromContext("1318b700e415")~ // ubuntu:latest
for pkg in pkgs {
printf("name: %s version: %sn", pkg.Name, pkg.Version)
}
扫描容器
pkgs = sca.ScanImageFromContext("fc6a11ef0e1c")~ // 容器id
for pkg in pkgs {
printf("name: %s version: %sn", pkg.Name, pkg.Version)
}
与cve标准库进行联动
pkgs = sca.ScanImageFromContext("1318b700e415")~ // ubuntu:latest
cveOptions = make([]var, len(pkgs))
for i, pkg = range pkgs {
cveOptions[i] = cve.product(pkg.Name, pkg.Version)
}
cveCh = cve.QueryEx(cveOptions...)
for result in cveCh {
printf("%vn", result.CVE)
}
/*
CVE-2019-9923
CVE-2022-0563
CVE-2022-1271
CVE-2022-1664
CVE-2022-48303
CVE-2009-2360
CVE-2021-20193
CVE-2021-32803
CVE-2021-32804
CVE-2021-37600
CVE-2021-37701
CVE-2021-37712
CVE-2021-37713
CVE-2021-3995
CVE-2021-3996
CVE-2020-3810
CVE-2016-2781
CVE-2018-1121
*/
使用DOT画出依赖供应链
(只用于临时展示)
后续
后续我们会在yakit中提供一个新的页面,方便用户操作,用户提供一个镜像ID/容器ID/本地文件,yakit对其进行扫描后输出依赖供应链和可能存在的CVE。
YAK官方资源
YAK 语言官方教程:
https://yaklang.com/docs/intro/
Yakit 视频教程:
https://space.bilibili.com/437503777
Github下载地址:
https://github.com/yaklang/yakit
Yakit官网下载地址:
https://yaklang.com/
Yakit安装文档:
https://yaklang.com/products/download_and_install
Yakit使用文档:
https://yaklang.com/products/intro/
常见问题速查:
https://yaklang.com/products/FAQ
长按识别添加工作人员
开启Yakit进阶之旅
推荐站内搜索:最好用的开发软件、免费开源系统、渗透测试工具云盘下载、最新渗透测试资料、最新黑客工具下载……
还没有评论,来说两句吧...