0

I am currently trying to translate a website's processes to python requests calls so we can avoid using a headless browser to automate entries into the European TracesNT system. Actually entering data can already be shortened to easy POST calls, but these use cookies acquired at login. The login has also been automated already till the point of having to enter the password. I have been able to reverse engineer most of the calls made to the server and just need to encrypt the password to put into the data being posted to the server.

This is done by the following JS:

whenJQueryReady(function() {
    if ("undefined" === typeof jQuery) throw Error("srp.js JavaScript requires jQuery");
    $(document).ready(function() {
        function u(b) {
            return "undefined" !== typeof b && b.value && 0 !== b.value.length && jcv_isEditable(b)
        }

        function w(b, a, c, d, e) {
            Jose.Utils.importRsaPublicKey(b, d.getKeyEncryptionAlgorithm()).then(function(f) {
                f = new Jose.JoseJWE.Encrypter(d, f);
                f.addHeader("kid", b.kid);
                f.addHeader("tx", a.elements.TxId.value.substring(0, 40));
                for (var h = [], g = {}, m = 0; m < c.length; g = {
                        $jscomp$loop$prop$field$2: g.$jscomp$loop$prop$field$2
                    },
                    m++)
                    if (g.$jscomp$loop$prop$field$2 = a.elements[c[m]], u(g.$jscomp$loop$prop$field$2)) {
                        var p = f.encrypt(g.$jscomp$loop$prop$field$2.value).then(function(k) {
                            return function(r) {
                                k.$jscomp$loop$prop$field$2.value = r;
                                "password" !== k.$jscomp$loop$prop$field$2.type && (k.$jscomp$loop$prop$field$2.type = "password");
                                return !0
                            }
                        }(g));
                        h.push(p)
                    } Promise.all(h).then(function(k) {
                    a.submit();
                    return !0
                }).catch(function(k) {
                    e();
                    logError(k)
                })
            }).catch(function(f) {
                logError("Unable to import server JWK key: " + f);
                e()
            })
        }

        function A(b,
            a, c, d) {
            function e(l) {
                for (var v = 0, n = void 0; v < g && (n = l + v) <= f; v++) {
                    var t = sha3_256.digest(n + p);
                    a: {
                        for (var q = 0; q < c.length; q++)
                            if ((t[q] & c[q]) !== c[q]) {
                                t = !1;
                                break a
                            } t = !0
                    }
                    if (t) {
                        h && (l = performance.now(), console.log("[POW] solution found: " + n + " in " + (l - x) + " milliseconds, hash=" + sha3_256.hex(n + p)));
                        k.attr("aria-valuenow", 100).css("width", "100%");
                        d(n);
                        return
                    }
                }
                n = l + g;
                m && console.log("[POW] attempt: " + n);
                l = 100 * k.width() / k.parent().width() + r;
                99 < l && (l = 50, r = 1);
                k.attr("aria-valuenow", l).css("width", l + "%");
                window.requestAnimationFrame(e.bind(this,
                    n))
            }
            var f = ECAS.ProofOfWork.Settings.getMaxSafeInt(),
                h = ECAS.ProofOfWork.Settings.isLoggingEnabled(),
                g = ECAS.ProofOfWork.Settings.getBatchSize(),
                m = h && 0 < g && g < f,
                p = b + a,
                k = $("#progressBarId"),
                r = 2,
                x = null;
            h && (console.log("[POW] Starting proof of work computation for algorithm=SHA3-256, challenge=" + b + NaN + a + ", mask=" + c), x = performance.now());
            window.requestAnimationFrame(e.bind(this, 0))
        }

        function B(b) {
            b = b.substring(1, b.length - 1);
            b = b.split(/\s*,\s*/);
            for (var a = [], c = 0, d = b.length; c < d; c++) a.push(parseInt(b[c], 16));
            return a
        }

        function C(b, a, c) {
            var d = $("#captchaPleaseWait");
            d.on("shown.bs.modal", function(e) {
                e = b.elements.TxId.value;
                var f = B(b.elements.proofOfWork.dataset.complexityMask);
                A(e, a, f, function(h) {
                    var g = $("#proofOfWork");
                    g.prop("disabled", !1);
                    g.val(h);
                    d.find(".progressBarStart").toggle();
                    d.find(".progressBarEnd").toggle();
                    c();
                    return !0
                })
            }).modal({
                backdrop: "static",
                keyboard: !1,
                show: !0
            })
        }

        function y(b, a) {
            $.get(ECAS.getContextPath() + "/srp/keys", function(c) {
                w(c, b, a, new Jose.WebCryptographer, function() {
                    var d = new Jose.WebCryptographer;
                    d.setKeyEncryptionAlgorithm("RSA-OAEP");
                    d.setContentEncryptionAlgorithm("A256CBC-HS512");
                    w(c, b, a, d, function() {
                        b.submit()
                    })
                })
            }, "json").fail(function(c, d, e) {
                logError("Unable to fetch JWK key from server: " + e);
                b.submit()
            })
        }
        var z = $("#loginForm, #expiredLoginForm, #changePasswordForm, #initialisePasswordLoginForm, #passwordSignatureForm, #smsSignatureStep1Form, #processSignatureForm, #softwareTokenSignatureForm, #addMobileDeviceForm, #changeMobileDevicePinCodeForm, #resetMobileDevicePinCodeForm, #eimExternalRegisterForm, #initialisePasswordCaptchaForm, #eimAddMobilePhoneNumberForm"),
            D = {
                loginForm: {
                    enc: ["password", "newPassword", "confirmNewPassword"],
                    pow: {
                        enabled: !0,
                        fields: []
                    }
                },
                expiredLoginForm: {
                    enc: ["password", "newPassword", "confirmNewPassword"],
                    pow: {
                        enabled: !0,
                        fields: []
                    }
                },
                changePasswordForm: {
                    enc: ["password", "newPassword", "confirmNewPassword"]
                },
                initialisePasswordLoginForm: {
                    enc: ["strongPassword", "confirmNewStrongPassword"]
                },
                passwordSignatureForm: {
                    enc: ["password"]
                },
                smsSignatureStep1Form: {
                    enc: ["password"]
                },
                processSignatureForm: {
                    enc: ["password"]
                },
                softwareTokenSignatureForm: {
                    enc: ["password"]
                },
                addMobileDeviceForm: {
                    enc: ["pinCode", "pinCodeConfirmation"]
                },
                changeMobileDevicePinCodeForm: {
                    enc: ["currentPinCode", "newPinCode", "newPinCodeConfirmation"]
                },
                resetMobileDevicePinCodeForm: {
                    enc: ["newPinCode", "newPinCodeConfirmation"]
                },
                eimExternalRegisterForm: {
                    enc: ["captcha"],
                    pow: {
                        enabled: !0,
                        fields: ["captcha"]
                    }
                },
                initialisePasswordCaptchaForm: {
                    enc: ["captcha"],
                    pow: {
                        enabled: !0,
                        fields: ["captcha"]
                    }
                },
                eimAddMobilePhoneNumberForm: {
                    enc: ["captcha"],
                    pow: {
                        enabled: !0,
                        fields: ["captcha"]
                    }
                }
            };
        z.length && Jose && Jose.caniuse &&
            Jose.caniuse() && z.each(function() {
                $(this).submit(function(b) {
                    var a = this,
                        c = D[a.id],
                        d = c.enc,
                        e = c.pow;
                    c = null;
                    if (e && e.enabled && a.data && 1 === a.data.clicks && !isCancelled(a) && ECAS && ECAS.ProofOfWork && ECAS.ProofOfWork.Settings && ECAS.ProofOfWork.Settings.isEnabled()) {
                        var f = a.elements.proofOfWork;
                        if ("undefined" !== typeof f) {
                            for (var h = "", g = 0; g < e.fields.length; g++) {
                                var m = a.elements[e.fields[g]];
                                u(m) && (h += m.value)
                            }
                            if (0 !== h.length || 0 === e.fields.length || "false" === f.dataset[e.fields[0] + "Enabled"]) c = function(p) {
                                return C(a,
                                    h, p)
                            }
                        }
                    }
                    e = !1;
                    for (f = 0; f < d.length; f++)
                        if (u(a.elements[d[f]])) {
                            e = !0;
                            break
                        } if (a.data && 1 === a.data.clicks && !isCancelled(a)) {
                        if (e && !a.encrypted) return a.encrypted = !0, b.preventDefault(), null !== c ? c(function() {
                            y(a, d);
                            return !0
                        }) : y(a, d), !1;
                        if (null !== c && !a.powComputed) return a.powComputed = !0, b.preventDefault(), c(function() {
                            a.submit();
                            return !0
                        }), !1
                    }
                })
            })
    })
});

Additional info:

Keys supplied by the server and entered into

data = {
    "kty": "RSA",
    "e": "<>",
    "kid": "<>",
    "n": "<>"
}

I've been able to boil most of this down to the following python script but this does not fully work yet:

from jose import constants, jwe

def encrypt(message: str, data: dict):
    key_algorithm = constants.ALGORITHMS.RSA_OAEP
    content_algorithm = constants.ALGORITHMS.A256CBC_HS512

    encrypted = jwe.encrypt(
        plaintext=bytes(message, "utf-8"),
        key=data,
        encryption=content_algorithm,
        algorithm=key_algorithm,
        kid=data['kid'])

    return encrypted

Data is in this case the keys and message is the password

Sadly this does not work yet and I get a simple Incorrect password error on the page and don't recieve all my cookies. What could I have done wrong and how do I fix this?

p.s. I'm new to posting on stackoverflow so if any aditional info is needed please mention it :D

Solved

The python-jose library jwe.encrypt does not take any extra headers into account, therefor the tx header (see js script) was not added and my jwk was lacking that

Drahc
  • 1
  • 1
  • The issue was that in the python jose library any other headers aren't added, this left my JWK lacking one header that I tried to input. – Drahc Aug 26 '23 at 11:54

0 Answers0