2023年第4回福建省「福建楯杯」~ブラックシールドトラック~オンライン予選からオフライン決勝まで~WriteUp
目次
0x00 序文
今年はブラックシールドカップが全国トラックに変更され、職業別と学部別の出題も変わりましたし、今年はオフラインでたくさんの友達に会い、たくさんの新しいマスターと知り合うことができました。お世話になりありがとうございました。オフライン部分 wp すべての良き友人とマスターから、ここに AhiSec と F5n のマスターに特別な感謝を送ります。
0x01 予選ラウンド
昨年の予選と比べ、理論問題だけでなくCTF問題も数問出題され、理論問題は依然として各種法律問題が多かった
CTFは通常の雑貨やWebなど。
1.1 DNSトラフィック分析
データ パケットを開くと、明らかな圧縮パケット ヘッダー 504b が表示されます。ここではこれが圧縮パケットであると推測されます。
まず要求されたデータをフィルタリングして除外し、次に名前部分をエクスポートします。
dns and ip.dst==192.168.50.1
ドメイン名部分を削除してプレフィックス部分だけを残してzipとして保存すると、暗号化された圧縮パッケージであることがわかりました
次に、パスワード Ap3l を取得します。
1.2 1シェル
ディレクトリをスキャンして 1.php を取得し、ツールを使用してパスワードを爆破します。ここでのパスワードは aj で、起動するたびに異なります。
接続してフラグを取得
1.3 マイログ
mysql のバイナリ ファイルの場合は、mysqlbinlog を使用して kali で SQL ステートメントを取得します。
次に、その中で f1ag を検索して、キーとなる SQL ステートメントを取得します。
ここではdatabase()を使用していますが、ここでcreatedatabaseを検索すると、ライブラリ名がBlack Shieldであることがわかります。
これらのステートメントを実行した結果は不完全であり、FLAG が flag に置き換えられていることがわかりますが、挿入にはフラグがありません。
ここで F14g を検索すると、ここに flag{ が挿入されていることがわかります (手動で FLAG{ を追加することも可能です)
最後に、ステートメントを取得し、データベース内で実行してフラグを取得します。
CREATE DATABASE `heidun` DEFAULT CHARACTER SET utf8;
CREATE TABLE `heidun`.`f1ag` (
`Id` int(11),
`data` varchar(50) default NULL
);
use heidun;
insert into f1ag values (1,'FLAG');
insert into f1ag values (null,'{');
insert into f1ag values(null,'heidun');
insert into f1ag values(null,'_');
insert into f1ag values(null,year(now()));
insert into f1ag values(null,'_');
insert into f1ag values(null,database());
insert into f1ag values(null,']');
update f1ag set data=replace(data,'_','-');
update f1ag set data=replace(data,']','}');
update f1ag set data=replace(data,'FLAG','flag');
select replace(group_concat(data),',','') from f1ag ;
0x02 再戦
準決勝での CTF の質問 10 問
2.1 脅威インテリジェンス分析 1
2 つの txt が指定され、1 つはアクセスされた IP またはドメイン名、もう 1 つは悪意のあるアドレスでした。
アクセスログと脅威インテリジェンス
まず、ioc ファイルを抽出し、ファイルの先頭と末尾にある [] を削除し、それを最後の行に追加し、スクリプトを使用して ioc フィールドを抽出します。
for i in open(r'ioc.txt',encoding="UTF-8"):
print(eval(i[:-2]).get("ioc",''))
次に、ファイルの先頭と末尾にある [] を削除して最終行に追加し、アクセスされた URL を抽出するようにスクリプトを変更します。
for i in open(r'network.txt',encoding="UTF-8"):
print(eval(i[:-2]).get("DestHost",''))
次に、コマンドを使用して同じ行を抽出し、答え 46.21.82.234 を取得します。
sort okioc.txt oknet.txt | uniq -d
2.2QZ
予想外の解決策
strings 镜像 | grep Zxm
Base64デコードでフラグを取得
2.3 Py 数学ゲーム
ポートを開いた後、NC 接続は情報が返されたことを検出し、算術問題は 3 秒以内に完了する必要があります。
Python ソケットを使用して接続し、計算を完了して送信すると、バックエンドが eval を使用して渡した値を受け取ることができることがわかりました。
os.popen('cat flag.txt').readline()
成功した読み取りをフラグに渡します
スクリプトにはスクリーンショットのみが含まれています
2.4 パイパス
ソースコード
from flask import Flask, request, Response
import os
import shutil
import site
app = Flask(__name__)
@app.route('/')
def index():
return app.send_static_file('index.html')
@app.route('/upload', methods=['POST'])
def upload():
f = request.files["data"]
with open(f'/tmp/storage/{f.filename}', 'wb+') as destination:
destination.write(f.read())
return Response("File is uploaded!", 200)
@app.route('/install', methods=['GET'])
def install():
package_name = request.args.get('package_name')
if '..' in package_name:
return Response("Not allowed!", 400)
src = os.path.join('contrib', 'packages', package_name)
dst = os.path.join('/tmp/extract', package_name)
shutil.copy(src, dst)
shutil.unpack_archive(dst, extract_dir='/tmp/extract')
return Response("Installed!", 200)
@app.route('/clean', methods=['GET'])
def clean():
file = os.path.basename(request.args.get('file'))
file_safe = f'/tmp/storage/{file}'
os.unlink(file_safe)
return Response("file removed!", 200)
@app.route('/add', methods=['GET'])
def add():
site_dir = "/tmp/extract"
name = request.args.get('name')
site.addpackage(site_dir, name, None)
if __name__ == "__main__":
app.run(debug=True, host='0.0.0.0')
デフォルトでは、upload メソッドは /tmp/storage/ を制限なくディレクトリに転送します。ディレクトリを横断することができます。add メソッドは /tmp/extract ディレクトリです。ここでは、最初に add メソッドのディレクトリにアップロードされます。コンテンツはdnslogを通じて取り出される情報です。
メソッドの追加時にトリガーされます
dnslog 受信フラグ
0x03 オフライン決勝
今年のオフライン決勝では携帯電話の回収が始まり、大会が始まると手机交上去
オンラインかどうか後ろを巡回する人がいて、質問数も昨年より増えています。
3.1 タスク 1
合計4つの質問
使用する onenav のバージョンは v0.9.12-20210726 ダウンロードアドレス https://github.com/helloxz/onenav
3.1.1 タスク 1 の最初の質問
バックアップファイルからconfig.simple.php
アカウントのパスワードを取得する
バックエンドにログインしてフラグを確認してください
3.1.2 タスク 1 の質問 2
プロンプト データベースは非常に小さい
バックアップ ファイルからデータベース パスを確認し、ダウンロードにアクセスしてdata/onenav.db3
開くと、フラグが表示されます。
3.1.2 タスク 1 の質問 3
Fscan スキャンで CVE-2012-1823 が見つかりました
次に、Web ディレクトリ内の cat flag.php
3.1.2 タスク 1 の質問 4
プロンプト キャッシュ データベース、ここでは 6379 が開いています、つまり Redis
Redis 構成ファイルに移動してパスワードを取得し、接続すると、多数のキーがあることがわかります。
flag の 4 つのキーの値をそれぞれ確認すると、内部の Base64 の復号化と結合によってフラグを取得できます。
3.2 タスク 2
問題はjava_web、使用プログラムはofcmsで、こちらも4問あります。
3.2.1 タスク 2 の質問 1
管理者 123456 ログイン
次に、F12 で flag1 のカテゴリの下に flag1 を見つけます。
3.2.2 タスク 2 の 2 番目の質問
tomcat tomcat tomcat に直接ログインする
WebShell に war パッケージをデプロイする
シェルで suid 権限の昇格を試したところ、ファイルの読み取りに使用できる権限が少ないことがわかり、pkexec が CVE-2021-4043 を思い出させました。
ここで簡単な注意事項を示します。ssh アカウント ubuntu パスワード 123456 に直接移動し、POC に移動して、ルート ディレクトリにある FI@G_2 ファイルを読み取る権限を昇格します。
3.2.3 タスク 2、質問 3
設定ファイルを見つけてデータベース アカウントのパスワードを取得する root ツール
次にデータベースに接続し、クエリを実行して flag3 を取得します。
3.2.4 タスク 2 の質問 4
ルートディレクトリに fLog_4 があります
3.3 タスク 3
質問のタイトルは、イントラネットの侵入に使用されているシステムはドリーマー cms であるというものです。質問は全部で 7 つありますが、最初の質問は 0 です。写真が完全に切り取られていないため、ここのフラグは必ずしも正しい位置にあるとは限りません。試合後はどっちがどっちだか忘れてしまったので、順番が少し違うかも知れません。
脆弱性の詳細リンク: https://forum.butian.net/share/2183
3.3 タスク 3 の質問 0
ホームページには、復号化された admin888 である Base64 でエンコードされたコードがあります。
管理者 admin888 ログイン
次に編集許可位置のフラグを取得します
3.3 3番目のタスク? 質問
添付ファイルに読み取るファイルがある場合は、ルート ディレクトリ フラグを読み取ります
それからダウンロードしてください
3.3.x ミッション 3? 質問
データベースをバックアップし、データベース ファイルを読み取ってフラグを取得します。
3.3.x ミッション 3? 質問
スケジュールされたタスクを記述してシェルをリバウンドし、フラグを確認します。
3.4 タスク 4
ファイアウォールのログを考慮した 4 つの質問
3.4.1 タスク 4 の質問 1
合計で IP 数がいくつあるかを確認するには、39 ips を取得しました
cat FwLog.txt |cut -d ',' -f 2 | sort | uniq -c |grep "sa" | wc -l
3.4.2 タスク 4 の質問 2
ここでは、スキャナーのみがこの種のファイルにアクセスし、IP を 1 回送信するため、bak.php を検索しました。
3.4.3 タスク 4 の質問 3
ブラストIPを調べるには
ログを見ると、爆発の特徴は /webfire/portal/sp/login.php?loginFailed=1&error=user_password_incorrect であることがわかります。
user_password_incorrect を含む IP を見つけるための直接スクリプトは次のとおりです。
import re
pattern = r"sa=(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})"
count = {}
with open(r"FwLog.txt",encoding='utf-8') as f:
for line in f:
if "user_password_incorrect" in line:
ip = re.search(pattern, line).group(1)
if ip in count:
count[ip] += 1
else:
count[ip] = 1
for ip, freq in count.items():
print(ip, freq)
それを並べ替えると、答えは 10_6_4_4_2_2 になります。
3.4.4 タスク 4 の質問 4
ssrf の IP を見つけて http を検索して 192.168.80.1 を取得します。
3.5 タスク 5
1 つのログと 1 つのトラフィック分析
3.5.1 タスク 5 の質問 1
データ量が多すぎるためまだ実行されていません
3.5.2 タスク 5 の質問 2
それを開くと、SQL インジェクション トラフィックであることがわかります。
ここでは、sbustrings によって取得された特定の数字の最後に判定された文字 (より成功した文字) を取り出す必要がありますが、ここではトラバーサルを使用しているため、成功した文字に到達すると停止します。
たとえば、ここでの 1 の最後の比較は 102 であり、次に 2 桁目は 102 と判断され、ASCII 文字 f に変換されます。
ここでスクリプトを直接抽出します
import re
with open("misc.pcapng", "rb") as f:
contents = f.read()
res = re.compile(r'0,1\),(\d+),1\)\)=(\d+)%23').findall(str(contents))
dic = {}
for a, b in res:
if a in dic:
if int(b) > dic[a]:
dic[a] = int(b)
else:
dic[a] = int(b)
flag = ""
for i in range(1,39):
flag += chr(dic[str(i)])
print(flag)
3.6 タスク 6
トロイの木馬検出に関する 2 つの質問
質問の説明
3.6.1 タスク 6 の質問 1
Webシェルのパスはsha1でエンコードして送信する必要があります。
システムに直接アクセスし、Web をパッケージ化し、d-shield でスキャンすると、最終的に 2 つのトロイの木馬がスキャンされます。
これが最初のものです。ファイルへのパスを書き込み、次に sha1sum
3.6.2 タスク 6 の 2 番目の質問
Webシェルを無効にして5分ごとにチェックする必要があると言われています。
ここでは、スキャンされた 2 つのシェルを削除することを選択し、シークレットを確認するために 5 分間待ちます。
3.7 タスク 7
ファイアウォール上で動作し、アカウントに管理者パスワード abc12345 を与えることになります。
3.7 タスク 7 の質問 1
ドメイン名を送信する必要があります
これは、基本ポリシー -> アプリケーションコンテンツ -> HTTP 特性で確認できます。
3.7 タスク 7 の質問 2
ここでは、基本的なポリシー設定 -> アドレス変換 -> 宛先アドレス変換 -> Web4 IP+ポートの送信を行います。
0x04 最終スコア
4.1 学部グループ
4.2 高等職業グループ
元リンク: 2023年福建省第4回「福建楯杯」 - Black Shield Track - オンライン予選からオフライン決勝まで - WriteUp