R's Hacking Daily Log

SQLi (5) 본문

Port Swigger/SQL Injection

SQLi (5)

hanhxx 2023. 4. 30. 22:05

이번에 살펴본 TOPIC은 

Blind SQL injection!!

 

:) 앞에서 살펴본 상황과는 다르게 Blind SQL injection은

DB 에러나 SQL 결과가 반영된 HTTP 응답을 받을 수 없는 상황에서 사용된다. 

 

:) SQL 결과가 HTTP 응답에 포함되지 않는다는 건, 이전에 풀어본 lab에서와 같이

username이나 password가 페이지에 출력되지 않는다는 뜻이다.

 

:) 이번에 살펴볼 application은 cookie를 사용해 인가된 사용자로부터 온 요청인지 확인한다.

 

:) 주입된 SQL로 username과 같은 세부정보는 알아낼 수 없지만

cookie가 유효한 경우에는 "Welcome Back" 문구를 출력하고 유효하지 않은 경우에는 아무것도 출력하지 않는다.

 

:) Welcome back 문구가 출력되느냐 안되느냐의 여부로 주입한 SQL의 결과가 "true or false"인지 판단할 수 있다.

 

 

이와 같이 SQL의 결과를 TRUE OR FALSE로만 알 수 있는 경우의 SQL injection

blind sql injection이라 한다.


Exploiting blind SQL injection by triggering conditional responses

application은 HTTP request에 포함된 cookie를 가지고 

Cookie: TrackingId=u5YD3PapBcR4lN3e7Tj4

 

cookie 정보가 저장되어 있는지 확인하는 과정을 거친다.

SELECT TrackingId FROM TrackedUsers WHERE TrackingId = 'u5YD3PapBcR4lN3e7Tj4'

 

 

applicaiton이 query를 만들 때, TrackingId 값이 아래의 $id로 들어가게 된다. 

SELECT TrackingId FROM TrackedUsers WHERE TrackingId='$id'

 

이때 공격자는 request cookie 부분에 다음과 같은 sql을 주입할 수 있다.

TrackingId = 'u5YD3PapBcR4lN3e7Tj4' AND '1'='1'

TrackingId = 'u5YD3PapBcR4lN3e7Tj4' AND '1'='2'

첫 번째 SQL ) '1' = '1'은 항상 True인 구문이기 때문에 이 sql의 결과는 True가 된다.

두 번째 SQL ) '1' = '2'는 항상 False인 구문이기 때문에 이 sql의 결과는 False가 된다.

 

* AND 연산은 비교 대상이 둘 다 True일 때, 결과가 True가 된다.

따라서 첫 번째 sql은 "welcome back" 문구를 출력시키고 두 번째 sql은 어느 것도 출력하지 않을 것이다.

 

이 예시로 얻어갈 아이디어는 

:) AND '1'='1'은 항상 TRUE

:) AND '1'='2'는 항상 FALSE

:) 이 개념을 사용해 YES or NO로 답을 얻을 수 있는 SQL을 활용할 수 있다!

 

 

 

username & password column을 갖는 users table에 administrator 계정이 있다고 상상해 보자. 

공격자는 위에서의 아이디어를 사용해 administrator의 password를 알아내고자 한다.

이런 상황에서 공격자는 어떤 sql을 만들 수 있을까??

 

~~7Tj4' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) > 'm

substring() 안에 있는 select 문 ) username이 administrator인 password를 조회해라!

substring() ) password의 첫 번째 문자만 뽑아내라!

 

AND 기준 오른쪽 부분은 password의 첫 번째 문자가 m보다 크면 sql 결과가 true가 되기 때문에

"welcome back" 문구가 출력된다. 

 

 

좀 더 범위를 좁혀보자.

~~7Tj4' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) > 't

위의 sql 결과로 welcome back 문구가 출력되어 이번에는 t보다 큰 문자인지 확인해 보는 sql을 만들어봤다.

 

만약 sql의 결과로 문구가 출력되지 않으면 administrator's password 첫 번째 문자가 m보다 크고 t보다 작다는 뜻이고,

welcome back 문구가 출력되면 첫 번째 문자가 t보다 큰 알파벳이라는 뜻이다.

 

 

이번엔 특정 문자인지 아닌지를 확인할 수 있는 sql을 실행해 보자.

~~7Tj4' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) = 's

sql 결과로 문구가 출력되면 password의 첫 번째 문자는 s라는 걸 알 수 있게 된다.

 

이처럼 sql의 결과로 문구가 출력되는지, 안 되는 지의 여부로(= true or false)

password의 길이가 n이라고 할 때, 1~n까지의 각 문자가 무엇인지를 확인할 수 있게 된다!!

 

* substring() 안에 2번째 파라미터 값을 1~n까지 증가시키면서 sql를 실행해 보면

password가 무엇인지 알아낼 수 있다.

 


Inducing conditional responses by triggering SQL errors

:) 이제는 application이 "welcome back" 문구를 띄워주지 않는다고 한다.. (OoO)

:) 대신 sql 결과에 따라 error가 출력된다고 한다.

 

이전에 살펴본 상황에서는 applicaiton이 sql의 결과가 True일 경우, 문구를 출력해 줬지만 이젠 아니라고 한다.

그래서! sql 결과가 True인 경우 error가 발생하도록 sql을 만들어 보고자 한다. 

 

~~' AND (SELECT CASE WHEN (1=2) THEN 1/0 ELSE 'a' END)='a

~~' AND (SELECT CASE WHEN (1=1) THEN 1/0 ELSE 'a' END)='a

위와 같은 sql을 주입하면 다음과 같은 select문이 만들어진다.

 

TrackingId = 'u5YD3PapBcR4lN3e7Tj4' AND (SELECT CASE WHEN (1=2) THEN 1/0 ELSE 'a' END)='a'

TrackingId = 'u5YD3PapBcR4lN3e7Tj4' AND (SELECT CASE WHEN (1=1) THEN 1/0 ELSE 'a' END)='a'

case when ) sql에서 조건문으로 사용할 수 있는 keyword로

조건이 참일 경우에는 THEN, 거짓일 경우에는 ELSE 내용이 실행된다. (END는 끝나는 부분을 나타내는)

 

첫 번째 SQL은 조건이 false(1=2)이기 때문에 else의 내용이 select 된다. 

따라서 'a' = 'a'라는 구문이 만들어져 TRUE인 결과가 나온다.

 

두 번째 SQL은 조건이 true(1=1)이기 때문에 then 내용이 select 된다.

따라서 (1/0) = 'a'라는 구문이 만들어져 FALSE인 결과가 나오게 된다.

 

* 어차피 두 번째 sql에서 1/0은 divide by zero error를 발생시킨다.

 

 

' AND (SELECT CASE WHEN (Username = 'Administrator' AND SUBSTRING(Password, 1, 1) > 'm') THEN 1/0 ELSE 'a' END FROM Users)='a

 

이 SQL은 administrator계정 password의 첫 번째 문자가 m보다 큰 알파벳이면 error를 발생시킬 것이다.

 

이렇게 page 상에서 그 어떤 정보도 얻을 수 없을 때 조건에 따라 error가 발생하는 SQL을 실행함으로써

한 문자씩 password의 내용을 알아낼 수도 있다.

 


 

Exploiting blind SQL injection by triggering time delays

:) 이번에는 그 어떤 error나 HTTP 응답을 하지 않는 경우를 고려해 보자

:) 이런 경우, TRUE OR FALSE에 따라 처리되는 시간을 조절해볼까 한다.

 

HTTP 상의 문구도, Error도, 그 어떤 정보도 알려주지 않는 상황에서 써먹어볼 것은 바로 "Delay"이다.

 

 

'; IF (1=2) WAITFOR DELAY '0:0:10'--
'; IF (1=1) WAITFOR DELAY '0:0:10'--

조건이 false인 경우는 뒤에 있는 내용이 실행되지 않기 때문에 delay가 없지만, 

조건이 true인 경우에는 뒤에 있는 내용이 실행돼 delay가 발생하게 된다.

 

* delay란, request가 처리되어 response가 화면에 출력되기까지의 시간 텀을 말한다.

화면에 출력되는 내용 상의 차이가 없기 때문에 화면이 출력되는 데 까지 걸리는 시간으로

SQL의 결과가 true인지 false인지 알아내자는 것이다. 

 

 

'; IF (SELECT COUNT(Username) FROM Users WHERE Username = 'Administrator' AND SUBSTRING(Password, 1, 1) > 'm') = 1 WAITFOR DELAY '0:0:{delay}'--

username이 administrator이고 password의 첫 번째 문자가 m보다 큰 알파벳인 결과가 1개 있다고 한다면,

10초 delay가 실행된다는 의미이다. 

 

이렇게 sql의 결과가 True인지 아닌지의 여부를 화면상의 나타낼 수 없다면

delay를 사용해서 알아낼 수도 있다.

 


[ summary ]

:) blind sql injection이란,

True or False로만 sql의 결과를 알 수 있는 경우의 sql injection을 말한다. 

 

:) HTTP 응답에 세부적인 정보를 포함하지 않는 경우

- 특정 문구가 출력되는 여부로 sql의 결과를 알 수 있다.

 

:) HTTP 응답 or 문구를 출력하지 않는 경우

- 조건문을 활용해 의도적인 error를 발생시키자!

 

:) 다른 경우를 포함하며 error도 알려주지 않는 경우

- 화면 상의 변화는 없지만 화면을 출력시키는 데에 걸리는 딜레이를 설정하자!

'Port Swigger > SQL Injection' 카테고리의 다른 글

SQLi (6)  (0) 2023.05.14
SQLi (5) - Lab  (0) 2023.05.01
SQLi (4)  (0) 2023.04.28
SQLi (3) - Lab  (0) 2023.04.28
SQLi (3)  (0) 2023.04.27
Comments