├── BappDescription.html ├── BappManifest.bmf ├── src └── main │ └── java │ └── burp │ ├── ConfigurationTableModel.java │ ├── PluginQueue.java │ ├── Configuration.java │ ├── PluginQueueTableModel.java │ ├── ScannerThread.java │ ├── BurpExtender.java │ └── PluginGUI.java ├── pom.xml └── README.md /BappDescription.html: -------------------------------------------------------------------------------- 1 |

This extension lets you configure multiple scan profiles, such as "XSS only" or "Quick scan". 2 | When sending items to be scanned, you can select which profile to use from the context menu.

3 | 4 |

The plugin will automatically manage the new queue and run scans with the different configuration.

5 | 6 |

Please note that when using this plugin you should NOT use the normal active scanner nor modify Burp scanning configuration.

7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /BappManifest.bmf: -------------------------------------------------------------------------------- 1 | Uuid: a019ad8b3cea46ac9032d279440f5372 2 | ExtensionType: 1 3 | Name: Attack Selector 4 | RepoName: attack-selector 5 | ScreenVersion: 0.1 6 | SerialVersion: 1 7 | MinPlatformVersion: 0 8 | ProOnly: True 9 | Author: Maurizio Agazzini 10 | ShortDescription: Allows you to create multiple scan profiles and select the one to use from the context menu. 11 | EntryPoint: target/AttackSelector-0.1-jar-with-dependencies.jar 12 | BuildCommand: mvn package -DskipTests=true -Dmaven.javadoc.skip=true -B 13 | -------------------------------------------------------------------------------- /src/main/java/burp/ConfigurationTableModel.java: -------------------------------------------------------------------------------- 1 | package burp; 2 | 3 | import java.util.List; 4 | import javax.swing.table.AbstractTableModel; 5 | 6 | public class ConfigurationTableModel extends AbstractTableModel { 7 | 8 | private final List configurationList; 9 | 10 | private static final long serialVersionUID = 1L; 11 | 12 | private final String[] columnNames = new String[] { "Enabled", "Name" }; 13 | 14 | private final Class[] columnClass = new Class[] { Boolean.class, String.class }; 15 | 16 | public ConfigurationTableModel(List configurationList) { 17 | this.configurationList = configurationList; 18 | } 19 | 20 | @Override 21 | public String getColumnName(int column) { 22 | return columnNames[column]; 23 | } 24 | 25 | @Override 26 | public Class getColumnClass(int columnIndex) { 27 | return columnClass[columnIndex]; 28 | } 29 | 30 | @Override 31 | public int getColumnCount() { 32 | return columnNames.length; 33 | } 34 | 35 | @Override 36 | public int getRowCount() { 37 | return configurationList.size(); 38 | } 39 | 40 | @Override 41 | public Object getValueAt(int rowIndex, int columnIndex) { 42 | Configuration row = configurationList.get(rowIndex); 43 | if (0 == columnIndex) { 44 | return row.getEnabled(); 45 | } else if (1 == columnIndex) { 46 | return row.getName(); 47 | } 48 | 49 | return null; 50 | } 51 | 52 | @Override 53 | public void setValueAt(Object value, int rowIndex, int colIndex) { 54 | Configuration row = configurationList.get(rowIndex); 55 | switch (colIndex) { 56 | case 0: 57 | row.setEnabled((Boolean) value); 58 | break; 59 | case 1: 60 | row.setName(value.toString()); 61 | break; 62 | } 63 | fireTableRowsUpdated(rowIndex, colIndex); 64 | } 65 | 66 | @Override 67 | public boolean isCellEditable(int rowIndex, int columnIndex) { 68 | if( rowIndex == 0 ) 69 | return false; 70 | 71 | return true; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | burp 6 | AttackSelector 7 | 0.1 8 | jar 9 | 10 | Burp Suite Attack Selector Plugin 11 | 12 | 13 | UTF-8 14 | 15 | 16 | 17 | 18 | 19 | org.json 20 | json 21 | 20170516 22 | 23 | 24 | 25 | net.portswigger.burp.extender 26 | burp-extender-api 27 | 1.7.22 28 | 29 | 30 | 31 | 32 | 33 | org.apache.maven.plugins 34 | maven-compiler-plugin 35 | 36 | 1.7 37 | 1.7 38 | 39 | jar-with-dependencies 40 | 41 | 42 | 43 | 44 | maven-assembly-plugin 45 | 3.1.0 46 | 47 | 48 | jar-with-dependencies 49 | 50 | 51 | 52 | 53 | make-assembly 54 | package 55 | 56 | single 57 | 58 | 59 | 60 | 61 | 62 | 63 | https://github.com/inode-/AttackSelector 64 | 65 | -------------------------------------------------------------------------------- /src/main/java/burp/PluginQueue.java: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * PluginQueue.java part of AttackSelector Burp Plugin * 3 | * * 4 | * Copyright (c) 2017, Agazzini Maurizio - inode@mediaservice.net * 5 | * All rights reserved. * 6 | * * 7 | * Redistribution and use in source and binary forms, with or without * 8 | * modification, are permitted provided that the following conditions * 9 | * are met: * 10 | * * Redistributions of source code must retain the above copyright * 11 | * notice, this list of conditions and the following disclaimer. * 12 | * * Redistributions in binary form must reproduce the above copyright * 13 | * notice, this list of conditions and the following disclaimer in * 14 | * the documentation and/or other materials provided with the * 15 | * distribution. * 16 | * * Neither the name of @ Mediaservice.net nor the names of its * 17 | * contributors may be used to endorse or promote products derived * 18 | * from this software without specific prior written permission. * 19 | * * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * 26 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * 27 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * 28 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * 29 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * 30 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 31 | *****************************************************************************/ 32 | 33 | package burp; 34 | 35 | public class PluginQueue { 36 | 37 | private int queueNumber; 38 | private IHttpRequestResponse message; 39 | private int configuration; 40 | private int status; 41 | private IScanQueueItem burp_queue; 42 | private boolean intruder; 43 | 44 | public int getQueueNumber() { 45 | return queueNumber; 46 | } 47 | 48 | public IHttpRequestResponse getMessage() { 49 | return message; 50 | } 51 | 52 | public int getConfiguration() { 53 | return configuration; 54 | } 55 | 56 | public int getStatus() { 57 | return status; 58 | } 59 | 60 | public boolean getIntruder() { 61 | return intruder; 62 | } 63 | 64 | public IScanQueueItem getBurpQueue() { 65 | return burp_queue; 66 | } 67 | 68 | public void setQueueNumber(int i) { 69 | queueNumber = i; 70 | } 71 | 72 | public void setIntruder(boolean i) { 73 | intruder = i; 74 | } 75 | 76 | public void setMessage(IHttpRequestResponse msg) { 77 | message = msg; 78 | } 79 | 80 | public void setConfiguration(int i) { 81 | configuration = i; 82 | } 83 | 84 | public void setStatus(int i) { 85 | status = i; 86 | } 87 | 88 | public void setBurpQueue(IScanQueueItem burp_queue) { 89 | this.burp_queue = burp_queue; 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/burp/Configuration.java: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * Configuration.java part of AttackSelector Burp Plugin * 3 | * * 4 | * Copyright (c) 2017, Agazzini Maurizio - inode@mediaservice.net * 5 | * All rights reserved. * 6 | * * 7 | * Redistribution and use in source and binary forms, with or without * 8 | * modification, are permitted provided that the following conditions * 9 | * are met: * 10 | * * Redistributions of source code must retain the above copyright * 11 | * notice, this list of conditions and the following disclaimer. * 12 | * * Redistributions in binary form must reproduce the above copyright * 13 | * notice, this list of conditions and the following disclaimer in * 14 | * the documentation and/or other materials provided with the * 15 | * distribution. * 16 | * * Neither the name of @ Mediaservice.net nor the names of its * 17 | * contributors may be used to endorse or promote products derived * 18 | * from this software without specific prior written permission. * 19 | * * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * 26 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * 27 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * 28 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * 29 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * 30 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 31 | *****************************************************************************/ 32 | 33 | package burp; 34 | 35 | import org.json.JSONObject; 36 | 37 | public class Configuration { 38 | 39 | private Boolean enabled; 40 | private String name; 41 | private JSONObject configuration; 42 | 43 | public Configuration() { 44 | 45 | } 46 | 47 | public Configuration(Boolean enabled, String name, String conf) { 48 | 49 | this.enabled = enabled; 50 | this.name = name; 51 | configuration = new JSONObject(conf); 52 | } 53 | 54 | public String getName() { 55 | return name; 56 | } 57 | 58 | public Boolean getEnabled() { 59 | return enabled; 60 | } 61 | 62 | public JSONObject getConfiguration() { 63 | return configuration; 64 | } 65 | 66 | public void setName(String name) { 67 | this.name = name; 68 | } 69 | 70 | public void setEnabled(Boolean enabled) { 71 | this.enabled = enabled; 72 | } 73 | 74 | public void setConfiguration(String conf) { 75 | configuration = new JSONObject(conf); 76 | } 77 | 78 | public JSONObject exportToJson() { 79 | JSONObject obj; 80 | 81 | obj = new JSONObject(); 82 | 83 | obj.put("name", name); 84 | obj.put("enabled", enabled); 85 | obj.put("configuration", configuration); 86 | 87 | return obj; 88 | } 89 | 90 | public void importFromJson(String conf) { 91 | JSONObject obj = new JSONObject(conf); 92 | 93 | setName((String) obj.get("name")); 94 | setEnabled((Boolean) obj.get("enabled")); 95 | 96 | configuration = new JSONObject(obj.getJSONObject("configuration").toString()); 97 | 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Burp Attack Selector Plugin 2 | 3 | During latest years Burp Suite scanner checks has been expanded a lot, but unfortunately the need of a scan time compromise has limited notably the checks executed during the scans with "Intelligent check" enabled. The current standard configuration will allow you to find the main issues but will not identify some kinds of problem. Also by modifiing the Burp configuration you will not be able to manage correctly the scans due [some actual Burp limitations](https://support.portswigger.net/customer/portal/questions/17025859-active-scan-configuration-taken-when-scan-request-insered-into-the-queue-and-not-when-scan-start). 4 | 5 | This plugin will let you to configure different settings for Burp active scanner and create some custom scanner configuration that can be launched via menu. The plugin will automatically manage the new queue and run scans with the different configuration. 6 | 7 | **Please note that when using this plugin you should NOT use the normal active scanner nor modify Burp scanning configuration**, by default the scanner will use the current configuration, so will execute only the tests configured in the running scan of this plugin. For this purpose we created a "default" scan configuration in this plugin that will allow you "simulate" the standard active scan, but it will be managed inside of the plugin so will be compatible with our others scans. 8 | 9 | During last week I discovered that [Burp Developers are planning to add some new features](https://support.portswigger.net/customer/portal/questions/17162032-my-letter-to-santa-burp-team-2-17-extender-api-enhancements-) like the queue management, maybe in some month my plugin will be unuseful ;) 10 | 11 | I have to thank [Federico Dotta](https://github.com/federicodotta/) for introducing me in Burp plugin programming and for the help given during the writing of this plugin. 12 | 13 | ## Usage 14 | 15 | When the plugin is added to Burp Suite a new tab will apper. This tab will allow you to see the plugin queue and configure your custom scanner configuration. After that you will able to launch the scan with that configuration via the content menu created. 16 | 17 | ![Configuration screenshot](https://user-images.githubusercontent.com/4608466/31863359-f0e1bb48-b74c-11e7-8242-726498266d3a.png) 18 | 19 | ![Queue management screenshot](https://user-images.githubusercontent.com/4608466/31863384-52999748-b74d-11e7-98b7-2b2b6899bbb5.png) 20 | 21 | ![Custom menu in proxy history](https://user-images.githubusercontent.com/4608466/31863391-7404902c-b74d-11e7-937d-1d40591d46b9.png) 22 | 23 | ![Custom menu in intruder](https://user-images.githubusercontent.com/4608466/31863404-9c206e82-b74d-11e7-92b0-58bb0ba3a2df.png) 24 | 25 | ## License 26 | 27 | Copyright (c) 2017, Agazzini Maurizio - inode@mediaservice.net 28 | All rights reserved. 29 | 30 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 31 | 32 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 33 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 34 | * Neither the name of @ Mediaservice.net nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 35 | 36 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /src/main/java/burp/PluginQueueTableModel.java: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * PluginQueueTableModel.java part of AttackSelector Burp Plugin * 3 | * * 4 | * Copyright (c) 2017, Agazzini Maurizio - inode@mediaservice.net * 5 | * All rights reserved. * 6 | * * 7 | * Redistribution and use in source and binary forms, with or without * 8 | * modification, are permitted provided that the following conditions * 9 | * are met: * 10 | * * Redistributions of source code must retain the above copyright * 11 | * notice, this list of conditions and the following disclaimer. * 12 | * * Redistributions in binary form must reproduce the above copyright * 13 | * notice, this list of conditions and the following disclaimer in * 14 | * the documentation and/or other materials provided with the * 15 | * distribution. * 16 | * * Neither the name of @ Mediaservice.net nor the names of its * 17 | * contributors may be used to endorse or promote products derived * 18 | * from this software without specific prior written permission. * 19 | * * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * 26 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * 27 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * 28 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * 29 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * 30 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 31 | *****************************************************************************/ 32 | 33 | package burp; 34 | 35 | import java.util.List; 36 | import java.net.URL; 37 | 38 | import javax.swing.table.AbstractTableModel; 39 | 40 | public class PluginQueueTableModel extends AbstractTableModel { 41 | 42 | private final List queueList; 43 | private List configurationList; 44 | 45 | private static final long serialVersionUID = 1L; 46 | 47 | private final String[] columnNames = new String[] { "#", "Host", "Url", "Configuration", "Status" }; 48 | 49 | private IExtensionHelpers helpers; 50 | 51 | private final Class[] columnClass = new Class[] { Integer.class, String.class, String.class, String.class, 52 | String.class }; 53 | 54 | public PluginQueueTableModel(List queueList, List configurationList, 55 | IExtensionHelpers helpers) { 56 | this.queueList = queueList; 57 | this.helpers = helpers; 58 | this.configurationList = configurationList; 59 | } 60 | 61 | @Override 62 | public String getColumnName(int column) { 63 | 64 | return columnNames[column]; 65 | } 66 | 67 | @Override 68 | public Class getColumnClass(int columnIndex) { 69 | return columnClass[columnIndex]; 70 | } 71 | 72 | @Override 73 | public int getColumnCount() { 74 | return columnNames.length; 75 | } 76 | 77 | @Override 78 | public int getRowCount() { 79 | return queueList.size(); 80 | } 81 | 82 | @Override 83 | public Object getValueAt(int rowIndex, int columnIndex) { 84 | 85 | PluginQueue row = queueList.get(rowIndex); 86 | if (0 == columnIndex) { 87 | return row.getQueueNumber(); 88 | } else if (1 == columnIndex) { 89 | return row.getMessage().getHttpService().getProtocol() + "://" + row.getMessage().getHttpService().getHost() 90 | + ":" + row.getMessage().getHttpService().getPort(); 91 | } else if (2 == columnIndex) { 92 | 93 | IRequestInfo request_info = helpers.analyzeRequest(row.getMessage()); 94 | URL requestUrl = request_info.getUrl(); 95 | 96 | String urlPath = requestUrl.getPath(); 97 | 98 | if ((requestUrl.getQuery() != null) && (!requestUrl.getQuery().isEmpty())) { 99 | urlPath.concat("?"); 100 | urlPath.concat(requestUrl.getQuery()); 101 | } 102 | 103 | return urlPath; 104 | 105 | } else if (3 == columnIndex) { 106 | return configurationList.get(row.getConfiguration()).getName(); 107 | } else if (4 == columnIndex) { 108 | 109 | switch (row.getStatus()) { 110 | 111 | case 0: 112 | return "queued"; 113 | case 1: 114 | return "scanning"; 115 | case 2: 116 | return "finished"; 117 | case 3: 118 | return "cancelled"; 119 | } 120 | 121 | return ""; 122 | } 123 | 124 | return null; 125 | } 126 | 127 | @Override 128 | public boolean isCellEditable(int rowIndex, int columnIndex) { 129 | 130 | return false; 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /src/main/java/burp/ScannerThread.java: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * ScannerThread.java part of AttackSelector Burp Plugin * 3 | * * 4 | * Copyright (c) 2017, Agazzini Maurizio - inode@mediaservice.net * 5 | * All rights reserved. * 6 | * * 7 | * Redistribution and use in source and binary forms, with or without * 8 | * modification, are permitted provided that the following conditions * 9 | * are met: * 10 | * * Redistributions of source code must retain the above copyright * 11 | * notice, this list of conditions and the following disclaimer. * 12 | * * Redistributions in binary form must reproduce the above copyright * 13 | * notice, this list of conditions and the following disclaimer in * 14 | * the documentation and/or other materials provided with the * 15 | * distribution. * 16 | * * Neither the name of @ Mediaservice.net nor the names of its * 17 | * contributors may be used to endorse or promote products derived * 18 | * from this software without specific prior written permission. * 19 | * * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * 26 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * 27 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * 28 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * 29 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * 30 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 31 | *****************************************************************************/ 32 | 33 | package burp; 34 | 35 | import java.io.PrintWriter; 36 | import java.util.List; 37 | import java.util.concurrent.locks.ReentrantLock; 38 | 39 | import org.json.JSONObject; 40 | 41 | public class ScannerThread implements Runnable { 42 | 43 | BurpExtender burp_plugin; 44 | 45 | private List queueList; 46 | private ReentrantLock lock; 47 | private static PrintWriter stdout; 48 | 49 | // Thread will check new work every X milliseconds 50 | private int check_every = 2000; 51 | 52 | private volatile boolean running = true; 53 | 54 | private IBurpExtenderCallbacks callbacks; 55 | 56 | public ScannerThread(BurpExtender plugin_ref) { 57 | 58 | burp_plugin = plugin_ref; 59 | 60 | queueList = burp_plugin.getqueueList(); 61 | lock = burp_plugin.getLock(); 62 | stdout = burp_plugin.getStdout(); 63 | callbacks = burp_plugin.getCallbacks(); 64 | } 65 | 66 | public void terminate() { 67 | running = false; 68 | } 69 | 70 | @Override 71 | public void run() { 72 | 73 | int maxThreads; 74 | 75 | while (running) { 76 | 77 | try { 78 | 79 | // Get current maximum of threads 80 | String jsonConfig = callbacks.saveConfigAsJson(); 81 | JSONObject obj = new JSONObject(jsonConfig); 82 | maxThreads = obj.getJSONObject("scanner").getJSONObject("active_scanning_engine") 83 | .getInt("number_of_threads"); 84 | 85 | lock.lock(); 86 | try { 87 | 88 | int currentThreads = 0; 89 | int configuration = -1; 90 | int thread_change = -1; 91 | 92 | // Removed unused threads 93 | for (int i = 0; i < queueList.size(); i++) { 94 | 95 | if (queueList.get(i).getStatus() == 1) { 96 | 97 | if (queueList.get(i).getBurpQueue().getStatus().contains("complete")) { 98 | 99 | // Save current running configuration 100 | configuration = queueList.get(i).getConfiguration(); 101 | currentThreads++; 102 | 103 | } else if (queueList.get(i).getBurpQueue().getStatus().contains("finished")) { 104 | queueList.get(i).setStatus(2); 105 | thread_change = 0; 106 | } 107 | 108 | else if (queueList.get(i).getBurpQueue().getStatus().contains("cancelled")) { 109 | queueList.get(i).setStatus(3); 110 | thread_change = 0; 111 | } 112 | 113 | } 114 | } 115 | 116 | // Revert configuration to default when all scan has been 117 | // finished 118 | if (thread_change == 0) 119 | burp_plugin.updateScannerConfig(queueList.get(0).getConfiguration()); 120 | 121 | // Add same configuration works 122 | for (int i = 0; i < queueList.size(); i++) { 123 | 124 | // If threads are full just skip 125 | if (currentThreads > maxThreads) 126 | break; 127 | 128 | if (queueList.get(i).getStatus() == 0) { 129 | 130 | if (queueList.get(i).getStatus() == 0 131 | && configuration == queueList.get(i).getConfiguration()) { 132 | 133 | if (currentThreads < maxThreads) { 134 | 135 | stdout.println("Add same configuration"); 136 | 137 | // Update to running 138 | queueList.get(i).setStatus(1); 139 | 140 | // Request to burp to scan the URL and 141 | // save the scan queue 142 | queueList.get(i).setBurpQueue(burp_plugin.scanVuln(queueList.get(i).getMessage(), 143 | queueList.get(i).getIntruder())); 144 | 145 | currentThreads++; 146 | 147 | stdout.println("Added a new URL to SCAN"); 148 | 149 | } 150 | } 151 | } 152 | } 153 | 154 | // Add new work if all threads are free 155 | for (int i = 0; i < queueList.size(); i++) { 156 | 157 | // If threads are full just skip 158 | if (currentThreads > maxThreads) 159 | break; 160 | 161 | if (queueList.get(i).getStatus() == 0) { 162 | 163 | if (configuration == -1) { 164 | 165 | configuration = queueList.get(i).getConfiguration(); 166 | burp_plugin.updateScannerConfig(configuration); 167 | 168 | } else if (configuration != queueList.get(i).getConfiguration()) 169 | continue; 170 | 171 | if (currentThreads < maxThreads) { 172 | 173 | // Update to running 174 | queueList.get(i).setStatus(1); 175 | 176 | // Request to burp to scan the URL and save the 177 | // scan queue 178 | queueList.get(i).setBurpQueue(burp_plugin.scanVuln(queueList.get(i).getMessage(), 179 | queueList.get(i).getIntruder())); 180 | 181 | currentThreads++; 182 | } 183 | 184 | } 185 | } 186 | 187 | } finally { 188 | lock.unlock(); 189 | } 190 | 191 | // wait sometimes, we do not want to use 100% of the CPU 192 | Thread.sleep(check_every); 193 | 194 | } catch (InterruptedException e) { 195 | 196 | stdout.println("Thread interrupted"); 197 | } 198 | } 199 | 200 | stdout.println("Thread ended."); 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /src/main/java/burp/BurpExtender.java: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * BurpExtender.java part of AttackSelector Burp Plugin * 3 | * * 4 | * Copyright (c) 2017, Agazzini Maurizio - inode@mediaservice.net * 5 | * All rights reserved. * 6 | * * 7 | * Redistribution and use in source and binary forms, with or without * 8 | * modification, are permitted provided that the following conditions * 9 | * are met: * 10 | * * Redistributions of source code must retain the above copyright * 11 | * notice, this list of conditions and the following disclaimer. * 12 | * * Redistributions in binary form must reproduce the above copyright * 13 | * notice, this list of conditions and the following disclaimer in * 14 | * the documentation and/or other materials provided with the * 15 | * distribution. * 16 | * * Neither the name of @ Mediaservice.net nor the names of its * 17 | * contributors may be used to endorse or promote products derived * 18 | * from this software without specific prior written permission. * 19 | * * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * 26 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * 27 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * 28 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * 29 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * 30 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 31 | *****************************************************************************/ 32 | 33 | package burp; 34 | 35 | import java.awt.event.ActionEvent; 36 | import java.awt.event.ActionListener; 37 | import java.io.PrintWriter; 38 | import java.lang.reflect.InvocationTargetException; 39 | import java.util.ArrayList; 40 | import java.util.Iterator; 41 | import java.util.List; 42 | import java.util.concurrent.locks.ReentrantLock; 43 | import javax.swing.JPanel; 44 | import javax.swing.SwingUtilities; 45 | import javax.swing.JMenuItem; 46 | import org.json.JSONObject; 47 | 48 | import java.awt.Component; 49 | import javax.swing.JMenu; 50 | import javax.swing.JCheckBox; 51 | import javax.swing.JComboBox; 52 | 53 | public class BurpExtender implements IBurpExtender, IContextMenuFactory, ActionListener, ITab, IExtensionStateListener { 54 | 55 | private IBurpExtenderCallbacks callbacks; 56 | private IExtensionHelpers helpers; 57 | 58 | private PrintWriter stdout; 59 | private PrintWriter stderr; 60 | 61 | IHttpRequestResponse[] selectedMessage; 62 | static char insertionPointChar; 63 | 64 | PluginGUI pluginGUI; 65 | 66 | JPanel configurationPanel; 67 | 68 | // JTable lists 69 | private List ConfigurationList; 70 | private List queueList; 71 | private PluginQueueTableModel queueModel; 72 | private ConfigurationTableModel configurationModel; 73 | 74 | // Threads objects 75 | private ReentrantLock lock; 76 | private Thread running_thread; 77 | private ScannerThread scannerThread = null; 78 | 79 | // Default burp configuration 80 | String json_configuration = new String( 81 | "{\"scanner\":{ \"active_scanning_areas\":{ \"csrf\":true, \"link_manipulation\":true, \"external_interaction\":true, \"file_path_traversal\":true, \"header_manipulation\":true, \"http_header_injection\":true, \"input_retrieval_reflected\":false, \"input_retrieval_stored\":false, \"ldap_injection\":true, \"open_redirection\":true, \"os_command_injection\":{ \"blind_checks\":true, \"enabled\":true, \"informed_checks\":true }, \"reflected_dom_issues\":true, \"reflected_xss\":false, \"server_level_issues\":true, \"server_side_code_injection\":true, \"server_side_template_injection\":true, \"smtp_header_injection\":true, \"sql_injection\":{ \"boolean_condition_checks\":true, \"enabled\":true, \"error_based_checks\":true, \"mssql_checks\":true, \"mysql_checks\":true, \"oracle_checks\":true, \"time_delay_checks\":true }, \"stored_dom_issues\":true, \"stored_xss\":true, \"suspicious_input_transformation\":true, \"xml_soap_injection\":true }, \"active_scanning_optimization\":{ \"intelligent_attack_selection\":true, \"scan_accuracy\":\"normal\", \"scan_speed\":\"normal\" }}}"); 82 | 83 | /** 84 | * @wbp.parser.entryPoint 85 | */ 86 | @Override 87 | public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) { 88 | 89 | // Keep a reference to our callbacks object 90 | this.callbacks = callbacks; 91 | 92 | // Obtain an extension helpers object 93 | helpers = callbacks.getHelpers(); 94 | 95 | // Set our extension name 96 | callbacks.setExtensionName("Attack Selector"); 97 | 98 | // register to produce options for the context menu 99 | callbacks.registerContextMenuFactory(this); 100 | 101 | callbacks.registerExtensionStateListener(this); 102 | 103 | // Initialize stdout and stderr 104 | stdout = new PrintWriter(callbacks.getStdout(), true); 105 | stderr = new PrintWriter(callbacks.getStderr(), true); 106 | 107 | stdout.println("Plugin loading..."); 108 | 109 | ConfigurationList = new ArrayList(); 110 | queueList = new ArrayList(); 111 | 112 | insertionPointChar = (char) 167; 113 | 114 | lock = new ReentrantLock(); 115 | 116 | queueModel = new PluginQueueTableModel(queueList, ConfigurationList, helpers); 117 | configurationModel = new ConfigurationTableModel(ConfigurationList); 118 | 119 | pluginGUI = new PluginGUI(callbacks, helpers, this, queueModel, configurationModel, ConfigurationList, 120 | queueList, stdout, stderr); 121 | 122 | try { 123 | SwingUtilities.invokeAndWait(pluginGUI); 124 | } catch (InvocationTargetException | InterruptedException e) { 125 | e.printStackTrace(); 126 | } 127 | 128 | callbacks.customizeUiComponent(pluginGUI.scannerPanel); 129 | callbacks.addSuiteTab(BurpExtender.this); 130 | 131 | // Start queue manager thread 132 | scannerThread = new ScannerThread(this); 133 | running_thread = new Thread(scannerThread); 134 | running_thread.start(); 135 | 136 | stdout.println("Attack selector loaded successfully."); 137 | 138 | // Used only for debugging purpose 139 | /* 140 | * String jsonConfig = this.callbacks.saveConfigAsJson(); JSONObject obj 141 | * = new JSONObject(jsonConfig); 142 | * stdout.println(obj.getJSONObject("scanner").toString()); 143 | */ 144 | 145 | } 146 | 147 | /** 148 | * Save the configuration of the plugin to burp preferences 149 | */ 150 | public void save_configuration_to_preferences() { 151 | JSONObject all_conf = new JSONObject(); 152 | 153 | for (int i = 0; i < ConfigurationList.size(); i++) { 154 | all_conf.put(Integer.toString(i), ConfigurationList.get(i).exportToJson()); 155 | } 156 | 157 | callbacks.saveExtensionSetting("configuration_list", all_conf.toString()); 158 | 159 | } 160 | 161 | /** 162 | * Load plugin configuration from burp preferences 163 | */ 164 | public void load_configuration_from_preferences() { 165 | 166 | JSONObject all_conf = new JSONObject(callbacks.loadExtensionSetting("configuration_list")); 167 | 168 | Iterator keys = all_conf.keys(); 169 | 170 | while (keys.hasNext()) { 171 | String key = (String) keys.next(); 172 | 173 | Configuration row1 = new Configuration(); 174 | row1.importFromJson(all_conf.getJSONObject(key).toString()); 175 | ConfigurationList.add(row1); 176 | 177 | } 178 | 179 | stdout.println("Configuration loaded."); 180 | 181 | } 182 | 183 | /** 184 | * Create the JSON containings the values from the UI 185 | */ 186 | public JSONObject build_json_from_ui() { 187 | 188 | Component[] allComponents = pluginGUI.panel_2.getComponents(); 189 | JSONObject obj = new JSONObject(json_configuration); 190 | 191 | // Parse active scanning optimization section 192 | JSONObject active_scanning_optimization = obj.getJSONObject("scanner") 193 | .getJSONObject("active_scanning_optimization"); 194 | 195 | for (int i = 0; i < allComponents.length; i++) { 196 | if (allComponents[i].getName() == null) 197 | continue; 198 | 199 | if (allComponents[i].getName().equals("intelligent_attack_selection")) { 200 | 201 | JCheckBox button22 = (JCheckBox) allComponents[i]; 202 | 203 | active_scanning_optimization.put("intelligent_attack_selection", button22.isSelected()); 204 | 205 | } else if (allComponents[i].getName().equals("scan_accuracy")) { 206 | 207 | JComboBox pluto = (JComboBox) allComponents[i]; 208 | 209 | switch (pluto.getSelectedIndex()) { 210 | case 0: 211 | active_scanning_optimization.put("scan_accuracy", "minimise_false_negatives"); 212 | break; 213 | case 1: 214 | active_scanning_optimization.put("scan_accuracy", "normal"); 215 | pluto.setSelectedIndex(1); 216 | break; 217 | case 2: 218 | active_scanning_optimization.put("scan_accuracy", "minimise_false_positives"); 219 | pluto.setSelectedIndex(2); 220 | break; 221 | } 222 | 223 | } else if (allComponents[i].getName().equals("scan_speed")) { 224 | JComboBox pluto = (JComboBox) allComponents[i]; 225 | 226 | switch (pluto.getSelectedIndex()) { 227 | case 0: 228 | active_scanning_optimization.put("scan_speed", "fast"); 229 | break; 230 | case 1: 231 | active_scanning_optimization.put("scan_speed", "normal"); 232 | break; 233 | case 2: 234 | active_scanning_optimization.put("scan_speed", "thorough"); 235 | break; 236 | } 237 | 238 | } 239 | } 240 | 241 | // Parse active scanning areas section 242 | JSONObject attackInsertionPoitnsObject = obj.getJSONObject("scanner").getJSONObject("active_scanning_areas"); 243 | 244 | Iterator keys = attackInsertionPoitnsObject.keys(); 245 | 246 | while (keys.hasNext()) { 247 | String key = (String) keys.next(); 248 | 249 | if (attackInsertionPoitnsObject.get(key) instanceof JSONObject) { 250 | JSONObject child = (JSONObject) (attackInsertionPoitnsObject.get(key)); 251 | Iterator keys1 = child.keys(); 252 | while (keys1.hasNext()) { 253 | String key1 = (String) keys1.next(); 254 | 255 | for (int i = 0; i < allComponents.length; i++) { 256 | 257 | if (allComponents[i].getName() == null) 258 | continue; 259 | 260 | if (allComponents[i].getName().equals(key + '+' + key1)) { 261 | 262 | if (allComponents[i] instanceof JCheckBox) { 263 | JCheckBox button22 = (JCheckBox) allComponents[i]; 264 | child.put(key1, button22.isSelected()); 265 | 266 | } 267 | } 268 | } 269 | 270 | } 271 | 272 | } else { 273 | 274 | for (int i = 0; i < allComponents.length; i++) { 275 | 276 | if (allComponents[i].getName() == null) 277 | continue; 278 | 279 | if (allComponents[i].getName().equals(key)) { 280 | 281 | if (allComponents[i] instanceof JCheckBox) { 282 | JCheckBox button22 = (JCheckBox) allComponents[i]; 283 | attackInsertionPoitnsObject.put(key, button22.isSelected()); 284 | } 285 | } 286 | } 287 | } 288 | } 289 | 290 | return obj; 291 | } 292 | 293 | /** 294 | * Update UI from a JSON containing the configuration 295 | */ 296 | public void update_ui_from_json(String json) { 297 | 298 | Component[] allComponents = pluginGUI.panel_2.getComponents(); 299 | 300 | JSONObject obj = new JSONObject(json); 301 | 302 | JSONObject active_scanning_optimization = obj.getJSONObject("scanner") 303 | .getJSONObject("active_scanning_optimization"); 304 | 305 | for (int i = 0; i < allComponents.length; i++) { 306 | if (allComponents[i].getName() == null) 307 | continue; 308 | 309 | if (allComponents[i].getName().equals("intelligent_attack_selection")) { 310 | 311 | JCheckBox button22 = (JCheckBox) allComponents[i]; 312 | button22.setSelected((boolean) active_scanning_optimization.get("intelligent_attack_selection")); 313 | 314 | } else if (allComponents[i].getName().equals("scan_accuracy")) { 315 | 316 | JComboBox pluto = (JComboBox) allComponents[i]; 317 | 318 | switch (active_scanning_optimization.get("scan_accuracy").toString()) { 319 | case "minimise_false_negatives": 320 | pluto.setSelectedIndex(0); 321 | break; 322 | case "normal": 323 | pluto.setSelectedIndex(1); 324 | break; 325 | case "minimise_false_positives": 326 | pluto.setSelectedIndex(2); 327 | break; 328 | } 329 | 330 | } else if (allComponents[i].getName().equals("scan_speed")) { 331 | JComboBox pluto = (JComboBox) allComponents[i]; 332 | 333 | switch (active_scanning_optimization.get("scan_speed").toString()) { 334 | case "fast": 335 | pluto.setSelectedIndex(0); 336 | break; 337 | case "normal": 338 | pluto.setSelectedIndex(1); 339 | break; 340 | case "thorough": 341 | pluto.setSelectedIndex(2); 342 | break; 343 | } 344 | 345 | } 346 | } 347 | 348 | JSONObject attackInsertionPoitnsObject = obj.getJSONObject("scanner").getJSONObject("active_scanning_areas"); 349 | 350 | Iterator keys = attackInsertionPoitnsObject.keys(); 351 | 352 | while (keys.hasNext()) { 353 | String key = (String) keys.next(); 354 | 355 | if (attackInsertionPoitnsObject.get(key) instanceof JSONObject) { 356 | JSONObject child = (JSONObject) (attackInsertionPoitnsObject.get(key)); 357 | Iterator keys1 = child.keys(); 358 | while (keys1.hasNext()) { 359 | String key1 = (String) keys1.next(); 360 | 361 | for (int i = 0; i < allComponents.length; i++) { 362 | 363 | if (allComponents[i].getName() == null) 364 | continue; 365 | 366 | if (allComponents[i].getName().equals(key + '+' + key1)) { 367 | if (allComponents[i] instanceof JCheckBox) { 368 | JCheckBox button22 = (JCheckBox) allComponents[i]; 369 | button22.setSelected((boolean) child.get(key1)); 370 | } 371 | } 372 | } 373 | 374 | } 375 | 376 | } else { 377 | 378 | for (int i = 0; i < allComponents.length; i++) { 379 | 380 | if (allComponents[i].getName() == null) 381 | continue; 382 | 383 | if (allComponents[i].getName().equals(key)) { 384 | if (allComponents[i] instanceof JCheckBox) { 385 | JCheckBox button22 = (JCheckBox) allComponents[i]; 386 | button22.setSelected((boolean) attackInsertionPoitnsObject.get(key)); 387 | } 388 | } 389 | } 390 | } 391 | } 392 | 393 | } 394 | 395 | @Override 396 | public List createMenuItems(IContextMenuInvocation invocation) { 397 | 398 | // Add custom content menu 399 | if (invocation.getInvocationContext() == IContextMenuInvocation.CONTEXT_MESSAGE_EDITOR_REQUEST 400 | || invocation.getInvocationContext() == IContextMenuInvocation.CONTEXT_MESSAGE_VIEWER_REQUEST 401 | || invocation.getInvocationContext() == IContextMenuInvocation.CONTEXT_INTRUDER_PAYLOAD_POSITIONS 402 | || invocation.getInvocationContext() == IContextMenuInvocation.CONTEXT_PROXY_HISTORY) { 403 | 404 | selectedMessage = invocation.getSelectedMessages(); 405 | 406 | List menu = new ArrayList(); 407 | 408 | JMenu main_menu = new JMenu("Attack selector"); 409 | 410 | for (int i = 0; i < ConfigurationList.size(); i++) { 411 | if (ConfigurationList.get(i).getEnabled() == true) { 412 | JMenuItem men_item = new JMenuItem(ConfigurationList.get(i).getName()); 413 | 414 | men_item.setActionCommand(Integer.toString(i + 1000)); 415 | men_item.addActionListener(this); 416 | 417 | main_menu.add(men_item); 418 | } 419 | } 420 | 421 | menu.add(main_menu); 422 | 423 | return menu; 424 | 425 | } else { 426 | 427 | return null; 428 | } 429 | 430 | } 431 | 432 | /** 433 | * Update burp scanner configuration with our needed option 434 | * 435 | * @param configurationIndex 436 | */ 437 | public void updateScannerConfig(int configurationIndex) { 438 | 439 | // Read Burp config 440 | String jsonConfig = callbacks.saveConfigAsJson(); 441 | 442 | // Parse Burp config and update the value of scanner parameters 443 | JSONObject obj = new JSONObject(jsonConfig); 444 | 445 | JSONObject current_config = obj.getJSONObject("scanner"); 446 | 447 | // Update the configuration with our options 448 | current_config.put("active_scanning_areas", ConfigurationList.get(configurationIndex).exportToJson() 449 | .getJSONObject("configuration").getJSONObject("scanner").getJSONObject("active_scanning_areas")); 450 | current_config.put("active_scanning_optimization", ConfigurationList.get(configurationIndex).exportToJson() 451 | .getJSONObject("configuration").getJSONObject("scanner").getJSONObject("active_scanning_optimization")); 452 | 453 | // Load updated config 454 | callbacks.loadConfigFromJson(obj.toString()); 455 | 456 | } 457 | 458 | /** 459 | * Add to burp active scan by Federico Dotta 460 | * 461 | * @param message 462 | * @param intruder 463 | * @return 464 | */ 465 | public IScanQueueItem scanVuln(IHttpRequestResponse message, boolean intruder) { 466 | 467 | IScanQueueItem ret; 468 | 469 | String requestString = new String(message.getRequest()); 470 | 471 | List insertionPointCoupledIndexes = new ArrayList(); 472 | int[] currentCouple = new int[2]; 473 | 474 | if (intruder == true) { 475 | boolean first = true; 476 | int currentIndex = requestString.indexOf(insertionPointChar); 477 | if (currentIndex != -1) { 478 | currentCouple[0] = currentIndex; 479 | requestString = deleteCharAt(requestString, currentIndex); 480 | first = false; 481 | } 482 | while (currentIndex >= 0) { 483 | currentIndex = requestString.indexOf(insertionPointChar); 484 | if (currentIndex != -1 && first) { 485 | requestString = deleteCharAt(requestString, currentIndex); 486 | currentCouple[0] = currentIndex; 487 | first = false; 488 | } else if (currentIndex != -1 && !first) { 489 | requestString = deleteCharAt(requestString, currentIndex); 490 | currentCouple[1] = currentIndex - 1; 491 | first = true; 492 | insertionPointCoupledIndexes.add(currentCouple); 493 | currentCouple = new int[2]; 494 | } 495 | 496 | } 497 | } 498 | 499 | if (intruder == true && insertionPointCoupledIndexes.size() > 0) { 500 | 501 | // Do active scan on selected insertion points 502 | ret = callbacks.doActiveScan(message.getHttpService().getHost(), message.getHttpService().getPort(), 503 | (message.getHttpService().getProtocol().equals("http") ? false : true), requestString.getBytes(), 504 | insertionPointCoupledIndexes); 505 | 506 | } else { 507 | 508 | // Do active scan on every insertion points 509 | ret = callbacks.doActiveScan(message.getHttpService().getHost(), message.getHttpService().getPort(), 510 | (message.getHttpService().getProtocol().equals("http") ? false : true), requestString.getBytes()); 511 | 512 | } 513 | 514 | return ret; 515 | 516 | } 517 | 518 | public static String deleteCharAt(String s, int index) { 519 | 520 | StringBuilder sb = new StringBuilder(s); 521 | sb.deleteCharAt(index); 522 | return sb.toString(); 523 | 524 | } 525 | 526 | @Override 527 | public void actionPerformed(ActionEvent event) { 528 | 529 | String command = event.getActionCommand(); 530 | 531 | PluginQueue obj = new PluginQueue(); 532 | obj.setMessage(selectedMessage[0]); 533 | 534 | obj.setQueueNumber(queueList.size()); 535 | obj.setStatus(0); 536 | 537 | if (Integer.parseInt(command) >= 1000) { 538 | obj.setConfiguration(Integer.parseInt(command) - 1000); 539 | obj.setIntruder(false); 540 | } else { 541 | obj.setConfiguration(Integer.parseInt(command)); 542 | obj.setIntruder(true); 543 | } 544 | 545 | lock.lock(); 546 | try { 547 | queueList.add(obj); 548 | } finally { 549 | lock.unlock(); 550 | } 551 | 552 | javax.swing.SwingUtilities.invokeLater(new Runnable() { 553 | public void run() { 554 | pluginGUI.update_scanner_table("insert", queueList.size() - 1, queueList.size() - 1); 555 | } 556 | }); 557 | 558 | } 559 | 560 | public List getqueueList() { 561 | return queueList; 562 | } 563 | 564 | public ReentrantLock getLock() { 565 | return lock; 566 | 567 | } 568 | 569 | public PrintWriter getStdout() { 570 | return stdout; 571 | 572 | } 573 | 574 | public IBurpExtenderCallbacks getCallbacks() { 575 | return callbacks; 576 | } 577 | 578 | /* 579 | * This method return the name of the created tab 580 | */ 581 | @Override 582 | public String getTabCaption() { 583 | 584 | return "Attack selector"; 585 | 586 | } 587 | 588 | /* 589 | * This method return the panel that will be included in Burp Suite 590 | */ 591 | @Override 592 | public Component getUiComponent() { 593 | 594 | return pluginGUI.mainPanel; 595 | } 596 | 597 | @Override 598 | public void extensionUnloaded() { 599 | 600 | // Request to stop the thread in case of extension unload 601 | scannerThread.terminate(); 602 | 603 | } 604 | } 605 | -------------------------------------------------------------------------------- /src/main/java/burp/PluginGUI.java: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * PluginGUI.java part of AttackSelector Burp Plugin * 3 | * * 4 | * Copyright (c) 2017, Agazzini Maurizio - inode@mediaservice.net * 5 | * All rights reserved. * 6 | * * 7 | * Redistribution and use in source and binary forms, with or without * 8 | * modification, are permitted provided that the following conditions * 9 | * are met: * 10 | * * Redistributions of source code must retain the above copyright * 11 | * notice, this list of conditions and the following disclaimer. * 12 | * * Redistributions in binary form must reproduce the above copyright * 13 | * notice, this list of conditions and the following disclaimer in * 14 | * the documentation and/or other materials provided with the * 15 | * distribution. * 16 | * * Neither the name of @ Mediaservice.net nor the names of its * 17 | * contributors may be used to endorse or promote products derived * 18 | * from this software without specific prior written permission. * 19 | * * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * 26 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * 27 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * 28 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * 29 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * 30 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 31 | *****************************************************************************/ 32 | 33 | package burp; 34 | 35 | import java.awt.BorderLayout; 36 | import java.awt.Color; 37 | import java.awt.Component; 38 | import java.awt.Font; 39 | import java.awt.event.ActionEvent; 40 | import java.awt.event.ActionListener; 41 | import java.awt.event.ItemEvent; 42 | import java.awt.event.ItemListener; 43 | import java.io.File; 44 | import java.io.FileInputStream; 45 | import java.io.FileWriter; 46 | import java.io.IOException; 47 | import java.io.PrintWriter; 48 | import java.util.Iterator; 49 | import java.util.List; 50 | 51 | import javax.swing.GroupLayout; 52 | import javax.swing.GroupLayout.Alignment; 53 | import javax.swing.JButton; 54 | import javax.swing.JCheckBox; 55 | import javax.swing.JComboBox; 56 | import javax.swing.JFileChooser; 57 | import javax.swing.JFrame; 58 | import javax.swing.JLabel; 59 | import javax.swing.JPanel; 60 | import javax.swing.JScrollPane; 61 | import javax.swing.JSplitPane; 62 | import javax.swing.JTabbedPane; 63 | import javax.swing.JTable; 64 | import javax.swing.LayoutStyle.ComponentPlacement; 65 | import javax.swing.ListSelectionModel; 66 | import javax.swing.event.ListSelectionEvent; 67 | import javax.swing.event.ListSelectionListener; 68 | 69 | import org.json.JSONObject; 70 | 71 | /** 72 | * This class create the GUI components of the plugin 73 | * 74 | */ 75 | public class PluginGUI implements Runnable, ActionListener, ListSelectionListener, ItemListener { 76 | 77 | JPanel configurationPanel; 78 | private JTable table; 79 | JTabbedPane mainPanel; 80 | private JPanel scan_profiles_panel; 81 | private JButton buttonAdd; 82 | private JButton buttonDelete; 83 | private JScrollPane scrollPane; 84 | private JTable scan_profile_table; 85 | private JPanel active_configurator_panel; 86 | private JLabel lblNewLabel; 87 | private JLabel label_1; 88 | private JLabel label_2; 89 | private JLabel label_3; 90 | private JPanel left_panel; 91 | private JButton buttonCancel; 92 | private JPanel main_panel; 93 | private JSplitPane splitPane; 94 | private JPanel button_panel; 95 | private JButton buttonExport; 96 | private JButton buttonImport; 97 | private JPanel jtable_panel; 98 | private JPanel header_panel; 99 | private JLabel lblNewLabel_1; 100 | private JScrollPane scrollPane_1; 101 | private JCheckBox chckbxNewCheckBox; 102 | private JComboBox comboBox; 103 | private JComboBox comboBox_1; 104 | private JCheckBox chckbxNewCheckBox_1; 105 | private JCheckBox checkBox_1; 106 | private JCheckBox checkBox_3; 107 | private JCheckBox checkBox_4; 108 | private JCheckBox checkBox_5; 109 | private JCheckBox checkBox_6; 110 | private JCheckBox checkBox_7; 111 | private JCheckBox checkBox_8; 112 | private JCheckBox checkBox_9; 113 | private JCheckBox checkBox_10; 114 | private JCheckBox checkBox_11; 115 | private JCheckBox checkBox_12; 116 | private JCheckBox checkBox_13; 117 | private JCheckBox checkBox_14; 118 | private JCheckBox checkBox_15; 119 | private JCheckBox checkBox_16; 120 | private JCheckBox checkBox_17; 121 | private JCheckBox checkBox_18; 122 | private JCheckBox checkBox_19; 123 | private JCheckBox checkBox_20; 124 | private JCheckBox checkBox_21; 125 | private JCheckBox checkBox_22; 126 | private JCheckBox checkBox_23; 127 | private JCheckBox checkBox_24; 128 | private JCheckBox checkBox_25; 129 | private JCheckBox checkBox_26; 130 | private JCheckBox checkBox_27; 131 | private JCheckBox checkBox_28; 132 | JPanel panel_2; 133 | private PluginQueueTableModel pluginModel; 134 | public JCheckBox checkBox; 135 | JPanel scannerPanel; 136 | 137 | private PrintWriter stdout; 138 | private PrintWriter stderr; 139 | 140 | IBurpExtenderCallbacks callbacks; 141 | IExtensionHelpers helpers; 142 | 143 | BurpExtender plugin_ref; 144 | 145 | ConfigurationTableModel configurationModel; 146 | 147 | List ConfigurationList; 148 | List queueList; 149 | 150 | JCheckBox checkBox_2; 151 | 152 | public PluginGUI(IBurpExtenderCallbacks callbacks, IExtensionHelpers helpers, BurpExtender plugin_ref, 153 | PluginQueueTableModel model1, ConfigurationTableModel model, List ConfigurationList, 154 | List QueueList, PrintWriter stdout, PrintWriter stderr) { 155 | this.callbacks = callbacks; 156 | this.helpers = helpers; 157 | this.plugin_ref = plugin_ref; 158 | this.pluginModel = model1; 159 | this.configurationModel = model; 160 | this.ConfigurationList = ConfigurationList; 161 | this.queueList = QueueList; 162 | this.stdout = stdout; 163 | this.stderr = stderr; 164 | } 165 | 166 | /** 167 | * @wbp.parser.entryPoint 168 | */ 169 | @Override 170 | public void run() { 171 | 172 | mainPanel = new JTabbedPane(); 173 | 174 | // Initialize a empy panel to include in Burp Tab 175 | scannerPanel = new JPanel(); 176 | configurationPanel = new JPanel(); 177 | 178 | scannerPanel.setLayout(new BorderLayout(0, 0)); 179 | 180 | left_panel = new JPanel(); 181 | scannerPanel.add(left_panel, BorderLayout.SOUTH); 182 | 183 | buttonCancel = new JButton("Cancel all scans"); 184 | buttonCancel.addActionListener(this); 185 | 186 | JButton buttonRemove = new JButton("Remove completed"); 187 | buttonRemove.addActionListener(this); 188 | 189 | GroupLayout gl_left_panel = new GroupLayout(left_panel); 190 | gl_left_panel.setHorizontalGroup(gl_left_panel.createParallelGroup(Alignment.LEADING) 191 | .addGroup(gl_left_panel.createSequentialGroup().addContainerGap().addComponent(buttonCancel) 192 | .addPreferredGap(ComponentPlacement.RELATED).addComponent(buttonRemove).addContainerGap(15, 193 | Short.MAX_VALUE))); 194 | gl_left_panel.setVerticalGroup(gl_left_panel.createParallelGroup(Alignment.LEADING) 195 | .addGroup(gl_left_panel.createSequentialGroup().addContainerGap().addGroup(gl_left_panel 196 | .createParallelGroup(Alignment.BASELINE).addComponent(buttonCancel).addComponent(buttonRemove)) 197 | .addGap(20))); 198 | left_panel.setLayout(gl_left_panel); 199 | 200 | main_panel = new JPanel(); 201 | scannerPanel.add(main_panel, BorderLayout.CENTER); 202 | 203 | main_panel.setLayout(new BorderLayout(0, 0)); 204 | 205 | table = new JTable(pluginModel); 206 | 207 | table.getColumnModel().getColumn(0).setPreferredWidth(60); 208 | table.getColumnModel().getColumn(0).setMinWidth(20); 209 | table.getColumnModel().getColumn(0).setMaxWidth(90); 210 | table.getColumnModel().getColumn(1).setPreferredWidth(300); 211 | table.getColumnModel().getColumn(1).setMinWidth(20); 212 | table.getColumnModel().getColumn(1).setMaxWidth(300); 213 | table.getColumnModel().getColumn(3).setPreferredWidth(150); 214 | table.getColumnModel().getColumn(3).setMinWidth(20); 215 | table.getColumnModel().getColumn(3).setMaxWidth(150); 216 | table.getColumnModel().getColumn(4).setPreferredWidth(90); 217 | table.getColumnModel().getColumn(4).setMinWidth(20); 218 | table.getColumnModel().getColumn(4).setMaxWidth(90); 219 | 220 | main_panel.add(new JScrollPane(table)); 221 | 222 | configurationPanel.setLayout(new BorderLayout(0, 0)); 223 | 224 | splitPane = new JSplitPane(); 225 | splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT); 226 | 227 | configurationPanel.add(splitPane, BorderLayout.CENTER); 228 | 229 | scan_profiles_panel = new JPanel(); 230 | splitPane.setLeftComponent(scan_profiles_panel); 231 | 232 | buttonAdd = new JButton("Add"); 233 | scan_profiles_panel.setLayout(new BorderLayout(0, 0)); 234 | 235 | buttonDelete = new JButton("Delete"); 236 | 237 | button_panel = new JPanel(); 238 | scan_profiles_panel.add(button_panel, BorderLayout.WEST); 239 | 240 | buttonExport = new JButton("Export conf."); 241 | buttonExport.addActionListener(this); 242 | 243 | buttonImport = new JButton("Import conf."); 244 | buttonImport.addActionListener(this); 245 | 246 | GroupLayout gl_button_panel = new GroupLayout(button_panel); 247 | gl_button_panel.setHorizontalGroup(gl_button_panel.createParallelGroup(Alignment.LEADING) 248 | .addGroup(gl_button_panel.createSequentialGroup().addContainerGap().addGroup(gl_button_panel 249 | .createParallelGroup(Alignment.TRAILING, false) 250 | .addComponent(buttonDelete, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 251 | GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 252 | .addComponent(buttonAdd, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 93, Short.MAX_VALUE) 253 | .addComponent(buttonExport, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 74, Short.MAX_VALUE) 254 | .addComponent(buttonImport, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 74, Short.MAX_VALUE)) 255 | .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) 256 | .addGroup(Alignment.TRAILING, 257 | gl_button_panel.createSequentialGroup().addContainerGap(14, Short.MAX_VALUE) 258 | 259 | .addContainerGap())); 260 | gl_button_panel.setVerticalGroup(gl_button_panel.createParallelGroup(Alignment.LEADING) 261 | .addGroup(gl_button_panel.createSequentialGroup().addGap(10).addComponent(buttonAdd) 262 | .addPreferredGap(ComponentPlacement.RELATED).addComponent(buttonDelete) 263 | .addPreferredGap(ComponentPlacement.RELATED).addComponent(buttonExport) 264 | .addPreferredGap(ComponentPlacement.RELATED).addComponent(buttonImport) 265 | .addPreferredGap(ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))); 266 | button_panel.setLayout(gl_button_panel); 267 | 268 | scan_profile_table = new JTable(configurationModel); 269 | 270 | scan_profile_table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 271 | scan_profile_table.getColumnModel().getColumn(0).setPreferredWidth(60); 272 | scan_profile_table.getColumnModel().getColumn(1).setPreferredWidth(300); 273 | 274 | jtable_panel = new JPanel(); 275 | jtable_panel.setBorder(null); 276 | 277 | scrollPane = new JScrollPane(scan_profile_table); 278 | jtable_panel.setLayout(new BorderLayout(0, 0)); 279 | jtable_panel.add(scrollPane, BorderLayout.CENTER); 280 | 281 | scan_profiles_panel.add(jtable_panel, BorderLayout.CENTER); 282 | 283 | header_panel = new JPanel(); 284 | scan_profiles_panel.add(header_panel, BorderLayout.NORTH); 285 | 286 | lblNewLabel_1 = new JLabel("Scan profiles"); 287 | 288 | lblNewLabel_1.setForeground(new Color(228, 136, 56)); 289 | Font f = lblNewLabel_1.getFont(); 290 | lblNewLabel_1.setFont(f.deriveFont(f.getStyle() | Font.BOLD)); 291 | f = lblNewLabel_1.getFont(); 292 | lblNewLabel_1.setFont(f.deriveFont((float) (f.getSize() + 2))); 293 | 294 | GroupLayout gl_header_panel = new GroupLayout(header_panel); 295 | gl_header_panel.setHorizontalGroup(gl_header_panel.createParallelGroup(Alignment.LEADING) 296 | .addGroup(gl_header_panel.createSequentialGroup().addGap(5).addComponent(lblNewLabel_1))); 297 | gl_header_panel.setVerticalGroup(gl_header_panel.createParallelGroup(Alignment.LEADING) 298 | .addGroup(gl_header_panel.createSequentialGroup().addGap(5).addComponent(lblNewLabel_1).addGap(10))); 299 | header_panel.setLayout(gl_header_panel); 300 | 301 | // add the custom tab to Burp's UI 302 | mainPanel.addTab("Scanner", scannerPanel); 303 | mainPanel.addTab("Configuration", configurationPanel); 304 | 305 | active_configurator_panel = new JPanel(); 306 | splitPane.setRightComponent(active_configurator_panel); 307 | active_configurator_panel.setLayout(new BorderLayout(0, 0)); 308 | 309 | scrollPane_1 = new JScrollPane(); 310 | active_configurator_panel.add(scrollPane_1, BorderLayout.CENTER); 311 | 312 | panel_2 = new JPanel(); 313 | 314 | scrollPane_1.setViewportView(panel_2); 315 | lblNewLabel = new JLabel("Active Scanning Optimization"); 316 | lblNewLabel.setForeground(new Color(228, 136, 56)); 317 | Font font1 = lblNewLabel.getFont(); 318 | lblNewLabel.setFont(font1.deriveFont(font1.getStyle() | Font.BOLD)); 319 | font1 = lblNewLabel.getFont(); 320 | lblNewLabel.setFont(font1.deriveFont((float) (font1.getSize() + 2))); 321 | 322 | label_1 = new JLabel("Active Scanning Areas"); 323 | label_1.setForeground(new Color(228, 136, 56)); 324 | font1 = label_1.getFont(); 325 | label_1.setFont(font1.deriveFont(font1.getStyle() | Font.BOLD)); 326 | font1 = label_1.getFont(); 327 | label_1.setFont(font1.deriveFont((float) (font1.getSize() + 2))); 328 | 329 | label_2 = new JLabel("Scan speed:"); 330 | 331 | label_3 = new JLabel("Scan accuracy:"); 332 | 333 | chckbxNewCheckBox = new JCheckBox("Use intelligent attack selection"); 334 | chckbxNewCheckBox.setName("intelligent_attack_selection"); 335 | 336 | String[] speed_text = new String[] { "Fast", "Normal", "Thorough" }; 337 | String[] accuracy_text = new String[] { "Minimize false genatives", "Normal", "Minimize false positives" }; 338 | 339 | comboBox = new JComboBox(speed_text); 340 | comboBox.setName("scan_speed"); 341 | comboBox_1 = new JComboBox(accuracy_text); 342 | comboBox_1.setName("scan_accuracy"); 343 | 344 | chckbxNewCheckBox_1 = new JCheckBox("SQL Injection"); 345 | chckbxNewCheckBox_1.setName("sql_injection+enabled"); 346 | chckbxNewCheckBox_1.setSelected(true); 347 | 348 | checkBox = new JCheckBox("Error-based"); 349 | checkBox.setName("sql_injection+error_based_checks"); 350 | checkBox_1 = new JCheckBox("Time-delay checks"); 351 | checkBox_1.setName("sql_injection+time_delay_checks"); 352 | checkBox_2 = new JCheckBox("Boolen condition checks"); 353 | checkBox_2.setName("sql_injection+boolean_condition_checks"); 354 | checkBox_3 = new JCheckBox("MSSQL-specific checks"); 355 | checkBox_3.setName("sql_injection+mssql_checks"); 356 | checkBox_4 = new JCheckBox("Oracle-specific checks"); 357 | checkBox_4.setName("sql_injection+oracle_checks"); 358 | checkBox_5 = new JCheckBox("MySQL-specific checks"); 359 | checkBox_5.setName("sql_injection+mysql_checks"); 360 | checkBox_6 = new JCheckBox("OS Injection"); 361 | checkBox_6.setSelected(true); 362 | 363 | checkBox_6.setName("os_command_injection+enabled"); 364 | checkBox_7 = new JCheckBox("Informed"); 365 | checkBox_7.setName("os_command_injection+informed_checks"); 366 | checkBox_8 = new JCheckBox("Blind"); 367 | checkBox_8.setName("os_command_injection+blind_checks"); 368 | checkBox_9 = new JCheckBox("Server-side code injection"); 369 | checkBox_9.setName("server_side_code_injection"); 370 | checkBox_10 = new JCheckBox("Server-side template injection"); 371 | checkBox_10.setName("server_side_template_injection"); 372 | checkBox_11 = new JCheckBox("Reflected cross-site scripting"); 373 | checkBox_11.setName("reflected_xss"); 374 | checkBox_12 = new JCheckBox("Stored cross-site scripting"); 375 | checkBox_12.setName("stored_xss"); 376 | checkBox_13 = new JCheckBox("Reflected DOM issues"); 377 | checkBox_13.setName("reflected_dom_issues"); 378 | checkBox_14 = new JCheckBox("Stored DOM issues"); 379 | checkBox_14.setName("stored_dom_issues"); 380 | checkBox_15 = new JCheckBox("File path traversal / manipulation"); 381 | checkBox_15.setName("file_path_traversal"); 382 | checkBox_16 = new JCheckBox("External / out-of-band interaction"); 383 | checkBox_16.setName("external_interaction"); 384 | checkBox_17 = new JCheckBox("HTTP header injection"); 385 | checkBox_17.setName("http_header_injection"); 386 | checkBox_18 = new JCheckBox("SMTP header injection"); 387 | checkBox_18.setName("smtp_header_injection"); 388 | checkBox_19 = new JCheckBox("XML / SOAP injection"); 389 | checkBox_19.setName("xml_soap_injection"); 390 | checkBox_20 = new JCheckBox("LDAP injection"); 391 | checkBox_20.setName("ldap_injection"); 392 | checkBox_21 = new JCheckBox("Cross-site request forgery"); 393 | checkBox_21.setName("csrf"); 394 | checkBox_22 = new JCheckBox("Open redirection"); 395 | checkBox_22.setName("open_redirection"); 396 | checkBox_23 = new JCheckBox("Header manipulation"); 397 | checkBox_23.setName("header_manipulation"); 398 | checkBox_24 = new JCheckBox("Server-level issues"); 399 | checkBox_24.setName("server_level_issues"); 400 | checkBox_25 = new JCheckBox("Suspicious input transformation"); 401 | checkBox_25.setName("suspicious_input_transformation"); 402 | checkBox_26 = new JCheckBox("Input returned in response (reflected)"); 403 | checkBox_26.setName("input_retrieval_reflected"); 404 | checkBox_27 = new JCheckBox("Input returned in response (stored)"); 405 | checkBox_27.setName("input_retrieval_stored"); 406 | checkBox_28 = new JCheckBox("Link manipulation"); 407 | checkBox_28.setName("link_manipulation"); 408 | 409 | GroupLayout gl_panel_2 = new GroupLayout(panel_2); 410 | gl_panel_2.setHorizontalGroup(gl_panel_2.createParallelGroup(Alignment.LEADING) 411 | .addGroup(gl_panel_2.createSequentialGroup().addGroup(gl_panel_2.createParallelGroup(Alignment.LEADING) 412 | .addGroup(gl_panel_2.createSequentialGroup().addContainerGap().addComponent(lblNewLabel)) 413 | .addGroup(gl_panel_2.createSequentialGroup().addGap(22) 414 | .addGroup(gl_panel_2.createParallelGroup(Alignment.LEADING).addComponent(checkBox_6) 415 | .addComponent(chckbxNewCheckBox_1).addComponent(checkBox_9) 416 | .addComponent(checkBox_10).addComponent(checkBox_11).addComponent(checkBox_12) 417 | .addComponent(checkBox_13).addComponent(checkBox_14).addComponent(checkBox_15) 418 | .addComponent(checkBox_16).addComponent(checkBox_17).addComponent(checkBox_18) 419 | .addComponent(checkBox_19).addComponent(checkBox_20).addComponent(checkBox_21) 420 | .addComponent(checkBox_22).addComponent(checkBox_23).addComponent(checkBox_24) 421 | .addComponent(checkBox_25).addComponent(checkBox_28).addComponent(checkBox_26) 422 | .addComponent(checkBox_27))) 423 | .addGroup(gl_panel_2.createSequentialGroup().addGap(72).addComponent(checkBox_7)) 424 | .addGroup(gl_panel_2.createSequentialGroup().addGap(66) 425 | .addGroup(gl_panel_2.createParallelGroup(Alignment.LEADING).addComponent(checkBox) 426 | .addComponent(checkBox_1).addGroup( 427 | gl_panel_2.createSequentialGroup().addComponent(checkBox_2).addGap(18) 428 | .addGroup(gl_panel_2.createParallelGroup(Alignment.LEADING) 429 | .addComponent(checkBox_4).addComponent(checkBox_5) 430 | .addComponent(checkBox_3).addComponent(checkBox_8))))) 431 | .addGroup(gl_panel_2.createParallelGroup(Alignment.LEADING, false) 432 | .addGroup(gl_panel_2.createSequentialGroup().addContainerGap().addComponent(label_1, 433 | GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) 434 | .addGroup( 435 | gl_panel_2.createSequentialGroup().addGap(22).addGroup(gl_panel_2 436 | .createParallelGroup(Alignment.LEADING).addGroup(gl_panel_2 437 | .createSequentialGroup() 438 | .addGroup(gl_panel_2 439 | .createParallelGroup(Alignment.TRAILING, false) 440 | .addComponent(label_2, GroupLayout.DEFAULT_SIZE, 441 | GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 442 | .addComponent(label_3, GroupLayout.DEFAULT_SIZE, 82, 443 | Short.MAX_VALUE)) 444 | .addPreferredGap(ComponentPlacement.RELATED) 445 | .addGroup(gl_panel_2 446 | .createParallelGroup(Alignment.LEADING, false) 447 | .addComponent(comboBox_1, 0, GroupLayout.DEFAULT_SIZE, 448 | Short.MAX_VALUE) 449 | .addComponent(comboBox, 0, 69, Short.MAX_VALUE))) 450 | .addComponent(chckbxNewCheckBox))))) 451 | .addContainerGap(484, Short.MAX_VALUE))); 452 | gl_panel_2.setVerticalGroup(gl_panel_2.createParallelGroup(Alignment.LEADING).addGroup(gl_panel_2 453 | .createSequentialGroup().addContainerGap().addComponent(lblNewLabel).addGap(18) 454 | .addGroup(gl_panel_2.createParallelGroup(Alignment.BASELINE).addComponent(label_2).addComponent( 455 | comboBox, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)) 456 | .addPreferredGap(ComponentPlacement.RELATED) 457 | .addGroup(gl_panel_2.createParallelGroup(Alignment.BASELINE).addComponent(label_3).addComponent( 458 | comboBox_1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)) 459 | .addPreferredGap(ComponentPlacement.UNRELATED).addComponent(chckbxNewCheckBox).addGap(18) 460 | .addComponent(label_1).addGap(18).addComponent(chckbxNewCheckBox_1) 461 | .addPreferredGap(ComponentPlacement.UNRELATED) 462 | .addGroup(gl_panel_2.createParallelGroup(Alignment.BASELINE).addComponent(checkBox) 463 | .addComponent(checkBox_3)) 464 | .addPreferredGap(ComponentPlacement.RELATED) 465 | .addGroup(gl_panel_2.createParallelGroup(Alignment.BASELINE).addComponent(checkBox_1) 466 | .addComponent(checkBox_4)) 467 | .addPreferredGap(ComponentPlacement.RELATED) 468 | .addGroup(gl_panel_2.createParallelGroup(Alignment.BASELINE).addComponent(checkBox_2) 469 | .addComponent(checkBox_5)) 470 | .addPreferredGap(ComponentPlacement.RELATED).addComponent(checkBox_6) 471 | .addPreferredGap(ComponentPlacement.RELATED) 472 | .addGroup(gl_panel_2.createParallelGroup(Alignment.BASELINE).addComponent(checkBox_7) 473 | .addComponent(checkBox_8)) 474 | .addPreferredGap(ComponentPlacement.UNRELATED).addComponent(checkBox_9) 475 | .addPreferredGap(ComponentPlacement.RELATED).addComponent(checkBox_10) 476 | .addPreferredGap(ComponentPlacement.RELATED).addComponent(checkBox_11) 477 | .addPreferredGap(ComponentPlacement.RELATED).addComponent(checkBox_12) 478 | .addPreferredGap(ComponentPlacement.RELATED).addComponent(checkBox_13) 479 | .addPreferredGap(ComponentPlacement.RELATED).addComponent(checkBox_14) 480 | .addPreferredGap(ComponentPlacement.RELATED).addComponent(checkBox_15) 481 | .addPreferredGap(ComponentPlacement.RELATED).addComponent(checkBox_16) 482 | .addPreferredGap(ComponentPlacement.RELATED).addComponent(checkBox_17) 483 | .addPreferredGap(ComponentPlacement.RELATED).addComponent(checkBox_18) 484 | .addPreferredGap(ComponentPlacement.RELATED).addComponent(checkBox_19) 485 | .addPreferredGap(ComponentPlacement.RELATED).addComponent(checkBox_20) 486 | .addPreferredGap(ComponentPlacement.RELATED).addComponent(checkBox_21) 487 | .addPreferredGap(ComponentPlacement.RELATED).addComponent(checkBox_22) 488 | .addPreferredGap(ComponentPlacement.RELATED).addComponent(checkBox_23) 489 | .addPreferredGap(ComponentPlacement.RELATED).addComponent(checkBox_24) 490 | .addPreferredGap(ComponentPlacement.RELATED).addComponent(checkBox_25) 491 | .addPreferredGap(ComponentPlacement.RELATED).addComponent(checkBox_28) 492 | .addPreferredGap(ComponentPlacement.RELATED).addComponent(checkBox_26) 493 | .addPreferredGap(ComponentPlacement.RELATED).addComponent(checkBox_27).addGap(20))); 494 | panel_2.setLayout(gl_panel_2); 495 | 496 | // scan_profile_table.setRowSelectionAllowed(rowSelectionAllowed); 497 | scan_profile_table.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); 498 | 499 | // Load configuration from preferences or create a default 500 | if (callbacks.loadExtensionSetting("configuration_list") != null) { 501 | // Load configuration 502 | plugin_ref.load_configuration_from_preferences(); 503 | 504 | } else { 505 | // Create default configuration and save it 506 | Configuration row1 = new Configuration(true, "Default", plugin_ref.json_configuration); 507 | ConfigurationList.add(row1); 508 | plugin_ref.save_configuration_to_preferences(); 509 | } 510 | 511 | scan_profile_table.setRowSelectionInterval(0, 0); 512 | 513 | plugin_ref.update_ui_from_json(ConfigurationList.get(0).getConfiguration().toString()); 514 | 515 | // Update the UI based on selected item 516 | ListSelectionModel selectionModel = scan_profile_table.getSelectionModel(); 517 | selectionModel.addListSelectionListener(this); 518 | 519 | // Create automatically action listeners that save the 520 | // configuration on changes 521 | 522 | panel_2.setName("config_panel"); 523 | 524 | Component[] allComponents = panel_2.getComponents(); 525 | for (int i = 0; i < allComponents.length; i++) { 526 | if (allComponents[i].getName() == null) 527 | continue; 528 | 529 | if (allComponents[i] instanceof JCheckBox) { 530 | 531 | ((JCheckBox) allComponents[i]).addItemListener(this); 532 | 533 | } else if (allComponents[i] instanceof JComboBox) { 534 | 535 | ((JComboBox) allComponents[i]).addItemListener(this); 536 | } 537 | 538 | } 539 | 540 | // Enable or disable sub options (SQL injections) 541 | chckbxNewCheckBox_1.addItemListener(this); 542 | 543 | // Enable or disable sub options (OS Injections) 544 | checkBox_6.addItemListener(this); 545 | 546 | buttonDelete.addActionListener(this); 547 | buttonAdd.addActionListener(this); 548 | 549 | } 550 | 551 | public void update_scanner_table(String action, int first_row, int last_row) { 552 | 553 | switch (action) { 554 | 555 | case "insert": 556 | pluginModel.fireTableRowsInserted(first_row, last_row); 557 | break; 558 | case "modify": 559 | pluginModel.fireTableRowsUpdated(first_row, last_row); 560 | break; 561 | case "delete": 562 | pluginModel.fireTableRowsDeleted(first_row, last_row); 563 | break; 564 | default: 565 | stdout.println("ERROR: wrong action on update swing"); 566 | break; 567 | } 568 | } 569 | 570 | @Override 571 | public void actionPerformed(ActionEvent e) { 572 | 573 | if (e.getSource() instanceof JButton) { 574 | String srcText = ((JButton) e.getSource()).getText(); 575 | stdout.println(srcText); 576 | 577 | switch (((JButton) e.getSource()).getText()) { 578 | 579 | // Remove button listener 580 | case "Delete": 581 | final int cur_row = scan_profile_table.getSelectedRow(); 582 | 583 | // Don't allow to remove default scan configuration 584 | if (cur_row != 0) { 585 | 586 | ConfigurationList.remove(cur_row); 587 | 588 | javax.swing.SwingUtilities.invokeLater(new Runnable() { 589 | public void run() { 590 | 591 | scan_profile_table.setRowSelectionInterval(cur_row - 1, cur_row - 1); 592 | configurationModel.fireTableRowsDeleted(cur_row, cur_row); 593 | 594 | } 595 | }); 596 | 597 | plugin_ref.save_configuration_to_preferences(); 598 | } 599 | 600 | break; 601 | 602 | // Add button listener 603 | case "Add": 604 | Configuration row2 = new Configuration(true, "User defined " + scan_profile_table.getRowCount(), 605 | plugin_ref.json_configuration); 606 | ConfigurationList.add(row2); 607 | 608 | javax.swing.SwingUtilities.invokeLater(new Runnable() { 609 | public void run() { 610 | 611 | configurationModel.fireTableRowsInserted(ConfigurationList.size() - 1, 612 | ConfigurationList.size() - 1); 613 | 614 | scan_profile_table.setRowSelectionInterval(scan_profile_table.getRowCount() - 1, 615 | 616 | scan_profile_table.getRowCount() - 1); 617 | scan_profile_table.scrollRectToVisible( 618 | scan_profile_table.getCellRect(scan_profile_table.getRowCount() - 1, 0, true)); 619 | 620 | } 621 | 622 | }); 623 | 624 | plugin_ref.save_configuration_to_preferences(); 625 | break; 626 | 627 | case "Export conf.": 628 | exportToFile(); 629 | break; 630 | 631 | case "Import conf.": 632 | importFromFile(); 633 | break; 634 | 635 | case "Cancel all scans": 636 | 637 | for (int i = 0; i < queueList.size(); i++) { 638 | 639 | queueList.get(i).getBurpQueue().cancel(); 640 | } 641 | 642 | break; 643 | 644 | case "Remove completed": 645 | 646 | for (int i = 0; i < queueList.size(); i++) { 647 | if (queueList.get(i).getBurpQueue().getStatus().contains("finished") 648 | || queueList.get(i).getBurpQueue().getStatus().contains("cancelled")) { 649 | queueList.remove(i); 650 | 651 | } 652 | } 653 | 654 | break; 655 | 656 | } 657 | 658 | } 659 | 660 | } 661 | 662 | public void exportToFile() { 663 | JFrame parentFrame = new JFrame(); 664 | JFileChooser fileChooser = new JFileChooser(); 665 | fileChooser.setDialogTitle("Configuration output file"); 666 | 667 | int userSelection = fileChooser.showSaveDialog(parentFrame); 668 | 669 | if (userSelection == JFileChooser.APPROVE_OPTION) { 670 | 671 | File outputFile = fileChooser.getSelectedFile(); 672 | FileWriter fw; 673 | try { 674 | fw = new FileWriter(outputFile); 675 | 676 | JSONObject all_conf = new JSONObject(); 677 | 678 | for (int i = 0; i < ConfigurationList.size(); i++) { 679 | all_conf.put(Integer.toString(i), ConfigurationList.get(i).exportToJson()); 680 | } 681 | 682 | fw.write(all_conf.toString()); 683 | fw.close(); 684 | 685 | } catch (IOException e) { 686 | stderr.println("ERROR"); 687 | stderr.println(e.toString()); 688 | return; 689 | } 690 | 691 | } 692 | } 693 | 694 | public void importFromFile() { 695 | JFrame parentFrame = new JFrame(); 696 | JFileChooser fileChooser = new JFileChooser(); 697 | fileChooser.setDialogTitle("Configuration input file"); 698 | 699 | int userSelection = fileChooser.showOpenDialog(parentFrame); 700 | 701 | if (userSelection == JFileChooser.APPROVE_OPTION) { 702 | 703 | File inputFile = fileChooser.getSelectedFile(); 704 | 705 | try { 706 | 707 | File file = new File(inputFile.toString()); 708 | FileInputStream fis = new FileInputStream(file); 709 | byte[] data = new byte[(int) file.length()]; 710 | fis.read(data); 711 | fis.close(); 712 | 713 | JSONObject all_conf = new JSONObject(new String(data)); 714 | 715 | Iterator keys = all_conf.keys(); 716 | 717 | ConfigurationList.clear(); 718 | 719 | while (keys.hasNext()) { 720 | String key = (String) keys.next(); 721 | 722 | Configuration row1 = new Configuration(); 723 | row1.importFromJson(all_conf.getJSONObject(key).toString()); 724 | ConfigurationList.add(row1); 725 | 726 | } 727 | 728 | } catch (Exception e) { 729 | stderr.println("ERROR"); 730 | stderr.println(e.toString()); 731 | return; 732 | } 733 | 734 | } 735 | 736 | } 737 | 738 | @Override 739 | public void valueChanged(ListSelectionEvent arg0) { 740 | int cur_row = scan_profile_table.getSelectedRow(); 741 | plugin_ref.update_ui_from_json(ConfigurationList.get(cur_row).getConfiguration().toString()); 742 | } 743 | 744 | @Override 745 | public void itemStateChanged(ItemEvent e) { 746 | 747 | if (e.getSource() instanceof JCheckBox) { 748 | 749 | // Checkbox on config panel 750 | if (((JCheckBox) e.getSource()).getParent().getName() == "config_panel") { 751 | int cur_row = scan_profile_table.getSelectedRow(); 752 | 753 | ConfigurationList.get(cur_row).setConfiguration(plugin_ref.build_json_from_ui().toString()); 754 | plugin_ref.save_configuration_to_preferences(); 755 | 756 | } 757 | 758 | // XXX BUG: if in default configuration the SQL injection or command 759 | // execution family is deselected 760 | // the child are not blocked after a plugin reload 761 | 762 | // Automatic grey some choices 763 | if (((JCheckBox) e.getSource()).getName() == "sql_injection+enabled") { 764 | 765 | if (e.getStateChange() == ItemEvent.DESELECTED) { 766 | checkBox.setEnabled(false); 767 | checkBox_1.setEnabled(false); 768 | checkBox_2.setEnabled(false); 769 | checkBox_3.setEnabled(false); 770 | checkBox_4.setEnabled(false); 771 | checkBox_5.setEnabled(false); 772 | } else { 773 | checkBox.setEnabled(true); 774 | checkBox_1.setEnabled(true); 775 | checkBox_2.setEnabled(true); 776 | checkBox_3.setEnabled(true); 777 | checkBox_4.setEnabled(true); 778 | checkBox_5.setEnabled(true); 779 | 780 | } 781 | } else if (((JCheckBox) e.getSource()).getName() == "os_command_injection+enabled") { 782 | 783 | if (e.getStateChange() == ItemEvent.DESELECTED) { 784 | 785 | checkBox_7.setEnabled(false); 786 | checkBox_8.setEnabled(false); 787 | } else { 788 | checkBox_7.setEnabled(true); 789 | checkBox_8.setEnabled(true); 790 | 791 | } 792 | } 793 | 794 | } 795 | 796 | else if (e.getSource() instanceof JComboBox) { 797 | 798 | // ComboBox on config panel 799 | if (((JComboBox) e.getSource()).getParent().getName() == "config_panel") { 800 | 801 | // Save json on preferences when a ComboBox is changed 802 | 803 | int cur_row = scan_profile_table.getSelectedRow(); 804 | 805 | if (e.getStateChange() == ItemEvent.SELECTED) { 806 | ConfigurationList.get(cur_row).setConfiguration(plugin_ref.build_json_from_ui().toString()); 807 | plugin_ref.save_configuration_to_preferences(); 808 | 809 | } 810 | 811 | } 812 | 813 | } 814 | } 815 | } 816 | --------------------------------------------------------------------------------