SV.FIU.PROCESS_VARIANTS

权限提升风险

某些进程创建系统调用会为本地权限提升带来风险。这些调用容易遭受攻击,此类攻击会通过主机进程权限来允许执行恶意代码。SV.FIU.PROCESS_VARIANTS 检查器会标记以下系统调用:

  • CreateProcess
  • CreateProcessAsUser
  • CreateProcessWithLogon
  • ShellExecute
  • ShellExecuteEx
  • WinExec
  • system
  • _wsystem
  • _*exec*
  • _*spawn*

漏洞与风险

如果在调用进程创建 API 之前,进程创建系统调用没有包含 .exe 可执行文件的完整路径,则可能使攻击者获得发动攻击的机会。搜索路径漏洞可能允许本地用户通过使用恶意 .exe 文件来获得权限。

缓解与预防

为防止暴露于风险之中:

  • 使用 fork、execve 和 pipe 来完全控制进程执行。
  • 在 Win32 CreateProcess、CreateProcessAsUser 或 CreateProcessWithLogonW 函数中,请勿为第一个参数 lpApplicationName 传递空值,以免运行任意命令。如果 lpApplicationName 必须为空,则需要在第二个参数 lpCommandLine 处用引号将路径括起来:
CreateProcess(NULL, "\"C:\Program Files\foo.exe\" -L -S", ...)

漏洞代码示例 #1

复制
  #include <stdio.h>
  #include <sys/types.h>
  #include <sys/stat.h>
  
  int main(int argc, char *argv[]) {
    int fd;
  
    if ((fd = open(argv[1], 0)) == -1) {
      error("can't open %s", argv[1]);
     return -1;
   }
   if (argc == 2) {/* execute command */
     if (execlp ("/bin/sh/", "sh", "-c", argv[1], (char*) 0)) {
 
         /* some code */
       } else {
         error("can't execute %s", argv[1]);
       }
   }
 }

Klocwork 标记出在第 13 行中使用了函数 execlp。该系统调用可能造成通过恶意 .exe 文件实现本地权限提升的风险。

修正代码示例 #1

复制
  #include <stdio.h>
  #include <sys/types.h>
  #include <sys/stat.h>
  
  int main(int argc, char *argv[]) {
    int fd;
  
    if ((fd = open(argv[1], 0)) == -1) {
      error("can't open %s", argv[1]);
     return -1;
   }
   if (argc == 2) {/* execute command */
     if (execve ("/bin/sh/", "sh", "-c", argv[1], (char*) 0)) { 
 
         /* some code */
       } else {
         error("can't execute %s", argv[1]);
       }
   }
 }

在经修复的代码中,函数 execlp 被替换为 execve,它将控制进程执行,消除权限提升的可能性。

漏洞代码示例 #2

复制
  #include <stdlib.h>
  /* Execute a program passed as a command-line argument */
  int main(char *argv[])
  {
      system(argv[1]); /* NON-COMPLIANT */

      return 0;
  }

修正代码示例 #2

复制
  #include <stdio.h>
  #include <stdlib.h>
  #include <unistd.h>

  int    main(int argc, char *argv[])
  {
      char *newargv[] = { NULL, "hello", "world", NULL };
      char *newenviron[] = { NULL };
  
     if (argc != 2) {
  
           fprintf(stderr, "Usage: %s <file-to-exec>\n", argv[0]);
  
           exit(EXIT_FAILURE); 
 
     }
     
     newargv[0] = argv[1];
 
     execve(argv[1], newargv, newenviron); /* COMPLIANT */
     perror("execve");                     /* execve() only returns on error */
     exit(EXIT_FAILURE);
 }

安全培训

应用程序安全培训材料由 Secure Code Warrior 提供。