From 099755dbcb6ee05348ae967e9645ed1af3c1b9e4 Mon Sep 17 00:00:00 2001 From: carlospolop Date: Sun, 2 Jul 2023 15:45:35 +0200 Subject: [PATCH] actions --- .github/actions/aicoder/action.yml | 53 +++++ .github/actions/aicoder/gh-aicoder.py | 47 ++++ .github/workflows/aicoder.yml | 22 ++ AICoder.py | 208 ++++++++++++++++++ .../linpeas_parts/1_system_information.sh | 142 ------------ 5 files changed, 330 insertions(+), 142 deletions(-) create mode 100644 .github/actions/aicoder/action.yml create mode 100644 .github/actions/aicoder/gh-aicoder.py create mode 100644 .github/workflows/aicoder.yml create mode 100644 AICoder.py diff --git a/.github/actions/aicoder/action.yml b/.github/actions/aicoder/action.yml new file mode 100644 index 0000000..af52745 --- /dev/null +++ b/.github/actions/aicoder/action.yml @@ -0,0 +1,53 @@ +name: 'AICoder GH Action' +description: 'A GitHub action that uses AICoder to generate PRs improving the code of files absed on prompts' +author: 'carlospolop' +inputs: + INPUT_MODE: + description: 'Mode of operation' + required: true + INPUT_PROMPT: + description: 'Prompt for the AI' + required: false + INPUT_API_KEY: + description: 'OpenAI API Key' + required: true + INPUT_MODEL: + description: 'Model to use for AI' + required: false + TEMPLATE_FILES: + description: 'Template files for file-generator mode' + required: false + CHECK_PATH: + description: 'Path to file/folder to modify' + required: false + ORIGIN_BRANCH: + description: 'Origin branch to checkout' + required: true + TO_BRANCH: + description: 'Branch to commit changes' + required: true +runs: + using: 'composite' + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.x' + - name: Install dependencies + run: pip3 install aicoder + shell: bash + - name: Run AI Coder + run: python3 gh-aicoder.py + env: + INPUT_MODE: ${{ inputs.INPUT_MODE }} + INPUT_PROMPT: ${{ inputs.INPUT_PROMPT }} + INPUT_API_KEY: ${{ inputs.INPUT_API_KEY }} + INPUT_MODEL: ${{ inputs.INPUT_MODEL }} + TEMPLATE_FILES: ${{ inputs.TEMPLATE_FILES }} + ORIGIN_BRANCH: ${{ inputs.ORIGIN_BRANCH }} + TO_BRANCH: ${{ inputs.TO_BRANCH }} + CHECK_PATH: ${{ inputs.CHECK_PATH }} + shell: bash + diff --git a/.github/actions/aicoder/gh-aicoder.py b/.github/actions/aicoder/gh-aicoder.py new file mode 100644 index 0000000..ce0a678 --- /dev/null +++ b/.github/actions/aicoder/gh-aicoder.py @@ -0,0 +1,47 @@ +import subprocess +import os + +# https://docs.github.com/en/actions/learn-github-actions/finding-and-customizing-actions +def main(mode, prompt, api_key, model, path, template_files): + + # Get inputs from env variables + mode = os.environ.get("INPUT_MODE").lower() + prompt = os.environ.get("INPUT_PROMPT", "") + api_key = os.environ.get("INPUT_API_KEY") + model = os.environ.get("INPUT_MODEL", "gpt-4") + path = os.environ.get("CHECK_PATH", "") + template_files = os.environ.get("TEMPLATE_FILES", "") + orig_branch = os.environ.get("ORIGIN_BRANCH", "") + to_branch = os.environ.get("TO_BRANCH", "") + + #Allowed modes + allowed_modes = ["file-enhancer", "file-generator", "file-security", "file-optimizer", "file-comments", "file-bugfixer"] + if mode not in allowed_modes: + raise ValueError(f"Mode must be one of {allowed_modes}") + + # Construct the aicoder command based on the mode + command = [ + "aicoder", + mode, + "--prompt", prompt, + "--api-key", api_key, + "--model", model, + "--orig-branch", orig_branch, + "--to-branch", to_branch + ] + + if path: + command.extend(["--path", path]) + elif template_files: + command.extend(["--template-files", template_files]) + else: + raise ValueError("Either path or template_files must be provided") + + if path and template_files: + raise ValueError("Either path or template_files must be provided") + + if template_files and mode != "file-generator": + raise ValueError("template_files can only be used with file-generator mode") + + # Run the command + subprocess.run(command) diff --git a/.github/workflows/aicoder.yml b/.github/workflows/aicoder.yml new file mode 100644 index 0000000..12942b5 --- /dev/null +++ b/.github/workflows/aicoder.yml @@ -0,0 +1,22 @@ +name: aicoder + +on: + workflow_dispatch: + +jobs: + Build_and_test_winpeas_master: + runs-on: ubuntu + + steps: + # checkout + - name: AICoder GH Action + uses: ./.github/actions/aicoder + with: + INPUT_MODE: 'file-optimizer' + INPUT_PROMPT: '' + INPUT_API_KEY: ${{ secrets.OPENAI_API_KEY }} + INPUT_MODEL: 'gpt-4' + TEMPLATE_FILES: '' + ORIGIN_BRANCH: 'aicoder' + TO_BRANCH: 'master' + CHECK_PATH: './parsers/json2pdf.py' \ No newline at end of file diff --git a/AICoder.py b/AICoder.py new file mode 100644 index 0000000..e302f88 --- /dev/null +++ b/AICoder.py @@ -0,0 +1,208 @@ +import argparse +import os +import sys +import string +import random +from typing import List +import openai +import json +import subprocess +import tiktoken +import requests +from github import Github + +######################### +#### OPENAI FUNCTIONS ### +######################### + +def reportTokens(prompt, model="gpt-4"): + encoding = tiktoken.encoding_for_model(model) + print("\033[37m" + str(len(encoding.encode(prompt))) + " tokens\033[0m" + " in prompt: " + "\033[92m" + prompt[:50] + "\033[0m" + ("..." if len(prompt) > 50 else "")) + +def write_file(file_path: str, content: str): + """Write content to a file creating the needed directories first""" + os.makedirs(os.path.dirname(file_path), exist_ok=True) + + with open(file_path, "w") as file: + file.write(content) + +def delete_file(file_path: str): + """Delete a file if it exists""" + + if os.path.isfile(file_path): + os.remove(file_path) + +openai_available_functions = { + "write_file": write_file, "delete_file": delete_file +} + +openai_functions = [ + { + "name": "write_file", + "description": "Write a file giving the path and the content", + "parameters": { + "type": "object", + "properties": { + "file_path": { + "type": "string", + "description": "Path to the file to write", + }, + "content": { + "type": "string", + "description": "Content to write in the file", + }, + }, + "required": ["file_path", "content"], + }, + }, + { + "name": "delete_file", + "description": "Delete a file", + "parameters": { + "type": "object", + "properties": { + "file_path": { + "type": "string", + "description": "Path to the file to write", + } + }, + "required": ["file_path"], + }, + } +] + + +######################### +#### GIT FUNCTIONS ###### +######################### + + +def create_pull_request(branch_name, commit_message, github_token): + github = Github(github_token) + repo = github.get_repo(os.environ["GITHUB_REPOSITORY"]) + + # Create a new branch + base_branch = repo.get_branch(repo.default_branch) + repo.create_git_ref(ref=f"refs/heads/{branch_name}", sha=base_branch.commit.sha) + + # Commit changes to the new branch + subprocess.run(["git", "checkout", branch_name]) + subprocess.run(["git", "add", "."]) + subprocess.run(["git", "commit", "-m", commit_message]) + subprocess.run(["git", "push", "origin", branch_name]) + + # Create a pull request + pr = repo.create_pull( + title=commit_message, + body="Generated by OpenAI Github Action", + head=branch_name, + base=repo.default_branch + ) + + return pr.html_url + + +######################### +#### FILE PROCESSING #### +######################### + + +def process_file(prompt: str, api_key: str, file_path: str, model: str="gpt-4") -> str: + with open(file_path, "r") as file: + file_content = file.read() + + messages = [ + {"role": "system", "content": f"You are a developer and your goal is to generate code. The user will ask you to improve and modify some code. Your response must be a valid JSON with the path of each file to write as keys and the content of the files as values. Several files can be written at the same time."}, + {"role": "user", "content": prompt}, + {"role": "user", "content": f"This is the code from the file '{file_path}':\n\n{file_content}"} + ] + openai.api_key = api_key + + reportTokens(f"This is the code from the file '{file_path}':\n\n{file_content}") + + response = openai.ChatCompletion.create( + model=model, + messages=messages, + temperature=0 + ) + response_message = response["choices"][0]["message"] + + # Step 2: check if GPT wanted to call a function + if response_message.get("function_call"): + + function_name = response_message["function_call"]["name"] + fuction_to_call = openai_available_functions[function_name] + function_args = json.loads(response_message["function_call"]["arguments"]) + fuction_to_call(**function_args) + + +def process_folder(prompt: str, api_key: str, folder_path: str, model: str="gpt-4") -> List[str]: + responses = [] + for root, _, files in os.walk(folder_path): + for file in files: + file_path = os.path.join(root, file) + response = process_file(prompt, api_key, file_path, model) + responses.append(response) + + +######################### +#### MAIN FUNCTION ###### +######################### + + +def get_random_string(length): + # With combination of lower and upper case + letters = string.ascii_letters + result_str = ''.join(random.choice(letters) for i in range(length)) + return result_str + +def main(prompt: str, api_key: str, file_path: str, github_token: str, model: str="gpt-4"): + if os.path.isfile(file_path): + process_file(prompt, api_key, file_path, model) + elif os.path.isdir(file_path): + process_folder(prompt, api_key, file_path, model) + else: + print("Error: Invalid file path.") + sys.exit(1) + + try: + create_pull_request(get_random_string(5), f"Modified {file_path}", github_token) + except Exception as e: + print(f"Error: Failed to create pull request. {e}") + sys.exit(1) + +if __name__ == "__main__": + # Setup the argument parser + parser = argparse.ArgumentParser() + + # Add arguments for prompt, api_key, file_path and github_token + parser.add_argument('--prompt', default=None, type=str, help='Input prompt') + parser.add_argument('--api-key', default=None, type=str, help='Input API key') + parser.add_argument('--path', default=None, type=str, help='Input file/folder path') + parser.add_argument('--github-token', default=None, type=str, help='Github token') + parser.add_argument('--model', default="gpt-4", type=str, help='Model to use') + + # Parse the arguments + args = parser.parse_args() + prompt = os.environ.get("INPUT_PROMPT", args.prompt) + api_key = os.environ.get("INPUT_API_KEY", args.api_key) + file_path = os.environ.get("INPUT_FILE_PATH", args.path) + github_token = os.environ.get("GITHUB_TOKEN", args.github_token) + model = os.environ.get("INPUT_MODEL", args.model) + + if not prompt or not api_key or not file_path: + print("Error: Missing required inputs.") + sys.exit(1) + + #if not github_token: + # print("Error: Missing github token.") + # sys.exit(1) + + if os.path.exists(prompt): + with open(prompt, "r") as file: + prompt = file.read() + + if prompt.startswith("http"): + prompt = requests.get(prompt).text + + main(prompt, api_key, file_path, github_token, model) \ No newline at end of file diff --git a/linPEAS/builder/linpeas_parts/1_system_information.sh b/linPEAS/builder/linpeas_parts/1_system_information.sh index 1579696..75c7d54 100644 --- a/linPEAS/builder/linpeas_parts/1_system_information.sh +++ b/linPEAS/builder/linpeas_parts/1_system_information.sh @@ -99,145 +99,3 @@ if [ "$(command -v smbutil)" ] || [ "$DEBUG" ]; then warn_exec smbutil statshares -a echo "" fi - -#-- SY) Environment vars -print_2title "Environment" -print_info "Any private information inside environment variables?" -(env || printenv || set) 2>/dev/null | grep -v "RELEVANT*|FIND*|^VERSION=|dbuslistG|mygroups|ldsoconfdG|pwd_inside_history|kernelDCW_Ubuntu_Precise|kernelDCW_Ubuntu_Trusty|kernelDCW_Ubuntu_Xenial|kernelDCW_Rhel|^sudovB=|^rootcommon=|^mounted=|^mountG=|^notmounted=|^mountpermsB=|^mountpermsG=|^kernelB=|^C=|^RED=|^GREEN=|^Y=|^B=|^NC=|TIMEOUT=|groupsB=|groupsVB=|knw_grps=|sidG|sidB=|sidVB=|sidVB2=|sudoB=|sudoG=|sudoVB=|timersG=|capsB=|notExtensions=|Wfolders=|writeB=|writeVB=|_usrs=|compiler=|PWD=|LS_COLORS=|pathshG=|notBackup=|processesDump|processesB|commonrootdirs|USEFUL_SOFTWARE|PSTORAGE_KUBERNETES" | sed -${E} "s,[pP][wW][dD]|[pP][aA][sS][sS][wW]|[aA][pP][iI][kK][eE][yY]|[aA][pP][iI][_][kK][eE][yY]|KRB5CCNAME,${SED_RED},g" || echo_not_found "env || set" -echo "" - -#-- SY) Dmesg -if [ "$(command -v dmesg 2>/dev/null)" ] || [ "$DEBUG" ]; then - print_2title "Searching Signature verification failed in dmesg" - print_info "https://book.hacktricks.xyz/linux-hardening/privilege-escalation#dmesg-signature-verification-failed" - (dmesg 2>/dev/null | grep "signature") || echo_not_found "dmesg" - echo "" -fi - -#-- SY) Kernel extensions -if [ "$MACPEAS" ]; then - print_2title "Kernel Extensions not belonging to apple" - kextstat 2>/dev/null | grep -Ev " com.apple." - - print_2title "Unsigned Kernel Extensions" - macosNotSigned /Library/Extensions - macosNotSigned /System/Library/Extensions -fi - -if [ "$(command -v bash 2>/dev/null)" ]; then - print_2title "Executing Linux Exploit Suggester" - print_info "https://github.com/mzet-/linux-exploit-suggester" - les_b64="peass{LES}" - echo $les_b64 | base64 -d | bash | sed "s,$(printf '\033')\\[[0-9;]*[a-zA-Z],,g" | grep -i "\[CVE" -A 10 | grep -Ev "^\-\-$" | sed -${E} "s/\[(CVE-[0-9]+-[0-9]+,?)+\].*/${SED_RED}/g" - echo "" -fi - -if [ "$(command -v perl 2>/dev/null)" ]; then - print_2title "Executing Linux Exploit Suggester 2" - print_info "https://github.com/jondonas/linux-exploit-suggester-2" - les2_b64="peass{LES2}" - echo $les2_b64 | base64 -d | perl 2>/dev/null | sed "s,$(printf '\033')\\[[0-9;]*[a-zA-Z],,g" | grep -i "CVE" -B 1 -A 10 | grep -Ev "^\-\-$" | sed -${E} "s,CVE-[0-9]+-[0-9]+,${SED_RED},g" - echo "" -fi - -if [ "$MACPEAS" ] && [ "$(command -v brew 2>/dev/null)" ]; then - print_2title "Brew Doctor Suggestions" - brew doctor - echo "" -fi - - - -#-- SY) AppArmor -print_2title "Protections" -print_list "AppArmor enabled? .............. "$NC -if [ "$(command -v aa-status 2>/dev/null)" ]; then - aa-status 2>&1 | sed "s,disabled,${SED_RED}," -elif [ "$(command -v apparmor_status 2>/dev/null)" ]; then - apparmor_status 2>&1 | sed "s,disabled,${SED_RED}," -elif [ "$(ls -d /etc/apparmor* 2>/dev/null)" ]; then - ls -d /etc/apparmor* -else - echo_not_found "AppArmor" -fi - -#-- SY) AppArmor2 -print_list "AppArmor profile? .............. "$NC -(cat /proc/self/attr/current 2>/dev/null || echo "unconfined") | sed "s,unconfined,${SED_RED}," | sed "s,kernel,${SED_GREEN}," - -#-- SY) LinuxONE -print_list "is linuxONE? ................... "$NC -( (uname -a | grep "s390x" >/dev/null 2>&1) && echo "Yes" || echo_not_found "s390x") - -#-- SY) grsecurity -print_list "grsecurity present? ............ "$NC -( (uname -r | grep "\-grsec" >/dev/null 2>&1 || grep "grsecurity" /etc/sysctl.conf >/dev/null 2>&1) && echo "Yes" || echo_not_found "grsecurity") - -#-- SY) PaX -print_list "PaX bins present? .............. "$NC -(command -v paxctl-ng paxctl >/dev/null 2>&1 && echo "Yes" || echo_not_found "PaX") - -#-- SY) Execshield -print_list "Execshield enabled? ............ "$NC -(grep "exec-shield" /etc/sysctl.conf 2>/dev/null || echo_not_found "Execshield") | sed "s,=0,${SED_RED}," - -#-- SY) SElinux -print_list "SELinux enabled? ............... "$NC -(sestatus 2>/dev/null || echo_not_found "sestatus") | sed "s,disabled,${SED_RED}," - -#-- SY) Seccomp -print_list "Seccomp enabled? ............... "$NC -([ "$(grep Seccomp /proc/self/status 2>/dev/null | grep -v 0)" ] && echo "enabled" || echo "disabled") | sed "s,disabled,${SED_RED}," | sed "s,enabled,${SED_GREEN}," - -#-- SY) AppArmor -print_list "User namespace? ................ "$NC -if [ "$(cat /proc/self/uid_map 2>/dev/null)" ]; then echo "enabled" | sed "s,enabled,${SED_GREEN},"; else echo "disabled" | sed "s,disabled,${SED_RED},"; fi - -#-- SY) cgroup2 -print_list "Cgroup2 enabled? ............... "$NC -([ "$(grep cgroup2 /proc/filesystems 2>/dev/null)" ] && echo "enabled" || echo "disabled") | sed "s,disabled,${SED_RED}," | sed "s,enabled,${SED_GREEN}," - -#-- SY) Gatekeeper -if [ "$MACPEAS" ]; then - print_list "Gatekeeper enabled? .......... "$NC - (spctl --status 2>/dev/null || echo_not_found "sestatus") | sed "s,disabled,${SED_RED}," - - print_list "sleepimage encrypted? ........ "$NC - (sysctl vm.swapusage | grep "encrypted" | sed "s,encrypted,${SED_GREEN},") || echo_no - - print_list "XProtect? .................... "$NC - (system_profiler SPInstallHistoryDataType 2>/dev/null | grep -A 4 "XProtectPlistConfigData" | tail -n 5 | grep -Iv "^$") || echo_no - - print_list "SIP enabled? ................. "$NC - csrutil status | sed "s,enabled,${SED_GREEN}," | sed "s,disabled,${SED_RED}," || echo_no - - print_list "Connected to JAMF? ........... "$NC - warn_exec jamf checkJSSConnection - - print_list "Connected to AD? ............. "$NC - dsconfigad -show && echo "" || echo_no -fi - -#-- SY) ASLR -print_list "Is ASLR enabled? ............... "$NC -ASLR=$(cat /proc/sys/kernel/randomize_va_space 2>/dev/null) -if [ -z "$ASLR" ]; then - echo_not_found "/proc/sys/kernel/randomize_va_space"; -else - if [ "$ASLR" -eq "0" ]; then printf $RED"No"$NC; else printf $GREEN"Yes"$NC; fi - echo "" -fi - -#-- SY) Printer -print_list "Printer? ....................... "$NC -(lpstat -a || system_profiler SPPrintersDataType || echo_no) 2>/dev/null - -#-- SY) Running in a virtual environment -print_list "Is this a virtual machine? ..... "$NC -hypervisorflag=$(grep flags /proc/cpuinfo 2>/dev/null | grep hypervisor) -if [ "$(command -v systemd-detect-virt 2>/dev/null)" ]; then - detectedvirt=$(systemd-detect-virt) - if [ "$hypervisorflag" ]; then printf $RED"Yes ($detectedvirt)"$NC; else printf $GREEN"No"$NC; fi -else - if [ "$hypervisorflag" ]; then printf $RED"Yes"$NC; else printf $GREEN"No"$NC; fi -fi