
SQL Injection
웹사이트에서 사용자가 로그인 폼을 채워 로그인 요청을 보낼 때 입력한 내용이 맞는지 확인하는 코드(PHP)를 예시로 들어보자.
$username = $_GET['username'];
$password = $_GET['password'];
$conn = new mysqli("localhost", "root", "", "users_db");
$sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
$result = $conn -> query($sql);
사용자가 입력한 내용: username: student, password: 1234
$sql = "SELECT * FROM users WHERE username = 'student' AND password = '1234'";
이런 식으로 사용자가 입력한 아이디와 비밀번호를 확인하는 절차를 갖는다. 즉, 사용자가 입력한 내용으로 SQL문을 완성시켜서 입력한 username과 password가 일치하는 사용자가 DB에 있는지 확인한다. 위의 입력은 개발자가 예상한 개발자의 의도대로 사용자들이 입력을 해주었을 때의 예시이다. 그러나 악의적으로 또는 의도한 바와 다르게 입력을 하는 경우라면?
사용자가 입력한 내용: username: ' OR 1=1" --, password: 1234 (random)
$sql = "SELECT * FROM users WHERE username = ' OR 1=1" --' AND password = '1234'";
만약 username: ' OR 1=1" -- 이라면 위의 SQL문의 의미가 달라진다. username의 입력에 "이 있어서 SQL문이 닫히고 입력의 -- 때문에 그 뒤의 내용은 주석 처리가 된다. 그리고 SQL문을 다시 보면 "username이 ' 이거나 1=1(true)인 user를 DB에서 찾아라" 다시 말해 언제나 만족하는 조건 때문에 "users라는 테이블에서 모든 정보를 불러와라"라는 의미가 되어버린다. 보통은 개발자가 의도한대로 유저네임에 자기 아이디를 입력할텐데, 그 입력 안에 SQL문의 일부를 넣으면 모든 고객 정보를 불러와서 보여지게 되는 상황이 발생할 수 있게 된 것이다.
이렇듯, SQL문의 일부를 입력으로 넣는 방식을 SQL Injection이라고 한다.
SQL Injection은 실제로 아직까지도 보안 공격 TOP 10에 들어가있을 만큼 많이 발생하는 공격이다.
SQL Injection을 막기 위해서 Input Validation을 한다.
function sanitizeInput($input) {
return preg_replace("/[\'\";#]/","", $input); // remove special characters
}
$username = $_GET['username'];
$password = $_GET['password'];
$conn = new mysqli("localhost", "root", "", "users_db");
$sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
$result = $conn -> query($sql);
들어오는 입력을 한 번 검증하는 단계를 추가하여 SQL Injection을 막는다. 위의 코드처럼 sanitizeInput이라는 함수를 이용하여 특수문자를 없애고 난 뒤 SQL문에 입력을 넣는 방식으로 실행된다.
Race Condition
Race Condition은 thread가 여러 개일 때 즉 multi-threading system일 때 공유 자원을 두고 경쟁하는 상태를 의미한다. 공유 자원에 접근하는 코드의 영역을 임계 구역 critical section이라 하고, 공유 자원은 여러 thread/process가 동시에 접근하면 안된다. 다시 말해, 여러 thread/process가 critical section에 동시에 접근하려고 서로 경쟁하는 상태를 의미한다.
Race condition을 막기 위해서는 Lock 또는 Mutex lock이나 Semaphore를 사용하여 막을 수 있다. 그리고 lock을 이용해서 atomic하게 실행되어야 하는 부분을 atomic하게 실행함으로써 race condition을 막을 수 있다. 아래 코드를 예시로 설명하면, 공유 자원인 `balance`를 접근하려 하는 if 조건문 부터 print까지는 critical section이고, critical section은 atomic하게 수행되어야 한다. 그렇지 않고 lock도 걸려있지 않다면, 그 사이에 context switching이 발생하여 공유 자원 동기화가 이루어지지 않는 문제가 발생할 수 있기 때문이다.
balance = 100
lock - Threading.Lock()
def withdraw(amount):
global balance
with lock:
if balance >= amount:
balance -= amount
print(f"Withdraw {amount}, New Balance: {balance}")
Buffer Overflow

Buffer Overflow는 변수에게 할당된 메모리를 넘어서 읽거나 쓰는 것을 말한다.
그냥 변수의 값만 덮어 쓰는 거면 크게 문제가 될까? 왜 위험한 공격이라고 말하는 것일까?
컴퓨터에서 프로그램을 실행시키면 자동으로 각각의 프로그램에 대해서 Process Memeory Map이 만들어진다. Process Memory Map은 개별적인 프로그램마다 메모리를 관리하기 위해서 사용되는 구조체이다.
실제로 프로그램이 작동하는 명령어나 코드들은 Code 세그먼트에 들어가고 BSS와 Data 세그먼트에는 static variables 또는 global variables과 같이 사이즈가 프로그램 전체에 걸쳐서 일정한 변수들이 들어간다.
Heap에는 동적으로 할당(malloc, new)되는 변수들을 보관해주는 기능을 한다.
Stack은 함수와 함수 사이에 호출이 일어날 때 함수가 호출될 때마다 Activation record를 생성한다. 함수가 호출되면서 넘어오는 파라미터들이나 함수가 끝나고 어디로 돌아가야 하는지에 대한 내용이나 함수 내에서 사용되는 지역 변수들에 대한 내용이 스택 공간 안에 있는 Activation record라는 형태로 들어가게 된다.

int foo(int x) {
char buf[10];
strcpy(buf, ...);
return x + 12;
}
int main() {
int ret = foo(10);
...
return 0;
}
위의 코드와 같은 프로그램이 있다고 가정해보자. main 함수에서 foo 함수를 호출하는데, 이 때 Activation record가 만들어지게 된다. 그 Activation record 안에는 foo 함수가 끝나면 어디로 돌아와야하는지, 어디로 돌아와서 프로그램이 재개가 되야 하는지에 대한 return address가 있다. 그리고 foo라는 함수가 호출될 때 어떤 파라미터들이 넘어오는지에 대한 내용을 담고 있다.

만약 foo 함수안의 strcpy 함수에서 buffer overflow가 발생해서 return address까지 overwrite하는 상황이 생기면 foo 함수가 어디로 돌아갈지에 대한 내용이 바뀌게 되는 것이다. 즉, foo 함수 실행이 끝이 나면 이후에 실행될 코드가 달라지게 된다. 만약 공격자가 return address에 악성코드가 실행되도록 주소를 넣는다면? 개인정보를 유출한다던지 랜섬웨엉와 같은 기능들을 섞어 둔 코드가 실행되도록 한다면? 이렇듯 Buffer Overflow는 프로그램이 진행되어야 하는 흐름 즉 execution flow 자체를 바꿀 수 있기 때문에 위험한 공격이라고 말하는 것이다.
이러한 방식을 Remote Code Execution 원격 코드 실행이라고 하는데, Buffer Overflow를 통해서 실행 경로를 변경시킴으로써 악성 코드가 실행되도록 하는 형태를 의미한다.
Buffer Overflow를 막는 방법으로는 몇 바이트만큼 copy를 할거라는 추가적인 변수를 받는 방법도 있고 Canary 방법도 있다.
Activation record에서 SFP는 고정적인 크기를 가지고 있다. 그래서 변수들의 구조만 알고 있으면 정확하게 몇 byte에 대해서 overflow를 일으키면 return address를 overwrite할 수 있는지 공격자들이 알 수 있다. 공격자들이 return address를 덮어 쓸 길이를 정확하게 추적하지 못하도록 하면 buffer overflow를 막을 수 있다. Local variable과 SFP 사이에 Canary라는 랜덤한 길이의 실제로 의미없는 쓰레기값들을 넣어서 Activation record마다 길이를 다르게 해서 공격자가 buffer overflow를 일으키기 위해 어느 정도의 string을 넣어야 return address를 건드릴 수 있는지를 짐작하지 못하도록 막는다. 이 방법을 Canary 방법이라고 한다.
아래 글 중 WannaCry 공격이 Buffer Overflow를 악용한 공격 중 하나:
[보안] Malware란? Worm, Ransomware, Rootkit 그리고 Botnet / WannaCry(2017)과 PumaKit(2024)
😈 Malware란?Malware란 malicious software의 약자로, 컴퓨터나 서버 또는 네트워크 등에 의도적으로 damage를 입히기 위해 만들어진 소프트웨어이다. 그냥 악성코드인 것. Malware가 사용되는 목적To steal sen
oiblog.tistory.com
아래 글 중 Static Program Analysis 내 strcpy 예시에 Buffer Overflow를 방지하기 위한 경고:
[보안] Program Analysis: 정적 프로그램 분석 방법과 동적 프로그램 분석 방법 그리고 역공학 Reversing
*아래 내용은 보안에서의 Program Analysis를 다루고 있습니다. Program Analysis프로그램 분석은 code, structure, 소프트웨어의 행동을 조사하고 잠재적인 security threat를 식별하고 bug를 수정하며 security를 향
oiblog.tistory.com
'자기개발 > 탐구' 카테고리의 다른 글
| [탐구] Pose Agent: 자세 판단을 위한 분석 방법 (0) | 2026.05.30 |
|---|---|
| [탐구] Hash Table과 Hashing (0) | 2026.04.26 |
| [보안] Program Analysis: 정적 프로그램 분석 방법과 동적 프로그램 분석 방법 그리고 역공학 Reversing (0) | 2026.04.26 |
| [보안] Obfuscation, Packing, and Dynamic Loading (0) | 2026.04.25 |
| [혼공컴운] Chapter 13. 교착상태 Deadlock (1) | 2026.04.24 |