freeBuf
CC++的命令执行分析
2023-06-26 10:03:58
所属地 浙江省

背景

最近发现一个命令执行风险;
一开始提供修复建议,是对特殊字符进行过滤,但是业务侧没有办法过滤,因为输入点是没有办法限制的,然后提供另一个方案是将用户的输入写到配置文件中,然后再进行操作,而不是直接拼接用户的输入;但是提供的方案没有被采纳,所以就有了下文的分析;

本文以Linux环境为背景,只分析C语言的命令执行漏洞。

C的命令执行漏洞分析

漏洞简介

wiki百科上描述:任意代码执行(简称ACE)是指攻击者能够让目标电脑或目标进程中执行任意命令或代码[1]。如果系统有地方可以被黑客利用以执行任意代码,则此处被称为任意代码执行漏洞。特别设计利用此一漏洞的程式,称为任意代码执行漏洞利用。可以通过网络(尤其是通过互联网等广域网)让目标电脑(远程电脑)执行任意代码的能力称为远程代码执行(RCE)。

wiki的描述比较偏于云端的场景,这里场景就是指用户通过浏览器或者其他辅助程序提交数据,由于执行端没有针对执行函数进行过滤,导致在没有指定绝对路径的情况下执行命令。

漏洞成因

在了解漏洞成因之前先看一下C语言在Linux环境中可以执行shell命令的函数;分别是system,popen和exec家族函数。

exec()							# 在当前进程中执行命令,其后所有的代码将被清空,不能执行
system() = fork + exec			# 在子进程中执行指令
popen()  = fork + exec + pipe		# 重定向子进程的标准输入或输出,提供控制子进程输入或输出的能力

关于exec()家族

  • l 代表函数取一个参数列表

execl ("/bin/sh", "sh", "-c", command, (char *) 0);
  • v 代表函数取一个 agrv[] 向量

char *argv[] = {"sh", "-c", command, (char *) 0};
execv("/bin/sh", argv);
  • p 代表通过 PATH 环境变量来查找可执行文件,因此只用提供文件名

execlp ("sh", "sh", "-c", command, (char *) 0);
  • e 代表使用指定的环境变量,函数取一个 envp[] 数组

char *env_init[] = { "USER=unknown", NULL };
execle("/bin/sh", "sh", "-c", command, (char *) 0, env_init);

实例代码

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

int main(int argc, char *argv[])
{
    if (argc < 2) {
        printf("usage: %s param1 [param2 ...[param n]]\n", argv[0]);
        return -1;
    }

    char cmdbuf[128] = {0};
    snprintf(cmdbuf, sizeof(cmdbuf), "ls %s", argv[1]);

    char cmd[128] = {0};
    snprintf(cmd, sizeof(cmdbuf), argv[1]);

    puts("call system function:");
    system(cmdbuf);

    puts("\ncall popen function:");
    FILE *fp = popen(cmdbuf, "r");
    char readbuf[2048] = {0};
    fread(readbuf, 1, 2048, fp);
    puts(readbuf);
    pclose(fp);

    int pid = fork();
    if (pid > 0) {
        sleep(1);
    } else if (pid == 0) {
        //puts("call execl function:");
        //execl("/bin/sh", "sh", "-c", cmdbuf, NULL);

        //puts("call execl function:");
        //execl("/bin/ls", cmd, NULL);

        //puts("call execve function:");
        //execve("/bin/ls", argv, NULL);

        puts("call execvp function:");
        execvp("/bin/ls", argv);
    }
    return 0;
}

测试结果,

Untitled.png
Untitled 1.png
Untitled 2.pngUntitled 3.pngUntitled 4.pngUntitled 5.png

一开始以为参考文章说的没错,自己测试也确实如文章示例一样,然后我试了一下别的playload发现可以绕过了,文章中说通过execve参数注入命令是不会解析执行的,跟自己测试的情况是对不上的;研究此的背景是,研发不采用我提供的修复方案,使用文章中所说的这种修复方式,因为不了解,所以学习一下;

Untitled 6.png
那么如果使用execve的方式不能完全修复,针对此类情况有什么较好的修复方案呢;

命令执行修复方案

在执行命令前,对入参进行过滤,对敏感字符进行转义处理;

其实按理说,只要参数是用户可控的都应该这么处理;

然后有些特殊场景,无法过滤的,可以看一下能否写到配置文件中,然后在进行配置的方式,而不是通过拼接命令执行用户输入的内容;

命令执行常见的绕过方式

管道符

“;”

WIndows:

Untitled 7.png

Linux:

Untitled 8.png

“|”

Untitled 9.png

Untitled 10.png

“||”

Untitled 11.png

Untitled 12.png

“&”

Untitled 13.png
Untitled 14.png

“&&”

Untitled 15.png

Untitled 16.png

linux下绕过空格

{cat,flag.txt}
cat${IFS}flag.txt
cat$IFS$9flag.txt
cat<flag.txt
cat<>flag.txt
ca\t fl\ag.txt

Untitled 17.png

参考

命令注入漏洞介绍(下篇) - FreeBuf网络安全行业门户

命令注入漏洞介绍(上篇) - FreeBuf网络安全行业门户

C 语言执行 shell 命令的三种方式总结_lylhw13_的博客-CSDN博客_c 执行命令

漏洞悬赏计划:涂鸦智能安全响应中心(https://src.tuya.com)欢迎白帽子来探索。

本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
文章目录