
非逆コンパイル型iOS/Androidアプリ脆弱性スキャナー (DC25 demo lab, CB17)
trueseeing は、iOS/Android アプリ向けの高速で正確かつ堅牢な脆弱性スキャナーです。Android では Dalvik VM レベルで動作するため、ターゲットアプリが難読化されているかどうかは問いません。
現在以下のことが可能です:
注:
すぐに使用できるコンテナを提供しています。以下は推奨される方法であり、Windows 上で実行する唯一の方法です:
$ docker run --rm -v $(pwd):/out -v ts2:/cache ghcr.io/alterakey/trueseeing
ステートレスに実行したい場合は、/cache へのボリュームマウントを省略します (日常的な使用には推奨しません。また #254 も参照):
$ docker run --rm -v $(pwd):/out ghcr.io/alterakey/trueseeing
または、uv を使用してパッケージをインストールすることもできます。特に uv tool install 形式のインストールは拡張機能 (後述) に役立ち、最大の自由度を与えます。ただし、JRE と (オプションでデバイスを操作するための) Android SDK が必要です。
$ uvx trueseeing
$ uv tool install trueseeing
$ trueseeing
もちろん、従来の pip を使用することもできます:
$ pip install trueseeing
アプリを対話的にスキャン/解析/パッチ適用などができるため、手動解析に最適です:
$ trueseeing target.apk
[+] trueseeing x.y.z
ts[target.apk]> ?
...
ts[target.apk]> i # 一般的な情報を表示
...
ts[target.apk]> pf AndroidManifest.xml # マニフェストファイルを表示
...
ts[target.apk]> a # リソースも解析
...
ts[target.apk]> /s something # テキスト検索
...
ts[target.apk]> as # スキャン
...
[+] done, found 6403 issues (174.94 sec.)
ts[target.apk]> gh report.html
プロンプトが表示される前に実行するインラインコマンド (-c) またはスクリプトファイル (-i) を受け付け、またプロンプトを表示せずにすぐに終了することもできます (-q; このモードでは tty は不要です!)。
これらの機能を使用してバッチスキャンを実行できます。例えば、結果を stderr に直接出力するには:
$ trueseeing -eqc 'as' target.apk
HTML 形式のレポートファイルを生成するには:
$ trueseeing -eqc 'as;gh report.html' target.apk
JSON 形式のレポートファイルを生成するには:
$ trueseeing -eqc 'as;gj report.json' target.apk
レポートを stdout に出力するには、最後の g* コマンドでファイル名を省略します:
$ trueseeing -eqc 'as;gh' target.apk > report.html
$ trueseeing -eqc 'as;gj' target.apk > report.json
従来は、以下のコマンドラインでアプリをスキャンし、結果を stderr に一覧表示できました:
$ trueseeing --scan target.apk
HTML 形式のレポートを生成するには:
$ trueseeing --scan --scan-output report.html target.apk
$ trueseeing --scan --scan-report=html --scan-output report.html target.apk
JSON 形式のレポートを生成するには:
$ trueseeing --scan --scan-report=json --scan-output report.json target.apk
レポートを stdout に出力するには、ファイル名として '-' を指定します:
$ trueseeing --scan --scan-output - target.apk > report.html
$ trueseeing --scan --scan-report=html --scan-output - target.apk > report.html
$ trueseeing --scan --scan-report=json --scan-output - target.apk > report.json
独自のコマンドやシグネチャを拡張機能として記述できます。拡張機能は /ext (コンテナ) または ~/.trueseeing2/extensions/ (uv/pip) に配置します。また、拡張機能を wheel として配布することもできます。型情報を提供しているため、zuban で型チェックを行うだけでなく、IDE からの十分な支援も受けられます。詳細については、詳細セクションを参照してください。
以下のようにビルドできます:
$ docker build -t trueseeing https://github.com/alterakey/trueseeing.git#main
wheel をビルドするには、flit を使用します:
$ flit build
ハックするには、適切なビルド環境を作成する必要があります。uv を使用する場合:
$ git clone https://github.com/alterakey/trueseeing.git wc
$ uv sync --locked --dev
$ (... ハック ...)
$ uv run trueseeing ... # 実行
$ uv run zuban check trueseeing && uv run ruff trueseeing # 検証
Success: no issues found in XX source files
$ uv run flit build # ビルド (wheel)
$ docker build -t trueseeing . # ビルド (コンテナ)
pip を使用する場合、まず venv をセットアップし、flit と検証ツールチェーン (zuban と ruff) をインストールし、flit で依存関係をプルします。簡単に言うと:
$ git clone https://github.com/alterakey/trueseeing.git wc
$ python3 -m venv wc/.venv
$ source wc/.venv/bin/activate
(.venv) $ pip install flit zuban ruff
(.venv) $ flit install --deps=develop -s
(.venv) $ (... ハック ...)
(.venv) $ trueseeing ... # 実行
(.venv) $ zuban check trueseeing && ruff check trueseeing # 検証
Success: no issues found in XX source files
(.venv) $ flit build # ビルド (wheel)
(.venv) $ docker build -t trueseeing . # ビルド (コンテナ)
現在、以下の脆弱性クラスを検出できます。主に OWASP Mobile Top 10 - 2016 でカバーされているものです:
プラットフォームの不適切な使用 (M1)
安全でないデータ (M2)
安全でない通信 (M3)
不十分な暗号化 (M5)
クライアントコードの品質問題 (M7)
コード改ざん (M8)
リバースエンジニアリング (M9)
拡張 API は trueseeing.api パッケージの下にあります。型情報が提供されているため、拡張機能の作成時に IDE が支援します。IDE (またはその言語サーバー) の PYTHONPATH が、当パッケージが存在する venv をカバーしていることを確認してください。uv tool install でインストールした場合は uv tool list --show-paths を参照してください。uvx でインストールした場合は、uvx install で再インストールを検討してください。pip でインストールした場合は、その場所は既におわかりでしょう。
新しいコマンドを定義するには、trueseeing.api.Command を実装し、広告します。
以下のクラスは、サンプルコマンドとして t を提供します:
from typing import TYPE_CHECKING
from trueseeing.api import Command
from trueseeing.core.ui import ui
if TYPE_CHECKING:
from trueseeing.api import CommandMap, CommandPatternMap, ModifierMap, OptionMap, ConfigMap
class MyCommand(Command):
@staticmethod
def create() -> Command:
return MyCommand()
def get_commands(self) -> CommandMap:
return {'t':dict(e=self._test, n='t', d='sample command')}
def get_command_patterns(self) -> CommandPatternMap:
return dict()
def get_modifiers(self) -> ModifierMap:
return dict()
def get_options(self) -> OptionMap:
return dict()
def get_configs(self) -> ConfigMap:
return dict()
async def _test(self) -> None:
ui.info('hello world')
新しいシグネチャを定義するには、trueseeing.api.Signature を実装し、広告します。
以下のクラスは、サンプル検出器として my-sig を提供します:
from typing import TYPE_CHECKING
from trueseeing.api import Signature
if TYPE_CHECKING:
from trueseeing.api import SignatureMap, ConfigMap
class MySignature(Signature):
@staticmethod
def create() -> Signature:
return MySignature()
def get_sigs(self) -> SignatureMap:
return {'my-sig':dict(e=self._detect, d='sample signature')}
def get_configs(self) -> ConfigMap:
return dict()
async def _detect(self) -> None:
self._helper.raise_issue(
self._helper.build_issue(
sigid='my-sig',
title='hello world',
cvss='CVSS:3.0/AV:P/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:N/',
)
)
新しいファイル形式を定義するには、まず形式の Context (ABC) を実装し、次に trueseeing.api.FileFormatHandler を実装してそのインスタンスを作成して返し、広告します。
以下のクラスは、apk2 という名前のタイプで APK ファイルサポートを提供します:
from typing import TYPE_CHECKING
from trueseeing.api import FileFormatHandler
from trueseeing.core.android.context import APKContext
if TYPE_CHECKING:
from typing import Optional, Set
from trueseeing.api import FormatMap, ConfigMap
from trueseeing.core.context import Context, ContextType
class MyAPKContext(APKContext):
# 異なるコンテキストタイプを使用
def _get_type(self) -> Set[ContextType]:
return {'apk2'}
class APKFileFormatHandler(FileFormatHandler):
@staticmethod
def create() -> FileFormatHandler:
return APKFileFormatHandler()
def get_formats(self) -> FormatMap:
return {'apk2':dict(e=self._handle, r=r'\.apk$', d='sample file format', t=None)} # このハンドラがデバイスコンテキストタイプを提案できる場合は t に広告
def get_configs(self) -> ConfigMap:
return dict()
def _handle(self, path: str) -> Optional[Context]:
return MyAPKContext(path)
次に、シグネチャ内でコンテキストのタイプをチェックし、サポートされていないコンテキストでは無視されるようにします:
context = self._helper.get_context().require_type('apk2')
チェックが成功すると、require_type(...) は便利なように適切なタイプにダウンキャストしようとします。
ただし、設計上、既知のタイプ (現在は apk) でのみ機能します。そのため、apk タイプと同様に新しいコンテキストクラスに詳細なインターフェースを定義している場合、ここでダウンキャストを行う必要があります:
context: MyAPKContext = self._helper.get_context().require_type('apk2') # type:ignore[assignment]
同じパターンに一致する複数の形式を定義することは可能です。パターンは最も厳密 (すなわち長い) なものから最も緩いものの順に評価します。-F スイッチを使用して、ターゲットファイルに特定の形式を強制できます:
$ trueseeing -F apk2 target.apk
拡張機能は、a) /ext (コンテナ) または ~/.trueseeing2/extensions (pip) に配置された任意のパッケージ、または b) 接頭辞 trueseeing_ext0_ で命名されたインストール済みモジュールのいずれかです。
D&D の呪文、True Seeing です。