diff --git a/CVE-2021-44228_log4j-core/CVE-2021-44228.sh b/CVE-2021-44228_log4j-core/CVE-2021-44228.sh index 7562488..13681cf 100755 --- a/CVE-2021-44228_log4j-core/CVE-2021-44228.sh +++ b/CVE-2021-44228_log4j-core/CVE-2021-44228.sh @@ -7,7 +7,7 @@ # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -VERSION="1.0" +VERSION="1.1" # Warning! Be sure to download the latest version of this script from its primary source: @@ -223,8 +223,8 @@ basic_args() { fi # canonicalize path (strip trailing /, convert to absolute, follow symlink) - scan_path="$( readlink -f "$scanpath" )" - tmp_path="$( readlink -f "$tmppath" )" + scan_path="$( readlink -f -- "$scanpath" )" + tmp_path="$( readlink -f -- "$tmppath" )" # strip trailing / scanpath="${scanpath%/}" @@ -437,7 +437,7 @@ is_subpath() { # Both supplied paths must be canonical. This eliminates symlinks and things like /../ - if [[ "$( readlink -f "$base_path_is" )" != "$base_path_is" ]] ; then + if [[ "$( readlink -f -- "$base_path_is" )" != "$base_path_is" ]] ; then err_internal_path_validation # exit 3 else check_2_a=1 @@ -445,7 +445,7 @@ is_subpath() { check_4_a=1 fi - if [[ "$( readlink -f "$proposed_path_is" )" != "$proposed_path_is" ]] ; then + if [[ "$( readlink -f -- "$proposed_path_is" )" != "$proposed_path_is" ]] ; then err_internal_path_validation # exit 3 else check_2_b=1 @@ -730,7 +730,7 @@ safe_sha256_sum_from_file() { fi local hash - hash="$( sha256sum "$src" )" + hash="$( sha256sum -- "$src" )" hash="${hash%% *}" if [[ $hash =~ ^[01-9a-f]{64}$ ]] ; then @@ -873,7 +873,7 @@ prepare_directories() { # Side effects: # Exits, if there's an issue, such as non-writable tmp_path. ( - cd "$tmp_path" || err_inaccessible + cd -- "$tmp_path" || err_inaccessible local are_there_files=(*) if (( "${#are_there_files[@]}" != 0 )) ; then @@ -924,13 +924,13 @@ delete_directories() { local check_report # All these paths should already be canonical, so let's canonicalize them again to check again. - check_queue="$( readlink -f "$tmp_path/$queue" || exit 1 )" - check_catalog="$( readlink -f "$tmp_path/$catalog" || exit 1 )" - check_decompressed="$( readlink -f "$tmp_path/$decompressed" || exit 1 )" - check_parents="$( readlink -f "$tmp_path/$parents" || exit 1 )" - check_backtrack="$( readlink -f "$tmp_path/$backtrack" || exit 1 )" - check_detections="$( readlink -f "$tmp_path/$detections" || exit 1 )" - check_report="$( readlink -f "$tmp_path/$report" || exit 1 )" + check_queue="$( readlink -f -- "$tmp_path/$queue" || exit 1 )" + check_catalog="$( readlink -f -- "$tmp_path/$catalog" || exit 1 )" + check_decompressed="$( readlink -f -- "$tmp_path/$decompressed" || exit 1 )" + check_parents="$( readlink -f -- "$tmp_path/$parents" || exit 1 )" + check_backtrack="$( readlink -f -- "$tmp_path/$backtrack" || exit 1 )" + check_detections="$( readlink -f -- "$tmp_path/$detections" || exit 1 )" + check_report="$( readlink -f -- "$tmp_path/$report" || exit 1 )" # Making sure tmp_path didn't get emptied somewhere. # Making sure the temporary directory contains the right number of items. @@ -1043,7 +1043,7 @@ is_zip() { if [[ -f "$file_to_check" && ! -L "$file_to_check" ]] ; then validate_path_inside_scan_or_tmp "$( pwd )/$file_to_check" - file -b "$file_to_check" | grep -q -E '^(Java archive data)|(Zip archive data)' + file -b -- "$file_to_check" | grep -q -E '^(Java archive data)|(Zip archive data)' else return 1 fi @@ -1067,7 +1067,7 @@ is_log4j() { local parent_il if [[ -d "$file_to_check" && ! -L "$file_to_check" ]] ; then ( - cd "$file_to_check" && { + cd -- "$file_to_check" && { # Forbid reading from anywhere else than inside scan_path or tmp_path validate_path_inside_scan_or_tmp "$( pwd )" @@ -1107,7 +1107,7 @@ is_vulnerable() { if [[ -d "$file_to_check" && ! -L "$file_to_check" ]] ; then ( - cd "$file_to_check" && { + cd -- "$file_to_check" && { # Forbid reading from anywhere else than inside scan_path or tmp_path validate_path_inside_scan_or_tmp "$( pwd )" @@ -1191,7 +1191,7 @@ catalog_dir() { if [[ -d "$dir_to_catalog" && ! -L "$dir_to_catalog" ]] ; then ( - cd "$dir_to_catalog" && { + cd -- "$dir_to_catalog" && { # Forbid reading from anywhere else than inside scan_path or tmp_path if [[ "$dir_to_catalog" != "$scan_path" ]] ; then validate_path_inside_scan_or_tmp "$( pwd )" @@ -1235,7 +1235,7 @@ catalog_file() { # Forbid reading from anywhere else than inside scan_path or tmp_path validate_path_inside_scan_or_tmp "$( pwd )/$file_to_catalog" - size="$( stat -c%s "$file_to_catalog" )" + size="$( stat -c%s -- "$file_to_catalog" )" # smallest known log4j-core is 375010 bytes, smallest known non-alpha is 702665 bytes, so 300k leaves us with a cushion in case there are other builds out there if (( size > 300000 )) ; then @@ -1314,7 +1314,7 @@ unpack_cataloged_recatalog() { validate_path_tmp "$tmp_path/$queue" "$queued_path" - cataloged_hash_ucr="$( basename "$queued_path" )" + cataloged_hash_ucr="$( basename -- "$queued_path" )" cataloged_hash_ucr="${cataloged_hash_ucr#q-${queue_position}-}" if [[ "$queued_path" != "$tmp_path/$queue/q-$queue_position-$cataloged_hash_ucr" ]] ; then echo "An external modification occurred in $tmp_path/$queue" @@ -1395,16 +1395,16 @@ produce_report() { # Record all leaf file path fragments (like "/log4j.jar") and all the parents that include these vulnerable files for detection_note_pr in "$tmp_path/$detections"/* ; do - cataloged_hash_pr="$( basename "$detection_note_pr" )" + cataloged_hash_pr="$( basename -- "$detection_note_pr" )" validate_path_tmp "$tmp_path/$detections" "$tmp_path/$detections/$cataloged_hash_pr" validate_path_tmp "$tmp_path/$parents" "$tmp_path/$parents/$cataloged_hash_pr" for immediate_parent_pr in "$tmp_path/$parents/$cataloged_hash_pr"/* ; do - immediate_parent_cataloged_hash_pr="$( basename "$immediate_parent_pr" )" + immediate_parent_cataloged_hash_pr="$( basename -- "$immediate_parent_pr" )" validate_path_tmp "$tmp_path/$parents/$cataloged_hash_pr" "$tmp_path/$parents/$cataloged_hash_pr/$immediate_parent_cataloged_hash_pr" validate_path_tmp "$tmp_path/$parents/$cataloged_hash_pr" "$immediate_parent_pr" for immediate_parent_pathfragment_path_pr in "$immediate_parent_pr"/* ; do validate_path_tmp "$tmp_path/$parents/$cataloged_hash_pr/$immediate_parent_cataloged_hash_pr" "$immediate_parent_pathfragment_path_pr" - immediate_parent_pathfragment_fn_pr="$( basename "$immediate_parent_pathfragment_path_pr" )" + immediate_parent_pathfragment_fn_pr="$( basename -- "$immediate_parent_pathfragment_path_pr" )" validate_path_tmp "$tmp_path/$parents/$cataloged_hash_pr/$immediate_parent_cataloged_hash_pr" "$tmp_path/$parents/$cataloged_hash_pr/$immediate_parent_cataloged_hash_pr/$immediate_parent_pathfragment_fn_pr" immediate_parent_pathfragment_pr="$( safe_cat_parents "$cataloged_hash_pr/$immediate_parent_cataloged_hash_pr/$immediate_parent_pathfragment_fn_pr" )" immediate_parent_pathfragment_hash_pr="$( safe_sha256_sum_from_string "$immediate_parent_pathfragment_pr" )" @@ -1424,20 +1424,20 @@ produce_report() { # One of them should be "0" - the scan_path. # If there's sth else, it's yet-unresolved path fragments. for parent_pr in "$tmp_path/$backtrack"/* ; do - parent_cataloged_hash_pr="$( basename "$parent_pr" )" + parent_cataloged_hash_pr="$( basename -- "$parent_pr" )" if [[ "$parent_cataloged_hash_pr" == "0" ]] ; then continue fi for grandparent_pr in "$tmp_path/$parents/$parent_cataloged_hash_pr"/* ; do - grandparent_cataloged_hash_pr="$( basename "$grandparent_pr" )" + grandparent_cataloged_hash_pr="$( basename -- "$grandparent_pr" )" for grandparent_pathfragment_path_pr in "$grandparent_pr"/* ; do validate_path_tmp "$tmp_path/$parents/$parent_cataloged_hash_pr/$grandparent_cataloged_hash_pr" "$grandparent_pathfragment_path_pr" - grandparent_pathfragment_fn_pr="$( basename "$grandparent_pathfragment_path_pr" )" + grandparent_pathfragment_fn_pr="$( basename -- "$grandparent_pathfragment_path_pr" )" validate_path_tmp "$tmp_path/$parents/$parent_cataloged_hash_pr/$grandparent_cataloged_hash_pr" "$tmp_path/$parents/$parent_cataloged_hash_pr/$grandparent_cataloged_hash_pr/$grandparent_pathfragment_fn_pr" grandparent_pathfragment_pr="$( safe_cat_parents "$parent_cataloged_hash_pr/$grandparent_cataloged_hash_pr/$grandparent_pathfragment_fn_pr" )" for parent_pathfragment_path_pr in "$parent_pr"/* ; do validate_path_tmp "$tmp_path/$backtrack" "$parent_pathfragment_path_pr" - parent_pathfragment_fn_pr="$( basename "$parent_pathfragment_path_pr" )" + parent_pathfragment_fn_pr="$( basename -- "$parent_pathfragment_path_pr" )" validate_path_tmp "$tmp_path/$backtrack" "$tmp_path/$backtrack/$parent_cataloged_hash_pr/$parent_pathfragment_fn_pr" parent_pathfragment_pr="$( safe_cat_backtrack "$parent_cataloged_hash_pr/$parent_pathfragment_fn_pr" )" # Double slash to signify an archive (one of the slashes is already at the beginning of $parent_pathfragment_pr) @@ -1461,7 +1461,7 @@ produce_report() { # Copy and rename the files into "report" for detection_path_pr in "$tmp_path/$backtrack"/0/* ; do - detection_path_basename_pr="$( basename "$detection_path_pr" )" + detection_path_basename_pr="$( basename -- "$detection_path_pr" )" report_filename_pr="vuln_log4j2_path_${detection_path_basename_pr:0:16}.txt" validate_path_tmp "$tmp_path/$backtrack" "$detection_path_pr" validate_path_tmp "$tmp_path/$backtrack" "$tmp_path/$backtrack/0/$detection_path_basename_pr" diff --git a/CVE-2021-44228_log4j-core/results_dashes.sha b/CVE-2021-44228_log4j-core/results_dashes.sha new file mode 100644 index 0000000..dc2a187 --- /dev/null +++ b/CVE-2021-44228_log4j-core/results_dashes.sha @@ -0,0 +1,7 @@ +8550aee14f9c6297cb7a3e87aa819e662bb1766ef46901293e484534fd4a6c5c test_integration_tmp/report/vuln_log4j2_path_0ba5f8c7b3b5059c.txt +9036b8056023e82d701262617349ed408b8a0aa080044568fd61ca83f7d2b5e6 test_integration_tmp/report/vuln_log4j2_path_32afa0818fdc5205.txt +dd5b29296dddf78fcefaefce113f30813654164e87ead86cad8479922ada756f test_integration_tmp/report/vuln_log4j2_path_4c6f762f161184d6.txt +74924ff7cf15b9ce0ad9dead54a6afdce57fa5c1e1a332e94fb52f597ac63436 test_integration_tmp/report/vuln_log4j2_path_6bd31dc9ac80a334.txt +bacec1d0914cd6952da50f59aecf2db42685ff10ce640bf148afdfb562324ce2 test_integration_tmp/report/vuln_log4j2_path_74c73e59a123a05c.txt +0e0b3bf29fb79991c5a68340d548ee3dbd0e3a56345c867b3486a5e0f0268f21 test_integration_tmp/report/vuln_log4j2_path_8dc28ee39dceaa20.txt +8374deb613d4c3a81022d0ecf36cce805425f7f5d875c3d36ce3a00059b0bd87 test_integration_tmp/report/vuln_log4j2_path_ed083df0595af0fe.txt diff --git a/CVE-2021-44228_log4j-core/tests_integration.bats b/CVE-2021-44228_log4j-core/tests_integration.bats index e4a4bd3..87290b6 100755 --- a/CVE-2021-44228_log4j-core/tests_integration.bats +++ b/CVE-2021-44228_log4j-core/tests_integration.bats @@ -386,3 +386,28 @@ teardown_file() { rm -rf test_integration_tmp rm -f symlinked_tmp } + + +@test "Integration -- filenames with dash" { + if ! command -v unzip &> /dev/null; then + return 0 + # This testing environment can't run the script. Lacks unzip. + fi + + rm -rf test_integration_tmp + mkdir -p test_integration_tmp + rm -rf dashes + mkdir dashes + cp -R fake_jar_test_battery_smoke_4 dashes/-X + cp -R fake_jar_test_battery_smoke_4 dashes/-i + cp fake_jar_test_battery_smoke_4/log4j-core-2.0.zip dashes/-E + run ./"${SCRIPT_NAME}" -n --scan "$CANONPWD"/dashes --tmp "$CANONPWD"/test_integration_tmp + (( status == 2 )) + [[ "$output" == *"The specified directory contains vulnerable log4j-core jar files."* ]] + [[ "$output" == *"* 7 files were identified."* ]] + ## sha256sum test_integration_tmp/report/vuln_log4j2_path_* > results_dashes.sha + run sha256sum -c --quiet results_dashes.sha + (( status == 0 )) + rm -rf test_integration_tmp + rm -rf dashes +}