Path: blob/master/extensions/admin_ui/media/javascript/ui/panel/tabs/ZombieTabRider.js
1155 views
//1// Copyright (c) 2006-2025 Wade Alcorn - [email protected]2// Browser Exploitation Framework (BeEF) - https://beefproject.com3// See the file 'doc/COPYING' for copying permission4//56/*7* The request Tab panel for the selected zombie.8* Loaded in /ui/panel/index.html9*/10ZombieTab_Requester = function(zombie) {1112// The status bar.13var commands_statusbar = new Beef_StatusBar('requester-bbar-zombie-'+zombie.session);141516/*17* The panel used to forge raw HTTP requests.18********************************************/19var requests_panel = new Ext.Panel({20id: 'requester-forge-requests-zombie-'+zombie.session,21title: 'Forge Request',22layout: 'fit'23});2425/*26* The panel used to select hooked browsers as proxy endpoints.27* TODO: Add list of hooked browsers here28********************************************/29var proxy_panel = new Ext.Panel({30id: 'requester-proxy-zombie-'+zombie.session,31title: 'Help',32layout: 'fit',33padding: '10 10 10 10',34html: "<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>",35listeners: {36activate: function(proxy_panel) {37// to do: refresh list of hooked browsers38}39}4041});4243/*44* TODO: The panel used to configure the proxy on-the-fly45********************************************/46/*47var options_panel = new Ext.Panel({48id: 'requester-options-zombie-'+zombie.session,49title: 'Proxy',50layout: 'fit'51});52*/53/*54* The panel that displays the history of all requests performed.55********************************************/56var history_panel_store = new Ext.ux.data.PagingJsonStore({57storeId: 'requester-history-store-zombie-'+zombie.session,58proxy: new Ext.data.HttpProxy({59method: 'GET',60url: '/api/requester/requests/' + zombie.session + '?token=' + beefwui.get_rest_token(),61}),62remoteSort: false,63autoDestroy: true,64autoLoad: false,65root: 'requests',6667fields: ['proto', 'domain', 'port', 'method', 'request_date', 'response_date','id', 'has_ran', 'path','response_status_code', 'response_status_text', 'response_port_status'],68sortInfo: {field: 'request_date', direction: 'DESC'},69});7071var req_pagesize = 30;7273var history_panel_bbar = new Ext.PagingToolbar({74pageSize: req_pagesize,75store: history_panel_store,76displayInfo: true,77displayMsg: 'Displaying history {0} - {1} of {2}',78emptyMsg: 'No history to display'79});8081var history_panel_grid = new Ext.grid.GridPanel({82id: 'requester-history-grid-zombie-'+zombie.session,83store: history_panel_store,84bbar: history_panel_bbar,85border: false,86loadMask: {msg:'Loading History...'},8788viewConfig: {89forceFit:true90},9192view: new Ext.grid.GridView({93forceFit: true,94emptyText: "No History",95enableRowBody:true96}),9798columns: [99{header: 'Id', width: 10, sortable: true, dataIndex: 'id', hidden:true},100{header: 'Proto', width: 30, sortable: true, dataIndex: 'proto', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}},101{header: 'Domain', sortable: true, dataIndex: 'domain', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}},102{header: 'Port', width: 30, sortable: true, dataIndex: 'port', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}},103{header: 'Method', width: 30, sortable: true, dataIndex: 'method', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}},104{header: 'Path', sortable: true, dataIndex: 'path', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}},105{header: 'Res Code', width: 35, sortable: true, dataIndex: 'response_status_code', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}},106{header: 'Res Text', width: 50, sortable: true, dataIndex: 'response_status_text', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}},107{header: 'Port Status', width: 40, sortable: true, dataIndex: 'response_port_status', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}},108{header: 'Processed', width: 50, sortable: true, dataIndex: 'has_ran', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}},109{header: 'Req Date', width: 50, sortable: true, dataIndex: 'request_date', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}},110{header: 'Res Date', width: 50, sortable: true, dataIndex: 'response_date', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}}111112],113114listeners: {115rowclick: function(grid, rowIndex) {116var tab_panel = Ext.getCmp('zombie-requester-tab-zombie-'+zombie.session);117var r = grid.getStore().getAt(rowIndex).data;118119if(r.has_ran != "complete") {120commands_statusbar.update_fail("Response for this request has not been received yet.");121return;122}123124if(!tab_panel.get('requester-response-'+r.id)) {125genResultTab(r, zombie, commands_statusbar);126}127},128afterrender: function(datagrid) {129datagrid.store.reload({params:{start:0,limit:req_pagesize, sort: "date", dir:"DESC"}});130},131132// History grid context menu (right click on a row in the history grid)133rowcontextmenu: function(grid, rowIndex, e){134e.preventDefault();135grid.getSelectionModel().selectRow(rowIndex);136if (!!grid.rowCtxMenu) {137grid.rowCtxMenu.destroy();138}139var record = grid.selModel.getSelected();140grid.rowCtxMenu = new Ext.menu.Menu({141items: [{142text: 'View Response',143iconCls: 'network-host-ctxMenu-web',144handler: function() {145if(record.get('has_ran') != "complete") {146commands_statusbar.update_fail("Response for this request has not been received yet.");147return;148}149if(!history_panel.get('requester-response-'+record.get('id'))) {150genResultTab(grid.getStore().getAt(rowIndex).data, zombie, commands_statusbar);151}152}153},{154text: 'Delete Response',155iconCls: 'zombie-tree-ctxMenu-delete',156handler: function() {157var response_id = record.get('id');158159if(record.get('has_ran') != "complete") {160commands_statusbar.update_fail("Response for this request has not been received yet.");161return;162} else {163if (!confirm('Are you sure you want to remove response [id: '+response_id+'] ?')) {164commands_statusbar.update_fail('Cancelled');165return;166}167commands_statusbar.update_sending('Removing network host [id: '+ response_id +'] ...');168deleteResponse(grid.getStore().getAt(rowIndex).data, zombie, commands_statusbar);169}170}171}]172});173grid.rowCtxMenu.showAt(e.getXY());174}175}176});177178var history_panel = new Ext.Panel({179id: 'requester-history-panel-zombie-'+zombie.session,180title: 'History',181items:[history_panel_grid],182layout: 'fit',183listeners: {184activate: function(history_panel) {185history_panel.items.items[0].store.reload({params: {nonce: Ext.get("nonce").dom.value}});186}187}188});189190// Return the extension_requester_http table row ID given a grid row index191function getHttpDbId(grid, rowIndex){192var row = grid.getStore().getAt(rowIndex).data;193var result = null;194if(row != null){195result = row.id;196}197return result;198}199200// Function generating the requests panel to send raw requests201//-------------------------------------------------------------202function genRawRequestPanel(zombie, bar, value) {203var form = new Ext.FormPanel({204title: 'Forge Raw HTTP Request',205id: 'requester-request-form-zombie'+zombie.session,206url: '/api/requester/send/' + zombie.session + '?token=' + beefwui.get_rest_token(),207hideLabels : true,208border: false,209padding: '3px 5px 0 5px',210211items:[{212xtype: 'checkboxgroup',213//border: true,214//fieldLabel : 'Request Options',215items: [{216boxLabel: 'SSL',217name: 'ssl',218inputValue: '1',219checked: false, // (window.location.protocol == 'https'),220id: 'requester-forge-requests-ssl'221}]222},{223xtype: 'textarea',224id: 'raw-request-zombie-'+zombie.session,225name: 'raw_request',226width: '100%',227height: '100%',228allowBlank: false229}],230231buttons: [{232text: 'Send',233handler: function() {234var use_ssl = Ext.getCmp('requester-forge-requests-ssl').getValue();235if (use_ssl) var proto = 'https'; else var proto = 'http';236var form = Ext.getCmp('requester-request-form-zombie'+zombie.session).getForm();237238bar.update_sending('Sending request to ' + zombie.ip + '...');239240form.submit({241params: {242raw_request: Ext.getCmp('raw-request-zombie-'+zombie.session).getValue(),243proto: proto244},245success: function() {246bar.update_sent("Request sent to hooked browser " + zombie.ip);247},248failure: function() {249bar.update_fail("Error! Invalid http request.");250}251});252}253}]254});255256if(!value) {257if (zombie.domain) {258value = "GET /demos/secret_page.html HTTP/1.1\n";259value += "Host: "+zombie.domain+":"+zombie.port+"\n";260} else value = "GET / HTTP/1.1\nHost: \n";261}262263form.get('raw-request-zombie-'+zombie.session).value = value;264265panel = Ext.getCmp('requester-forge-requests-zombie-'+zombie.session);266panel.setTitle('Forge Request');267panel.add(form);268};269270// Function to delete a response from the requester history271//------------------------------------------------------------------272function deleteResponse(request, zombie, bar) {273274Ext.Ajax.request({275url: '/api/requester/response/' + request.id + '?token=' + beefwui.get_rest_token(),276method: 'DELETE',277loadMask: true,278279success: function(response) {280var xhr = Ext.decode(response.responseText);281if (xhr['success'] == 'true') {282bar.update_sent("Deleted response.");283} else {284bar.update_fail("Error! Could not delete the response.");285}286},287288failure: function() {289bar.update_fail("Error! Could not delete the response.");290}291});292}293294// Function generating the panel that shows the results of a request295// This function is called when the user clicks on a row in the grid296// showing the results in the history.297//------------------------------------------------------------------298function genResultTab(request, zombie, bar) {299var tab_panel = Ext.getCmp('zombie-requester-tab-zombie-'+zombie.session);300301bar.update_sending('Getting response...');302303Ext.Ajax.request({304url: '/api/requester/response/' + request.id + '?token=' + beefwui.get_rest_token(),305loadMask: true,306success: function(response) {307var xhr = Ext.decode(response.responseText);308309if (xhr['success'] !== 'true') {310bar.update_fail("Error! Could not load the response.");311return;312}313314var tab_result_response_headers = new Ext.Panel({315title: 'Response Headers',316border: false,317collapsed: true,318layout: 'fit',319padding: '5px 5px 5px 5px',320items:[new Ext.form.TextArea({id: 'requester-response-res-headers-'+request.id, value: xhr.result.response_headers + "\n"})]321});322323var tab_result_response_body = new Ext.Panel({324title: 'Response Body',325border: false,326collapsed: false,327layout: 'fit',328padding: '5px 5px 5px 5px',329items:[new Ext.form.TextArea({id: 'requester-response-res-body-'+request.id, value: xhr.result.response + "\n"})]330});331332var tab_result_request = new Ext.Panel({333title: 'Request',334border: false,335collapsed: true,336layout: 'fit',337padding: '5px 5px 5px 5px',338items:[new Ext.form.TextArea({id: 'requester-response-req-'+request.id, value: xhr.result.request})]339});340341var tab_result_accordion = new Ext.Panel({342id: 'requester-response-'+request.id,343title: $jEncoder.encoder.encodeForHTML(request.path),344split: true,345border: false,346layout:'accordion',347closable: true,348items:[tab_result_request, tab_result_response_headers, tab_result_response_body]349});350351tab_panel.add(tab_result_accordion);352tab_panel.activate(tab_result_accordion.id);353354bar.update_sent("Displaying response.");355},356357failure: function() {358bar.update_fail("Error! Could not retrieve the response.");359}360});361};362363364ZombieTab_Requester.superclass.constructor.call(this, {365id: 'zombie-requester-tab-zombie-'+zombie.session,366title: 'Proxy',367activeTab: 0,368viewConfig: {369forceFit: true,370type: 'fit'371},372373items: [history_panel, requests_panel, proxy_panel],374375bbar: commands_statusbar,376377listeners: {378afterrender : function(){379genRawRequestPanel(zombie, commands_statusbar);380}381}382});383384};385386Ext.extend(ZombieTab_Requester, Ext.TabPanel, {});387388389