Fortify:C 中的路径操作 - 白名单实现不起作用 - fopen 问题

Fortify : Path Manipulation in C - White List Implementation doesn't work - fopen issue

大家好我有一个强化问题"Path manipulation"它是由fopen使用产生的。根据 fortify 我可以实现一个白名单来修复它,所以有我的白名单验证器:

white_list.c

#define BUFF_WHITE_LIST_FILE 200
const char *white_list_validator( char *variable )
{
  FILE *fp = NULL;
  ssize_t read;
  char * line = NULL;
  size_t len = 0;
  char white_list_file_buff[BUFF_WHITE_LIST_FILE];
  if ( __secure_getenv("WHITE_LIST_FILE") == NULL )
    return NULL;
  else
  {
    strncpy(white_list_file_buff,
         __secure_getenv("WHITE_LIST_FILE"),sizeof(white_list_file_buff)-1);
    fp = fopen(white_list_file_buff,"r");
    if ( fp == NULL )
        return NULL;
    else
    {
        while( (read = getline(&line, &len, fp)) != -1 )
        {
            if ( strncmp(line,variable,read - 1) == 0 ){
                fclose(fp);
                return variable;
            }

        }
        fclose(fp);

    }
    if(line)
        free(line);
 }
 return NULL;
}

它 return 如果在 White.list 中找不到 变量 (*) 或 return 指向 char 的指针,则为 NULL它找到了

int main( int argc, char **argv ) {

    FILE *fp = NULL;
    char mrd[50]={0};
    const char *ptr = white_list_validator(argv[1]);

    if ( argv[1] == NULL )
        return -1;

    if(ptr==NULL)
        return -1;
    else
    {
        strncpy(mrd,ptr,sizeof(mrd)-1);
        printf("variables found : %s\n",mrd);

        fp = fopen(mrd,"w");  <------   SINK
        if ( fp == NULL ){
                printf("line 22\n");
                exit(1);
        }
        fprintf(fp, "%s %s %s %d", "We", "are", "in", 2077);
        fclose(fp);

    }

  return 0;
 }

但是当我运行 fortify报告出现fopen中的操作路径漏洞时,我不知道为什么。你可以在代码中看到,在使用fopen管理文件之前它验证了white_list_validator。 所以有人知道为什么它不能正常工作吗?

注意(*) : 导出 WHITE_LIST_FILE=/path/White.list

猫White.list

测试1

测试2

某事

当我运行二进制文件时:

./white_list 东西

找到变量:一些东西

快速搜索 __secure_getenv 会转到此页面:

https://refspecs.linuxfoundation.org/LSB_1.1.0/gLSB/baselib---secure-getenv-1.html

引用:

__secure_getenv(name) has the same specification as getenv(name) with the exception that if the program is running SUID or SGID enabled, the result is always NULL.

所以,问题是:您的程序 运行 是否设置了 SUID 或 SGID 位?作为 据我所知,__secure_getenv 已重命名为 secure_getenv(我的手册页说它出现在 glibc 2.17 中)。 您应该改用它。

另一个原因可能是:如果源字符串的长度比 strncpysize 参数长, 它不会添加 '[=20=]' 终止字节。使用 strncpy 时你应该 始终确保写入 '[=20=]' 终止字节。

man strcpy

#include <string.h>
char *strncpy(char *dest, const char *src, size_t n);

The strncpy() function is similar, except that at most n bytes of src are copied. Warning: If there is no null byte among the first n bytes of src, the string placed in dest will not be null-terminated.

white_list_file_buff 可能不会被 '[=20=]' 终止,因此 fopen 失败。 但是你说你做到了export WHITE_LIST_FILE=/path/White.list。是 /path/White.list 您使用的实际值或一些长度超过 200 个字符?

这里还有你的代码

while( (read = getline(&line, &len, fp)) != -1 )
{
    else if ( strncmp(line,variable,read - 1) == 0 ){
        fclose(fp);
        return variable;
    }

}

是错误的还是您忘记粘贴整个代码?没有 前一个 if 那个 else.

假设您犯了复制粘贴错误,格式如何 White.list?每行仅包含变量名称?您的 strncmp 比较你知道的整行,如果你只想匹配一个 子字符串,你应该使用 strstr.

您的白名单方法方法是从环境变量中获取白名单的名称。这很容易被操纵,甚至无法证明首先实施白名单所增加的复杂性是合理的,而且它当然应该是其自身路径操纵漏洞的原因。使用 __secure_getenv() 获取值并没有真正帮助;这只是意味着如果 运行 在安全的上下文中,您的程序将无法运行。

即使白名单自身的路径在编译时固定,您仍然是从外部源获取白名单路径。这比完全未经验证的用户输入更难操纵,但它并没有真正解决漏洞。

如果您无法将白名单编译到程序中,请考虑硬编码路径前缀白名单和可能出现在其余路径组件中的字符白名单。目前还不清楚 Fortify 是否会真正认识到这是解决问题的方法,但这足以让我满意地将问题的分析设置为 "Not an issue".

Fortify 通常不会将白名单验证识别为解决问题 - 一旦您验证了例程,您需要告诉它这是一个验证例程。这将确保不会报告使用此例程正确验证的任何跟踪。

您应确保已解决其他评论,并验证底层例程本身是安全的。然后,您应该通过规则编辑器添加自定义规则,将白名单例程注册为验证例程。执行此操作的最佳方法是添加 taintFlag="VALIDATED_PATH_MANIPULATION" 的污点标志的验证/清理规则 - 路径操作的接收器规则不应报告此污点的问题。

有关使用污点标志的更多信息,请参阅 https://community.softwaregrp.com/dcvta86296/attachments/dcvta86296/fortify-discussions/2950/1/HP_Fortify_SCA_Custom_Rules_Guide_4.21.pdf