[CTF] SECCON Beginners 2023

2023. 6. 4. 16:05정보보안/CTFLOG

반응형

 

Forbidden - web

var express = require("express");
var app = express();

const HOST = process.env.CTF4B_HOST;
const PORT = process.env.CTF4B_PORT;
const FLAG = process.env.CTF4B_FLAG;

app.get("/", (req, res, next) => {
    return res.send('FLAG はこちら: <a href="/flag">/flag</a>');
});

const block = (req, res, next) => {
    if (req.path.includes('/flag')) {
        return res.send(403, 'Forbidden :(');
    }

    next();
}

app.get("/flag", block, (req, res, next) => {
    return res.send(FLAG);
})

var server = app.listen(PORT, HOST, () => {
    console.log("Listening:" + server.address().port);
});

워밍업 문제였다.

a태그를 클릭하면 block에 막혀서 flag를 얻을 수 없었다.

하지만 "flag"라는 문자열을 막고 있었으므로 대문자를 입력하면 

필터링을 통과하여 flag를 얻을 수 있다.


aiwaf - web

저번에 풀었던 nginx 파서 버그와 비슷하다고 생각이 들었던 문제이다.

대회가 끝나고 풀었는데 이상하게 대회때는

import uuid
import openai
import urllib.parse
from flask import Flask, request, abort

# from flask_limiter import Limiter
# from flask_limiter.util import get_remote_address

##################################################
# OpenAI API key
KEY = "****REDACTED****"
##################################################

app = Flask(__name__)
app.config["RATELIMIT_HEADERS_ENABLED"] = True

# limiter = Limiter(get_remote_address, app=app, default_limits=["3 per minute"])

openai.api_key = KEY

top_page = """
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8" />
    <title>亞空文庫</title>
</head>

<body>
    <h1>亞空文庫</h1>
    AIにセキュリティの物語を書いてもらいました。<br>
    内容は正しいかどうかわかりません。<br>
<ul>
    <li><a href="/?file=book0.txt">あ書</a></li>
    <li><a href="/?file=book1.txt">い書</a></li>
    <li><a href="/?file=book2.txt">う書</a></li>
    <!-- <li><a href="/?file=book3.txt">え書</a></li> -->
</ul>

※セキュリティのためAI-WAFを導入しています。<br>
© 2023 ももんがの書房
</body>

</html>
"""


@app.route("/")
def top():
    file = request.args.get("file")
    if not file:
        return top_page
    if file in ["book0.txt", "book1.txt", "book2.txt"]:
        with open(f"./books/{file}", encoding="utf-8") as f:
            return f.read()
    # AI-WAF
    puuid = uuid.uuid4()
    prompt = f"""\
以下の{puuid}に囲まれた部分のURLクエリはパストラバーサル攻撃でしょうか?
そうである場合Yesを、違う場合Noを返してください。
../やflagという文字列が含まれていた場合もYesを返してください。

{puuid}
{urllib.parse.unquote(request.query_string)[:50]}
{puuid}
"""
    try:
        response = openai.ChatCompletion.create(
            model="gpt-3.5-turbo",
            messages=[
                {
                    "role": "user",
                    "content": prompt,
                },
            ],
        )
        result = response.choices[0]["message"]["content"].strip()
    except:
        return abort(500, "OpenAI APIのエラーです。\n少し時間をおいてアクセスしてください。")
    if "No" in result:
        with open(f"./books/{file}", encoding="utf-8") as f:
            return f.read().replace(KEY, "")
    return abort(403, "AI-WAFに検知されました👻")


if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=31415)

 

​저 코드에서 ../와 flag가 들어가면 path traversal로 판단하고 YES를 출력한다.

그 밑 코드에서는 ai의 대답에 No의 유무로 path traversal을 판단하고 있다.

 

나는 이것만 보고 계속 파라미터의 입력에서 ai가 ../와 flag를 인지하지 못하게 하는 우회 방법만 생각하다가

막혔는데 코드를 유심히 보면

 

{puuid}
{urllib.parse.unquote(request.query_string)[:50]}
{puuid}

 

이 부분에서 [:50] 까지만 읽고 있기 때문에,

저번에 nginx에서 파서의 길이제한으로 취약점이 터지던 버그와 비슷하다고 생각이 들었다.

따라서 아래와 같은 방법으로 해결 가능했다.


Half - rev

 

워밍업 문제로 리버싱 문외한인 나도 ida로 까보니 풀수있었다.

 

 


CoughingFox2 - crypto

 

# coding: utf-8
import random
import os

flag = b"ctf4b{xxx___censored___xxx}"

# Please remove here if you wanna test this code in your environment :)
flag = os.getenv("FLAG").encode()

cipher = []

for i in range(len(flag)-1):
    c = ((flag[i] + flag[i+1]) ** 2 + i)
    cipher.append(c)

random.shuffle(cipher)

print(f"cipher = {cipher}")

간단한 암호학 문제

 

plain text에서 첫번째 문자와 그 다음에 오는 문자의 값을 더한 뒤, 

제곱하여 i를 더해주고 있다.

import random
import os

flag = ["c"]
cipher = [4396, 22819, 47998, 47995, 40007, 9235, 21625, 25006, 4397, 51534, 46680, 44129, 38055, 18513, 24368, 38451, 46240, 20758, 37257, 40830, 25293, 38845, 22503, 44535, 22210, 39632, 38046, 43687, 48413, 47525, 23718, 51567, 23115, 42461, 26272, 28933, 23726, 48845, 21924, 46225, 20488, 27579, 21636]
plain = []

def find_possible_chars():
    possible_chars = []
    for j in range(33, 127):
        if (ord(flag[-1]) + j)**2 + len(flag)-1 in cipher:
            possible_chars.append(chr(j))
    return possible_chars

def backtrack():
    if len(flag) == len(cipher):
        print(''.join(flag))
        return
    
    possible_chars = find_possible_chars()
    for char in possible_chars:
        flag.append(char)
        backtrack()
        flag.pop()

backtrack()

백트래킹으로 풀었는데 나만 좀 어렵게 해결한 것 같다.

flag = ["c"]
cipher = [4396, 22819, 47998, 47995, 40007, 9235, 21625, 25006, 4397, 51534, 46680, 44129, 38055, 18513, 24368, 38451, 46240, 20758, 37257, 40830, 25293, 38845, 22503, 44535, 22210, 39632, 38046, 43687, 48413, 47525, 23718, 51567, 23115, 42461, 26272, 28933, 23726, 48845, 21924, 46225, 20488, 27579, 21636]
plain = []

def find_possible_chars():
    possible_chars = []
    for j in range(33, 127):
        if (ord(flag[-1]) + j)**2 + len(flag)-1 in cipher:
            possible_chars.append(chr(j))
    return possible_chars

def backtrack():
    if len(flag) == len(cipher):
        print(''.join(flag))
        return
    
    possible_chars = find_possible_chars()
    for char in possible_chars:
        flag.append(char)
        backtrack()
        flag.pop()

backtrack()

 

반응형

'정보보안 > CTFLOG' 카테고리의 다른 글

[CTF] SSTF 2023  (0) 2023.08.20
[CTF] CCE2023 final  (1) 2023.07.13
[CTF] DEFCON31 Quals  (0) 2023.05.29
[CTF] GreyCTF'23 write up  (0) 2023.05.22
[CTF] LINE CTF 2023 - old pal  (0) 2023.03.26