Created
September 18, 2023 10:24
-
-
Save BorjaMerino/d1534a3b563df9f1d5188c435b98f212 to your computer and use it in GitHub Desktop.
Silly script to extract the compressed-encrypted payload of PNG images dropped by HijackLoader
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# @BorjaMerino (Alpine Security) | |
import lznt1, argparse, os, struct | |
TAG = b'\xC6\xA5\x79\xEA' | |
CHUNK_ID = b'\x49\x44\x41\x54' | |
DWORD = 4 | |
def get_header(png): | |
with open(png, "rb") as file: | |
filebuf = file.read() | |
offset_TAG = filebuf.find(TAG) | |
if offset_TAG != -1: | |
offset_KEY = offset_TAG + DWORD | |
offset_CSIZE = offset_KEY + DWORD | |
offset_USIZE = offset_CSIZE + DWORD | |
KEY = filebuf[offset_KEY:offset_CSIZE] | |
CSIZE = filebuf[offset_CSIZE:offset_USIZE] | |
USIZE = filebuf[offset_USIZE:offset_USIZE + DWORD] | |
print(f"[+] HEADER: 0x{offset_TAG:02X} 0x{KEY.hex().upper()} 0x{CSIZE.hex().upper()} 0x{USIZE.hex().upper()}") | |
print(f"\t TAG: 0x{TAG.hex().upper()}") | |
print(f"\t KEY: 0x{KEY.hex().upper()}") | |
print(f"\t CSIZE: 0x{CSIZE.hex().upper()} ({(int.from_bytes(CSIZE, byteorder='little'))} bytes) ") | |
print(f"\t USIZE: 0x{USIZE.hex().upper()} ({(int.from_bytes(USIZE, byteorder='little'))} bytes)") | |
return offset_TAG, KEY, CSIZE | |
else: | |
print("[-] Header not found :/") | |
return None, None, None | |
def get_encrypted_payload(png, offset_TAG): | |
with open(png, "rb") as file: | |
filebuf = file.read() | |
offset_TAG += DWORD * 4 # ID + XOR + CSIZE + USIZE | |
content_buf = filebuf[offset_TAG:] | |
ID_offset = content_buf.find(CHUNK_ID) | |
if ID_offset != -1: | |
xored_buffer = bytearray() | |
while ID_offset != -1: | |
ID_offset_8 = ID_offset - 8 # Ignoring offset/size for each chunk (changeme) | |
data_to_extract = content_buf[:ID_offset_8] | |
xored_buffer.extend(data_to_extract) | |
content_buf = content_buf[ID_offset + DWORD:] | |
ID_offset = content_buf.find(CHUNK_ID) | |
xored_buffer.extend(content_buf) | |
return xored_buffer | |
else: | |
print("[-] ID chunk not found:/") | |
return None | |
def decrypt_xor(enc_payload, KEY): | |
xor_buff = bytearray() | |
for i, byte in enumerate(enc_payload): | |
xor_byte = byte ^ KEY[i % 4] | |
xor_buff.append(xor_byte) | |
return xor_buff | |
def uncompress_lznt(compressed_payload): | |
output = "payload.bin" | |
try: | |
uncompressed_payload = lznt1.decompress(compressed_payload) | |
except Exception as e: | |
print(f"[-] ERROR occurred while decompressing: {str(e)} :/") | |
uncompressed_payload = None | |
return | |
with open(output, 'wb') as dump_buffer: | |
dump_buffer.write(uncompressed_payload) | |
print(f"[+] Payload saved to {output}") | |
def main(): | |
parser = argparse.ArgumentParser(description="payload extractor") | |
parser.add_argument("File", help="PNG file name") | |
png_file = parser.parse_args().File | |
offset_TAG, KEY, CSIZE = get_header(png_file) | |
if offset_TAG is not None: | |
enc_payload = get_encrypted_payload(png_file, offset_TAG) | |
if enc_payload is not None: | |
dec_payload = decrypt_xor(enc_payload, KEY) | |
uncompress_lznt(dec_payload[:(int.from_bytes(CSIZE, byteorder='little'))]) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment