JSR223 Pre Processor generated value looks like garbage data after encryption

52 Views Asked by At

Our website is generating a dynamic loginkey which uses AES. Now, since I'm not using the encrypt.js code that they used on the website.

I tried to replicate this part of the code from the website using groovy:

var type="DATABASE";
    a2 = encrypt.AESEncrypt(a2, "<%=(String)session.getAttribute("__GETLOGINKEY")%>", 256);
    document.forms[0].a3.value = a2;
    document.forms[0].a2.value = a2n;
    document.forms[0].txtResFrac.value= screen.width;
    if (getControlPrefix.prefix){
        return getControlPrefix.prefix;
    }

I copied the code from https://groovy.apache.org/blog/encryption-and-decryption-with-groovy and replace the var text with

var a2 = vars.get('password'); << taken from the user-defined variables
var a3 = ""; << this is the parameter from the website login page

I'm passing the encrypted value using this code because I need to pass it back to the website as a loginkey

vars.put("a3","${new String(encrypted)}");

The website reads the value as

userid=PERFUNIADM05
password=Password_1 << This is user-defined variable
a2=********** << This is the masked password from user-defined variable  
a3=h(Dl�cg[25�z3h << This is the encrypted value using the code from this https://groovy.apache.org/blog/encryption-and-decryption-with-groovy.
This is being pass to the application server for authentication.
But since it cannot read it, the application is throwing an error.
encryption=EBWZJQ7XNGJN53MN7I50N2XQJ71T9LK3 << This key came from the Welcome.do page generated from encrypt.js embedded in the page.

This is the error from the server.log

29.02.2024 23:21:21,133 DEBUG [org.apache.coyote.http11] JBWEB003028: Start processing with input [txtUserid=PERFUNIADM06&a2=**********
&**a3=%07%EF%BF%BDC%05%2F%EF%BF%BD%EF%BF%BD%60%EF%BF%BD%EF%BF%BD%C6%B6%EF%BF%BD3%09%EF%BF%BD**&txtpasswd=I+am+an+idiot.&cmbOrgCodes=001&submit=Sign+in&txtResFrac=1920]
29.02.2024 23:21:21,133 INFO  [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/collections]] (http-/0.0.0.0:50443-17) I am in Timer Filter 
29.02.2024 23:21:21,133 DEBUG [org.apache.struts.util.RequestUtils] Get module name for path /loginAction.do
29.02.2024 23:21:21,133 DEBUG [org.apache.struts.util.RequestUtils] Module name found: default
29.02.2024 23:21:21,133 DEBUG [org.apache.struts.action.RequestProcessor] Processing a 'POST' for path '/loginAction'
29.02.2024 23:21:21,133 DEBUG [org.apache.struts.util.RequestUtils] Looking for ActionForm bean instance in scope 'session' under attribute key 'personalizeActionform'
29.02.2024 23:21:21,133 DEBUG [org.apache.struts.util.RequestUtils] Recycling existing DynaActionForm instance of type 'personalizeActionform'
29.02.2024 23:21:21,133 DEBUG [org.apache.struts.action.RequestProcessor] Storing ActionForm bean instance in scope 'session' under attribute key 'personalizeActionform'
29.02.2024 23:21:21,133 DEBUG [org.apache.struts.action.RequestProcessor] Populating bean properties from this request
29.02.2024 23:21:21,133 DEBUG [org.apache.commons.beanutils.BeanUtils] BeanUtils.populate(DynaActionForm[dynaClass=personalizeActionform,a1=,a2=,a3=,txtpasswd=,txtUserid=,cmblayout=,cmbOrgCodes=,txtMenuCode=,txtResFrac=,cmblocale=,txtMultipleOrg=,cmbtemplates=], {a2=[Ljava.lang.String;@7a6fe440, a3=[Ljava.lang.String;@5cfc5339, txtpasswd=[Ljava.lang.String;@2212b535, txtUserid=[Ljava.lang.String;@2b9b67ba, submit=[Ljava.lang.String;@2ed3cb6d, cmbOrgCodes=[Ljava.lang.String;@10083015, txtResFrac=[Ljava.lang.String;@2784843c})
29.02.2024 23:21:21,133 DEBUG [org.apache.commons.beanutils.ConvertUtils] Convert string '**********' to class 'java.lang.String'
29.02.2024 23:21:21,133 DEBUG [org.apache.commons.beanutils.ConvertUtils] **Convert string '�C/��`��ƶ�3 �' to class 'java.lang.String'**
29.02.2024 23:21:21,133 DEBUG [org.apache.commons.beanutils.ConvertUtils] Convert string 'I am an idiot.' to class 'java.lang.String'
29.02.2024 23:21:21,133 DEBUG [org.apache.commons.beanutils.ConvertUtils] Convert string 'PERFUNIADM06' to class 'java.lang.String'
29.02.2024 23:21:21,133 DEBUG [org.apache.commons.beanutils.ConvertUtils] Convert string '001' to class 'java.lang.String'
29.02.2024 23:21:21,133 DEBUG [org.apache.commons.beanutils.ConvertUtils] Convert string '1920' to class 'java.lang.String'
29.02.2024 23:21:21,133 DEBUG [org.apache.struts.action.RequestProcessor] Looking for Action instance for class indus.collproj.action.security.LoginAction
29.02.2024 23:21:21,133 ERROR [stderr] java.lang.StringIndexOutOfBoundsException: String index out of range: 15
29.02.2024 23:21:21,134 ERROR [stderr]  at java.lang.String.charAt(String.java:658)
29.02.2024 23:21:21,134 ERROR [stderr]  at indus.common.security.aas.AES_Algorithm.decodeBase64(AES_Algorithm.java:352)
29.02.2024 23:21:21,134 ERROR [stderr]  at indus.common.security.aas.AES_Algorithm.AESDecrypt(AES_Algorithm.java:250)
29.02.2024 23:21:21,134 ERROR [stderr]  at indus.collproj.action.security.LoginAction.login(LoginAction.java:95)

What should I do to get a key readable by the website in order to properly authenticate it?

encrypt.js

var encrypt = {
Sbox: [99,..],
Rcon: [[0, 0, 0, 0],..,
b64: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
Cipher: function(e, a) 
{var declaration
  for (var f = 0; f < 4 * d; f++)}
g = this.AddRoundKey(g, a, 0, d);
for (var c = 1; c < h; c++){
<< each one is created with their own function >>
g = this.SubBytes(g, d);
g = this.ShiftRows(g, d); 
g = this.MixColumns(g, d); 
g = this.AddRoundKey(g, a, c, d); }
KeyExpansion: function(f) { some for loop, if loop, SubWord and RotWord are used here... }
SubWord: function(a) { some for loop and Sbox is used here..}
RotWord: function(a) { some for loop..}
AESEncrypt: function(j, a, t) {
    var k = 16;
    if (!(t == 128 || t == 192 || t == 256)) {
        return "";
    }
    j = this.encodeUTF8(j);
    a = this.encodeUTF8(a);
    << some code>>
    var y = this.Cipher(f, this.KeyExpansion(f));
    <<some code>>
    x = this.encodeBase64(x);
encodeBase64: function(n) { for loop.. }
decodeBase64: function(e) {
    e = (typeof e == "undefined") ? false : e;
    var f, b, a, m, j, h, g, o, i = [], n, l;
    l = e ? this.decodeUTF8() : this; <<some for loop>>}
encodeUTF8: function(a) {
    var b = a.replace(/[\u0080-\u07ff]/g, function(e) { << some code.. >>}
decodeUTF8: function() {
    var a = this.replace(/[\u00c0-\u00df][\u0080-\u00bf]/g, function(d) { <<some code..>>}

The encrypt.js is called in this function:

function getControlPrefix() {
    var a2 = document.forms[0].a2.value;
    var a2n = "";
    for(var i=0; i < a2.length; i++){
        a2n += "*";
    }

    var type="DATABASE";
    a2 = encrypt.AESEncrypt(a2, "<%=(String)session.getAttribute("__GETLOGINKEY")%>", 256);
    document.forms[0].a3.value = a2;
    document.forms[0].a2.value = a2n;
    document.forms[0].txtResFrac.value= screen.width;
    if (getControlPrefix.prefix){
        return getControlPrefix.prefix;
    }

Hope this snippet of code helps in giving more light into the errors I'm getting.

1

There are 1 best solutions below

2
Ivan G On

I think you need to replace this guy:

vars.put("a3","${new String(encrypted)}");

with this one:

vars.put("a3", new String(encrypted));

See Strings chapter of Groovy documentation for more details

also going forward consider providing a minimal reproducible example because we don't know what does your encrypt.AESEncrypt do and what does it return. If you have a "website function" source code maybe it worth sharing it as well, this way you will get the most comprehensive help

Also AES is kind of broad term, the implementations could be at least the following:

  • AES/CBC/NoPadding (128)
  • AES/CBC/PKCS5Padding (128)
  • AES/ECB/NoPadding (128)
  • AES/ECB/PKCS5Padding (128)

See Apache Groovy: What Is Groovy Used For? article for more information on Groovy scripting in JMeter.