Extracts the embedded source code from Cisco Security Agent Management Console.
#!/usr/bin/env python | |
"""htl_extract.py, Extracts the embedded source code from Cisco Security Agent Management Console. | |
Gerry <gerry@hiredhacker.com> | |
""" | |
import os | |
import sys | |
import struct | |
import pefile | |
from itertools import takewhile | |
_KEY = 'Copyright material protected by a technological protection measure!' | |
_KEY_LEN = len(_KEY) | |
def get_section_by_name(pe, name): | |
try: | |
section = filter(lambda s: s.Name == name, pe.sections)[0] | |
except IndexError, e: | |
return None | |
return section | |
def not_null(c): | |
return c != '\0' | |
def decrypt_data(data): | |
decrypted_data = [] | |
for idx, val in enumerate(data): | |
decrypted_data.append(chr(ord(val) - ord(_KEY[idx % _KEY_LEN]))) | |
return ''.join(decrypted_data) | |
def main(output_path="./extracted", filename="webadmin.exe", section_name="htlconst"): | |
pe = pefile.PE(filename, fast_load=True) | |
# Create the output path is needed, then chdir to it | |
output_path = os.path.abspath(output_path) | |
if not os.path.isdir(output_path): | |
os.makedirs(output_path) | |
os.chdir(output_path) | |
# Filename to search for when locating the file table | |
search_string = "login.htl" | |
# The htlconst section contains all the data we need | |
htlconst = get_section_by_name(pe, section_name) | |
assert htlconst is not None, "Could not find section: %s" % section_name | |
image_base = pe.OPTIONAL_HEADER.ImageBase | |
try: | |
# Get index of known filename in htlconst section data | |
filename_offset = htlconst.data.index(search_string) | |
except ValueError: | |
sys.exit("Could not find search string: %s" % search_string) | |
# Get address of known filename in htlconst section | |
filename_rva = filename_offset + htlconst.VirtualAddress + image_base | |
# Search for a pointer to the filename | |
filename_ptr = struct.pack("I", filename_rva) | |
assert filename_ptr in htlconst.data, "Could not find pointer to filename" | |
# Search back for 0x00000000 and add 4 to get the start of the struct | |
table_offset = None | |
filename_ptr_idx = htlconst.data.index(filename_ptr) | |
# Is there a better way todo this? | |
for idx in reversed(xrange(0, filename_ptr_idx, 4)): | |
if htlconst.data[idx:idx+4] == "\x00\x00\x00\x00": | |
table_offset = idx + 4 | |
break | |
assert table_offset is not None, "Could not find start of file table" | |
cur_offset = table_offset | |
while True: | |
# unpack pointers to the filename and its 'encrypted' contents | |
(ptr_filename, ptr_data) = struct.unpack('II', htlconst.data[cur_offset:cur_offset + 8]) | |
# Check for the end of the structure | |
if not htlconst.contains_rva(ptr_data - image_base): | |
break | |
filename = pe.get_string_at_rva(ptr_filename - image_base) | |
print '[+] Extracting: %s' % filename | |
data_offset = (ptr_data - image_base - htlconst.VirtualAddress) | |
encrypted_data = takewhile(not_null, htlconst.data[data_offset:]) | |
decrypted_data = decrypt_data(encrypted_data) | |
f = open(filename, 'w') | |
f.write(decrypted_data) | |
f.close() | |
cur_offset += 8 | |
print "[+] Done extracting %d files." % ((cur_offset - table_offset)/8) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment