본문 바로가기

SYSTEM HACKING

[SWING] Pwnable 04 - Use After Free

 

원룸을 임대해 거주하다가 계약이 만료되었다고 하자.

그럼 세입자는 임대인에게 원룸 접근 권한 즉, 열쇠나 비밀번호 설정 권한 등을 반납해야할 것이다.

세입자가 나가고 임대인은 원룸을 청소한 뒤 새로운 세입자를 구한다.

 

이 때 이전 세입자에게서 접근 권한을 회수하고, 방을 깨끗이 청소해 이전 세입자의 정보를 지우는 것은 매우 중요하다.

 

ptmalloc2를 이용한 메모리 관리도 위의 예시와 같다.

 

메모리 참조에 사용한 포인터를 메모리 해제 후에 적절히 초기화하지 않거나,

해제한 메모리를 초기화하지 않고 다음 청크에 재할당할 때 발생하는 취약점

 

실습 환경 Dockerfile

 

FROM ubuntu:18.04

ENV PATH="${PATH}:/usr/local/lib/python3.6/dist-packages/bin"
ENV LC_CTYPE=C.UTF-8

RUN apt update
RUN apt install -y \
    gcc \
    git \
    python3 \
    python3-pip \
    ruby \
    sudo \
    tmux \
    vim \
    wget

# install pwndbg
WORKDIR /root
RUN git clone https://github.com/pwndbg/pwndbg
WORKDIR /root/pwndbg
RUN git checkout 2023.03.19
RUN ./setup.sh

# install pwntools
RUN pip3 install --upgrade pip
RUN pip3 install pwntools

# install one_gadget command
RUN gem install one_gadget

WORKDIR /root

 

도커 이미지 빌드, 컨테이너 실행, 셸 실행

 

원래는 18.04 버전에 맞춰서하라고 되어있었으나 22.04 버전에 맞추어 임의로 수정하였다.

 

 

Dangling Pointer

유효하지 않은 메모리 영역을 가리키는 포인터

 

메모리 동적 할당 시 포인터를 선언하고, malloc 함수가 할당한 메모리 주소를 저장한다.

메모리에 접근할 때는 그 포인터를 참조한다.

메모리를 해제할 때는 free 함수를 호출한다.

 

그러나 free 함수는 청크를 ptmalloc에 반환하기만 할 뿐, 청크의 주소를 담고 있던 포인터를 초기화하지는 않기 때문에,

free 호출 이후 프로그래머가 포인터를 초기화하지 않으면, 포인터는 해제된 청크를 가리키는 Dangling Pointer가 된다.

 

 

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

int main() {
  char *ptr = NULL;
  int idx;

  while (1) {
    printf("> ");
    scanf("%d", &idx);
    switch (idx) {
      case 1:
        if (ptr) {
          printf("Already allocated\n");
          break;
        }
        ptr = malloc(256);
        break;
      case 2:
        if (!ptr) {
          printf("Empty\n");
        }
        free(ptr);
        break;
      default:
        break;
    }
  }
}

 

청크 해제 이후 청크를 가리키던 ptr 변수를 초기화하지 않았다.

 

 

 

 

 

ptr이 해제된 청크의 주소를 가리키고 있는데 이를 다시 해제할 수도 있다.

=> Double Free Bug

 

Use After Free

해제된 메모리에 접근할 수 있을 때 발생하는 취약점

 

malloc, free 함수는 할당 또는 해제할 메모리의 데이터를 초기화하지 않는다.

새롭게 할당한 청크를 프로그래머가 초기화하지 않으면, 메모리에 남아있던 데이터가 유출될 수 있다.

 

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

struct NameTag {
  char team_name[16];
  char name[32];
  void (*func)();
};

struct Secret {
  char secret_name[16];
  char secret_info[32];
  long code;
};

int main() {
  int idx;

  struct NameTag *nametag;
  struct Secret *secret;

  secret = malloc(sizeof(struct Secret));

  strcpy(secret->secret_name, "ADMIN PASSWORD");
  strcpy(secret->secret_info, "P@ssw0rd!@#");
  secret->code = 0x1337;

  free(secret);
  secret = NULL;

  nametag = malloc(sizeof(struct NameTag));

  strcpy(nametag->team_name, "security team");
  memcpy(nametag->name, "S", 1);

  printf("Team Name: %s\n", nametag->team_name);
  printf("Name: %s\n", nametag->name);

  if (nametag->func) {
    printf("Nametag function: %p\n", nametag->func);
    nametag->func();
  }
}

 

정의된 구조체 NameTag, Secret 중 유출되면 안 되는 Secret 구조체를 먼저 할당한다.

secret_name, secret_info, code에 값을 입력하고 해제한다.

nametag을 생성하고 team_name, name에 각각의 값을 입력하고 입력한 데이터를 출력한다.

func가 NULL이 아니라면 포인터가 가리키는 주소를 출력하고 해당 주소의 함수를 호출한다.

 

 

Name으로 secret_info 문자열이 출력되고, 값을 입력한 적 없는 함수 포인터가 0x1337을 가리킨다.

 

uaf 동적 분석

ptmalloc2:

새로운 할당 요청이 들어오면 비슷한 크기의 청크가 bin이나 tcache에 있는지 확인하고, 있다면 청크를 꺼내어 재사용한다.

 

Nametag와 Secret은 같은 크기의 구조체이므로,

secret을 해제하고 nametag을 할당하면, 둘은 같은 메모리 영역을 사용하게 된다.

 

free는 해제한 메모리의 데이터를 초기화하지 않으므로, nametag에는 secret의 값 일부가 남아있게 된다.

 

gdb로 secret 해제 후 secret이 사용하던 메모리 영역의 데이터를 살펴보자.

 

 

 

free 명령어 부분에 중단점을 설정

 

 

heap: 할당 및 해제된 청크들의 정보 조회

 

 

0x405290: secret 청크, 해제되어서 tcache 엔트리에 들어감

0x405000: tcache_perthread_struct 구조체, libc 단에서 힙 영역 초기화할 때 할당하는 청크

0x4052d0: 탑 청크

 

secret이 사용하던 메모리 영역 출력

 

 

secret_name은 적절한 fd와 bk 값으로 초기화됨

secret_info 부분은 그대로 남아있음

 

nametag 할당 후 printf 호출 시점에서 nametag 멤버 변수 값 확인

 

 

nametag -> team_name: "security team" 그대로 입력됨

nametag -> name: 초기화되지 않은 secret_info 값 존재

nametag -> func: secret -> code에 대입했던 0x1337이 남아있음

이 값이 0이 아니므로 nametag -> func 호출되고 Segmentation Fault 발생 

 

'SYSTEM HACKING' 카테고리의 다른 글

[SWING] Pwnable 05 - Tcache Poisoning  (0) 2023.11.19
[SWING] Pwnable 05 - Double Free Bug  (0) 2023.11.19
[SWING] Pwnable 04 - ptmalloc2  (0) 2023.11.11
[SWING] Pwnable 04 - Format String Bug  (0) 2023.11.11
[SWING] Pwnable 03 - PLT&GOT  (0) 2023.09.25