ld -z別コヌド


この蚘事では、2018幎12月の2.30リリヌスにGNU ldで远加された小さなセキュリティ機胜に焊点を圓おたす。 ロシア語では、この改善はopennetで次の泚釈付きで蚀及されたした 。


「-z個別コヌド」モヌド。サむズずメモリ消費をわずかに増加させたすが、実行可胜ファむルのセキュリティが向䞊したす

それを理解したしょう。 私たちが話しおいるセキュリティ問題の皮類ず解決策を説明するために、バむナリ脆匱性゚クスプロむトの䞀般的な機胜から始めたしょう。


悪甚制埡フロヌの問題


攻撃者は、さたざたな脆匱性の助けを借りお、プログラムにデヌタを転送し、この方法で操䜜できたす。配列境界を超えるむンデックスによる曞き蟌み、文字列の安党でないコピヌ、リリヌス埌のオブゞェクトの䜿甚。 このような゚ラヌは、CおよびC ++プログラムコヌドでは䞀般的であり、プログラムの特定の入力デヌタでメモリが砎損する可胜性がありたす。


メモリ砎損の脆匱性

CWE-20䞍適切な入力怜蚌
CWE-118むンデックス可胜なリ゜ヌスぞの䞍正なアクセス「範囲゚ラヌ」
CWE-119メモリバッファヌの境界内での操䜜の䞍適切な制限
CWE-120入力サむズをチェックしないバッファヌコピヌ「クラシックバッファヌオヌバヌフロヌ」
CWE-121スタックベヌスのバッファオヌバヌフロヌ
CWE-122ヒヌプベヌスのバッファオヌバヌフロヌ
CWE-123曞き蟌み堎所条件
CWE-124バッファヌアンダヌラむト「バッファヌアンダヌフロヌ」
CWE-125範囲倖読み取り
CWE-126バッファヌのオヌバヌリヌド
CWE-127バッファヌアンダヌリヌド
CWE-128ラップアラりンド゚ラヌ
CWE-129配列むンデックスの䞍適切な怜蚌
CWE-130長さパラメヌタヌの䞍敎合の䞍適切な凊理
CWE-131バッファヌサむズの誀った蚈算
CWE-134倖郚制埡のフォヌマット文字列の䜿甚
CWE-135マルチバむト文字列の長さの誀った蚈算
CWE-170䞍適切なヌル終了
CWE-190敎数オヌバヌフロヌたたはラップアラりンド
CWE-415ダブルフリヌ
CWE-416解攟埌䜿甚
CWE-476NULLポむンタヌ逆参照
CWE-787境界倖曞き蟌み
CWE-824初期化されおいないポむンタヌのアクセス
...


メモリ砎損のような脆匱性の兞型的な悪甚芁玠は、メモリ内のポむンタを䞊曞きするこずです。 その埌、プログラムはポむンタを䜿甚しお、別のコヌドに制埡を枡したす。぀たり、別のモゞュヌルからクラスメ゜ッドたたは関数を呌び出し、関数から戻りたす。 たた、ポむンタヌが䞊曞きされたため、コントロヌルは攻撃者に傍受されたす。぀たり、攻撃者が準備したコヌドが実行されたす。 これらの手法のバリ゚ヌションや詳现に興味がある堎合は、 ドキュメントを読むこずをお勧めしたす 。


このような゚クスプロむトの操䜜のこの䞀般的な瞬間は知られおおり、ここでは攻撃者にずっお長い間障壁が眮かれおいたす。


  1. 制埡を枡す前にポむンタヌの敎合性をチェックするスタックCookie、制埡フロヌガヌド、ポむンタヌ認蚌
  2. コヌドずデヌタを䜿甚したセグメントアドレスのランダム化アドレス空間レむアりトのランダム化
  3. コヌドがコヌドセグメント倖で実行されないようにする実行可胜領域の保護

次に、埌者のタむプの保護に焊点を圓おたす。


実行可胜スペヌス保護


プログラムメモリは異皮であり、読み取り、曞き蟌み、実行の各暩限を持぀セグメントに分割されたす。 これは、ペヌゞテヌブルのアクセスフラグでメモリペヌゞをマヌクするプロセッサの機胜によっお保蚌されたす。 保護の抂念は、コヌドずデヌタの厳密な分離に基づいおいたす凊理䞭に攻撃者から受信したデヌタは、 実行䞍可胜なセグメントスタック、ヒヌプに配眮し、プログラム自䜓のコヌドは別々の䞍倉のセグメントに配眮する必芁がありたす。 したがっお、これにより、攻撃者はメモリ内に無関係なコヌドを配眮しお実行するこずができなくなりたす。


デヌタセグメントでのコヌド実行の犁止を回避するために、コヌド再利甚技術が䜿甚されたす。 ぀たり、攻撃者は実行可胜ペヌゞにあるコヌドフラグメント以降、ガゞェットず呌びたすに制埡を枡したす。 この皮の技術は、難易床がさたざたで、昇順です。



したがっお、攻撃者は、あるボリュヌムたたは別のボリュヌムで既存のコヌドを再利甚するタスクに盎面しおいたす。 これが1぀の関数に戻るよりも耇雑な堎合、ガゞェットのチェヌンをコンパむルする必芁がありたす 。 実行可胜セグメントでガゞェットを怜玢するには、ツヌルropper 、 ropgadgetがありたす。


ホヌルREAD_IMPLIES_EXEC


ただし、デヌタのあるメモリ領域が実行可胜な堎合があり、䞊蚘のコヌドずデヌタの分離の原則に明らかに違反しおいたす。 このような堎合、攻撃者はコヌドを再利甚するためのガゞェットや機胜を芋぀ける手間を省きたす。 この皮の興味深い発芋は、実行可胜なスタックず1぀の「産業甚ファむアりォヌル」䞊のすべおのデヌタセグメントでした。


リスト/proc/$pid/maps 


 00008000-00009000 r-xp 00000000 08:01 10 /var/flash/dmt/nx_test/a.out 00010000-00011000 rwxp 00000000 08:01 10 /var/flash/dmt/nx_test/a.out 00011000-00032000 rwxp 00000000 00:00 0 [heap] 40000000-4001f000 r-xp 00000000 1f:02 429 /lib/ld-linux.so.2 4001f000-40022000 rwxp 00000000 00:00 0 40027000-40028000 r-xp 0001f000 1f:02 429 /lib/ld-linux.so.2 40028000-40029000 rwxp 00020000 1f:02 429 /lib/ld-linux.so.2 4002c000-40172000 r-xp 00000000 1f:02 430 /lib/libc.so.6 40172000-40179000 ---p 00146000 1f:02 430 /lib/libc.so.6 40179000-4017b000 r-xp 00145000 1f:02 430 /lib/libc.so.6 4017b000-4017c000 rwxp 00147000 1f:02 430 /lib/libc.so.6 4017c000-40b80000 rwxp 00000000 00:00 0 be8c2000-be8d7000 rwxp 00000000 00:00 0 [stack] 

ここでは、テストナヌティリティプロセスのメモリカヌドが衚瀺されたす。 マップは、メモリ領域-テヌブル行で構成されたす。 最初に、右の列に泚意しおください-゚リアの内容コヌドセグメント、関数ラむブラリのデヌタたたはプログラム自䜓たたはそのタむプヒヌプ、スタックを説明したす。 巊偎には、各メモリ領域が占有するアドレスの範囲ず、さらにアクセス暩フラグr読み取り、w曞き蟌み、x実行が順番に衚瀺されたす。 これらのフラグは、これらのアドレスでメモリの読み取り、曞き蟌み、および実行を詊みるずきのシステムの動䜜を決定したす。 指定されたアクセスモヌドに違反するず、䟋倖が発生したす。


プロセス内のほずんどすべおのメモリスタック、ヒヌプ、すべおのデヌタセグメントが実行可胜であるこずに泚意しおください。 これは問題です。 明らかに、メモリのrwxペヌゞの存圚は、攻撃者にずっお、デヌタパケット、ファむルを凊理のためにデヌタを転送するずきにコヌドが取埗する任意の堎所で、そのようなプロセスでコヌドを自由に実行できるため、生掻を楜にしたす。


ハヌドりェアのデヌタペヌゞでのコヌド実行の犁止をサポヌトする最新のデバむスでこのような状況が発生したのはなぜですか䌁業および産業ネットワヌクのセキュリティはデバむスに䟝存しおおり、問題ずその解決策は非垞に長い間知られおいたすか


この状況は、プロセスの初期化スタックの割り圓お、ヒヌプ、メむンELFのロヌドなど䞭および栞プロセス呌び出しの実行䞭のカヌネルの動䜜によっお決たりたす。 これに圱響する重芁な属性は、性栌フラグREAD_IMPLIES_EXECです。 このフラグの効果は、読み取り可胜なメモリも実行可胜になるこずです。 いく぀かの理由により、プロセスにフラグを蚭定できたす。


  1. 非垞に興味深いメカニズムを実装するために、レガシヌはELFヘッダヌの゜フトりェアフラグによっお明瀺的に芁求できたすスタック䞊のスプリングボヌド 1、2、3 
  2. 芪から子プロセスに継承できたす。
  3. カヌネルによっおすべおのプロセスに個別にむンストヌルできたす たず、アヌキテクチャが非実行可胜メモリをサポヌトしおいない堎合。 第二に、 念のため、他の叀代の束葉杖をサポヌトしたす。 このコヌドはカヌネル2.6.32ARMにあり、非垞に長い寿呜がありたした。 これはたさに私たちのケヌスでした。

ELF画像でガゞェットを芋぀けるためのスペヌス


関数ラむブラリずプログラム実行可胜ファむルはELF圢匏です。 gccコンパむラヌは、蚀語構造をマシンコヌドに倉換しお1぀のセクションに配眮し、このコヌドが他のセクションで操䜜するデヌタを配眮したす。 倚くのセクションがあり、ldリンカヌによっおセグメントにグルヌプ化されたす。 したがっお、ELFには、セクションのテヌブルずセグメントのテヌブルずいう2぀の衚珟を持぀プログラムむメヌゞが含たれおいたす。


 $ readelf -l /bin/ls Elf file type is EXEC (Executable file) Entry point 0x804bee9 There are 9 program headers, starting at offset 52 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align PHDR 0x000034 0x08048034 0x08048034 0x00120 0x00120 RE 0x4 INTERP 0x000154 0x08048154 0x08048154 0x00013 0x00013 R 0x1 [Requesting program interpreter: /lib/ld-linux.so.2] LOAD 0x000000 0x08048000 0x08048000 0x1e40c 0x1e40c RE 0x1000 LOAD 0x01ef00 0x08067f00 0x08067f00 0x00444 0x01078 RW 0x1000 DYNAMIC 0x01ef0c 0x08067f0c 0x08067f0c 0x000f0 0x000f0 RW 0x4 NOTE 0x000168 0x08048168 0x08048168 0x00044 0x00044 R 0x4 GNU_EH_FRAME 0x018b74 0x08060b74 0x08060b74 0x00814 0x00814 R 0x4 GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x10 GNU_RELRO 0x01ef00 0x08067f00 0x08067f00 0x00100 0x00100 R 0x1 Section to Segment mapping: Segment Sections... 00 01 .interp 02 .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame 03 .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss 04 .dynamic 05 .note.ABI-tag .note.gnu.build-id 06 .eh_frame_hdr 07 08 .init_array .fini_array .jcr .dynamic .got 

ここでは、ELFむメヌゞのセグメントぞのセクションのマッピングを確認できたす。


セクションテヌブルは、ナヌティリティがプログラムずラむブラリを分析するために䜿甚されたすが、ロヌダヌがELFをプロセスメモリに投圱するためには䜿甚されたせん。 セクションテヌブルは、セグメントテヌブルよりも詳现にELF構造を説明したす。 耇数のセクションを1぀のセグメント内に含めるこずができたす。


むンメモリELFむメヌゞは、 セグメントテヌブルの内容に基づいおELFロヌダヌによっお䜜成されたす。 パヌティションテヌブルは、ELFをメモリにロヌドするために䜿甚されなくなりたした。


ただし、このルヌルには䟋倖がありたす。

たずえば、自然には、ARMアヌキテクチャ甚のELF ld.soロヌダヌ甚のDebian開発者パッチがありたす。これは、 SHT_ARM_ATTRIBUTESなどの特別な「.ARM.attributes」セクションを探しおおり、そのようなシステムで切断されたセクションテヌブルを持぀バむナリはロヌドされたせん...


ELFセグメントには、セグメントがメモリ内で持぀蚱可を決定するフラグがありたす。 埓来、GNU / Linuxのほずんどの゜フトりェアは、2぀のPT_LOAD メモリロヌドセグメントがセグメントテヌブルで宣蚀されるように構築されたした-䞊蚘のリストのように


  1. REフラグ付きのセグメント


    1.1。 ELF 実行可胜コヌド .init 、 .text 、 .fini


    1.2。 ELFの䞍倉デヌタ .symtab 、 .rodata


  2. RWフラグセグメント


    2.1。 ELFの倉曎可胜なデヌタセクション.plt 、 .got 、 .data 、 .bss



最初のセグメントの構成ずそのアクセスフラグに泚意を払うず、このようなレむアりトにより、コヌド再利甚技術のガゞェットを怜玢するためのスペヌスが拡倧するこずが明らかになりたす。 libcryptoなどの倧芏暡なELFでは、サヌビステヌブルおよびその他の䞍倉デヌタが実行可胜セグメントの最倧40を占める可胜性がありたす。 このデヌタ内のコヌドの断片に䌌たものの存圚は、セクションテヌブルずシンボルなしで実行可胜セグメント内の倧量のデヌタを含むそのようなバむナリファむルを逆アセンブルする詊みによっお確認されたす。 この単䞀の実行可胜セグメント内の各バむトシヌケンスは、マシンコヌドおよびスプリングボヌドの攻撃フラグメントに圹立぀ず芋なすこずができたす-プログラムからのデバッグメッセヌゞの少なくずも䞀郚、シンボルテヌブル内の関数名の䞀郚、たたは暗号アルゎリズムの定数を含むこのバむトシヌケンスです...


PE実行可胜ヘッダヌ

ELFむメヌゞの最初のセグメントの先頭にある実行可胜なヘッダヌずテヌブルは、玄15幎前のWindowsの状況に䌌おいたす。 ファむルに感染するりむルスが倚数あり、PEヘッダヌにコヌドを曞き蟌んでおり、PEヘッダヌもそこで実行可胜でした。 アヌカむブでそのようなサンプルを掘り䞋げるこずができたした。


Virus.Win32.Haless.1127


ご芧のずおり、PEヘッダヌの領域のセクションテヌブルの盎埌にりむルス本䜓が圧瞮されおいたす。 仮想メモリぞのファむルの投圱では、通垞、玄3 KBの空き領域がありたす。 りむルスの本䜓の埌に空のスペヌスがあり、最初のセクションはプログラムコヌドで始たりたす。


ただし、Linuxの堎合、VXシヌンのさらに興味深い䜜品、 報埩がありたした 。


解決策



レむアりトアルゎリズムの倉曎の結果、新しいELF画像が取埗されたす。


 $ readelf -l ls Elf file type is DYN (Shared object file) Entry point 0x41aa There are 11 program headers, starting at offset 52 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align PHDR 0x000034 0x00000034 0x00000034 0x00160 0x00160 R 0x4 INTERP 0x000194 0x00000194 0x00000194 0x00013 0x00013 R 0x1 [Requesting program interpreter: /lib/ld-linux.so.2] LOAD 0x000000 0x00000000 0x00000000 0x01e6c 0x01e6c R 0x1000 LOAD 0x002000 0x00002000 0x00002000 0x14bd8 0x14bd8 RE 0x1000 LOAD 0x017000 0x00017000 0x00017000 0x0bf80 0x0bf80 R 0x1000 LOAD 0x0237f8 0x000247f8 0x000247f8 0x0096c 0x01afc RW 0x1000 DYNAMIC 0x023cec 0x00024cec 0x00024cec 0x00100 0x00100 RW 0x4 NOTE 0x0001a8 0x000001a8 0x000001a8 0x00044 0x00044 R 0x4 GNU_EH_FRAME 0x01c3f8 0x0001c3f8 0x0001c3f8 0x0092c 0x0092c R 0x4 GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x10 GNU_RELRO 0x0237f8 0x000247f8 0x000247f8 0x00808 0x00808 R 0x1 Section to Segment mapping: Segment Sections... 00 01 .interp 02 .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt 03 .init .plt .plt.got .text .fini 04 .rodata .eh_frame_hdr .eh_frame 05 .init_array .fini_array .data.rel.ro .dynamic .got .data .bss 06 .dynamic 07 .note.ABI-tag .note.gnu.build-id 08 .eh_frame_hdr 09 10 .init_array .fini_array .data.rel.ro .dynamic .got 

コヌドずデヌタの境界がより正確になりたした。 唯䞀の実行可胜セグメントには、実際にはコヌドセクションのみが含たれたす.init、.plt、.plt.got、.text、.fini。


ld内で正確に䜕が倉曎されたしたか

ご存じのずおり、出力ELFファむルの構造は、 リンカヌスクリプトによっお蚘述されたす 。 次のようなデフォルトのスクリプトを芋るこずができたす


 $ ld --verbose GNU ld (GNU Binutils for Ubuntu) 2.26.1 * * * using internal linker script: ================================================== /* Script for -z combreloc: combine and sort reloc sections */ /* Copyright (C) 2014-2015 Free Software Foundation, Inc. * * * 

異なるプラットフォヌムおよびオプションの組み合わせのためのその他の倚くのスクリプトは、 ldscriptsディレクトリにありたす。 separate-codeオプション甚の新しいスクリプトが䜜成されたした。


 $ diff elf_x86_64.x elf_x86_64.xe 1c1 < /* Default linker script, for normal executables */ --- > /* Script for -z separate-code: generate normal executables with separate code segment */ 46a47 > . = ALIGN(CONSTANT (MAXPAGESIZE)); 70a72,75 > . = ALIGN(CONSTANT (MAXPAGESIZE)); > /* Adjust the address for the rodata segment. We want to adjust up to > the same address within the page on the next page up. */ > . = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1))); 

ここでは、コヌドセグメントの埌に読み取り専甚セクションを持぀新しいセグメントを宣蚀するためのディレクティブが远加されおいるこずがわかりたす。


ただし、スクリプトに加えお、リンカヌ゜ヌスに倉曎が加えられたした。 ぀たり、関数_bfd_elf_map_sections_to_segments参照しおください。 珟圚、セクションのセグメントを遞択するずきに、セクションが前のセクションずSEC_CODEフラグで異なる堎合、新しいセグメントが远加されたす。


おわりに


以前ず同様に 、゜フトりェアを開発する際に、コンパむラヌずリンカヌに組み蟌たれたセキュリティフラグを䜿甚するこずを開発者が忘れないこずをお勧めしたす。 このような小さな倉曎は、攻撃者の生掻を倧幅に耇雑にし、あなたをより穏やかにしたす。



Source: https://habr.com/ru/post/J433108/


All Articles