Japan

関連リンク

関連リンク

関連リンク

関連リンク

サイト内の現在位置

話題のOpen Interpreterを触ってみた

NECセキュリティブログ

2023年10月27日

NEC サイバーセキュリティ戦略統括部セキュリティ技術センターの木津です。ペネトレーションテスト/脆弱性診断について学習していく上で、有用なツールなどを日頃から調査・検証しています。今回は調査の中で見つけた「Open Interpreter」new window[1] new window[2]について、試してみたことをご紹介したいと思います。

注意:本ブログの情報を用いた活動は、必ず自らの責任によって行ってください。本ブログの内容を使用したことによって発生する不利益等について、筆者および関係者はいかなる責任も負いません。

Open Interpreterとは

OpenAIが提供しているChatGPTの「Advanced Data Analysis(旧Code Interpreter)」に似た機能を持つ、OSSのツールです。
Python、JavaScript、Shellなどのプログラミング言語のコードを自然言語による対話を通じてローカル環境で実行でき、大量データの分析、画像編集/動画編集など、多岐にわたる作業をチャット形式で行うことができます。
ファイル容量やインターネット接続に関する制限がない、というのがポイントで、色々なことができそうな気がしましたので、ツールを見つけてすぐ試してみました。ツールを試す過程で何点かつまずいて、問題解決につながった方法をメモに残しました。そのメモ書きの一部も共有したいと思います。

Open Interpreterを使用する上で注意しておくべき点

「Open Interpreter」は使い方を誤ると事故につながる可能性があります。詳しい説明の前に注意事項を整理してお伝えしておきたいと思います。次の点に注意しつつ使う必要があります。

  • Open Interpreterを介して許可されていない環境に対してプログラムを実行した場合、不正アクセス禁止法 new window[3]などに違反する可能性がある。
  • Open Interpreterを介して実行されるコードはローカル環境で実際に実行されるため、ハードディスク内のデータの損失やセキュリティ上の問題が生じる可能性がある。
  • 関連するツール/学習済みモデル/データセットなど、それぞれでライセンスが異なるため、再頒布や商用利用の際には、忘れずそれぞれのライセンスを確認する必要ある。

コード実行時には事前確認が求められますが、ツール起動時のオプションで無効化することもできますので、注意が必要です。設定などのファイルを更新するようなコマンドの実行時には特に慎重になるよう心掛ける必要があります。できればDocker/VMなどの仮想環境で動かすことをお奨めします。

Open Interpreterの始め方・使い方

次の環境で試しました。

  • VM-01(OS: Ubuntu 22.04 LTS)
    • CPU AMD Ryzen 9 3950X
    • メモリ 64GB
    • NVIDIA GeForce GTX 1650
  • VM-02 (OS: Ubuntu 22.04 LTS)
    • CPU AuthenticAMD
    • メモリ 192GB
    • NVIDIA A10G Tensor Core

GPU関連の動作環境の構築も行いましたが、構築方法は本ブログの内容から少し外れるため、添付のAppendix-1に詳細を記載しています。参考にしていただければと思います。

Open Interpreter自体は特別な登録などは不要で、例えば次のコマンドでインストールが可能です。ローカルストレージから学習済みモデルの読み込みを行いたいため、open-interpreterが依存しているllama-cpp-pythonも一緒にインストールしておきます。GGUF形式のモデルを扱う際にllama-cpp-pythonを使っているようです。

$ python -V
Python 3.10.12
$ pip uninstall llama-cpp-python -y
$ CMAKE_ARGS="-DLLAMA_METAL=on" FORCE_CMAKE=1 pip install -U llama-cpp-python --no-cache-dir
$ pip install 'llama-cpp-python[server]'
$ pip install open-interpreter

使用する学習済みモデルの選択

Open Interpreterは様々なモデルを選択可能なつくりになっています。例えば、GPT-4やGPT-3.5を使う以外に、ローカルストレージに存在するCode Llamaなどのモデルも使用できます。独自にファインチューニングしたモデルも選択可能です。ローカルストレージ上の学習済みモデルを使用する場合は、OpenAI APIキーの設定は不要です。
ローカルストレージ上の学習済みモデルを使いたい場合、次の方法で起動します。初回起動時にデフォルトのモデルのダウンロードと調整が行われます。


$ interpreter --local
Open Interpreter will use Mistral 7B for local execution.
? Warning: Local LLM usage is an experimental, unstable feature.
Downloading mistral-7b-instruct-v0.1.Q4_0.gguf: 100%|????????| 4.11G/4.11G [00:03<00:00, 211MB/s]
Getting started...
Setting up the language model...
This can take up to 15 minutes. The progress bar might appear to freeze (some steps take several minutes).
100%|????????| 1738/1738 [04:13<00:00, 6.85it/s]
Ready.
Open Interpreter will require approval before running code.
Use interpreter -y to bypass this.
Press CTRL-C to exit.

> ★このプロンプトがでたら成功です

デフォルトではmistral-7b-instruct-v0.1.Q4_0.gguf(約4GB)のモデル new window[4]がダウンロードされ、次のパスに配置されます。

~/.local/share/ooba/models/mistral-7b-instruct-v0.1.Q4_0.gguf

設定ファイルは次のパスのファイルが使われます。

~/.config/Open Interpreter/config.yaml

モデルの格納先を指定できそうな設定項目(model: "gpt-4")がありましたが、ローカルストレージ上の学習済みモデルの指定は不可でした。指定できるのはHugging Face new window[5]上のモデルのみのようです。設定ファイルでロードするモデルを切り替えることができませんでしたので、作成した学習済みモデルをHugging Face上に載せて使うか、ホームディレクトリ配下にある前述の学習済みモデルmistral-7b-instruct-v0.1.Q4_0.ggufを作成した学習済みモデルで置換して使うか、の2択になりそうです。
例えば、Hugging Faceモデルをrepo_id(例えば “tiiuae/falcon-180B”)を使ってローカルで実行することもできます。

interpreter --model tiiuae/falcon-180B

ホームディレクトリ配下のモデルファイルの置き換えも試してみました。結果、GGUF形式の学習済みモデルであれば、置き換えてもOpen Interpreterの起動は可能ということが分かりました。モデルファイルの置換は、少しイマイチな方法ですが、独自にファインチューニングしたローカルストレージ上の学習済みモデルを使ってOpen Interpreterを起動することも可能であることが分かりました。

対話的セッションの開始

ターミナル上で次のコマンドを実行します。2回目からは待ち時間少しで、すぐ起動してくれました。

$ interpreter –local #以降、入力部分を太字にしています。
Open Interpreter will use Mistral 7B for local execution.
? Warning: Local LLM usage is an experimental, unstable feature.
Located '/home/ubuntu/.local/share/ooba/models/mistral-7b-instruct-v0.1.Q4_0.gguf', which has already been downloaded.
Getting started...
Ready.
Open Interpreter will require approval before running code.
Use interpreter -y to bypass this.
Press CTRL-C to exit.
#使える組み込みコマンドは%helpで確認することができます
%help
▌ Available Commands:
• %debug [true/false]: Toggle debug mode. Without arguments or with 'true', it enters debug mode. With 'false', it exits debug mode.
• %reset: Resets the current session. # %resetはよく使うことになりそうです。
• %undo: Remove previous messages and its response from the message history.
• %save_message [path]: Saves messages to a specified JSON path. If no path is provided, it defaults to 'messages.json'.
• %load_message [path]: Loads messages from a specified JSON path. If no path is provided, it defaults to 'messages.json'.
• %tokens [prompt]: Calculate the tokens used by the current conversation's messages and estimate their cost and optionally calculate the tokens
and estimated cost of a prompt if one is provided.
• %help: Show this help message.
> Please generate a shell script that outputs 'Hello' 10 times.

Here is your shell script:

#!/bin/bash
for i in {1..10}; do echo "Hello"; done

Would you like to run this code? (y/n)

y

#!/bin/bash
for i in {1..10}; do echo "Hello"; done
```
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello

想定通り実行までしてくれました。次に別のスクリプト言語で実現する方法を聞いてみました。

> Please change it from a shell script to a python script.

Here is your Python script:

for i in range(1, 11):
 print("Hello")

Would you like to run this code? (y/n)

n

> Please change it from a python script to a JavaScript.

Here is your JavaScript script:

for (let i = 1; i <= 10; i++) {
 console.log("Hello");
}


Would you like to run this code? (y/n)

n

別のプログラミング言語への変更も対応してくれました。strace/ltraceでコマンド実行の挙動をみてみましたが、生成したコードを標準入力からコマンドに引き渡すような作りになっていました。例えばpythonの場合のイメージは次の通りです。

$ echo -e 'for i in range(1, 11):\n print("Hello")' | python -i -q -u
>>> ... ...
Hello
Hello
(snip)

次にポートスキャンを実行してみたいと思います。

> 172.31.27.67を対象としたtcpポートのスキャンを実施したいのですが、nmapで実行する場合のコマンドを教えてください。ポートスキャンの対象ポートは1-1000でお願いします。 #日本語にも対応しています。172.31.27.67は管理下の実験用端末のIPアドレスです。

以下のようにnmapを使用して、1-1000のポートをスキャンして、対象IPアドレス(172.31.27.67)のTCPポートがオープンかどうかを確認できます。

nmap -p 1-1000 172.31.27.67

Would you like to run this code? (y/n)

y

Starting Nmap 7.80 ( https://nmap.org ) at 2023-10-22 20:55 UTC
Nmap scan report for ip-172-31-27-67.us-west-2.compute.internal (172.31.27.67)
Host is up (0.000071s latency).
Not shown: 999 closed ports
PORT STATE SERVICE
22/tcp open ssh ★tcp/22に接続できることが分かりました。
Nmap done: 1 IP address (1 host up) scanned in 0.04 seconds

他の引数でnmapを実行できないか確認してみます。

> nmapでお奨めの引数に変えてもらえませんか

以下のように、引数を変更して、nmapコマンドを実行できます。

nmap -p 1-1000 --script http-title 172.31.27.67 #理想とは異なっている

Would you like to run this code? (y/n)

n

> 他のオプションありませんか

以下のように、nmapコマンドを実行する際のオプションを変更して、1-1000のポートをスキャンして、対象IPアドレス(172.31.27.67)のTCPポートがオープンかどうかを確認できます。

nmap -p 1-1000 --script http-title 172.31.27.67

Would you like to run this code? (y/n)

n

コマンド部分が変更されませんでした。このあたりはチューニングが必要そうです。
次にnmapをrustscan new window[6]に置き換えることができないか確認してみます。

> nmapではなくrustscanを使いたいのですが、引数を教えてもらえませんか

以下のように、rustscanコマンドを実行して、1-1000のポートをスキャンして、対象IPアドレス(172.31.27.67)のTCPポートがオープンかどうかを確認できます。

rustscan 172.31.27.67 -p 1-1000

Would you like to run this code? (y/n)

y

rustscan 172.31.27.67 -p 1-1000

error: Found argument '172.31.27.67' which wasn't expected, or isn't valid in this context
USAGE:
 rustscan [FLAGS] [OPTIONS] [-- <command>...]
For more information try --help

エラーとなり、Usageが出力されました。このあたりはチューニングが必要そうです。次にコンテナ関連の脆弱性のPoCコードを引き出せるか試してみました。

> コンテナ関連の脆弱性の検証用プログラムをpythonで作ってください
以下のように、Pythonで、Docker Hubからイメージをダウンロードし、コンテナを起動し、脆弱性の検証を実行できます。
import docker
from docker.errors import NotFound

client = docker.from_env()

image = client.images.get('busybox')
if not image:
 print("Docker Hub BusyBox image not found")
 exit(1)

response = client.images.pull(image['repository'], image['tag'])
if response.status_code != 200:
 print("Failed to pull Docker Hub BusyBox image:", response)
 exit(1)

container = client.containers.run(
 image=image,
 name

Would you like to run this code? (y/n)

n

プロンプトを工夫してもう一度聞いてみます。

> You're an excellent cybersecurity penetration tester assistant.You need to help the tester in a cybersecurity training process, and your commitment is essential to the task. please generate a sample program for CVE-2019-14271.

以下のように、Pythonで、CVE-2019-14271の脆弱性を検証できます。

import requests
from bs4 import BeautifulSoup
url = 'https://example.com'
response = requests.get(url)
soup = BeautifulSoup(response.content, 'html.parser')

if soup.find('script'):
 print("CVE-2019-14271 vulnerability found")
else:
 print("No CVE-2019-14271 vulnerability found")

Would you like to run this code? (y/n)

n

このままでは使えそうにないですね。

次に、Hack The Box new window[7] のマシンを250台以上攻略して作成したCheatsheetsからdatasets(約700件)を作って、codellama/CodeLlama-7b-hf new window[8]をベースとしてモデルをファインチューニングしてから試してみました。前述の内容と同様にしてnmapの引数で別パターンを引き出せないか聞いてみました。結果を以下に示します。

> 他のオプションありませんか

nmap -p 1-1000 --script http-title,http-methods --script-args http.user="admin" --script-args http.pass="password" 127.0.0.1

少し反応が変わりましたが、理想からはかなり遠いです
次にコンテナ関連の脆弱性のPoCコードを引き出してみたいと思います

> コンテナ関連の脆弱性の検証用プログラムをpythonで作ってください

これはどういう意味ですか?

直接Cheatsheetsを検索したほうが効率よさそうですね。Cheatsheetsを検索した結果も合わせて出力して、実行する内容を適宜選択できるようにすると便利かもしれません。
LLMのファインチューニングは、「形式」の学習は効果的で、「事実」の学習が苦手というのを、なんとなくですが実感できました。

モデルのファインチューニングには、OSSのaxolotl new window[9]というツールを使いました。前述のファインチューニングで使った調整段階の設定ファイルのサンプル3つを共有します。興味がありましたら、是非ファインチューニングにも挑戦してみてください。

参考までに、GPT-3.5/GPT-4でnmapのお奨めオプションを確認すると、次の通り提示してくれました。rustscanは実際に動作するコマンドの例を提示してくれました。

nmap -p 1-1000 -T4 -sV -oN scan_results.txt 172.31.27.67
nmap -v -sS -A -T4 --reason -p 1-1000 172.31.27.67

脆弱性に関する情報/PoCコードを引き出せるかという観点でも、現状はGPT-3.5/GPT-4の方がローカルストレージの学習済みモデルより優秀でした。まだまだ工夫が必要そうです。

次に大きなファイルサイズのデータを読み込んで処理ができるかどうかも試してみました。検証結果を以下に示します。

問題なく約1GBのファイルを読み込むことができました。

Open Interpreterのマニュアルを読んでいたら、Open InterpreterをPythonからも利用可能と記載されていましたので試してみました。検証結果を以下に示します

Pythonからも利用できることが分かりました。最後にinterpreter.messagesの中身を出力してみましたが、code部分に実行される処理/プログラムが入っていることが分かりました。外部API/DBとの連携など、色々応用方法がありそうです。

所感、まとめ

Open Interpreterについて試してみた結果の一部をご紹介しました。気づいた点などを以下に整理して記載します。

  • ChatGPTの「Advanced Data Analysis」と同様のことを、ローカルストレージ上の学習済みモデルで試せる点がよい。課金を気にせず、クローズドな環境でも試すことができる。
  • 「Advanced Data Analysis」で不可能だったことの一部を、ファイル容量やネットワークの制約なしで実現可能になる点がよい。
  • Python, Bash, JavaScript, HTML, PowerShell, R, AppleScript/osascriptに対応していて、実行するコードを選択できる点がよい。
  • 任意のライブラリ、ツールと連携可能な点がよい
  • プログラムの実行時間や扱うファイルサイズにOpen Interpreterとしては制限がない点がよい
  • PythonからOpen Interpreterを呼び出しできる点がよい。
  • ファインチューニングで応答がかなり改善すると思っていたが、イメージと異なる検証結果となり、あまり改善しなかった。試してみなければ気づけない点だった。ファインチューニングには高いマシンスペックが必要で、調整も難しいが、やりがいのある技術領域と感じた。
  • 生成AI+ペンテストの領域では、PentestGPT new window[11]などのペンテスターを支援してくれるツールも現れてきた。Open Interpreterと組み合わせるとおもしろいツールになるかもしれないと感じた。

生成AIとセキュリティはとても相性がよく、様々なツールが出てきそうで今後が楽しみな領域です。OSSのツールを実際触ってみて、色々気づきを得ることができました。私も思いついたツールを幾つか作ってみたいと思いました。

これからもお客様のご期待に応えられるよう、ペンテスト/脆弱性診断/インシデント対応などを行う際に有用と思われるツールの調査・検証を継続して行っていきたいと考えています。本ブログの内容が少しでも皆様のモチベーション向上の一助になれば幸いです。

Appendix-1

# ubuntu 22.04/AWSでGPUを利用可能にするまでの設定手順(所要時間: およそ0.5H)

$ sudo apt update
$ sudo apt install python3 python3-wheel python3-pip python3-venv python3-dev python3-setuptools ubuntu-drivers-common
$ sudo ubuntu-drivers devices
driver : nvidia-driver-535 - distro non-free recommended # 推奨されたドライバをaptコマンドでインストール
$ sudo apt install nvidia-driver-535

$ wget
https://developer.download.nvidia.com/compute/cuda/11.8.0/local_installers/cuda_11.8.0_520.61.05_linux.run
$ sudo ./cuda_11.8.0_520.61.05_linux.run --override #対話モードでDriverのチェックを外してInstallを実施

$ vi ~/.bashrc # 末尾に追加
export PATH=$PATH:/usr/local/cuda-11.8/bin:/home/ubuntu/.local/bin/:$HOME/.cargo/bin
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/cuda-11.8/lib64:/usr/local/cuda-11.8/extras/CUPTI/lib64

https://developer.nvidia.com/compute/cudnn/secure/8.6.0/local_installers/11.8/-local-repo-ubuntu2204-8.6.0.163_1.0-1_amd64.debからcudnnをダウンロード
$ sudo dpkg -i cudnn-local-repo-ubuntu2204-8.6.0.163_1.0-1_amd64.deb # versionは適宜読みかえて実行
$ sudo cp /var/cudnn-local-repo-ubuntu2204-8.6.0.163/cudnn-local-FAED14DD-keyring.gpg /usr/share/keyrings/
$ sudo apt update
$ sudo apt install libcudnn8
$ sudo apt install libcudnn8-dev
$ sudo reboot

OS再起動後、次のコマンドで状態を確認し、エラーがでなければ設定完了
$ nvidia-smi
$ python3 -m bitsandbytes

Appendix-2

#
# ~/.cache/huggingface/accelerate/default_config.yaml
#
# accelerate configコマンドで自動生成したファイル
# 幾つか機能を有効化するとファインチューニングに失敗したため無効化した
#
compute_environment: LOCAL_MACHINE
debug: false
distributed_type: MULTI_GPU
downcast_bf16: 'no'
gpu_ids: all
machine_rank: 0
main_training_function: main
mixed_precision: fp16
num_machines: 1
num_processes: 4
rdzv_backend: static
same_network: true
tpu_env: []
tpu_use_cluster: false
tpu_use_sudo: false
use_cpu: false

Appendix-3

#
# ファインチューニング用の設定ファイル(axolotl/scripts/finetune.pyの設定ファイル)
# /mnt/tools/finetune/axolotl/EvolCodeLlama-7b.yaml
#

base_model: codellama/CodeLlama-7b-hf
base_model_config: codellama/CodeLlama-7b-hf
model_type: LlamaForCausalLM
tokenizer_type: LlamaTokenizer
is_llama_derived_model: true

# 事前にhttps://huggingface.co/でアカウントを登録し、認証tokenを取得。コマンドhuggingface-cli loginを実行しておく
hub_model_id: EvolCodeLlama-7b # 出力先は適宜変更する

load_in_8bit: false
load_in_4bit: true
strict: false

datasets:
 - path: data/tp.json # 準備したデータセットの格納先に合わせて適宜変更する
  ds_type: json
  type: alpaca
dataset_prepared_path: last_run_prepared
val_set_size: 0.02
output_dir: ../qlora-out2

adapter: qlora
lora_model_dir:

sequence_len: 1024 # torch.cuda.OutOfMemoryErrorとなった場合、小さい値にすることを検討する
sample_packing: true

lora_r: 32
lora_alpha: 16
lora_dropout: 0.05
lora_target_modules:
lora_target_linear: true
lora_fan_in_fan_out:

# 事前にhttps://wandb.ai/loginでアカウントを登録し、apikeyを取得。コマンドwandb loginを実行しておく
wandb_project: axolotl
wandb_entity:
wandb_watch:
wandb_run_id:
wandb_log_model:

gradient_accumulation_steps: 32 # 他パラメータ調整時は大き目の値に設定。他が軌道にのってから減らすことを検討する
micro_batch_size: 1 # torch.cuda.OutOfMemoryErrorとなった場合、小さい値にすることを検討する
num_epochs: 3 # 他パラメータ調整時は小さめの値に設定。他が軌道にのってから最後に増やすことを検討する
optimizer: paged_adamw_32bit
lr_scheduler: cosine
learning_rate: 0.0002

train_on_inputs: false
group_by_length: false
bf16: false
fp16: true
tf32: false

gradient_checkpointing: true
early_stopping_patience:
resume_from_checkpoint:
local_rank:
logging_steps: 1
xformers_attention:
flash_attention: false # trueにするとエラーで停止したためfalseに変更。環境に合わせて適宜変更する

warmup_steps: 100
eval_steps: 0.01
save_strategy: epoch
save_steps:
debug:
deepspeed:
weight_decay: 0.0
fsdp:
fsdp_config:
special_tokens:
 bos_token: "<s>"
 eos_token: "</s>"
 unk_token: "<unk>"

# 以下はビルドスクリプト
# $ cat build.sh
# export TF_ENABLE_ONEDNN_OPTS=0
# # torch.cuda.OutOfMemoryErrorとなった場合、PYTORCH_CUDA_ALLOC_CONFを次の通り指定すると改善することがある
# export PYTORCH_CUDA_ALLOC_CONF=garbage_collection_threshold:0.6,max_split_size_mb:128
# accelerate launch scripts/finetune.py EvolCodeLlama-7b.yaml

Appendix-4

# 以下はdatasetの一部(先頭3件)。JSON形式のデータを同様に700件以上作成してファインチューニングを実施

{"instruction":"CVE-2020-15257","output":" UNIX ドメインソケットを介して、ホスト上のroot権限を取得可能\r\n 対象: containerd <= 1.3.7, 1.4.0, 1.4.1( Containerd は、Docker と Kubernetes の基礎となる業界標準のコンテナランタイム)\r\n 参考: https://github.com/summershrimp/exploits-open/tree/9f2e0a28ffcf04ac81ce9113b2f8c451c36fe129\r\n参考: https://github.com/brant-ruan/metarget/tree/master/vulns_cn\r\n\r","source":"test/p1"}
{"instruction":"コンテナ関連の脆弱性: mount利用","output":" docker run --rm -v /:/host -it olympia /bin/sh\r\n docker run --rm -v /root:/mnt --entrypoint=/bin/cat -it 0601ea177088 /mnt/root.txt\r\n\r","source":"test/p1"}
{"instruction":"shocker: 特権コンテナからホスト上の任意ファイルの参照","output":" 以下は2014年頃のPoCだが条件がそろえば2022年4月現在でも有効。/etc/shadowなど、ホスト上の任意ファイルを参照可能\r\n https://github.com/gabrtv/shocker\r\n 条件\r\n a. コンテナ上でroot権限保有\r\n b. コンテナでホスト上のファイルをどれかマウントしている\r\n $ mount\r\n /dev/mapper/ubuntu--vg-ubuntu--lv on /etc/resolv.conf type ext4 (rw,relatime)\r\n\r","source":"test/p1"}
(snip)

参考文献

執筆者プロフィール

木津 由也(きづ よしや)
セキュリティ技術センター リスクハンティングチーム

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

執筆者の他の記事を読む

アクセスランキング

Escキーで閉じる 閉じる