一种残膜回收机防缠绕挑膜装置的制 一种秧草收获机用电力驱动行走机构

面向解释型语言源程序的系统调用白名单生成方法

2022-06-01 18:34:26 来源:中国专利 TAG:


1.本发明属于系统安全和容器安全领域,具体涉及面向解释型语言源程序的系统调用白名单生成方法。


背景技术:

2.随着云计算技术的广泛使用,应用越来越多地部署在以docker为代表的容器环境中。与每台虚拟机都能获得一个虚拟的操作系统不同,容器无需将内核和虚拟硬件等资源进行打包,而是直接利用了宿主机的内核,每个容器化的应用都会共享宿主机的内核,每个容器的用户空间相互隔离。因此,容器具有消耗资源更少、启动速度更快等优点。与此同时,由于不同容器共享宿主机的内核,如何保证容器和内核的安全将成为人们关心的问题。如果容器中运行了一个恶意的应用,那么它可以通过执行某些系统调用对内核进行攻击,如引起内存泄漏,发起拒绝服务攻击(参考cve-2018-10924.https://www.cvedetails.com/cve/cve-2018-10924/)以及得到系统的root权限(参考cve-2019-5736.https://cve.mitre.org/cgi-bin/cvename.cgi?name=cve-2019-5736)。因此我们需要限制容器中的应用可以调用的系统调用种类,来防止其对宿主机内核进行攻击。本文提出了一种基于静态分析的系统调用分析方案,并针对python、java和php三种解释型语言,分别设计了一套系统调用的分析工具。在该工具的帮助下,用户只需提供应用的源代码,即可生成一份应用在执行时可能需要调用的系统调用白名单,随后用户可以通过seccomp机制,对应用可以调用的系统调用种类进行限制。
3.系统调用分析
4.目前常用的分析系统调用的方法是动态分析,即在运行程序时统计程序调用的系统调用。linux的strace命令是一个用户程序调试工具,可以用来监控程序运行时使用的所有系统调用。sysdig是一个可视化的容器分析工具,可以追踪特定的容器在执行程序时使用的系统调用。在分析应用的系统调用方面,suyeol lee等人和lingguang lei等人使用strace命令追踪容器在运行时执行的所有系统调用(参考s.lee,j.seo,j.nam,and s.shin.poster:tclp:enforcing least privileges to prevent containers from kernel vulnerabili-ties.in proceedings of the 2019acm sigsac conference on computer and communications security,pages 2665

2667,2019.;l.lei,j.sun,k.sun,c.shenefiel,r.ma,y.wang,and q.li.speaker:split-phase execution of application containers.in international conference on detection of intrusions and malware,and vulnerability assessment,pages 230

251.springer,2017.)。但动态分析的局限在于无法覆盖程序中所有的分支,如果某些函数在程序运行中没有被调用,那么这些函数调用时需要的系统调用将无法被分析到。因此,要想使用动态分析方法,必须设计好完备的测试用例,并且需要多次运行才能得到结果。而静态分析最大的优点就是不用运行源程序,且能覆盖程序中的所有分支。因此,本文采用静态分析和动态分析将结合的方法来分析应用的系统调用。


技术实现要素:

5.针对现有技术中存在的技术问题,本发明的目的在于提供一种面向解释型语言源程序的系统调用白名单生成方法及控制方法。在容器内运行的应用可能会通过执行某些系统调用来攻击宿主机,因而产生一些安全隐患。本发明通过分析应用在运行过程中可能会调用的所有系统调用,生成一个白名单,在容器上运行时,只允许应用调用白名单上的系统调用。
6.本发明的技术方案为:
7.一种面向解释型语言源程序的系统调用白名单生成方法,其步骤包括:
8.1)用户提供待分析应用的源代码目录或者文件,并上传至系统调用分析系统中;
9.2)系统调用分析系统根据接收信息启动待分析程序的源代码,获取该源代码中可能调用的系统调用;
10.进一步的,分析源代码中可能调用的系统调用主要是通过对输入的源代码建立抽象语法树(ast)实现的。本文选取了三种解释型语言python、java和php,由于每种语言的实现机制与运行机制不同,所以对抽象语法树的分析方法也各不相同,本发明根据三种语言不同的特性,对每种语言提出了一种系统调用静态分析方案,总体流程大致为:通过一定的方法得到语言层面的底层函数,并将其映射到二进制文件中,进而通过二进制分析得到操作系统层面的系统调用。下面分别阐述。
11.进一步的,分析python程序中系统调用的方法为:
12.211)使用开源模块astroid为python源代码生成抽象语法树,并遍历其中的函数调用节点,函数调用节点中表示的函数即为一个在代码中被调用的函数,根据这个被调用的函数所在的模块名与类名找出所有c语言函数。因为被调用的函数中还可能调用其他的函数,所以为了完整的统计所有调用的函数,在访问下一个函数调用节点之前,需要先访问表示当前被调用函数的函数体的语法树节点,对函数体中的语法树节点进行遍历,如果遇到函数调用节点,继续使用上述方法遍历被调用函数的函数体节点,经过这样的递归分析,最终输出所有使用c语言函数;
13.212)使用开源模块pycparser对211)步得到的所有c语言函数所在模块的源码生成抽象语法树,根据python的c语言api的特性,找到语法树中表示存放模块中所有函数以及所有类方法的结构体数组的节点,这个数组中每个元素都表示该模块的一个函数或者该模块某个类中的一个方法,每个元素会存储这个函数或者方法在python代码中使用的名称和实现该函数或方法的c语言函数的名称。根据这些信息,可以建立每个c语言函数在python中和c源码中函数名的映射,得到映射之后,根据模块所在的c语言文件是否和解释器编译到了同一个二进制文件中,可以确定模块在编译之后的二进制文件路径(如果模块与解释器编译到了同一个二进制文件中,那么路径为解释器二进制文件的路径,反之,路径则为该模块源文件在编译后对应的动态链接库路径。解释器二进制文件的路径在编译后即可唯一确定,模块编译后的动态链接库路径可以通过模块的__file__属性获得,如果模块没有__file__属性,则表明它和解释器编译到了同一个二进制文件中。)最终输出211)步的所有c语言函数在其源码中的函数名,及其源码所在的动态链接库路径。
14.213)对212)步中输出的二进制文件进行静态分析,得到应用运行时可能调用的所有系统调用。
15.进一步的,分析java程序中系统调用的方法为:
16.221)使用开源工具javaparser为java源代码生成抽象语法树,并遍历其中的方法调用节点,对于每个方法调用节点,根据此方法所在包名和其方法名找到此方法的具体实现,并对每个方法的方法体,建立起语法树递归的进行分析。native方法是一类由其他语言(c语言)实现的java方法,其并无java方法体,递归分析过程中,将遍历到的native方法节点加入集合,最终输出java源程序调用的native方法集合;
17.222)遍历java开发工具包(java development kit)下的动态库文件,针对每一个动态库都导出符号表,截取符号表中的jni函数名,按照一定的规则解析得到对应的native方法名,最终建立起jni函数-native方法映射;
18.223)对jdk所有自带的jni函数进行二进制分析,得到对应的系统调用集合,建立起jni函数-系统调用映射;
19.224)对221)得到的native方法集合,结合222)得到的native方法-jni函数映射,得到执行的jni函数,再结合223)得到的jni函数-系统调用映射,最后得到native方法调用的所有系统调用。
20.进一步的,分析php程序中系统调用的方法为:
21.231)使用开源php静态分析工具phan对整个php应用源代码以及其依赖的第三方库进行扫描,生成抽象语法树,并利用开源静态分析工具phan对抽象语法树进行递归关联搜索生成函数调用链,所有应用源码运行中调用到的php导出函数即为所有函数调用链尾端的函数之和,这些方法类似java当中的native方法,这些方法的底层由c语言实现。
22.232)按照php函数名映射关系,将231)步得到的导出函数名转换为php解释器中对应函数的函数名。这些php中的导出函数与解释器当中具体实现的函数名不同,我们需要对函数名进行映射。函数名虽然不同,但有一定的命名规范。
23.233)对232)步中获取的函数名和php解释器进行二进制代码静态分析,得到应用运行时可能调用的所有系统调用。
24.3)动态分析:用三种语言分别编写一个简单的测试程序,该程序中的语句不需要执行初始化解释器之外的系统调用,比如一个简单的加法计算。然后运行程序,并使用strace命令得到运行时所需的系统调用,这些可认为是python、java和php解释器初始化时所需的所有系统调用。然后将动态分析的结果与相应语言静态分析的结果结合,即为最终输出的系统调用白名单。
25.一种系统调用控制方法,其步骤包括:
26.1)对于待分析应用的源代码,根据该源代码的编写语言选取对应的目标解释器;
27.2)利用所选目标解释器获取该源代码中可能调用的系统调用;
28.3)利用该源代码的编写语言编写一测试程序并运行,获取运行测试程序时所需的系统调用作为该目标解释器初始化时所需的系统调用,然后将其与步骤2)所得系统调用相结合,得到该待分析应用的系统调用白名单;
29.4)获取该待分析应用运行时的系统调用a,如果该系统调用a位于该系统调用白名单中,则运行该系统调用a执行,否则拒绝执行该系统调用a。
30.本发明的有益效果:
31.基于上述三种语言分析系统调用的方案,本发明分别实现了python、java和php的
系统调用分析工具。
32.本发明通过对上述三种语言内部执行过程的分析调研,针对三种语言的特性,总结出了分析系统调用的方案。验证阶段,本文从网络搜集了用三种语言编写的开源程序,对本文提出的系统调用分析工具进行测试,结果显示,工具输出的系统调用数量平均在70-100个,而不加限制时,容器上的应用程序可以调用269个系统调用,可见,有一半以上的系统调用被禁止,且该工具-能根据每种应用生成特定的系统调用白名单,进一步增强了安全性。
附图说明
33.图1为python系统调用分析部分中对python源程序进行分析的流程图;
34.图2为python系统调用分析部分中对c源程序进行分析的流程图;
35.图3为java系统调用分析部分中对java源程序进行分析的流程图;
36.图4为java系统调用分析部分中对本地方法映射进行分析的流程图;
37.图5为java系统调用分析部分中对二进制文件进行分析的流程图;
38.图6为php系统调用分析整体流程图。
具体实施方式
39.python系统调用分析部分主要有三个部分。python源程序分析、c源程序分析以及二进制文件分析。实验中使用的python版本为python3.6。
40.python源程序分析
41.python源程序分析流程如图1所示。为了找出源文件中使用的用c编写的函数,我们需要访问语法树上每一个函数调用节点,并使用astroid的inference功能推断该函数调用的相关信息,如果该函数时builtin函数,那么直接将其加入结果集合,形式为“builtin 函数名”;如果该函数为某个类中的方法,那么还需要判断其在语法树中的函数体是否为空,如果为空则表明它是用c语言编写的函数,这类函数也需要加入结果集合,形式为“模块名 类名 函数名”;如果以上两种情况都不是,那么该函数是某个模块中的一个函数,这时也需要查看其函数体,如果为空就加入结果集合,形式为“模块名 函数名”。随后需访问表示当前被调用函数的函数体的节点,遍历函数体节点的每个子节点,如果遇到函数调用节点,也按照上述方法和形式将符合条件的函数加入结果集合,并对该函数的函数体节点进行递归分析。
42.c源程序分析
43.c源程序分析如图2所示。在这一部分我们使用pycparser对c语言源码建立语法树,并在此基础上进行分析。首先,python模块的c语言源码都有一个"pymoduledef"类型的变量,它记录了模块的相关信息。一个简单的例子如下。
[0044][0045]
该变量是一个结构体,它的第二个元素表示模块名,第五个元素表示模块中的方法集合,所以我们第一步需要遍历语法树,找到这个结构体,并从第二个和第五个元素获得模块的名称和存储模块方法集合的变量名称。随后我们用得到的模块方法集合的名称去语法树中寻找,找到表示该集合的节点。模块的方法集合是一个“pymethoddef"类型的数组,数组中的每一个元素代表模块中的一个方法。一个简单的例子如下。
[0046][0047]
数组中的每一个元素是一个结构体,它的第一个元素是python中的函数名,第二个元素是其c语言源码中的函数名,我们需要用这两个名称对模块中的每个方法建立映射。此外,我们还需要知道模块中类的相关信息。类在源码中是用类型为"pytypeobject"的结构体变量表示的。一个简单的例子如下。
[0048][0049]
在这个结构体变量中,第2个元素代表了该类的类名,第28个元素代表类中的方法集合,这个方法集合与模块中的方法集合的类型相同。为了得到所有类中的方法名映射,我们需要在语法树中找到每一个pytypeobject类型的变量,并从中得到类名与方法集合的名
称,再对方法集合进行分析,这部分的分析方法与分析模块的方法集合相同,故不再赘述。在实际实现中,为加快程序运行效率,我们预先对python中所有用c编写的模块的源码都进行了分析,得到了c函数名和python函数名的对应关系,并存储在一个json文件中,在实际执行时只需在文件中查找即可。
[0050]
二进制文件分析
[0051]
对每一个使用c编写的函数,其所在的模块在python中有两种存在方式。一种是以动态链接库的形式存在,还有些模块和python解释器编译到同一个二进制文件中。该部分对于每一个用c编写的函数,找到其所在模块对应的二进制文件,以待分析的函数为入口,对模块二进制文件进行静态分析,根据系统调用在汇编语言中的指令格式找出其使用的系统调用号,再根据系统的系统调用表,将其转换为对应的系统调用名称。
[0052]
java系统调用分析部分主要有三个部分。java源程序分析、本地方法映射分析和二进制分析。
[0053]
java源程序分析
[0054]
java源程序分析流程如图3所示。图中md代表methoddeclaration节点,mce代表methodcallexpr节点。模块首先接收一个.java文件并生成一颗抽象语法树(ast);之后访问语法树中的md节点,若该方法声明为native方法,则加入native方法集合并访问下一个md节点;否则访问该md节点下的mce节点,并将mce转化为md;若转化成功且转化得到的md节点尚未被访问过,则继续访问该md节点,否则访问剩余mce节点;当项目的所有源文件均被分析后,模块流程终止,返回native方法集合。
[0055]
本地方法映射分析
[0056]
本地方法映射分析如图4所示。模块首先接收一个动态库文件,利用objdump命令导出符号表到txt格式文件中;接着截取符号表中的jni函数名;再按照一定规则解析jni函数名,得到native方法名,建立native方法-jni函数映射;若还有未分析的动态库文件,则重复上述流程,否则结束,返回native方法-jni函数映射。
[0057]
二进制分析
[0058]
二进制分析如图5所示。模块首先以“jni函数名@动态库文件名”的格式,作为二进制分析模块的输入,进行二进制分析,得到系统调用号集合;之后利用ausyscall命令,得到系统调用号-系统调用名映射,将系统调用号转换成系统调用名,建立jni函数-系统调用名映射;最后合并本地方法映射模块返回的native方法-jni函数映射,建立native方法-系统调用名映射。
[0059]
php系统调用分析部分主要有三个部分:php源程序静态分析、函数名映射和二进制静态分析。总体流程图如图6所示。
[0060]
php源程序静态分析
[0061]
当我们获取到待分析程序源代码之后,我们需要对源代码进行静态语法分析,找到所有源程序执行过程中所有可能调用的导出函数。经过对各种工具的尝试,最终选择phan这个静态语法分析工具,phan静态分析工具基于php7 和php-ast扩展,通过phan我们可以检查所有的方法、函数、类、特征、接口、常量和属性变量是否已定义和可访问。phan实现了构建抽象语法树、追踪函数调用链以及检查方法和函数是否可定义、可访问。不仅如此,该工具还可以一直追踪到应用引用的第三方模块中的函数调用链,这样就可以获得应
用用到的第三方库中函数底层用到的导出函数(类似java native方法)。我们通过定位和修改phan底层源码,将这些应用用到的导出函数保存到文件当中。
[0062]
函数名映射
[0063]
通过阅读php源码发现,php的对外暴露的函数主要在main和ext文件夹下,一些内置的函数都是在ext文件夹下,即通过扩展的方式实现,我们可以查看.h文件中的函数定义来得知php暴露了哪些函数。php中函数的函数名和二进制解释器中的函数名是有关联关系的。因为之后是通过对二进制解释器文件进行静态分析,所以需要找出导出函数在二进制解释器中对应的函数名,php中函数名命名有一定的规则,通过编写python代码,依据规则对函数名进行映射。
[0064]
二进制静态分析
[0065]
对解释器中的函数进行二进制静态分析,找到函数使用到的所有的系统调用,保存到文件当中,对所有函数使用系统调用求并集,生成应用程序的系统调用白名单。
[0066]
尽管前面公开的内容示出了本发明的示例性实施例,但应注意,在不背离权利要求限定的本发明的范围的前提下,可以进行多种改变和修改。根据这里描述的发明实施例的结构,权利要求的组成元件可以用任何功能等效的元件替代。因此,本发明的保护范围应当由所附的权利要求书的内容确定。
再多了解一些

本文用于企业家、创业者技术爱好者查询,结果仅供参考。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

相关文献