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);
}