主要内容

CWE Rule 78

R2026b

Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')

自 R2024a 起

描述

The product constructs all or part of an OS command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended OS command when it is sent to a downstream component.

Polyspace 实现

规则检查项会检查以下问题:

  • 执行外部控制命令

  • 不安全的系统函数调用

示例

全部展开

问题

当命令完全或部分由外部控制的输入构造时,会出现此问题。

风险

攻击者可以将外部控制的输入用作操作系统命令或应用程序的参量。攻击者可以读取或修改敏感数据,执行非预期代码,或者获取对程序其他方面的访问权限。

修复

验证输入,仅允许预期的输入值。例如,创建可接受输入列表,并将输入与该列表进行比较。

扩展检查项

默认情况下,Polyspace® 假定来自外部源的数据已被污染。请参阅Sources of Tainting in a Polyspace Analysis。要将任何并非源自 Polyspace 分析当前作用域的数据视为已被污染,请使用命令行选项 -consider-analysis-perimeter-as-trust-boundary。

示例 - 调用外部命令
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "unistd.h"
#include "dlfcn.h"
#include "limits.h"
#define MAX 128


void taintedexternalcmd(void)
{
	char* usercmd;
	fgets(usercmd,MAX,stdin);
	char cmd[MAX] = "/usr/bin/cat ";
	strcat(cmd, usercmd);
	system(cmd);//Noncompliant 
}

此示例函数在未检查命令变量的情况下,从用户输入调用命令。

更正 - 使用预定义命令

一种可能的更正方法是使用 switch 语句来运行预定义命令,并将用户输入作为 switch 变量。下面这段更正后的代码还将对 system() 的调用替换为对 execve() 的调用,后者的安全性更高。

#define _XOPEN_SOURCE
#define _GNU_SOURCE

#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "unistd.h"
#include "dlfcn.h"
#include "limits.h"

enum {
    SIZE10  =  10,
    SIZE100 = 100,
    SIZE128 = 128
};
enum { CMD0 = 1, CMD1, CMD2 };

void taintedexternalcmd(void)
{
    int usercmd = strtol(getenv("cmd"), NULL, 10);
    char *argv[3];
    char cmd[SIZE128] = "/usr/bin/cat";
    char arg[SIZE10];

    switch(usercmd) {
        case CMD0:
            strcpy(arg, "*.c");
            break;
        case CMD1:
            strcpy(arg, "*.h");
            break;
        case CMD2:
            strcpy(arg, "*.cpp");
            break;
        default:
            strcpy(arg, "*.c");
    }

    argv[0] = cmd;
    argv[1] = arg;
    argv[2] = NULL;

    execve(cmd, argv, NULL);

    // If execve returns, there was an error
    perror("execve");
    exit(EXIT_FAILURE);
}
问题

当您使用的函数会调用实现定义的命令处理器时,会出现此问题。这些函数包括:

  • C 标准 system() 函数。

  • POSIX popen() 函数。

  • Windows® _popen() 和 _wpopen() 函数。

风险

如果调用命令处理器的函数的参量没有经过安全处理,可能会导致可被利用的漏洞。攻击者可能会执行任意命令,或在系统的任何位置读取和修改数据。

修复

不要使用 system 系列函数来调用命令处理器。请改用 POSIX execve() 和 WinAPI CreateProcess() 等更安全的函数。

示例 - 调用 system()
# include <string.h>
# include <stdlib.h>
# include <stdio.h>
# include <unistd.h>

enum { 
SIZE512=512,
SIZE3=3};

void func(char *arg)
{
	char buf[SIZE512];
	int retval=sprintf(buf, "/usr/bin/any_cmd %s", arg);
	
	if (retval<=0 || retval>SIZE512){
		/* Handle error */
		abort();
	}
	/* Use of system() to pass any_cmd with 
	unsanitized argument to command processor */
	
	if (system(buf) == -1) { //Noncompliant
	/* Handle error */
  }
} 

在此示例中,system() 将其参量传递给主机环境,供命令处理器执行。这段代码容易受到命令注入攻击。

更正 - 对参量进行安全处理,并使用 execve()

在以下代码中,any_cmd 的参量经过安全处理,然后传递给 execve() 进行执行。exec 系列函数不易遭受命令注入攻击。

# include <string.h>
# include <stdlib.h>
# include <stdio.h>
# include <unistd.h>

enum { 
SIZE512=512,
SIZE3=3};


void func(char *arg)
{
  char *const args[SIZE3] = {"any_cmd", arg, NULL};
  char  *const env[] = {NULL}; 
  
  /* Sanitize argument */
  
  /* Use execve() to execute any_cmd. */

  if (execve("/usr/bin/time", args, env) == -1) { 
    /* Handle error */
  }
} 

检查信息

类别:数据中性化问题
PQL 名称:std.cwe_native.R78

版本历史记录

在 R2024a 中推出