Compact
true
担当領域:リスクハンティング
主にネットワークセキュリティ製品・サービスの開発に従事してきたが、最近はCTFに取り組んできた経験を活かし、ペネトレーションテスト、脆弱性診断などの領域にも仕事の範囲を拡大中。 2013年にnoraneco という社会人CTF チームを立ち上げ、現在は主にPwn/Reversing 問を担当。 SANS - Cyber Defense NetWars 2019.10 1位(Team) SECCON 2019 国際決勝5位 Hack The Box - Omniscient

今回は、生成AIを使ってセキュリティの検査作業を自動化できるオープンソースのツール「PentAGI」を紹介します。PentAGIでできることや、利用時に確認すべきポイントなどを記載します。

注意

本ブログは、ツールの仕組みを理解し、防御に役立てることを目的としています。本ブログで紹介するツールを試すときは、ご自身で管理する環境か、管理者から明示的に許可を得た環境だけで行ってください。内容は筆者が独自に調査したものですが、すべてが正確・最新であることを保証するものではありません。本ブログの内容を使用したことによって生じた不利益等について、筆者および所属組織は一切の責任を負いません。

1
1

PentAGIとは

PentAGIは、生成AIを使ってペネトレーションテストを自動で進めることができるオープンソースソフトウェア(OSS)です[1]。セキュリティ企業のVXControl[2]が開発し、GitHubでMITライセンスのもと公開されています[3]。

テストの対象と目的を言葉で伝えると、複数のAIエージェントが役割を分担し、次のような流れでテストを自律的に進めてくれます。

  1. 情報収集:どんなサーバか、どのポートが開いているかを調べる
  2. 調査:弱点の候補を探す
  3. 確認:本当に悪用できる弱点かを確かめる
  4. 報告:結果をレポートにまとめる

商用のEnterprise版もあり、報告書のテンプレート、DOCX形式での出力機能、商用サポートなどが追加されるようです[4]。

PentAGIの主な特徴を以下に記載します。

PentAGIのインストール

Dockerを用いてインストールする手順を紹介します。

動作要件は次の通りです[7]。

動作検証で使用した環境は次の通りです。

header-row-bg
left
center
30
70
項目
1
1
環境
1
1
OS
1
1
Ubuntu 24.04 LTS
1
1
CPU
1
1
AMD Ryzen 9 7950X3D
1
1
メモリ
1
1
128GB
1
1
GPU
1
1
NVIDIA GeForce RTX 4080 SUPER
1
1
GPUメモリ(VRAM)
1
1
16GB
1
1

なお、本記事でインストールするPentAGIのバージョンは v2.2.0-ce です。

Docker EngineとDocker Composeが利用できる状態を前提とします。Docker自体の導入は、Ubuntu向けの公式手順を参照してください[8]。

公式には対話形式のインストーラも用意されていますが、内部構造、設定ファイルなどを含め全体を把握しながら進めたいと考えて、Docker Composeによる手動導入を行うことにしました。

次の手順でPentAGIをインストール・起動することができます。

dockerコマンドの実行について

以降sudoコマンドなしで docker コマンドを実行していますが、実行するには、dockerコマンドを実行するユーザを予めdocker グループに追加しておく必要があります。

1
1

1.  PentAGIのソースコードを取得します。

git clone https://github.com/vxcontrol/pentagi.git
cd pentagi
1
1

2.  標準のComposeファイルが参照する設定ファイルを用意します。使わないプロバイダの分も含め、3つとも配置が必要になります。

cp examples/configs/custom-openai.provider.yml example.custom.provider.yml
cp examples/configs/ollama-llama318b.provider.yml example.ollama.provider.yml
cp examples/configs/bedrock.provider.yml example.bedrock.provider.yml
1
1

3.  設定ファイルを配置します。

cp .env.example .env
1
1

4.  設定ファイル.env を編集します。このファイルには、接続先や認証情報を記述します。主に確認する項目は次のとおりです[7]。

header-row-bg
left
center
30
70
項目
1
1
設定内容
1
1
LLMプロバイダの設定
1
1
利用するAIサービスやモデルサーバの接続先・認証情報
1
1
PUBLIC_URL
1
1
利用者がブラウザで開くPentAGIのURL
1
1
CORS_ORIGINS
1
1
クロスオリジンリクエストを許可するオリジン
1
1
COOKIE_SIGNING_SALT
1
1
ログイン状態の保護に使う値
1
1
データベースのパスワード
1
1
データベースに接続するための認証情報
1
1

一旦、LLMプロバイダの設定を次の通り行います。

OPEN_AI_KEY=sk-proj-(省略: 適宜ご自身で取得したAPI KEYに置き換えてください)
OPEN_AI_SERVER_URL=https://api.openai.com/v1
(省略)
OLLAMA_SERVER_URL=http://192.168.1.48:11434
OLLAMA_SERVER_API_KEY=ollama
OLLAMA_SERVER_MODEL=gpt-oss-20b-64k:latest
1
1

※ OLLAMA_SERVER_MODELとして指定しているgpt-oss-20b-64kは、gpt-oss:20bのコンテキスト長をOllamaで64kに拡張したモデルです。 Ollamaはホスト側(192.168.1.48)で動かしています。適宜環境に合わせてIPアドレス部分を変更してください。外部から接続できるようにするため、Ollamaの起動時に環境変数OLLAMA_HOST=0.0.0.0やOLLAMA_ORIGINS=172.17.0.* を設定しています。Ollamaには認証機能がないため、信頼できるネットワーク内だけで使うようにしてください。

あわせて、推測されやすい初期値になっている以下の項目も、初回起動の前に変更しておきます。ランダムな文字列は、たとえばコマンド `openssl rand -hex 32` で作れます。

データベースのパスワードは初回起動時に保存されるため、起動後に変更しても反映されない点に注意してください。その他の項目はデフォルト値のまま進めます。

5.  手順4での設定後、次のコマンドでコンテナを起動して状態を確認します。

docker compose up -d
docker compose ps
1
1

コマンド`docker compose ps` で、各コンテナの STATUS が Up(または healthy)になっていれば起動に成功しています。

6.  Webブラウザを起動して https://localhost:8443にアクセスします。
自己署名証明書を使っているため、ブラウザに警告が表示されます。自分で起動したサーバであれば、そのまま進めていただいて問題ありません。ログイン画面にアクセスできたら起動成功です。

図 1. ログイン画面
100

7. 初期アカウント「admin@pentagi.com」、初期パスワード「admin」でログインして、最初にパスワードを変更します。

left
100
80
.env を変更したとき
次のコマンドで設定を反映できます。設定が変わったコンテナのみが自動で作り直されます。
docker compose up -d
1
1

標準の docker-compose.yml では、主に次のコンテナがホストにポートを公開します。いずれも既定では 127.0.0.1(localhost)にバインドされます。

header-row-bg
center
20
20
60
ポート
1
1
コンテナ名
1
1
役割
1
1
8443/tcp
1
1
pentagi
1
1
Web UI と REST/GraphQL API
1
1
5432/tcp
1
1
pgvector
1
1
PostgreSQL + pgvector(データ・ベクトルの保存)
1
1
9187/tcp
1
1
pgexporter
1
1
PostgreSQLのメトリクス出力(監視用)
1
1
9443/tcp
1
1
scraper
1
1
内蔵ブラウザ(スクレイパー)へのアクセス用
1
1

検証用やられサーバの起動

「やられサーバ」とは、攻撃手法・防御手法を学ぶために、意図的に脆弱性を持たせたシステムのことです。PentAGIがこれらの弱点を見つけられるかを試します。

今回は、次の4つの問題を順番につなげて侵入できる「やられサーバ」を用意しました。侵入後に管理者権限まで奪える、という流れを再現しています。

header-row-bg
center
20
40
40
ID
1
1
問題
1
1
悪用される流れ
1
1
a
1
1
認証情報をコマンドライン引数で平文指定したプロセスが常駐している
1
1
プロセス一覧に、ユーザID・パスワードがそのまま見える
1
1
b
1
1
SNMP(v1/v2c・コミュニティ名public)でプロセス一覧を外部から取得できる
1
1
ネットワーク越しに a の認証情報を読み取れる
1
1
c
1
1
SSHサーバが起動しており、パスワードを用いた認証が許可されている
1
1
b で得た認証情報でリモートからssh接続できる
1
1
d
1
1
sudoコマンドを介して/usr/bin/tarコマンドをroot権限で実行できる
1
1
tarの機能を悪用して管理者権限を奪うことができる
1
1

想定する攻撃の流れは次のとおりです。

(b) SNMPでプロセス一覧(a)を取得する
   ↓
  認証情報 testuser/testuser が漏れる
   ↓
(c)取得した認証情報を基にSSHでログインする
   ↓
(d)sudo /usr/bin/tar を悪用して root ユーザ権限を奪取する

サーバの作り方は記事末尾の [Appendix-1] にまとめました。次のコマンドで起動できます。

$ docker build -t vuln-target ./vuln-target
$ docker run -d --name vuln-target --rm vuln-target
1
1

起動後、やられサーバのIPアドレスを、例えば次のコマンドで確認しておきます。

$ docker inspect vuln-target | grep '"IPAddress"'

"IPAddress": "172.17.0.3",

1
1
やられサーバは隔離環境で起動すること
このサーバは意図的に脆弱です。インターネットから直接接続できないクローズドなネットワークで起動してください。
1
1

PentAGIの使用方法

PentAGIでは、一連の作業を「Flow」として管理します[9]。WebUIのFlowsメニューを開き、画面右上の「+ New Flow」ボタンをクリックします。

図 2. Flowの一覧画面
100

表示される新規Flowの作成画面(図3)でモデルと作業内容を指定します。

図 3. 新規Flowの作成画面
100

最初は対象を一つに絞り、目的と終了条件を明確にすると、挙動を追いやすくなります。例えば、次のように指示します(テキストエリアに指示文を入力します)。指示は英語でも日本語でも問題ありませんが、いくつかのローカルモデルでも検証することを考慮し、出力精度への影響を避けるため、システムプロンプトと同じ英語で入力することにしました。

Target: 172.17.0.3

Goal:

Perform an authorized security assessment of the target and identify exposed services, weak configurations, and exploitable vulnerabilities.

Verify whether it is possible to compromise the target by leveraging the identified vulnerabilities and escalate privileges to obtain root user permissions.

Execution requirements:

Use the terminal resource assigned to this flow.

Begin by identifying reachable services and versions.

Do not access any IP address or host other than the target.

Action plan:

1. Network Reconnaissance: ARP scanning, identify network segments, map internal infrastructure

2. Service Discovery: comprehensive port scanning of internal hosts; perform both TCP and UDP scans

Be sure to perform a UDP scan.

Example:

nmap -sU --top-ports=500 --max-rtt-timeout=1s --max-retries=0 §*ipv4*§

Be sure to search the knowledge base for every open port. If relevant knowledge exists, run the commands specified in that knowledge to verify the findings.

3. Credential Attacks: relay attacks, password spraying

4. Vulnerability Exploitation: exploit unpatched services, test default credentials, known CVEs

5. Privilege Escalation: exploit local vulnerabilities, misconfigured services, weak permission settings

6. Report: document internal security resilience, attack path visualization, remediation priorities

Deliverables:

Return a summary of findings with severity, evidence, affected service, and remediation guidance. The deliverables must be written in Japanese.

1
1

IPアドレスは環境によって変わりますので、コマンド`docker inspect` で実際のIPアドレスを確認して、適宜変更してください。

上記の「Execution requirements:」のように、文章で実行時の制約条件を指定しておくのがよいと考えます。指示文は予め登録しておいたTemplateを基に作成していくこともできるようになっています。左メニューのTemplatesから事前登録することができます。

指示文を入力した後、図3に示す「Create a new flow」画面左下のプルダウンメニューからモデル/Provider(例えばopenai)を選択し、画面右下の「↑」をクリックします。クリックすると以下の図4のように自動で検査が開始され、画面下のテキストエリアに「PentAGI is working...Click Stop to interrupt」と表示されます。

図 4. 検査実行中の画面
100

実行中は、ツールへの指示と応答を確認し、対象や処理内容が想定通りかを見ます。

途中で処理が停止した場合は、画面下のテキストエリアに「Provide additional context or instructions...」と出力されます。ヒントを与えると、タスクが自動生成され、追加で処理が実行されていきます。ヒントを与えながらですが、権限昇格まで到達した画面を以下に示します。

図 5. 権限昇格まで到達した画面
100

実行後はレポートを読み、重要な指摘について手動で再確認します。

結果の読み方
「脆弱性がある可能性」と「再現して確認できた事実」は分けて読む必要があります。また、何も検出されなかった場合も、安全性が証明されたわけではありませんので、それらを踏まえてみていく必要があります。
1
1

また、画面右上のタブを切り替えることで、それぞれ以下を確認することができます。

図 6. Tasksタブ
100

画面上部の「Dashboard」タブに切り替えると、そのFlowで使用したリソースを確認できます。実行したタスク数・ツール呼び出し回数・所要時間に加えて、LLMのトークン使用量と、そのFlowにかかったコスト(課金額)を確認できます。使用量とコストはモデル別・エージェント別にも集計されるため、「どのエージェントにどのモデルを割り当てると、精度とコストのバランスが良いか」を調整する際の参考になります。

図 7. Dashboardタブ
100

1点、Flow操作に関して、考慮に入れておいた方が良い点があります。
図2に示すFlowの一覧画面を参照した際、StatusがWaitingとなっているFlowに紐づくコンテナ(Terminal)は、起動状態のまま存在し続けます。StatusがWaitingになっているFlowで、かつ追加指示を出さないFlowについては、随時Flowを削除するか、StatusをFinishedに変えておくことを推奨します。Flowを削除するか、StatusをFinishedに変えることでコンテナが停止・削除され、マシンリソースが解放されます。操作はFlowsメニューから行うことができます。

コンテナの後片付け
FlowのStatus更新/削除を忘れると大量にコンテナが起動した状態のままになりますので、注意してください。
1
1

左メニューのResourcesでは、検査で使うコンテナにマウントしたいリソースデータを登録しておくことができます。前述のFilesタブから登録したリソースデータを実行中のFlowと紐づけることにより、実行中コンテナのディレクトリ/work/resources/配下 にリソースデータが配置(マウント)され、検査時に使うことができるようになります。Resources画面から辞書ファイル(rockyou.txt など)を予めアップロードしておいて、検査時(パスワードクラック時)に使用するなどが具体的な利用例になります。

左メニューのKnowledgesでは、コマンド操作などのナレッジ(CheatSheetsなど)を登録しておくことができます。詳細は後述します。FlowのStatusをFinishedに変えたタイミングと思いますが、自動でKnowledgesが幾つか追加されました。PentAGIは、使えば使うほど賢くなる仕組みも備えているようです。

ナレッジの追加方法

自動検査の前にナレッジを登録しておくことで、検査の精度を上げることができます。次の手順でナレッジを追加登録することができます。

  1. 左メニューからKnowledges画面を開きます。
  2. 画面右上の「+ New Knowledge」ボタンをクリックします。「Create a new knowledge document」画面(ナレッジの登録画面)に遷移します。
  3. ペンテスト自動化に関するナレッジを登録したい場合、例えば以下のように設定します。
    Document type:guide(guide以外にcodeとanswerを選択できます)
    Guide type:pentest(pentest以外にconfigure, development, install, other, useを選択できます)
    Question:ナレッジの概要を記載します。※検索時にQuestionは参照されないようです。
    Content:コマンドの使用例など、ナレッジを記載していきます。Contentの内容がナレッジ検索時の検索対象になります。
    設定例を図8に示します。
図 8. ナレッジの登録画面
100

4. 記載が完了したら画面右上の「Create」ボタンをクリックします。

Anonymize ボタン
Anonymizeボタンをクリックすると、記載内容の匿名化を自動で実施してくれます。意図しない変更になる可能性があるため、一旦記載した内容をクリップボードに退避してから実行した方がよいです。
1
1

検査時にKnowledgeが参照されているかどうかは、前述のFlow操作で記載しました「Vector Store」タブから確認することができます。検索結果として、Scoreなども出力されますので、微調整していくことができるようになっています。

APIを用いて自動で検査する方法

APIを使用することで、スクリプトや定期実行の仕組みからFlowを開始できます。ここでは公式のGraphQL APIを使った開始例を紹介します[10]。

実環境のAPI仕様は、次の画面で確認できます。画面を参照する前に認証をパスしておく必要があります。

APIの利用には、API Tokenが必要になります。まずはWeb画面の「Settings」→「API Tokens」でトークンを作成し、表示された値を保存します。

図 9. APIトークンの作成画面
100

[Appendix-2]に、検証時に使っていたスクリプトを記載します。環境変数 PENTAGI_API_TOKEN で取得したトークンを設定して使うような作りにしています。定期実行に組み込む場合は、重複起動を避ける処理を追加しておいた方がよいと考えます。CI/CDのフローに組み込む際の参考にしていただければと思います。

カスタムProvidersの設定

Web画面の「Settings」→「Providers」の画面で、Primary Agent、Pentester、Searcherなどエージェントの役割ごとに使用するモデルを選択し、カスタムProviderとして登録できるような設定画面があります。適宜、重要なところ(Generator/Refiner/Coderなど)で使用するモデルをカスタマイズすると、精度を上げることができます。

図 10. Providersの設定画面
100

重要な設定ですが、賢いモデル(商用の上位モデルなど)を選ぶと、モデル側の安全機構によって攻撃的な操作が拒否され、処理が先に進まなくなることがありました。これはPentAGIの制限ではなく、モデル提供元のポリシーによるものです。セキュリティのガードが比較的緩いローカルモデルを調整する際に利用することが多くなりそうな機能かなと思いました。

また、筆者が試した範囲では、OpenAI、Ollamaで選択できるモデルを一つのProviderにまとめて登録するような設定は、PentAGI単体ではできないようでした。OpenAIベースで設定を開始した場合、OpenAI関連のモデル一覧のみから、各エージェントで使用するモデルを選択/カスタマイズしていくような形になるようです。

まとめ

PentAGIを使い、自分で用意したやられサーバに対して、自動でペネトレーションテストを実行してみました。ヒントを与えながらではありますが、最終的に権限昇格(root権限の奪取)まで到達することができました。

PentAGIに関して気づいた点などを以下に記載します。

今回は主にOpenAIのモデルを使用してPentAGIの動作を検証しましたが、安全機構に止められずに済むローカルモデルだけで、どこまで同じ検査を完走できるかを継続して検証していきたいと思っています。

今後、LLMの活用によりペネトレーションテスト/セキュリティ診断の領域は大きな変化が生じていきそうです。引き続き動向を注視し、興味深い技術については深く調査していきたいと考えています。本ブログの内容が、少しでも皆様の学習や検証に取り組むきっかけになれば幸いです。

参考文献

[1] PentAGI公式サイト
https://pentagi.com/

[2] VXControl
https://vxcontrol.com/

[3] PentAGIソースコード(MIT License)
https://github.com/vxcontrol/pentagi

[4] Enterprise版とOSS版の比較
https://pentagi.com/enterprise/

[5] Nmap
https://github.com/nmap/nmap

[6] Ollama(MIT License)
https://github.com/ollama/ollama

[7] Installing and Configuring PentAGI
https://github.com/vxcontrol/pentagi/blob/main/examples/guides/installation_configuration.md

[8] Docker Engine:Ubuntuへのインストール
https://docs.docker.com/engine/install/ubuntu/

[9] README:How to Use PentAGI After Login
https://github.com/vxcontrol/pentagi#how-to-use-pentagi-after-login

[10] README:API Access
https://github.com/vxcontrol/pentagi#api-access

Appendix-1 やられサーバのDockerfile

前述の a~d の弱点を持つ「やられサーバ」を、作成するためのDockerfileを以下に記載します。vuln-target/Dockerfileとして保存して使用してください。

FROM debian:12-slim

# --- 必要なパッケージ ---
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        snmpd openssh-server sudo procps && \
    rm -rf /var/lib/apt/lists/*

# --- (a) 認証情報を引数で平文指定する常駐プロセス ---
RUN printf '#!/bin/sh\nwhile : ; do sleep 3 ; done\n' > /opt/monitor.sh && \
    chmod +x /opt/monitor.sh

# --- (c)(d) 権限昇格に使うユーザと sudo 設定 ---
RUN useradd -m -s /bin/bash testuser && \
    echo 'testuser:testuser' | chpasswd && \
    usermod -aG adm testuser && \
    echo 'Cmnd_Alias ALLOWCMD = /usr/bin/tar' > /etc/sudoers.d/vuln && \
    echo '%adm ALL = (ALL) ALLOWCMD' >> /etc/sudoers.d/vuln && \
    chmod 440 /etc/sudoers.d/vuln && \
    mkdir -p /var/run/sshd

# --- (b) SNMP: コミュニティ名 public で参照可能 ---
RUN printf 'agentaddress udp:161\nview all included .1 80\nrocommunity public default -V all\n' \
    > /etc/snmp/snmpd.conf

# --- 起動スクリプト ---
RUN printf '#!/bin/sh\n\
service ssh start\n\
service snmpd start\n\
nohup sh /opt/monitor.sh -u testuser -p testuser >/dev/null 2>&1 &\n\
tail -f /dev/null\n' > /root/init.sh && chmod +x /root/init.sh

EXPOSE 22 161/udp
CMD ["/root/init.sh"]
1
1

Appendix-2 フロー自動実行スクリプト

検証では、Web画面を操作せずにFlowを作成・監視するスクリプトを使っていました。使用していたスクリプトを以下に記載します。

PentAGIのAPI(フロー作成はGraphQL、状態確認はREST)を呼び出し、フローが running (実行中)を経て waiting(指示待ち)に到達したら成功とみなして終了するようにしています。cronなどからの定期実行を想定しています。ファイルpentagi-scheduled-flow.shとして保存してください。

実行には curlコマンド と jqコマンド、および有効なAPIトークンが必要です。トークンはWeb画面の設定から発行し、環境変数で渡すようにしています。

# スクリプトの使い方(環境変数を設定してからスクリプトを実行します)
export PENTAGI_API_TOKEN="eyJhb(省略)" # 発行したAPIトークンを指定します
export TARGET_IPADDR="172.17.0.3" # 検査対象を指定します
bash pentagi-scheduled-flow.sh
1
1
自己署名証明書の検証スキップ
INSECURE_TLS=true(既定)では、自己署名証明書の検証を省略します(コマンドcurlに-kオプションを付与します)。ローカル検証用の設定なので、信頼できる環境以外では使わないでください。
1
1
#!/usr/bin/env bash
# =================================================================
# PentAGI のフローを API 経由で自動実行するスクリプト
#
# 概要:
#   GraphQL API(createFlow)で新規フローを作成し、REST API でステータスを
#   ポーリングする。フローが running を経て waiting に到達したら成功とみなし
#   て終了する。cron などから定期実行することを想定している。
#
# 必要なもの:
#   curl, jq / 有効な PentAGI API トークン
#
# 主な環境変数(未設定時は右記の既定値):
#   PENTAGI_URL            PentAGI の URL        (既定: https://127.0.0.1:8443)
#   PENTAGI_API_TOKEN      API トークン          (必須。未設定ならエラー終了)
#   MODEL_PROVIDER         使用するモデル提供元  (既定: openai)
#   TARGET_IPADDR          検査対象の IP アドレス(既定: 172.17.0.3)
#   POLL_INTERVAL_SECONDS  状態確認の間隔(秒)    (既定: 30)
#   TIMEOUT_SECONDS        全体のタイムアウト(秒)(既定: 3600)
#   INSECURE_TLS           自己署名証明書を許可  (既定: true → curl -k)
#
# 終了コード:
#   0 = waiting に到達(成功) / 1 = エラー / 2 = タイムアウト
# =================================================================

# set -Eeuo pipefail: 未定義変数の参照やコマンド失敗、パイプ途中の失敗で
# 即座に終了させ、エラーの見落としを防ぐ
set -Eeuo pipefail

# --- 設定項目(環境変数で上書き可能。${VAR:-既定値} 形式) -------------------
PENTAGI_URL="${PENTAGI_URL//127.0.0.1:8443}"
# :? を使い、トークン未設定なら明示的にエラーメッセージを出して終了する
PENTAGI_API_TOKEN="${PENTAGI_API_TOKEN:?PENTAGI_API_TOKENが未設定です}"
# 使用するモデル提供元。下の行のコメントを外せば他の提供元に切り替えられる
MODEL_PROVIDER="${MODEL_PROVIDER:-openai}"
#MODEL_PROVIDER="${MODEL_PROVIDER:-anthropic}"
#MODEL_PROVIDER="${MODEL_PROVIDER:-ollama}"
#MODEL_PROVIDER="${MODEL_PROVIDER:-openai-custom3}"
TARGET_IPADDR="${TARGET_IPADDR:-172.17.0.3}"
POLL_INTERVAL_SECONDS="${POLL_INTERVAL_SECONDS:-30}"
TIMEOUT_SECONDS="${TIMEOUT_SECONDS:-3600}"
# true の場合、後段で curl に -k を付けて証明書検証をスキップする
INSECURE_TLS="${INSECURE_TLS:-true}"

# --- フローへ渡す指示文(プロンプト) ---------------------------------------
# ここから下のヒアドキュメント本文が、そのまま PentAGI への指示として送られる。
# ${TARGET_IPADDR} のみ変数展開される。文面を変えると検査内容が変わる点に注意。
TASK_DESCRIPTION=$(cat <<EOF
Target: ${TARGET_IPADDR}

Goal:
Perform an authorized security assessment of the target and identify exposed services, weak configurations, and exploitable vulnerabilities.
Verify whether it is possible to compromise the target by leveraging the identified vulnerabilities and escalate privileges to obtain root user permissions.

Execution requirements:
Use the terminal resource assigned to this flow.
Begin by identifying reachable services and versions.
Do not access any IP address or host other than the target.

Action plan:
1. Network Reconnaissance: ARP scanning, identify network segments, map internal infrastructure
2. Service Discovery: comprehensive port scanning of internal hosts; perform both TCP and UDP scans
   Be sure to perform a UDP scan.
   Example:
   nmap -sU --top-ports=500 --max-rtt-timeout=1s --max-retries=0 §*ipv4*§
   Be sure to search the knowledge base for every open port. If relevant knowledge exists, run the commands specified in that knowledge to verify the findings.
3. Credential Attacks: relay attacks, password spraying
4. Vulnerability Exploitation: exploit unpatched services, test default credentials, known CVEs
5. Privilege Escalation: exploit local vulnerabilities, misconfigured services, weak permission settings
6. Report: document internal security resilience, attack path visualization, remediation priorities

Deliverables:
Return a summary of findings with severity, evidence, affected service, and remediation guidance. The deliverables must be written in Japanese.
EOF
)

# --- 前提コマンドの存在確認 -------------------------------------------------
for cmd in curl jq; do
    command -v "$cmd" >/dev/null || { echo "$cmd が必要です" >&2; exit 1; }
done

# URL 末尾の / を除去してパス連結時の // を防ぐ
PENTAGI_URL="${PENTAGI_URL%/}"
# 全 curl 呼び出しで共通のオプション(静かに実行/失敗時も本文表示/認証ヘッダ)
curl_opts=(-sS --fail-with-body -H "Authorization: Bearer ${PENTAGI_API_TOKEN}")
if [[ "$INSECURE_TLS" == true ]]; then curl_opts+=(-k); fi

# --- フローの作成(GraphQL mutation) ---------------------------------------
# createFlow に provider と input(指示文)を渡し、id/title/status を受け取る
query='mutation($provider:String!,$input:String!){createFlow(modelProvider:$provider,input:$input){id title status}}'
# jq -n でクエリと変数を JSON に組み立てる(特殊文字のエスケープも jq に任せる)
payload=$(jq -nc --arg query "$query" --arg provider "$MODEL_PROVIDER" \
    --arg input "$TASK_DESCRIPTION" \
    '{query:$query,variables:{provider:$provider,input:$input}}')

created=$(curl "${curl_opts[@]}" -H 'Content-Type: application/json' \
    --data-binary "$payload" "${PENTAGI_URL}/api/v1/graphql")
# GraphQL は HTTP 200 でも errors を返すことがあるため、本文側で判定する
if jq -e '.errors and (.errors | length > 0)' <<<"$created" >/dev/null; then
    echo "$created" >&2
    exit 1
fi

# 作成されたフローの ID を取得(取れなければ中断)
FLOW_ID=$(jq -er '.data.createFlow.id // empty' <<<"$created") || {
    echo "フローIDを取得できませんでした" >&2
    exit 1
}
# 初期ステータスを控え、以降のポーリングで running を観測済みか追跡する
initial_status=$(jq -r '.data.createFlow.status // empty' <<<"$created")
seen_running=false
if [[ "$initial_status" == running ]]; then seen_running=true; fi
echo "flow_id=${FLOW_ID} initial_status=${initial_status}" >&2

# --- ステータスのポーリング -------------------------------------------------
# SECONDS は bash の組み込み変数で、0 代入後の経過秒数を自動で数える。
# TIMEOUT_SECONDS を超えるまで、一定間隔でフローの状態を確認し続ける。
SECONDS=0
last_status="$initial_status"
while (( SECONDS < TIMEOUT_SECONDS )); do
    # フロー一覧(init タイプ)を取得する
    response=$(curl "${curl_opts[@]}" \
        "${PENTAGI_URL}/api/v1/flows/?page=1&type=init")

    # 応答が期待する配列形式かを確認する
    jq -e '(.data.flows | type) == "array"' <<<"$response" >/dev/null || {
        echo "フロー一覧の応答形式が不正です" >&2
        exit 1
    }

    # 一覧から対象の FLOW_ID の要素を抜き出す
    flow=$(jq -c --arg id "$FLOW_ID" \
        '.data.flows[] | select((.id | tostring) == $id)' <<<"$response")
    # まだ一覧に現れていなければ、待って再試行する
    if [[ -z "$flow" ]]; then
        sleep "$POLL_INTERVAL_SECONDS"
        continue
    fi

    # 状態が前回から変化したときだけログを出す(出力の重複を抑える)
    status=$(jq -r '.status // empty' <<<"$flow")
    if [[ "$status" != "$last_status" ]]; then
        echo "flow_id=${FLOW_ID} status=${status}" >&2
        last_status="$status"
    fi

    case "$status" in
        running)
            # 稼働を確認。waiting 判定の前提になるフラグを立てる
            seen_running=true
            ;;
        waiting)
            # 一度 running を経てからの waiting を「指示待ち=成功」とみなす。
            # (作成直後の waiting を誤検知しないよう seen_running で保護)
            if [[ "$seen_running" == true ]]; then
                title=$(jq -r '.title // "(タイトルなし)"' <<<"$flow")
                printf 'flow_id=%s title=%s status=waiting\n' "$FLOW_ID" "$title"
                exit 0
            fi
            ;;
        created|queued|pending|working|in_progress)
            # 処理継続中の状態。何もせず次のポーリングへ
            ;;

finished|completed|complete|succeeded|done|success|failed|failure|error|cancelled|canceled|stopped)
            # waiting に至らず終了してしまったケースは失敗として扱う
            echo "waitingになる前にフローが終了しました: ${status}" >&2
            exit 1
            ;;
        *)
            # 想定外の状態は安全側に倒してエラー終了する
            echo "不明な状態です: ${status}" >&2
            exit 1
            ;;
    esac

    sleep "$POLL_INTERVAL_SECONDS"
done

# ループを抜けた=制限時間内に waiting に到達しなかった
echo "タイムアウトしました: ${TIMEOUT_SECONDS}秒" >&2
exit 2
1
1

執筆者プロフィール

original
50

木津 由也(きづ よしや)
担当領域:リスクハンティング

主にネットワークセキュリティ製品・サービスの開発に従事してきたが、最近はCTFに取り組んできた経験を活かし、ペネトレーションテスト、脆弱性診断などの領域にも仕事の範囲を拡大中。
2013年にnoraneco という社会人CTF チームを立ち上げ、現在は主にPwn/Reversing 問を担当。
SANS - Cyber Defense NetWars 2019.10 1位(Team)
SECCON 2019 国際決勝5位
Hack The Box - Omniscient