Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2021-3156-Heap-Based-Buffer-Overflow-in-Sudo-Baron-Samedit- | Kitploit
ツール/GitHubGitHub/sornphut/cve-2021-3156-heap-based-buffer-overflow-in-sudo-baron-samedit-
特権昇格脆弱性分析エクスプロイトペネトレーションテスト論文と研究学習と教育バイナリエクスプロイト
GitHubsornphut/cve-2021-3156-heap-based-buffer-overflow-in-sudo-baron-samedit-

CVE-2021-3156-Heap-Based-Buffer-Overflow-in-Sudo-Baron-Samedit-

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有
リポジトリを見る
1年前未レビュー

Qualys セキュリティアドバイザリ

Baron Samedit: Sudo におけるヒープベースのバッファオーバーフロー (CVE-2021-3156)

======================================================================== 目次

概要 分析 悪用 謝辞 タイムライン

======================================================================== 概要

私たちは Sudo にヒープベースのバッファオーバーフローを発見しました (https://www.sudo.ws/)。この脆弱性は次のとおりです:

  • 認証なしで、任意のローカルユーザー(通常ユーザーおよびシステムユーザー、 sudoers と非 sudoers)によって悪用可能です(つまり、攻撃者は ユーザーのパスワードを知る必要はありません);

  • 2011年7月(コミット 8255ed69)に導入され、デフォルト設定において、 すべてのレガシーバージョン 1.8.2 から 1.8.31p2 と、 すべての安定版 1.9.0 から 1.9.5p1 に影響します。

私たちはこの脆弱性に対する3つの異なるエクスプロイトを開発し、 Ubuntu 20.04 (Sudo 1.8.31)、Debian 10 (Sudo 1.8.27)、 Fedora 33 (Sudo 1.9.2) で完全な root 権限を取得しました。他のオペレーティングシステムや ディストリビューションでも悪用可能である可能性が高いです。

======================================================================== 分析

Sudo が "shell" モード(shell -c command)でコマンドを実行するために実行される場合:

  • -s オプション(Sudo の MODE_SHELL フラグを設定する)による方法;

  • または -i オプション(Sudo の MODE_SHELL と MODE_LOGIN_SHELL フラグを設定する)による方法;

その場合、Sudo の main() の先頭で parse_args() は argv を書き換えます(行 609-617)。 すべてのコマンドライン引数を連結し(行 587-595)、すべてのメタ文字をバックスラッシュでエスケープします(行 590-591):


571 if (ISSET(mode, MODE_RUN) && ISSET(flags, MODE_SHELL)) { 572 char **av, *cmnd = NULL; 573 int ac = 1; ... 581 cmnd = dst = reallocarray(NULL, cmnd_size, 2); ... 587 for (av = argv; *av != NULL; av++) { 588 for (src = *av; src != '\0'; src++) { 589 / quote potential meta characters */ 590 if (!isalnum((unsigned char)*src) && *src != '_' && *src != '-' && *src != '$') 591 *dst++ = '\'; 592 *dst++ = *src; 593 } 594 dst++ = ' '; 595 } ... 600 ac += 2; / -c cmnd */ ... 603 av = reallocarray(NULL, ac + 1, sizeof(char *)); ... 609 av[0] = (char )user_details.shell; / plugin may override shell */ 610 if (cmnd != NULL) { 611 av[1] = "-c"; 612 av[2] = cmnd; 613 } 614 av[ac] = NULL; 615 616 argv = av; 617 argc = ac; 618 }

その後、sudoers_policy_main() 内の set_cmnd() は、コマンドライン引数を ヒープベースのバッファ "user_args" に連結し(行 864-871)、 メタ文字のエスケープを解除します(行 866-867)。これは "sudoers の マッチングとロギングのため" です:


819 if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) { ... 852 for (size = 0, av = NewArgv + 1; *av; av++) 853 size += strlen(*av) + 1; 854 if (size == 0 || (user_args = malloc(size)) == NULL) { ... 857 } 858 if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) { ... 864 for (to = user_args, av = NewArgv + 1; (from = *av); av++) { 865 while (*from) { 866 if (from[0] == '\' && !isspace((unsigned char)from[1])) 867 from++; 868 *to++ = *from++; 869 } 870 *to++ = ' '; 871 } ... 884 } ... 886 }

残念ながら、コマンドライン引数が単一のバックスラッシュ文字で終わる場合、次のようになります:

  • 行 866 では、"from[0]" はバックスラッシュ文字であり、"from[1]" は 引数のヌル終端文字です(つまり、スペース文字ではありません);

  • 行 867 では、"from" がインクリメントされ、ヌル終端文字を指します;

  • 行 868 では、ヌル終端文字が "user_args" バッファにコピーされ、 "from" が再度インクリメントされ、ヌル終端文字の後の最初の文字を指します (つまり、引数の境界外です);

  • 行 865-869 の "while" ループは、境界外の文字を読み取って "user_args" バッファにコピーします。

言い換えると、set_cmnd() は、ヒープベースのバッファオーバーフローに対して脆弱です。 "user_args" バッファにコピーされる境界外の文字が、 そのサイズ(行 852-853 で計算)に含まれていないためです。

しかし理論上は、コマンドライン引数が単一のバックスラッシュ文字で終わることはありません: MODE_SHELL または MODE_LOGIN_SHELL が設定されている場合(行 858、 これは脆弱なコードに到達するための必要条件)、MODE_SHELL が設定され(行 571)、 parse_args() はすでにバックスラッシュを含むすべてのメタ文字をエスケープしています (つまり、すべての単一バックスラッシュを2番目のバックスラッシュでエスケープしています)。

しかし実際には、set_cmnd() 内の脆弱なコードと parse_args() 内のエスケープコードは、 わずかに異なる条件で囲まれています:


819 if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) { ... 858 if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) {

一方:


571 if (ISSET(mode, MODE_RUN) && ISSET(flags, MODE_SHELL)) {

では、私たちの疑問は次のとおりです: MODE_SHELL と MODE_EDIT または MODE_CHECK のいずれかを設定し(脆弱なコードに到達するため)、 デフォルトの MODE_RUN を設定しない(エスケープコードを回避するため)ことは可能でしょうか?

答えは、どうやら「いいえ」のようです: MODE_EDIT(-e オプション、行 361)または MODE_CHECK(-l オプション、行 423 および 519)を設定すると、 parse_args() は "valid_flags" から MODE_SHELL を削除し(行 363 および 424)、 MODE_SHELL のような無効なフラグを指定するとエラーで終了します(行 532-533):


358 case 'e': ... 361 mode = MODE_EDIT; 362 sudo_settings[ARG_SUDOEDIT].value = "true"; 363 valid_flags = MODE_NONINTERACTIVE; 364 break; ... 416 case 'l': ... 423 mode = MODE_LIST; 424 valid_flags = MODE_NONINTERACTIVE|MODE_LONG_LIST; 425 break; ... 518 if (argc > 0 && mode == MODE_LIST) 519 mode = MODE_CHECK; ... 532 if ((flags & valid_flags) != flags) 533 usage(1);

しかし、私たちは抜け穴を見つけました: "sudo" の代わりに "sudoedit" として Sudo を実行すると、 parse_args() は自動的に MODE_EDIT を設定しますが(行 270)、 "valid_flags" をリセットせず、"valid_flags" にはデフォルトで MODE_SHELL が含まれます(行 127 および 249):


127 #define DEFAULT_VALID_FLAGS (MODE_BACKGROUND|MODE_PRESERVE_ENV|MODE_RESET_HOME|MODE_LOGIN_SHELL|MODE_NONINTERACTIVE|MODE_SHELL) ... 249 int valid_flags = DEFAULT_VALID_FLAGS; ... 267 proglen = strlen(progname); 268 if (proglen > 4 && strcmp(progname + proglen - 4, "edit") == 0) { 269 progname = "sudoedit"; 270 mode = MODE_EDIT; 271 sudo_settings[ARG_SUDOEDIT].value = "true"; 272 }

したがって、"sudoedit -s" を実行すると、MODE_EDIT と MODE_SHELL の両方を設定し(ただし MODE_RUN は設定しない)、 エスケープコードを回避し、脆弱なコードに到達し、単一のバックスラッシュ文字で終わるコマンドライン引数を介して ヒープベースのバッファ "user_args" をオーバーフローさせます:


sudoedit -s '' perl -e 'print "A" x 65536' malloc(): corrupted top size Aborted (core dumped)

攻撃者の観点から見ると、このバッファオーバーフローは理想的です:

  • 私たちはオーバーフローさせる "user_args" バッファのサイズを制御します(連結されたコマンドライン引数のサイズ、行 852-854);

  • オーバーフロー自体のサイズと内容を独立して制御します(最後のコマンドライン引数の直後に最初の環境変数が続きます。これらは行 852-853 のサイズ計算には含まれません);

  • オーバーフローさせるバッファにヌルバイトを書き込むことさえできます(単一のバックスラッシュで終わるすべてのコマンドライン引数または環境変数は、"user_args" にヌルバイトを書き込みます、行 866-868)。

たとえば、amd64 Linux では、次のコマンドは 24 バイトの "user_args" バッファ(32 バイトのヒープチャンク)を割り当て、 次のチャンクの size フィールドを "A=a\0B=b\0" (0x00623d4200613d41)、 fd フィールドを "C=c\0D=d\0" (0x00643d4400633d43)、 bk フィールドを "E=e\0F=f\0" (0x00663d4600653d45) で上書きします:


env -i 'AA=a' 'B=b' 'C=c' 'D=d' 'E=e' 'F=f' sudoedit -s '1234567890123456789012'

--|--------+--------+--------+--------|--------+--------+--------+--------+-- | | |12345678|90123456|789012.A|A=a.B=b.|C=c.D=d.|E=e.F=f.| --|--------+--------+--------+--------|--------+--------+--------+--------+-- size <---- user_args buffer ----> size fd bk

======================================================================== 悪用

Sudo は main() 関数の先頭でローカライズ関数を呼び出すため:


154 setlocale(LC_ALL, ""); 155 bindtextdomain(PACKAGE_NAME, LOCALEDIR); 156 textdomain(PACKAGE_NAME);

そして、翻訳文字列を(gettext() 関数と _() マクロを通じて) フォーマット文字列関数に渡します。例:


301 sudo_printf(SUDO_CONV_ERROR_MSG, _("%s is not in the sudoers " 302 "file. This incident will be reported.\n"), user_name);

私たちは当初、https://www.halfdog.net/Security/2017/LibcRealpathBufferUnderflow/ の halfdog の魅力的な手法を再利用し、Sudo のヒープベースのバッファオーバーフローを フォーマット文字列エクスプロイトに変換したいと考えていました。より正確には:

  • 行 154 の setlocale() で、複数の LC 環境変数(LC_CTYPE、LC_MESSAGES、LC_TIME など)を malloc() して free() し、 Sudo のヒープの先頭に小さな穴を作成します(解放された fast または tcache チャンク);

  • 行 155 の bindtextdomain() は struct binding を malloc() します。これには、".mo" カタログファイル、つまり翻訳文字列を含むディレクトリの名前を指す dirname ポインタが含まれます;

  • set_cmnd() では、"user_args" バッファを Sudo のヒープの先頭にある穴の1つに malloc() し、このバッファをオーバーフローさせて、struct binding の dirname ポインタを上書きします;

  • 行 301(例)で、gettext()(_() マクロを通じて)は、上書きされた dirname から私たち自身の翻訳文字列をロードします。つまり、sudo_printf() に渡されるフォーマット文字列を制御します。

この初期手法を実装するために、gdb 内で Sudo を実行し、"user_args" バッファをオーバーフローさせ、次のパラメータをランダムに選択する 初歩的なブルートフォーサーを作成しました:

  • Sudo に渡す LC 環境変数とその長さ("C.UTF-8" ロケールを使用し、ランダムな "@modifier" を追加します);

  • オーバーフローさせる "user_args" バッファのサイズ;

  • オーバーフロー自体のサイズ;

  • Sudo の認証コードを経由するか(-A または -n オプション)経由しないか(-u #realuid オプション)。

残念ながら、この初期手法は失敗しました。私たちのブルートフォーサーは struct binding の dirname ポインタを上書きできました:


Program received signal SIGSEGV, Segmentation fault.

0x00007f6e0dde1ea9 in __dcigettext (domainname=domainname@entry=0x7f6e0d9cc020 "sudoers", msgid1=msgid1@entry=0x7f6e0d9cc014 "user NOT in sudoers", msgid2=msgid2@entry=0x0, plural=plural@entry=0, n=n@entry=0, category=5) at dcigettext.c:619

=> 0x7f6e0dde1ea9 <__dcigettext+1257>: cmpb $0x2f,(%rax)

rax 0x4141414141414141 4702111234474983745

しかし、LC_MESSAGES は常にデフォルトの "C" ロケール("C.UTF-8" ではない)であり、 gettext() での文字列翻訳が無効になります(つまり、gettext() はオリジナルのフォーマット文字列を返し、私たち自身のものは返しません)。

しかし幸運なことに、私たちのブルートフォーサーは数十のユニークな Sudo クラッシュと gdb バックトレースを生成しました。その中で3つが私たちの注意を引き、最終的にその3つすべてを悪用しました。

======================================================================== 1/ struct sudo_hook_entry の上書き

私たちの注意を引いた最初のクラッシュは次のとおりです:


Program received signal SIGSEGV, Segmentation fault.

0x000056291a25d502 in process_hooks_getenv (name=name@entry=0x7f4a6d7dc046 "SYSTEMD_BYPASS_USERDB", value=value@entry=0x7ffc595cc240) at ../../src/hooks.c:108

=> 0x56291a25d502 <process_hooks_getenv+82>: callq *0x8(%rbx)

rbx 0x56291c1df2b0 94734565372592

0x56291c1df2b0: 0x4141414141414141 0x4141414141414141

信じられないことに、Sudo の関数 process_hooks_getenv() は(行 108 で)クラッシュしました。 これは、関数ポインタである getenv_fn(ヒープベースの struct sudo_hook_entry のメンバ)を直接上書きしたためです:


99 int 100 process_hooks_getenv(const char *name, char **value) 101 { 102 struct sudo_hook_entry *hook; 103 char *val = NULL; ... 107 SLIST_FOREACH(hook, &sudo_hook_getenv_list, entries) { 108 rc = hook->u.getenv_fn(name, &val, hook->closure);

この struct sudo_hook_entry の上書きを悪用するために、次の点に注目します:

  • getenv_fn への呼び出し(行 108)は、execve() への呼び出しと互換性があります:

    . name ("SYSTEMD_BYPASS_USERDB") は execve() の pathname 引数と互換性があります;

    . &val(NULL ポインタへのポインタ)は execve() の argv と互換性があります;

    . hook->closure(NULL ポインタ)は execve() の envp と互換性があります;

  • 関数ポインタ getenv_fn(共有ライブラリ sudoers.so 内の関数 sudoers_hook_getenv() を指す)を部分的に上書きすることで ASLR を無効化できます。幸いなことに、sudoers.so の先頭には execve()(または execv())への呼び出しが含まれています:


0000000000008a00 execv@plt: 8a00: f3 0f 1e fa endbr64 8a04: f2 ff 25 65 55 05 00 bnd jmpq *0x55565(%rip) # 5df70 <execv@GLIBC_2.2.5> 8a0b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)

  • Ubuntu では非特権ユーザーとして /dev/kmsg (dmesg) を読み取ることができ、 したがって Sudo のクラッシュに関する詳細な情報を得ることができます。

したがって、次の戦略を採用します:

  • まず、getenv_fn を無効なユーザーランドアドレス(0x800000000000 を超える)で上書きするまで、 エクスプロイトパラメータをブルートフォースします。getenv_fn の呼び出しサイトで一般保護違反が観測されるまでです:

sudoedit[15904] general protection fault ip:55e9b645b502 sp:7ffe53d6fa40 error:0 in sudo[55e9b644e000+1a000] ^^^

  • 次に、これらのエクスプロイトパラメータを再利用しますが、getenv_fn を有効(0x800000000000 未満)だが未マップのユーザーランドアドレスの規則的なパターンで上書きします。 この例では、getenv_fn は私たちが上書きする22番目のポインタです(0x32 は '2' で、パターンの一部です):

sudoedit[15906]: segfault at 323230303030 ip 0000323230303030 sp 00007ffeeabf2868 error 14 in sudo[55b036c16000+5000] ^^^^

  • 最後に、getenv_fn を部分的に上書きします(下位2バイトを 0x8a00 で上書きします。これは sudoers.so 内の execv() のオフセットであり、 3番目のバイトを 0x00 で上書きします。これは set_cmnd() 内の user_args のヌル終端文字です)。ASLR を無効化するまで続けます。 2^(3*8-12) = 2^12 = 4096 回の試行後に getenv_fn を execv() のアドレスで上書きできる可能性が高く、 その結果、"SYSTEMD_BYPASS_USERDB" という名前の独自のバイナリを root として実行できます。

私たちはこの最初のエクスプロイトを Ubuntu 20.04 で正常にテストしました。

======================================================================== 2/ struct service_user の上書き

私たちの注意を引いた2番目のクラッシュは次のとおりです:


Program received signal SIGSEGV, Segmentation fault.

0x00007f6bf9c294ee in nss_load_library (ni=ni@entry=0x55cf1a1dd040) at nsswitch.c:344

=> 0x7f6bf9c294ee <nss_load_library+46>: cmpq $0x0,0x8(%rbx)

rbx 0x41414141414141 18367622009667905

glibc の関数 nss_load_library() は(行 344 で)クラッシュしました。 これは、ヒープベースの struct service_user のメンバであるポインタ "library" を上書きしたためです:


327 static int 328 nss_load_library (service_user ni) 329 { 330 if (ni->library == NULL) 331 { ... 338 ni->library = nss_new_service (service_table ?: &default_table, 339 ni->name); ... 342 } 343 344 if (ni->library->lib_handle == NULL) 345 { 346 / Load the shared library. / 347 size_t shlen = (7 + strlen (ni->name) + 3 348 + strlen (__nss_shlib_revision) + 1); 349 int saved_errno = errno; 350 char shlib_name[shlen]; 351 352 / Construct shared object name. */ 353 __stpcpy (__stpcpy (__stpcpy (_"), 355 ni->name), 356 ".so"), 357 __nss_shlib_revision); 358 359 ni->library->lib_handle = __libc_dlopen (shlib_name);

この struct service_user の上書きを任意コード実行に簡単に変換できます:

  • ni->library を NULL ポインタで上書きし、行 330-342 のブロックに入り、行 344 でのクラッシュを回避して、行 344-359 のブロックに入ります;

  • ni->name(文字の配列、初期値は "systemd")を "X/X" で上書きします;

  • 行 353-357 は共有ライブラリ "libnss_X/X.so.2" の名前を構築します("libnss_systemd.so.2" の代わりに);- at line 359 では、現在の作業ディレクトリから独自の共有ライブラリ「libnss_X/X.so.2」を読み込み、root として _init() コンストラクタを実行します。

この 2 番目のエクスプロイトは、Ubuntu 20.04、Debian 10、Fedora 33 で正常にテストしました。

======================================================================== 3/ def_timestampdir の上書き

3 番目のエクスプロイトは、Sudo のクラッシュから派生したものではなく、何気ない観察から得られたものです。ブルートフォース中に、Sudo が現在の作業ディレクトリに多数の新しいディレクトリ(AAAAAA、AAAAAAAAA など)を作成しました。これらのディレクトリはすべて root が所有し、各ディレクトリには自分のユーザー名にちなんだ小さなファイルが 1 つだけ含まれています。それが Sudo のタイムスタンプファイルです。つまり、Sudo のタイムスタンプディレクトリの名前である def_timestampdir を上書きしていたのです。

def_timestampdir を、まだ存在しないディレクトリの名前で上書きすると、Sudo の ts_mkdirs() に対して競争を仕掛け、任意のファイルへのシンボリックリンクを作成し、以下の操作を行うことができます。

3a/ この任意のファイルをユーザー root およびグループ root に chown() する。

3b/ この任意のファイルを root として開く(または作成する)か、そこに struct timestamp_entry を書き込む。

私たちは 3a/ を完全な root 権限に変換することはできませんでした(たとえば、自分の SUID バイナリを root に chown() すると、カーネルが自動的にバイナリの SUID ビットを削除します)。読者の皆様で、この問題の解決策を見つけた方は、公開の oss-security メーリングリストに投稿してください。

最終的に、私たちは 3b/ を完全な root 権限に変換できましたが、最初は 2 つの問題に直面しました。

  • Sudo の timestamp_open() は、シンボリックリンクが指すファイルが起動時間より古い場合、任意のシンボリックリンクを削除します。この最初の問題は、非常に古いタイムスタンプファイル(Unix エポックのもの)を作成し、timestamp_open() がそれを削除するまで待ち、timestamp_open() との競争を仕掛けて最終的な任意のシンボリックリンクを作成することで解決できました。

  • 任意のファイルに書き込まれる struct timestamp_entry の内容を制御することはできません。私たちが知る限り、制御できるのは 3 バイト(プロセス ID または struct timespec)だけで、この 3 バイトの書き込みを完全な root 権限に変換することはできませんでした。読者の皆様で、この問題の解決策を見つけた方は、公開の oss-security メーリングリストに投稿してください。

しかし、Sudo の timestamp_lock() にある軽微なバグを悪用することで、2 番目の問題を回避できました。ts_mkdirs() と timestamp_open() の 2 つの競争に勝ち、任意のシンボリックリンクが /etc/passwd を指すようにすると、このファイルは root として開かれ、次のようになります。


65 struct timestamp_entry { 66 unsigned short version; /* version number / 67 unsigned short size; / entry size / 68 unsigned short type; / TS_GLOBAL, TS_TTY, TS_PPID */ .. 78 };

305 static ssize_t 306 ts_write(int fd, const char *fname, struct timestamp_entry *entry, off_t offset) 307 { ... 318 nwritten = pwrite(fd, entry, entry->size, offset); ... 350 }

619 bool 620 timestamp_lock(void *vcookie, struct passwd *pw) 621 { 622 struct ts_cookie *cookie = vcookie; 623 struct timestamp_entry entry; ... 644 nread = read(cookie->fd, &entry, sizeof(entry)); 645 if (nread == 0) { ... 652 } else if (entry.type != TS_LOCKEXCL) { ... 657 if (ts_write(cookie->fd, cookie->fname, &entry, 0) == -1)

  • 644 行目で、/etc/passwd の最初の 0x38 バイト("root❌0:0:...")がスタック上の struct timestamp_entry である entry に読み込まれます。

  • 652 行目で、entry.type は TS_LOCKEXCL ではなく 0x783a(":x")です。

  • 657 行目と 318 行目で、スタック上の entry から entry->size バイトが /etc/passwd に書き込まれますが、entry->size は実際には sizeof(struct timestamp_entry) ではなく 0x746f("ot")です。

その結果、Sudo のスタックの内容全体(コマンドライン引数と環境変数を含む)を /etc/passwd に書き込むことになります。つまり、/etc/passwd に任意のユーザーを注入し、完全な root 権限を獲得します。この 3 番目のエクスプロイトは、Ubuntu 20.04 で正常にテストしました。

注: timestamp_lock() のこの軽微なバグは、2020 年 1 月にコミット 586b418a で修正されましたが、この修正はレガシーバージョンにはバックポートされませんでした。

======================================================================== 謝辞

Todd C. Miller 氏のプロフェッショナリズム、迅速な対応、そして私たちの報告書の細部にまで行き届いた注意に感謝します。また、distros@openwall のメンバーにも感謝します。

======================================================================== タイムライン

2021-01-13: アドバイザリを Todd.Miller@sudo に送付。

2021-01-19: アドバイザリとパッチを distros@openwall に送付。

2021-01-26: 調整済みリリース日(UTC 18:00)。

ツールをダウンロード
stpcpy (shlib_name, 354 "libnss