禁用C和Pascal中的system()和exec()函数

Disable system() and exec() function in C and Pascal

本文关键字:函数 exec 中的 Pascal 禁用 system      更新时间:2023-10-16

是否有任何方法禁用system()exec()功能在C/c++和Pascal,通过使用任何编译器参数或修改头/单元文件?(这是一台Windows)

我已经尝试使用-Dsystem=NONEXIST为gcc和g++,但#include <cstdio>导致编译错误。

编辑:当然我知道他们可以使用#undef system来绕过防御,所以我试着在stdlib.h中注释掉system函数行,但这也不起作用。

EDIT2(注释):它是一个系统,用户提交他们的程序,服务器用不同的输入数据编译并运行它,然后将程序输出与预先计算的标准输出进行比较,看程序是否正确。现在一些用户发送类似system("shutdown -s -t 0");的代码来关闭服务器。

服务器运行Windows系统,所以我没有任何chroot环境。此外,服务器应用程序是闭源的,所以我不能做什么来控制用户提交的程序是如何执行的。我能做的是修改编译器命令行参数和修改头文件。

好吧,你可以试试:

#define system DontEvenThinkAboutUsingThisFunction
#define exec   OrThisOneYouClown

在头文件中,但我很确定任何一个称职的代码猴子都可以绕过这样的"保护"。

我很想了解为什么你认为这是必要的(如果我们更好地理解这个问题,可能会有更好的解决方案)。

唯一想到的是你想提供一些类似于Euler项目的在线编译器/运行器。如果是这种情况,那么您可以在代码中搜索字符串system<whitespace>(作为选项,但即使这样,有决心的一方也可以:

#define InoccuousFunction system

来绕过你的防御。

如果的情况,您可能想要考虑使用chroot之类的东西,这样没有人甚至可以获得访问到任何危险的二进制文件,如shutdown(而且那个特定的野兽无论如何都不应该由普通用户运行)-换句话说,限制他们的环境,使只有他们甚至可以看到gcc和它的同类。

你需要做适当的沙箱,因为即使你以某种方式阻止他们运行外部程序,他们仍然可能做一些危险的事情,比如覆盖文件或打开套接字连接到他们自己的盒子,通过你的宝贵信息的内容发送。

一种可能性是创建您自己版本的这些函数,并将它们链接到您在服务器上编译/链接的每个程序中。如果在对象中找到该符号,它将优先。

确保你得到了它们;)

使用尽可能少的权限的用户运行程序会更好。这样你就不用担心他们会删除/访问系统文件,关闭系统等等。

EDIT:当然,根据我的逻辑,用户也可以提供他们自己版本的函数,它可以动态加载库&符号查找查找原始函数。你只需要对它进行沙盒处理。

对于单类环境,有Geordi,它使用操作系统的大量帮助来沙箱化要执行的代码。

基本上你想在一个非常受限的环境中运行代码;Linux提供了一个特殊的进程标志,用于禁用任何系统调用,这些系统调用将允许访问进程在设置该标志时没有的资源(即,它禁止打开新文件,但任何已经打开的文件都可以正常访问)。

我认为Windows应该有类似的机制。

不是真的(因为调用一些会调用system本身的库函数的技巧,或者因为生成进程的功能可以只用fork &execve系统调用,仍然可用…)。

但是为什么要问呢?

你永远不能(正如你所发现的)依赖用户输入是安全的。systemexecXX不太可能是您唯一的问题。

这意味着您有以下选项:

  1. 在某种chroot版本的监狱中运行程序(不确定如何在windows上这样做)
  2. 编译前扫描代码,确保没有"非法"函数。
  3. 编译后扫描可执行二进制文件,确保它没有使用任何"禁止"的库函数。
  4. 阻止链接器链接到任何外部库,包括unix上的标准C库(libc)。然后,您可以创建自己的"libc",它显式地允许某些功能。

Number 3在unix上可以使用像readelf或objdump这样的工具来检查链接的符号。这也可以使用二进制文件描述符库来完成。

第4条需要修改编译器标志,但可能是上面列出的选项中最安全的。

你可以这样写

#include<stdlib.h>
#include<unistd.h>
#define system  <stdlib.h>
#define exec   <unistd.h>

在这种情况下,即使用户想要交换宏值,他们也不能。如果它们试图像这样交换宏值

#define <stdlib.h> system
#define <unistd.h> exec

不能,因为C不允许在宏中使用这种类型的名字。即使它们以某种方式交换了这些值,那么我们已经包含了那些将创建编译时错误的头文件。