🐈

LangChainを使ってOSINTを自動化する

2023/01/27に公開

OSINTとは

OSINT (Open-Source Intelligence) とは、インターネット上に公にアクセス可能な情報を収集・分析することを指します。サイバーセキュリティの分野では特に重要な役割を担い、情報収集から脅威の評価・対策までの業務をサポートします。特に、LinuxコマンドやGoogle検索を使った情報収集はOSINTにおいて重要な手法のひとつです。

LangChainとは

langchainは、LLMと外部リソース(データソースや言語処理系等)を組み合わせたアプリケーションの開発支援を目的としてHarrison Chaseさんが開発したPythonライブラリです。langchainを使うことで、OSINTにおいて人間が手作業で行うタスクを自動化することができます。

例えば、サイバー脅威に関連する情報を収集したい場合、langchainを使って自然言語からLinuxコマンドやGoogle検索用のクエリを生成することができ、情報を自動的に収集して分析することができます。
本記事はlangchainを使ってOSINTのタスクを自動化することで、効率的な情報収集・分析を実現する手法について解説します。

準備

はじめに必要なライブラリをインストールします。

pip install langchain
pip install openai
pip install google-api-python-client
pip install click

次にこちらの記事を参考にしながらAPIキーの取得を行い環境変数に設定します。

export OPENAI_API_KEY='openapi APIキー'
export GOOGLE_CSE_ID='Googleカスタム検索ID'
export GOOGLE_API_KEY='Google APIキー'

スクリプトの作成

以下のようなPythonスクリプトを用意します。
prompt=の部分に具体的な調査方法と判定基準を書いておきます。

import os
import sys
import click

from langchain.chains.conversation.memory import ConversationBufferMemory
from langchain import OpenAI, SerpAPIWrapper, LLMChain, LLMMathChain, LLMBashChain
from langchain.agents import ZeroShotAgent, Tool, AgentExecutor, load_tools, initialize_agent

def generate_prompt(identifier:str,input_value:str):
    if identifier in ["url", "domain"]:
        prompt = f"""
以下の手順を使ってURL({input_value})の調査を行い、悪意の有無について「日本語」で出力してください。
* digコマンドを使って入力されたドメイン名からIPアドレスを取得します。
* whoisコマンドを使ってWhois情報を取得します。
* IPアドレスをgoogleで検索する

判定基準
* IP Abuse Reports
"""

    if identifier == "ip":
        prompt = f"""
以下の手順を使ってIPアドレス({input_value})の調査を行い、悪意の有無について「日本語」で出力してください。
* whoisコマンドを使ってWhois情報を取得します。
* IPアドレスをgoogleで検索する

判定基準
* 悪意のあるIPアドレスとして報告されている
* IP Abuse Reports
"""

    if identifier == "hash":
       prompt = f"""
以下の手順を使ってHash({input_value})の調査を行い、悪意の有無について「日本語」で出力してください。
* ハッシュ値をGoogle検索する

判定基準
* 悪意のあるファイルとして報告されている
"""
    return prompt

@click.command()
@click.option("--url", "identifier", flag_value="url", help="Investigate based on URL.")
@click.option("--hash", "identifier", flag_value="hash", help="Investigate based on file hash.")
@click.option("--domain", "identifier", flag_value="domain", help="Investigate based on domain name.")
@click.option("--ip", "identifier", flag_value="ip", help="Investigate based on IP address.")
@click.argument("input_value")
def main(identifier: str, input_value: str):
    # ツールの準備
    llm = OpenAI(temperature=0)
    tools = load_tools(["terminal", "google-search"], llm=llm)
    llm_math_chain = LLMMathChain(llm=llm, verbose=True)
    llm_bash_chain = LLMBashChain(llm=llm, verbose=True)
    tools.append(
        Tool(
            name="Calculator",
            func=llm_math_chain.run,
            description="useful for when you need to answer questions about math",
        )
    )

    memory = ConversationBufferMemory(memory_key="chat_history")
    prompt = generate_prompt(identifier, input_value)
    agent = initialize_agent(tools, llm, agent="zero-shot-react-description", verbose=True)
    agent.run(prompt)

if __name__ == "__main__":
    main()

以下のように実行してみましょう。
悪意あるハッシュとして登録されているためマルウェアだという判定が出るはずです。

python intelgpt.py --hash fafe11f23567080fb14cfd3b51cb440b9c097804569402d720fd32dd66059830

他にもIPアドレスやURLの調査にも対応することができます。
asciicast

ここまででも十分機能するのですが、以下のように日本語でpromptを書いてしまうと、トークンの数が英語の場合と比較してかなり不利になります。

そこで先ほどのスクリプトの日本語部分を英語で書いてみます。(Deeplを使って翻訳しました)

import os
import sys
import click

from langchain.chains.conversation.memory import ConversationBufferMemory
from langchain import OpenAI, SerpAPIWrapper, LLMChain, LLMMathChain, LLMBashChain
from langchain.agents import ZeroShotAgent, Tool, AgentExecutor, load_tools, initialize_agent

def generate_prompt(identifier:str,input_value:str):
    if identifier in ["url", "domain"]:
        prompt = f"""
Please use the following procedure to investigate the URL ({input_value}) and output about the presence or absence of maliciousness
* Get the IP address from the entered domain name using the dig command.
* Get Whois information using the whois command.
* Search the IP address with google.

Criteria:
* IP Abuse Reports
"""

    if identifier == "ip":
        prompt = f"""
Please use the following procedure to investigate the IP address ({input_value}) and output about the presence or absence of maliciousness
* Use the whois command to obtain Whois information.
* Search the IP address with google.

Criteria:
* Reported as a malicious IP address
* IP Abuse Reports
"""

    if identifier == "hash":
       prompt = f"""
Please use the following procedure to investigate the Hash value ({input_value}) and output about the presence or absence of maliciousness
* Google search for the hash value

Criteria
* Reported as a malicious file
"""
    return prompt

@click.command()
@click.option("--url", "identifier", flag_value="url", help="Investigate based on URL.")
@click.option("--hash", "identifier", flag_value="hash", help="Investigate based on file hash.")
@click.option("--domain", "identifier", flag_value="domain", help="Investigate based on domain name.")
@click.option("--ip", "identifier", flag_value="ip", help="Investigate based on IP address.")
@click.argument("input_value")
def main(identifier: str, input_value: str):
    # ツールの準備
    llm = OpenAI(temperature=0)
    tools = load_tools(["terminal", "google-search"], llm=llm)
    llm_math_chain = LLMMathChain(llm=llm, verbose=True)
    llm_bash_chain = LLMBashChain(llm=llm, verbose=True)
    tools.append(
        Tool(
            name="Calculator",
            func=llm_math_chain.run,
            description="useful for when you need to answer questions about math",
        )
    )

    memory = ConversationBufferMemory(memory_key="chat_history")
    prompt = generate_prompt(identifier, input_value)
    agent = initialize_agent(tools, llm, agent="zero-shot-react-description", verbose=True)
    agent.run(prompt)

if __name__ == "__main__":
    main()

実行すると結果が英語で出力されるようになりました。

$ python intelgpt.py --hash fafe11f23567080fb14cfd3b51cb440b9c097804569402d720fd32dd66059830

Successfully initialized

> Entering new AgentExecutor chain...
 I need to find out if this hash value is associated with a malicious file
Action: Google Search
Action Input: fafe11f23567080fb14cfd3b51cb440b9c097804569402d720fd32dd66059830
Observation: Nov 3, 2022 ... fd93693b2f1a8649192175a64e9861d456ac1712. SHA256: fafe11f23567080fb14cfd3b51cb440b9c097804569402d720fd32dd66059830. Technologies: Engines ... Jan 3, 2023 ... FAFE11F23567080FB14CFD3B51CB440B9C097804569402D720FD32DD66059830. Raspberry Robin. Yara Rules. SHA1: fd93693b2f1a8649192175a64e9861d456ac1712. SHA256: fafe11f23567080fb14cfd3b51cb440b9c097804569402d720fd32dd66059830. Tags: dll. ハッシュ値(SHA-256)fafe11f23567080fb14cfd3b51cb440b9c097804569402d720fd32dd66059830. エンジンStatic分析エンジン. 検証環境Windows10 × FFRI yarai 3.3.0 (2019 ...
Thought: It looks like this hash value is associated with a malicious file
Final Answer: The hash value (fafe11f23567080fb14cfd3b51cb440b9c097804569402d720fd32dd66059830) is associated with a malicious file.

> Finished chain.

最後に

今回は、langchainを使ってLinuxコマンド操作やGoogle検索の自動化を行いました。
検索順位によっては、Google検索の結果が間違っている可能性があるため、検索結果の取得方法やpromptについて工夫することで、間違いを最小限に減らすことができます。
また、同じような手法を使用すれば、OSINT以外の様々な調査活動にも応用することができます。
ちなみに、今回実装したコードはGithubにも公開しています。

この記事を読んで、少しでもお役に立てたなら幸いです。何か質問やご意見がありましたら、お気軽にご連絡ください。

参考にした記事

GitHubで編集を提案

Discussion