Closed h00die closed 6 days ago
I've verified that the Ace-Responder POC works for Empire <v5.9.3. Ironically running Empire in a container acts as an inadvertent defense as the container does not have cron
installed and won't run crontabs. I'm working on creating a test container with cron
installed and porting the exploit over to msf.
I've hit a bit of dead end and need help. Stage0 is completed and I've successfully grabbed the staging key from the C2. At Stage1 I'm sending over a SessionID but the server isn't reading it. Below is the Python code I'm trying to replicate from the original POC:
def build_routing_packet(self, meta=0, enc_data=b'', additional=0):
data = self.session_id + struct.pack("=BBHL", 2, meta, additional, len(enc_data))
RC4IV = os.urandom(4)
key = RC4IV + self.sk
rc4EncData = encryption.rc4(key, data)
packet = RC4IV + rc4EncData + enc_data
return packet
And here is the code from my Metasploit module:
1) Generate SessionID
session_id = SecureRandom.alphanumeric(8).encode('UTF-8').upcase
2) Build a Routing Packet
def build_routing_packet(enc_data, stage_num, staging_key, session_id)
# pack data
pack = [2, stage_num, 0, enc_data.length].pack(">CCSL")
# PTHON https://docs.python.org/3/library/struct.html
# =BBHL
# = Native on Linux little endian, need to dynamically find endianess of the machine
# B unsigned char
# H Unsigned Short
# L Unsigned Long
# RUBY From https://docs.ruby-lang.org/en/master/packed_data_rdoc.html
#
# > == big endian < == lil endian
# C = 8 bit unisgned char
# S = Unsigned 16 bit integer
# L = Unsigned long 32 bit integer
#data = session_id + pack
data = session_id + pack
# Generate Cipher & IV
#rc4 = OpenSSL::Cipher.new('rc4')
#rc4.encrypt
iv = OpenSSL::Random.random_bytes(4)
# Turn the key into bytes
key = iv + staging_key
#key_bytes = key.scan(/../).map { |x| x.hex.chr }.join
#rc4.key_len= key_bytes.length
#rc4.key= key_bytes
# encrypt
#d = rc4.update(data) + rc4.final
d = rc4encrypt(key,data)
#final packet
packet = iv + d + enc_data
end
When I run the module I can't move onto the next stage because the server doesn't read the SessionID correctly. I think I'm either not sending the data over in the proper format i.e. not packing it correctly or I haven't implemented RC4 encryption.
These are the logs from the Empire Server when it gets the SessionID:
[WARNING]: strip_python_comments is deprecated and should not be used
[WARNING]: strip_python_comments is deprecated and should not be used
[WARNING]: handle_agent_data(): sessionID GØ=W¿ not present
[ERROR]: http: Error returned for results by 192.168.0.239 : b'ERROR: sessionID G\xc3\x98=W\x15\xc2\xbf\x1b\xc2\x95 not in cache!'
Any ideas on why it's not understanding the SessionID being sent over?
I've created a Docker container to run the proper version of empire you can find it here . My exploit code is available here. Thanks !
The formatting specs look correct to me. Empire's use of struct.pack("=BBHL"
is an odd choice though because it's going to be dependent on the host running Empire's endianness matching the agents. I doubt that's the problem though.
When I've approached these problems in the past, I've isolated the code, and set the values to known contrived values and compared the code I'm porting (Ruby) to the code I'm referencing (Python). This all looks pretty deterministic. Start by unrandomizing everything you can just for right now to compare the results, so substitute os.urandom(4) with b'\xde\xad\xad\x37'
, etc. Rinse and repeat until the Python and Ruby functions return the same output when provided the same input.
Closing since this has been implemented in https://github.com/rapid7/metasploit-framework/pull/19331
Summary
Looks like the Empire C2 framework has an RCE vuln. While @zeroSteiner is mentioned in the article, they aren't claiming this new vuln. I think based on the amount of code in the PoC repo, this may be tough for a beginner.
Basic example
https://aceresponder.com/blog/exploiting-empire-c2-framework
https://github.com/ACE-Responder/Empire-C2-RCE-PoC
Motivation
Hack the hacker time