.dtorsは書き込み可能に見えますが、segfaultを書き込もうとします


9

これはUbuntu 9.04、2.6.28-11-server、32ビットx86です。


$ cat test.c
main() { int *dt = (int *)0x08049f18; *dt = 1; }
$ readelf -S ./test
...
  [18] .dtors            PROGBITS        08049f14 000f14 000008 00  WA  0   0  4
...
$ ./test
Segmentation fault
$

開始されていない場合:gccは、終了.dtors後に呼び出されるelf実行可能ファイルにデストラクタセグメントを作成しmain()ます。このテーブルは長い間書き込み可能readelfでしたが、私の場合はそうであるように見えます(出力を参照)。ただし、テーブルに書き込もうとすると、セグメンテーション違反が発生します。

最近読み取り専用の.dtors、pltに移行する動きがあったことは承知していますが、私が理解していないのはreadelfとsegfaultの不一致です。


本当の問題は、なぜ書き込み可能にしたいのですか?
アレックス

1
私は一連の脆弱なプログラムを破壊することを含むセキュリティクラスを教えていますが、1つの演習では.dtorsに書き込んでシェルコードを実行します。動作しなくなり、問題を追跡しようとしています。
フィクシー

不一致は、おそらくデータの再配置がいくつかあるためです(読み取り専用とマークする前に修正する必要があり、とにかく怠惰にすることはできないため、修正すると定数になります)。
ninjalj

回答:


5

これらのセクションは、GNU_RELRO(読み取り専用再配置)とマークされています。つまり、ダイナミックローダーがすべての再配置を修正すると(ロード時に、遅延再配置はありません)、それらのセクションは読み取り専用になります。ほとんどの.got.pltページが別のページにあるため、扱いません。

リンカスクリプトはld --verboseで確認できます。RELROを検索すると、次のようなものが見つかります。

.got            : { *(.got) }
. = DATA_SEGMENT_RELRO_END (12, .);
.got.plt        : { *(.got.plt) }

つまり、RELROセクションは12バイトで終わります.got.plt(動的リンカー関数へのポインターはすでに解決されているため、読み取り専用としてマークできます)。

強化されたGentooプロジェクトには、http: //www.gentoo.at/proj/en/hardened/hardened-toolchain.xml#RELROにRELROに関するドキュメントがあります


5

システムのどの部分が原因なのか実際にはわかりませんが、なぜ失敗するのかはわかります。一方で.dtors、バイナリで書き込み可能とマークされ、それはそれのように見えます(に沿って.ctors、GOT、およびいくつかの他のもの)メモリに独立し、非書き込み可能なページにマッピングされています。私のシステムで.dtorsは、に置かれてい0x8049f14ます:

$ readelf -S test
  [17] .ctors            PROGBITS        08049f0c 000f0c 000008 00  WA  0   0  4
  [18] .dtors            PROGBITS        08049f14 000f14 000008 00  WA  0   0  4
  [19] .jcr              PROGBITS        08049f1c 000f1c 000004 00  WA  0   0  4
  [20] .dynamic          DYNAMIC         08049f20 000f20 0000d0 08  WA  6   0  4
  [21] .got              PROGBITS        08049ff0 000ff0 000004 04  WA  0   0  4
  [22] .got.plt          PROGBITS        08049ff4 000ff4 00001c 04  WA  0   0  4
  [23] .data             PROGBITS        0804a010 001010 000008 00  WA  0   0  4
  [24] .bss              NOBITS          0804a018 001018 000008 00  WA  0   0  4

実行可能ファイルを実行してチェックすると/proc/PID/maps、次のようになります。

08048000-08049000 r-xp 00000000 08:02 163678     /tmp/test
08049000-0804a000 r--p 00000000 08:02 163678     /tmp/test
0804a000-0804b000 rw-p 00001000 08:02 163678     /tmp/test

.data/ .bssはまだ自分のページで書き込み可能ですが、他のページは書き込み可能で0x8049000-0x804a000はありません。これはカーネルのセキュリティ機能だと思いますが(あなたが言ったように、「最近、読み取り専用の.dtors、plt、最近入手された」という動きがありました)、私はそれが何と呼ばれているのか特にわかりません(OpenBSDには非常によく似たものがあります)W ^ X ; LinuxにはPaXがありますが、ほとんどのカーネルには組み込まれていません)

mprotectページのメモリ内属性を変更できるで回避できます。

mprotect((void*)0x8049000, 4096, PROT_WRITE);

これでテストプログラムはクラッシュしませんが、.dtors0x8049f18)の終了センチネルを別の関数のアドレスで上書きしようとしても、その関数は実行されません。私にはわからないその部分。

うまくいけば、他の誰かがページを読み取り専用にする責任があること、および変更.dtorsが私のシステムで何もしないように見える理由を知っています


3
PaXをmprotect使用するOP Linuxが実行可能ページを書き込み可能にできないか、その機能をで無効にしない限り、以前に書き込み可能であったページを実行可能にできない場合paxctl -m
stribika '25

@stribikaああ、知っておきたいこと
Michael Mrozek
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.