web-dev-qa-db-ja.com

Linuxでシステムコールテーブルを変更する必要があるのはなぜですか?

私は最近ルートキットについて学び、カーネルランドのルートキットが悪意のあるアクションを実行するために使用するこのhookingテクニックに気づきました。

典型的なフッキング操作では、正当なシステムコールにフックし、実際に正当なアクションを呼び出す前に、まず正当なアクションを悪意のあるアクションに置き換えます。

しかし、その場合は、システムコールテーブルを最初から変更できないようにしてください。

34
meoware

Syscallテーブル読み取り専用で、 カーネル2.6.16以降 となっています。ただし、カーネルルートキットには、再度書き込み可能にする機能があります。それがする必要があるすべてはこのような関数を実行することです* 引数としてテーブルを使用:

static void set_addr_rw(const unsigned long addr)
{
    unsigned int level;
    pte_t *pte;

    pte = lookup_address(addr, &level);
    if (pte->pte &~ _PAGE_RW)
        pte->pte |= _PAGE_RW;

    local_flush_tlb();
}

これにより、syscallテーブルの権限が変更され、編集できるようになります。これが何らかの理由で機能しない場合は、次のASMを使用してカーネルの書き込み保護をグローバルに無効にできます。

cli
mov %cr0, %eax
and $~0x10000, %eax
mov %eax, %cr0
sti

これにより、割り込みが無効になり、 [〜#〜] wp [〜#〜] (書き込み保護)ビットが CR で無効になり、割り込みが再び有効になります。

無効にするのが簡単なのに、なぜそれが読み取り専用としてマークされているのですか? 1つの理由は、カーネルメモリを変更できるが、必ずしもコードを直接実行できるとは限らない脆弱性が存在するためです。カーネルの重要な領域を読み取り専用としてマークすることにより、 additional 脆弱性を見つけてページを書き込み可能としてマークする(または書き込み保護を完全に無効にする)ことなく、それらを悪用することがより困難になります。これは非常に強力なセキュリティを提供しないため、読み取り専用としてマークされている主な理由は、バグによって引き起こされる accidental の上書きを壊滅的かつ回復不可能なシステムクラッシュ。

*カーネルの内部APIは常に変更されるため、この正確な関数は古いカーネルまたは新しいカーネルでは機能しない可能性があります。グローバルに無効にするCR0.WP ASMは、カーネルのバージョンに関係なく、すべてのx86システムで動作することが保証されています。

58
forest

フォレストで言及されているように、最近のLinuxではこれを許可していませんが、オーバーライドするのは簡単です。

ただし、歴史的には、セキュリティの目的で以前は有用でした(おそらくまだそうです):脆弱性に対するホットパッチ。 1990年代と2000年代の初めに、絶対に必要としなかったシステムコールに対して新しい脆弱性が発表されたとき(ptraceは当時は本当に一般的なものでした)、関数を上書きするカーネルモジュールを書きました。 return -ENOSYS;を実行したばかりの関数のアドレスを含むsyscallテーブルのアドレス。これにより、アップグレードされたカーネルが利用可能になるまで攻撃面が排除されました。一部の怪しいシステムコールについては、脆弱性が繰り返し発生することを必要としていませんでした。そのため、先を見越してこれを実行し、モジュールを常に有効にしたままにしました。