流れに流れて今回はシェルコードに挑戦してみようと思います。
まずシェルコードとは
ソフトウェアのセキュリティホールを利用するペイロードとして使われるコード断片である。
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用のシェルコードを書いてみる