SQL Injection Point 찾기
SQL Injection 공격 포인트 찾기
SQL Injection 공격을 수행하려면 기본적으로 서버가 파라미터를 입력받아 이를 화면에 출력하도록 처리하는 경우 해당 데이터에 악의적인 SQL 문법을 삽입해야 합니다 하지만 이러한 공격 포인트를 찾는 것은 여간 쉽지 않습니다
오늘은 SQLinjection의 point를 찾아 인젝션 공격을 가능하게끔 찾는 과정을 담아내겠습니다
SQL Injection의 취약점이 흔히 발견되는 지점
사이트 내에서 SQL Injection 취약점이 주로 발견되는 위치는 다음과 같습니다
- 쿠키(Cookie) : 클라이언트와 서버 간 교환되는 데이터
- 테이블(Table) : 동적으로 생성되는 데이터베이스 테이블 구조
- 칼럼(Column) : 쿼리의 일부로 사용되는 열 이름
- ORDER BY : 정렬 기준을 동적으로 처리하는 경우
이해를 돕기 위해 SQL Injection 공격이 가능한 포인트를 찾아보겠습니다
1. 사용자 입력 기반 공격
해당 사이트주소를 버프스위트을 이용해서 오고 가는 데이터를 분석해 보겠습니다
이미지와 같이 [user]와 [PHPSESSID] 값이 표시되는데, 이는 서버와 클라이언트 간 상호작용이 이루어진 것을 의미합니다
![]() |
![]() |
- 사용자 입력란에 **ser_ser' and '1'='1**을 삽입한 결과 참(True)이 반환되었습니다
- 반대로, **ser_ser' and '1'='2**를 삽입한 경우 거짓(False)으로 확인되었습니다
이를 통해 사이트가 Blind SQL Injection 공격에 취약하다는 것을 확인할 수 있었습니다
2. 칼럼 기반 공격
서버가 특정 칼럼명을 파라미터로 받아 동적으로 SQL 쿼리를 생성하는 경우, SQL Injection 공격이 가능합니다
게시글 작성 기능을 사용하여 다양한 게시글을 생성했습니다
title 칼럼에 **select 1**을 삽입한 뒤 서버 응답을 확인했습니다
title column에서 select+1을 찾는 sql 쿼리를 보냈고 컴퓨터는 그게 해당하는 데이터를 사용자에게 보냈다 select+1을 보내면 서버가 해당 데이터를 보내주는 것을 체크하여 sql injection을 시도해 보겠습니다
select+1 and '1'='1을 넣으니 아무것도 출력이 되지 않는 것을 확이 할 수 있습니다 그렇다면 해당 SQL문법은 다음과 같다고 예상해 볼 수 있겠습니다
기존 예상 쿼리
SELECT * FROM board_table
WHERE option_val = title
OR board_result LIKE '%select 1%' AND '1'='1';
board_result부분의 반환이 되지 않자
최종 유추 쿼리
SELECT * FROM board_table
WHERE option_val = title
AND board_result LIKE '%select 1%' and '1'='1';
and문법이라 'select 1' and '1'='1'자체 문자를 찾고 있는 것으로 판단되고 그렇다면 맞는지 한번 실험해 봅시다
select 1' and '1'='1 게시글을 만들고 board_result에 다시 같은 값을 넣어보겠습니다
예상과 드러 맞듯이 'select 1' and '1'='1' 문자열을 찾고 있었고
SELECT * FROM board_table
WHERE option_val = title
AND board_result LIKE '%select 1%' and '1'='1';
해당 코드가 명확해 보입니다 그러면 title로 sql injection을 시도해 보겠습니다
title 바로 앞에 and문구가 있기 때문에 'title' and '1'='1'이 먹히지 않을 것으로 보입니다 왜냐하면 1=1은 참이기 때문에 and를 바로 이어서 쓸 수 없기 때문입니다 and는 뒤는 무조건 조건이 붙어야 다음으로 넘어갈 수 있기에 and의 조건을 만족시키려면 title 앞에 and를 넣어주는 방법을 사용하면 됩니다
'1' = '1' and title 이렇게 말이죠
![]() |
![]() |
해당값이 참/거짓을 구별할 수 있게 되며 이 사이트 또한 blind sql injection으로 서버 데이터를 긁어 올 수 있습니다
또한 우리가 유심히 체크해야 할 곳이 바로 order by절입니다 그 이유는 정렬 기준을 동적으로 처리하기 위해 사용자 입력을 쿼리에 직접 포함하는 경우가 많기 때문이죠
ord, sort가 이 order by절에 해당함으로 필히 체크해야 합니다
제공된 사이트에 들어가서 해당 사이트에 어떤 부분이 SQLinjection이 통하는지 알아보도록 하겠습니다
![]() |
![]() |
이전 사이트와 똑같아 보이지만 버프스위트으로 분석하면 해당 페이지에 sort라는 문구가 생긴 것을 확인할 수 있습니다 이 sort는 정렬 기준을 동적으로 처리해야 하기 때문에 입력 쿼리를 직접 포함해야 하는 경우가 많아 대게 sqlinjection 공격이 먹힐 확률이 높다고 볼 수 있죠 한번 확인해보도록 합시다
![]() |
![]() |
sort에 title을 지우고 1,2를 넣어서 해당 코드가 사용자 설정으로 정열을 하고 있는지 확인해 봅시다
이미지를 처럼 정열이 바뀌는 것을 확인할 수 있으며 이것은 SQLinjection이 통한다는 의미이기도 하고 (select 1 union select 2 where 1=1) 넣어 참이면 오류가 뜨고 거짓이면 실행시키는 방식으로 진행해 보도록 하겠습니다
![]() |
![]() |
결괏값이 바뀌는 것을 보아 이 페이지 또한 blind sqlinjection 가능하다는 것을 알 수 있습니다
이렇게 sqlinjection의 포인트를 찾는 여러 과정들을 알아보았고
그렇다면 이런 sqlinjection을 방어하는 가장 효과적인 방법은 어떤 것들이 있을까요?
Prepared Statement
> prepare를 사용하면 기존 구조를 컴파일 해두기 때문에 sqlinjection으로 추가 문법을 끼워 넣으려고 해도 이것이 문자열로 읽히기 때문에 문법이 적용이 안됩니다
예를 들어
a'and '1'='1을 입력을 해도 'a는 참이다' 인식하지 않고 [a'and '1'='1]라는 문자 자체를 찾을 것이며
이론상 prepared statement를 적용시키면 sqlinjection을 원천 차단할 수 있게 됩니다
우리는 그렇다면 왜 여태 SQL injection을 배웠을까? prepared statement 쓰면 원천 차단 당하는 구조인데
이유는 간단합니다
- 문법을 잘못 쓴 경우 :
개발자들도 사람인지라 코드에 실수를 범할 때가 있어 prepared statement를 잘못 사용해 sqlinjection이 통하는 경우가 생깁니다 - 적용 불가 영역:
테 table 이름, column 이름, cookie 값, order by를 사용하는 경우
특이 odrder by는 정렬 기준을 동적으로 처리하기 위해 사용자 입력을 쿼리에 직접 포함하는 경우가 많기 때문에 이런 위험에 노출될 가능성이 매우 높습니다