Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Password is logged in clear text #70

Open
timodenissen opened this issue Mar 2, 2022 · 2 comments
Open

Password is logged in clear text #70

timodenissen opened this issue Mar 2, 2022 · 2 comments
Labels

Comments

@timodenissen
Copy link

timodenissen commented Mar 2, 2022

When setting a logger to debug, the user's password is logged in plaintext after the initial connection is set up.

PoC:

import odoorpc
import logging

logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
hostname = input("hostname: ")
method = "jsonrpc"
port = 8169
database = input("database: ")
username = input("username: ")
password = input("password: ")

logging.debug("starting connection")
con = odoorpc.ODOO(hostname, method, port)
con.login(database, username, password)
con.execute(
        "res.partner", "search_read", [('id', '=', 1)], ['id']
        )

method can be both jsonrpc or jsonrpc+ssl and port can be any valid Odoo or reverse proxy port.

The above results in:

hostname: 10.200.23.3
database: database_name
username: username
password: super_secret_password
DEBUG:root:starting connection
DEBUG:odoorpc.rpc.jsonrpclib:(JSON,send) https://10.200.23.3:8169/web/webclient/version_info {'jsonrpc': '2.0', 'method': 'call', 'params': {}, 'id': 879508241}
DEBUG:odoorpc.rpc.jsonrpclib:(JSON,recv) https://10.200.23.3:8169/web/webclient/version_info {'jsonrpc': '2.0', 'method': 'call', 'params': {}, 'id': 879508241} => {'jsonrpc': '2.0', 'id': 879508241, 'result': {'server_version': '14.0+e-20211126', 'server_version_info': [14, 0, 0, 'final', 0, 'e'], 'server_serie': '14.0', 'protocol_version': 1}}
DEBUG:odoorpc.rpc.jsonrpclib:(JSON,send) https://10.200.23.3:8169/web/session/authenticate {'jsonrpc': '2.0', 'method': 'call', 'params': {'db': 'database_name', 'login': 'username', 'password': '**********'}, 'id': 100563349}
DEBUG:odoorpc.rpc.jsonrpclib:(JSON,recv) https://10.200.23.3:8169/web/session/authenticate {'jsonrpc': '2.0', 'method': 'call', 'params': {'db': 'database_name', 'login': 'username', 'password': '**********'}, 'id': 100563349} => {'jsonrpc': '2.0', 'id': 100563349, 'result': {'uid': 341, 'is_system': False, 'is_admin': False, 'user_context': {'lang': 'en_US', 'tz': 'Europe/Berlin', 'uid': 341}, 'db': 'database_name', 'server_version': '14.0+e-20211126', 'server_version_info': [14, 0, 0, 'final', 0, 'e'], 'name': 'John Doe', 'username': 'username', 'partner_display_name': 'Example Company, John Doe', 'company_id': 1, 'partner_id': 196008, 'web.base.url': 'http://localhost:8069', 'active_ids_limit': 20000, 'max_file_upload_size': 134217728, 'user_companies': {'current_company': [1, 'Example Company'], 'allowed_companies': [[1, 'Example Company']]}, 'currencies': {'5': {'symbol': 'CHF', 'position': 'after', 'digits': [69, 2]}, '1': {'symbol': '€', 'position': 'after', 'digits': [69, 2]}, '2': {'symbol': '$', 'position': 'before', 'digits': [69, 2]}}, 'show_effect': 'True', 'display_switch_company_menu': False, 'cache_hashes': {'load_menus': '8a32d6233210c1a64f7f2fe20fa31b88699e4bad13138f7c82c385d4d8119908', 'qweb': '5f01507b1f0131aa08ca989d88a79694d9b6ad1c2f83b0d3490e4d337e6a2418', 'translations': '4d10653cd680e5a0727ac1a9880e46d09d67e907'}, 'user_id': [341], 'max_time_between_keys_in_ms': 55, 'company_currency_id': 1, 'companies_currency_id': {'1': 1}, 'warning': 'user', 'expiration_date': '2022-08-01 00:00:00', 'expiration_reason': 'renewal', 'notification_type': 'email', 'map_box_token': False, 'odoobot_initialized': True, 'ocn_token_key': False, 'fcm_project_id': False, 'inbox_action': 114, 'timesheet_uom': {'id': 6, 'name': 'Hours', 'rounding': 0.01, 'timesheet_widget': 'float_time'}, 'timesheet_uom_factor': 1.0}}
DEBUG:odoorpc.rpc.jsonrpclib:(JSON,send) https://10.200.23.3:8169/jsonrpc {'jsonrpc': '2.0', 'method': 'call', 'params': {'service': 'object', 'method': 'execute', 'args': ['database_name', 341, 'super_secret_password', 'res.partner', 'search_read', [('id', '=', 1)], ['id']]}, 'id': 625924402}
DEBUG:odoorpc.rpc.jsonrpclib:(JSON,recv) https://10.200.23.3:8169/jsonrpc {'jsonrpc': '2.0', 'method': 'call', 'params': {'service': 'object', 'method': 'execute', 'args': ['database_name', 341, 'super_secret_password', 'res.partner', 'search_read', [('id', '=', 1)], ['id']]}, 'id': 625924402} => {'jsonrpc': '2.0', 'id': 625924402, 'result': [{'id': 1}]}

First witnessed in version 0.6.0, reproducable in 0.8.0.

Depending if the module is used on a server this could lead to possibly leaked passwords.

@x2nie
Copy link

x2nie commented Sep 9, 2024

FYI, when using /jsonrpc, that password is a must. and odoorpc is using that channel. And, that is still valid in odoo 17.

# /odoo/addons/base/controllers/rpc.py

    @route('/jsonrpc', type='json', auth="none", save_session=False)
    def jsonrpc(self, service, method, args):
        """ Method used by client APIs to contact OpenERP. """
        return dispatch_rpc(service, method, args)

and finally:

# /odoo/service/model.py

def dispatch(method, params):
    db, uid, passwd = params[0], int(params[1]), params[2]
    security.check(db, uid, passwd)

    threading.current_thread().dbname = db
    threading.current_thread().uid = uid
    registry = odoo.registry(db).check_signaling()
    with registry.manage_changes():
        if method == 'execute':
            res = execute(db, uid, *params[3:])
        elif method == 'execute_kw':
            res = execute_kw(db, uid, *params[3:])
        else:
            raise NameError("Method not available %s" % method)
    return res

@x2nie
Copy link

x2nie commented Sep 9, 2024

I think we can switch to a more secure channel, once logged-in (user established).
like so the /web/dataset/call_kw

# /addons/web/controllers/dataset.py

    @http.route(['/web/dataset/call_kw', '/web/dataset/call_kw/<path:path>'], type='json', auth="user")
    def call_kw(self, model, method, args, kwargs, path=None):
        return self._call_kw(model, method, args, kwargs)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants