Today I Learned …

[해킹] Blind SQL Injection 본문

Study/해킹

[해킹] Blind SQL Injection

염베리 2021. 11. 8. 23:02

* 개인적인 공부 내용을 기록한 글입니다.


사담

그새 좀 해이해진 것 같아서...

뭐라도 해보자는 심산으로 물고 늘어져 본다.


Blind SQL Injection이란?

1. 에러가 출력되지 않고

2. 참 거짓은 판별할 수 있는 사이트에서

3. 조건을 일일이 넣어

4. DB 이름, 테이블 이름, 컬럼 이름, 결국 데이터 추출까지

5. 실현 가능하게 하는 최후의 보루

 

 

Blind SQL Injection을 위한 기법

1. LIMIT

2. substring

3. ASCII

4. 2진 탐색 알고리즘

 

1. LIMIT

게시글 페이징 기능 구현에서

"SELECT ~ LIMIT $start, $per" 를 사용하여 원하는 게시글을 뽑아냈듯

LIMIT를 사용하면 시작 위치와 개수를 지정하여 원하는 행의 데이터를 뽑아낼 수 있다.

Blind SQLi에서 주로 쓰게 되는 LIMIT의 형태는

"LIMIT 0, 1" "LIMIT 1, 1" "LIMIT 2, 1" 과 같은 것인데

이를 사용하면 해당 테이블의 행을 한 줄씩 뽑아낼 수 있게 된다.

주의할 점은 시작 인덱스가 0이라는 점이다.

⇒ LIMIT [시작위치:0으로시작] [개수]

 

2. substring

Blind SQLi의 목표는 미지의 DB명, 테이블명 또는 컬럼명 등을

한 글자 씩 뽑아내서 ASCII 코드의 번호와 대조하여 해당 글자의 정체(?)를 알아내는 것이다.

이렇게 하는 이유는 DB명, 테이블명, 컬럼명 등을 알아서 뱉어주지 않기 때문이다.

이를 위해서는 문자열을 한 자 한 자 잘라와야하는데, 이 것을 가능하게 하는 것이 substring이다.

어찌보면 사용성 측면에서는 LIMIT과 유사하지만, 주의해야하는 부분은 LIMIT과 달리 시작 인덱스가 1이라는 점이다.

⇒ substring [시작위치:1로시작] [개수]

 

3. ASCII 코드

아스키 코드란... 결국 특수문자와 알파벳 등을 숫자로 표기한 것이다.

아스키 코드가 없었다면 아마 모든 문자를 일일이 등호로 대조해야했을 것이다.

다시 말해 만약 해당 문자가 z라면,

알파벳 대소문자 A~Z a~z까지 모두 대조한 끝에 해당 문자의 정체를 알 수 있었을 것이다.

하지만 아스키 코드는 문자를 숫자로 치환하여 대소 비교를 통한 범위 축소를 가능하게 한다.

예를 들어 z의 정체를 알기 위해서는

먼저 중간 근사값인 60 정도로 ascii('z')와 대소를 비교한 뒤,

60보다 크면 90과 비교하고, 더 크면 100과 비교하고, 110, 120과 비교해나가는 식으로 범위를 확확 좁혀나갈 수 있다.

⇒ 키보드 특수키를 제외한 아스키 코드는 33~126 사이에 있기 때문에 이 숫자들을 pool로 삼아 대소 비교를 진행하면 된다.

 

4. 2진 탐색 알고리즘

업다운 게임을 생각하면 된다.

예를 들어, 1부터 100 사이의 임의의 랜덤한 숫자를 맞추는 게임이 있다고 생각해보자.

합리적인 플레이어라면 먼저 50을 고른 뒤,

업이라는 결과가 나온다면 75를 고르고,

다운이라는 결과가 나온다면 50과 75의 중간값인 62를 고르는 식으로 범위를 점차 좁혀나갈 것이다.

이 플레이어가 채택하고 있는 것이 바로 2진 탐색 알고리즘이다.

1부터 100까지 모든 숫자를 일일이 대조하지 않고, 중간값을 선택해 업다운 결과를 얻음으로써 훨씬 더 효율적으로 정답에 접근해갈 수 있다.

사실 바로 위에서 아스키에 대해 이야기할 때 이미 다룬 부분이다.

 

 

Blind SQLi의 절차

1. Blind SQLi가 먹힐 것 같은지 (= 취약점이 있는지) 확인

2. Blind SQLi 참/거짓 테스트

3. Blind SQLi 임의의 SELECT문 테스트

4. DB명 추출

5. 테이블명 추출

6. 컬럼명 추출

7. 데이터 추출

 

1. Blind SQLi가 먹힐 것 같은지 (= SQLi 취약점이 있는지) 확인

변수 바인딩이나 필터링이 적용되어있는지 확인하는 과정이다.

변수 바인딩은 뚫을 방법이 없고, 필터링의 경우 우회할 수 있는 경우가 있다.

아이디 폼에

choco를 입력했을 때와

choco' and '1'='1 입력했을 때

아무런 차이 없이 인증에 성공한다면

취약점이 존재한다고 볼 수 있다. (바인딩이나 필터링이 되어있다면 후자의 경우 로그인에 실패해야한다.)

 

2. Blind SQLi 참/거짓 테스트

choco' and '1'='1 가 가능하다면

choco' and ('1'='1') and '1'='1 도 가능할 것이다.

그렇다면

choco' and ('1'='2') and '1'='1 는 어떤지 확인해보자.

이처럼 삽입한 쿼리문이 참일 때와 거짓일 때 서버의 응답이 어떻게 다른지 확인한다.

로그인의 경우, 당연한 말이지만 로그인 성공과 로그인 실패로 나뉠 것이다.

일부러 중간에 괄호를 붙인 조건을 하나 더 추가하여 참/거짓 쿼리문을 삽입하는 이유는 앞으로의 과정에서 헷갈림을 방지하고 보다 간편하게 조건을 바꾸어가며 대입하기 위한 것이다.

 

3. Blind SQLi 임의의 SELECT문 테스트

이제 임의의 SELECT문을 삽입해본다.

SELECT문을 만들 때는 한 번에 쫙 쓰려고 하지 말고 차곡차곡 스택을 쌓듯 진행해야한다.

무조건 헷갈릴 수 밖에 없기 때문에 무의미한 시간 낭비를 방지하기 위함이다.

순서는 다음과 같다.

 

(미완. 집에가서 계속)

프로필사진
berry
FE Developer, loves React & better DX
Comments