shell bypass 403
"""
This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License,
or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Copyright © 2019 Cloud Linux Software Inc.
This software is also available under ImunifyAV commercial license,
see <https://www.imunify360.com/legal/eula>
"""
# TODO: The script should be able to process a large number of files and should be optimized for speed
# TODO: It should not use more than X GB of memory
import argparse
import os
from imav.patchman.fs_scanner.utils import HashCalculator
from imav.patchman.fs_scanner.db import DB
from imav.patchman.fs_scanner.matcher import (
PatchDependenciesMatcher,
VersionsMatcher,
)
from imav.patchman.fs_scanner.utils import (
all_possible_relative_paths,
dir_traverse_generator,
)
class ExistingDirAction(argparse.Action):
"""
Check that directory exists and turn its path into absolute path
"""
def __call__(self, parser, namespace, values, option_string=None):
if not os.path.isdir(values):
raise ValueError(f"{values} dir does not exist")
setattr(namespace, self.dest, os.path.abspath(values))
class ReadableFileAction(argparse.Action):
"""
Check that file exists and is readable
"""
def __call__(self, parser, namespace, values, option_string=None):
if not os.path.isfile(values):
raise ValueError(f"{values} does not exist")
if not os.access(values, os.R_OK):
raise ValueError(f"{values} is not readable")
setattr(namespace, self.dest, values)
class WritableFilePathAction(argparse.Action):
"""
Check that file path is writable
"""
def __call__(self, parser, namespace, values, option_string=None):
dir_name = os.path.dirname(values) or "."
if not os.access(dir_name, os.W_OK):
raise ValueError(f"Directory {dir_name} is not writable")
setattr(namespace, self.dest, values)
def main():
argparser = argparse.ArgumentParser()
argparser.add_argument(
"version_identifiers",
type=str,
action=ReadableFileAction,
help="Path to file with version_identifiers",
)
argparser.add_argument(
"patch_deps",
type=str,
action=ReadableFileAction,
help="Path to file with patch_dependencies",
)
argparser.add_argument(
"target_dir",
type=str,
action=ExistingDirAction,
help="Path to target dir",
)
argparser.add_argument(
"--output",
"-o",
type=str,
action=WritableFilePathAction,
help="Path to output sqlite db file",
required=True,
)
argparser.add_argument(
"--algorithm",
type=str,
choices=HashCalculator.HASHING_ALGORITHMS.keys(),
default="md5",
help="Hashing algorithm",
)
args = argparser.parse_args()
versions_matcher = VersionsMatcher(args.version_identifiers)
deps_matcher = PatchDependenciesMatcher(args.patch_deps)
hash_calculator = HashCalculator(args.algorithm)
with DB(args.output) as db:
for file_path in dir_traverse_generator(args.target_dir):
# check all possible relative paths of absolute file_path
for relative_path in all_possible_relative_paths(
file_path, args.target_dir
):
version_matched = versions_matcher.match_and_save(
file_path, relative_path, db, hash_calculator
)
deps_matched = deps_matcher.match_and_save(
file_path, relative_path, db, hash_calculator
)
if version_matched and deps_matched:
# no need to check other possible relative paths if we already have all matches
break
if __name__ == "__main__":
main()