Last active
April 8, 2020 11:08
-
-
Save gerry/765797 to your computer and use it in GitHub Desktop.
Extracts the embedded source code from Cisco Security Agent Management Console.
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
#!/usr/bin/env python | |
"""htl_extract.py, Extracts the embedded source code from Cisco Security Agent Management Console. | |
Gerry <[email protected]> | |
""" | |
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