Blind based SQL Injection

Blind based SQL Injection의 간단한 기본개념

  • 기본원리는 참과 거짓의 개념이다
  • 예전에 어디 가서 놀이를 할 때 스무고개라는 게임을 다 아는지 모르겠는데 그 게임과 메커니즘이 동일하다.
  • 질문자는 질문을 할수있는 횟수를 정해놓고 질문을 한다.
  • 그럼 대답자는 오로지 예 아니요라고만 대답할 수 있는데 그 대답을 유추해서 질문자는 정답을 맞히는 게임이다.
  • 여기서 Blind based SQL Injection는 스무고개랑 동일한 게임이다
  • 다만 질문 횟수는 무제한일 뿐… 예 아니오로 대답이 돌아오는 것은 마찬가지이다.
  • 예를 들어 ID 가 normaltic라고 할 때 첫 글자가 a 맞나요? → 아니요 , 이런 메커니즘이다.

Blind based SQL Injection Process

1. SQLI 포인트 찾기

  • 먼저 참과 거짓 구문이 적용되는지부터 살펴본다
  • 예를 들어
    • normaltic' and '1'='1 → 존재하는 아이디
    • normaltic' and '1'='2 → 존재하지 않는 아이디
  • 이렇게 적용이 가능하다면 SQLI 취약점이 있는 것이다.

2. select 문구가 사용가능한지 체크

  • 참 거짓 구분 구문에서 and를 하나 더 넣어준다.
  • 하나 더 넣는 이유는 나중에 자동화할 때 헷갈리지 않게 하기 위함이다.
  • normaltic' and ( 여기에 조건을 넣는다 ) and '1'='1
    • 예를 들어 (select 'test')='test’를 넣어서 select가 사용가능한지 체크한다
    • normaltic' and ( (select 'test')='test’ ) and '1'='1 → 에러가 나지 않는다면 사용가능하다.

3. 공격 format 만들기

  • 여기 부분이 아주 중요하고 헷갈리기 쉽기 때문에 잘 따라와야 한다.
  • 아까 만든 구문을 그대로 가져와준다
    • normaltic' and ( 여기에 조건을 넣는다 ) and '1'='1
  • 여기서 select는 가능하므로 이제 우리가 원하는 질의를 넣으면 된다.
  • 이때 중요한 것이 Blind SQLI로 알 수 있는 건 참 거짓 밖에 알 수 없다. 그래서 유추를 해야 하는데 그때 필요한 함수가 바로 substr 함수이다.
  • substr 함수
    • 기본적인 함수의 형태는 다음과 같다
    • substr('test' , 1 , 1)
      • 첫 번째 인자값 = 물어보고 싶은 것
      • 두 번째 인자값 = ~ 번째부터 라는 뜻이다 예시를 보면 1번째부터 라는뜻
      • 세 번째 인자값 = ~ 번째까지 라는 뜻이다 예시를 보면 1번째까지 라는뜻
      • 정리하자면 1,1 은 1번째 1번째까지 라는 뜻이므로 test에서 t를 나타낸다.
      • 응용하면 2,1 은 2번째부터 1번째까지 즉 test에서 두 번째 글자인 s를 나타낸다.
      • 하나만 더해보면 2,2는 2번째부터 2번째 까지 라는 뜻이므로 test에서 두 번째인 e부터 그 이후 2번째라는 뜻이므로 es라는 문자가 출력된다.
      • 그럼 여기서 우리는 첫 번째 인자값이 물어보고 싶은 것 이기 때문에 test를 빼고 sql 질의문을 입력하면 된다.
      • substr( ( sql 질의문) , 1 , 1)으로 만들어주면 된다.
  • 여기서 이제 우리는 새로운 게임을 배워보자
  • 바로 숫자 확률 게임으로 범위를 줄이는 것이다. 이건 up and down 게임과 동일하다.
  • 내가 질문을 할 때 질문 횟수는 정해져 있는데 a~z 또는 A~Z까지 일일이 물어볼 수는 없을 것이다.
  • 물론 Blind SQLI는 횟수는 무제한이지만 일일이 쳐봐야 한다면 그만한 노동도 없을 것이다.
  • 그래서 우리는 일일이 물어보는 수고로움을 덜어주기 위해 up and down 게임으로 문자를 유추할 것이다.
  • 하지만 문자를 가지고 up and down 게임을 할 수 있을까? → 불가능하지는 않지만 번거로움도 많고 헷갈릴 위험이 있다…
  • 그래서 이 문자를 표현하기 쉽게 숫자로 만들어 볼 건데 문자를 숫자로 변환하는 방법은 ascii 코드가 있다.

ascii 코드표

  • 이 코드표를 보면 특수기호까지 모두 포함하였을 때 33번부터 126번까지이다.
  • ascii 함수는 다음과 같다.
    • ascii('a')라고 입력하면 위의 표를 참고하여 97이 나올 것이다.
    • 그럼 내가 a라는 문자를 숫자로 찾고 싶을 때는 ascii(’a’) = 97이라고 입력하면 이 문장은 참이 된다.
    • 이러한 메커니즘을 통하여 ascii( sql 질의 ) > 0이라고 구문을 만들면 내가 질의하고 싶은 쿼리를 넣게 된다면 그 구문의 뜻하는 문자가 0 보다 크다면 참이 나올 것이고 그렇지 않다면 거짓이 나올 것이다.
  • 위에서 만든 substr 함수를 sql 질의 표시된 곳에 넣으면 된다.
    • ascii(substr(( sql 질의문),1,1)) > 0
  • 위의 쿼리를 이제 맨 처음 만들어 놓았던 normaltic' and ( 여기에 조건을 넣는다 ) and '1'='1 여기에 괄호 속에 대입하면 된다
  • 최종 공격 format
    • normaltic' and (ascii(substr(( SQL 질의문 넣는 곳 ),1,1)) > 0) and '1'='1

4. 바이너리 서치

  • 이제 우리가 원하는 단어를 찾기만 하면 된다.
  • 예를 들어 normaltic이라는 단어를 찾도록해보자
    • select 'normaltic’
  • 우리가 만들어 놓은 공격 format에 sql 질의문 넣는 곳에 넣으면 된다.
  • normaltic' and (ascii(substr((select 'normaltic’ ),1,1)) > 0) and '1'='1
    • 이때 n이라는 단어의 숫자를 뭔지 모른다고 치자
    • 이럴 때 우리는 33 ~ 126의 중간값으로 찾을 것이다
    • 그럼 공격 format 은 다음과 같다.
    • normaltic' and (ascii(substr((select 'normaltic'),1,1)) > 70) and '1'='1
    • 이런 식으로 찾다가 보면 다음과 같이 답을 알 수 있다.
    • 아스키코드에서 n은 110이다. 이랬을 때 우리는 저 정보를 모르는 상태에서 단어를 찾다 보면 109는 존재하는 아이디라고 하는데 110으로 하였을 때는 존재하지 않는 아이디라고 나올 것이다.
    • 이 말인즉슨 110보다는 작고 109보다는 크다라는 것인데 이 숫자는 바로 110일 것이다
    • 헷갈린다면 110을 넣고 > 기호가 아닌 = 기호를 넣어보면 존재하는 아이디 즉, 참인 결과가 나올 것이다
  • 이런 식으로 우리는 모든 정보를 추출 가능하다.

5. DB 이름 추출

  • 이제 DB이름부터 차근차근히 데이터를 추출해 보자
  • DB이름 추출하는 쿼리문은 다음과 같다
    • select database()
  • 이 쿼리문을 우리가 만들어 놓은 공격 format에 대입하면 된다
    • normaltic' and (ascii(substr((select database()),1,1)) > 0) and '1'='1
    • 넣는 곳에 쿼리를 넣자.
    • normaltic' and (ascii(substr((select database()),1,1)) > 0) and '1'='1
  • 바이너리 서치를 하면서 한 글자씩 찾으면 된다.

6. 테이블 이름 추출

  • 다음으론 테이블 이름을 추출하자
  • 테이블 이름을 추출하는 쿼리문은 다음과 같다.
    • select table_name from information_schema.tables where table_schema = 'DB이름' limit 1
  • 이 쿼리문을 공격 format에 대입하면 다음과 같다
    • normaltic' and (ascii(substr(( select table_name from information_schema.tables where table_schema = 'DB이름' limit 1 ),1,1)) > 0) and '1'='1
  • 바이너리 서치를 통해 알아내면 된다.

7. 칼럼 이름 추출

  • 칼럼이름을 추출하자
  • 컬럼 이름을 추출하는 쿼리문은 다음과 같다.
    • select column_name from information_schema.columns where table_name = '테이블이름' limit 1
  • 이 쿼리문을 공격 format에 대입하면 다음과 같다
    • normaltic' and (ascii(substr(( select column_name from information_schema.columns where table_name = '테이블이름' limit 1 ),1,1)) > 0) and '1'='1
  • 바이너리 서치를 통해 알아내면 된다.

8. 원하는 정보 추출

  • 우리가 만들어 놓은 공격 format에 찾은 내용들을 조합하여 대입하면 된다.
    • normaltic' and (ascii(substr(( select id from game ),1,1)) > 0) and '1'='1
    • 예를 들어서 game 테이블의 id 칼럼의 내용을 서치 하는 과정
  • 바이너리 서치를 통하여 알아내면 된다.

Blind SQL Injection의 자동화 도구

  • 위에 process를 통해서 알 수 있듯이 에러 하나만으로도 DB의 정보를 모두 추출할 수 있다는 장점이 있지만 사람이 하나하나 수작업으로 몇 천 번이 될 수도 있을 만큼의 질문이 있을 수도 있다.
  • 이러한 점을 간단하게 수행하고자 우리는 자동화 도구를 만들어서 사용하는 것이 바람직한 거 같다.

'모의해킹 스터디 > 개념 정리' 카테고리의 다른 글

SQL Injection Point 찾기  (2) 2024.12.11
Error based SQL Injection Process  (0) 2024.12.03
Error based SQL Injection  (0) 2024.12.03