'2018/08'에 해당되는 글 1건

  1. 2018.08.21 [TIP?] sql injection을 위한 깔끔한 코드 작성법 2


주제 : SQL injection을 위한 깔끔한 코드 작성법

날짜 : 2018.08.21

작성자: Sakuya Izayoi



1. 개요 및 목적

'글쓴이 경험상' 대회때마다 SQL 문제가 나오면 그 문제에 맞게 툴을 새로 짜고, 펜테스트를 할때에도 툴을 새로 짜고.. 날이면 날마다 늘어가는 ???.py 들을 보고 있자니 파일관리를 못하는건지, 내가 범용성이 없게 짜는건지 도저히 모르게 되어버려서 쿼리의 형태를 작성하면 injection을 해주는 범용적인 툴을 제작하는것을 그 목적으로 한다.


2. 내용

이번은 기술문서가 아니라서 실망할 분들도 꽤 있을것 같다. 기술문서도 좋지만 쓸데없이 늘어가는 ???.py 들을 한번에 정리하고 깔끔한 Desktop 폴더를 만들기 위해서 본 글을 작성하기로 했다. 이번 포스팅의 정확한 목표는 '이 글을 참고하여 나만의 sql 자동화 툴을 만들자!' 가 되겠다.

이 글을 읽고싶어 하는 분들은 대부분의 세팅을 끝마친 상황일것이다. (Python, pip, APM 등등.)
하지만 그렇지 않은 분들을 위해 조금의 기초세팅을 소개하고 난 후, 본격적인 코드작성에 돌입하도록 하자.


2-1. Python - Requests 모듈

Python은 Ubuntu를 사용한다면 기본적으로 깔려있다. Requests 모듈은 웹에 서비스를 요청하는데 사용되는 대중적인 모듈중 하나이다. urllib 나 httplib를 쓰는분도 있긴하지만, 여기선 Requests를 쓰기로 하자. 이를 사용하기 위해선 pip install requests라고 입력후 엔터를 치면 된다.

이미 설치되어 있다면 위와 비슷한 화면이 뜨게 된다. 제대로 설치 되었는지 알고 싶다면 python을 실행후 import requests 를 입력후 엔터를 쳤을때, 아무런 에러가 나지 않으면 성공적으로 설치 된 것이다.

자신이 테스트할 웹 페이지가 있는것이 좋지만, 여기선 웹 해커의 자습서인 LOS를 예제로 조금 진행해 보도록 하겠다.  SQL injection에 대한 기초지식이 없다면 기초문서를, 조금의 지식이 있다면 심화문서를 읽도록 하자. 굳이 다 알고 있지 않아도 개략적인것을 기억한다면, 문서를 참고하면 언제든지 코드작성이 가능하므로 반드시 암기해야해! 같은 생각은 조금 접어두는것이 좋다.


3. 코드 작성

코드를 작성하기전에, 어떤것들을 코드로 작성하는게 좋을지 조금 생각해보자. 간단한 인증우회와 같은 것들은 툴로 작성할 필요가 없다. POC를 위해서라면 간단하게 작성할수 있지만, 이것을 자동화 라고 부르기엔 너무 간단하게 끝나지 않을까?
그렇다면 자연스레 목표는 정보유출에 관점을 맞추게 된다. union이 사용한 것들은 일반적으로 한문장의 쿼리로 유출이 가능하니 이것들도 제외하자.
남는것은 Blind 계열, Time based 계열의 injection들이 남게 된다. 이러한 것들은 대체적으로 특징적인 형태를 띄고 있는 경우가 많다.

해당 문제에서 SQL injection 구문을 짜게 되면,

pw=' || id='admin' && if(ascii(substring(pw,?,1))>0,1,0)#

정도 될것 같다. 변하는 값은 ?에 있는값으로 1,2,3,4,.. 증가하게 될것이다. 그럼 여기서 숫자는 언제까지 증가해야할까?ㅋ
이는 length를 통해 값을 가져올수 있다. 그럼 이 length는 어디까지 검증해야 할까?

조금 머리를 굴릴수 있다면 length에 대해서 binary search 를 적용해 볼수 있을것이다. 하지만 내가정한 상한값이 과연 원하는 정보의 길이를 포함하는 충분히 큰 값인가? 에 대한 질문은 확실히 답변하기 애매할수 있다. 무엇보다, '깔끔한' 코드 작성과는 거리가 멀다. 코드내에 for i in range(1,10000)이라고 적혀있을 내 코드를 보자. 작성하면서도 찜찜하지 않을까?

여기서 제안하는 방법은 length(length()) 쿼리이다. 이것으로 값을 한번 추출하면, 해당 값의 최대크기와 최소 크기를 지정할 수 있다. 무슨 뜻인가 하면,

length의 반환값을 하나의 string으로 보고 다시 length를 걸어서 이 글자의 최대길이를 잰다. 10의 n승 형태로 나타낼수 있게 값을 리턴해 주므로, 최대와 최소 길이를 정할수 있고, 이를 통해 binary search를 깔끔하게 작성할 수 있다. 여기서는 2를 리턴해줬으므로, 최소값은 10, 최대값은 100 이다. 그리고 이 사이에 16이라는 값은 반드시 들어있게 된다.
length(length())의 리턴값을 powret이라고 두면, 개략적으로 아래와 같은 코드를 작성 할 수 있다.

print에 들어있는 \033은 커서를 좌측 상단으로 떙기는 출력으로, console progressbar를 구현할때 글쓴이가 종종쓰는 방법이다. 코드를 실행시키면 실시간으로 LENGTH가 변하는것처럼 보이게 된다.

이렇게 length에 대한 값을 얻었으면,  sql 구문을 작동시키는 코드를 작성해 보도록 하자.

BLIND SQL injection 을 하면서 달라지는 값들에 대해서 한번 다시 생각해보도록 하자
pw=' || id='admin' && if(ascii(substring(pw,?,1))>0,1,0)#
여기서 중요한것은 처음의 pw와 substring내의 pw가 다를수 있다는것이다.


이 문제처럼, no값에 injection을 하고 가져와야하는 값이 pw일수도 있는것이다. 이렇게 되면

no=' ||id='admin' && if(ascii(substring(pw,?,1))>0,1,0)# 과 같이 두개의 값이 다를수 있다는 점이 중요하다.

이렇게 가변적인 값이 총 4개로 지정되었다. 이를 Blind SQL을 하기위해 4개의 인자를 가진 함수(메소드)를 제작하고 binary search를 행하는 구문을 개략적으로 작성해 넣는다면, 성공적으로 돌아가지 않을까?
코드를 작성함에 있어 필요한 것들을 정리해보면,
- Query의 뼈대
- Target이 될 Parameter
- True/False 를 판단할수 있는 판단조건
- 가져와야할 Column 이름
- 가져올 값의 길이 (length)

가 될 것이다. 간단한 예시로 Length를 구하는 Query를 살펴보도록 하자.

우리가 넣을 쿼리에 length({}) 부분을 length(length({})) 로 바꿔줌으로써 사용에 불편함이 없도록 한다.

그의 리턴값을 받아서 Bianry Search를 돌리게 되면 간단하게 값이 나오게 된다.

if column is None 부분에 대해서 조금 의문이 들수 있는데, 이 부분은 위에 예시를 들었던 no,pw 처럼 injection하는 파라미터와 가져와야할 column이 다를경우 설정해 주는 값으로, 설정해주지 않으면 동일한 것으로 판단하고 인젝션하는 코드가 되겠다.

위와 같이 코드를 작성하게 된다면 Length를 가져오는 쿼리의 예시는

LengthQuery = "1' || id = 0x61646d696e && if(length({})>{},1,0)#

이는 getLength(LengthQuery,"pw",TrueCondition,column='pw') 처럼 호출되거나

getLength(LengthQuery,"no",TrueCondition,column='pw') 처럼 호출 될 것이다.

본편에서는 Length Query만을 예제로 들었지만, 다른 blind sql 구문또한 이와같이 작성해주면 간단히 해결 할 수 있다.


4. 보너스

이렇게 열심히 코드를 작성해놓고 밋밋하게 출력된다면 또한 재미가 없다. 한글자씩 나오더라도 영화처럼 나오면 보는 사람또한 즐겁기 마련이다.


여기서 key는 전역변수로, blind sql을 통해 한글자를 얻을때 마다 갱신된다. threading을 사용하여 돌려보면 마치 무작위대입을 하다가 한글자씩 맞추는것 같은, 영화와 같은 출력을 볼 수 있다.


'Web' 카테고리의 다른 글

Webhacking Study - Binary search with filtering  (0) 2019.10.10
XSS TEST  (0) 2019.04.15
Webhacking Study - Query sniff  (2) 2018.04.06
Webhacking Study - no more BLIND  (6) 2017.04.18
SQLi.py  (0) 2016.11.02
Posted by IzayoiSakuya
,