Fixed path symlink resolutions

This commit is contained in:
platomav 2022-04-16 23:39:56 +03:00
parent 40686d5edf
commit 44546a67c5
2 changed files with 34 additions and 29 deletions

View file

@ -7,7 +7,7 @@ AMI UCP BIOS Extractor
Copyright (C) 2021-2022 Plato Mavropoulos
"""
title = 'AMI UCP BIOS Extractor v2.0_a7'
title = 'AMI UCP BIOS Extractor v2.0_a8'
import os
import re
@ -24,7 +24,7 @@ sys.dont_write_bytecode = True
from common.a7z_comp import a7z_decompress, is_7z_supported
from common.checksums import get_chk_16
from common.efi_comp import efi_decompress, is_efi_compressed
from common.path_ops import get_safe_name, get_safe_path
from common.path_ops import get_comp_path, get_safe_name, get_safe_path
from common.patterns import PAT_AMI_UCP, PAT_INTEL_ENG
from common.struct_ops import get_struct, char, uint8_t, uint16_t, uint32_t
from common.system import script_init, argparse_init, printer
@ -387,7 +387,7 @@ def uaf_extract(buffer, extract_path, mod_info, padding=0, is_checksum=False, na
printer(info_tag + ' : ' + info_value, padding + 8, False) # Print @NAL Module Tag-Path Info
info_part = PurePath(info_value.replace('\\', os.sep)).parts # Split path in parts
info_part = PurePath(get_comp_path(info_value)).parts # Split OS agnostic path in parts
info_path = to_string(info_part[1:-1], os.sep) # Get path without drive/root or file
info_name = info_part[-1] # Get file from last path part

View file

@ -11,29 +11,30 @@ from common.text_ops import to_string
# Fix illegal/reserved Windows characters
def get_safe_name(in_name):
raw_name = repr(in_name).strip("'")
name_repr = repr(in_name).strip("'")
fix_name = re.sub(r'[\\/*?:"<>|]', '_', raw_name)
return fix_name
return re.sub(r'[\\/:"*?<>|]+', '_', name_repr)
# 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
def get_safe_path(base_path, user_paths):
# Convert base path to absolute path
base_path = get_real_path(base_path)
# Convert user path(s) to absolute path with 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):
if is_safe_path(base_path, target_path):
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):
if is_safe_path(base_path, nuked_path):
return nuked_path
# Still illegal, create fallback base path + placeholder file
@ -42,13 +43,12 @@ def get_safe_path(base_path, user_paths, follow_symlinks=False):
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)
def is_safe_path(base_path, target_path):
base_path = get_real_path(base_path)
common_path = os.path.commonpath((base_path, actual_path))
target_path = get_real_path(target_path)
common_path = os.path.commonpath((base_path, target_path))
return base_path == common_path
@ -56,6 +56,14 @@ def is_safe_path(base_path, target_path, follow_symlinks=True):
def get_norm_path(base_path, user_path):
return os.path.normpath(base_path + os.sep + user_path)
# Get absolute path, resolving any symlinks
def get_real_path(in_path):
return str(Path(in_path).resolve())
# Get Windows/Posix OS compatible path
def get_comp_path(in_path):
return in_path.replace('\\', os.sep)
# Walk path to get all files
def get_path_files(in_path):
path_files = []
@ -70,8 +78,8 @@ def get_path_files(in_path):
def get_path_parent(in_path):
return Path(in_path).parent.absolute()
# Get absolute file path (argparse object)
def get_absolute_path(argparse_path):
# Get absolute file path of argparse object
def get_argparse_path(argparse_path):
script_dir = get_path_parent(get_script_dir())
if not argparse_path:
@ -91,30 +99,27 @@ def process_input_files(argparse_args, sys_argv=None):
# Drag & Drop or CLI
if argparse_args.input_dir:
input_path_user = argparse_args.input_dir
input_path_full = get_absolute_path(input_path_user) if input_path_user else ''
input_path_full = get_argparse_path(input_path_user) if input_path_user else ''
input_files = get_path_files(input_path_full)
else:
input_files = [file.name for file in argparse_args.files]
output_path = get_absolute_path(argparse_args.output_dir or argparse_args.input_dir)
output_path = get_argparse_path(argparse_args.output_dir or argparse_args.input_dir)
else:
# Script w/o parameters
input_path_user = input('\nEnter input directory path: ')
input_path_full = get_absolute_path(input_path_user) if input_path_user else ''
input_path_full = get_argparse_path(input_path_user) if input_path_user else ''
input_files = get_path_files(input_path_full)
output_path = get_absolute_path(input('\nEnter output directory path: '))
output_path = get_argparse_path(input('\nEnter output directory path: '))
return input_files, output_path
# https://stackoverflow.com/a/22881871 by jfs
def get_script_dir(follow_symlinks=True):
def get_script_dir():
if getattr(sys, 'frozen', False):
path = os.path.abspath(sys.executable)
path = sys.executable
else:
path = inspect.getabsfile(get_script_dir)
if follow_symlinks:
path = os.path.realpath(path)
return os.path.dirname(path)
return os.path.dirname(get_real_path(path))