'найти' шаблон для обработки любого файла


Уставшие от всех способов, в которых файл цикл может быть нарушен (найти -распечатать | время чтения) или читается (найти -старпома со сложной команды), я думаю, мне удалось построить найти шаблон , который может обрабатывать любые файлы, которые могут существовать в системе Linux (не столь знаменитые последние слова). Можете ли вы найти способ, чтобы разбить его, изменяя либо испытание _ переменные или окружающей среды? Например, можно ли связываться с дескриптором файла 9 за сценарий так, что он не будет работать?

Единственным требованием является "вменяемость". Другими словами, test_file_name и test_dir_path не может содержать \0 или /, test_file_path не может содержать \0 (или более чем на 1 уровень, глубокий, с помощью mkdir ради теста без -п), и /Бин/Баш должна быть стабильная версия Баш 4.

#!/bin/bash
# Filenames can contain *any* character except only null (\0) and slash (/);
# here's some general rules to handle them:
#
# $'...' can be used to create human readable strings with escape sequences.
#
# ' -- ' in commands is necessary to separate arguments from filenames, since
# filenames can start with '--', and would therefore be handled as parameters.
# To handle parameters properly (like GNU tools) use `getopt`.
#
# `find` doesn't support this syntax, so we use `readlink` to get an absolute
# path which by definition starts with slash.
#
# The "$()" construct strips trailing newlines, so we have to add a different
# character and then strip it outside the "$()" construct.
#
# `IFS=` is necessary to avoid that any characters in IFS are stripped from
# the start and end of $path.
#
# '-r' avoids interpreting backslash in filenames specially.
#
# '-d '' splits filenames by the null character.
#
# '-print0' separates find output by null characters.
#
# Variables inside '$()' have to be quoted just like outside this construct.
#
# Use process substitution with "<(" instead of pipes to avoid broken pipes.
#
# Use file descriptor 9 for data storage instead of standard input to avoid
# greedy commands like `cat` eating all of it.

set -o errexit
set -o nounset
set -o noclobber

test_file_name=$'--$`\! *@ \a\b\e\E\f\r\t\v\\\"\' \n'
test_dir_path="$test_file_name"
test_file_path="${test_dir_path}/${test_file_name}"

mkdir -- "$test_dir_path"
touch -- "$test_file_path"

absolute_dir_path_x="$(readlink -fn -- "$test_dir_path"; echo x)"
absolute_dir_path="${absolute_dir_path_x%x}"

exec 9< <( find "$absolute_dir_path" -type f -print0 )
while IFS= read -r -d '' -u 9
do
    file_path="$(readlink -fn -- "$REPLY"; echo x)"
    file_path="${file_path%x}"
    echo "START${file_path}END"
done

rm -- "$test_file_path"
rmdir -- "$test_dir_path"


1267
12
задан 18 марта 2011 в 02:03 Источник Поделиться
Комментарии
2 ответа

Этот код уязвим к TOCTOU. Есть крошечный зазор между тем, когда "простые" файлы считываются из процесса замещения (найти -типа F ...) и время, которое более ранних версий(1) называется на этих именах.

Злоумышленник может создать программу, которая ждет твоя программа для запуска и затем быстро удаляет один из этих файлов, найденных на Найти(1) и заменяет его на ссылку, чтобы где-то еще. более ранних версий(1) затем покорно вернуться объектом символической ссылки, что и это будет выход. Цель может быть вне $absolute_dir_path и файлов любого типа (каталогов, устройства, узла, ...).

Например:

#!/bin/bash

set -o errexit
set -o nounset
set -o noclobber

# setup directory containing two plain files
# hardcode absolute_dir_path to /tmp/dir for simplicity
mkdir -p /tmp/dir
rm -f /tmp/dir/a /tmp/dir/b
touch /tmp/dir/a /tmp/dir/b

# emulate OP's find loop, but with inserted actions
# performed by an attacker (in real attack these would
# happen in an external program).
exec 9< <( find /tmp/dir -type f -print0 )
while IFS= read -r -d '' -u 9
do
file_path_x="$(readlink -fn -- "$REPLY"; echo x)"
file_path="${file_path_x%x}"
ls -l "${file_path}"
# attacker jumps in here and does:
rm /tmp/dir/b
ln -s /etc/passwd /tmp/dir/b
done

Выход:

-rw-r--r-- 1 martin martin 0 2011-03-31 10:56 /tmp/dir/a
-rw-r--r-- 1 root root 2119 2011-03-28 11:35 /etc/passwd

Этот риск может быть снижен путем поиска только файлы в каталогах, под которым недоверенные пользователи не имеют доступ на запись. Каталоги, такие как в/tmp и в/var/tmp в несколько проблематично, хотя и это трудно решить. Увидеть источник (ЭГ) tmpreaper для некоторых идей.

13
ответ дан 31 марта 2011 в 10:03 Источник Поделиться

find . -type f -execdir echo START{}END ";"
START./--$`\! *@

\"'
/--$`\! *@

\"'
END

В каких случаях вам не найти?

find . -type f  -execdir md5sum {} ";"
\d41d8cd98f00b204e9800998ecf8427e ./--$`\\! *@

\\"' \n/--$`\\! *@

\\"' \n

(поменял из -exec для -execdir после полезную подсказку).

2
ответ дан 24 марта 2011 в 06:03 Источник Поделиться