流れに流れて今回はシェルコードに挑戦してみようと思います。
まずシェルコードとは
ソフトウェアのセキュリティホールを利用するペイロードとして使われるコード断片である。
By Wikipedia
いわゆるfragmentだ。
とりあえず参考サイトのままに権限を取得するコードを試しでやってみた。
実行結果しか載せないけど、うまくいかずに結構時間はかかってる。
アセンブラむずかしい。
[takeken@32bittest]$ id [/home/takeken/asm] uid=500(takeken) gid=500(takeken) [takeken@32bittest]$ ./shelltest.o sh-4.1# zsh [root@32bittest]$ id uid=0(root) gid=500(takeken) [root@32bittest]$
さくっとrootが取れちゃうような、こういうものらしいけど・・・、サンプルがこういうのしかなく試しただけであって、自分でアセンブラを使ってなにか作りたいのさ。
アセンブリに詳しくなりそうだし、まずはやっぱりHello Worldだわよね。
とりあえず前回作ったHello Worldのコードを修正する。
-nostdlibオプションを使うように、短いコードにする。
[takeken@32bittest]# cat hello2.s [/home/takeken/asm] .att_syntax noprefix .global _start _start: mov $1, %ebx mov $4, %eax mov $msg, %ecx mov $15, %edx int $0x80 mov $1, %eax int $0x80 .data msg: .ascii "Hello, World!!\n" [takeken@32bittest]# ./hello2 [/home/takeken/as Hello, World!! [takeken@32bittest]#
実行可能となりました。
だけどこのままではダメなようで、シェルコードはヌルバイトをなくさないといけないらしい。
レジスタのことはまだいまいち分かってないので、パズル式にやってみる。
pushとaddを使って、ヌルにならないようにしてみた。
[takeken@32bittest]# cat hello2.s [/home/takeken/asm] .att_syntax noprefix .global _start _start: mov $1, %ebx mov $4, %eax mov $msg, %ecx mov $15, %edx int $0x80 mov $1, %eax int $0x80 .data msg: .ascii "Hello, World!!\n" [takeken@32bittest]# objdump -d hello hello: file format elf32-i386 Disassembly of section .text: 080480b8 <_start>: 80480b8: 31 d2 xor %edx,%edx 80480ba: 6a 01 push $0x1 80480bc: 53 push %ebx 80480bd: 83 c0 04 add $0x4,%eax 80480c0: b9 d0 90 04 08 mov $0x80490d0,%ecx 80480c5: 83 c2 0f add $0xf,%edx 80480c8: cd 80 int $0x80 80480ca: b0 01 mov $0x1,%al 80480cc: cd 80 int $0x80 [takeken@32bittest]# ./hello2 Hello, World!!
ご覧のようにヌルバイトがなくなり、実行も可能な状態となった。
だが
Cの形式にしてみて実行しても
objdump -M att -d hello2 | grep '^ ' | cut -f2 | perl -pe 's/(\w{2})\s+/\\x\1/g' #include <stdio.h> char shellcode[] = "\x31\xd2\x6a\x01\x53\x83\xc0\x04\xb9\xd0\x90\x04\x08\x83\xc2\x0f\xcd\x80\xb0\x01\xcd\x80"; int main() { printf("sizeof(shellcode) == %d\n", sizeof(shellcode)); (*(void (*)())shellcode)(); } $ ./aa.o [/home/takeken/asm] sizeof(shellcode) == 23 zsh: segmentation fault ./aa.o
だめらしい。
うーん・・・。
どうしたもんかなぁ。
普通にデバッグしてみたものの
(gdb) next Single stepping until exit from function shellcode, which has no line number information. Program received signal SIGSEGV, Segmentation fault. 0x0804966c in shellcode () (gdb) next Single stepping until exit from function shellcode, which has no line number information. Program terminated with signal SIGSEGV, Segmentation fault. The program no longer exists.
うーん、分からん。
nasm式というのがあるらしいので、そっちでやってみることにした。
[takeken@32bittest nasm]$ cat hello.asm section .text global _start BITS 32 _start: xor edx, edx mov ebx, 1 ; stdout mov eax, 4 ; write mov ecx, msg ; address mov edx, len int 0x80 mov eax, 1 ; sys_exit int 0x80 section .data msg db 'hello, world',0xa len equ $ - msg [takeken@32bittest nasm]$ ./hello hello, world
とりあえず実行できるようにはなったものの。
[takeken@32bittest nasm]$ objdump -d hello.o hello.o: file format elf32-i386 Disassembly of section .text: 00000000 <_start>: 0: 31 d2 xor %edx,%edx 2: bb 01 00 00 00 mov $0x1,%ebx 7: b8 04 00 00 00 mov $0x4,%eax c: b9 00 00 00 00 mov $0x0,%ecx 11: ba 0d 00 00 00 mov $0xd,%edx 16: cd 80 int $0x80 18: b8 01 00 00 00 mov $0x1,%eax 1d: cd 80 int $0x80
そりゃそうなんだが、ヌルヌルなのであった。
さっきの要領でヌル除去を進めていくんだが、うまくいかないらしい。
もうダメかなーなんて思ってたらNASMは変数タイプを保存しないというのを発見して閃いた。
[takeken@32bittest nasm]$ cat hello.asm section .text global _start BITS 32 foo equ 1 bar equ 4 _start: xor edx, edx mov bl,foo ; stdout mov al,bar ; write mov ecx, msg ; address mov dl, len int 0x80 mov al, 1 ; sys_exit mov ah, 0 int 0x80 section .data msg db 'hello, world',0xa len equ $ - msg [takeken@32bittest nasm]$ nasm -f elf hello.asm && ld -s -o hello hello.o [takeken@32bittest nasm]$ ./hello hello, world [takeken@32bittest nasm]$ objdump -d hello hello: file format elf32-i386 Disassembly of section .text: 08048080 <.text>: 8048080: 31 d2 xor %edx,%edx 8048082: b3 01 mov $0x1,%bl 8048084: b0 04 mov $0x4,%al 8048086: b9 98 90 04 08 mov $0x8049098,%ecx 804808b: b2 0d mov $0xd,%dl 804808d: cd 80 int $0x80 804808f: b0 01 mov $0x1,%al 8048091: b4 00 mov $0x0,%ah 8048093: cd 80 int $0x80
おおおー。
[takeken@32bittest nasm]$ ./mike
セグメンテーション違反です orz
ダメか。
なにか違うところに原因があるのかもしれない。
参考サイト
技術メモ帖 shellcode を書く
ももいろテクノロジー Linux x86用のシェルコードを書いてみる