Skip to content

Commit

Permalink
Merge branch 'jsvoboda_CVE-2021-44228_v1.1' into 'master'
Browse files Browse the repository at this point in the history
Handle filenames with leading dash properly.

See merge request Insights/vulnerability-detection-scripts!34
  • Loading branch information
jsvob committed Dec 17, 2021
2 parents 6047b5c + 2fa472f commit 2bf1f01
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 28 deletions.
56 changes: 28 additions & 28 deletions CVE-2021-44228_log4j-core/CVE-2021-44228.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down Expand Up @@ -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%/}"
Expand Down Expand Up @@ -437,15 +437,15 @@ 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
check_3_a=1
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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand All @@ -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 )"

Expand Down Expand Up @@ -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 )"

Expand Down Expand Up @@ -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 )"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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" )"
Expand All @@ -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)
Expand All @@ -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"
Expand Down
7 changes: 7 additions & 0 deletions CVE-2021-44228_log4j-core/results_dashes.sha
Original file line number Diff line number Diff line change
@@ -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
25 changes: 25 additions & 0 deletions CVE-2021-44228_log4j-core/tests_integration.bats
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

0 comments on commit 2bf1f01

Please sign in to comment.