[모의해킹 스터디] 8주차 정리

바울·2024년 12월 10일
0

모의해킹 스터디

목록 보기
22/40

SQL Injection Point

SQL Injection을 이용한 공격을 하려면 SQL Injection Point 즉 DB에게 SQL 질의문을 사용하는 곳을 찾아야 한다. 실무에서는 여기서 sql injection이 일어난다고 광고를 하진 않을 것이다. 지금까지는 대게 직접 입력값을 넣는 곳 로그인, 검색 기능 등에서 sql injection을 수행했지만 이번 포스팅에서는 다른 곳에서 발생하는 sql injection에 대해 알아보고자 한다.


findSQLi_1: COOKIE

아무런 정보도 없는 상태에서 해당 사이트에 SQL Injection Point를 찾아보고자 한다!

회원가입을 해준 후에 로그인을 시도해 주었다. 회원가입 페이지와 로그인 페이지에는 특별한 점을 찾지 못했다.

로그인 성공 시 해당 사이트로 이동하게 된다. 마이페이지와 게시판을 이용할 수 있다. 마이페이지부터 확인해 보도록 하자!

마이페이지로 접근을 하게 되면 사용자 정보가 나오고 update를 할 수 있는 버튼이 있다. 정보를 수정하고 버튼을 누르게 되면 db에게 해당 정보로 update 하라는 요청을 보낼 것이라고 유추할 수 있다. 그럼 사용자 정보는 어떻게 가져오는 것일까? burp suite를 이용해 패킷을 확인해 보자!

쿠키 값을 확인해 보면 user=baul이라고 되어있는 것을 볼 수 있다. 여기서 알 수 있는 건 사용자 정보를 쿠키 값에 있는 user=이름의 정보를 읽어 마이페이지에 보여주고 있는 거라면 여기에 조건문을 사용해 참과 거짓을 구분할 수 있을 것이다.

서버에서 실행되는 쿼리가 select * from user where user='__' 일 거라고 추측되기 때문에 쿠키 값을 baul' and '1'='1입력해 서버에 전달해 보았더니 이전과 같은 화면이 나온 걸 볼 수 있다. 쿠키에 입력한 값이 그대로 출력되는데..? 그거는 쿠키의 user 값을 그대로 placeholder에 넣고 있는 듯하다. 그럼 참이 아닌 거짓인 조건을 넣는다면 어떻게 될까?

baul' and '1'='2 입력해 거짓인 조건을 입력하면 참일 경우랑은 다르게 nothing here 부분이 없어진 걸 알 수 있다. 이로써 참과 거짓을 구분할 수 있으므로 blind injection을 수행할 수 있는 injection point를 찾은 것이다!


findSQLi_2: Column Name

계속해서 게시판에서도 찾아보자!

사용자가 작성한 게시글을 볼 수 있다.

일치한 문자가 하나라도 있을 경우 글을 보여준다. 이걸로 알 수 있는 건 like%__%를 사용하는 걸 알 수 있다. 그리고 일치하는 문자가 없을 경우는 에러 메시지가 나오는 걸 볼 수 있다.

패킷의 파라미터를 살펴보면 option_val=username&board_result=b 내가 입력한 b와 username은 작성자 밑에는 title은 제목 카테고리인 것을 알 수 있다. 이 파라미터가 서버에 전달된다면 제목을 기준으로 내가 입력한 문자를 조건으로 찾기 때문에

select * from user where CATEGORY like '%USER_INPUT%'

이런 식으로 쿼리가 작성돼있을 것이라고 예상할 수 있다. 여기서 and 조건문을 사용해 쿼리를 사용할 수 있는지 확인을 해보자. 예상한 select 문을 보면 두 번째 파라미터에 쿼리를 삽입하는 건 의미가 없어 보인다. 그럼 첫 번째에 and 조건문을 넣어보면?

select * from user where title and '1'='1' like '%t%'

아무런 의미가 없다.. 그럼 title 앞에 and 조건문을 넣어 본다면?

select * from user where '1'='1' and title like '%t%'

참인 조건일 경우 기존과 같이 값이 나오고 거짓일 경우에는 값이 안 나오는 걸 볼 수 있다! 참과 거짓을 구분할 수 있으므로 Blind injection을 수행할 수 있다!


findSQLi_3: order by

이전과는 다르게 동작하는 게시판을 살펴보자!

총 3개의 게시글을 작성한 후 검색 기능을 사용해 검색을 해보았다.

검색 카테고리를 작성자로 하고 ba라는 단어를 검색 시 다음과 같은 파라미터가 나왔다. findSQLi_3와 비교해 보면 마지막에 sort=title이라는 파라미터를 볼 수 있다. 이걸로 알 수 있는 것은 sort에 있는 값을 가져가 order by에서 사용한다는 것을 알 수 있다. title 부분을 1부터 계속 입력하다 보면 11에서 값이 나오지 않는다. sql injection을 수행할 수 있는 것이다. 이제 참과 거짓을 구분할 수 있는 쿼리가 필요한데 그때 사용할 수 있는 것이 case 문이다.

case when (조건) then (true) else (false) end

case 문은 sql에서 사용하는 if 문이라고 생각하면 된다. 조건 부분에는 확인하고자 하는 조건 true 부분에는 조건이 참일 시 실행할 내용 false는 조건이 거짓일 시 실행할 내용을 넣으면 된다. 예를 들어

sort=case when (1=1) then username else title end

이라고 입력 시 1=1은 참이니까 user name으로 정렬을 하는 것이다.

참과 거짓의 따라 정렬 기준이 바뀌기 때문에 참 거짓을 구분할 수 있게 되었다. 하지만 column 이름을 모르는 상태에서는 어떻게 참과 거짓을 구분할 수 있을까? 그럴 때 사용하는 쿼리가 있다.

select 1 union select 2 where (1=1)
select 1 union select 2 where (1=2)

해당 쿼리를 살펴보면 조건이 참일 경우는 두 개의 row가 전달이 되면서 에러가 나기 때문에 화면에 아무런 글이 출력되지 않고 조건이 거짓일 경우에는 select 1 즉 하나의 row만 전달이 되어서 화면에 글이 정상적으로 출력되기 때문에 화면에 나오는 결과에 따라 참과 거짓을 구분할 수 있어서 Blind injection을 수행할 수 있는 것이다.

case when은 어떤 column을 기준으로 정렬을 하는지에 따라 참 거짓을 구분했다면 UNION은 게시물이 화면에 출력이 되는가에 따라 참 거짓을 구분할 수 있다.

(select 1 union select 2 where substr((select 'bawool'),1,1)='u')
(select 1 union select 2 where substr((select 'bawool'),1,1)='b')

이제 where 문 뒤에 우리가 원하는 쿼리를 넣음으로써 원하는 정보를 추출할 수 있을 것이다!


findSQLi_4

마지막으로 살펴볼 취약점은 마이페이지에서 찾을 수 있다.

처음과 같이 쿠키 값에 쿼리를 삽입해 보았지만 바뀌는 게 없었다.. 만약 잘못된 문법을 사용하면?

select * from user where user='bawool''

따옴표를 사용하면 문법에 맞지 않기 때문에 에러가 나게 된다. 이렇게 에러를 이용해 참과 거짓을 구분할 수 있는 경우도 있다! 위에서 사용한 쿼리를 활용해 보면

bawool' and (select 1 union select 2 where (1=2)) and '1'='1
bawool' and (select 1 union select 2 where (1=1)) and '1'='1

결과적으로 matrix 값이 중간에 들어가기 때문에 에러가 발생하게 된다. where 부분에 우리가 원하는 sql 조건을 넣어서 에러 발생 유무로 참 거짓을 구분할 수 있다! 실제로는 prepared statement를 사용하면 sql injection이 아직까지는 전혀 불가능하다고 보면 된다. 그럼에도 우리가 sql injection을 사용하는 이유는 이번에 작성한 글처럼 prepared statement를 사용할 수 없는 곳이 있다. 그게 바로 order by, table 이름, column 이름이다. 눈에 보이는 곳 말고 다른 곳에서도 sql injection을 수행할 수 있다!

0개의 댓글