Я пытался выполнить скрипт Python, используя pexpect на CentOS с Apache от вызова php, но получил ошибку «out of pty devices» только при попытке запустить его из браузера.Если я выполняю код с python или даже php, он работает нормально.
Версия CentOS - 7.5.1804
Версия Python - 2.7.5
Apache / 2.4.6(CentOS)
Я перемонтировал / dev / pts, как предлагалось в нескольких постах с gid 5, добавил пользователя apache в ttl (или gid 5 как бы) и проверил унаследованное членство, протестированное с пользователем apache, выполнил тот же код на коробке Debian без проблем.
$ mount | grep pts
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,seclabel,gid=5,mode=620,ptmxmode=000)
В моей последней попытке я попытался настроить его для cgi, чтобы обойти php, в случае, если это было преступником.Это не было.
Версия, использующая cgi
#!/usr/bin/env python
import pexpect, pickle, cgi, cgitb
cgitb.enable()
print "Content-type: text/html\n\n"
def load_obj(name):
with open(name + '.pkl', 'rb') as f:
return pickle.load(f)
def test(query):
user = load_obj('pw')
password = user['password']
user = user['user']
capture = {}
host = query["host"]
connection = pexpect.spawn("ssh %s@%s" % (user, query['host']))
connection.timeout = 90
connection.expect('.assword:|\?')
print "It worked!"
connection.close()
if __name__ == '__main__':
query = {"host": "x.x.x.x"}
test(query)
Версия, использующая выполнение php / shell
#!/usr/bin/env python
import pexpect, pickle
def load_obj(name):
with open(name + '.pkl', 'rb') as f:
return pickle.load(f)
def test(query):
user = load_obj('pw')
password = user['password']
user = user['user']
capture = {}
host = query["host"]
connection = pexpect.spawn("ssh %s@%s" % (user, query['host']))
connection.timeout = 90
connection.expect('.assword:|\?')
print "It worked!"
connection.close()
if __name__ == '__main__':
query = {"host": "x.x.x.x"}
try:
test(query)
except Exception as e:
print "Fail: " + str(e)
PHP скрипт
<?php
ini_set("display_errors", TRUE);
$output = shell_exec("python /var/www/html/include/test.py");
$output = nl2br("$output");
echo $output;
?>
Работа сshell:
$ python /var/www/html/cgi-enabled/temp.py
It worked!
Работа с PHP с использованием оболочки:
$ php test.php
It worked!<br />
Не работает с CGI:
--> -->
<type 'exceptions.OSError'> Python 2.7.5: /usr/bin/python
Fri May 17 21:39:56 2019
A problem occurred in a Python script. Here is the sequence of function calls leading up to the error, in the order they occurred.
/var/www/html/cgi-enabled/temp.py in ()
24 connection.close()
25
26 if __name__ == '__main__':
27 query = {"host": "x.x.x.x"}
=> 28 test(query)
test = <function test>, query = {'host': 'x.x.x.x'}
/var/www/html/cgi-enabled/temp.py in test(query={'host': 'x.x.x.x'})
18 capture = {}
19 host = query["host"]
=> 20 connection = pexpect.spawn("ssh %s@%s" % (user, query['host']))
21 connection.timeout = 90
22 connection.expect('.assword:|\?')
connection undefined, global pexpect = <module 'pexpect' from '/usr/lib/python2.7/site-packages/pexpect/__init__.pyc'>, pexpect.spawn = <class 'pexpect.pty_spawn.spawn'>, user = 'user', query = {'host': 'x.x.x.x'}
/usr/lib/python2.7/site-packages/pexpect/pty_spawn.py in __init__(self=<pexpect.pty_spawn.spawn object>, command='ssh user@x.x.x.x', args=[], timeout=30, maxread=2000, searchwindowsize=None, logfile=None, cwd=None, env=None, ignore_sighup=False, echo=True, preexec_fn=None, encoding=None, codec_errors='strict', dimensions=None, use_poll=False)
202 self.name = '<pexpect factory incomplete>'
203 else:
=> 204 self._spawn(command, args, preexec_fn, dimensions)
205 self.use_poll = use_poll
206
self = <pexpect.pty_spawn.spawn object>, self._spawn = <bound method spawn._spawn of <pexpect.pty_spawn.spawn object>>, command = 'ssh user@x.x.x.x', args = [], preexec_fn = None, dimensions = None
/usr/lib/python2.7/site-packages/pexpect/pty_spawn.py in _spawn(self=<pexpect.pty_spawn.spawn object>, command='ssh user@x.x.x.x', args=[], preexec_fn=None, dimensions=None)
301
302 self.ptyproc = self._spawnpty(self.args, env=self.env,
=> 303 cwd=self.cwd, **kwargs)
304
305 self.pid = self.ptyproc.pid
cwd undefined, self = <pexpect.pty_spawn.spawn object>, self.cwd = None, kwargs = {'echo': True, 'preexec_fn': None}
/usr/lib/python2.7/site-packages/pexpect/pty_spawn.py in _spawnpty(self=<pexpect.pty_spawn.spawn object>, args=['/usr/bin/ssh', 'user@x.x.x.x'], **kwargs={'cwd': None, 'echo': True, 'env': None, 'preexec_fn': None})
312 def _spawnpty(self, args, **kwargs):
313 '''Spawn a pty and return an instance of PtyProcess.'''
=> 314 return ptyprocess.PtyProcess.spawn(args, **kwargs)
315
316 def close(self, force=True):
global ptyprocess = <module 'ptyprocess' from '/usr/lib/python2.7/site-packages/ptyprocess/__init__.pyc'>, ptyprocess.PtyProcess = <class 'ptyprocess.ptyprocess.PtyProcess'>, ptyprocess.PtyProcess.spawn = <bound method type.spawn of <class 'ptyprocess.ptyprocess.PtyProcess'>>, args = ['/usr/bin/ssh', 'user@x.x.x.x'], kwargs = {'cwd': None, 'echo': True, 'env': None, 'preexec_fn': None}
/usr/lib/python2.7/site-packages/ptyprocess/ptyprocess.py in spawn(cls=<class 'ptyprocess.ptyprocess.PtyProcess'>, argv=['/usr/bin/ssh', 'user@x.x.x.x'], cwd=None, env=None, echo=True, preexec_fn=None, dimensions=(24, 80))
224
225 if use_native_pty_fork:
=> 226 pid, fd = pty.fork()
227 else:
228 # Use internal fork_pty, for Solaris
pid undefined, fd undefined, global pty = <module 'pty' from '/usr/lib64/python2.7/pty.pyc'>, pty.fork = <function fork>
/usr/lib64/python2.7/pty.py in fork()
105 return pid, fd
106
=> 107 master_fd, slave_fd = openpty()
108 pid = os.fork()
109 if pid == CHILD:
master_fd undefined, slave_fd undefined, global openpty = <function openpty>
/usr/lib64/python2.7/pty.py in openpty()
27 except (AttributeError, OSError):
28 pass
=> 29 master_fd, slave_name = _open_terminal()
30 slave_fd = slave_open(slave_name)
31 return master_fd, slave_fd
master_fd undefined, slave_name undefined, global _open_terminal = <function _open_terminal>
/usr/lib64/python2.7/pty.py in _open_terminal()
68 continue
69 return (fd, '/dev/tty' + x + y)
=> 70 raise os.error, 'out of pty devices'
71
72 def slave_open(tty_name):
global os = <module 'os' from '/usr/lib64/python2.7/os.pyc'>, os.error = <type 'exceptions.OSError'>
<type 'exceptions.OSError'>: out of pty devices
args = ('out of pty devices',)
errno = None
filename = None
message = 'out of pty devices'
strerror = None
Не работает с помощью браузера + скрипт php:
Fail: out of pty devices
Редактировать:
Проведя дополнительные исследования, я обнаружил, что SELinux был причиной невозможности создания pty.Тем не менее, я не смог создать правила, чтобы обойти это, и был в состоянии выполнить сценарий, только если я делаю это в разрешающем режиме.Делая это, я все еще получаю журналы от монитора событий, но эти журналы для генерации разрешений с помощью audit2allow были неудачны в их реализации.
$ sudo grep denied /var/log/audit/audit.log
type=AVC msg=audit(1558274289.811:55236): avc: denied { open } for pid=16235 comm="python" path="/dev/ptmx" dev="devtmpfs" ino=7590 scontext=system_u:system_r:httpd_sys_script_t:s0 tcontext=system_u:object_r:ptmx_t:s0 tclass=chr_file
type=AVC msg=audit(1558274289.812:55237): avc: denied { ioctl } for pid=16235 comm="python" path="/dev/ptmx" dev="devtmpfs" ino=7590 scontext=system_u:system_r:httpd_sys_script_t:s0 tcontext=system_u:object_r:ptmx_t:s0 tclass=chr_file
type=AVC msg=audit(1558274289.813:55238): avc: denied { getattr } for pid=16235 comm="python" path="/dev/ptmx" dev="devtmpfs" ino=7590 scontext=system_u:system_r:httpd_sys_script_t:s0 tcontext=system_u:object_r:ptmx_t:s0 tclass=chr_file
Я следовал этому руководству, которое все еще не решало проблему.отказы: https://osric.com/chris/accidental-developer/2017/11/selinux-audit2why-audit2allow-policy-files/
$ sudo audit2why -i /var/log/audit/audit.log
type=AVC msg=audit(1558274289.811:55236): avc: denied { open } for pid=16235 comm="python" path="/dev/ptmx" dev="devtmpfs" ino=7590 scontext=system_u:system_r:httpd_sys_script_t:s0 tcontext=system_u:object_r:ptmx_t:s0 tclass=chr_file
Was caused by:
Missing type enforcement (TE) allow rule.
You can use audit2allow to generate a loadable module to allow this access.
type=AVC msg=audit(1558274289.812:55237): avc: denied { ioctl } for pid=16235 comm="python" path="/dev/ptmx" dev="devtmpfs" ino=7590 scontext=system_u:system_r:httpd_sys_script_t:s0 tcontext=system_u:object_r:ptmx_t:s0 tclass=chr_file
Was caused by:
Missing type enforcement (TE) allow rule.
You can use audit2allow to generate a loadable module to allow this access.
type=AVC msg=audit(1558274289.813:55238): avc: denied { getattr } for pid=16235 comm="python" path="/dev/ptmx" dev="devtmpfs" ino=7590 scontext=system_u:system_r:httpd_sys_script_t:s0 tcontext=system_u:object_r:ptmx_t:s0 tclass=chr_file
Was caused by:
Missing type enforcement (TE) allow rule.
You can use audit2allow to generate a loadable module to allow this access.
[bkapsch@ohcolm-pl-nettlmn01 test]$ sudo audit2allow -i /var/log/audit/audit.log
#============= httpd_sys_script_t ==============
allow httpd_sys_script_t ptmx_t:chr_file { getattr ioctl open };
$ sudo audit2allow -i /var/log/audit/audit.log --module local > local.te
$ make -f /usr/share/selinux/devel/Makefile local.pp
/usr/share/selinux/devel/include/contrib/container.if:14: Error: duplicate definition of container_runtime_domtrans(). Original definition on 14.
/usr/share/selinux/devel/include/contrib/container.if:33: Error: duplicate definition of container_runtime_exec(). Original definition on 60.
/usr/share/selinux/devel/include/contrib/container.if:52: Error: duplicate definition of container_search_lib(). Original definition on 97.
/usr/share/selinux/devel/include/contrib/container.if:71: Error: duplicate definition of container_exec_lib(). Original definition on 116.
/usr/share/selinux/devel/include/contrib/container.if:90: Error: duplicate definition of container_read_lib_files(). Original definition on 135.
/usr/share/selinux/devel/include/contrib/container.if:109: Error: duplicate definition of container_read_share_files(). Original definition on 154.
/usr/share/selinux/devel/include/contrib/container.if:131: Error: duplicate definition of container_exec_share_files(). Original definition on 176.
/usr/share/selinux/devel/include/contrib/container.if:149: Error: duplicate definition of container_manage_lib_files(). Original definition on 194.
/usr/share/selinux/devel/include/contrib/container.if:169: Error: duplicate definition of container_manage_lib_dirs(). Original definition on 251.
/usr/share/selinux/devel/include/contrib/container.if:205: Error: duplicate definition of container_lib_filetrans(). Original definition on 287.
/usr/share/selinux/devel/include/contrib/container.if:223: Error: duplicate definition of container_read_pid_files(). Original definition on 305.
/usr/share/selinux/devel/include/contrib/container.if:242: Error: duplicate definition of container_systemctl(). Original definition on 324.
/usr/share/selinux/devel/include/contrib/container.if:267: Error: duplicate definition of container_rw_sem(). Original definition on 349.
/usr/share/selinux/devel/include/contrib/container.if:285: Error: duplicate definition of container_use_ptys(). Original definition on 367.
/usr/share/selinux/devel/include/contrib/container.if:303: Error: duplicate definition of container_filetrans_named_content(). Original definition on 385.
/usr/share/selinux/devel/include/contrib/container.if:336: Error: duplicate definition of container_stream_connect(). Original definition on 432.
/usr/share/selinux/devel/include/contrib/container.if:355: Error: duplicate definition of container_spc_stream_connect(). Original definition on 453.
/usr/share/selinux/devel/include/contrib/container.if:376: Error: duplicate definition of container_admin(). Original definition on 474.
/usr/share/selinux/devel/include/contrib/container.if:423: Error: duplicate definition of container_spc_read_state(). Original definition on 659.
/usr/share/selinux/devel/include/contrib/container.if:441: Error: duplicate definition of container_auth_domtrans(). Original definition on 521.
/usr/share/selinux/devel/include/contrib/container.if:460: Error: duplicate definition of container_auth_exec(). Original definition on 540.
/usr/share/selinux/devel/include/contrib/container.if:479: Error: duplicate definition of container_auth_stream_connect(). Original definition on 559.
/usr/share/selinux/devel/include/contrib/container.if:498: Error: duplicate definition of container_runtime_typebounds(). Original definition on 578.
Compiling targeted local module
/usr/bin/checkmodule: loading policy configuration from tmp/local.tmp
/usr/bin/checkmodule: policy configuration loaded
/usr/bin/checkmodule: writing binary representation (version 19) to tmp/local.mod
Creating targeted local.pp policy package
rm tmp/local.mod.fc tmp/local.mod
$ sudo semodule -i local.pp
$ sudo grep denied /var/log/audit/audit.log
type=AVC msg=audit(1558274289.811:55236): avc: denied { open } for pid=16235 comm="python" path="/dev/ptmx" dev="devtmpfs" ino=7590 scontext=system_u:system_r:httpd_sys_script_t:s0 tcontext=system_u:object_r:ptmx_t:s0 tclass=chr_file
type=AVC msg=audit(1558274289.812:55237): avc: denied { ioctl } for pid=16235 comm="python" path="/dev/ptmx" dev="devtmpfs" ino=7590 scontext=system_u:system_r:httpd_sys_script_t:s0 tcontext=system_u:object_r:ptmx_t:s0 tclass=chr_file
type=AVC msg=audit(1558274289.813:55238): avc: denied { getattr } for pid=16235 comm="python" path="/dev/ptmx" dev="devtmpfs" ino=7590 scontext=system_u:system_r:httpd_sys_script_t:s0 tcontext=system_u:object_r:ptmx_t:s0 tclass=chr_file
type=AVC msg=audit(1558275000.559:55293): avc: denied { getattr } for pid=16310 comm="python" name="/" dev="devpts" ino=1 scontext=system_u:system_r:httpd_sys_script_t:s0 tcontext=system_u:object_r:devpts_t:s0 tclass=filesystem
type=AVC msg=audit(1558275000.560:55294): avc: denied { getattr } for pid=16310 comm="python" path="/dev/pts/5" dev="devpts" ino=8 scontext=system_u:system_r:httpd_sys_script_t:s0 tcontext=system_u:object_r:devpts_t:s0 tclass=chr_file
type=AVC msg=audit(1558275000.560:55295): avc: denied { read write } for pid=16310 comm="python" name="5" dev="devpts" ino=8 scontext=system_u:system_r:httpd_sys_script_t:s0 tcontext=system_u:object_r:devpts_t:s0 tclass=chr_file
type=AVC msg=audit(1558275000.560:55295): avc: denied { open } for pid=16310 comm="python" path="/dev/pts/5" dev="devpts" ino=8 scontext=system_u:system_r:httpd_sys_script_t:s0 tcontext=system_u:object_r:devpts_t:s0 tclass=chr_file
type=AVC msg=audit(1558275000.562:55296): avc: denied { ioctl } for pid=16311 comm="python" path="/dev/pts/5" dev="devpts" ino=8 scontext=system_u:system_r:httpd_sys_script_t:s0 tcontext=system_u:object_r:devpts_t:s0 tclass=chr_file