Ver3.0 ๐ก๏ธ ์ ํ๋ฆฌ์ผ์ด์ ๋ณด์: ๋ฒํผ ์ค๋ฒํ๋ก์ฐ ์ทจ์ฝ์ ์๋ฒฝ ๋์ ๊ฐ์ด๋

๐ก๏ธ ์ ํ๋ฆฌ์ผ์ด์ ๋ณด์: ๋ฒํผ ์ค๋ฒํ๋ก์ฐ ์ทจ์ฝ์ ์๋ฒฝ ๋์ ๊ฐ์ด๋
๐ฅ ๋ฒํผ ์ค๋ฒํ๋ก์ฐ, ์ ์์ง๋ ๋ฌธ์ ์ผ๊น?
์ผ ์์งํ 2024๋
์ธ๋ฐ ์์ง๋ ๋ฒํผ ์ค๋ฒํ๋ก์ฐ ์๊ธฐํ๋๊ณ ? ใ
ใ
ใ
๊ทผ๋ฐ ์ง์ง ์ด๊ฒ ์์ง๋ ํ์ญ์ด์ผ. ๐คฆโโ๏ธ
OWASP Top 10์๋ ์ง์ ์ ์ผ๋ก ์ ๋์ค์ง๋ง, ๋ฉ๋ชจ๋ฆฌ ์์ ์ฑ ๋ฌธ์ ๋ ์ฌ์ ํ ์ฌ๊ฐํ ๋ณด์ ์ด์๊ฑฐ๋ . ํนํ C/C++๋ก ์์ฑ๋ ๋ ๊ฑฐ์ ์์คํ
์ด๋ ์๋ฒ ๋๋ ์ฅ๋น, IoT ๋๋ฐ์ด์ค์์๋ ์ง๊ธ๋ ๋ฒํผ ์ค๋ฒํ๋ก์ฐ ์ทจ์ฝ์ ์ด ๊ณ์ ๋ฐ๊ฒฌ๋๊ณ ์์ด.
2023๋
๊ธฐ์ค์ผ๋ก๋ CVE(Common Vulnerabilities and Exposures) ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฑ๋ก๋ ๋ฒํผ ์ค๋ฒํ๋ก์ฐ ๊ด๋ จ ์ทจ์ฝ์ ์ด ์๋ฐฑ ๊ฑด์ด ๋๋๋ค๋ ๊ฑฐ ์๊ณ ์์์ด? ๐ฑ
1988๋ ๋ชจ๋ฆฌ์ค ์(Morris Worm)์ด ๋ฒํผ ์ค๋ฒํ๋ก์ฐ๋ฅผ ์ ์ฉํ ์ต์ด์ ๋๊ท๋ชจ ์ฌ์ด๋ฒ ๊ณต๊ฒฉ์ด์์ด. ๊ทธ๋ก๋ถํฐ 35๋ ์ด ์ง๋ฌ๋๋ฐ๋ ์ฌ์ ํ ์ด ์ทจ์ฝ์ ์ ์ด์์๋ค๋ ๊ฒ ์์ด๋ฌ๋ํ์ง ใ ใ
๐ง ๋ฒํผ ์ค๋ฒํ๋ก์ฐ์ ๊ธฐ๋ณธ ์๋ฆฌ
๐ ๋ฉ๋ชจ๋ฆฌ ๊ตฌ์กฐ๋ถํฐ ์ดํดํ์
๋ฒํผ ์ค๋ฒํ๋ก์ฐ๋ฅผ ์ ๋๋ก ์ดํดํ๋ ค๋ฉด ํ๋ก๊ทธ๋จ์ ๋ฉ๋ชจ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ์์์ผ ํด. ํ๋ก๊ทธ๋จ์ด ์คํ๋๋ฉด ๋ฉ๋ชจ๋ฆฌ๋ ํฌ๊ฒ 4๊ฐ์ง ์์ญ์ผ๋ก ๋๋๊ฑฐ๋ :
1. ์ฝ๋(Text) ์์ญ: ์คํ ๊ฐ๋ฅํ ํ๋ก๊ทธ๋จ ์ฝ๋๊ฐ ์ ์ฅ๋๋ ๊ณณ
2. ๋ฐ์ดํฐ(Data) ์์ญ: ์ ์ญ ๋ณ์์ ์ ์ ๋ณ์๊ฐ ์ ์ฅ๋๋ ๊ณณ
3. ํ(Heap) ์์ญ: ๋์ ์ผ๋ก ํ ๋น๋๋ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ (malloc, new ๋ฑ)
4. ์คํ(Stack) ์์ญ: ์ง์ญ ๋ณ์, ํจ์ ๋งค๊ฐ๋ณ์, ๋ฆฌํด ์ฃผ์ ๋ฑ์ด ์ ์ฅ๋๋ ๊ณณ
๋ฒํผ ์ค๋ฒํ๋ก์ฐ๋ ์ฃผ๋ก ์คํ ์์ญ์์ ๋ฐ์ํด. ์๋๋ฉด ์คํ์ ํจ์ ํธ์ถ๊ณผ ๊ด๋ จ๋ ์ค์ํ ์ ๋ณด๋ค์ด ์ ์ฅ๋๋ ๊ณณ์ด๊ฑฐ๋ .
๐ฅ ๋ฒํผ ์ค๋ฒํ๋ก์ฐ๊ฐ ๋ฐ์ํ๋ ์๊ฐ
์, ์ด์ ์ค์ ๋ก ์ด๋ป๊ฒ ๋ฒํผ ์ค๋ฒํ๋ก์ฐ๊ฐ ๋ฐ์ํ๋์ง ์ฝ๋๋ก ๋ณด์. ์ง์ง ๊ฐ๋จํ ์์ ์ผ:
#include <stdio.h>
#include <string.h>
void vulnerable_function(char *input) {
char buffer[10]; // 10๋ฐ์ดํธ ๋ฒํผ
strcpy(buffer, input); // ์ํํ ํจ์!
printf("์
๋ ฅ๊ฐ: %s\n", buffer);
}
int main() {
char large_input[50] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAA"; // 28๊ฐ์ A
vulnerable_function(large_input);
return 0;
}
์ด ์ฝ๋์ ๋ฌธ์ ์ ์ด ๋ญ์ง ๋ณด์ฌ? ๐
buffer๋ 10๋ฐ์ดํธ๋ง ์ ์ฅํ ์ ์๋๋ฐ, strcpy() ํจ์๋ ์
๋ ฅ ํฌ๊ธฐ๋ฅผ ์ฒดํฌํ์ง ์๊ณ ๊ทธ๋ฅ ๋ณต์ฌํด๋ฒ๋ ค. ๊ทธ๋์ 28๋ฐ์ดํธ์ ๋ฐ์ดํฐ๊ฐ 10๋ฐ์ดํธ ๊ณต๊ฐ์ ๋ค์ด๊ฐ๋ ค๊ณ ํ๋ฉด... ๐ฃ BOOM!
๋จ์ 18๋ฐ์ดํธ๋ ์ด๋๋ก ๊ฐ๊น? ๋ฐ๋ก ์คํ์ ๋ค๋ฅธ ์์ญ์ ๋ฎ์ด์ฐ๊ฒ ๋ผ. ์ฌ๊ธฐ์๋ ํจ์์ ๋ฆฌํด ์ฃผ์, ๋ค๋ฅธ ๋ณ์๋ค, ์ค์ํ ์ ์ด ์ ๋ณด๋ค์ด ์์ ์ ์๊ฑฐ๋ .
๊ณต๊ฒฉ์๊ฐ ๋ฆฌํด ์ฃผ์๋ฅผ ์กฐ์ํ๋ฉด ํ๋ก๊ทธ๋จ์ ์คํ ํ๋ฆ์ ๋ง์๋๋ก ๋ฐ๊ฟ ์ ์์ด. ์ด๊ฒ ๋ฐ๋ก ์ฝ๋ ์คํ ๊ณต๊ฒฉ(Code Execution Attack)์ ํต์ฌ์ด์ผ!
๐ฏ ๋ฒํผ ์ค๋ฒํ๋ก์ฐ์ ์ ํ๋ค
1๏ธโฃ ์คํ ๊ธฐ๋ฐ ๋ฒํผ ์ค๋ฒํ๋ก์ฐ (Stack-based Buffer Overflow)
๊ฐ์ฅ ํํ๊ณ ์ ํต์ ์ธ ํํ์ผ. ์์์ ๋ณธ ์์ ๊ฐ ๋ฐ๋ก ์ด๊ฑฐ์ง.
์คํ์ LIFO(Last In First Out) ๊ตฌ์กฐ๋ก ๋์ํ๋๋ฐ, ํจ์๊ฐ ํธ์ถ๋๋ฉด ์คํ ํ๋ ์์ด ์์ฑ๋๊ณ ์ฌ๊ธฐ์ ์ง์ญ ๋ณ์, ๋งค๊ฐ๋ณ์, ๋ฆฌํด ์ฃผ์ ๋ฑ์ด ์ ์ฅ๋ผ. ๋ฒํผ ์ค๋ฒํ๋ก์ฐ๊ฐ ๋ฐ์ํ๋ฉด ์ด ๋ฆฌํด ์ฃผ์๋ฅผ ๋ฎ์ด์ธ ์ ์๊ณ , ๊ณต๊ฒฉ์๋ ์ด๊ฑธ ์
์ฉํด์ ์๊ธฐ๊ฐ ์ํ๋ ์ฝ๋๋ฅผ ์คํ์ํฌ ์ ์์ด. ๐
2๏ธโฃ ํ ๊ธฐ๋ฐ ๋ฒํผ ์ค๋ฒํ๋ก์ฐ (Heap-based Buffer Overflow)
๋์ ์ผ๋ก ํ ๋น๋ ๋ฉ๋ชจ๋ฆฌ(ํ)์์ ๋ฐ์ํ๋ ์ค๋ฒํ๋ก์ฐ์ผ. ์คํ ๊ธฐ๋ฐ๋ณด๋ค ์
์ฉํ๊ธฐ๋ ์ข ๋ ๋ณต์กํ์ง๋ง, ์ฌ์ ํ ์ํํด.
ํ ์ค๋ฒํ๋ก์ฐ๋ ์ฃผ๋ก ๋ฉํ๋ฐ์ดํฐ๋ฅผ ์กฐ์ํ๋ ๋ฐฉ์์ผ๋ก ๊ณต๊ฒฉ์ด ์ด๋ฃจ์ด์ ธ. ํ ๊ด๋ฆฌ ๊ตฌ์กฐ์ฒด๋ฅผ ๋ฎ์ด์จ์ ์์์ ๋ฉ๋ชจ๋ฆฌ ์ฐ๊ธฐ๋ฅผ ๊ฐ๋ฅํ๊ฒ ๋ง๋๋ ๊ฑฐ์ง.
#include <stdlib.h>
#include <string.h>
int main() {
char *buffer1 = (char *)malloc(10);
char *buffer2 = (char *)malloc(10);
// buffer1์ 20๋ฐ์ดํธ๋ฅผ ์ฐ๋ฉด buffer2 ์์ญ์ ์นจ๋ฒ!
strcpy(buffer1, "AAAAAAAAAAAAAAAAAAAA");
free(buffer1);
free(buffer2);
return 0;
}
3๏ธโฃ ์ ์ ์ค๋ฒํ๋ก์ฐ (Integer Overflow)
์๋ฐํ ๋งํ๋ฉด ๋ฒํผ ์ค๋ฒํ๋ก์ฐ์๋ ๋ค๋ฅด์ง๋ง, ์ข
์ข
๋ฒํผ ์ค๋ฒํ๋ก์ฐ๋ฅผ ์ ๋ฐํ๋ ์์ธ์ด ๋ผ. ใ
ใ
ใ
์ ์ํ ๋ณ์๊ฐ ํํํ ์ ์๋ ์ต๋๊ฐ์ ๋์ด์๋ฉด ๊ฐ์ด ์ํ(wrap around)๋๋ ํ์์ด์ผ:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void vulnerable(unsigned int size, char *data) {
unsigned int buffer_size = size + 10; // ์ ์ ์ค๋ฒํ๋ก์ฐ ๊ฐ๋ฅ!
char *buffer = (char *)malloc(buffer_size);
if (buffer == NULL) return;
memcpy(buffer, data, size); // ๋ฒํผ ์ค๋ฒํ๋ก์ฐ ๋ฐ์!
free(buffer);
}
int main() {
// size๊ฐ 4294967290 (0xFFFFFFFA)์ด๋ฉด
// size + 10 = 4 (์ค๋ฒํ๋ก์ฐ!)
vulnerable(0xFFFFFFFA, "malicious data");
return 0;
}
์ด ๊ฒฝ์ฐ size + 10์ด ์ค๋ฒํ๋ก์ฐ๋์ด ์์ฃผ ์์ ๊ฐ์ด ๋๊ณ , ์ค์ ๋ก๋ ํจ์ฌ ํฐ ๋ฐ์ดํฐ๋ฅผ ์์ ๋ฒํผ์ ๋ณต์ฌํ๊ฒ ๋๋ ๊ฑฐ์ผ. ์์ ํธ๋ฆญํคํ์ง? ๐ช
4๏ธโฃ ์คํ๋ฐ์ด์ ์ค๋ฅ (Off-by-One Error)
๋ฑ 1๋ฐ์ดํธ๋ง ๋์น๋ ๊ฒฝ์ฐ์ธ๋ฐ, ์ด๊ฒ๋ ์ถฉ๋ถํ ์ํํด. ํนํ ๋ฌธ์์ด ์ฒ๋ฆฌํ ๋ null terminator(\0)๋ฅผ ๊ณ ๋ คํ์ง ์์ผ๋ฉด ์์ฃผ ๋ฐ์ํ์ง:
char buffer[10];
for (int i = 0; i <= 10; i++) { // ์ฃผ๋ชฉ! <= 10
buffer[i] = 'A';
}
// buffer[10]์ ๋ฒ์๋ฅผ ๋ฒ์ด๋จ!
๐ ์ค์ ์ฌ๋ก๋ก ๋ณด๋ ๋ฒํผ ์ค๋ฒํ๋ก์ฐ
๐ฑ Heartbleed (2014)
OpenSSL์ Heartbeat ํ์ฅ ๊ธฐ๋ฅ์์ ๋ฐ๊ฒฌ๋ ๋ฒํผ ์ค๋ฒ๋ฆฌ๋(over-read) ์ทจ์ฝ์ ์ด์ผ. ์๋ฐํ๋ ์ค๋ฒํ๋ก์ฐ๊ฐ ์๋๋ผ ์ค๋ฒ๋ฆฌ๋์ง๋ง, ๋ฉ๋ชจ๋ฆฌ ๊ฒฝ๊ณ๋ฅผ ๋์ด์ ๋ค๋ ์ ์์ ๊ฐ์ ๋งฅ๋ฝ์ด์ง.
๊ณต๊ฒฉ์๊ฐ ์๋ฒ์ ์์ ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด๋ฉด์ "64KB๋ฅผ ๋ณด๋๋ค"๊ณ ๊ฑฐ์ง๋งํ๋ฉด, ์๋ฒ๋ 64KB๋ฅผ ์ฝ์ด์ ๋๋ ค์ค. ๊ทธ ๊ณผ์ ์์ ๋ฉ๋ชจ๋ฆฌ์ ์๋ ๋ฏผ๊ฐํ ์ ๋ณด(๊ฐ์ธํค, ๋น๋ฐ๋ฒํธ ๋ฑ)๊ฐ ์ ์ถ๋๋ ๊ฑฐ์ผ. ๐ฑ
์ ์ธ๊ณ ์น์ฌ์ดํธ์ 17%๊ฐ ์ํฅ์ ๋ฐ์๋ค๋ ํต๊ณ๊ฐ ์์ ์ ๋๋ก ์ฌ๊ฐํ์ด.
๐ฎ PlayStation Portable ํดํน (2005)
PSP์ TIFF ์ด๋ฏธ์ง ํ์ฑ ๋ฃจํด์์ ๋ฒํผ ์ค๋ฒํ๋ก์ฐ๊ฐ ๋ฐ๊ฒฌ๋์ด. ํน์ํ๊ฒ ์กฐ์๋ TIFF ํ์ผ์ PSP์์ ์ด๋ฉด ์์์ ์ฝ๋๋ฅผ ์คํํ ์ ์์์ง.
์ด๊ฑธ ํตํด ํ๋ธ๋ฃจ(homebrew) ์ํํธ์จ์ด๋ฅผ ์คํํ ์ ์๊ฒ ๋๊ณ , ์๋๋ ์ฌ๋ฌ ์ฐจ๋ก ํ์จ์ด ์
๋ฐ์ดํธ๋ก ๋ง์ผ๋ ค ํ์ง๋ง... ํด์ปค๋ค์ด ๊ณ์ ์๋ก์ด ์ทจ์ฝ์ ์ ์ฐพ์๋์ด ใ
ใ
ใ
๐ป Code Red ์ (2001)
Microsoft IIS ์น ์๋ฒ์ ์ธ๋ฑ์ฑ ์๋น์ค์ ์๋ ๋ฒํผ ์ค๋ฒํ๋ก์ฐ ์ทจ์ฝ์ ์ ์
์ฉํ ์์ด์ผ.
๋จ ํ๋ฃจ ๋ง์ 35๋ง ๋ ์ด์์ ์๋ฒ๊ฐ ๊ฐ์ผ๋๊ณ , ๊ฒฝ์ ์ ์์ค์ ์ฝ 26์ต ๋ฌ๋ฌ๋ก ์ถ์ ๋ผ. ๋น์๋ก์๋ ์์ฒญ๋ ๊ท๋ชจ์ ์ฌ์ด๋ฒ ๊ณต๊ฒฉ์ด์์ง. ๐
์ด๋ฐ ๋๊ท๋ชจ ๊ณต๊ฒฉ๋ค์ ๊ณตํต์ ์? ๋ฐ๋ก ์ ๋ ฅ ๊ฒ์ฆ์ ๋ถ์ฌ์ผ. ์ฌ์ฉ์ ์ ๋ ฅ์ ๋ฏฟ์ง ๋ง๊ณ , ํญ์ ๊ฒ์ฆํ๊ณ ์ ํํด์ผ ํด!
๐ก๏ธ ๋ฒํผ ์ค๋ฒํ๋ก์ฐ ๋ฐฉ์ด ๊ธฐ๋ฒ
1๏ธโฃ ์์ ํ ํจ์ ์ฌ์ฉํ๊ธฐ
๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ด๋ฉด์๋ ํจ๊ณผ์ ์ธ ๋ฐฉ๋ฒ์ด์ผ. ์ํํ ํจ์๋ค์ ์์ ํ ๋์ฒด ํจ์๋ก ๋ฐ๊พธ๋ ๊ฑฐ์ง:
| ์ํํ ํจ์ | ์์ ํ ๋์ฒด ํจ์ | ์ค๋ช |
|---|---|---|
| strcpy() | strncpy(), strlcpy() | ๋ณต์ฌํ ์ต๋ ๊ธธ์ด ์ง์ |
| strcat() | strncat(), strlcat() | ์ฐ๊ฒฐํ ์ต๋ ๊ธธ์ด ์ง์ |
| sprintf() | snprintf() | ๋ฒํผ ํฌ๊ธฐ ์ ํ |
| gets() | fgets() | ์ฝ์ ์ต๋ ๊ธธ์ด ์ง์ |
| scanf("%s") | scanf("%10s") | ํ๋ ๋๋น ์ง์ |
์ค์ ์ฝ๋๋ก ๋ณด๋ฉด ์ด๋ ๊ฒ ๋ฐ๋๋ ๊ฑฐ์ผ:
// โ ์ํํ ์ฝ๋
char buffer[10];
strcpy(buffer, user_input);
// โ
์์ ํ ์ฝ๋
char buffer[10];
strncpy(buffer, user_input, sizeof(buffer) - 1);
buffer[sizeof(buffer) - 1] = '\0'; // null terminator ๋ณด์ฅ
2๏ธโฃ ์คํ ์นด๋๋ฆฌ (Stack Canary)
์นด๋๋ฆฌ์ ์๊ฐ ๊ด์ฐ์์ ์ ๋
๊ฐ์ค๋ฅผ ๊ฐ์งํ๋ ๋ฐ ์ฌ์ฉ๋๋ ๊ฒ์ฒ๋ผ, ์คํ ์นด๋๋ฆฌ๋ ๋ฒํผ ์ค๋ฒํ๋ก์ฐ๋ฅผ ๊ฐ์งํ๋ ํน๋ณํ ๊ฐ์ด์ผ. ๐ค
์ปดํ์ผ๋ฌ๊ฐ ํจ์ ํ๋กค๋ก๊ทธ์์ ๋ฆฌํด ์ฃผ์ ์์ ํน๋ณํ ๊ฐ(์นด๋๋ฆฌ)์ ๋ฃ์ด๋๊ณ , ํจ์๊ฐ ๋๋ ๋ ์ด ๊ฐ์ด ๋ณ๊ฒฝ๋๋์ง ์ฒดํฌํด. ๋ง์ฝ ๋ณ๊ฒฝ๋๋ค๋ฉด ๋ฒํผ ์ค๋ฒํ๋ก์ฐ๊ฐ ๋ฐ์ํ ๊ฑฐ๋๊น ํ๋ก๊ทธ๋จ์ ์ข
๋ฃ์ํค๋ ๊ฑฐ์ง.
// GCC์์ ์คํ ์นด๋๋ฆฌ ํ์ฑํ
gcc -fstack-protector-all vulnerable.c -o safe_program
// ๋๋ ์ต์ ๋ฒ์ ์์๋ ๊ธฐ๋ณธ์ผ๋ก ํ์ฑํ๋จ
gcc -fstack-protector-strong vulnerable.c -o safe_program
โข Terminator Canary: NULL, CR, LF, -1 ๋ฑ ๋ฌธ์์ด ์ข ๋ฃ ๋ฌธ์๋ค๋ก ๊ตฌ์ฑ
โข Random Canary: ํ๋ก๊ทธ๋จ ์์ ์ ๋ฌด์์๋ก ์์ฑ๋ ๊ฐ
โข Random XOR Canary: ์ ์ด ๋ฐ์ดํฐ์ XOR ์ฐ์ฐ๋ ๋ฌด์์ ๊ฐ
3๏ธโฃ ASLR (Address Space Layout Randomization)
๋ฉ๋ชจ๋ฆฌ ์ฃผ์๋ฅผ ๋ฌด์์๋ก ๋ฐฐ์นํ๋ ๊ธฐ๋ฒ์ด์ผ. ๊ณต๊ฒฉ์๊ฐ ํน์ ๋ฉ๋ชจ๋ฆฌ ์ฃผ์๋ฅผ ์์ธกํ ์ ์๊ฒ ๋ง๋๋ ๊ฑฐ์ง. ๐ฒ
์คํ, ํ, ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฑ์ ์์น๊ฐ ํ๋ก๊ทธ๋จ ์คํ๋ง๋ค ๋ฐ๋๊ธฐ ๋๋ฌธ์, ๊ณต๊ฒฉ์๊ฐ ์์ฝ๋๋ ROP ๊ฐ์ ฏ์ ์ฃผ์๋ฅผ ์์๋ด๊ธฐ ์ด๋ ค์์ ธ.
# Linux์์ ASLR ์ํ ํ์ธ
cat /proc/sys/kernel/randomize_va_space
# 0 = ๋นํ์ฑํ
# 1 = ์คํ๊ณผ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ง ๋๋คํ
# 2 = ์ ์ฒด ๋๋คํ (๊ถ์ฅ)
# ASLR ํ์ฑํ (์ฌ๋ถํ
ํ์๋ ์ ์ง)
echo 2 | sudo tee /proc/sys/kernel/randomize_va_space
4๏ธโฃ DEP/NX (Data Execution Prevention / No-eXecute)
๋ฉ๋ชจ๋ฆฌ ์์ญ์ ์คํ ๊ฐ๋ฅ(executable)๊ณผ ์ฐ๊ธฐ ๊ฐ๋ฅ(writable)์ผ๋ก ๊ตฌ๋ถํ๋ ๊ธฐ๋ฒ์ด์ผ. ๋ฐ์ดํฐ ์์ญ(์คํ, ํ)์์๋ ์ฝ๋๋ฅผ ์คํํ ์ ์๊ฒ ๋ง๋๋ ๊ฑฐ์ง. ๐ซ
๊ณต๊ฒฉ์๊ฐ ์์ฝ๋๋ฅผ ์คํ์ ์ฃผ์
ํด๋ ์คํํ ์ ์์ผ๋๊น ๊ณต๊ฒฉ์ด ๋ฌด๋ ฅํ๋๋ ์๋ฆฌ์ผ.
// GCC์์ NX ๋นํธ ํ์ฑํ (๊ธฐ๋ณธ๊ฐ)
gcc -z noexecstack vulnerable.c -o protected_program
// Windows์์ DEP ํ์ธ
// ์์
๊ด๋ฆฌ์ โ ์ธ๋ถ ์ ๋ณด โ DEP ์ด ์ถ๊ฐ
5๏ธโฃ ๊ฒฝ๊ณ ๊ฒ์ฌ (Bounds Checking)
๋ชจ๋ ๋ฐฐ์ด ์ ๊ทผ๊ณผ ํฌ์ธํฐ ์ฐ์ฐ์์ ๊ฒฝ๊ณ๋ฅผ ์ฒดํฌํ๋ ๊ฑฐ์ผ. ์ปดํ์ผ๋ฌ๋ ๋ฐํ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์๋์ผ๋ก ํด์ฃผ๊ธฐ๋ ํ๊ณ , ๊ฐ๋ฐ์๊ฐ ์ง์ ์ฝ๋์ ๋ฃ์ ์๋ ์์ด.
// ์๋ ๊ฒฝ๊ณ ๊ฒ์ฌ
void safe_copy(char *dest, size_t dest_size, const char *src) {
size_t src_len = strlen(src);
if (src_len >= dest_size) {
// ์๋ฌ ์ฒ๋ฆฌ
fprintf(stderr, "Error: ๋ฒํผ ํฌ๊ธฐ ์ด๊ณผ!\n");
return;
}
memcpy(dest, src, src_len + 1); // null terminator ํฌํจ
}
// ์ฌ์ฉ ์
char buffer[10];
safe_copy(buffer, sizeof(buffer), user_input);
6๏ธโฃ ์์ ํ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด ์ฌ์ฉ
์์งํ ๋งํ๋ฉด, ๊ฐ์ฅ ํ์คํ ๋ฐฉ๋ฒ์ ๋ฉ๋ชจ๋ฆฌ ์์ ์ฑ์ ๋ณด์ฅํ๋ ์ธ์ด๋ฅผ ์ฐ๋ ๊ฑฐ์ผ. ใ
ใ
ใ
๋ฉ๋ชจ๋ฆฌ ์์ ์ธ์ด๋ค:
โข Rust: ์ปดํ์ผ ํ์์ ๋ฉ๋ชจ๋ฆฌ ์์ ์ฑ ๋ณด์ฅ, ์ฑ๋ฅ๋ C/C++๊ธ
โข Go: ๊ฐ๋น์ง ์ปฌ๋ ์
, ๊ฒฝ๊ณ ๊ฒ์ฌ ์๋ํ
โข Java/C#: ๊ด๋ฆฌ๋๋ ๋ฉ๋ชจ๋ฆฌ, ์๋ ๊ฒฝ๊ณ ๊ฒ์ฌ
โข Python: ๊ณ ์์ค ์ธ์ด, ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ ์๋ํ
๋ฌผ๋ก ๋ ๊ฑฐ์ ์์คํ
์ด๋ ์ฑ๋ฅ์ด ์ค์ํ ์์คํ
์์๋ C/C++์ ๊ณ์ ์จ์ผ ํ๋ ๊ฒฝ์ฐ๋ ๋ง์ง. ๊ทธ๋ด ๋ ์์ ๋ฐฉ์ด ๊ธฐ๋ฒ๋ค์ ์ฒ ์ ํ ์ ์ฉํด์ผ ํด!
๐ง ์ค์ ์ฝ๋ฉ ๊ฐ์ด๋๋ผ์ธ
๐ ์ฒดํฌ๋ฆฌ์คํธ
1. ์ ๋ ฅ ๊ฒ์ฆ
โก ๋ชจ๋ ์ธ๋ถ ์ ๋ ฅ์ ๊ธธ์ด๋ฅผ ๊ฒ์ฆํ๋๊ฐ?
โก ์ ๋ ฅ ๋ฐ์ดํฐ์ ํ์๊ณผ ๋ฒ์๋ฅผ ์ฒดํฌํ๋๊ฐ?
โก ํ์ดํธ๋ฆฌ์คํธ ๋ฐฉ์์ ๊ฒ์ฆ์ ์ฌ์ฉํ๋๊ฐ?
2. ํจ์ ์ฌ์ฉ
โก ์ํํ ํจ์(strcpy, sprintf ๋ฑ)๋ฅผ ์ฌ์ฉํ์ง ์์๋๊ฐ?
โก ์์ ํ ๋์ฒด ํจ์๋ฅผ ์ฌ์ฉํ๋๊ฐ?
โก ๋ฒํผ ํฌ๊ธฐ๋ฅผ ๋ช ์์ ์ผ๋ก ์ง์ ํ๋๊ฐ?
3. ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ
โก ๋์ ํ ๋น ์ ํฌ๊ธฐ๋ฅผ ์ ํํ ๊ณ์ฐํ๋๊ฐ?
โก ์ ์ ์ค๋ฒํ๋ก์ฐ ๊ฐ๋ฅ์ฑ์ ์ฒดํฌํ๋๊ฐ?
โก ๋ฉ๋ชจ๋ฆฌ ํด์ ๋ฅผ ๋น ๋จ๋ฆฌ์ง ์์๋๊ฐ?
4. ์ปดํ์ผ๋ฌ ์ต์
โก ์คํ ๋ณดํธ ์ต์ ์ ํ์ฑํํ๋๊ฐ?
โก ๊ฒฝ๊ณ ๋ฅผ ์๋ฌ๋ก ์ฒ๋ฆฌํ๋๋ก ์ค์ ํ๋๊ฐ?
โก ์ต์ ์ปดํ์ผ๋ฌ๋ฅผ ์ฌ์ฉํ๊ณ ์๋๊ฐ?
๐ป ์ค์ ์์ : ์์ ํ ๋ฌธ์์ด ์ฒ๋ฆฌ
์, ์ด์ ์ค์ ๋ก ์์ ํ ์ฝ๋๋ฅผ ์ด๋ป๊ฒ ์์ฑํ๋์ง ์ข ํฉ์ ์ธ ์์ ๋ฅผ ๋ณด์:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
// ์์ ํ ๋ฌธ์์ด ๋ณต์ฌ ํจ์
int safe_strcpy(char *dest, size_t dest_size, const char *src) {
if (dest == NULL || src == NULL || dest_size == 0) {
return -1; // ์๋ชป๋ ๋งค๊ฐ๋ณ์
}
size_t src_len = strlen(src);
if (src_len >= dest_size) {
return -2; // ๋ฒํผ ํฌ๊ธฐ ๋ถ์กฑ
}
memcpy(dest, src, src_len + 1);
return 0; // ์ฑ๊ณต
}
// ์์ ํ ๋ฌธ์์ด ์ฐ๊ฒฐ ํจ์
int safe_strcat(char *dest, size_t dest_size, const char *src) {
if (dest == NULL || src == NULL || dest_size == 0) {
return -1;
}
size_t dest_len = strlen(dest);
size_t src_len = strlen(src);
// ์ค๋ฒํ๋ก์ฐ ์ฒดํฌ
if (dest_len >= dest_size) {
return -2; // ์ด๋ฏธ ๋ฒํผ๊ฐ ๊ฐ๋ ์ฐธ
}
size_t available = dest_size - dest_len - 1; // null terminator ๊ณต๊ฐ
if (src_len > available) {
return -3; // ๊ณต๊ฐ ๋ถ์กฑ
}
memcpy(dest + dest_len, src, src_len + 1);
return 0;
}
// ์์ ํ ์ ์ ๋ง์
(์ค๋ฒํ๋ก์ฐ ์ฒดํฌ)
int safe_add(size_t a, size_t b, size_t *result) {
if (result == NULL) {
return -1;
}
// SIZE_MAX - a < b ์ด๋ฉด ์ค๋ฒํ๋ก์ฐ
if (SIZE_MAX - a < b) {
return -2; // ์ค๋ฒํ๋ก์ฐ ๋ฐ์
}
*result = a + b;
return 0;
}
// ์์ ํ ๋ฒํผ ํ ๋น ๋ฐ ๋ณต์ฌ
char* safe_buffer_copy(const char *src, size_t max_size) {
if (src == NULL) {
return NULL;
}
size_t src_len = strlen(src);
// ์ต๋ ํฌ๊ธฐ ์ ํ
if (src_len > max_size) {
src_len = max_size;
}
// ์ ์ ์ค๋ฒํ๋ก์ฐ ์ฒดํฌ๋ฅผ ํฌํจํ ํ ๋น
size_t alloc_size;
if (safe_add(src_len, 1, &alloc_size) != 0) {
return NULL; // ์ค๋ฒํ๋ก์ฐ
}
char *buffer = (char *)malloc(alloc_size);
if (buffer == NULL) {
return NULL; // ํ ๋น ์คํจ
}
memcpy(buffer, src, src_len);
buffer[src_len] = '\0';
return buffer;
}
// ์ฌ์ฉ ์์
int main() {
char buffer[32];
const char *user_input = "Hello, World!";
// ์์ ํ ๋ณต์ฌ
if (safe_strcpy(buffer, sizeof(buffer), user_input) == 0) {
printf("๋ณต์ฌ ์ฑ๊ณต: %s\n", buffer);
} else {
fprintf(stderr, "๋ณต์ฌ ์คํจ!\n");
return 1;
}
// ์์ ํ ์ฐ๊ฒฐ
if (safe_strcat(buffer, sizeof(buffer), " Welcome!") == 0) {
printf("์ฐ๊ฒฐ ์ฑ๊ณต: %s\n", buffer);
} else {
fprintf(stderr, "์ฐ๊ฒฐ ์คํจ!\n");
return 1;
}
// ๋์ ํ ๋น
char *dynamic_buffer = safe_buffer_copy(user_input, 1024);
if (dynamic_buffer != NULL) {
printf("๋์ ๋ณต์ฌ ์ฑ๊ณต: %s\n", dynamic_buffer);
free(dynamic_buffer);
} else {
fprintf(stderr, "๋์ ๋ณต์ฌ ์คํจ!\n");
return 1;
}
return 0;
}
์ด ์ฝ๋์ ํต์ฌ ํฌ์ธํธ๋ค์ ์ ๋ฆฌํ๋ฉด:
1. NULL ํฌ์ธํฐ ์ฒดํฌ: ๋ชจ๋ ํฌ์ธํฐ ๋งค๊ฐ๋ณ์๋ฅผ ์ฌ์ฉ ์ ์ ๊ฒ์ฆ
2. ํฌ๊ธฐ ๊ฒ์ฆ: ๋ฒํผ ํฌ๊ธฐ๋ฅผ ํญ์ ํ์ธํ๊ณ ์ด๊ณผํ์ง ์๋๋ก ์ ํ
3. ์ ์ ์ค๋ฒํ๋ก์ฐ ๋ฐฉ์ง: ํฌ๊ธฐ ๊ณ์ฐ ์ ์ค๋ฒํ๋ก์ฐ ๊ฐ๋ฅ์ฑ ์ฒดํฌ
4. ๋ช
์์ ์๋ฌ ์ฒ๋ฆฌ: ๊ฐ ๋จ๊ณ์์ ์๋ฌ ์ฝ๋ ๋ฐํ
5. ์์ ํ ๋ฉ๋ชจ๋ฆฌ ์ฐ์ฐ: memcpy ์ฌ์ฉ ์ ์ ํํ ํฌ๊ธฐ ์ง์
๐ ์ ์ ๋ถ์ ๋๊ตฌ ํ์ฉ
์๋ฌด๋ฆฌ ์กฐ์ฌํด๋ ์ฌ๋์ด ํ๋ ์ผ์ด๋ผ ์ค์ํ ์ ์์ด. ๊ทธ๋์ ์๋ํ๋ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ ์ค์ํด! ๐ค
โข Clang Static Analyzer: ๋ฌด๋ฃ, ์คํ์์ค, C/C++/Objective-C ์ง์
โข Coverity: ์์ฉ, ๋งค์ฐ ๊ฐ๋ ฅํ ๋ถ์ ๋ฅ๋ ฅ
โข PVS-Studio: ์์ฉ, ๋ค์ํ ์ธ์ด ์ง์
โข Cppcheck: ๋ฌด๋ฃ, ์คํ์์ค, C/C++ ์ ์ฉ
โข Flawfinder: ๋ฌด๋ฃ, ๋ณด์ ์ทจ์ฝ์ ์ค์ฌ ๋ถ์
โข SonarQube: ๋ฌด๋ฃ/์์ฉ, ๋ค์ํ ์ธ์ด ์ง์, CI/CD ํตํฉ ์ฉ์ด
# Clang Static Analyzer ์ฌ์ฉ ์
scan-build gcc -o myprogram myprogram.c
# Cppcheck ์ฌ์ฉ ์
cppcheck --enable=all --inconclusive myprogram.c
# Flawfinder ์ฌ์ฉ ์
flawfinder myprogram.c
๐งช ํ ์คํ ๊ณผ ๊ฒ์ฆ
๐ฏ ํผ์ง(Fuzzing)
ํผ์ง์ ํ๋ก๊ทธ๋จ์ ๋ฌด์์ ๋๋ ๋ณํ๋ ์
๋ ฅ์ ๋๋์ผ๋ก ๋ฃ์ด์ ์ทจ์ฝ์ ์ ์ฐพ๋ ๊ธฐ๋ฒ์ด์ผ. ๋ฒํผ ์ค๋ฒํ๋ก์ฐ๋ฅผ ์ฐพ๋ ๋ฐ ์์ฒญ ํจ๊ณผ์ ์ด์ง! ๐ฃ
๋ํ์ ์ธ ํผ์ง ๋๊ตฌ๋ค:
์ปค๋ฒ๋ฆฌ์ง ๊ธฐ๋ฐ ํผ์ ๋ก, ์ฝ๋์ ์๋ก์ด ๊ฒฝ๋ก๋ฅผ ํ์ํ๋ฉด์ ํ ์คํธํด. ์๋ง์ ์ทจ์ฝ์ ์ ๋ฐ๊ฒฌํ ์ ์ค์ ์ธ ๋๊ตฌ์ผ.
๐จ libFuzzer:
LLVM ํ๋ก์ ํธ์ ์ผ๋ถ๋ก, ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํจ์๋ฅผ ์ง์ ํ ์คํธํ ์ ์์ด. ๋น ๋ฅด๊ณ ํจ์จ์ ์ด์ง.
๐จ Honggfuzz:
๊ตฌ๊ธ์์ ๋ง๋ ํผ์ ๋ก, ํ๋์จ์ด ๊ธฐ๋ฐ ํผ๋๋ฐฑ์ ํ์ฉํด. ๋ฉํฐ์ค๋ ๋ ์ง์๋ ๋ผ.
๐จ OSS-Fuzz:
๊ตฌ๊ธ์ ์คํ์์ค ํ๋ก์ ํธ ํผ์ง ์๋น์ค. ๋ฌด๋ฃ๋ก ์ฌ์ฉ ๊ฐ๋ฅํ๊ณ , ์ง์์ ์ผ๋ก ํผ์ง์ ๋๋ ค์ค.
# AFL ์ฌ์ฉ ์์
# 1. AFL๋ก ์ปดํ์ผ
afl-gcc -o target target.c
# 2. ์
๋ ฅ ์ํ ์ค๋น
mkdir input
echo "test" > input/sample.txt
# 3. ํผ์ง ์์
afl-fuzz -i input -o output ./target @@
# libFuzzer ์ฌ์ฉ ์์
# 1. ํผ์ง ํ๊ฒ ์์ฑ
cat > fuzz_target.c << 'EOF'
#include <stdint.h>
#include <stddef.h>
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
// ํ
์คํธํ ํจ์ ํธ์ถ
if (size > 0) {
vulnerable_function((char*)data, size);
}
return 0;
}
EOF
# 2. ์ปดํ์ผ ๋ฐ ์คํ
clang -fsanitize=fuzzer,address fuzz_target.c -o fuzzer
./fuzzer
๐ฌ ๋์ ๋ถ์ ๋๊ตฌ
ํ๋ก๊ทธ๋จ์ ์คํํ๋ฉด์ ๋ฉ๋ชจ๋ฆฌ ์ค๋ฅ๋ฅผ ํ์งํ๋ ๋๊ตฌ๋ค์ด์ผ. ๋ฐํ์์ ์ค์ ๋ก ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ ์๊ฐ์ ์ก์๋ด์ง.
๋ฉ๋ชจ๋ฆฌ ๋์, ๋ฒํผ ์ค๋ฒํ๋ก์ฐ, ์ด๊ธฐํ๋์ง ์์ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ ๋ฑ์ ํ์ง. ์ข ๋๋ฆฌ์ง๋ง ๋งค์ฐ ์ ํํด.
๐ ๏ธ AddressSanitizer (ASan):
๊ตฌ๊ธ์์ ๊ฐ๋ฐํ ๋น ๋ฅธ ๋ฉ๋ชจ๋ฆฌ ์ค๋ฅ ํ์ง๊ธฐ. Valgrind๋ณด๋ค ํจ์ฌ ๋น ๋ฅด๊ณ , ์ค๋ฒํค๋๋ ์ ์ด.
๐ ๏ธ MemorySanitizer (MSan):
์ด๊ธฐํ๋์ง ์์ ๋ฉ๋ชจ๋ฆฌ ์ฝ๊ธฐ๋ฅผ ํ์ง. ASan๊ณผ ํจ๊ป ์ฌ์ฉํ๋ฉด ๊ธ์์ฒจํ!
๐ ๏ธ UndefinedBehaviorSanitizer (UBSan):
์ ์ ์ค๋ฒํ๋ก์ฐ, null ํฌ์ธํฐ ์ญ์ฐธ์กฐ ๋ฑ ์ ์๋์ง ์์ ๋์์ ํ์ง.
# Valgrind ์ฌ์ฉ
valgrind --leak-check=full --show-leak-kinds=all ./myprogram
# AddressSanitizer ์ฌ์ฉ
gcc -fsanitize=address -g myprogram.c -o myprogram
./myprogram
# ์ฌ๋ฌ Sanitizer ๋์ ์ฌ์ฉ
gcc -fsanitize=address,undefined -g myprogram.c -o myprogram
./myprogram
ASan์ ์ฌ์ฉํ๋ฉด ๋ฒํผ ์ค๋ฒํ๋ก์ฐ๊ฐ ๋ฐ์ํ์ ๋ ์ด๋ฐ ์์ผ๋ก ์์ธํ ๋ฆฌํฌํธ๋ฅผ ๋ฐ์ ์ ์์ด:
=================================================================
==12345==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fff1234abcd
WRITE of size 20 at 0x7fff1234abcd thread T0
#0 0x4567890 in vulnerable_function /path/to/file.c:15
#1 0x4567abc in main /path/to/file.c:25
Address 0x7fff1234abcd is located in stack of thread T0 at offset 42 in frame
#0 0x4567def in vulnerable_function /path/to/file.c:10
This frame has 1 object(s):
[32, 42) 'buffer' (line 12) <== Memory access at offset 42 overflows this variable
=================================================================
์์ ์น์ ํ๊ฒ ์ด๋์ ๋ฌธ์ ๊ฐ ์๊ฒผ๋์ง ์๋ ค์ฃผ์ง? ใ ใ ใ
๐ ์น ์ ํ๋ฆฌ์ผ์ด์ ์์์ ๋ฒํผ ์ค๋ฒํ๋ก์ฐ
"์น ์ ํ๋ฆฌ์ผ์ด์
์ PHP, Python, Java ๊ฐ์ ์์ ํ ์ธ์ด๋ก ๋ง๋ค์ด์ง๋๊น ๋ฒํผ ์ค๋ฒํ๋ก์ฐ ๊ฑฑ์ ์๊ฒ ๋ค?" ๋ผ๊ณ ์๊ฐํ ์ ์๋๋ฐ... ์์ ํ ์์ ํ ๊ฑด ์๋์ผ! ๐
์น ์ ํ๋ฆฌ์ผ์ด์
์์๋ ๋ฒํผ ์ค๋ฒํ๋ก์ฐ๊ฐ ๋ฐ์ํ ์ ์๋ ๊ฒฝ์ฐ๋ค:
1๏ธโฃ ๋ค์ดํฐ๋ธ ํ์ฅ ๋ชจ๋
Python์ C ํ์ฅ, PHP์ ๋ค์ดํฐ๋ธ ๋ชจ๋, Java์ JNI ๋ฑ์ C/C++๋ก ์์ฑ๋๊ธฐ ๋๋ฌธ์ ๋ฒํผ ์ค๋ฒํ๋ก์ฐ์ ์ทจ์ฝํ ์ ์์ด.
2๏ธโฃ ์น ์๋ฒ์ ๋ฏธ๋ค์จ์ด
Apache, Nginx, IIS ๊ฐ์ ์น ์๋ฒ๋ ์ ํ๋ฆฌ์ผ์ด์ ์๋ฒ๋ ๋๋ถ๋ถ C/C++๋ก ์์ฑ๋ผ ์์ด. ์ด๋ค์ ์ทจ์ฝ์ ์ ์ง์ ์ ์ธ ์ํฅ์ ๋ฏธ์น์ง.
3๏ธโฃ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋๋ผ์ด๋ฒ
MySQL, PostgreSQL ๋ฑ์ ํด๋ผ์ด์ธํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๋ค์ดํฐ๋ธ ์ฝ๋๋ก ์์ฑ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์.
4๏ธโฃ ์ด๋ฏธ์ง/๋น๋์ค ์ฒ๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
ImageMagick, FFmpeg, GD ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฑ์ ๋ณต์กํ ํ์ผ ํฌ๋งท์ ํ์ฑํ๋ ๊ณผ์ ์์ ๋ฒํผ ์ค๋ฒํ๋ก์ฐ๊ฐ ๋ฐ์ํ ์ ์์ด.
ImageMagick์ ์ฌ๋ฌ ์ทจ์ฝ์ ์ด ๋ฐ๊ฒฌ๋๋๋ฐ, ํน์ํ๊ฒ ์กฐ์๋ ์ด๋ฏธ์ง ํ์ผ์ ์ ๋ก๋ํ๋ฉด ์๊ฒฉ ์ฝ๋ ์คํ์ด ๊ฐ๋ฅํ์ด. ์๋ง์ ์น์ฌ์ดํธ๊ฐ ์ํฅ์ ๋ฐ์์ง.
๐ก๏ธ ์น ์ ํ๋ฆฌ์ผ์ด์ ๋ณด์ ๋์ฑ
์น ํ๊ฒฝ์์ ๋ฒํผ ์ค๋ฒํ๋ก์ฐ๋ฅผ ๋ฐฉ์ดํ๋ ค๋ฉด:
โข ํ์ผ ์ ๋ก๋ ์ ํ์ผ ํ์ , ํฌ๊ธฐ, ๋ด์ฉ ๊ฒ์ฆ
โข ํ์ดํธ๋ฆฌ์คํธ ๊ธฐ๋ฐ ๊ฒ์ฆ ์ฌ์ฉ
โข ํ์ผ ํ์ฅ์๋ง ๋ฏฟ์ง ๋ง๊ณ ๋งค์ง ๋ฐ์ดํธ ํ์ธ
2. ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ ๋ฐ์ดํธ
โข ์ฌ์ฉ ์ค์ธ ๋ชจ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ต์ ๋ฒ์ ์ผ๋ก ์ ์ง
โข ๋ณด์ ํจ์น๊ฐ ๋์ค๋ฉด ์ฆ์ ์ ์ฉ
โข ์์กด์ฑ ๊ด๋ฆฌ ๋๊ตฌ ํ์ฉ (npm audit, pip-audit ๋ฑ)
3. ์๋๋ฐ์ฑ
โข ํ์ผ ์ฒ๋ฆฌ๋ฅผ ๊ฒฉ๋ฆฌ๋ ํ๊ฒฝ์์ ์ํ
โข ์ปจํ ์ด๋๋ VM ํ์ฉ
โข ์ต์ ๊ถํ ์์น ์ ์ฉ
4. WAF (Web Application Firewall)
โข ์ ์์ ์ธ ์์ฒญ ํจํด ์ฐจ๋จ
โข ํ์ผ ์ ๋ก๋ ํฌ๊ธฐ ์ ํ
โข ๋น์ ์์ ์ธ ํค๋๋ ํ์ด๋ก๋ ํํฐ๋ง
# Python์์ ์์ ํ ์ด๋ฏธ์ง ์ฒ๋ฆฌ ์์
from PIL import Image
from io import BytesIO
import magic
def safe_image_upload(file_data, max_size=5*1024*1024): # 5MB ์ ํ
# 1. ํฌ๊ธฐ ๊ฒ์ฆ
if len(file_data) > max_size:
raise ValueError("ํ์ผ์ด ๋๋ฌด ํฝ๋๋ค")
# 2. ๋งค์ง ๋ฐ์ดํธ๋ก ์ค์ ํ์ผ ํ์
ํ์ธ
file_type = magic.from_buffer(file_data, mime=True)
allowed_types = ['image/jpeg', 'image/png', 'image/gif']
if file_type not in allowed_types:
raise ValueError("ํ์ฉ๋์ง ์๋ ํ์ผ ํ์์
๋๋ค")
# 3. PIL๋ก ์ด๋ฏธ์ง ๊ฒ์ฆ (์์๋ ์ด๋ฏธ์ง ๊ฑฐ๋ถ)
try:
img = Image.open(BytesIO(file_data))
img.verify() # ์ด๋ฏธ์ง ๋ฌด๊ฒฐ์ฑ ๊ฒ์ฆ
# ์ฌ๋ก๋ (verify ํ์๋ ์ด๋ฏธ์ง๋ฅผ ๋ค์ ์ด์ด์ผ ํจ)
img = Image.open(BytesIO(file_data))
# 4. ํฌ๊ธฐ ์ ํ
max_dimension = 4096
if img.width > max_dimension or img.height > max_dimension:
raise ValueError("์ด๋ฏธ์ง ํฌ๊ธฐ๊ฐ ๋๋ฌด ํฝ๋๋ค")
return img
except Exception as e:
raise ValueError(f"์ ํจํ์ง ์์ ์ด๋ฏธ์ง: {str(e)}")
# ์ฌ์ฉ ์
try:
with open('uploaded_file.jpg', 'rb') as f:
file_data = f.read()
img = safe_image_upload(file_data)
# ์์ ํ๊ฒ ์ฒ๋ฆฌ...
except ValueError as e:
print(f"์
๋ก๋ ์คํจ: {e}")
๐ ์ฌ๋ฅ๋ท์์ ๋ฐฐ์ฐ๋ ๋ณด์ ๊ฐ๋ฐ
๋ฒํผ ์ค๋ฒํ๋ก์ฐ ๊ฐ์ ๋ณด์ ์ทจ์ฝ์ ์ ์ ๋๋ก ์ดํดํ๊ณ ๋์ํ๋ ค๋ฉด ์ฒด๊ณ์ ์ธ ํ์ต์ด ํ์ํด. ํผ์ ๊ณต๋ถํ๊ธฐ ์ด๋ ต๋ค๋ฉด ์ฌ๋ฅ๋ท์์ ์ ๋ฌธ๊ฐ์๊ฒ ๋ฐฐ์๋ณด๋ ๊ฒ๋ ์ข์ ๋ฐฉ๋ฒ์ด์ผ! ๐ฏ
์ฌ๋ฅ๋ท(https://www.jaenung.net)์ '์ง์์ธ์ ์ฒ'์๋ ์ด๋ฐ ๋ณด์ ๊ด๋ จ ์ง์๋ค์ด ๊ฐ๋ํ๊ณ , ์ค์ ํ์
๊ฐ๋ฐ์๋ค์ด ๋ฉํ ๋ง๋ ํด์ฃผ๊ฑฐ๋ . ํนํ ํ๋ก๊ทธ๋จ ๊ฐ๋ฐ๊ณผ ๋ณด์์ ํจ๊ป ๋ฐฐ์ฐ๊ณ ์ถ๋ค๋ฉด ์์ ์ถ์ฒ! ใ
ใ
ใ
์ฝ๋ ๋ฆฌ๋ทฐ๋ฅผ ๋ฐ๊ฑฐ๋, ์ค์ ํ๋ก์ ํธ์์ ๋ณด์์ ์ด๋ป๊ฒ ์ ์ฉํ๋์ง ๋ฐฐ์ธ ์ ์์ด. ์ด๋ก ๋ง ์๋ ๊ฒ๊ณผ ์ค์ ๋ก ์ ์ฉํ ์ ์๋ ๊ฑด ์์ ๋ค๋ฅด๋๊น ๋ง์ด์ผ.
๋ณด์์ ํ ๋ฒ ๋ฐฐ์ฐ๊ณ ๋์ด ์๋์ผ. ์๋ก์ด ๊ณต๊ฒฉ ๊ธฐ๋ฒ๊ณผ ๋ฐฉ์ด ๊ธฐ์ ์ด ๊ณ์ ๋์ค๋๊น ๊พธ์คํ ์ ๋ฐ์ดํธํด์ผ ํด. ์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์์ ์ต์ ํธ๋ ๋๋ฅผ ๊ณ์ ๋ฐ๋ผ๊ฐ๋ ๊ฒ ์ค์ํ์ง!
๐ ์ต์ ํธ๋ ๋์ ๋ฏธ๋ ์ ๋ง
๐ฎ ๋ฉ๋ชจ๋ฆฌ ์์ ์ธ์ด์ ๋ถ์
์ต๊ทผ ๋ช ๋
๊ฐ ๋ฉ๋ชจ๋ฆฌ ์์ ์ฑ์ ๋ํ ๊ด์ฌ์ด ํญ๋ฐ์ ์ผ๋ก ์ฆ๊ฐํ์ด. ํนํ Rust์ ์ธ๊ธฐ๊ฐ ๊ธ์์นํ๊ณ ์์ง! ๐ฆ
Rust๊ฐ ์ฃผ๋ชฉ๋ฐ๋ ์ด์ :
โข ์ปดํ์ผ ํ์์ ๋ฉ๋ชจ๋ฆฌ ์์ ์ฑ ๋ณด์ฅ
โข C/C++๊ณผ ๋น์ทํ ์ฑ๋ฅ
โข ์์ ๊ถ(Ownership) ์์คํ
์ผ๋ก ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ ์๋ํ
โข ๋ฐ์ดํฐ ๋ ์ด์ค(data race) ๋ฐฉ์ง
์ค์ ๋ก Microsoft, Google, Amazon ๊ฐ์ ๋๊ธฐ์
๋ค์ด ๊ธฐ์กด C/C++ ์ฝ๋๋ฒ ์ด์ค๋ฅผ Rust๋ก ์ฌ์์ฑํ๋ ํ๋ก์ ํธ๋ฅผ ์งํํ๊ณ ์์ด. Linux ์ปค๋์๋ Rust ์ง์์ด ์ถ๊ฐ๋๊ณ !
// Rust์์๋ ์ด๋ฐ ์ฝ๋๊ฐ ์ปดํ์ผ ์๋ฌ!
fn main() {
let mut buffer = vec![0u8; 10];
// ์ปดํ์ผ๋ฌ๊ฐ ๊ฒฝ๊ณ ๊ฒ์ฌ๋ฅผ ๊ฐ์ ํจ
buffer[15] = 42; // โ ์ปดํ์ผ ์๋ฌ ๋๋ ํจ๋!
// ์์ ํ ๋ฐฉ๋ฒ
if let Some(elem) = buffer.get_mut(5) {
*elem = 42; // โ
์์ !
}
}
๐ค AI/ML ๊ธฐ๋ฐ ์ทจ์ฝ์ ํ์ง
๋จธ์ ๋ฌ๋์ ํ์ฉํด์ ์ฝ๋์์ ์ทจ์ฝ์ ์ ์๋์ผ๋ก ์ฐพ๋ ์ฐ๊ตฌ๊ฐ ํ๋ฐํด. ์ ํต์ ์ธ ์ ์ ๋ถ์๋ณด๋ค ๋ ์ ํํ๊ณ ๋น ๋ฅด๊ฒ ๋ฌธ์ ๋ฅผ ์ฐพ์๋ผ ์ ์๋. ๐ง
GitHub Copilot ๊ฐ์ AI ์ฝ๋ฉ ์ด์์คํดํธ๋ค๋ ๋ณด์์ ๊ณ ๋ คํ ์ฝ๋๋ฅผ ์ ์ํ๊ธฐ ์์ํ์ด. ์์ผ๋ก๋ AI๊ฐ ์ค์๊ฐ์ผ๋ก ์ฝ๋๋ฅผ ๋ถ์ํ๊ณ ์ทจ์ฝ์ ์ ๊ฒฝ๊ณ ํด์ฃผ๋ ์๋๊ฐ ์ฌ ๊ฑฐ์ผ.
๐ ํ๋์จ์ด ๊ธฐ๋ฐ ๋ณด์
Intel์ CET(Control-flow Enforcement Technology), ARM์ PAC(Pointer Authentication Code) ๊ฐ์ ํ๋์จ์ด ์์ค์ ๋ณด์ ๊ธฐ๋ฅ๋ค์ด ๋์ค๊ณ ์์ด.
์ด๋ฐ ๊ธฐ์ ๋ค์ CPU ๋ ๋ฒจ์์ ๋ฉ๋ชจ๋ฆฌ ๋ณดํธ๋ฅผ ๊ฐํํด์, ์ํํธ์จ์ด๋ง์ผ๋ก๋ ๋ง๊ธฐ ์ด๋ ค์ด ๊ณต๊ฒฉ๋ค๋ ์ฐจ๋จํ ์ ์์ง. ๐ช
๐ ๊ณต๊ธ๋ง ๋ณด์ (Supply Chain Security)
์์ฆ์ ์คํ์์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์์ฒญ ๋ง์ด ์ฐ์์? ๊ทธ๋ฐ๋ฐ ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค ์ค ํ๋๋ผ๋ ์ทจ์ฝ์ ์ด ์์ผ๋ฉด ๋ด ์ ํ๋ฆฌ์ผ์ด์
๋ ์ํํด์ง๋ ๊ฑฐ์ผ.
๊ทธ๋์ SBOM(Software Bill of Materials), ์์กด์ฑ ์ค์บ๋, ์๋ ์
๋ฐ์ดํธ ๊ฐ์ ๊ณต๊ธ๋ง ๋ณด์์ด ์ค์ํด์ง๊ณ ์์ด. ๐
โข Dependabot: GitHub์ ์๋ ์์กด์ฑ ์ ๋ฐ์ดํธ ๋๊ตฌ
โข Snyk: ์คํ์์ค ์ทจ์ฝ์ ์ค์บ๋
โข OWASP Dependency-Check: ์์กด์ฑ ๋ถ์ ๋๊ตฌ
โข npm audit / pip-audit: ํจํค์ง ๋งค๋์ ๋ด์ฅ ๋ณด์ ๊ฒ์ฌ
โข Trivy: ์ปจํ ์ด๋ ์ด๋ฏธ์ง ์ทจ์ฝ์ ์ค์บ๋
๐ ๋ ๊ณต๋ถํ๊ณ ์ถ๋ค๋ฉด?
๐ ์ถ์ฒ ์๋ฃ
โข "The Art of Software Security Assessment" - ๋ณด์ ์ทจ์ฝ์ ๋ถ์์ ๋ฐ์ด๋ธ
โข "Hacking: The Art of Exploitation" - ์ค์ต ์ค์ฌ์ ํดํน ์ ๋ฌธ์
โข "The Shellcoder's Handbook" - ์ต์คํ๋ก์ ๊ฐ๋ฐ ๊ฐ์ด๋
โข "Secure Coding in C and C++" - ์์ ํ ์ฝ๋ฉ ์ค์ ๊ฐ์ด๋
์จ๋ผ์ธ ๋ฆฌ์์ค:
โข OWASP (https://owasp.org) - ์น ์ ํ๋ฆฌ์ผ์ด์ ๋ณด์ ํ๋ก์ ํธ
โข CWE (https://cwe.mitre.org) - ์ํํธ์จ์ด ์ทจ์ฝ์ ๋ถ๋ฅ
โข CVE (https://cve.mitre.org) - ๊ณต๊ฐ๋ ์ทจ์ฝ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค
โข Exploit Database (https://www.exploit-db.com) - ์ต์คํ๋ก์ ์์นด์ด๋ธ
์ค์ต ํ๋ซํผ:
โข Pwnable.kr - ์์คํ ํดํน ์๊ฒ์
โข HackTheBox - ์ค์ ํดํน ์ฐ์ต
โข OverTheWire - ๋จ๊ณ๋ณ ๋ณด์ ์ฑ๋ฆฐ์ง
โข Microcorruption - ์๋ฒ ๋๋ ์์คํ ํดํน
๐ฏ ํ์ต ๋ก๋๋งต
๋ฒํผ ์ค๋ฒํ๋ก์ฐ๋ฅผ ์ ๋๋ก ์ดํดํ๊ณ ์ถ๋ค๋ฉด ์ด๋ฐ ์์๋ก ๊ณต๋ถํ๋ ๊ฑธ ์ถ์ฒํด:
๐ฌ ๋ง๋ฌด๋ฆฌํ๋ฉฐ
์, ์ฌ๊ธฐ๊น์ง ๋ฒํผ ์ค๋ฒํ๋ก์ฐ์ ๋ํด ์์ฒญ ๊น๊ฒ ํ๋ดค์ด! ๐
์์งํ ์ฒ์์๋ "์ด๊ฒ ๋ญ ์๋ฆฌ์ผ?" ์ถ์ ์๋ ์๋๋ฐ, ํ๋์ฉ ์ฐจ๊ทผ์ฐจ๊ทผ ๋ฐ๋ผ๊ฐ๋ค ๋ณด๋ฉด ๋ถ๋ช
ํ ์ดํดํ ์ ์์ด. ์ค์ํ ๊ฑด ํฌ๊ธฐํ์ง ์๊ณ ๊ณ์ ์ค์ตํ๋ ๊ฑฐ์ผ!
๋ฒํผ ์ค๋ฒํ๋ก์ฐ๋ ์ค๋๋ ์ทจ์ฝ์ ์ด์ง๋ง, ์ฌ์ ํ ํ์ญ์ด๊ณ ์์ผ๋ก๋ ๋น๋ถ๊ฐ์ ๊ณ์ ๋ฌธ์ ๊ฐ ๋ ๊ฑฐ์ผ. ํนํ IoT, ์๋ฒ ๋๋ ์์คํ
, ๋ ๊ฑฐ์ ์ฝ๋์์๋ ๋๋์ฑ ๊ทธ๋ ์ง.
ํ์ง๋ง ์ด์ ๋๋ ์ด ์ทจ์ฝ์ ์ด ๋ญ์ง, ์ด๋ป๊ฒ ๋ฐ์ํ๋์ง, ์ด๋ป๊ฒ ๋ง์ ์ ์๋์ง ์๊ฒ ๋์์? ์ด ์ง์์ ๋ฐํ์ผ๋ก ๋ ์์ ํ ์ฝ๋๋ฅผ ์์ฑํ ์ ์์ ๊ฑฐ์ผ! ๐ช
1. ๋ฒํผ ์ค๋ฒํ๋ก์ฐ๋?
๋ฉ๋ชจ๋ฆฌ ๋ฒํผ์ ๊ฒฝ๊ณ๋ฅผ ๋์ด์ ๋ฐ์ดํฐ๋ฅผ ์ฐ๋ ๊ฒ. ํ๋ก๊ทธ๋จ ์ ์ด ํ๋ฆ์ ์กฐ์ํ ์ ์์ด ๋งค์ฐ ์ํํจ.
2. ์ฃผ์ ์์ธ:
โข ์ ๋ ฅ ๊ฒ์ฆ ๋ถ์ฌ
โข ์ํํ ํจ์ ์ฌ์ฉ (strcpy, sprintf ๋ฑ)
โข ๊ฒฝ๊ณ ๊ฒ์ฌ ๋๋ฝ
โข ์ ์ ์ค๋ฒํ๋ก์ฐ
3. ๋ฐฉ์ด ๊ธฐ๋ฒ:
โข ์์ ํ ํจ์ ์ฌ์ฉ
โข ์คํ ์นด๋๋ฆฌ, ASLR, DEP
โข ์ ์ /๋์ ๋ถ์ ๋๊ตฌ ํ์ฉ
โข ํผ์ง ํ ์คํธ
โข ๋ฉ๋ชจ๋ฆฌ ์์ ์ธ์ด ์ฌ์ฉ
4. ๊ฐ๋ฐ์์ ์์ธ:
โข ์ฌ์ฉ์ ์ ๋ ฅ์ ์ ๋ ๋ฏฟ์ง ๋ง ๊ฒ
โข ํญ์ ๊ฒฝ๊ณ๋ฅผ ์ฒดํฌํ ๊ฒ
โข ์ต์ ๋ณด์ ํจ์น ์ ์ฉ
โข ์ง์์ ์ธ ํ์ต๊ณผ ์ ๋ฐ์ดํธ
๋ณด์์ ํ ๋ฒ ์ค์ ํ๊ณ ๋๋๋ ๊ฒ ์๋๋ผ ์ง์์ ์ธ ๊ณผ์ ์ด์ผ. ์๋ก์ด ๊ณต๊ฒฉ ๊ธฐ๋ฒ์ด ๋์ค๋ฉด ์๋ก์ด ๋ฐฉ์ด ๊ธฐ๋ฒ๋ ๋์ค๊ณ , ์ด ์ฌ์ดํด์ ๊ณ์ ๋ฐ๋ณต๋์ง.
๊ทธ๋ฌ๋๊น ํญ์ ์ต์ ํธ๋ ๋๋ฅผ ๋ฐ๋ผ๊ฐ๊ณ , ์ปค๋ฎค๋ํฐ์ ์ํตํ๋ฉด์ ๋ฐฐ์์ผ ํด. ์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์์ ๋ค๋ฅธ ๊ฐ๋ฐ์๋ค๊ณผ ์ง์์ ๊ณต์ ํ๋ ๊ฒ๋ ์ ๋ง ์ข์ ๋ฐฉ๋ฒ์ด์ผ! ๐
๋ง์ง๋ง์ผ๋ก, ๋ณด์ ๊ณต๋ถ๋ ์ด๋ ต์ง๋ง ์์ฒญ ์ฌ๋ฏธ์์ด. ํผ์ฆ์ ํธ๋ ๊ฒ ๊ฐ์ ๋๋์ด๋๊น? ใ
ใ
ใ
ํ ๋ฒ ๋ง์ ๋ค์ด๋ฉด ํค์ด๋์ฌ ์ ์์ ๊ฑฐ์ผ. ๐
์, ์ด์ ๋๋ ๋ฒํผ ์ค๋ฒํ๋ก์ฐ ์ ๋ฌธ๊ฐ์ ๊ธธ๋ก ํ ๊ฑธ์ ๋์๊ฐ์ด! ํ์ดํ
! ๐
๋ณด์ ์ฐ๊ตฌ๋ ํญ์ ํฉ๋ฒ์ ์ธ ๋ฒ์ ๋ด์์ ํด์ผ ํด. ์์ ์ ์์คํ ์ด๋ ๋ช ์์ ์ผ๋ก ํ๊ฐ๋ฐ์ ์์คํ ์์๋ง ํ ์คํธํ๊ณ , ์ ๋๋ก ๋ค๋ฅธ ์ฌ๋์ ์์คํ ์ ๋ฌด๋จ์ผ๋ก ๊ณต๊ฒฉํ๋ฉด ์ ๋ผ. ์ค๋ฆฌ์ ํดํน(Ethical Hacking)์ ์์น์ ์งํค์! ๐ค
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.