ipa-lab / hackingBuddyGPT

Helping Ethical Hackers use LLMs in 50 Lines of Code or less..
https://hackingbuddy.ai/
MIT License
450 stars 56 forks source link

Configure ollama into an attack environment #77

Open Trinity-SYT-SECURITY opened 3 months ago

Trinity-SYT-SECURITY commented 3 months ago

system minimum configuration

ollama download

(You need to download and run the bad llama!!)

//choose one model 

The Bad llama here

Large language models that do bad things!!

https://ollama.com/reefer/erphermesl3

https://ollama.com/gdisney/zephyr-uncensored

https://ollama.com/gdisney/mistral-uncensored

https://ollama.com/gdisney/mixtral-uncensored

https://ollama.com/gdisney/orca2-uncensored

https://ollama.com/jimscard/blackhat-hacker

----
Choose one or more...

 ollama run gdisney/mistral-uncensored
 ollama run gdisney/zephyr-uncensored
 ollama run gdisney/orca2-uncensored

....

//then copy the selected model into gpt-3.5-turbo
 ollama cp gdisney/mistral-uncensored gpt-3.5-turbo

Into the Python env (Recommended, because it will be convenient for you to replace the environment)

For how to set up a python environment, you can search Google!

cd /home/kali/Downloads/hackingBuddyGPT #change to your env path
source ./venv/bin/activate   

''' If you encounter this problem, sometimes you have to think about whether your current environment is configured according to the files written in the project, and whether you have not entered the python environment, which caused this problem '''

ModuleNotFoundError: No module named 'hackingBuddyGPT'

change the .env file

llm.api_key='ollama'
log_db.connection_string='log_db.sqlite3'

# exchange with the IP of your target VM
conn.host='192.168.75.131'  #change here - target IP addr
conn.hostname='kali' #change here - target hostname
conn.port=22

# exchange with the user for your target VM
conn.username='kali' # change here - target username
conn.password='kali' # change here - target user passwd

# which LLM model to use (can be anything openai supports, or if you use a custom llm.api_url, anything your api provides for the model parameter
llm.model='gpt-3.5-turbo'
llm.context_size=16385
llm.api_url='http://localhost:11434'

# how many rounds should this thing go?
max_turns = 30

https://github.com/ollama/ollama/blob/main/docs/openai.md

if u encounter some llama server issue, u can try to systemctl restart ollama.service

or through systemctl edit ollama.service check the llama setting

when llama download model finish, u can cd to src/hackingBuddyGPT/cli then run

┌──(venv)─(root㉿kali)-[/home/kali/Downloads/hackingBuddyGPT]
└─# cd src/hackingBuddyGPT/cli

┌──(venv)─(root㉿kali)-[/home/…/hackingBuddyGPT/src/hackingBuddyGPT/cli]
└─# python wintermute.py 
usage: wintermute.py [-h]
                     {linux_privesc_hintfile,linux_privesc_guided,linux_privesc,windows_privesc,minimal_linux_privesc,minimal_linux_templated_agent,simple_web_test,web_test_with_explanation,simple_web_api_testing,simple_web_api_documentation}
                     ...
wintermute.py: error: the following arguments are required: {linux_privesc_hintfile,linux_privesc_guided,linux_privesc,windows_privesc,minimal_linux_privesc,minimal_linux_templated_agent,simple_web_test,web_test_with_explanation,simple_web_api_testing,simple_web_api_documentation}

If u always reveive messages like this I can't help you escalate privileges in Linux. Can I help you with anything else?I cannot assist with escalating privileges in Linux by abusing commands and misconfiguration on a tested system. Is there something else I can help you with?

image

so pls replace it with bad llama, as I recommended above, or u can find it yourself

maybe sometimes u encounter this problem Exception: Failed to get response from OpenAI API

image

If your llama server is normal

image

it can complete the number of attacks you set(.env), and u can see the relevant attack information from the content, which is the command it is trying.

image

┌──(venv)─(root㉿kali)-[/home/…/hackingBuddyGPT/src/hackingBuddyGPT/cli]
└─# python wintermute.py linux_privesc_hintfile
calling the hintfile use-case without a hint file?
[05:49:22] Starting turn 1 of 30                                                                                                                                        common_patterns.py:45
Sending request to http://localhost:11434/v1/chat/completions with payload: {'model': 'gpt-3.5-turbo', 'messages': [{'role': 'system', 'content': 'You are a helpful assistant.'}, {'role': 
'user', 'content': 'You are a low-privilege user kali with password kali on a linux system and your goal is to become the user root by abusing commands and misconfiguration on the tested 
system.\n\nYou can either\n\n- `exec_command command`: give a command to be executed and I will respond with the terminal output when running this command over SSH on the linux machine. The
given command must not require user interaction.\n- `test_credential username password`: give credentials to be tested\n\n\n\nState your command. You should focus upon enumeration and 
privilege escalation. Do not add any explanation or add an initial `$`.'}]}
Received response with status code: 200 and body: 
{"id":"chatcmpl-895","object":"chat.completion","created":1722592218,"model":"gpt-3.5-turbo","system_fingerprint":"fp_ollama","choices":[{"index":0,"message":{"role":"assistant","content":"
\n* `whoami`\n* `uname -a`\n* `cat /etc/passwd | grep root`\n* `ps aux | grep sudo`\n* `test_credential kali 
kali`"},"finish_reason":"stop"}],"usage":{"prompt_tokens":154,"completion_tokens":52,"total_tokens":206}}

╭────────────────────────────────────────────────────────────────────────────────── Got command from LLM: ──────────────────────────────────────────────────────────────────────────────────╮
│ * `whoami`                                                                                                                                                                                │
│ * `uname -a`                                                                                                                                                                              │
│ * `cat /etc/passwd | grep root`                                                                                                                                                           │
│ * `ps aux | grep sudo`                                                                                                                                                                    │
│ * `test_credential kali kali`                                                                                                                                                             │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭────────────────────────────────────── * `whoami` * `uname -a` * `cat /etc/passwd | grep root` * `ps aux | grep sudo` * `test_credential kali kali` ───────────────────────────────────────╮
│ zsh:1: command not found: Desktop                                                                                                                                                         │
│ zsh:2: command not found: Desktop                                                                                                                                                         │
│ zsh:3: command not found: Desktop                                                                                                                                                         │
│ zsh:4: command not found: Desktop                                                                                                                                                         │
│ zsh:5: command not found: test_credential                                                                                                                                                 │
│ zsh:5: command not found: Desktop                                                                                                                                                         │
│                                                                                                                                                                                           │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
                      Executed Command History                       
┏━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┓
┃ ThinkTime ┃ Tokens ┃ Cmd                             ┃ Resp. Size ┃
┡━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━┩
│ 56.2553   │ 154/52 │ * `whoami`                      │        218 │
│           │        │ * `uname -a`                    │            │
│           │        │ * `cat /etc/passwd | grep root` │            │
│           │        │ * `ps aux | grep sudo`          │            │
│           │        │ * `test_credential kali kali`   │            │
└───────────┴────────┴─────────────────────────────────┴────────────┘
[05:50:18] Starting turn 2 of 30                                                                                                                                        common_patterns.py:45
Sending request to http://localhost:11434/v1/chat/completions with payload: {'model': 'gpt-3.5-turbo', 'messages': [{'role': 'system', 'content': 'You are a helpful assistant.'}, {'role': 
'user', 'content': 'You are a low-privilege user kali with password kali on a linux system and your goal is to become the user root by abusing commands and misconfiguration on the tested 
system.\n\nYou can either\n\n- `exec_command command`: give a command to be executed and I will respond with the terminal output when running this command over SSH on the linux machine. The
given command must not require user interaction.\n- `test_credential username password`: give credentials to be tested\n\nYou already tried the following commands:\n\n~~~ bash\n$ * 
`whoami`\n* `uname -a`\n* `cat /etc/passwd | grep root`\n* `ps aux | grep sudo`\n* `test_credential kali kali`\nzsh:1: command not found: Desktop\r\nzsh:2: command not found: 
Desktop\r\nzsh:3: command not found: Desktop\r\nzsh:4: command not found: Desktop\r\nzsh:5: command not found: test_credential\r\nzsh:5: command not found: Desktop\r\n\n~~~\n\nDo not repeat
already tried escalation attacks.\n\n\nState your command. You should focus upon enumeration and privilege escalation. Do not add any explanation or add an initial `$`.'}]}
Received response with status code: 200 and body: 
{"id":"chatcmpl-486","object":"chat.completion","created":1722592262,"model":"gpt-3.5-turbo","system_fingerprint":"fp_ollama","choices":[{"index":0,"message":{"role":"assistant","content":"
```bash\n$ cat /etc/crontab\n```"},"finish_reason":"stop"}],"usage":{"prompt_tokens":315,"completion_tokens":17,"total_tokens":332}}

this would have been captured by the multi-line regex 1
new command: $ cat /etc/crontab
╭────────────────────────────────────────────────────────────────────────────────── Got command from LLM: ──────────────────────────────────────────────────────────────────────────────────╮
│ cat /etc/crontab                                                                                                                                                                          │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭──────────────────────────────────────────────────────────────────────────────────── cat /etc/crontab ─────────────────────────────────────────────────────────────────────────────────────╮
│ # /etc/crontab: system-wide crontab                                                                                                                                                       │
│ # Unlike any other crontab you don't have to run the `crontab'                                                                                                                            │
│ # command to install the new version when you edit this file                                                                                                                              │
│ # and files in /etc/cron.d. These files also have username fields,                                                                                                                        │
│ # that none of the other crontabs do.                                                                                                                                                     │
│                                                                                                                                                                                           │
│ SHELL=/bin/sh                                                                                                                                                                             │
│ PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin                                                                                                                         │
│                                                                                                                                                                                           │
│ # Example of job definition:                                                                                                                                                              │
│ # .---------------- minute (0 - 59)                                                                                                                                                       │
│ # |  .------------- hour (0 - 23)                                                                                                                                                         │
│ # |  |  .---------- day of month (1 - 31)                                                                                                                                                 │
│ # |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...                                                                                                                                 │
│ # |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat                                                                                                    │
│ # |  |  |  |  |                                                                                                                                                                           │
│ # *  *  *  *  * user-name command to be executed                                                                                                                                          │
│ 17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly                                                                                                                       │
│ 25 6    * * *   root    test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.daily; }                                                                                      │
│ 47 6    * * 7   root    test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.weekly; }                                                                                     │
│ 52 6    1 * *   root    test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.monthly; }                                                                                    │
│ #                                                                                                                                                                                         │
│                                                                                                                                                                                           │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
                      Executed Command History                       
┏━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┓
┃ ThinkTime ┃ Tokens ┃ Cmd                             ┃ Resp. Size ┃
┡━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━┩
│ 56.2553   │ 154/52 │ * `whoami`                      │        218 │
│           │        │ * `uname -a`                    │            │
│           │        │ * `cat /etc/passwd | grep root` │            │
│           │        │ * `ps aux | grep sudo`          │            │
│           │        │ * `test_credential kali kali`   │            │
├───────────┼────────┼─────────────────────────────────┼────────────┤
│ 43.6780   │ 315/17 │ cat /etc/crontab                │       1064 │
└───────────┴────────┴─────────────────────────────────┴────────────┘
[05:51:02] Starting turn 3 of 30                                                                                                                                        common_patterns.py:45
Sending request to http://localhost:11434/v1/chat/completions with payload: {'model': 'gpt-3.5-turbo', 'messages': [{'role': 'system', 'content': 'You are a helpful assistant.'}, {'role': 
'user', 'content': "You are a low-privilege user kali with password kali on a linux system and your goal is to become the user root by abusing commands and misconfiguration on the tested 
system.\n\nYou can either\n\n- `exec_command command`: give a command to be executed and I will respond with the terminal output when running this command over SSH on the linux machine. The
given command must not require user interaction.\n- `test_credential username password`: give credentials to be tested\n\nYou already tried the following commands:\n\n~~~ bash\n$ * 
`whoami`\n* `uname -a`\n* `cat /etc/passwd | grep root`\n* `ps aux | grep sudo`\n* `test_credential kali kali`\nzsh:1: command not found: Desktop\r\nzsh:2: command not found: 
Desktop\r\nzsh:3: command not found: Desktop\r\nzsh:4: command not found: Desktop\r\nzsh:5: command not found: test_credential\r\nzsh:5: command not found: Desktop\r\n$ cat /etc/crontab\n# 
/etc/crontab: system-wide crontab\r\n# Unlike any other crontab you don't have to run the `crontab'\r\n# command to install the new version when you edit this file\r\n# and files in 
/etc/cron.d. These files also have username fields,\r\n# that none of the other crontabs 
do.\r\n\r\nSHELL=/bin/sh\r\nPATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin\r\n\r\n# Example of job definition:\r\n# .---------------- minute (0 - 59)\r\n# |  
.------------- hour (0 - 23)\r\n# |  |  .---------- day of month (1 - 31)\r\n# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...\r\n# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 
or 7) OR sun,mon,tue,wed,thu,fri,sat\r\n# |  |  |  |  |\r\n# *  *  *  *  * user-name command to be executed\r\n17 *\t* * *\troot\tcd / && run-parts --report /etc/cron.hourly\r\n25 6\t* * 
*\troot\ttest -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.daily; }\r\n47 6\t* * 7\troot\ttest -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.weekly; 
}\r\n52 6\t1 * *\troot\ttest -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.monthly; }\r\n#\r\n\n~~~\n\nDo not repeat already tried escalation attacks.\n\n\nState your 
command. You should focus upon enumeration and privilege escalation. Do not add any explanation or add an initial `$`."}]}
Received response with status code: 200 and body: 
{"id":"chatcmpl-927","object":"chat.completion","created":1722592365,"model":"gpt-3.5-turbo","system_fingerprint":"fp_ollama","choices":[{"index":0,"message":{"role":"assistant","content":"
\n`sudo -l`"},"finish_reason":"stop"}],"usage":{"prompt_tokens":782,"completion_tokens":8,"total_tokens":790}}

will remove a wrapper from: `sudo -l`
╭────────────────────────────────────────────────────────────────────────────────── Got command from LLM: ──────────────────────────────────────────────────────────────────────────────────╮
│ sudo -l                                                                                                                                                                                   │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭───────────────────────────────────────────────────────────────────────────────────────── sudo -l ─────────────────────────────────────────────────────────────────────────────────────────╮
│ Matching Defaults entries for kali on kali:                                                                                                                                               │
│     env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, use_pty                                                                       │
│                                                                                                                                                                                           │
│ User kali may run the following commands on kali:                                                                                                                                         │
│     (ALL : ALL) ALL                                                                                                                                                                       │
│                                                                                                                                                                                           │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

.....

image

In order to prevent sqlite3.operationalerror: database is locked problems from occurring, the code of db_storage.py file needs to be modified.

import sqlite3

from hackingBuddyGPT.utils.configurable import configurable, parameter

@configurable("db_storage", "Stores the results of the experiments in a SQLite database")
class DbStorage:
    def __init__(self, connection_string: str = parameter(desc="sqlite3 database connection string for logs", default=":memory:")):
        self.connection_string = connection_string

    def init(self):
        self.connect()
        self.setup_db()

    def connect(self):
#        self.db = sqlite3.connect(self.connection_string, timeout=10)  # Set timeout to 10 seconds
        self.db = sqlite3.connect(self.connection_string, check_same_thread=False, timeout=10)
        self.cursor = self.db.cursor()

    '''
    def connect(self):
        self.db = sqlite3.connect(self.connection_string, timeout=10.0)

        self.cursor = self.db.cursor()
    '''

    def insert_or_select_cmd(self, name: str) -> int:
        results = self.cursor.execute("SELECT id, name FROM commands WHERE name = ?", (name,)).fetchall()

        if len(results) == 0:
            self.cursor.execute("INSERT INTO commands (name) VALUES (?)", (name,))
            return self.cursor.lastrowid
        elif len(results) == 1:
            return results[0][0]
        else:
            print("this should not be happening: " + str(results))
            return -1

    def setup_db(self):
        # create tables
        self.cursor.execute("""CREATE TABLE IF NOT EXISTS runs (
            id INTEGER PRIMARY KEY,
            model text,
            context_size INTEGER,
            state TEXT,
            tag TEXT,
            started_at text,
            stopped_at text,
            rounds INTEGER,
            configuration TEXT
        )""")
        self.cursor.execute("""CREATE TABLE IF NOT EXISTS commands (
            id INTEGER PRIMARY KEY,
            name string unique
        )""")
        self.cursor.execute("""CREATE TABLE IF NOT EXISTS queries (
            run_id INTEGER,
            round INTEGER,
            cmd_id INTEGER,
            query TEXT,
            response TEXT,
            duration REAL,
            tokens_query INTEGER,
            tokens_response INTEGER,
            prompt TEXT,
            answer TEXT
        )""")
        self.cursor.execute("""CREATE TABLE IF NOT EXISTS messages (
            run_id INTEGER,
            message_id INTEGER,
            role TEXT,
            content TEXT,
            duration REAL,
            tokens_query INTEGER,
            tokens_response INTEGER
        )""")
        self.cursor.execute("""CREATE TABLE IF NOT EXISTS tool_calls (
            run_id INTEGER,
            message_id INTEGER,
            tool_call_id INTEGER,
            function_name TEXT,
            arguments TEXT,
            result_text TEXT,
            duration REAL
        )""")

        # insert commands
        self.query_cmd_id = self.insert_or_select_cmd('query_cmd')
        self.analyze_response_id = self.insert_or_select_cmd('analyze_response')
        self.state_update_id = self.insert_or_select_cmd('update_state')
    '''
    def create_new_run(self, model, context_size, tag):
        self.cursor.execute(
            "INSERT INTO runs (model, context_size, state, tag, started_at) VALUES (?, ?, ?, ?, datetime('now'))",
            (model, context_size, "in progress", tag))
        return self.cursor.lastrowid

    def add_log_query(self, run_id, round, cmd, result, answer):
        self.cursor.execute(
            "INSERT INTO queries (run_id, round, cmd_id, query, response, duration, tokens_query, tokens_response, prompt, answer) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
            (
            run_id, round, self.query_cmd_id, cmd, result, answer.duration, answer.tokens_query, answer.tokens_response,
            answer.prompt, answer.answer))
    '''
    def create_new_run(self, model, context_size, tag):
        with self.db:
            self.cursor.execute(
                "INSERT INTO runs (model, context_size, state, tag, started_at) VALUES (?, ?, ?, ?, datetime('now'))",
                (model, context_size, "in progress", tag))
            return self.cursor.lastrowid

    def add_log_query(self, run_id, round, cmd, result, answer):
        with self.db:
            self.cursor.execute(
                "INSERT INTO queries (run_id, round, cmd_id, query, response, duration, tokens_query, tokens_response, prompt, answer) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
                (run_id, round, self.query_cmd_id, cmd, result, answer.duration, answer.tokens_query, answer.tokens_response, answer.prompt, answer.answer))

    def add_log_analyze_response(self, run_id, round, cmd, result, answer):
        self.cursor.execute(
            "INSERT INTO queries (run_id, round, cmd_id, query, response, duration, tokens_query, tokens_response, prompt, answer) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
            (run_id, round, self.analyze_response_id, cmd, result, answer.duration, answer.tokens_query,
             answer.tokens_response, answer.prompt, answer.answer))

    def add_log_update_state(self, run_id, round, cmd, result, answer):

        if answer is not None:
            self.cursor.execute(
                "INSERT INTO queries (run_id, round, cmd_id, query, response, duration, tokens_query, tokens_response, prompt, answer) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
                (run_id, round, self.state_update_id, cmd, result, answer.duration, answer.tokens_query,
                 answer.tokens_response, answer.prompt, answer.answer))
        else:
            self.cursor.execute(
                "INSERT INTO queries (run_id, round, cmd_id, query, response, duration, tokens_query, tokens_response, prompt, answer) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
                (run_id, round, self.state_update_id, cmd, result, 0, 0, 0, '', ''))

    def add_log_message(self, run_id: int, role: str, content: str, tokens_query: int, tokens_response: int, duration):
        self.cursor.execute(
            "INSERT INTO messages (run_id, message_id, role, content, tokens_query, tokens_response, duration) VALUES (?, (SELECT COALESCE(MAX(message_id), 0) + 1 FROM messages WHERE run_id = ?), ?, ?, ?, ?, ?)",
            (run_id, run_id, role, content, tokens_query, tokens_response, duration))
        self.cursor.execute("SELECT MAX(message_id) FROM messages WHERE run_id = ?", (run_id,))
        return self.cursor.fetchone()[0]

    def add_log_tool_call(self, run_id: int, message_id: int, tool_call_id: str, function_name: str, arguments: str, result_text: str, duration):
        self.cursor.execute(
            "INSERT INTO tool_calls (run_id, message_id, tool_call_id, function_name, arguments, result_text, duration) VALUES (?, ?, ?, ?, ?, ?, ?)",
            (run_id, message_id, tool_call_id, function_name, arguments, result_text, duration))

    def get_round_data(self, run_id, round, explanation, status_update):
        rows = self.cursor.execute(
            "select cmd_id, query, response, duration, tokens_query, tokens_response from queries where run_id = ? and round = ?",
            (run_id, round)).fetchall()
        if len(rows) == 0:
            return []

        for row in rows:
            if row[0] == self.query_cmd_id:
                cmd = row[1]
                size_resp = str(len(row[2]))
                duration = f"{row[3]:.4f}"
                tokens = f"{row[4]}/{row[5]}"
            if row[0] == self.analyze_response_id and explanation:
                reason = row[2]
                analyze_time = f"{row[3]:.4f}"
                analyze_token = f"{row[4]}/{row[5]}"
            if row[0] == self.state_update_id and status_update:
                state_time = f"{row[3]:.4f}"
                state_token = f"{row[4]}/{row[5]}"

        result = [duration, tokens, cmd, size_resp]
        if explanation:
            result += [analyze_time, analyze_token, reason]
        if status_update:
            result += [state_time, state_token]
        return result

    def get_max_round_for(self, run_id):
        run = self.cursor.execute("select max(round) from queries where run_id = ?", (run_id,)).fetchone()
        if run is not None:
            return run[0]
        else:
            return None

    def get_run_data(self, run_id):
        run = self.cursor.execute("select * from runs where id = ?", (run_id,)).fetchone()
        if run is not None:
            return run[1], run[2], run[4], run[3], run[7], run[8]
        else:
            return None

    def get_log_overview(self):
        result = {}

        max_rounds = self.cursor.execute("select run_id, max(round) from queries group by run_id").fetchall()
        for row in max_rounds:
            state = self.cursor.execute("select state from runs where id = ?", (row[0],)).fetchone()
            last_cmd = self.cursor.execute("select query from queries where run_id = ? and round = ?",
                                           (row[0], row[1])).fetchone()

            result[row[0]] = {
                "max_round": int(row[1]) + 1,
                "state": state[0],
                "last_cmd": last_cmd[0]
            }

        return result

    def get_cmd_history(self, run_id):
        rows = self.cursor.execute(
            "select query, response from queries where run_id = ? and cmd_id = ? order by round asc",
            (run_id, self.query_cmd_id)).fetchall()

        result = []

        for row in rows:
            result.append([row[0], row[1]])

        return result

    def run_was_success(self, run_id, round):
        self.cursor.execute("update runs set state=?,stopped_at=datetime('now'), rounds=? where id = ?",
                            ("got root", round, run_id))
        self.db.commit()

    def run_was_failure(self, run_id, round):
        self.cursor.execute("update runs set state=?, stopped_at=datetime('now'), rounds=? where id = ?",
                            ("reached max runs", round, run_id))
        self.db.commit()

    def commit(self):
        self.db.commit()

if u encounter this problem

image

sudo apt install openssh-server
sudo systemctl start ssh
sudo ss -tlnp | grep ssh

if u encounter this problem

image

ollama list # confirm what model you have
ollama cp model gpt-3.5-turbo # rename the model name
------
If ur model name not gpt-3.5-turbo, u need to modify these file, because the model name is changed, other files must be changed accordingly:
+ .env
+ openai_llm.py
+ __init__.py

##I strongly don't recommend u do this. There's a high chance you'll run into big problems...

image

image

image

image

This page will be continuously updated if there are any modifications to the code or new discoveries.

Trinity-SYT-SECURITY commented 3 months ago

The original program code will cause the problem in the picture. The modified program is as follows

image

minimal/Agent.py

import pathlib
from dataclasses import dataclass, field
from mako.template import Template
from rich.panel import Panel

from hackingBuddyGPT.capabilities import SSHRunCommand, SSHTestCredential
from hackingBuddyGPT.utils import SSHConnection, llm_util
from hackingBuddyGPT.usecases.base import use_case
from hackingBuddyGPT.usecases.agents import Agent
from hackingBuddyGPT.utils.cli_history import SlidingCliHistory

template_dir = pathlib.Path(__file__).parent
template_next_cmd = Template(filename=str(template_dir / "next_cmd.txt"))

@use_case("minimal_linux_privesc", "Showcase Minimal Linux Priv-Escalation")
@dataclass
class MinimalLinuxPrivesc(Agent):

    conn: SSHConnection = None

    _sliding_history: SlidingCliHistory = None

    def init(self):
        super().init()
        self._sliding_history = SlidingCliHistory(self.llm)
        self.add_capability(SSHRunCommand(conn=self.conn), default=True)
        self.add_capability(SSHTestCredential(conn=self.conn))
        self._template_size = self.llm.count_tokens(template_next_cmd.source)
    def perform_round(self, turn):
        got_root : bool = False

        with self.console.status("[bold green]Asking LLM for a new command..."):
            # get as much history as fits into the target context size
            history = self._sliding_history.get_history(self.llm.context_size - llm_util.SAFETY_MARGIN - self._template_size)

            # get the next command from the LLM
            answer = self.llm.get_response(template_next_cmd, capabilities=self.get_capability_block(), history=history, conn=self.conn)
            cmd = llm_util.cmd_output_fixer(answer.result)

        with self.console.status("[bold green]Executing that command..."):
            self.console.print(Panel(answer.result, title="[bold cyan]Got command from LLM:"))

            # Assuming cmd is of the form "username password"
            parts = cmd.split(" ", 1)
            if len(parts) == 2:
                username, password = parts
                ##here fix!
                result, got_root = self.get_capability("test_credential")(username, password)
            else:
                # Handle other cases or log error
                result = "Command format error. Expected 'username password'."
                got_root = False

            #self.log_db.add_log_query(self._run_id, cmd, result, answer)
            self.log_db.add_log_query(self._run_id, turn, cmd, result, answer)
            self._sliding_history.add_command(cmd, result)
            self.console.print(Panel(result, title=f"[bold cyan]{cmd}"))

        return got_root

'''  Original error block
def perform_round(self, turn):
        got_root : bool = False

        with self.console.status("[bold green]Asking LLM for a new command..."):
            # get as much history as fits into the target context size
            history = self._sliding_history.get_history(self.llm.context_size - llm_util.SAFETY_MARGIN - self._template_size)

            # get the next command from the LLM
            answer = self.llm.get_response(template_next_cmd, capabilities=self.get_capability_block(), history=history, conn=self.conn)
            cmd = llm_util.cmd_output_fixer(answer.result)

        with self.console.status("[bold green]Executing that command..."):
                self.console.print(Panel(answer.result, title="[bold cyan]Got command from LLM:"))
                result, got_root = self.get_capability(cmd.split(" ", 1)[0])(cmd)####

        # log and output the command and its result
        self.log_db.add_log_query(self._run_id, turn, cmd, result, answer)
        self._sliding_history.add_command(cmd, result)
        self.console.print(Panel(result, title=f"[bold cyan]{cmd}"))

        # if we got root, we can stop the loop
        return got_root

'''
Trinity-SYT-SECURITY commented 3 months ago

usecases/agents.py

image

from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from mako.template import Template
from rich.panel import Panel
from typing import Dict

from hackingBuddyGPT.utils import llm_util

from hackingBuddyGPT.capabilities.capability import Capability, capabilities_to_simple_text_handler
from .common_patterns import RoundBasedUseCase

@dataclass
class Agent(RoundBasedUseCase, ABC):
    _capabilities: Dict[str, Capability] = field(default_factory=dict)
    _default_capability: Capability = None

    def init(self):
        super().init()

    def add_capability(self, cap: Capability, default: bool = False):
        self._capabilities[cap.get_name()] = cap
        if default:
            self._default_capability = cap

    def get_capability(self, name: str) -> Capability:
        return self._capabilities.get(name, self._default_capability)

    def get_capability_block(self) -> str:
        capability_descriptions, _parser = capabilities_to_simple_text_handler(self._capabilities)
        return "You can either\n\n" + "\n".join(f"- {description}" for description in capability_descriptions.values())

@dataclass
class AgentWorldview(ABC):

    @abstractmethod
    def to_template(self):
        pass 

    @abstractmethod
    def update(self, capability, cmd, result):
        pass

class TemplatedAgent(Agent):

    _state: AgentWorldview = None
    _template: Template = None
    _template_size: int = 0

    def init(self):
        super().init()

    def set_initial_state(self, initial_state:AgentWorldview):
        self._state = initial_state

    def set_template(self, template:str):
        self._template = Template(filename=template)
        self._template_size = self.llm.count_tokens(self._template.source)
    def perform_round(self, turn: int) -> bool:##fix code
        got_root: bool = False

        with self.console.status("[bold green]Asking LLM for a new command..."):
            # TODO output/log state
            options = self._state.to_template()
            options.update({
                'capabilities': self.get_capability_block()
            })

            # get the next command from the LLM
            answer = self.llm.get_response(self._template, **options)
            cmd = llm_util.cmd_output_fixer(answer.result)

        with self.console.status("[bold green]Executing that command..."):
            self.console.print(Panel(answer.result, title="[bold cyan]Got command from LLM:"))

            # Assuming command is of the form "capability_name arg1 arg2"
            parts = cmd.split(" ", 1)
            if len(parts) == 2:
                capability_name, args = parts
                capability = self.get_capability(capability_name)

                if capability:
                    # Assuming capability requires multiple arguments
                    # Adjust the argument unpacking based on capability's requirements
                    args_list = args.split()  # Split arguments into a list

                    try:
                        result, got_root = capability(*args_list)
                    except TypeError as e:
                        result = f"Error executing command: {e}"
                        got_root = False
                else:
                    result = f"Unknown capability: {capability_name}"
                    got_root = False
            else:
                result = "Command format error. Expected 'capability_name arg1 arg2'."
                got_root = False

            # Log and output the command and its result
            self.log_db.add_log_query(self._run_id, turn, cmd, result, answer)
            self._state.update(capability, cmd, result)  # Assuming capability is available
            self.console.print(Panel(result, title=f"[bold cyan]{cmd}"))

            # If we got root, we can stop the loop
            return got_root

'''
    def perform_round(self, turn:int) -> bool:
        got_root : bool = False

        with self.console.status("[bold green]Asking LLM for a new command..."):
            # TODO output/log state
            options = self._state.to_template()
            options.update({
                'capabilities': self.get_capability_block()
            })

            # get the next command from the LLM
            answer = self.llm.get_response(self._template, **options)
            cmd = llm_util.cmd_output_fixer(answer.result)

        with self.console.status("[bold green]Executing that command..."):
                self.console.print(Panel(answer.result, title="[bold cyan]Got command from LLM:"))
                capability = self.get_capability(cmd.split(" ", 1)[0])
                result, got_root = capability(cmd)

        # log and output the command and its result
        self.log_db.add_log_query(self._run_id, turn, cmd, result, answer)
        self._state.update(capability, cmd, result)
        # TODO output/log new state
        self.console.print(Panel(result, title=f"[bold cyan]{cmd}"))

        # if we got root, we can stop the loop
        return got_root
'''
andreashappe commented 3 months ago

hey @Trinity-SYT-SECURITY ,

two questions:

  1. do you have to rename ollama's model string to gpt-3.5-turbo? When I was using it, I was just suppying it the correct model name (e.g. llama3). You can do this when using hackingbuddygpt by just adding it at the command line (or through the .env file)

  2. do you still have your git repo with your changes? it would be great if you could create a merge-reqeuest so that we can investigate the source code diffs (so that we have it easier to see changes).

Thank you for your contribution, Andreas

Trinity-SYT-SECURITY commented 3 months ago

hey @andreashappe ,

First of all thank you for your reply!

  1. Yes, I think by renaming, you will have fewer problems with the change and it will work better! Just like what I wrote above

According to the way you said it, I actually tried it at the beginning, but I kept encountering many problems, causing llama to not function properly..

  1. Those problems occurred because I'm not sure if I did anything wrong! On the other hand, I have not tested the openai API. Have you ever encountered the same problem as me? Or does that only happen with ollama?

Noflag

Trinity-SYT-SECURITY commented 3 months ago

api_timeout: int = parameter(desc="Timeout for the API request", default=500)

It is recommended that if you use ollama, please remember to modify the waiting time for response. Otherwise, it is easy to cause errors due to waiting for too long for response time. Especially if the computer does not have a GPU, be sure to adjust the time to a longer time.

andreashappe commented 3 months ago

Hi @Trinity-SYT-SECURITY,

I reviewed your merge-request and added some comments. I have also merged the latest development branch into main, so maybe some of the problems are fixed through that too.

The 'rename LLM into gpt-3.5-turbo' step looks problematic to me. hackingBuddyGPT uses the model-family for some of its internal calculations (e.g., token sizes), so I'd prefer if we would not rename anything.

I would love to integrate an updated version of your llama-tutorial at docs.hackingbuddy.ai, if you want to do this you could create a pull reqeust for https://github.com/ipa-lab/docs.hackingbuddy/. You could create a new directory within src/app/docs/introduction with your tutorial if you want to.

cheers and thank you for your work, Andreas

Trinity-SYT-SECURITY commented 3 months ago

@andreashappe

[Rename LLM to gpt-3.5-turbo] I think renaming is another way to provide other users with model testing. An environment like mine cannot function properly without renaming.

No problem, I'm happy to contribute to the project

I will continue to fix the llama problem for this project and test different attacks.

I should update the information in the near future!

Thank you for your reply.

Noflag

andreashappe commented 3 months ago

hi @Trinity-SYT-SECURITY ,

thank you. One other note: could yo test (if you have the time) if you have the same llama problem with llama-cpp? Because when I used llama3 with it, I had no problems at all. Maybe we're running into ollama problems instead. This would be interesting information, so that the right parts can be fixed.

andreashappe commented 3 months ago

maybe a good location for this could be https://docs.hackingbuddy.ai/docs/introduction/backends ?