ptmalloc2

(๋ฆฌ๋ˆ…์Šค glibc 2.23 ์—์„œ ํž™ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น์„ ํ•  ๋•Œ, ptmalloc2 ๋ผ๋Š” ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น์ž๋ฅผ ์‚ฌ์šฉ)

 

1. Use-After-Free

: ๋ฉ”๋ชจ๋ฆฌ ์ฐธ์กฐ์— ์‚ฌ์šฉํ•œ ํฌ์ธํ„ฐ๋ฅผ ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ ํ›„์— ์ ์ ˆํžˆ ์ดˆ๊ธฐํ™”ํ•˜์ง€ ์•Š์•„์„œ, ๋˜๋Š” ํ•ด์ œํ•œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜์ง€ ์•Š๊ณ  ๋‹ค์Œ ์ฒญํฌ์— ์žฌํ• ๋‹นํ•ด์ฃผ๋ฉด์„œ ๋ฐœ์ƒํ•˜๋Š” ์ทจ์•ฝ์ 

โ€‹

Dangling Pointer

: ์œ ํšจํ•˜์ง€ ์•Š์€ ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ

- ํ”„๋กœ๊ทธ๋žจ์ด ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋™์ž‘์„ ํ•  ๊ฐ€๋Šฅ์„ฑ์„ ํ‚ค์›€

- ๊ณต๊ฒฉ์ž์—๊ฒŒ ๊ณต๊ฒฉ ์ˆ˜๋‹จ์œผ๋กœ ํ™œ์šฉ๋  ์ˆ˜๋„ ์žˆ์Œ

โ€‹

* malloc ํ•จ์ˆ˜๋Š” ํ• ๋‹นํ•œ ๋ฉ”๋ชจ๋ฆฌ์˜ ์ฃผ์†Œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜

๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋™์  ํ• ๋‹นํ•  ๋•Œ์— ํฌ์ธํ„ฐ๋ฅผ ์„ ์–ธํ•˜๊ณ , ๊ทธ ํฌ์ธํ„ฐ์— mallocํ•จ์ˆ˜๊ฐ€

ํ• ๋‹นํ•œ ๋ฉ”๋ชจ๋ฆฌ์˜ ์ฃผ์†Œ๋ฅผ ์ €์žฅ -> ์ ‘๊ทผ

๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ•ด์ œํ•  ๋• freeํ•จ์ˆ˜ ์‚ฌ์šฉ

โ€‹

free ํ•จ์ˆ˜๋Š” ์ฒญํฌ๋ฅผ ptmalloc์— ๋ฐ˜ํ™˜ํ•˜๊ธฐ๋งŒ ํ•˜๊ณ  ์ฒญํฌ์˜ ์ฃผ์†Œ๋ฅผ ๋‹ด๊ณ  ์žˆ๋˜ ํฌ์ธํ„ฐ๋Š” ์ดˆ๊ธฐํ™”ํ•˜์ง€ ์•Š์Œ

-> ๋”ฐ๋กœ ํฌ์ธํ„ฐ๋ฅผ ์ดˆ๊ธฐํ™”ํ•ด์ฃผ์ง€ ์•Š์œผ๋ฉด ๊ทธ ํฌ์ธํ„ฐ๋Š” ํ•ด์ œ๋œ ์ฒญํฌ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” Dangling Pointer๊ฐ€ ๋จ

โ€‹

โ€ป chunk(์ฒญํฌ) : malloc()์œผ๋กœ ํ• ๋‹น ๋ฐ›๋Š” ์˜์—ญ๊ณผ header๋ฅผ ํฌํ•จํ•œ ์˜์—ญ

// Name: dangling_ptr.c
// Compile: gcc -o dangling_ptr dangling_ptr.c
#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;
    }
  }
}
 } }

์œ„์˜ ์ฝ”๋“œ๋Š” freeํ˜ธ์ถœ ์ดํ›„ ์ดˆ๊ธฐํ™”๋ฅผ ํ•˜์ง€ ์•Š์•„์„œ Dangling Pointer์˜ ์œ„ํ—˜์„ฑ์„ ๋ณด์ด๋Š” ์˜ˆ์ œ์ด๋‹ค.

์œ„ ์˜ˆ์ œ์—์„œ๋Š” ptr๋ณ€์ˆ˜๋ฅผ ํ•ด์ œํ•˜๊ณ  ์ดˆ๊ธฐํ™”ํ•˜์ง€ ์•Š๋Š”๋‹ค.

๋”ฐ๋ผ์„œ ์ปดํŒŒ์ผ์„ ํ•ด์ฃผ๊ณ  ์ฒญํฌ๋ฅผ ํ• ๋‹น(1)ํ•˜๊ณ  ํ•ด์ œ(2)ํ•˜๋ฉด ptr์€ ์ฒญํฌ์˜ ์ฃผ์†Œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” Dangling Pointer๊ฐ€ ๋œ๋‹ค.

ptr์ด ํ•ด์ œ๋œ ์ฒญํฌ์˜ ์ฃผ์†Œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ์œผ๋ฏ€๋กœ 2๋ฅผ ๋‹ค์‹œ ์ž…๋ ฅํ•ด์„œ ํ•ด์ œํ•  ์ˆ˜ ์žˆ๋‹ค.

=> Double Free Bug (์†Œํ”„ํŠธ์›จ์–ด ์ทจ์•ฝ์ )

โ€‹

โ€‹

โ€‹

โ€‹

โ€‹

Use After Free (UAF)

: ํ•ด์ œ๋œ ๋ฉ”๋ชจ๋ฆฌ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์„ ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ์ทจ์•ฝ์ 

- ์ด์ „ ๊ฒฝ์šฐ์™€ ๋‹ฌ๋ฆฌ ์ƒˆ๋กญ๊ฒŒ ํ• ๋‹นํ•œ ์˜์—ญ์„ ์ดˆ๊ธฐํ™”ํ•˜์ง€ ์•Š๊ณ  ์‚ฌ์šฉํ•˜๋ฉด์„œ ๋ฐœ์ƒํ•˜๊ธฐ๋„ ํ•จ

 

// Name: uaf.c
// Compile: gcc -o uaf uaf.c -no-pie
#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));          // secret๊ตฌ์กฐ์ฒด ๋จผ์ € ํ• ๋‹น
  strcpy(secret->secret_name, "ADMIN PASSWORD");   // secret_name, secret_info, code์— ๊ฐ’์„ ์ž…๋ ฅ
  strcpy(secret->secret_info, "P@ssw0rd!@#");
  secret->code = 0x1337;
  free(secret);                                     // ํ•ด์ œ
  secret = NULL;                                    // ์ดˆ๊ธฐํ™”
  nametag = malloc(sizeof(struct NameTag));         
  strcpy(nametag->team_name, "security team");      // team_name, name์˜ ๊ฐ’์„ ์ž…๋ ฅ
  memcpy(nametag->name, "S", 1);
  printf("Team Name: %s\n", nametag->team_name);
  printf("Name: %s\n", nametag->name);
  if (nametag->func) {                               // func๊ฐ€ NULL์ด ์•„๋‹ˆ๋ฉด ํฌ์ธํ„ฐ๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ฃผ์†Œ ์ถœ๋ ฅ, ํ•จ์ˆ˜ ํ˜ธ์ถœ
    printf("Nametag function: %p\n", nametag->func);
    nametag->func();
  }
}

Name๋กœ secret_info์˜ ๋ฌธ์ž์—ด์ด ์ถœ๋ ฅ๋˜๊ณ , ๊ฐ’์„ ์ž…๋ ฅํ•œ ์  ์—†๋Š” ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๊ฐ€ 0x1337์„ ๊ฐ€๋ฆฌํ‚จ๋‹ค.

์™ค๊นŒ?

โ€‹

โ€‹

โ€‹

uaf ๋™์  ๋ถ„์„

ptmalloc2๋Š” ์ƒˆ๋กœ์šด ํ• ๋‹น ์š”์ฒญ์ด ๋“ค์–ด์™”์„ ๋•Œ ์š”์ฒญ๋œ ํฌ๊ธฐ์™€ ๋น„์Šทํ•œ ์ฒญํฌ๊ฐ€ bin์ด๋‚˜ tcache์— ์žˆ๋Š”์ง€ ํ™•์ธํ•œ ํ›„, ์žˆ๋‹ค๋ฉด ํ•ด๋‹น ์ฒญํฌ๋ฅผ ๊บผ๋‚ด ์žฌ์‚ฌ์šฉํ•œ๋‹ค.

โ€‹

secret๊ณผ nametag๋Š” ๊ฐ™์€ ํฌ๊ธฐ์˜ ๊ตฌ์กฐ์ฒด์ด๋‹ค.

--> secret์„ ํ•ด์ œํ•˜๊ณ  nametag๋ฅผ ํ• ๋‹นํ•˜๋ฉด nametag๋Š” secret๊ณผ ๊ฐ™์€ ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์„ ์‚ฌ์šฉ

-- free๋Š” ํ•ด์ œํ•œ ๋ฉ”๋ชจ๋ฆฌ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— nametag์—๋Š” secret์˜ ๊ฐ’์ด ์ผ๋ถ€ ๋‚จ์Œ

 

disassemble main
main+108์— ๋ธŒ๋ ˆ์ดํฌํฌ์ธํŠธ ์„ค์ •
heap

heap - ํ• ๋‹น ๋ฐ ํ•ด์ œ๋œ ์ฒญํฌ๋“ค์˜ ์ •๋ณด๋ฅผ ์กฐํšŒํ•˜๋Š” ๋ช…๋ น์–ด์ด๋‹ค.โ€‹

0x602250์ดํ›„๋กœ 8byte ๋‹จ์œ„๋กœ 10๊ฐœ์˜ ๋ฉ”๋ชจ๋ฆฌ ํ™•์ธ / 0x602270์˜ ๋ฉ”๋ชจ๋ฆฌ ํ™•์ธ

secret์ด ์‚ฌ์šฉํ•œ ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์„ ์ถœ๋ ฅํ•œ ๊ฒƒ์ด๋‹ค. 

secret_name์€ ์ ์ ˆํ•œ fd์™€ bk๊ฐ’์œผ๋กœ ์ดˆ๊ธฐํ™”๋์ง€๋งŒ secret_info์˜ ๊ฐ’์€ ๊ทธ๋Œ€๋กœ ๋‚จ์•„์žˆ๋Š” ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

โ€‹

โ€‹

๋‹ค์Œ์œผ๋กœ printfํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์‹œ์ ์—์„œ nametag ๋ฉค๋ฒ„ ๋ณ€์ˆ˜๋“ค์˜ ๊ฐ’์„ ํ™•์ธํ•ด๋ณด๊ณ ์ž ํ•œ๋‹ค.

disassemble main

printf ํ•จ์ˆ˜๊ฐ€ main+207์—์„œ ํ˜ธ์ถœ๋˜๋Š” ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

โ€‹

 main+207์— ๋ธŒ๋ ˆ์ดํฌ ํฌ์ธํŠธ
0x602250์ดํ›„๋กœ 8byte ๋‹จ์œ„๋กœ 10๊ฐœ์˜ ๋ฉ”๋ชจ๋ฆฌ ํ™•์ธ / 0x602270์˜ ๋ฉ”๋ชจ๋ฆฌ ํ™•์ธ / 0x602270์˜ ๋ฉ”๋ชจ๋ฆฌ ํ™•์ธ / 0x602290 8byte๋‹จ์œ„๋กœ ๋ฉ”๋ชจ๋ฆฌ ํ™•์ธ

 

nametag->team_name์—๋Š” "security team"์ด ๊ทธ๋Œ€๋กœ ์ž…๋ ฅ๋˜์—ˆ์œผ๋‚˜,

nametag->name์—๋Š” ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์€ secret_info์˜ ๊ฐ’์ด ์กด์žฌํ•˜๋Š” ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

๋˜ํ•œ nametag->func์œ„์น˜์— secret->code์— ๋Œ€์ž…ํ–ˆ๋˜ 0x1337์ด ๋‚จ์•„์žˆ๋Š” ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

โ€‹

 

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

0x1337์ด 0์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ์œ„์˜ ์†Œ์Šค์ฝ”๋“œ์—์„œ nametag->func๊ฐ€ ํ˜ธ์ถœ๋˜๊ณ , Segmentation fault๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

 

๋ณต์‚ฌํ–ˆ์Šต๋‹ˆ๋‹ค!