Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
beefproject
GitHub Repository: beefproject/beef
Path: blob/master/extensions/admin_ui/media/javascript/ui/panel/tabs/ZombieTabRider.js
1155 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
* The request Tab panel for the selected zombie.
9
* Loaded in /ui/panel/index.html
10
*/
11
ZombieTab_Requester = function(zombie) {
12
13
// The status bar.
14
var commands_statusbar = new Beef_StatusBar('requester-bbar-zombie-'+zombie.session);
15
16
17
/*
18
* The panel used to forge raw HTTP requests.
19
********************************************/
20
var requests_panel = new Ext.Panel({
21
id: 'requester-forge-requests-zombie-'+zombie.session,
22
title: 'Forge Request',
23
layout: 'fit'
24
});
25
26
/*
27
* The panel used to select hooked browsers as proxy endpoints.
28
* TODO: Add list of hooked browsers here
29
********************************************/
30
var proxy_panel = new Ext.Panel({
31
id: 'requester-proxy-zombie-'+zombie.session,
32
title: 'Help',
33
layout: 'fit',
34
padding: '10 10 10 10',
35
html: "<div style='font:11px tahoma,arial,helvetica,sans-serif;width:500px' ><p style='font:11px tahoma,arial,helvetica,sans-serif'>The Tunneling Proxy allows you to use a hooked browser as a proxy. Simply right-click a browser from the Hooked Browsers tree to the left and select \"Use as Proxy\".</p><p style='margin: 10 0 10 0'><img src='<%= @base_path %>/media/images/help/proxy.png'></p><p>The proxy runs on localhost port 6789 by default. Each request sent through the Proxy is recorded in the History panel in the Proxy tab. Click a history item to view the HTTP response headers and response body.</p><p style='margin: 10 0 10 0'><img src='<%= @base_path %>/media/images/help/history.png'></p><p style='font:11px tahoma,arial,helvetica,sans-serif'>To manually forge an arbitrary HTTP request use the \"Forge Request\" tab from the Proxy tab.</p><p style='margin: 10 0 10 0'><img src='<%= @base_path %>/media/images/help/forge.png'></p><p style='font:11px tahoma,arial,helvetica,sans-serif'>For more information see: <a href=\"https://github.com/beefproject/beef/wiki/Tunneling\">https://github.com/beefproject/beef/wiki/Tunneling</a></p></div>",
36
listeners: {
37
activate: function(proxy_panel) {
38
// to do: refresh list of hooked browsers
39
}
40
}
41
42
});
43
44
/*
45
* TODO: The panel used to configure the proxy on-the-fly
46
********************************************/
47
/*
48
var options_panel = new Ext.Panel({
49
id: 'requester-options-zombie-'+zombie.session,
50
title: 'Proxy',
51
layout: 'fit'
52
});
53
*/
54
/*
55
* The panel that displays the history of all requests performed.
56
********************************************/
57
var history_panel_store = new Ext.ux.data.PagingJsonStore({
58
storeId: 'requester-history-store-zombie-'+zombie.session,
59
proxy: new Ext.data.HttpProxy({
60
method: 'GET',
61
url: '/api/requester/requests/' + zombie.session + '?token=' + beefwui.get_rest_token(),
62
}),
63
remoteSort: false,
64
autoDestroy: true,
65
autoLoad: false,
66
root: 'requests',
67
68
fields: ['proto', 'domain', 'port', 'method', 'request_date', 'response_date','id', 'has_ran', 'path','response_status_code', 'response_status_text', 'response_port_status'],
69
sortInfo: {field: 'request_date', direction: 'DESC'},
70
});
71
72
var req_pagesize = 30;
73
74
var history_panel_bbar = new Ext.PagingToolbar({
75
pageSize: req_pagesize,
76
store: history_panel_store,
77
displayInfo: true,
78
displayMsg: 'Displaying history {0} - {1} of {2}',
79
emptyMsg: 'No history to display'
80
});
81
82
var history_panel_grid = new Ext.grid.GridPanel({
83
id: 'requester-history-grid-zombie-'+zombie.session,
84
store: history_panel_store,
85
bbar: history_panel_bbar,
86
border: false,
87
loadMask: {msg:'Loading History...'},
88
89
viewConfig: {
90
forceFit:true
91
},
92
93
view: new Ext.grid.GridView({
94
forceFit: true,
95
emptyText: "No History",
96
enableRowBody:true
97
}),
98
99
columns: [
100
{header: 'Id', width: 10, sortable: true, dataIndex: 'id', hidden:true},
101
{header: 'Proto', width: 30, sortable: true, dataIndex: 'proto', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}},
102
{header: 'Domain', sortable: true, dataIndex: 'domain', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}},
103
{header: 'Port', width: 30, sortable: true, dataIndex: 'port', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}},
104
{header: 'Method', width: 30, sortable: true, dataIndex: 'method', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}},
105
{header: 'Path', sortable: true, dataIndex: 'path', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}},
106
{header: 'Res Code', width: 35, sortable: true, dataIndex: 'response_status_code', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}},
107
{header: 'Res Text', width: 50, sortable: true, dataIndex: 'response_status_text', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}},
108
{header: 'Port Status', width: 40, sortable: true, dataIndex: 'response_port_status', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}},
109
{header: 'Processed', width: 50, sortable: true, dataIndex: 'has_ran', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}},
110
{header: 'Req Date', width: 50, sortable: true, dataIndex: 'request_date', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}},
111
{header: 'Res Date', width: 50, sortable: true, dataIndex: 'response_date', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}}
112
113
],
114
115
listeners: {
116
rowclick: function(grid, rowIndex) {
117
var tab_panel = Ext.getCmp('zombie-requester-tab-zombie-'+zombie.session);
118
var r = grid.getStore().getAt(rowIndex).data;
119
120
if(r.has_ran != "complete") {
121
commands_statusbar.update_fail("Response for this request has not been received yet.");
122
return;
123
}
124
125
if(!tab_panel.get('requester-response-'+r.id)) {
126
genResultTab(r, zombie, commands_statusbar);
127
}
128
},
129
afterrender: function(datagrid) {
130
datagrid.store.reload({params:{start:0,limit:req_pagesize, sort: "date", dir:"DESC"}});
131
},
132
133
// History grid context menu (right click on a row in the history grid)
134
rowcontextmenu: function(grid, rowIndex, e){
135
e.preventDefault();
136
grid.getSelectionModel().selectRow(rowIndex);
137
if (!!grid.rowCtxMenu) {
138
grid.rowCtxMenu.destroy();
139
}
140
var record = grid.selModel.getSelected();
141
grid.rowCtxMenu = new Ext.menu.Menu({
142
items: [{
143
text: 'View Response',
144
iconCls: 'network-host-ctxMenu-web',
145
handler: function() {
146
if(record.get('has_ran') != "complete") {
147
commands_statusbar.update_fail("Response for this request has not been received yet.");
148
return;
149
}
150
if(!history_panel.get('requester-response-'+record.get('id'))) {
151
genResultTab(grid.getStore().getAt(rowIndex).data, zombie, commands_statusbar);
152
}
153
}
154
},{
155
text: 'Delete Response',
156
iconCls: 'zombie-tree-ctxMenu-delete',
157
handler: function() {
158
var response_id = record.get('id');
159
160
if(record.get('has_ran') != "complete") {
161
commands_statusbar.update_fail("Response for this request has not been received yet.");
162
return;
163
} else {
164
if (!confirm('Are you sure you want to remove response [id: '+response_id+'] ?')) {
165
commands_statusbar.update_fail('Cancelled');
166
return;
167
}
168
commands_statusbar.update_sending('Removing network host [id: '+ response_id +'] ...');
169
deleteResponse(grid.getStore().getAt(rowIndex).data, zombie, commands_statusbar);
170
}
171
}
172
}]
173
});
174
grid.rowCtxMenu.showAt(e.getXY());
175
}
176
}
177
});
178
179
var history_panel = new Ext.Panel({
180
id: 'requester-history-panel-zombie-'+zombie.session,
181
title: 'History',
182
items:[history_panel_grid],
183
layout: 'fit',
184
listeners: {
185
activate: function(history_panel) {
186
history_panel.items.items[0].store.reload({params: {nonce: Ext.get("nonce").dom.value}});
187
}
188
}
189
});
190
191
// Return the extension_requester_http table row ID given a grid row index
192
function getHttpDbId(grid, rowIndex){
193
var row = grid.getStore().getAt(rowIndex).data;
194
var result = null;
195
if(row != null){
196
result = row.id;
197
}
198
return result;
199
}
200
201
// Function generating the requests panel to send raw requests
202
//-------------------------------------------------------------
203
function genRawRequestPanel(zombie, bar, value) {
204
var form = new Ext.FormPanel({
205
title: 'Forge Raw HTTP Request',
206
id: 'requester-request-form-zombie'+zombie.session,
207
url: '/api/requester/send/' + zombie.session + '?token=' + beefwui.get_rest_token(),
208
hideLabels : true,
209
border: false,
210
padding: '3px 5px 0 5px',
211
212
items:[{
213
xtype: 'checkboxgroup',
214
//border: true,
215
//fieldLabel : 'Request Options',
216
items: [{
217
boxLabel: 'SSL',
218
name: 'ssl',
219
inputValue: '1',
220
checked: false, // (window.location.protocol == 'https'),
221
id: 'requester-forge-requests-ssl'
222
}]
223
},{
224
xtype: 'textarea',
225
id: 'raw-request-zombie-'+zombie.session,
226
name: 'raw_request',
227
width: '100%',
228
height: '100%',
229
allowBlank: false
230
}],
231
232
buttons: [{
233
text: 'Send',
234
handler: function() {
235
var use_ssl = Ext.getCmp('requester-forge-requests-ssl').getValue();
236
if (use_ssl) var proto = 'https'; else var proto = 'http';
237
var form = Ext.getCmp('requester-request-form-zombie'+zombie.session).getForm();
238
239
bar.update_sending('Sending request to ' + zombie.ip + '...');
240
241
form.submit({
242
params: {
243
raw_request: Ext.getCmp('raw-request-zombie-'+zombie.session).getValue(),
244
proto: proto
245
},
246
success: function() {
247
bar.update_sent("Request sent to hooked browser " + zombie.ip);
248
},
249
failure: function() {
250
bar.update_fail("Error! Invalid http request.");
251
}
252
});
253
}
254
}]
255
});
256
257
if(!value) {
258
if (zombie.domain) {
259
value = "GET /demos/secret_page.html HTTP/1.1\n";
260
value += "Host: "+zombie.domain+":"+zombie.port+"\n";
261
} else value = "GET / HTTP/1.1\nHost: \n";
262
}
263
264
form.get('raw-request-zombie-'+zombie.session).value = value;
265
266
panel = Ext.getCmp('requester-forge-requests-zombie-'+zombie.session);
267
panel.setTitle('Forge Request');
268
panel.add(form);
269
};
270
271
// Function to delete a response from the requester history
272
//------------------------------------------------------------------
273
function deleteResponse(request, zombie, bar) {
274
275
Ext.Ajax.request({
276
url: '/api/requester/response/' + request.id + '?token=' + beefwui.get_rest_token(),
277
method: 'DELETE',
278
loadMask: true,
279
280
success: function(response) {
281
var xhr = Ext.decode(response.responseText);
282
if (xhr['success'] == 'true') {
283
bar.update_sent("Deleted response.");
284
} else {
285
bar.update_fail("Error! Could not delete the response.");
286
}
287
},
288
289
failure: function() {
290
bar.update_fail("Error! Could not delete the response.");
291
}
292
});
293
}
294
295
// Function generating the panel that shows the results of a request
296
// This function is called when the user clicks on a row in the grid
297
// showing the results in the history.
298
//------------------------------------------------------------------
299
function genResultTab(request, zombie, bar) {
300
var tab_panel = Ext.getCmp('zombie-requester-tab-zombie-'+zombie.session);
301
302
bar.update_sending('Getting response...');
303
304
Ext.Ajax.request({
305
url: '/api/requester/response/' + request.id + '?token=' + beefwui.get_rest_token(),
306
loadMask: true,
307
success: function(response) {
308
var xhr = Ext.decode(response.responseText);
309
310
if (xhr['success'] !== 'true') {
311
bar.update_fail("Error! Could not load the response.");
312
return;
313
}
314
315
var tab_result_response_headers = new Ext.Panel({
316
title: 'Response Headers',
317
border: false,
318
collapsed: true,
319
layout: 'fit',
320
padding: '5px 5px 5px 5px',
321
items:[new Ext.form.TextArea({id: 'requester-response-res-headers-'+request.id, value: xhr.result.response_headers + "\n"})]
322
});
323
324
var tab_result_response_body = new Ext.Panel({
325
title: 'Response Body',
326
border: false,
327
collapsed: false,
328
layout: 'fit',
329
padding: '5px 5px 5px 5px',
330
items:[new Ext.form.TextArea({id: 'requester-response-res-body-'+request.id, value: xhr.result.response + "\n"})]
331
});
332
333
var tab_result_request = new Ext.Panel({
334
title: 'Request',
335
border: false,
336
collapsed: true,
337
layout: 'fit',
338
padding: '5px 5px 5px 5px',
339
items:[new Ext.form.TextArea({id: 'requester-response-req-'+request.id, value: xhr.result.request})]
340
});
341
342
var tab_result_accordion = new Ext.Panel({
343
id: 'requester-response-'+request.id,
344
title: $jEncoder.encoder.encodeForHTML(request.path),
345
split: true,
346
border: false,
347
layout:'accordion',
348
closable: true,
349
items:[tab_result_request, tab_result_response_headers, tab_result_response_body]
350
});
351
352
tab_panel.add(tab_result_accordion);
353
tab_panel.activate(tab_result_accordion.id);
354
355
bar.update_sent("Displaying response.");
356
},
357
358
failure: function() {
359
bar.update_fail("Error! Could not retrieve the response.");
360
}
361
});
362
};
363
364
365
ZombieTab_Requester.superclass.constructor.call(this, {
366
id: 'zombie-requester-tab-zombie-'+zombie.session,
367
title: 'Proxy',
368
activeTab: 0,
369
viewConfig: {
370
forceFit: true,
371
type: 'fit'
372
},
373
374
items: [history_panel, requests_panel, proxy_panel],
375
376
bbar: commands_statusbar,
377
378
listeners: {
379
afterrender : function(){
380
genRawRequestPanel(zombie, commands_statusbar);
381
}
382
}
383
});
384
385
};
386
387
Ext.extend(ZombieTab_Requester, Ext.TabPanel, {});
388
389