[Android]adb setuidオプションの脆弱性の分析
RageAgainstTheCageのソースコードを分析するのに良い文章を見たが、元のリンクが失効したことに気づき、ページのキャッシュコピーからクモの跡を探すしかなかった.以下は私が見つけた内容で、自分のブログに保存して、後で見つけることができることを保証します.
昨年のAndroid adb setuidオプションの脆弱性は各種rootブラシに用いられ、脆弱性発見者Sebastian Krahmerが発表した利用ツールRageAgainstTheCage(rageagainstthecage-arm 5.bin)はz 4 rootなどのオプションツール、Trojanに用いられた.Android.Rootcagerなどの悪意のあるコードの中にあります.この脆弱性の発生原因を分析します.
The Android Exploid Crewグループは後にPoCコードを発表した:rageagainstthecage.c.このコードから着手します.
main(:72)関数では、まずRLIMIT_を取得するLinuxカーネルで定義された各ユーザが実行できる最大プロセス数であるNPROCの値(:83).
次にfind_を呼び出しますadb()関数(:94)は、AndroidシステムにおけるadbプロセスのPIDを検索し、具体的には、各プロセスに対応するファイルの/proc//cmdlineを読み出し、それが「/sbin/adb」に等しいか否かに基づいてadbプロセスであるか否かを判断する.
次にforkは新しいプロセス(:109)を行い、親プロセスは終了し、サブプロセスは継続する.次に、113行にパイプを作成します.
次の122~138行で、コードは次のとおりです.
新しいプロセスを作成すると、サブプロセスでexploitコードがfork():125)され、新しいサブプロセスが終了し続け、大量のゾンビプロセス(shellユーザーを占めるプロセス数)が生成されます.最終的に、プロセス数が上限に達し、fork()は0未満を返し、現在作成されているサブプロセスの数を印刷し、パイプに文字(:131)を入力します.
ここで、パイプの役割は、141行readのパイプである(:122)forkからの親プロセスと同期し、ゾンビプロセスが上限に達するまでブロックされる(:131).
さらに、exploitはadbプロセスを殺し、システムがこの現象を検出してadbを再起動する前に、もう一度fork()を行い、前のadbに残されたプロセス空席を占有する.最後に、152行でexploit呼び出しwait_for_root_adb()は、システムがadbを再起動するのを待つと、この新しいadbにはroot権限があります.
shellユーザーのプロセス数が上限RLIMIT_に達した理由NPROC以降、新しいadbにroot権限がありますか?adbのソースコードを見てみましょう.
/system/core/adb/adb.cの918行目には、次のコードが表示されます.
これはすでに脆弱性修正後のコードです.脆弱性が最初に発見された場合、コードは次のとおりです.
簡単に言えば、setuid()関数の戻り値はチェックされていません.実際、その前にadb.cのコードはroot権限で実行され、一部の初期化作業を完了します.この行では、setuid()を呼び出すことでユーザーをrootからshellに切り替えますが、setuid()はshellユーザープロセス数が上限RLIMIT_に達します.NPROCの場合、失敗するのでadb.cエラーなしでrootとして動作し続けます.
setuid()のmanマニュアル(man 2 setuid)を見てみましょう.以下の説明があります.
setuidはエラーが発生し、uidのプロセス数がRLIMIT_を超えていることがわかります.NPROC限界時、EAGAINエラーが発生しました.
androidのソースコードでは、setuid()は/bionic/libc/unistd/setuid.c,実際には外部シンボル__を参照している.setuid、この記号は/bionic/libc/arch_xxx/syscalls/__setuid.Sで定義され、最終的には%eax=$_NR_setuid 32,%ebx=uidのint 0×80が中断しました.
原理を分析するだけなので、Androidでは苦戦せず、Linuxカーネルを見ています.
最新のkernel 2.6では、setuid()はkernel/sysにある.cの682行、そのうち697行、すべて正常な場合、set_が呼び出されます.ユーザー()は、ユーザー切り替えを完了します.
set_user()は、同じファイルの587行に実装され、コードの一部は以下の通りである.
ターゲットユーザのプロセス数が上限に達すると,システムはもう1つのプロセスを割り当てることができず,EAGEINに戻るという意味である.次にsetuid()で、後ろのコードを直接スキップしてエラーを返します.
これで,脆弱性全体の原理は解析済みである.以下に整理します.
1、Androidのshellユーザーの下で、shellユーザーのプロセス数の上限RLIMIT_に達するまで大量のゾンビプロセスを製造するNPROC;
2、kill現在のシステムのadbプロセスは、再びそのプロセスの位置を占めて上限を維持する.
3、システムは一定時間後にadbプロセスを再起動し、このプロセスは最初はrootユーザーであり、少量の初期化作業が完了した後、setuid()を呼び出してshellユーザーに切り替える.
4、この時shellユーザーのプロセス数が上限に達したため、setuid()に失敗し、-1に戻り、ユーザーの交換が完了していない.adbはroot権限である.
5、adbはsetuid()の戻り値をチェックせず、後続の作業を継続するため、root権限を持つadbプロセスを生成し、ユーザーとの次のインタラクションに使用することができる.
実際、setuidはターゲットユーザプロセス数でRLIMIT_に達している.NPROC限界時にエラーが返され、この問題が発生する可能性のあるセキュリティ上の危険性は2000年にさかのぼることができます.2006年には、この符号化問題を真に利用する脆弱性が現れた(CVE-2006-2607).
そのため、これは新しい脆弱性ではありません.いくつかの結論を出すことができます.
1、関数の戻り値は無視されたオブジェクトです.getuid()は失敗しないため、プログラマはsetuid()も失敗しないと思っている可能性があります.少なくとも遭遇したことがないので、戻り値のチェックは無視されます.システム関数の呼び出しに失敗したかどうかをチェックするのは常識ですが、面倒なことで、手間を省くために無視すれば、問題が発生する可能性があります.
2、Androidのセキュリティの問題は、新しいものではないことが多く、個人的な判断は将来、多くの脆弱性があり、悪意のあるコードが伝統的な考え方で発生し、新しいプラットフォームに作用すると判断しています.この新しいプラットフォームに直面して、私たちが攻撃者より先に防犯準備をすることができるかどうかは、私たちの思考と実践が必要な問題です.
昨年のAndroid adb setuidオプションの脆弱性は各種rootブラシに用いられ、脆弱性発見者Sebastian Krahmerが発表した利用ツールRageAgainstTheCage(rageagainstthecage-arm 5.bin)はz 4 rootなどのオプションツール、Trojanに用いられた.Android.Rootcagerなどの悪意のあるコードの中にあります.この脆弱性の発生原因を分析します.
The Android Exploid Crewグループは後にPoCコードを発表した:rageagainstthecage.c.このコードから着手します.
main(:72)関数では、まずRLIMIT_を取得するLinuxカーネルで定義された各ユーザが実行できる最大プロセス数であるNPROCの値(:83).
次にfind_を呼び出しますadb()関数(:94)は、AndroidシステムにおけるadbプロセスのPIDを検索し、具体的には、各プロセスに対応するファイルの/proc/
次にforkは新しいプロセス(:109)を行い、親プロセスは終了し、サブプロセスは継続する.次に、113行にパイプを作成します.
if (fork() > 0)
exit(0);
setsid();
pipe(pepe);
次の122~138行で、コードは次のとおりです.
if (fork() == 0) {
close(pepe[0]);
for (;;) {
if ((p = fork()) == 0) {
exit(0);
} else if (p < 0) {
if (new_pids) {
printf("
[+] Forked %d childs.
", pids);
new_pids = 0;
write(pepe[1], &c, 1);
close(pepe[1]);
}
} else {
++pids;
}
}
}
新しいプロセスを作成すると、サブプロセスでexploitコードがfork():125)され、新しいサブプロセスが終了し続け、大量のゾンビプロセス(shellユーザーを占めるプロセス数)が生成されます.最終的に、プロセス数が上限に達し、fork()は0未満を返し、現在作成されているサブプロセスの数を印刷し、パイプに文字(:131)を入力します.
ここで、パイプの役割は、141行readのパイプである(:122)forkからの親プロセスと同期し、ゾンビプロセスが上限に達するまでブロックされる(:131).
さらに、exploitはadbプロセスを殺し、システムがこの現象を検出してadbを再起動する前に、もう一度fork()を行い、前のadbに残されたプロセス空席を占有する.最後に、152行でexploit呼び出しwait_for_root_adb()は、システムがadbを再起動するのを待つと、この新しいadbにはroot権限があります.
shellユーザーのプロセス数が上限RLIMIT_に達した理由NPROC以降、新しいadbにroot権限がありますか?adbのソースコードを見てみましょう.
/* then switch user and group to "shell" */
if (setgid(AID_SHELL) != 0) {
exit(1);
}
if (setuid(AID_SHELL) != 0) {
exit(1);
}
これはすでに脆弱性修正後のコードです.脆弱性が最初に発見された場合、コードは次のとおりです.
/* then switch user and group to "shell" */
setgid(AID_SHELL);
setuid(AID_SHELL);
簡単に言えば、setuid()関数の戻り値はチェックされていません.実際、その前にadb.cのコードはroot権限で実行され、一部の初期化作業を完了します.この行では、setuid()を呼び出すことでユーザーをrootからshellに切り替えますが、setuid()はshellユーザープロセス数が上限RLIMIT_に達します.NPROCの場合、失敗するのでadb.cエラーなしでrootとして動作し続けます.
setuid()のmanマニュアル(man 2 setuid)を見てみましょう.以下の説明があります.
RETURN VALUE
On success, zero is returned. On error, -1 is returned, and errno is
set appropriately.
ERRORS
EAGAIN The uid does not match the current uid and uid brings process
over its RLIMIT_NPROC resource limit.
setuidはエラーが発生し、uidのプロセス数がRLIMIT_を超えていることがわかります.NPROC限界時、EAGAINエラーが発生しました.
androidのソースコードでは、setuid()は
原理を分析するだけなので、Androidでは苦戦せず、Linuxカーネルを見ています.
最新のkernel 2.6では、setuid()はkernel/sysにある.cの682行、そのうち697行、すべて正常な場合、set_が呼び出されます.ユーザー()は、ユーザー切り替えを完了します.
set_user()は、同じファイルの587行に実装され、コードの一部は以下の通りである.
if (atomic_read(&new_user->processes) >= rlimit(RLIMIT_NPROC) &&
new_user != INIT_USER) {
free_uid(new_user);
return -EAGAIN;
}
ターゲットユーザのプロセス数が上限に達すると,システムはもう1つのプロセスを割り当てることができず,EAGEINに戻るという意味である.次にsetuid()で、後ろのコードを直接スキップしてエラーを返します.
これで,脆弱性全体の原理は解析済みである.以下に整理します.
1、Androidのshellユーザーの下で、shellユーザーのプロセス数の上限RLIMIT_に達するまで大量のゾンビプロセスを製造するNPROC;
2、kill現在のシステムのadbプロセスは、再びそのプロセスの位置を占めて上限を維持する.
3、システムは一定時間後にadbプロセスを再起動し、このプロセスは最初はrootユーザーであり、少量の初期化作業が完了した後、setuid()を呼び出してshellユーザーに切り替える.
4、この時shellユーザーのプロセス数が上限に達したため、setuid()に失敗し、-1に戻り、ユーザーの交換が完了していない.adbはroot権限である.
5、adbはsetuid()の戻り値をチェックせず、後続の作業を継続するため、root権限を持つadbプロセスを生成し、ユーザーとの次のインタラクションに使用することができる.
実際、setuidはターゲットユーザプロセス数でRLIMIT_に達している.NPROC限界時にエラーが返され、この問題が発生する可能性のあるセキュリティ上の危険性は2000年にさかのぼることができます.2006年には、この符号化問題を真に利用する脆弱性が現れた(CVE-2006-2607).
そのため、これは新しい脆弱性ではありません.いくつかの結論を出すことができます.
1、関数の戻り値は無視されたオブジェクトです.getuid()は失敗しないため、プログラマはsetuid()も失敗しないと思っている可能性があります.少なくとも遭遇したことがないので、戻り値のチェックは無視されます.システム関数の呼び出しに失敗したかどうかをチェックするのは常識ですが、面倒なことで、手間を省くために無視すれば、問題が発生する可能性があります.
2、Androidのセキュリティの問題は、新しいものではないことが多く、個人的な判断は将来、多くの脆弱性があり、悪意のあるコードが伝統的な考え方で発生し、新しいプラットフォームに作用すると判断しています.この新しいプラットフォームに直面して、私たちが攻撃者より先に防犯準備をすることができるかどうかは、私たちの思考と実践が必要な問題です.