/ POSTS

한글 데이터 sql injection

한글데이터 Blind SQL Injection

안녕하세요. 쁘니입니다.

오늘은 Blind SQL Injection으로 한글 데이터를 추출하는 방법을 알아보겠습니다.

보통 Blind SQL Injection이라 하면 substring 함수로 데이터를 나누고,

ascii 함수로 아스키코드 값을 비교해가며 데이터를 추출하는 방법을 생각하실 겁니다.

그러나 ascii는 American Standard Code for Information Interchange라는

풀 네임에서도 알 수 있듯이 미국에서 정의한 인코딩 방식으로 영문 알파벳을 표현하기 위해 만들어졌습니다.

즉 ascii 함수를 이용한 한글 데이터 추출은 무리가 있다는 거죠!

그럼 한글을 표현하기 위해 만들어진 인코딩은 무엇이 있고, 이를 이용해 데이터를 어떻게 추출할 수 있을까요?

한글을 표현하는 대표적인 인코딩 방식엔 EUC-KR과 UTF-8이 있습니다. 각각에 대해서 설명해드리겠습니다.

한글 인코딩 EUC-KR과 UTF-8

먼저 EUC-KR은 한글과 영문, 한자 정도를 표현할 수 있어 문자의 범위가 굉장히 한정적입니다.

또한 EUC-KR은 아래와 같은 완성형 방식을 사용하기 때문에 문자표를 토대로 완성된 문자를 인식하고 표현합니다.

만약 문자표에 내가 찾으려는 한글이 없다면 어떻게 될까요? EUC-KR은 이를 표현하지 못하게 됩니다.

EUC-KR은 이러한 특성으로 표현할 수 있는 한글의 개수가 2,350자 정도로 제한적입니다.

[완성형 방식]

반면에 UTF-8 인코딩 방식은 한글의 특징(초성, 중성, 종성)을 그대로 사용할 수 있는 조합형 인코딩 방식으로

한글로 표현할 수 있는 11,172자의 문자를 전부 표현할 수 있습니다.

[조합형 방식]

그럼 UTF-8을 쓰지 왜 EUC-KR을 쓰냐? 하고 생각하는 분들도 계실 겁니다. (물론 접근성이나 범위는 UTF-8이 더 뛰어나서 UTF-8을 많이 사용하긴 합니다)

EUC-KR은 한글 한 자당 2바이트를 사용하지만, UTF-8은 초성, 중성, 종성을 각각 1바이트씩 한글 한 자당

총 3바이트를 사용하기 때문에 리소스를 많이 잡아먹습니다. 만약 다국어나 특수문자를 사용하지 않는다면

EUC-KR이 더 효율적일 수도 있습니다. (무조건 UTF-8 방식을 사용한다고 단정 짓지 맙시다!!)

MySQL에서 인코딩 유추하기

이제 EUC-KR과 UTF-8의 차이를 알았으니, Mysql에서 이 차이를 어떻게 구분할지 알아보겠습니다.

bit_length 함수는 문자열의 비트크기를 반환합니다. ‘추’라는 한글의 비트수가 16비트(2바이트)인 것을 보니 EUC-KR이 확실하네요!

[EUC-KR의 한글 비트수]

문자셋을 변환하고 다시 ‘추’라는 한글의 비트크기를 확인하니 24비트가 출력됐습니다. 이번엔 UTF-8인 것을 알 수 있습니다.

[UTF-8의 한글 비트수]

인코딩 구분했는데 어떻게 한글데이터를 출력해야 할까요? 기존 영문데이터를 뽑는 방식처럼 한글을 한 글자씩 hex 함수로 변환시켜

substring으로 자르고 ascii로 문자를 구분한 다음.. 이걸 합해 다시 한글로 변환시킨다면 코드는 굉장히 비효율적이게 됩니다.

우리는 데이터를 더 효율적으로 추출해낼 방법이 있습니다!!!!!

인코딩 방식에 따른 ord 값 차이

mysql에는 문자열에 대한 코드를 리턴하는 ord 함수가 있습니다. ord 함수는 아래의 공식을 통해서 값을 출력해줍니다.

EUC-KR일 경우 2바이트 코드에 256을 곱한 값을 1바이트 코드와 합하여 출력합니다.

UTF-8일 경우 2바이트 코드에 256을 곱한 값과 3바이트 코드에 256^2을 곱한 값을 1바이트 코드와 합하여 출력해줍니다.

[ord의 공식]

‘추’라는 한글의 ord 값을 출력하면 같은 문자여도 공식에 따라 결과의 차이가 큰것을 확인하실 수 있습니다!

[EUC-KR의 ord 값]
[UTF-8의 ord 값]

이제 인젝션을 하기 위해 각 인코딩방식 별 ord 범위를 구해보겠습니다.

아래는 EUC-KR의 코드표입니다 한글데이터 범위를 ord로 표현하면 45217 ~ 51454의 값이 나옵니다.

[euc-kr 문자표]

UTF-8에서 한글은 U+0800~U+FFFF 범위에 해당됩니다. 이 범위를 ord로 표현하면 약 15380608 ~ 15572643의 값이 나오게 됩니다.

이 범위를 이용해 Blind 방식으로 한글데이터를 추출하는 SQL Injection을 시도해보겠습니다.

[euc-kr 문자표]

Blind SQL Injection 예제코드

테스트 환경은 아래와 같습니다.

-Python Flask

-Nginx 1.10.3

SQL Injection을 시도하는 게시판은 사진처럼 bbs_no 파라미터에 조건문을 붙여 상태코드로 참과 거짓을 구분할 수 있습니다.

테이블 명과 컬럼 명은 뽑았다는 가정하에 user_id 컬럼의 한글데이터를 출력할것입니다.

[조건이 참일 경우]
[조건이 거짓일 경우]

main 함수는 bit_length를 이용하여 한글인코딩이 EUC-KR인지 UTF-8인지를 구분하는 함수 입니다.

16비트일 경우 EUC-KR에 해당하는 ord 범위를 반환해주고, 24비트 일 경우 UTF-8에 해당하는 ord 범위를 반환해줍니다.

[한글인코딩 구분 함수]

queryToSite는 user_id의 데이터를 limit로 한행 씩 뽑아와 substring으로 나눠준 후

ord의 값을 바이너리 서치 방식으로 질의하는 함수입니다.

질의에 대한 참 거짓 결과는 status_code를 이용해 요청 성공(200), 내부 서버 오류(500)의 결과로 구분합니다.

참 거짓을 구분해나가면서 start와 end의 범위를 좁혀나가고 start와 end의 차가 1보다 작거나 같게 될땐 결과 값이 출력됩니다.

[한글데이터를 구하는 함수]

결과값을 16수 형식으로 출력시키면 0x값과 함께 출력됩니다. 출력된 값에 %를 붙여 URL Decoding 합니다!

[한글 출력 함수]

user_id 컬럼의 한글데이터를 추출한 결과입니다! 참 쉽죠 ㅎㅎ

[한글데이터 출력 결과]

한글 데이터 뽑아오는 것은 생각도 못했는데 이번 포스팅 작성하면서 새로운 공부를 했습니다 ㅎㅎ

다음번엔 Error Based Injection과 Xml 함수를 이용한 Error Based Injection 포스팅을 들고 오겠습니다. 감사합니다.