Improved AMI UCP > NAL unpacking

Fix potential illegal path traversals
This commit is contained in:
platomav 2022-04-15 18:17:58 +03:00
parent 672b4b2321
commit 40686d5edf
13 changed files with 102 additions and 43 deletions

View file

@ -42,4 +42,4 @@ def a7z_decompress(in_path, out_path, in_name, padding, static=False):
printer('Succesfull %s decompression via 7-Zip!' % in_name, padding)
return 0
return 0

View file

@ -18,4 +18,4 @@ def get_chk_8_xor(data, value=0):
value ^= 0x0
return value
return value

View file

@ -48,4 +48,4 @@ def efi_decompress(in_path, out_path, padding, comp_type='--uefi'):
printer('Succesfull EFI/Tiano decompression via TianoCompress!', padding)
return 0
return 0

View file

@ -8,4 +8,4 @@ def get_bgs_tool():
except:
BigScript = None
return BigScript
return BigScript

View file

@ -8,4 +8,4 @@ def get_ordinal(number):
v = number % 100
return f'{number}{s[v % 10]}' if v > 13 else f'{number}{s[v]}'
return f'{number}{s[v % 10]}' if v > 13 else f'{number}{s[v]}'

View file

@ -7,14 +7,55 @@ import sys
import inspect
from pathlib import Path
from common.text_ops import to_string
# Fix illegal/reserved Windows characters
def safe_name(in_name):
def get_safe_name(in_name):
raw_name = repr(in_name).strip("'")
fix_name = re.sub(r'[\\/*?:"<>|]', '_', raw_name)
return fix_name
# Check and attempt to fix illegal/unsafe OS path traversals
def get_safe_path(base_path, user_paths, follow_symlinks=False):
# Convert user path(s) to string w/ OS separators
user_path = to_string(user_paths, os.sep)
# Create target path from base + requested user path
target_path = get_norm_path(base_path, user_path)
# Check if target path is OS illegal/unsafe
if is_safe_path(base_path, target_path, follow_symlinks):
return target_path
# Re-create target path from base + leveled/safe illegal "path" (now file)
nuked_path = get_norm_path(base_path, get_safe_name(user_path))
# Check if illegal path leveling worked
if is_safe_path(base_path, nuked_path, follow_symlinks):
return nuked_path
# Still illegal, create fallback base path + placeholder file
failed_path = get_norm_path(base_path, 'illegal_path_traversal')
return failed_path
# Check for illegal/unsafe OS path traversal
def is_safe_path(base_path, target_path, follow_symlinks=True):
if follow_symlinks:
actual_path = os.path.realpath(target_path)
else:
actual_path = os.path.abspath(target_path)
common_path = os.path.commonpath((base_path, actual_path))
return base_path == common_path
# Create normalized base path + OS separator + user path
def get_norm_path(base_path, user_path):
return os.path.normpath(base_path + os.sep + user_path)
# Walk path to get all files
def get_path_files(in_path):
path_files = []
@ -76,4 +117,4 @@ def get_script_dir(follow_symlinks=True):
if follow_symlinks:
path = os.path.realpath(path)
return os.path.dirname(path)
return os.path.dirname(path)

View file

@ -5,7 +5,7 @@ import re
PAT_AMI_PFAT = re.compile(b'_AMIPFAT.AMI_BIOS_GUARD_FLASH_CONFIGURATIONS', re.DOTALL)
PAT_AMI_UCP = re.compile(br'@(UAF|HPU).{12}@', re.DOTALL)
PAT_DELL_PKG = re.compile(br'\x72\x13\x55\x00.{45}7zXZ', re.DOTALL)
PAT_DELL_HDR = re.compile(br'\xEE\xAA\x76\x1B\xEC\xBB\x20\xF1\xE6\x51.\x78\x9C', re.DOTALL)
PAT_DELL_FTR = re.compile(br'\xEE\xAA\xEE\x8F\x49\x1B\xE8\xAE\x14\x37\x90')
PAT_INTEL_ENG = re.compile(br'\x04\x00{3}[\xA1\xE1]\x00{3}.{8}\x86\x80.{9}\x00\$((MN2)|(MAN))', re.DOTALL)
PAT_DELL_HDR = re.compile(br'\xEE\xAA\x76\x1B\xEC\xBB\x20\xF1\xE6\x51.\x78\x9C', re.DOTALL)
PAT_DELL_PKG = re.compile(br'\x72\x13\x55\x00.{45}7zXZ', re.DOTALL)
PAT_INTEL_ENG = re.compile(br'\x04\x00{3}[\xA1\xE1]\x00{3}.{8}\x86\x80.{9}\x00\$((MN2)|(MAN))', re.DOTALL)

View file

@ -21,4 +21,4 @@ def get_struct(buffer, start_offset, class_name, param_list=None):
ctypes.memmove(ctypes.addressof(structure), struct_data, fit_len)
return structure
return structure

View file

@ -6,7 +6,7 @@ import ctypes
import argparse
import traceback
from common.text_ops import padder
from common.text_ops import padder, to_string
from common.path_ops import process_input_files
# Get Python Version (tuple)
@ -106,11 +106,8 @@ def nice_exc_handler(exc_type, exc_value, tb):
sys.exit(3)
# Show message(s) while controlling padding, newline, pausing & separator
def printer(in_message='', padd_count=0, new_line=True, pause=False, sep_char=' '):
if type(in_message).__name__ in ('list','tuple'):
message = sep_char.join(map(str, in_message))
else:
message = str(in_message)
def printer(in_message='', padd_count=0, new_line=True, pause=False, sep_char=' '):
message = to_string(in_message, sep_char)
padding = padder(padd_count)
@ -118,4 +115,4 @@ def printer(in_message='', padd_count=0, new_line=True, pause=False, sep_char='
output = newline + padding + message
(input if pause and not is_auto_exit() else print)(output)
(input if pause and not is_auto_exit() else print)(output)

View file

@ -3,4 +3,13 @@
# Generate padding (spaces or tabs)
def padder(padd_count, tab=False):
return ('\t' if tab else ' ') * padd_count
return ('\t' if tab else ' ') * padd_count
# Get String from given input object
def to_string(input_object, sep_char=''):
if type(input_object).__name__ in ('list','tuple'):
output_string = sep_char.join(map(str, input_object))
else:
output_string = str(input_object)
return output_string