<SQLi 가 뭘까?>
SQL 인젝션 이란것이 뭐길레 이렇게 자주 미디어에 보일까?
당장의 저번주 뉴스기사만 보더라도 SQL 인젝션 이라는 단어를 심심치않게 볼수 있다.
대체 무슨 취약점이길레 예로부터 계속 언급이 되는것일까? 이것을 막는법은 없는건가?
오늘 다뤄볼 내용은 이에 대한 내용이 될것이다.
1. SQLi 란?
SQLi 란 SQL Injection 을 칭한다. SQL 인젝션은 웹사이트의 보안허점을 이용해 특정 SQL 쿼리문을 전송하여 공격자가 데이터베이스를 탐색 및 변조를 할 수 있는 공격을 말한다.
로그인페이지 나 게시판 검색창 같은 DB 와 연동된 기능을 하는 부분이 SQL 취약점의 공격 포인트가 되며,
데이터베이스가 직접적으로 공격당하는 만큼 공격위험도 또한 매우 높으므로 주의깊게 살펴볼 이유가 충분하다.
기본적인 원리는 다음과 같다.
[로그인 상황] : 로그인시 이런 SQL 구문이 실행된다.
SELECT * FROM userinfo where id='doldol' and password='dol1234'
그런데 여기서 ID 값으로 doldol' OR '1'='1 를 넣게되면 어떻게 될까?
SELECT * FROM userinfo where id='doldol'or '1'='1' and password='dol1234'
이런식의 SQL 구문이 동작하게 되고 , 연산자 우선순위로 인하여 PASSWORD 가 무엇이든간에 ID 가 doldol 인 정보로
로그인이 가능해진다. 이런식으로 SQL 구문을 조작하는것을 SQL 인젝션이라고 한다.
2. 공격종류
- Error based SQL Injection : 논리적 에러를 이용한 SQL 인젝션 공격
SQL 오류엔 두가지 종류가 있다.
- 문법오류
- 논리오류
문법오류란 ' 같은 것을 빼먹거나 할때 흔히 볼수 있는 에러이며 , 여기서 알아낼 수 있는정보는 없다.
우리가 관심가져야 할 부분은 바로 논리오류이다.
문법적으로 틀리진 않으나 함수 사용이 논리적 에러를 발생시키는 경우이다.
보통 extractvalue(xml_frag,xpath_expr) 함수의 xpath_expr 부분은 '/' 혹은 '@' 으로 시작해야 하는데 여기다가 이렇게 지정된 문자가 아닌 다른 문자 ( ':' , '!') 를 넣어주게 되면 오류가 발생하게 된다.
보시면 MySQL 메시지에 필자가 넣어준 sql 쿼리의 값이 출력이된다.
이 방법은 내장된 함수인 extractvalue 의 XPATH 를 이용한 방법이며 , 만약 SQL 오류창을 클라이언트가 볼수있게 되어있는 홈페이지 라면 이 방법으로 데이터를 추출해낼수 있다.
- Union based SQL Injection : Union 구문을 이용한 SQL 인젝션 공격
<Union 구문에 대한 설명> 은 앞선 게시물에서 참고하겠다.
https://jamesbexter.tistory.com/entry/SQL-UNION-ORDER-BY-LIMIT-LIKE
<게시글 검색기능> 이런 SQL구문으로 동작한다 생각해보자.
SELECT * FROM userinfo where title like '%jain%'
우리가 검색하는 창에 저 jain 이라는 글자가 들어가는것이다. 그러면 저기다 jain 말고
%' union select password from userinfo where id ='jain' -- 이라는 내용을 넣어주게 되면?
SELECT * FROM userinfo where title like '%%' union select password from userinfo where id ='jain' --%'
ID=jain 이라는 사람의 password 정보를 빼낼수가 있다.
※이 Union 기법은 6단계의 절차를 몸에 익혀두면 헷갈리지 않게 진행할 수 있다.
1.SQL Injection 포인트 찾기
=> 이 예시에선 게시글 검색창이 포인트가 된다.
2. column 개수찾기
=> %' order by 1~10 # 이라는 order by 구문을 이용하여 컬럼 개수를 특정시킨다.
3. 출력되는 column 위치 찾기
=>union select 1,2,3,4,5,6 이런식으로 대입해보면 어떤 컬럼의 정보가 어디에 나오는지를 확인할 수 있다.
4. DB 이름확인
=> over%' union select '1',database(),'3','4' # 이런식으로 database() 함수를 이용해 db 이름을 알 수 있다.
5.Table 이름 확인
=>select 1,table_name,3,4 form information_schema.tables where table_schema ='DB이름'
4번 단계에서 확인한 db 명을 가지고 이런식으로 table 의 정보를 얻을수 있으며
6. Column 명 확인
=> select column_name from information_schema.columns where table_name = '테이블이름'
5번 단계에서 확인한 table name 을 가지고 테이블의 column 명을 확인할수 있다.
이런식으로 db,table,column 에 대한 정보를 다 알았으면 union 구문을 이용해 원하는 데이터를 탈취할 수 있게된다.
- Blind SQL Injection(Boolean based SQL) : 참 거짓 스무고개 방식
이 방법은 특정한 데이터를 뽑아낸다기 보단 여러차례 참 거짓문을 시도해보면서 DB 정보를 알아가는 방식입니다.
<로그인 상황>
SELECT * FROM userinfo where id='doldol' and password='dol1234'
<공격 상황>
SELECT * FROM userinfo where id='doldol'
and ASCII(SUBSTR(SELECT name FROM information_schema.tables where table_type='base table' limit 0,1)1,1) > 100
--' and password='dol1234'
SUBSTR 함수를 사용하여 테이블이 USERinfo 라는 이름이라면 , 뒤에 100 이라는 숫자를 바꿔가며 아스키문자값과
비교하는식으로 반복하다가 로그인이 되는 시점을 찾아냄으로써 table 의 이름을 알아갈수있다.
- Blind SQL Injection(Time based SQL) : 시간지연을 통한 정보유추
SQL 에는 SLEEP 이라는 함수가 있습니다.
SLEEP(3) 이런식으로 활용하게 되면 SQL 구문이 동작이 되는데 시간지연이 발생하게 되는데 , 참일 경우에만 시간지연을 발생시키는 방식으로 정보를 유추할수 있게됩니다.
<로그인 상황>
SELECT * FROM userinfo where id='doldol' and password='dol1234'
<공격 상황>
SELECT * FROM userinfo where id='doldol' or (length(database())=1 and sleep(4))'-- and password='dol1234'
=> 이런식으로 DB 이름의 길이를 1부터 증가시켜보면서 만약 시간지연이 발생하게 된다면 그 시점의 길이가 DB 이름의 길이라는 것을 유추할 수 있는 기법입니다.
꼭 DB이름만 알아내기 보다도 로그인 인증방식을 확인할 때 SQL 구문이 잘 들어가고 있나 확인차 사용하기도 좋습니다.
<정리>
>UNION SQLi
: SQL 질의 결과가 화면에 출력되는 경우에 사용!
>Error Based SQLi
: SQL 오류가 화면에 출력되는 경우 사용!
> Blind SQLi
: SQLi 를 시도할 수 있는 상황이면 언제나 사용가능!
<공격 Tip>
> 쿠키조작을 통해서도 SQLi 가 가능하다!
: 쿠키에 있는 변수를 통해 SQL 인젝션 구문이 돌아가는 상황이라면 쿠키를 조작해서 추출이 가능하다.
꼭 로그인창,검색창 같은 입력창이 있어야만 가능한 것은 아니다. Burp Suite 를 잘 이용하자!
> 컬럼이름에 SQL 인젝션이 가능하다!
:만약 SELECT * FROM TABLE WHERE NAME LIKE '%something%' 라는 구문에서
NAME 과 something 이 쿠키나 post 변수로 들어오게되어 입력되는 값이라면,NAME 에다가
(참/거짓 조건절) AND NAME 을 넣어줌으로써 SQLi 를 진행할 수 있다.
꼭 '(single quote) 안에 SQL 구문을 넣어야 한다는 고정관념은 버리자
ex) ('1'='1') and NAME
> SQL 문법중 case when 문법을 사용하여 참/거짓을 판별할 수 있다.
:SQL 문법중엔 if 문 역할을 하는 case when 을 사용하여 의도적으로 에러를 일으켜 Blind SQLi 를 진행해볼수 있다.
예를들어 order by 절 뒤에 case when (조건절) then 1 else (select 1 union select 2) end
=>(조건절) 이 참이면 1 아니면 (select 1 union select 2)의 결과값.
Q. 그냥 else 뒤에 9999 넣으면 거짓일텐데 왜 안넣어주나요?
-> 사이트마다 다르지만 9999넣어도 문자열로 인식하여 order by '9999' 자체가 참이되어 결과가 나오는 경우가 있어서 ,
확실하게 (select 1 union select 2) 를 사용해 행이 2개인 데이터를 뽑아 에러를 일으키는것이 좋습니다.
> 에러 유발 코드 삽입
: 바로 위에 case when 방식을 할때 사용했던 구문과 비슷하다.
SQL = test' and (select 1 union select 2 where (__SQL조건문__)) and '1'='1
이렇게 되면 저 안에 (__SQL조건문__) 이 참이냐 거짓이냐 에 따라 결과가 명확히 나뉘게 됩니다.
3.예방법
그러면 이런 강력한 공격을 어떻게 예방하나?
1. Prepared Statement 구문 사용
=> 이 구문을 사용하게 되면 SQL 구문 파라미터로 집어넣는 과정에서 바로 집어넣는게 아니라 미리 컴파일 하지않고
대기시킵니다. 이렇게 되면 위에 저희가 넣었던 SQL 인젝션 구문들이 파라미터가 아닌 단순 문자열로 인식이 되므로
SQL 공격이 불가능해집니다.
-> 하지만 (order by 절) ,(table 이름) ,(column이름) 이 들어가는 부분에서는 Prepared Statement 로 방어가 불가능 한 경우도 있으므로 SQL 인젝션은 아직까지도 유효한 공격으로 평가되고 있는듯 하다.
2.블랙리스트 작성
=> SQL 인젝션의 사용되는 특수문자,키워드를 금지시키는 방식입니다.
예를들어 위에서 본 UNION,ORDER BY, ; , ' , -- ,# 같은 경우를 입력값의 블랙리스트로 지정해놓으면 SQL 공격으로 부터 안전해 질 수 있습니다.(인증방식에서 개행을 추가하여 주석처리를 방지하는 것도 또 하나의 방법이 될수도 있습니다!)
[참고]
White List Filtering > 특정단어만 쓰게 하는 방식
Black List Filtering > 특정단어만 못쓰게 하는 방식
긴 글 읽어주셔서 감사합니다!
'웹해킹' 카테고리의 다른 글
XSS 공격 대응방안 (0) | 2024.06.30 |
---|---|
XSS(Cross-site scripting)기법 (0) | 2024.06.24 |
File upload vulnerabilities (0) | 2024.01.30 |
SSRF(Server-side request forgery) (0) | 2024.01.29 |
Authentication vulnerabilities (1) | 2024.01.26 |