DB의 정보를 확인하기 위해
지난 글에서 SQL Injection을 했다. 바로 Guessing(추측) 공격으로 말이다.

하지만 DB에 관한 지식? 정보를 알면 조금 더 정확하게(?) 정보를 꺼낼 수 있다.

우리가 지금 사용하는 MySQL에 관한 지식을 이해해보면서
이러한 가능성을 이해해보자 :)

MySQL에는 기본 DB가 있다. (우리가 만들지 않아도)
그 중 하나가 information_schema인데 이 DB에는 DB내의 모든 정보가 들어있다.
information_schema는 MySQL5 이상에서만 존재한다.
이 DB는 논리적인 DB로 수정이나 삭제가 불가능하다.

이 information_schema DB를 살펴보자!



(information_schema DB)



이 DB에 들어있는 테이블들을 확인해보면
DB 정보가 들어있는 테이블들을 확인 할 수 있다.
여기서 우리는 테이블 정보가 들어있는 tables 라는 테이블을 확인해보겠다.



(TABLES 테이블)



테이블 내용 중 몇가지만 명령문에 넣어 select 명령문을 사용해보겠다.



(TABLES 내용 확인)



그렇다면
다른 DB에서도 information_schema DB에 들어있는 정보를 SELECT해서 확인 할 수 있는지 확인해보겠다.



(다른 DB에서 SELECT)



에러가 난다.!
그런데 에러 내용을 보니 blind.columns 이 없다고 나온다. 즉 경로를 입력해줘야 한다는 뜻이다.


select 1, column_name, table_name from information_schema.columns;
이런식으로 명령을 내리면 다른 DB에서도 해당 DB의 테이블 정보를 확인 할 수 있다.
그렇다면 union명령으로 SQL Injection 해보겠다.
information_schema 정보를 가져올 수 있다면 다른 DB에 대한 정보를 이용해 여러가지 정보를 가져올 수 있기 때문에 중요한 것이다.



(SQL Injection)



명령
http://100.100.100.129/view.php?no=1 union select 1, column_name, table_name from information_schema.columns;



(실행 결과)



실행 결과를 보니 information_schema DB의 columns 테이블의 정보들 중 우리가 선택한 column_name, table_name 정보가 나오는 것을 확인 할 수 있다. 첫번째 컬럼은 화면에 출력 되지 않으므로 그냥 1로 한 것이다.
우리가 이 페이지를 만들 때 일부러 취약하게 만들기 위해 while문을 사용했었는데
난이도를 올려 while을 제거해보겠다.


(while 제거)



제거하면 기존의 페이지 모습과 같다.



(제거한 모습)





(거짓 Injection)





(참 Injection)



다만,
아까와 같이 SQL Injection 시 정보가 주르륵 전부 나오지 않고 하나만 나오기 때문에 그리고 제일 먼저 담겨오는 원래정보만 나오기 때문에 난이도가 올라간다.
즉 여기서 우리는 새로운 명령 문법을 배워야한다.
바로 limit 명령이다.
limit을 이용하면 select의 개수를 정할 수 있다.
* limit 을 이용하면 출력의 개수를 정해줄 수 있다.

또 출력을 시작할 행의 번호 또한 지정할 수 있다.
MySQL에서는 0번부터 시작한다.
mysql> select * from [Table] limit 시작, 갯수;



(사용 예시)



위 사용은 10번째 행부터 10개 까지만 가져오도록 하는 명령을 사용한 것이다.

이것을 이용하면 아까 우리 페이지는 한개의 행만 가져올 수 있으므로 개수는 1개로 지정하되
시작하는 행의 번호는 자유이므로 아래와 같이 명령을 하게되면 정보를 확인 할 수 있게 된다.



(테이블 정보 확인)



이를 이용해
http://100.100.100.129/view.php?no=1 union select 1,2,table_name from information_schema.tables limit 1,1
이렇게 url로 SQL Injection을 하면 아래와 같이 나온다.



(실행 결과)




(실행 결과2)



여기서 난이도를 더 올려보겠다.
만약 화면에 DB 정보가 안나온다면??..



(DB정보 출력 제거)



난이도를 올린 페이지 모습



(업그레이드 페이지 모습)




(참 Injection)





(거짓 Injection)



참과 거짓을 이용했을 때 화면에 문구가 나오느냐 안나오느냐 확인 할 수 있으므로
SQL Injection에 취약한 지는 체크할 수 있다.

하지만 DB정보가 출력되는 곳이 없는데 어떻게 정보를 확인할 수 있단 말인가...

이를 이해하기 위해 우리는 또다른 mysql 명령 문법을 알고 가는 것이 좋다.
substr 이라는 문법이다.
이 문법은 php에서도 사용된다.

바로 문자열을 분할하는 함수이다.
이 함수를 이용하면 아래와 같이 한글자를 확인 할 수 있다.



(substr 이용 확인)



위 화면은 information_schema DB에 있는 tables 라는 테이블에 테이블 이름 컬럼의 정보 중 첫번째 행의 데이터의 첫번째 글자를 확인한 것이다.

이를 우리는 웹에서 DB정보가 출력되는 것이 없기 때문에 참과 거짓을 이용하여 찾을 것이다.
그러기 위해 참과 거짓이 되게 비교를 해야하는데 물론 문자도 비교가 되지만 정확하게 하기 위하여
아스키코드를 비교하는 것이 좋다.



(아스키 코드 비교 화면)



이를 이용하여 아래와 같이 비교문장을 and 뒤에 추가하면 만약 참이되면
화면에 글자가 나올것이고(Welcome 어쩌구)
만약 거짓이면 and이기 때문에 화면에 아무 글자도 출력되지 않을 것이다.
바로 이것을 이용하여 찾는 것이다.



(SQL Injection)





(거짓 화면)



그렇다면 66이 아니니 67을 너보는 것이다.



(참 화면)



67일 때 글자가 나온것을 봐서
67이구나 즉 C라는 글자구나라고 생각할 수 있다.
이런 식으로
ascii(substr( (select table_name from information_schema.tables limit 1,1), 2,1)) = 66;
ascii(substr( (select table_name from information_schema.tables limit 1,1), 3,1)) = 66;
...
이렇게 한글자씩 찾는 것이다.

비교문이므로 크다, 작다 부등호로도 판별이 가능하다.



(부등호 사용)



이제 난이도를 더 올려보겠다.
화면에는 이제 Welcome이라는 글자 조차.. 아무 화면도 안뜬다...
이런 상황에서도 가능할까??



(출력 정보 없다.)





(페이지 모습)





(참 Injection)





(거짓 Injection)




참도,, 거짓도... 알아볼 수 없는 화면이다...
이럴 때는 일부러 특이 현상을 일으키는 것도 방법이다.
예를 들어 sleep명령이 있다.
and 뒤에 비교문(아까와 같이) 또 그 뒤에 sleep을 걸어주면
비교가 참일 경우 sleep이 발생되고
거짓일 경우 뒤의 명령을 실행할 필요가 없기 때문에 sleep이 나타나지 않는다.
즉 이걸 이용하면 아까와 같은 방법으로 한글자씩 알아낼 수 있다.




(참 Injection)




참일 경우 위와 같이 sleep이 발동되어 화면이 돌아가고 있는 모습을 볼 수 있다.

이렇듯 화면에 출력되는 정보가 없어도
확인이 힘들더라도
SQL Injection은 가능할 수 가 있다.
:)



+ Recent posts