taint源码分析与使用介绍

一、介绍

动态污点分析(Dynamic Taint Analysis,DTA)是一种动态信息流分析方法,其跟踪程序运行时对数据的处理,并记录处理过程中数据的传播,污点分析的目的是找出目的数据结果与源数据之间的依赖关系。污点分析可以分为三个方面:污点标记、污点传播和污点检查。污点标记是指来自网络等不可信渠道的数据都会被标记为“污点”。在污点标记后,污点数据进行各种运算所得的结果也是不可信的,因此也被标记上了“被污染的”的属性,这个过程就是污点传播。

简介:Taint是一个PHP插件,主要的功能有检测XSS、SQL注入、命令注入、代码注入等漏洞。

原理:检查某些关键函数(是否直接使用(没有经过过滤或转义处理)了来自$_GET,$_POST,$_COOKIE,的数据,如使用则给出提示

二、安装使用

wget http://pecl.php.net/get/taint-1.2.2.tgz (下载最新的taint)
tar zxvf taint-1.2.2.tgz
cd taint-1.2.2
Phpize
./configure
make
make install
配置:php/lib/php.ini

成功安装后,会在nginx的error.log处生成warning日志:

三、漏洞测试:

XSS漏洞代码:$uri = Yii::app()->request->getParam(‘uri‘);echo $uri; Error.log内容:2018/10/09 11:39:29 [error] 14763#0: *2333 FastCGI sent in stderr: "PHP message: PHP Warning:  actionIndex() [echo]: Attempt to echo a string that might be tainted in /home/dly/www/main/controller/TemplateController.php on line 18" while reading response header from upstream, client: 10.0.27.12, server: localhost, request: "GET /Template/index?uri=dlytestxssecho HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "localhost"

SQL漏洞代码: public function getLikeStableLink($url){       $strSql="select id from ".$this->table." where state= 2 AND stable_link like ‘%".$url."%‘ order by create_time desc";        $result=$this->db()->query($strSql);        return $result;    } Error.log内容:2018/10/09 14:28:03 [error] 14762#0: *2483 FastCGI sent in stderr: "PHP message: PHP Warning:  query() [mysqli::query]: SQL statement contains data that might be tainted in /home/dly/www/common/shared/db/DB.php on line 531PHP message: PHP Warning:  query() [mysqli::query]: SQL statement contains data that might be tainted in /home/dly/www/common/shared/db/DB.php on line 531" while reading response header from upstream, client: 10.0.27.12, server: localhost, request: "GET /getinnerlink/index?logid=634395945&url=https%3A%2f%2flocalhost%2fcredit%2f12312&category_id=8 HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "localhost" 

任意文件读取漏洞代码:Echo $uri;$this->renderFile($uri ); Error.log内容:2018/10/09 15:36:19 [error] 14770#0: *2623 FastCGI sent in stderr: "PHP message: PHP Warning:  actionIndex() [echo]: Attempt to echo a string that might be tainted in /home/dly/www/main/controller/TemplateController.php on line 18PHP message: PHP Warning:  renderInternal() [require]: File path contains data that might be tainted in /home/dly/www/framework/web/CBaseController.php on line 123" while reading response header from upstream, client: 10.0.27.12, server: localhost, request: "GET /Template/index?uri=/etc/passwd HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "localhost" 

命令执行漏洞代码:System($_GET[‘a‘]);Error.log内容:2018/10/09 15:57:09 [error] 14769#0: *2651 FastCGI sent in stderr: "PHP message: PHP Warning:  actionIndex() [system]: CMD statement contains data that might be tainted in /home/dly/www/main/controller/TemplateController.php on line 19" while reading response header from upstream, client: 10.0.27.12, server: localhost, request: "GET /Template/index?uri=ifconfig HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "localhost"

代码执行漏洞代码:$fun = $_GET[‘fun‘];$par = $_GET[‘par‘];$fun($par); Error.log内容:2018/10/09 16:00:38 [error] 14769#0: *2653 FastCGI sent in stderr: "PHP message: PHP Warning:  actionIndex() [fcall]: Attempt to call a function which name might be tainted in /home/dly/www/main/controller/TemplateController.php on line 21" while reading response header from upstream, client: 10.0.27.12, server: localhost, request: "GET /Template/index?fun=phpinfo HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "localhost" 

四、代码分析:

1、

#define IS_STR_TAINT_POSSIBLE    (1<<7)
//定义mark规则
#define TAINT_MARK(str)        (GC_FLAGS((str)) |= IS_STR_TAINT_POSSIBLE)
#define TAINT_POSSIBLE(str) (GC_FLAGS((str)) & IS_STR_TAINT_POSSIBLE)
#define TAINT_CLEAN(str)      (GC_FLAGS((str)) &= ~IS_STR_TAINT_POSSIBLE)

2、对用户传入的数据进行mark

PHP_RINIT_FUNCTION(taint)
{
    if (SG(sapi_started) || !TAINT_G(enable)) {
        return SUCCESS;
    }

//污染post数据
    if (Z_TYPE(PG(http_globals)[TRACK_VARS_POST]) == IS_ARRAY) {
        php_taint_mark_strings(Z_ARRVAL(PG(http_globals)[TRACK_VARS_POST]));
    }
//污染GET变量数据
    if (Z_TYPE(PG(http_globals)[TRACK_VARS_GET]) == IS_ARRAY) {
        php_taint_mark_strings(Z_ARRVAL(PG(http_globals)[TRACK_VARS_GET]));
    }
//污染COOKIE数据
    if (Z_TYPE(PG(http_globals)[TRACK_VARS_COOKIE]) == IS_ARRAY) {
        php_taint_mark_strings(Z_ARRVAL(PG(http_globals)[TRACK_VARS_COOKIE]));
    }

    return SUCCESS;
}
//标记所有的GET、COOKIE、POST、SERVER这些array中的每个key->value初始标记为taintstatic void php_taint_mark_strings(zend_array *symbol_table) /* {{{ */ {   zval *val;   ZEND_HASH_FOREACH_VAL(symbol_table, val) {      ZVAL_DEREF(val);      if (Z_TYPE_P(val) == IS_ARRAY) {         php_taint_mark_strings(Z_ARRVAL_P(val));      } else if (IS_STRING == Z_TYPE_P(val) && Z_STRLEN_P(val)) {         TAINT_MARK(Z_STR_P(val));      }   } ZEND_HASH_FOREACH_END();} /* }}} */
 

3、遇到非变量赋值函数时,去掉MARK

赋值函数list:

static void php_taint_override_functions() /* {{{ */ {
    const char *f_join         = "join";
    const char *f_trim         = "trim";
    const char *f_split        = "split";
    const char *f_rtrim        = "rtrim";
    const char *f_ltrim        = "ltrim";
    const char *f_strval       = "strval";
    const char *f_strstr       = "strstr";
    const char *f_substr       = "substr";
    const char *f_sprintf      = "sprintf";
    const char *f_explode      = "explode";
    const char *f_implode      = "implode";
    const char *f_str_pad      = "str_pad";
    const char *f_vsprintf     = "vsprintf";
    const char *f_str_replace  = "str_replace";
    const char *f_str_ireplace = "str_ireplace";
    const char *f_strtolower   = "strtolower";
    const char *f_strtoupper   = "strtoupper";
    const char *f_dirname      = "dirname";
    const char *f_basename     = "basename";
    const char *f_pathinfo     = "pathinfo";

    php_taint_override_func(f_strval, PHP_FN(taint_strval), &TAINT_O_FUNC(strval));
    php_taint_override_func(f_sprintf, PHP_FN(taint_sprintf), &TAINT_O_FUNC(sprintf));
    php_taint_override_func(f_vsprintf, PHP_FN(taint_vsprintf), &TAINT_O_FUNC(vsprintf));
    php_taint_override_func(f_explode, PHP_FN(taint_explode), &TAINT_O_FUNC(explode));
    php_taint_override_func(f_split, PHP_FN(taint_explode), NULL);
    php_taint_override_func(f_implode, PHP_FN(taint_implode), &TAINT_O_FUNC(implode));
    php_taint_override_func(f_join, PHP_FN(taint_implode), NULL);
    php_taint_override_func(f_trim, PHP_FN(taint_trim), &TAINT_O_FUNC(trim));
    php_taint_override_func(f_rtrim, PHP_FN(taint_rtrim), &TAINT_O_FUNC(rtrim));
    php_taint_override_func(f_ltrim, PHP_FN(taint_ltrim), &TAINT_O_FUNC(ltrim));
    php_taint_override_func(f_str_replace, PHP_FN(taint_str_replace), &TAINT_O_FUNC(str_replace));
    php_taint_override_func(f_str_ireplace, PHP_FN(taint_str_ireplace), &TAINT_O_FUNC(str_ireplace));
    php_taint_override_func(f_str_pad, PHP_FN(taint_str_pad), &TAINT_O_FUNC(str_pad));
    php_taint_override_func(f_strstr, PHP_FN(taint_strstr), &TAINT_O_FUNC(strstr));
    php_taint_override_func(f_strtolower, PHP_FN(taint_strtolower), &TAINT_O_FUNC(strtolower));
    php_taint_override_func(f_strtoupper, PHP_FN(taint_strtoupper), &TAINT_O_FUNC(strtoupper));
    php_taint_override_func(f_substr, PHP_FN(taint_substr), &TAINT_O_FUNC(substr));
    php_taint_override_func(f_dirname, PHP_FN(taint_dirname), &TAINT_O_FUNC(dirname));
    php_taint_override_func(f_basename, PHP_FN(taint_basename), &TAINT_O_FUNC(basename));
    php_taint_override_func(f_pathinfo, PHP_FN(taint_pathinfo), &TAINT_O_FUNC(pathinfo));

} /* }}} */

去掉taint标记

PHP_FUNCTION(untaint)
{
    zval *args;
    int argc;
    int i;

    if (!TAINT_G(enable)) {
        RETURN_TRUE;
    }

    if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
    //zend_parse_parameters获取函数传递的参数
    //ZEND_NUM_ARGS函数中传递参数的个数
        return;
    }

    for (i = 0; i < argc; i++) {
        zval *el = &args[i];
        ZVAL_DEREF(el);
//判断变量是string型,并且被标记过
        if (IS_STRING == Z_TYPE_P(el) && TAINT_POSSIBLE(Z_STR_P(el))) {
            TAINT_CLEAN(Z_STR_P(el));
        }
    }

    RETURN_TRUE;
}

4、漏洞判断逻辑(XSS举例):

static int php_taint_echo_handler(zend_execute_data *execute_data) /* {{{ */ {
    const zend_op *opline = execute_data->opline;//指向当前执行的opcode,初始时指向zend_op_array起始位置
    //* opcode指令:即PHP代码具体对应的处理动作,与二进制程序中的代码段对应
    taint_free_op free_op1;
    zval *op1;

    op1 = php_taint_get_zval_ptr(execute_data, opline->op1_type, opline->op1, &free_op1, BP_VAR_R, 0);
    //获取传入函数的参数

    if (op1 && IS_STRING == Z_TYPE_P(op1) && TAINT_POSSIBLE(Z_STR_P(op1))) {
    //Z_STRVAL_P(op1)获取zval中的string类型的值。XSS漏洞只有在string类型的时候才会触发
        if (opline->extended_value) {//opline->extended_value据百度大佬说,这个取出来的函数参数,因为echo使用时,不存在参数传递,但是这个结构却是uint32_t类型感觉跟函数名有关
            php_taint_error("print", "Attempt to print a string that might be tainted");
        } else {
            php_taint_error("echo", "Attempt to echo a string that might be tainted");
        }
    }

    return ZEND_USER_OPCODE_DISPATCH;
} /* }}} */

五、taint存在的问题:

1、无法检测二次漏洞,二次注入,二次命令注入等。
2、使用白名单进行过滤后,依旧会报出来

3、最重要的是,taint中对不在上面所说的赋值函数list中的函数,如base64_decode都当成过滤函数看待,会导致大量漏洞

如:

$a = base64_decode($_GET[‘a‘]);
echo $a;

这种明显是一段XSS漏洞,但是taint无法报出来。

所以修复建议:去掉untaint,自己手写取消mark逻辑。我也是在思考中,有编码进展会直接更新到这篇博客。

原文地址:https://www.cnblogs.com/ermei/p/9778021.html

时间: 2024-08-02 07:37:44

taint源码分析与使用介绍的相关文章

android 6.0 SystemUI源码分析(1)-SystemUI介绍 转

1. SystemUI介绍 SystemUI是一个系统应用,主要功能有: 1)状态栏信息显示,比如电池,wifi信号,3G/4G等icon显示 2)通知面板,比如系统消息,第三方应用消息,都是在通知面板显示. 3)近期任务栏显示面板.比如长按主页或近期任务快捷键,可以显示近期使用的应用. 4)提供截图服务.比如电源+音量加可以截图. 5)提供壁纸服务.比如壁纸的显示. 6)提供屏保服务. 7)系统UI显示.比如系统事件到来时,显示系统UI提示用户. SystemUI源码路径: framework

spark 源码分析之三 -- LiveListenerBus介绍

LiveListenerBus 首先,它定义了 4 个 消息堵塞队列,队列的名字分别为shared.appStatus.executorManagement.eventLog.队列的类型是 org.apache.spark.scheduler.AsyncEventQueue#AsyncEventQueue,保存在 queues 变量中.每一个队列上都可以注册监听器,如果队列没有监听器,则会被移除. 它有启动和stop和start两个标志位来指示 监听总线的的启动停止状态. 如果总线没有启动,有事

详解SpringMVC请求的时候是如何找到正确的Controller[附带源码分析]

目录 前言 源码分析 重要接口介绍 SpringMVC初始化的时候做了什么 HandlerExecutionChain的获取 实例 资源文件映射 总结 参考资料 前言 SpringMVC是目前主流的Web MVC框架之一. 如果有同学对它不熟悉,那么请参考它的入门blog:http://www.cnblogs.com/fangjian0423/p/springMVC-introduction.html 我们使用浏览器通过地址 http://ip:port/contextPath/path进行访问

PreferenceActivity源码分析与简单应用

· PreferenceActivity可以显示一系列Header,每一个Header可以关联一个Fragment或者Activity.此外,它还可以直接显示Preference条目. · PreferenceActivity显示Header的时候有两种模式:single pane和two panes:如果是Fragment,那么在two panes模式下,也就是大屏模式下,它可以同时显示Header和Fragment,这充分利用了屏幕的空间.而在singlepane模式下只会显示Header,

OpenStack Kolla 源码分析 --Ansible

OpenStack Kolla 源码分析 –Ansible Kolla介绍 Kolla项目利用Docker.Docker-Compose.Ansible来完成部署OpenStack,目前Kolla已经能够完成一个all-in-one的开发环境的部署.从Kolla项目spec中的描述来看,主要是利用Docker容器的隔离性来达到OpenStack的原子升级.回退在升级.整个升级.回退的过程更容易控制影响范围,降低整个OpenStack的运维复杂度.Kolla 提供了生产级别的 OpenStack

Stack和Vector源码分析

Stack和Vector源码分析 Stack和Vector源码分析stack源码分析1.Stack是什么2.Stack的结构图3.Stack继承关系4.Stack的主要方法5.Stack源码Vector源码分析1.vector介绍2.vector的关系图3.vector和ArrayList的关系4.Vector的大致图像5.Vector的源码 stack源码分析 1.Stack是什么 Stack是栈.它的特性是:先进后出(FILO, First In Last Out). java工具包中的St

Spark 源码分析系列

如下,是 spark 源码分析系列的一些文章汇总,持续更新中...... Spark RPC spark 源码分析之五--Spark RPC剖析之创建NettyRpcEnv spark 源码分析之六--Spark RPC剖析之Dispatcher和Inbox.Outbox剖析 spark 源码分析之七--Spark RPC剖析之RpcEndPoint和RpcEndPointRef剖析 spark 源码分析之八--Spark RPC剖析之TransportContext和TransportClie

Java ArrayList源码分析(有助于理解数据结构)

arraylist源码分析 1.数组介绍 数组是数据结构中很基本的结构,很多编程语言都内置数组,类似于数据结构中的线性表 在java中当创建数组时会在内存中划分出一块连续的内存,然后当有数据进入的时候会将数据按顺序的存储在这块连续的内存中.当需要读取数组中的数据时,需要提供数组中的索引,然后数组根据索引将内 存中的数据取出来,返回给读取程序.在Java中并不是所有的数据都能存储到数组中,只有相同类型的数据才可以一起存储到数组中.    因为数组在存储数据时是按顺序存储的,存储数据的内存也是连续的

【Heritrix源码分析】Heritrix基本内容介绍

1.版本说明 (1)最新版本:3.3.0 (2)最新release版本:3.2.0 (3)重要历史版本:1.14.4 3.1.0及之前的版本:http://sourceforge.net/projects/archive-crawler/files/ 3.2.0及之后的版本:http://archive.org/ 由于国情需要,后者无法访问,因此本blog研究的是1.14.4版本. 2.官方材料 source:http://sourceforge.net/projects/archive-cra