百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

利用动静结合方法检测软件供应链安全

toyiye 2024-06-27 01:03 12 浏览 0 评论

背景

最近的SolarWinds事件展示了软件供应链攻击的过程。供应链攻击的范围很广,本文重点关注涉及代码和数据的应用程序安全。随着DevOps的成熟,大量的代码是通过本地或通过SaaS方案自动构建和发布的。企业将大部分精力放在保护运行此代码的生产系统上,而对构建系统的重视程度不足,或者将这种责任转移给服务提供商。在软件构建过程中,需要使用安全工具针对软件组成或者依赖进行检查,及时发现并删除废弃的软件组件以及存在已知漏洞的软件包,并及时升级为不包含已知漏洞的软件版本。


构建过程中植入恶意代码

构建系统通常在构建和部署或软件发布的过程中动态创建和销毁。攻击者的切入点则是在软件构建过程中植入恶意的程序代码。

如果用户安装了包含恶意代码的软件包,攻击者将可以执行以下一些活动:

  1. 窃取代码和敏感数据。
  2. 在代码中植入后门并部署到生产环境中。
  3. 利用计算机资源实现挖矿等目的。
  4. 窃取敏感数据,包括但不限于环境变量、敏感文件、凭据、证书等。
  5. 执行横向移动和特权提升。

由于软件构建过程中的安全检测内容比较多,这里以python程序环境变量的获取与使用为例进行分享,其他类型的可以使用相同的防范思路进行扩展。


获取环境变量

  • 使用python API获取 os.environ。

return os.environ

  • 运行ENV命令。

subprocess.check_output(['env'])

  • 运行shell内置的set命令。

subprocess.check_output(['sh', '-c', 'set'])

  • 从/proc//environ读取环境变量。

loc = Path('/proc') / str(os.getpid()) / 'environ'

return loc.read_text()

  • 读取可能包含环境变量的文件。

data = [] commons = { '/etc/environment', '/etc/profile', '/etc/bashrc', '~/.bash_profile', '~/.bashrc', '~/.profile', '~/.cshrc', '~/.zshrc', '~/.tcshrc', }

for i in commons:

env = Path(i).expanduser().read_text()

data.append(env)

  • 利用libc.so共享库获取环境变量。

libc = ctypes.CDLL(None)

environ = ctypes.POINTER(ctypes.c_char_p).in_dll(libc, 'environ')

还有其他的环境变量获取方法,这里就不再赘述了。


静态分析

通过对环境变量获取方法的总结,可以使用semgrep 进行静态分析,以下是用于检测对环境变量访问的semgrep静态分析规则。

rules:

- id: env-set

patterns:

- pattern-either:

- pattern: |

subprocess.check_output([..., "=~/env|set/", ...])

- pattern: |

subprocess.run([..., "=~/env|set/", ...])

- pattern: |

subprocess.Popen([..., "=~/env|set/", ...])

message: |

Reading from env or set commands

severity: ERROR

languages:

- python

- id: python-os-environ

patterns:

- pattern-not-inside: os.environ.get(...)

- pattern-not-inside: os.environ[...]

- pattern-either:

- pattern: |

os.environ

message: |

Reading from python's os.environ()

severity: ERROR

languages:

- python

- id: python-proc-fs

patterns:

- pattern-either:

- pattern: |

pathlib.Path('/proc') / ... / 'environ'

message: |

Reading python /proc//environ

severity: ERROR

languages:

- python

- id: environ-files

patterns:

- pattern-inside: |

$X = {..., "=~/\/etc\/environment|\/etc\/profile|\/etc\/bashrc|~\/.bash_profile|~\/.bashrc|~\/.profile|~\/.cshrc|~\/.zshrc|~\/.tcshrc/", ...}

...

- pattern-either:

- pattern: |

Path(...)

- pattern: |

open(...)

message: |

Reading from sensitve files that contain environment variables

severity: ERROR

languages:

- python

- id: libc-environ

patterns:

- pattern-either:

- pattern: |

$LIB = ctypes.CDLL(...)

...

$Y.in_dll($LIB, 'environ')

message: |

Reading from libc.environ

severity: ERROR

languages:

- python

这个规则的语法是比较简单的。关于规则编写以及相关的语法,可以参考 https://semgrep.dev/docs/。

编写python脚本static_analysis.py针对目标软件包进行检测。脚本代码如下:

import os

os.system('semgrep -f static_scan_rules.yml pkgs/')

在命令行运行脚本的检测结果如下:

静态分析可以帮助我们轻松地检测出一些代码中明显的安全问题,但是静态分析对于混淆的代码具有局限性,因为实现相同逻辑的代码和API有不同的指令排列方式。从长远来看,可能无法为所有内容编写检测规则。因此还需要进行动态分析,使检测更加精确。


动态分析

对于动态分析,可以跟踪比较核心的系统调用或者函数调用,从而判定软件是否存在一些安全风险。为了简单表示动态分析,这里以strace工具为例来进行环境变量获取的跟踪分析。

  • 命令执行

考虑到一些恶意代码是通过执行系统命令来获取系统环境信息的,可以通过strace监视execve系列函数调用来发现具体的命令调用,从而判定是否存在危害性。

$ strace -f -e trace=execve -o strace python -c 'import subprocess;subprocess.call(["env"])'

$ cat strace

431765 execve("/home/ajin/package_scan/venv/bin/python", ["python", "-c", "import subprocess;subprocess.cal"...], 0x7ffee0ac8c48 /* 28 vars */) = 0

431766 execve("/home/ajin/package_scan/venv/bin/env", ["env"], 0x7fff8fa0b308 /* 28 vars */) = -1 ENOENT (No such file or directory)

431766 execve("/home/ajin/.local/bin/env", ["env"], 0x7fff8fa0b308 /* 28 vars */) = -1 ENOENT (No such file or directory)

431766 execve("/usr/local/sbin/env", ["env"], 0x7fff8fa0b308 /* 28 vars */) = -1 ENOENT (No such file or directory)

431766 execve("/usr/local/bin/env", ["env"], 0x7fff8fa0b308 /* 28 vars */) = -1 ENOENT (No such file or directory)

431766 execve("/usr/sbin/env", ["env"], 0x7fff8fa0b308 /* 28 vars */) = -1 ENOENT (No such file or directory)

431766 execve("/usr/bin/env", ["env"], 0x7fff8fa0b308 /* 28 vars */) = 0

431766 +++ exited with 0 +++

431765 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=431766, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---

431765 +++ exited with 0 +++

  • 文件读取

针对通过读取文件方式获取系统环境变量的情况,可以通过监视openat()或 open() 系列系统调用进行分析与判定。

strace -f -e trace=open,openat -o strace python -c 'from pathlib import Path; Path("~/.bashrc").expanduser().read_text()'

$ cat strace | grep bashrc

432709 openat(AT_FDCWD, "/home/ajin/.bashrc", O_RDONLY|O_CLOEXEC) = 3

  • 网络连接

攻击者窃取的数据会通过网络方式向外发送,可以监视connect()系统调用来发现外联的情况。

$ strace -f -e trace=connect -o strace python -c 'import urllib.request;urllib.request.urlopen("http://python.org/")'

$ cat strace | grep 'htons(80)'

435764 connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("45.55.99.72")}, 16) = 0

  • 实施跟踪分析

针对新的安装包,可以通过strace工具跟踪其所有的敏感系统调用,并查找与恶意行为对应的模式。strace的命令如下:

strace -s 1000 -fqqe trace=openat,execve,connect --seccomp-bpf

参数说明如下:

-s strsizelimit length of print strings to STRSIZE chars (default 32)

-ffollow forks

-qsuppress messages about attaching, detaching, etc.

-e expra qualifying expression: option=[!]all or option=[!]val1[,val2]...

--seccomp-bpf Enable seccomp-bpf filtering to improve performance.

cmdthe command for process running.

以检测软件包rogue为例,编写动态检测脚本如下:

import re

import subprocess

from pathlib import Path


EXEC = re.compile(r', \[.*\]')

IP = re.compile(r'inet_addr\(\".+\"\)')

PORT = re.compile(r'htons\([0-9]+\)')


ENV_LOCATIONS = {

'/etc/environment',

'/etc/profile',

'/etc/bashrc',

'~/.bash_profile',

'~/.bashrc',

'~/.profile',

'~/.cshrc',

'~/.zshrc',

'~/.tcshrc',

}

BAD_COMMANDS = {

'"set"',

'"env"',

}

def check_path(pkg, syscall):

path = syscall.split('"')[1]

for loc in ENV_LOCATIONS:

if Path(loc).expanduser().as_posix() == path:

print(pkg +" tried to access sensitive environment location "+loc+" during installation.')


def check_cmd(pkg, syscall):

args = EXEC.search(syscall)

match_str = args.group()

if(cmd in match_str):

for cmd in BAD_COMMANDS):

print( pkg +" tried to access environment variables by executing "+match_str+" command during installation.')


def check_connect(pkg, syscall):

ipo = IP.search(syscall)

porto = PORT.search(syscall)

ip_addr = ipo.group().replace('inet_addr(', '').replace('"', '').replace(')', '')

port = porto.group().replace('htons(', '').replace(')', '')

loc = ip_addr + ":" + port

print(pkg + ' tried to connect to "+ loc +" during installation.')


def lookup_env(pkg, syscalls):

calls = syscalls.splitlines()

for i in calls:

if 'openat(' in i:

check_path(pkg, i)

elif 'execve(' in i:

check_cmd(pkg, i)

elif 'connect(' in i and 'sin_addr=' in i:

check_connect(pkg, i)


def collect_syscalls(pkg):

print(f'Analyzing: {pkg}')

args = [

'strace', '-s', '2000', '-fqqe',

'trace=openat,execve,connect','--seccomp-bpf',

'pip', 'install', '--no-cache'] + pkg.split()

return subprocess.check_output(args, stderr=subprocess.STDOUT).decode('utf-8', 'ignore')


def check():

pkg = "-e git://github.com/ajinabraham/poc-rogue.git"

syscalls = collect_syscalls(pkg)

lookup_env("rogue", syscalls)


if __name__ == "__main__":

check()


执行脚本运行结果如下:


例外情况

Python开发的软件包中并不是所有的行为都可以通过syscall监控到,例如利用外部函数接口从libc通过函数指针从内存中访问的方法,这种情况可以使用LD_PRELOAD跟踪libc符号和函数调用行为精确匹配。


总结

为了保证生产环境的安全,必须在构建系统中实施必要的安全控制流程,例如开启双重认证以及每次进行生产构建的时候进行环境安全检测等,避免成为攻击者攻击的目标。在现实世界中,攻击并不总是很复杂,而是针对目标系统最薄弱的环节进行攻击。本文旨在推动安全意识的提高,分享一些在软件供应链中需要主动安全分析的过程和工具等内容。


参考链接

https://ajinabraham.com/blog/detecting-zero-days-in-software-supply-chain-with-static-and-dynamic-analysis

https://github.com/ajinabraham/package_scan


格物实验室

绿盟科技格物实验室专注于工业互联网、物联网和车联网三大业务场景的安全研究。实验室以“格物致知”的问学态度,致力于以智能设备为中心的漏洞挖掘和安全分析,提供基于业务场景的安全解决方案。积极与各方共建万物互联的安全生态,为企业和社会的数字化转型安全护航。

绿盟威胁情报中心

绿盟威胁情报中心(NSFOCUS Threat Intelligence center, NTI)是绿盟科技为落实智慧安全2.0战略,促进网络空间安全生态建设和威胁情报应用,增强客户攻防对抗能力而组建的专业性安全研究组织。其依托公司专业的安全团队和强大的安全研究能力,对全球网络安全威胁和态势进行持续观察和分析,以威胁情报的生产、运营、应用等能力及关键技术作为核心研究内容,推出了绿盟威胁情报平台以及一系列集成威胁情报的新一代安全产品,为用户提供可操作的情报数据、专业的情报服务和高效的威胁防护能力,帮助用户更好地了解和应对各类网络威胁。

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码