Userland-RootKit Azazelの「膝の上」のルートキット対策

ValdikSSユーザーからの素晴らしいニュース-New Userland-RootKit Azazelです。 最初の段落を引用させてください:



ルートキットJynxおよびJynx2について聞いたことがあるかもしれません。 これらはいわゆるユーザーランドルートキットであり、LD_PRELOAD変数の可能性を使用して、プログラムが起動する前にライブラリをロードできるようにします。 それらはすでに比較的古いですが、それでもうまく機能します。

2日前、githubユーザーChokepointがルートキットAzazelを投稿しました。 Jynxソースコードに基づいており、多くの新機能があります。



デバッグ防止メカニズム

非表示、lsof、ps、lddから非表示

ファイルとディレクトリを非表示にする

リモート接続を隠す

プロセスの非表示

ログインを隠す

PCAPを介したローカルトラフィックスニッフィングから隠す

完全なシェルを備えた2つのバックドア(PTY付き):

-Crypthook accept()-バックドア

-通常の受け入れ()-バックドア

すべてのユーザーの認証用のPAMバックドア

PTYのutmp / wtmpログのクリーニング

xorによるコンパイルされたライブラリ行の難読化。




したがって、ルートキットはLD_PRELOAD



介してライブラリをロードする標準機能を使用します。 問題は、これを何らかの形で制御できるかどうかです。







冗長にならないように、すぐにLinuxカーネルの簡単なソリューションを紹介します。これは、 execve



関数(またはsys_execve )をインターセプトし、環境変数( envp



として知られる)のリストのパラメーターをスキャンして特定の文字列、つまり同じLD_PRELOAD



が存在するかenvp



ます。



そのため、ソリューションはカーネルモジュールとして設計されています。 関数のインターセプトは、前の記事で説明した方法に基づいています。







次のコードは、sys_execve関数をインターセプトするために使用されます。



 DECLARE_KHOOK(sys_execve); long khook_sys_execve( const char __user * file, const char __user * const __user * argv, const char __user * const __user * envp ) { long result; KHOOK_USAGE_INC(sys_execve); scan_env_for((void *)file, (void *)envp, env_token); result = KHOOK_ORIGIN(sys_execve, file, argv, envp); KHOOK_USAGE_DEC(sys_execve); return result; }
      
      







インターセプトされた関数sys_execve



の元の呼び出しを行う直前に、指定されたenv_token



文字列に対する環境変数の対応を検索します。 単純なscan_env_for関数がこれを行います:



 void scan_env_for(char * file, char * envp[], const char * token) { int i; char * string; char * string_ptr; if (!envp || !token) return; string = kmalloc(MAX_ARG_STRLEN + 1, GFP_KERNEL); if (!string) { debug("Can't get memory for the environ string\n"); return; } for (i = 0; i < MAX_ARG_STRINGS; i++) { if (get_user(string_ptr, envp + i)) { debug("Can't get user pointer value\n"); goto out_kfree; } if (string_ptr == NULL) goto out_kfree; if (strncpy_from_user(string, string_ptr, MAX_ARG_STRLEN) == -EFAULT) { debug("Can't get user string\n"); goto out_kfree; } string[MAX_ARG_STRLEN] = 0; if (strncmp(string, token, strlen(token)) == 0) { char * filename; filename = kmalloc(PATH_MAX + 1, GFP_KERNEL); if (filename) { strncpy_from_user(filename, file, PATH_MAX + 1); filename[PATH_MAX] = 0; } debug("Attention, task \"%s\" trying to execute \"%s\" with \"%s\"\n", \ current->comm, filename ? filename : "(unknown)", string); kfree(filename); goto out_kfree; } } out_kfree: kfree(string); }
      
      







ご覧のとおり、起動時にメモリが割り当てられ、環境変数のすべての可能な文字列要素がスキャンされます。 スキャンの終了時に、メモリはそれに応じて解放されます。 必要な行がカーネルログで見つかった場合、警告が表示されます。



モジュールの正常性を確認するには、アセンブリ後に次を実行できます。



 $ sudo insmod envscan.ko env_token=\"LD_PRELOAD=\" $ dmesg | grep envscan [37713.809903] [envscan] Symbol "module_free" found @ ffffffff810bdcd0 [37713.810190] [envscan] Symbol "module_alloc" found @ ffffffff810407e0 [37713.810523] [envscan] Symbol "sort_extable" found @ ffffffff81048a90 [37713.810524] [envscan] Hunting for "LD_PRELOAD=" [37713.811798] [envscan] Symbol "sys_execve" found @ ffffffff8119ba30 $ LD_PRELOAD=/lib/ld-linux.so.2 ls [37743.786499] [envscan] Attention, task "bash" trying to execute "/bin/ls" with "LD_PRELOAD=/lib/ld-linux.so.2"
      
      







したがって、偏執的なユーザーには、必要に応じてLD_PRELOAD



の機能に関連するトラブルから身を守ることができるソリューションがあります。



パニックの少ない人にとっては、この資料はカーネルの操作方法に関する情報源、つまりその機能をインターセプトし、システムの動作を変更する方法として役立ちます。



モジュールコードはgithubで入手できます。



All Articles