将自己放入 chroot 沙箱后如何(合法)访问文件?

发布于 2024-08-25 01:11:06 字数 318 浏览 15 评论 0原文

更改 Linux C++ 程序,从而为用户提供有限的文件访问权限。因此,程序chroot本身到一个沙箱,其中包含用户可以访问的文件。一切顺利。

然而现在,程序需要访问一些文件来满足自己的需要(而不是用户的需要),但它们位于沙箱之外。我知道 chroot 允许访问在 chroot 之前打开的文件,但在这种情况下,所需的文件可能有数百个,因此仅为可能需要的几个文件打开所有文件显然是不切实际的。

有什么办法可以获取这些文件吗?

Changing a Linux C++ program which gives the user limited file access. Thus the program chroots itself to a sandbox with the files the user can get at. All worked well.

Now, however, the program needs to access some files for its own needs (not the user's) but they are outside the sandbox. I know chroot allows access to files opened before the chroot but in this case the needed files could a few among many hundreds so it is obviously impractical to open them all just for the couple that might be required.

Is there any way to get at the files?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

无声情话 2024-09-01 01:11:06

将它们复制到沙箱中或在 chroot 之前将它们全部打开。严重地。如果有办法做到这一点,那就有办法收买它以允许其他访问并使您的保护变得毫无用处。

沙箱的全部目的就是阻止你想要实现的目标。

Copy them into the sandbox or open them all before chrooting. Seriously. If there was a way to do this, there would be a way to suborn it to allow other access and make your protection useless.

The whole point of the sandbox is to prevent exactly what you're trying to achieve.

ι不睡觉的鱼゛ 2024-09-01 01:11:06

如果文件全部位于 1 个目录中,您可以使用 mount 将它们绑定到沙箱内的目录。

mount --bind /path/to/files /sandbox/files

您可以通过 /sandbox/files/ 访问文件。如果您不希望用户看到它们,请执行 mount --bind /path/to/files /sandbox/.files 以便隐藏 .files 目录

If the files are all in 1 directory, you could use mount to bind them to a directory inside the sandbox.

mount --bind /path/to/files /sandbox/files

The you can access the files through /sandbox/files/. If you don't want the user to see them, do mount --bind /path/to/files /sandbox/.files so the .files directory is hidden

分开我的手 2024-09-01 01:11:06

我想您应该能够将程序分成两部分,一部分是 chroot 的,另一部分不是,并且 chroot 部分通过非 chroot 部分请求文件内容您选择的 IPC 机制。

这是一个 hack,很容易出错,从而否定 chroot 的任何好处。就像 paxdiablo 所说,你试图绕过 chroot 沙箱的全部目的,所以你的选择非常非常有限。

也许如果您进一步解释一下您想要实现的目标,我们也许可以提供一些其他想法。例如,SELinux 和 AppArmor 比 chroot 更灵活,并且可能能够为您提供所需的安全性。

I guess that you ought to be able to split your program into two parts, one which is chroot'ed and one which isn't, and have the chroot'ed portion request files' contents from the non-chroot'ed portion via the IPC mechanism of your choice.

This is a hack, and it may be easy to get wrong, negating any benefit of a chroot. Like paxdiablo says, you're trying to get around the whole purpose of a chroot sandbox, so your options are very, very limited.

Maybe if you explained a bit more what you're trying to accomplish, we might be able to offer some other ideas. For example, SELinux and AppArmor are more flexible than chroot and may be able to give you the security you seek.

残龙傲雪 2024-09-01 01:11:06

如果您需要访问的文件位于几个目录中,您可以在 chroot 之前打开这些目录并保存文件描述符。然后,您可以使用所谓的 *at 函数(例如 openat()、renameat() 等)来获取个人文件。基本上,您打开的文件相对于已打开的目录文件描述符而不是 chroot 目录。

这是否安全还有待商榷,但它应该可以在 Linux 中工作。

编辑:这有点丑陋,但似乎有效。你应该比我更多地寻找漏洞。我还没有测试过放弃特权等会如何影响事情。

#include <iostream>
#include <string>

using namespace std;

#include <cstdio>
#include <cstdlib>
#include <cerrno>
#include <cstring>

#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>


int main(int argc, char *argv[])
{
    if (argc < 4)
    {
        cerr << "USAGE: " << argv[0] << " <jail directory> <freeworld directory> <filename>\n";
        exit(EXIT_FAILURE);
    }

    const string JAILDIR(argv[1]);
    const string FREEDIR(argv[2]);
    string freefilename(argv[3]);

    while (freefilename[0] == '/')
        freefilename.erase(0, 1);

    DIR *pDir;

    if ((pDir = opendir(FREEDIR.c_str())) == NULL)
    {
        perror("Could not open outside dir");
        exit(EXIT_FAILURE);
    } 

    int freeFD = dirfd(pDir);

    //cd to jail dir
    if (chdir(JAILDIR.c_str()) == -1)
    {
        perror("cd before chroot");
        exit(EXIT_FAILURE);
    }

    //lock in jail
    if (chroot(JAILDIR.c_str()) < 0)
    {
        cerr << "Failed to chroot to " << JAILDIR << " - " << strerror(errno) << endl;
        exit(EXIT_FAILURE);
    }

    //
    //in jail, won't work
    //

    string JailFile(FREEDIR);
    JailFile += "/";
    JailFile += freefilename;

    int jailFD;

    if ((jailFD = open(JailFile.c_str(), O_RDONLY)) == -1)
    {
        cout << "as expected, could not open " << JailFile << endl;
        perror("exected open fail");
    }
    else
    {
        cout << "defying all logic, opened " << JailFile << endl;
        exit(EXIT_FAILURE);
    }

    //
    //using this works
    //

    if ((jailFD = openat(freeFD, freefilename.c_str(), O_RDONLY)) == -1)
    {
        cout << "example did not work. Could not open " << freefilename << " Sorry!" << endl;
        exit(EXIT_FAILURE);
    }
    else
        cout << "opened " << freefilename << " from inside jail" << endl;

    char     buff[255];
    ssize_t  numread;

    while (1)
    {
        if ((numread = read(jailFD, buff, sizeof(buff) - 1)) == -1)
        {
            perror("read");
            exit(EXIT_FAILURE);
        }

        if (numread == 0)
            break;

        buff[numread] = '\0';
        cout << buff << endl;
    }

    return 0;
}

测试:

echo "Hello World" >/tmp/mystuff.dat

mkdir /tmp/jail

sudo ./myprog /tmp/jail /tmp mystuff.dat

If the files you need to access are within a few directories you could open those directories before you chroot and save the file descriptors. You can then use the so-called *at functions (e.g. openat(), renameat(), etc.) to get at the individual files. Basically you are opening the files relative to the already open directory file descriptors rather than the chrooted directory.

Whether this is a safe thing to do is open to question but it should work in Linux.

EDIT: This is on the ugly side but it seems to work. You should poke around a lot more for vulnerabilities than I have. I haven't tested how dropping privileges and so forth will effect things.

#include <iostream>
#include <string>

using namespace std;

#include <cstdio>
#include <cstdlib>
#include <cerrno>
#include <cstring>

#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>


int main(int argc, char *argv[])
{
    if (argc < 4)
    {
        cerr << "USAGE: " << argv[0] << " <jail directory> <freeworld directory> <filename>\n";
        exit(EXIT_FAILURE);
    }

    const string JAILDIR(argv[1]);
    const string FREEDIR(argv[2]);
    string freefilename(argv[3]);

    while (freefilename[0] == '/')
        freefilename.erase(0, 1);

    DIR *pDir;

    if ((pDir = opendir(FREEDIR.c_str())) == NULL)
    {
        perror("Could not open outside dir");
        exit(EXIT_FAILURE);
    } 

    int freeFD = dirfd(pDir);

    //cd to jail dir
    if (chdir(JAILDIR.c_str()) == -1)
    {
        perror("cd before chroot");
        exit(EXIT_FAILURE);
    }

    //lock in jail
    if (chroot(JAILDIR.c_str()) < 0)
    {
        cerr << "Failed to chroot to " << JAILDIR << " - " << strerror(errno) << endl;
        exit(EXIT_FAILURE);
    }

    //
    //in jail, won't work
    //

    string JailFile(FREEDIR);
    JailFile += "/";
    JailFile += freefilename;

    int jailFD;

    if ((jailFD = open(JailFile.c_str(), O_RDONLY)) == -1)
    {
        cout << "as expected, could not open " << JailFile << endl;
        perror("exected open fail");
    }
    else
    {
        cout << "defying all logic, opened " << JailFile << endl;
        exit(EXIT_FAILURE);
    }

    //
    //using this works
    //

    if ((jailFD = openat(freeFD, freefilename.c_str(), O_RDONLY)) == -1)
    {
        cout << "example did not work. Could not open " << freefilename << " Sorry!" << endl;
        exit(EXIT_FAILURE);
    }
    else
        cout << "opened " << freefilename << " from inside jail" << endl;

    char     buff[255];
    ssize_t  numread;

    while (1)
    {
        if ((numread = read(jailFD, buff, sizeof(buff) - 1)) == -1)
        {
            perror("read");
            exit(EXIT_FAILURE);
        }

        if (numread == 0)
            break;

        buff[numread] = '\0';
        cout << buff << endl;
    }

    return 0;
}

To test:

echo "Hello World" >/tmp/mystuff.dat

mkdir /tmp/jail

sudo ./myprog /tmp/jail /tmp mystuff.dat

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文