是否可能从受限制的(自定义)shell中逃脱?

huangapple go评论90阅读模式
英文:

Is it possible to break out of a restricted (custom) shell?

问题

不确定这是否是一个适合提问的地方。

假设我编写了一个接受标准输入的shell,过滤输入内容,只允许特定的命令,比如:

  • ls(列出二进制目录和子目录的内容)
  • update(git克隆)
  • build(go build)
  • test(go test)
  • start(仅启动this.service)
  • stop(仅停止this.service)
  • running(二进制文件是否正在执行,以及使用了多少个GOMAXPROCS)
  • usage(内存、CPU使用情况)
  • gensvc(生成.service文件)
  • exit(退出shell/注销)

你猜对了,我试图为用户提供仅限于SSH的非常有限的维护访问权限。

假设我对\0很小心(无论如何,我会使用Go中的bufio.Scanner来编写它)

有没有办法停止正在运行的shell并执行/bin/sh或类似的操作,或者绕过这个shell?

思考逻辑,如果用户只能写入被接受的特定字符串,那么是不可能的。但也许你知道一种方法,一些ctrl+z的魔法,或者其他什么办法。

唯一的攻击面是输入字符串,或者更准确地说是字节。当然,用户可以通过git push一个构建自己的shell或运行特定命令的程序,但这超出了范围(我会使用systemd删除权限并限制设备访问,并禁止除了与数据库服务器的连接、私有tmp等之外的任何东西,还有命名空间和子命名空间,这是待办事项)。

我唯一看到的问题是git push,但我相信我可以在仅限于git的模式下通过argv和将其添加到~/.ssh/authorized_keys来解决这个问题。类似于lish gitmode,如果输入的命令以git开头或类似的形式,就执行标准输入命令。

示例:

https://gist.github.com/dalu/ce2ef43a2ef5c390a819

英文:

Not sure if this is the right place to ask.

Say I write a shell that takes stdin input, filters this input so let's say only certain commands like

  • ls (list contents of binary directory and subdirectory)
  • update (git clone)
  • build (go build)
  • test (go test)
  • start (systemctl start this.service only)
  • stop (systemctl stop this.service only)
  • running (is the binary being executed and with how many GOMAXPROCS?)
  • usage (memory, cpu usage)
  • gensvc (generate .service file)
  • exit (leave shell/logout)

work, you guessed it, I'm trying to give a user only very limited maintenance access over ssh.

Say I'm careful with \0 (I'd write it in Go anyway using bufio.Scanner)

Is there any way to stop the running shell and execute /bin/sh or similar or any way to get around this shell?

The idea is a user should push their stuff via git to a bare repo, this repo is cloned to the filesystem to a certain directory, then go build is called and the binary is ran with a systemd .service file that is generated previously.

Thinking logically, if the user is only able to write certain strings that are accepted, no there is no way. But maybe you know of one, some ctrl+z witchcraft 是否可能从受限制的(自定义)shell中逃脱? or whatever.

The only attack surface is the input string or rather bytes. Of course the user could git push a program that builds its own shell or runs certain commands, but that's out of scope (I would remove capabilities with systemd and restrict device access and forbid anything but the connection to the database server, private tmp and all, namespace and subnamespace it TODO)

The only problem I see is git pushing but I'm sure I could work around that in a git only mode argv and adding it to ~/.ssh/authorized_keys. something like lish gitmode and execute stdin commands if they start with git or something like it.

Example:

https://gist.github.com/dalu/ce2ef43a2ef5c390a819

答案1

得分: 3

如果你只允许特定的命令,你的"shell"将读取命令,解析并执行它,那么你应该是安全的,除非我误解了你的意思。

Go的"内存"不能被执行,除非你使用一些汇编的恶意技巧,所以你不必担心shell注入。

以下是一个安全的示例代码:

func getAction() (name string, args []string) {
    // 从标准输入读取用户的命令
}

func doAction() {
    for {
        action, args := getAction()
        switch action {
            case "update": //假设完整的命令是:update https://repo/path.git
                if len(args) != 1 {
                    //错误处理
                }
                out, err := exec.Command("/usr/bin/git", "clone", "--recursive", args[0]).CombinedOutput()
                // 处理 out 和 err
        }
    }
}

希望对你有帮助!

英文:

If you're only allowed certain commands, your "shell" will read the command, parse it and then execute it then you should be fine, unless I misunderstood it.

Go "memory" can't be executed, not without you doing some nasty hacks with assembly anyway, so you don't have to worry about shell injection.

Something along these lines should be safe:

func getAction() (name string, args []string) {
	// read stdin to get the command of the user
}

func doAction() {
	for {
		action, args := getAction()
		switch action {
			case "update": //let's assume the full command is: update https://repo/path.git
				if len(args) != 1 {
					//error
				}
				out, err := exec.Command("/usr/bin/git", "clone", "--recursive", args[0]).CombinedOutput()
				// do stuff with out and err
		}
	}
} 

答案2

得分: 3

如果您正在自己实现shell并通过exec()直接执行命令,或者在内部实现它们,那么完全可以生成一个安全的受限shell。如果您只是在将命令传递给真正的shell之前表面检查命令行,那么可能会出现一些您意想不到的边界情况。

话虽如此,我对您列出的test命令有些担忧。它是否旨在运行用户上传的Go软件包的测试套件?如果是这样,作为攻击者,我甚至不会尝试利用受限shell:我只需上传一个包含执行我想要的操作的测试的软件包。对于build/start也可以这样说。

英文:

If you are implementing the shell yourself and directly executing the commands via exec() or implementing them internally, then it is certainly possible to produce a secure restricted shell. If you are just superficially checking a command line before passing it on to a real shell then there will probably be edge cases you might not expect.

With that said, I'd be a bit concerned about the test command you've listed. Is it intended to run the test suite of a Go package the user uploads? If so, I wouldn't even try to exploit the restricted shell if I was an attacker: I'd simply upload a package with tests that perform the actions I want. The same could be said for build/start.

答案3

得分: 1

请由渗透测试团队进行审核。

当破坏任何类型的沙盒时,人们可以非常有创造力。只有当您从不接受用户的输入时,您才可以认为自己在本地环境中相对安全(但在这里,任何命令都是输入)- 纸上的安全假设被认为是评估软件的弱点。它们类似于算法的“无错误”假设:一旦您实施它,99% 的时间都会出现错误。

英文:

Have it reviewed by a pentesting team.

People can be very creative when breaking out a sandbox of any type. Only if you never accept the user's input you can consider yourself rather safe on premises (but here any command is an input) - paper security assumptions are considered a weak to assess the software. They are similar to 'no-bug' assumptions for an algorithm on paper: as soon as you implement it, 99% of time a bug raises

huangapple
  • 本文由 发表于 2014年9月30日 10:16:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/26111729.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定