From 386dddbb87884f8c9be5f66141246d1412206d0b Mon Sep 17 00:00:00 2001 From: Matthieu Maitre Date: Wed, 6 Mar 2024 15:40:32 -0800 Subject: [PATCH 1/4] Report pickle module as dangerous --- src/picklescan/scanner.py | 5 +---- tests/data/malicious13.pkl | 15 +++++++++++++++ tests/test_scanner.py | 21 +++++++++++++++++---- 3 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 tests/data/malicious13.pkl diff --git a/src/picklescan/scanner.py b/src/picklescan/scanner.py index a5d1dea..d8c5661 100644 --- a/src/picklescan/scanner.py +++ b/src/picklescan/scanner.py @@ -114,15 +114,12 @@ def __str__(self) -> str: "subprocess": "*", "sys": "*", "operator": "attrgetter", # Ex of code execution: operator.attrgetter("system")(__import__("os"))("echo pwned") + "pickle": "*", } # # TODO: handle methods loading other Pickle files (either mark as suspicious, or follow calls to scan other files [preventing infinite loops]) # -# pickle.loads() -# https://docs.python.org/3/library/pickle.html#pickle.loads -# pickle.load() -# https://docs.python.org/3/library/pickle.html#pickle.load # numpy.load() # https://numpy.org/doc/stable/reference/generated/numpy.load.html#numpy.load # numpy.ctypeslib.load_library() diff --git a/tests/data/malicious13.pkl b/tests/data/malicious13.pkl new file mode 100644 index 0000000..a1a75dd --- /dev/null +++ b/tests/data/malicious13.pkl @@ -0,0 +1,15 @@ +cpickle +loads +p0 +(c_codecs +encode +p1 +(VI12345\u000a. +p2 +Vlatin1 +p3 +tp4 +Rp5 +tp6 +Rp7 +. \ No newline at end of file diff --git a/tests/test_scanner.py b/tests/test_scanner.py index e55d9d7..29392c7 100644 --- a/tests/test_scanner.py +++ b/tests/test_scanner.py @@ -78,6 +78,11 @@ def __reduce__(self): return sys.exit, (0,) +class Malicious13: + def __reduce__(self): + return pickle.loads, (b"I12345\n.",) # Loads the value 12345 + + class HTTPResponse: def __init__(self, status, data=None): self.status = status @@ -296,6 +301,7 @@ def initialize_pickle_files(): initialize_pickle_file(f"{_root_path}/data/malicious7.pkl", Malicious6(), 4) initialize_pickle_file(f"{_root_path}/data/malicious8.pkl", Malicious7(), 4) initialize_pickle_file(f"{_root_path}/data/malicious9.pkl", Malicious8(), 4) + initialize_pickle_file(f"{_root_path}/data/malicious13.pkl", Malicious13(), 0) initialize_zip_file( f"{_root_path}/data/malicious1.zip", @@ -516,7 +522,7 @@ def test_scan_file_path(): def test_scan_directory_path(): sr = ScanResult( - [ + globals=[ Global("builtins", "eval", SafetyLevel.Dangerous), Global("httplib", "HTTPSConnection", SafetyLevel.Dangerous), Global("collections", "OrderedDict", SafetyLevel.Innocuous), @@ -550,10 +556,12 @@ def test_scan_directory_path(): Global("os", "system", SafetyLevel.Dangerous), Global("operator", "attrgetter", SafetyLevel.Dangerous), Global("builtins", "__import__", SafetyLevel.Suspicious), + Global("pickle", "loads", SafetyLevel.Dangerous), + Global("_codecs", "encode", SafetyLevel.Suspicious), ], - 24, - 22, - 19, + scanned_files=25, + issues_count=23, + infected_files=20, ) compare_scan_results(scan_directory_path(f"{_root_path}/data/"), sr) @@ -589,3 +597,8 @@ def test_main(): importlib.import_module("picklescan.__main__") finally: sys.argv = argv + + +def test_pickle_files(): + with open(f"{_root_path}/data/malicious13.pkl", "rb") as file: + assert pickle.load(file) == 12345 From d683ef83ebba234a1379902174f3efb76e500d0e Mon Sep 17 00:00:00 2001 From: Matthieu Maitre Date: Wed, 6 Mar 2024 15:41:42 -0800 Subject: [PATCH 2/4] Bump package version --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 40c22a3..68bc1b2 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = picklescan -version = 0.0.13 +version = 0.0.14 author = Matthieu Maitre author_email = mmaitre314@users.noreply.github.com description = Security scanner detecting Python Pickle files performing suspicious actions From 6d6591acdeaacfad4990540f52bc9296dbaeba3f Mon Sep 17 00:00:00 2001 From: Matthieu Maitre Date: Thu, 7 Mar 2024 10:32:33 -0800 Subject: [PATCH 3/4] Handle newer pickle module --- src/picklescan/scanner.py | 1 + .../{malicious13.pkl => malicious13a.pkl} | 0 tests/data/malicious13b.pkl | Bin 0 -> 47 bytes tests/test_scanner.py | 18 +++++++++++++----- 4 files changed, 14 insertions(+), 5 deletions(-) rename tests/data/{malicious13.pkl => malicious13a.pkl} (100%) create mode 100644 tests/data/malicious13b.pkl diff --git a/src/picklescan/scanner.py b/src/picklescan/scanner.py index d8c5661..62bde2b 100644 --- a/src/picklescan/scanner.py +++ b/src/picklescan/scanner.py @@ -115,6 +115,7 @@ def __str__(self) -> str: "sys": "*", "operator": "attrgetter", # Ex of code execution: operator.attrgetter("system")(__import__("os"))("echo pwned") "pickle": "*", + "_pickle": "*", } # diff --git a/tests/data/malicious13.pkl b/tests/data/malicious13a.pkl similarity index 100% rename from tests/data/malicious13.pkl rename to tests/data/malicious13a.pkl diff --git a/tests/data/malicious13b.pkl b/tests/data/malicious13b.pkl new file mode 100644 index 0000000000000000000000000000000000000000..7c413f26da4ea87a250ab54b248b25217381eca3 GIT binary patch literal 47 ycmZo*nX1A70X^*T1)0g&IjK{6Sab3dQ;Mfdp5n~mX=r3@V#=jArFBZs6g>biUk)b# literal 0 HcmV?d00001 diff --git a/tests/test_scanner.py b/tests/test_scanner.py index 29392c7..c265884 100644 --- a/tests/test_scanner.py +++ b/tests/test_scanner.py @@ -301,7 +301,12 @@ def initialize_pickle_files(): initialize_pickle_file(f"{_root_path}/data/malicious7.pkl", Malicious6(), 4) initialize_pickle_file(f"{_root_path}/data/malicious8.pkl", Malicious7(), 4) initialize_pickle_file(f"{_root_path}/data/malicious9.pkl", Malicious8(), 4) - initialize_pickle_file(f"{_root_path}/data/malicious13.pkl", Malicious13(), 0) + initialize_pickle_file( + f"{_root_path}/data/malicious13a.pkl", Malicious13(), 0 + ) # pickle module serialized as cPickle + initialize_pickle_file( + f"{_root_path}/data/malicious13b.pkl", Malicious13(), 4 + ) # pickle module serialized as _pickle initialize_zip_file( f"{_root_path}/data/malicious1.zip", @@ -557,11 +562,12 @@ def test_scan_directory_path(): Global("operator", "attrgetter", SafetyLevel.Dangerous), Global("builtins", "__import__", SafetyLevel.Suspicious), Global("pickle", "loads", SafetyLevel.Dangerous), + Global("_pickle", "loads", SafetyLevel.Dangerous), Global("_codecs", "encode", SafetyLevel.Suspicious), ], - scanned_files=25, - issues_count=23, - infected_files=20, + scanned_files=26, + issues_count=24, + infected_files=21, ) compare_scan_results(scan_directory_path(f"{_root_path}/data/"), sr) @@ -600,5 +606,7 @@ def test_main(): def test_pickle_files(): - with open(f"{_root_path}/data/malicious13.pkl", "rb") as file: + with open(f"{_root_path}/data/malicious13a.pkl", "rb") as file: + assert pickle.load(file) == 12345 + with open(f"{_root_path}/data/malicious13b.pkl", "rb") as file: assert pickle.load(file) == 12345 From 0012bd4512620dafa74dd5effc9946f178ade678 Mon Sep 17 00:00:00 2001 From: Matthieu Maitre Date: Thu, 7 Mar 2024 10:35:28 -0800 Subject: [PATCH 4/4] Fix typo --- tests/test_scanner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_scanner.py b/tests/test_scanner.py index c265884..5193143 100644 --- a/tests/test_scanner.py +++ b/tests/test_scanner.py @@ -303,7 +303,7 @@ def initialize_pickle_files(): initialize_pickle_file(f"{_root_path}/data/malicious9.pkl", Malicious8(), 4) initialize_pickle_file( f"{_root_path}/data/malicious13a.pkl", Malicious13(), 0 - ) # pickle module serialized as cPickle + ) # pickle module serialized as cpickle initialize_pickle_file( f"{_root_path}/data/malicious13b.pkl", Malicious13(), 4 ) # pickle module serialized as _pickle