Skip to content

Instantly share code, notes, and snippets.

@kendallgoto
Created January 10, 2024 10:22
Show Gist options
  • Save kendallgoto/530526755d527f44618ee3baf75e154e to your computer and use it in GitHub Desktop.
Save kendallgoto/530526755d527f44618ee3baf75e154e to your computer and use it in GitHub Desktop.
tear up ilo4_extract.py to messily read ilo3 binaries
#!/usr/bin/python
# modified from https://github.com/airbus-seclab/ilo4_toolbox/blob/master/scripts/iLO4/ilo4_extract.py
# and dependent on some adjacent libraries
# Extract binaries from HPIMAGE update file
# Blackbox analysis, might be inaccurate
import os
import sys
from ilo4lib import *
from struct import unpack_from
BEGIN_SIGN = "--=</Begin HP Signed File Fingerprint\>=--\n"
END_SIGN = "--=</End HP Signed File Fingerprint\>=--\n"
BEGIN_CERT = "-----BEGIN CERTIFICATE-----\n"
END_CERT = "-----END CERTIFICATE-----\n"
IMG_LIST = ["elf", "kernel_main", "kernel_recovery"]
HPIMAGE_HDR_SIZE = 0x4A0
BOOTLOADER_HDR_SIZE = 0x440
IMG_HDR_SIZE = 0x440
if len(sys.argv) != 3:
print "usage: %s <filename> <outdir>"
sys.exit(1)
filename = sys.argv[1]
outdir = sys.argv[2]
if not os.path.exists(outdir):
os.makedirs(outdir)
with open(filename, "rb") as fff:
data = fff.read()
# jump to fingerprints
signature_data = data[:]
cert_num = 0
while True:
end_mark = signature_data.find(END_SIGN)
if end_mark < 0:
break
signature_data = signature_data[end_mark+len(END_SIGN):]
while signature_data.startswith(BEGIN_CERT):
off = signature_data.find(END_CERT) + len(END_CERT)
cert_data = signature_data[:off]
signature_data = signature_data[off:]
print "[+] Extracting certificate %d" % cert_num
with open(outdir + "/cert%d.x509" % cert_num, "wb") as fff:
fff.write(cert_data)
cert_num += 1
#------------------------------------------------------------------------------
# extract HP images: userland, kernel and bootloader
# HPImage header seems to go away in iLO3,
# instead we immediately start with the iLO magic string ...
# if not data.startswith("HPIMAGE"):
# print "[-] Bad file format\n HPIMAGE magic not found"
# sys.exit(1)
# hpimage_header = data[:HPIMAGE_HDR_SIZE]
# data = data[HPIMAGE_HDR_SIZE:]
# offsets_map["HPIMAGE_HDR"] = global_offset
# global_offset += HPIMAGE_HDR_SIZE
# print "[+] iLO HPIMAGE header :"
# with open(outdir + "/hpimage.hdr", "wb") as fff:
# fff.write(hpimage_header)
# img_hdr = HpImageHeader.from_buffer_copy(hpimage_header)
# img_hdr.dump()
#------------------------------------------------------------------------------
# extract target info
# not sure where this lives in ilo3s
#------------------------------------------------------------------------------
# get signature: should be iLO3, iLO4 or iLO5
ilo_sign = data[:4]
ilo_bootloader_header = data[:BOOTLOADER_HDR_SIZE]
ilo_bootloader_footer = data[-0x40:]
data = data[BOOTLOADER_HDR_SIZE:]
print "[+] iLO bootloader header : %s" % (ilo_bootloader_header[:0x1a])
with open(outdir + "/bootloader.hdr", "wb") as fff:
fff.write(ilo_bootloader_header)
bootloader_header = BootloaderHeader.from_buffer_copy(ilo_bootloader_header)
bootloader_header.dump()
with open(outdir + "/bootloader.sig", "wb") as fff:
fff.write(bootloader_header.to_str(bootloader_header.signature))
#------------------------------------------------------------------------------
# extract Bootloader footer and cryptographic parameters
print "[+] iLO Bootloader footer : %s" % (ilo_bootloader_footer[:0x1a])
bootloader_footer = BootloaderFooter.from_buffer_copy(ilo_bootloader_footer)
bootloader_footer.dump()
total_size = bootloader_header.total_size
print "\ntotal size: 0x%08x" % total_size
print "payload size: 0x%08x" % len(data)
print "kernel offset: 0x%08x\n" % bootloader_footer.kernel_offset
ilo_bootloader = data[-bootloader_footer.kernel_offset:-BOOTLOADER_HDR_SIZE]
with open(outdir + "/bootloader.bin", "wb") as fff:
fff.write(ilo_bootloader)
data = data[:total_size-BOOTLOADER_HDR_SIZE]
ilo_crypto_params = data[len(data)-((~bootloader_footer.sig_offset + 1) & 0xFFFF): len(data)-0x40]
with open(outdir + "/sign_params.raw", "wb") as fff:
fff.write(ilo_crypto_params)
crypto_params = SignatureParams.from_buffer_copy(ilo_crypto_params)
crypto_params.dump()
#------------------------------------------------------------------------------
# extract images
ilo_num = 0
off = data.find(ilo_sign)
while off >= 0:
# skip padding
if data[:off] != "\xff" * off:
with open(outdir + "/failed_assert.bin", "wb") as fff:
fff.write(data)
assert(data[:off] == "\xff" * off)
data = data[off:]
# extract header
ilo_header = data[:IMG_HDR_SIZE]
data = data[IMG_HDR_SIZE:]
with open(outdir + "/%s.hdr" % IMG_LIST[ilo_num], "wb") as fff:
fff.write(ilo_header)
print "[+] iLO Header %d: %s" % (ilo_num, ilo_header[:0x1a])
img_header = ImgHeader.from_buffer_copy(ilo_header)
img_header.dump()
with open(outdir + "/%s.sig" % IMG_LIST[ilo_num], "wb") as fff:
fff.write(img_header.to_str(img_header.signature))
payload_size = img_header.raw_size - IMG_HDR_SIZE
data1 = data[:payload_size]
data = data[payload_size:]
psz, = unpack_from("<L", data1)
data1 = data1[4:]
assert(psz == payload_size-4)
assert(psz == len(data1))
window = ['\0'] * 0x1000
wchar = 0
with open(outdir + "/%s.raw" % IMG_LIST[ilo_num], "wb") as fff:
fff.write(data1)
print "[+] Decompressing"
output_size = decompress_all(data1, outdir + "/%s.bin" % IMG_LIST[ilo_num])
print " decompressed size : 0x%08x\n" % (output_size)
print "[+] Extracted %s.bin" % IMG_LIST[ilo_num]
off = data.find(ilo_sign)
ilo_num += 1
if ilo_num == 3:
break
#------------------------------------------------------------------------------
# output offsets map
# broken
print "\n> done\n"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment