有没有办法通过使用任何编译器参数或修改标题/单元文件来禁用C / C ++和Pascal中的system()
和exec()
函数? (这是一个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
及其亲属。
您需要进行适当的沙盒操作,因为即使您以某种方式阻止它们运行外部程序,它们仍然可以执行危险的操作,例如覆盖文件或打开套接字连接到自己的盒子以发送您的宝贵信息的内容。
一种可能性是创建自己的此类函数版本,并将它们链接到您在服务器上编译/链接的每个程序。如果在对象中找到符号,则优先。
只要确保你得到它们;)
以具有尽可能少的权限的用户身份运行程序会好得多。然后您不必担心他们删除/访问系统文件,关闭系统等。
编辑:当然,按照我的逻辑,用户也可以提供自己的函数版本,它可以动态库加载和符号查找来查找原始函数。你真的只需要沙箱。
对于unixoid环境,有Geordi,它使用操作系统的大量帮助来沙箱化要执行的代码。
基本上你想在非常有限的环境中运行代码; Linux提供了一个特殊的进程标志,用于禁用任何系统调用,这些调用可以访问进程在设置标志时没有的资源(即它不允许打开新文件,但任何已打开的文件可能是正常访问)。
我认为Windows应该有类似的机制。
不是真的(因为调用一些库函数会调用system
本身的技巧,或者因为产生进程的功能只能通过fork
和execve
系统调用来完成,它们仍然可用......)。
但你为什么这么问?
您永远不会(因为您已经发现)依赖用户输入是安全的。 system
和execXX
不太可能是你唯一的问题。
这意味着您有以下选择:
chroot
ed监狱中运行该程序(不知道如何在Windows上执行此操作)unix上的数字3可以使用像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不会在宏中允许这种类型的名字。即使他们以某种方式交换这些值,我们也包含了那些会产生编译时错误的头文件。