├── .gitignore ├── LICENSE ├── README.md ├── doc ├── bypass-through-sleep-chunked.png ├── config.png └── menu.png ├── pom.xml └── src └── main ├── java └── burp │ ├── BurpExtender.java │ ├── ChunkedLogTable.java │ ├── Config.java │ ├── ConfigDlg.java │ ├── Menu.java │ ├── Transfer.java │ ├── sleepchunked │ ├── ChunkedInfoEntity.java │ ├── SleepChunkedDlg.java │ ├── SleepChunkedSender.java │ ├── SleepChunkedWorker.java │ ├── SleepSendConfig.java │ ├── SleepSendTableModel.java │ └── X509TrustManagerImpl.java │ └── utils │ ├── DateUtil.java │ ├── GBC.java │ └── Util.java └── test ├── StringTest.java ├── TransferTest.java └── burp └── sleepchunked └── SocketSleepClientTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | /target/ 26 | /.idea/ 27 | 28 | /*.iml 29 | .DS_Store -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 残亦 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Chunked coding converter 2 | 3 | 本插件主要用于分块传输绕WAF,不了解分块传输绕WAF的请阅读文末的文章。 4 | 5 | ## 插件编译 6 | 7 | ``` 8 | mvn package 9 | ``` 10 | 11 | ## 插件使用 12 | 13 | ![菜单](doc/menu.png) 14 | 15 | ![配置](doc/config.png) 16 | 17 | 延时分块传输 18 | 19 | ![延时分块传输](doc/bypass-through-sleep-chunked.png) 20 | 21 | ## 相关文章 22 | * [利用分块传输吊打所有WAF](https://www.anquanke.com/post/id/169738) 23 | * [在HTTP协议层面绕过WAF](https://www.freebuf.com/news/193659.html) 24 | * [编写Burp分块传输插件绕WAF](https://mp.weixin.qq.com/s?__biz=Mzg3NjA4MTQ1NQ==&mid=2247483787&idx=1&sn=54c33727696f8ee6d67f997acc11ab89&chksm=cf36f9cbf84170dd7da9b48b3365fb05d7ccec6bdeff480d0c38962f712e400a40b2b38dc467&token=360242838&lang=zh_CN#rd) 25 | * [Java反序列化数据绕WAF之延时分块传输](https://gv7.me/articles/2021/java-deserialized-data-bypasses-waf-through-sleep-chunked/) -------------------------------------------------------------------------------- /doc/bypass-through-sleep-chunked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/c0ny1/chunked-coding-converter/8a04777bb324048b6f75871544539f9aa058bcb5/doc/bypass-through-sleep-chunked.png -------------------------------------------------------------------------------- /doc/config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/c0ny1/chunked-coding-converter/8a04777bb324048b6f75871544539f9aa058bcb5/doc/config.png -------------------------------------------------------------------------------- /doc/menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/c0ny1/chunked-coding-converter/8a04777bb324048b6f75871544539f9aa058bcb5/doc/menu.png -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.burp 8 | chunked-coding-converter 9 | 1.0 10 | 11 | 12 | UTF-8 13 | UTF-8 14 | 15 | 16 | 17 | 18 | 19 | net.portswigger.burp.extender 20 | burp-extender-api 21 | 1.7.22 22 | 23 | 24 | 25 | 26 | junit 27 | junit 28 | 4.13.2 29 | test 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | org.apache.maven.plugins 38 | maven-assembly-plugin 39 | 40 | 41 | package 42 | 43 | single 44 | 45 | 46 | 47 | 48 | 49 | jar-with-dependencies 50 | 51 | 52 | 53 | 54 | org.apache.maven.plugins 55 | maven-compiler-plugin 56 | 57 | 6 58 | 6 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /src/main/java/burp/BurpExtender.java: -------------------------------------------------------------------------------- 1 | package burp; 2 | 3 | import java.io.PrintWriter; 4 | 5 | public class BurpExtender implements IBurpExtender,IHttpListener,IProxyListener { 6 | public static IBurpExtenderCallbacks callbacks; 7 | public static IExtensionHelpers helpers; 8 | private String extensionName = "Chunked coding converter"; 9 | private String version ="0.4.0"; 10 | public static PrintWriter stdout; 11 | public static PrintWriter stderr; 12 | 13 | @Override 14 | public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) { 15 | this.callbacks = callbacks; 16 | this.helpers = callbacks.getHelpers(); 17 | callbacks.setExtensionName(String.format("%s %s",extensionName,version)); 18 | callbacks.registerContextMenuFactory(new Menu()); 19 | callbacks.registerHttpListener(this); 20 | callbacks.registerProxyListener(this); 21 | stdout = new PrintWriter(callbacks.getStdout(),true); 22 | stderr = new PrintWriter(callbacks.getStderr(),true); 23 | stdout.println(getBanner()); 24 | } 25 | 26 | 27 | @Override 28 | public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse messageInfo) { 29 | // 处理除代理套件之外的套件流量 30 | if(messageIsRequest && isValidTool(toolFlag) && (toolFlag != IBurpExtenderCallbacks.TOOL_PROXY)){ 31 | IRequestInfo reqInfo = helpers.analyzeRequest(messageInfo.getRequest()); 32 | 33 | if(reqInfo.getMethod().equals("POST")){ 34 | try { 35 | byte[] request = Transfer.encoding(messageInfo, Config.getMin_chunked_len(),Config.getMax_chunked_len(),Config.isAddComment(),Config.getMin_comment_len(),Config.getMax_comment_len()); 36 | if (request != null) { 37 | messageInfo.setRequest(request); 38 | } 39 | } catch (Exception e) { 40 | e.printStackTrace(stderr); 41 | } 42 | } 43 | } 44 | } 45 | 46 | 47 | @Override 48 | public void processProxyMessage(final boolean messageIsRequest, final IInterceptedProxyMessage proxyMessage) { 49 | // 处理代理套件流量 50 | if(messageIsRequest && isValidTool(IBurpExtenderCallbacks.TOOL_PROXY)){ 51 | IHttpRequestResponse messageInfo = proxyMessage.getMessageInfo(); 52 | IRequestInfo reqInfo = helpers.analyzeRequest(messageInfo.getRequest()); 53 | 54 | if(reqInfo.getMethod().equals("POST")){ 55 | try { 56 | byte[] request = Transfer.encoding(messageInfo, Config.getMin_chunked_len(),Config.getMax_chunked_len(),Config.isAddComment(),Config.getMin_comment_len(),Config.getMax_comment_len()); 57 | if (request != null) { 58 | messageInfo.setRequest(request); 59 | } 60 | } catch (Exception e) { 61 | e.printStackTrace(stderr); 62 | } 63 | } 64 | } 65 | } 66 | 67 | /** 68 | * 插件是否作用于该套件 69 | * @param toolFlag 70 | * @return 71 | */ 72 | private boolean isValidTool(int toolFlag){ 73 | return (Config.isAct_on_all_tools() || 74 | (Config.isAct_on_proxy() && toolFlag== IBurpExtenderCallbacks.TOOL_PROXY) || 75 | (Config.isAct_on_intruder() && toolFlag== IBurpExtenderCallbacks.TOOL_INTRUDER) || 76 | (Config.isAct_on_repeater() && toolFlag== IBurpExtenderCallbacks.TOOL_REPEATER) || 77 | (Config.isAct_on_scanner() && toolFlag== IBurpExtenderCallbacks.TOOL_SCANNER) || 78 | (Config.isAct_on_sequencer() && toolFlag== IBurpExtenderCallbacks.TOOL_SEQUENCER) || 79 | (Config.isAct_on_spider() && toolFlag== IBurpExtenderCallbacks.TOOL_SPIDER) || 80 | (Config.isAct_on_extender() && toolFlag== IBurpExtenderCallbacks.TOOL_EXTENDER) || 81 | (Config.isAct_on_target() && toolFlag== IBurpExtenderCallbacks.TOOL_TARGET)); 82 | } 83 | 84 | 85 | /** 86 | * 插件Banner信息 87 | * @return 88 | */ 89 | public String getBanner(){ 90 | String bannerInfo = 91 | "[+]\n" 92 | + "[+] ##############################################\n" 93 | + "[+] " + extensionName + " v" + version +"\n" 94 | + "[+] anthor: c0ny1\n" 95 | + "[+] email: root@gv7.me\n" 96 | + "[+] contributor: phith0n\n" 97 | + "[+] github: http://github.com/c0ny1/chunked-coding-converter\n" 98 | + "[+] ##############################################"; 99 | return bannerInfo; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/burp/ChunkedLogTable.java: -------------------------------------------------------------------------------- 1 | package burp; 2 | 3 | import burp.sleepchunked.SleepSendTableModel; 4 | 5 | import javax.swing.*; 6 | 7 | public class ChunkedLogTable extends JTable { 8 | private SleepSendTableModel model; 9 | 10 | // 不能命名为getModel,否则表格无法显示 11 | public SleepSendTableModel getChunkedLogModel() { 12 | return model; 13 | } 14 | 15 | public ChunkedLogTable(SleepSendTableModel tableModel) { 16 | super(tableModel); 17 | this.model = tableModel; 18 | } 19 | } -------------------------------------------------------------------------------- /src/main/java/burp/Config.java: -------------------------------------------------------------------------------- 1 | package burp; 2 | 3 | /** 4 | * 配置对象类,负责对配置项进行设置与获取 5 | */ 6 | public class Config { 7 | private static Integer min_chunked_len = 1; 8 | private static Integer max_chunked_len = 3; 9 | private static boolean addComment = true; 10 | private static Integer min_comment_len = 5; 11 | private static Integer max_comment_len = 25; 12 | private static boolean act_on_all_tools = false; 13 | private static boolean act_on_target = false; 14 | private static boolean act_on_proxy = false; 15 | private static boolean act_on_spider = false; 16 | private static boolean act_on_intruder = false; 17 | private static boolean act_on_repeater = false; 18 | private static boolean act_on_scanner = false; 19 | private static boolean act_on_extender = false; 20 | private static boolean act_on_sequencer = false; 21 | 22 | public static Integer getMin_chunked_len() { 23 | String val = BurpExtender.callbacks.loadExtensionSetting("min_chunked_len"); 24 | try { 25 | return Integer.valueOf(val); 26 | }catch(Exception e){ 27 | return Config.min_chunked_len; 28 | } 29 | } 30 | 31 | public static void setMin_chunked_len(Integer min_chunked_len) { 32 | BurpExtender.callbacks.saveExtensionSetting("min_chunked_len", String.valueOf(min_chunked_len)); 33 | Config.min_chunked_len = min_chunked_len; 34 | } 35 | 36 | public static Integer getMax_chunked_len() { 37 | String val = BurpExtender.callbacks.loadExtensionSetting("max_chunked_len"); 38 | try { 39 | return Integer.valueOf(val); 40 | }catch(Exception e){ 41 | return Config.max_chunked_len; 42 | } 43 | } 44 | 45 | public static void setMax_chunked_len(Integer max_chunked_len) { 46 | BurpExtender.callbacks.saveExtensionSetting("max_chunked_len", String.valueOf(max_chunked_len)); 47 | Config.max_chunked_len = max_chunked_len; 48 | } 49 | 50 | public static boolean isAddComment() { 51 | String val = BurpExtender.callbacks.loadExtensionSetting("addComment"); 52 | if(val == null) return Config.addComment; 53 | try { 54 | return Boolean.valueOf(val); 55 | }catch(Exception e){ 56 | return Config.addComment; 57 | } 58 | } 59 | 60 | public static void setAddComment(boolean addComment) { 61 | BurpExtender.callbacks.saveExtensionSetting("addComment", String.valueOf(addComment)); 62 | Config.addComment = addComment; 63 | } 64 | 65 | public static Integer getMin_comment_len() { 66 | String val = BurpExtender.callbacks.loadExtensionSetting("min_comment_len"); 67 | try { 68 | return Integer.valueOf(val); 69 | }catch(Exception e){ 70 | return Config.min_comment_len; 71 | } 72 | } 73 | 74 | public static void setMin_comment_len(Integer min_comment_len) { 75 | BurpExtender.callbacks.saveExtensionSetting("min_comment_len", String.valueOf(min_comment_len)); 76 | Config.min_comment_len = min_comment_len; 77 | } 78 | 79 | public static Integer getMax_comment_len() { 80 | String val = BurpExtender.callbacks.loadExtensionSetting("max_comment_len"); 81 | try { 82 | return Integer.valueOf(val); 83 | }catch(Exception e){ 84 | return Config.max_comment_len; 85 | } 86 | } 87 | 88 | public static void setMax_comment_len(Integer max_comment_len) { 89 | BurpExtender.callbacks.saveExtensionSetting("max_comment_len", String.valueOf(max_comment_len)); 90 | Config.max_comment_len = max_comment_len; 91 | } 92 | 93 | public static boolean isAct_on_all_tools() { 94 | String val = BurpExtender.callbacks.loadExtensionSetting("act_on_all_tools"); 95 | if(val == null) return Config.act_on_all_tools; 96 | try { 97 | return Boolean.valueOf(val); 98 | }catch(Exception e){ 99 | return Config.act_on_all_tools; 100 | } 101 | } 102 | 103 | public static void setAct_on_all_tools(boolean act_on_all_tools) { 104 | BurpExtender.callbacks.saveExtensionSetting("act_on_all_tools", String.valueOf(act_on_all_tools)); 105 | Config.act_on_all_tools = act_on_all_tools; 106 | } 107 | 108 | public static boolean isAct_on_target() { 109 | String val = BurpExtender.callbacks.loadExtensionSetting("act_on_target"); 110 | if(val == null) return Config.act_on_target; 111 | try { 112 | return Boolean.valueOf(val); 113 | }catch(Exception e){ 114 | return Config.act_on_target; 115 | } 116 | } 117 | 118 | public static void setAct_on_target(boolean act_on_target) { 119 | BurpExtender.callbacks.saveExtensionSetting("act_on_target", String.valueOf(act_on_target)); 120 | Config.act_on_target = act_on_target; 121 | } 122 | 123 | public static boolean isAct_on_proxy() { 124 | String val = BurpExtender.callbacks.loadExtensionSetting("act_on_proxy"); 125 | if(val == null) return Config.act_on_proxy; 126 | try { 127 | return Boolean.valueOf(val); 128 | }catch(Exception e){ 129 | return Config.act_on_proxy; 130 | } 131 | } 132 | 133 | public static void setAct_on_proxy(boolean act_on_proxy) { 134 | BurpExtender.callbacks.saveExtensionSetting("act_on_proxy", String.valueOf(act_on_proxy)); 135 | Config.act_on_proxy = act_on_proxy; 136 | } 137 | 138 | public static boolean isAct_on_spider() { 139 | String val = BurpExtender.callbacks.loadExtensionSetting("act_on_spider"); 140 | if(val == null) return Config.act_on_spider; 141 | try { 142 | return Boolean.valueOf(val); 143 | }catch(Exception e){ 144 | return Config.act_on_spider; 145 | } 146 | } 147 | 148 | public static void setAct_on_spider(boolean act_on_spider) { 149 | BurpExtender.callbacks.saveExtensionSetting("act_on_spider", String.valueOf(act_on_spider)); 150 | Config.act_on_spider = act_on_spider; 151 | } 152 | 153 | public static boolean isAct_on_intruder() { 154 | String val = BurpExtender.callbacks.loadExtensionSetting("act_on_intruder"); 155 | if(val == null) return Config.act_on_intruder; 156 | try { 157 | return Boolean.valueOf(val); 158 | }catch(Exception e){ 159 | return Config.act_on_intruder; 160 | } 161 | } 162 | 163 | public static void setAct_on_intruder(boolean act_on_intruder) { 164 | BurpExtender.callbacks.saveExtensionSetting("act_on_intruder", String.valueOf(act_on_intruder)); 165 | Config.act_on_intruder = act_on_intruder; 166 | } 167 | 168 | public static boolean isAct_on_repeater() { 169 | String val = BurpExtender.callbacks.loadExtensionSetting("act_on_repeater"); 170 | if(val == null) return Config.act_on_repeater; 171 | try { 172 | return Boolean.valueOf(val); 173 | }catch(Exception e){ 174 | return Config.act_on_repeater; 175 | } 176 | } 177 | 178 | public static void setAct_on_repeater(boolean act_on_repeater) { 179 | BurpExtender.callbacks.saveExtensionSetting("act_on_repeater", String.valueOf(act_on_repeater)); 180 | Config.act_on_repeater = act_on_repeater; 181 | } 182 | 183 | public static boolean isAct_on_scanner() { 184 | String val = BurpExtender.callbacks.loadExtensionSetting("act_on_scanner"); 185 | if(val == null) return Config.act_on_scanner; 186 | try { 187 | return Boolean.valueOf(val); 188 | }catch(Exception e){ 189 | return Config.act_on_scanner; 190 | } 191 | } 192 | 193 | public static void setAct_on_scanner(boolean act_on_scanner) { 194 | BurpExtender.callbacks.saveExtensionSetting("act_on_scanner", String.valueOf(act_on_scanner)); 195 | Config.act_on_scanner = act_on_scanner; 196 | } 197 | 198 | public static boolean isAct_on_extender() { 199 | String val = BurpExtender.callbacks.loadExtensionSetting("act_on_extender"); 200 | if(val == null) return Config.act_on_extender; 201 | try { 202 | return Boolean.valueOf(val); 203 | }catch(Exception e){ 204 | return Config.act_on_extender; 205 | } 206 | } 207 | 208 | public static void setAct_on_extender(boolean act_on_extender) { 209 | BurpExtender.callbacks.saveExtensionSetting("act_on_extender", String.valueOf(act_on_extender)); 210 | Config.act_on_extender = act_on_extender; 211 | } 212 | 213 | public static boolean isAct_on_sequencer() { 214 | String val = BurpExtender.callbacks.loadExtensionSetting("act_on_sequencer"); 215 | if(val == null) return Config.act_on_sequencer; 216 | try { 217 | return Boolean.valueOf(val); 218 | }catch(Exception e){ 219 | return Config.act_on_sequencer; 220 | } 221 | } 222 | 223 | public static void setAct_on_sequencer(boolean act_on_sequencer) { 224 | BurpExtender.callbacks.saveExtensionSetting("act_on_sequencer", String.valueOf(act_on_sequencer)); 225 | Config.act_on_sequencer = act_on_sequencer; 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /src/main/java/burp/ConfigDlg.java: -------------------------------------------------------------------------------- 1 | package burp; 2 | 3 | import javax.swing.*; 4 | import java.awt.*; 5 | import java.awt.event.ActionEvent; 6 | import java.awt.event.ActionListener; 7 | 8 | /** 9 | * 配置窗口类,负责显示配置窗口,处理窗口消息 10 | */ 11 | public class ConfigDlg extends JDialog { 12 | private final JPanel mainPanel = new JPanel(); 13 | private final JPanel topPanel = new JPanel(); 14 | private final JPanel centerPanel = new JPanel(); 15 | private final JPanel bottomPanel = new JPanel();; 16 | private final JLabel lbChunkedLen = new JLabel("Length of chunked:"); 17 | private final JSpinner spMinChunkedLen = new JSpinner(new SpinnerNumberModel(1, 1, 100, 1)); 18 | private final JSpinner spMaxChunkedLen = new JSpinner(new SpinnerNumberModel(3, 1, 100, 1)); 19 | private final JCheckBox cbComment = new JCheckBox("Add comments"); 20 | private final JLabel lbCommentLen = new JLabel("Length of comment:"); 21 | private final JSpinner spMinCommentLen = new JSpinner(new SpinnerNumberModel(5, 1, 50, 1)); 22 | private final JLabel lbCommentLenRangeSymbols = new JLabel("-"); 23 | private final JSpinner spMaxCommentLen = new JSpinner(new SpinnerNumberModel(25, 1, 50, 1)); 24 | private final JLabel lbCommentLenRange = new JLabel("(1-50)"); 25 | private final JLabel lbActOnModel = new JLabel("Act on:"); 26 | private final JCheckBox chkAllTools = new JCheckBox("All Tools"); 27 | private final JCheckBox chkSpider = new JCheckBox("Spider"); 28 | private final JCheckBox chkIntruder = new JCheckBox("Intruder"); 29 | private final JCheckBox chkScanner = new JCheckBox("Scanner"); 30 | private final JCheckBox chkRepeater = new JCheckBox("Repeater"); 31 | private final JCheckBox chkSequencer = new JCheckBox("Sequencer"); 32 | private final JCheckBox chkProxy = new JCheckBox("Proxy"); 33 | private final JCheckBox chkExtender = new JCheckBox("Extender"); 34 | private final JCheckBox chkTarget = new JCheckBox("Target"); 35 | private final JButton btSave = new JButton("Save"); 36 | private final JButton btCancel = new JButton("Cancel"); 37 | 38 | 39 | public ConfigDlg(){ 40 | initGUI(); 41 | initEvent(); 42 | initValue(); 43 | this.setTitle("Chunked coding converter config"); 44 | } 45 | 46 | 47 | /** 48 | * 初始化UI 49 | */ 50 | private void initGUI(){ 51 | topPanel.setLayout(new FlowLayout(FlowLayout.LEFT)); 52 | topPanel.add(lbChunkedLen); 53 | topPanel.add(spMinChunkedLen); 54 | topPanel.add(new JLabel("-")); 55 | topPanel.add(spMaxChunkedLen); 56 | topPanel.add(new JLabel("(1-100)")); 57 | topPanel.add(Box.createHorizontalStrut(20)); 58 | topPanel.add(cbComment); 59 | cbComment.setSelected(true); 60 | topPanel.add(Box.createHorizontalStrut(5)); 61 | topPanel.add(lbCommentLen); 62 | topPanel.add(spMinCommentLen); 63 | topPanel.add(lbCommentLenRangeSymbols); 64 | topPanel.add(spMaxCommentLen); 65 | topPanel.add(lbCommentLenRange); 66 | 67 | centerPanel.setLayout(new FlowLayout(FlowLayout.LEFT)); 68 | centerPanel.add(lbActOnModel); 69 | centerPanel.add(chkAllTools); 70 | centerPanel.add(chkTarget); 71 | centerPanel.add(chkProxy); 72 | centerPanel.add(chkSpider); 73 | centerPanel.add(chkIntruder); 74 | centerPanel.add(chkRepeater); 75 | centerPanel.add(chkScanner); 76 | centerPanel.add(chkSequencer); 77 | centerPanel.add(chkExtender); 78 | 79 | bottomPanel.setLayout(new FlowLayout(FlowLayout.CENTER)); 80 | bottomPanel.add(btSave); 81 | bottomPanel.add(btCancel); 82 | 83 | mainPanel.setLayout(new BorderLayout()); 84 | mainPanel.add(topPanel,BorderLayout.NORTH); 85 | mainPanel.add(centerPanel,BorderLayout.CENTER); 86 | mainPanel.add(bottomPanel,BorderLayout.SOUTH); 87 | 88 | this.setModal(true); 89 | this.setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); 90 | this.add(mainPanel); 91 | //使配置窗口自动适应控件大小,防止部分控件无法显示 92 | this.pack(); 93 | //居中显示配置窗口 94 | Dimension screensize=Toolkit.getDefaultToolkit().getScreenSize(); 95 | this.setBounds(screensize.width/2-this.getWidth()/2,screensize.height/2-this.getHeight()/2,this.getWidth(),this.getHeight()); 96 | } 97 | 98 | 99 | /** 100 | * 初始化事件 101 | */ 102 | private void initEvent(){ 103 | chkAllTools.addActionListener(new ActionListener() { 104 | @Override 105 | public void actionPerformed(ActionEvent e) { 106 | if(chkAllTools.isSelected()){ 107 | chkTarget.setSelected(true); 108 | chkProxy.setSelected(true); 109 | chkSpider.setSelected(true); 110 | chkIntruder.setSelected(true); 111 | chkRepeater.setSelected(true); 112 | chkScanner.setSelected(true); 113 | chkExtender.setSelected(true); 114 | }else{ 115 | chkTarget.setSelected(false); 116 | chkProxy.setSelected(false); 117 | chkSpider.setSelected(false); 118 | chkIntruder.setSelected(false); 119 | chkRepeater.setSelected(false); 120 | chkScanner.setSelected(false); 121 | chkExtender.setSelected(false); 122 | } 123 | 124 | } 125 | }); 126 | 127 | cbComment.addActionListener(new ActionListener() { 128 | @Override 129 | public void actionPerformed(ActionEvent e) { 130 | if(cbComment.isSelected()){ 131 | lbCommentLen.setEnabled(true); 132 | spMinCommentLen.setEnabled(true); 133 | lbCommentLenRangeSymbols.setEnabled(true); 134 | spMaxCommentLen.setEnabled(true); 135 | lbCommentLenRange.setEnabled(true); 136 | }else{ 137 | lbCommentLen.setEnabled(false); 138 | spMinCommentLen.setEnabled(false); 139 | lbCommentLenRangeSymbols.setEnabled(false); 140 | spMaxCommentLen.setEnabled(false); 141 | lbCommentLenRange.setEnabled(false); 142 | } 143 | } 144 | }); 145 | 146 | btCancel.addActionListener(new ActionListener() { 147 | @Override 148 | public void actionPerformed(ActionEvent e) { 149 | ConfigDlg.this.dispose(); 150 | } 151 | }); 152 | 153 | btSave.addActionListener(new ActionListener() { 154 | @Override 155 | public void actionPerformed(ActionEvent e) { 156 | Integer min_chunked_len = (Integer)spMinChunkedLen.getValue(); 157 | Integer max_chunked_max = (Integer)spMaxChunkedLen.getValue(); 158 | Integer min_comment_len = (Integer)spMinCommentLen.getValue(); 159 | Integer max_comment_len = (Integer)spMaxCommentLen.getValue(); 160 | 161 | if(min_chunked_len > max_chunked_max){ 162 | JOptionPane.showConfirmDialog(ConfigDlg.this,"Please set minimum chunked length less than maximum!","Warning",JOptionPane.CLOSED_OPTION,JOptionPane.WARNING_MESSAGE); 163 | return; 164 | } 165 | 166 | if(min_comment_len > max_comment_len){ 167 | JOptionPane.showConfirmDialog(ConfigDlg.this,"Please set the minimum comment length to be less than the maximum!","Warning",JOptionPane.CLOSED_OPTION,JOptionPane.WARNING_MESSAGE); 168 | return; 169 | } 170 | 171 | Config.setMin_chunked_len(min_chunked_len); 172 | Config.setMax_chunked_len(max_chunked_max); 173 | Config.setAddComment(cbComment.isSelected()); 174 | Config.setMin_comment_len(min_comment_len); 175 | Config.setMax_comment_len(max_comment_len); 176 | Config.setAct_on_all_tools(chkAllTools.isSelected()); 177 | Config.setAct_on_target(chkTarget.isSelected()); 178 | Config.setAct_on_proxy(chkProxy.isSelected()); 179 | Config.setAct_on_spider(chkSpider.isSelected()); 180 | Config.setAct_on_intruder(chkIntruder.isSelected()); 181 | Config.setAct_on_repeater(chkRepeater.isSelected()); 182 | Config.setAct_on_scanner(chkScanner.isSelected()); 183 | Config.setAct_on_sequencer(chkSequencer.isSelected()); 184 | Config.setAct_on_extender(chkExtender.isSelected()); 185 | ConfigDlg.this.dispose(); 186 | } 187 | }); 188 | } 189 | 190 | 191 | /** 192 | * 为控件赋值 193 | */ 194 | public void initValue(){ 195 | spMinChunkedLen.setValue(Config.getMin_chunked_len()); 196 | spMaxChunkedLen.setValue(Config.getMax_chunked_len()); 197 | cbComment.setSelected(Config.isAddComment()); 198 | if(cbComment.isSelected()){ 199 | lbCommentLen.setEnabled(true); 200 | spMinCommentLen.setEnabled(true); 201 | lbCommentLenRangeSymbols.setEnabled(true); 202 | spMaxCommentLen.setEnabled(true); 203 | lbCommentLenRange.setEnabled(true); 204 | }else{ 205 | lbCommentLen.setEnabled(false); 206 | spMinCommentLen.setEnabled(false); 207 | lbCommentLenRangeSymbols.setEnabled(false); 208 | spMaxCommentLen.setEnabled(false); 209 | lbCommentLenRange.setEnabled(false); 210 | } 211 | spMinCommentLen.setValue(Config.getMin_comment_len()); 212 | spMaxCommentLen.setValue(Config.getMax_comment_len()); 213 | chkAllTools.setSelected(Config.isAct_on_all_tools()); 214 | chkTarget.setSelected(Config.isAct_on_target()); 215 | chkProxy.setSelected(Config.isAct_on_proxy()); 216 | chkSpider.setSelected(Config.isAct_on_spider()); 217 | chkIntruder.setSelected(Config.isAct_on_intruder()); 218 | chkRepeater.setSelected(Config.isAct_on_repeater()); 219 | chkScanner.setSelected(Config.isAct_on_scanner()); 220 | chkSequencer.setSelected(Config.isAct_on_sequencer()); 221 | chkExtender.setSelected(Config.isAct_on_extender()); 222 | } 223 | } -------------------------------------------------------------------------------- /src/main/java/burp/Menu.java: -------------------------------------------------------------------------------- 1 | package burp; 2 | 3 | import burp.sleepchunked.SleepChunkedDlg; 4 | 5 | import javax.swing.*; 6 | import java.awt.event.ActionEvent; 7 | import java.awt.event.ActionListener; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | /** 12 | * 菜单类,负责显示菜单,处理菜单事件 13 | */ 14 | public class Menu implements IContextMenuFactory { 15 | public List createMenuItems(final IContextMenuInvocation invocation) { 16 | List menus = new ArrayList(); 17 | JMenu chunkedMenu = new JMenu("Chunked coding converter"); 18 | JMenuItem encodeChunked = new JMenuItem("Encoding request body"); 19 | JMenuItem decodeChunked = new JMenuItem("Decoding request body"); 20 | JMenuItem config = new JMenuItem("Config"); 21 | JMenuItem sleepClient = new JMenuItem("Sleep chunked sender"); 22 | chunkedMenu.add(encodeChunked); 23 | chunkedMenu.add(decodeChunked); 24 | chunkedMenu.add(config); 25 | chunkedMenu.addSeparator(); 26 | chunkedMenu.add(sleepClient); 27 | 28 | //若数据包无法编辑,则将编码解码菜单项设置为禁用 29 | if(invocation.getInvocationContext() != IContextMenuInvocation.CONTEXT_MESSAGE_EDITOR_REQUEST){ 30 | encodeChunked.setEnabled(false); 31 | decodeChunked.setEnabled(false); 32 | } 33 | 34 | encodeChunked.addActionListener(new ActionListener(){ 35 | 36 | public void actionPerformed(ActionEvent arg0) { 37 | IHttpRequestResponse iReqResp = invocation.getSelectedMessages()[0]; 38 | IRequestInfo reqInfo = BurpExtender.helpers.analyzeRequest(iReqResp.getRequest()); 39 | // 不对GET请求进行编码 40 | if(!reqInfo.getMethod().equals("POST")){ 41 | JOptionPane.showConfirmDialog(null,"GET requests cannot be chunked encoded!","Warning",JOptionPane.CLOSED_OPTION,JOptionPane.WARNING_MESSAGE); 42 | return; 43 | } 44 | 45 | // 不重复编码 46 | if(Transfer.isChunked(iReqResp)){ 47 | JOptionPane.showConfirmDialog(null,"The request has been chunked encoded,Do not repeat the encoding!","Warning",JOptionPane.CLOSED_OPTION,JOptionPane.WARNING_MESSAGE); 48 | return; 49 | } 50 | 51 | try { 52 | byte[] request = Transfer.encoding(iReqResp, Config.getMin_chunked_len(),Config.getMax_chunked_len(),Config.isAddComment(),Config.getMin_comment_len(),Config.getMax_comment_len()); 53 | if (request != null) { 54 | iReqResp.setRequest(request); 55 | } 56 | } catch (Exception e) { 57 | BurpExtender.stderr.println(e.getMessage()); 58 | } 59 | } 60 | }); 61 | 62 | decodeChunked.addActionListener(new ActionListener(){ 63 | 64 | public void actionPerformed(ActionEvent arg0) { 65 | IHttpRequestResponse iReqResp = invocation.getSelectedMessages()[0]; 66 | 67 | // 进制对未编码请求解码 68 | if(!Transfer.isChunked(iReqResp)){ 69 | JOptionPane.showConfirmDialog(null,"The request is unencoded and cannot be decoded!","Warning",JOptionPane.CLOSED_OPTION,JOptionPane.WARNING_MESSAGE); 70 | return; 71 | } 72 | 73 | try { 74 | byte[] request = Transfer.decoding(iReqResp); 75 | if (request != null) { 76 | iReqResp.setRequest(request); 77 | } 78 | } catch (Exception e) { 79 | BurpExtender.stderr.println(e.getMessage()); 80 | } 81 | } 82 | }); 83 | 84 | config.addActionListener(new ActionListener(){ 85 | 86 | public void actionPerformed(ActionEvent arg0) { 87 | try { 88 | ConfigDlg dlg = new ConfigDlg(); 89 | BurpExtender.callbacks.customizeUiComponent(dlg); 90 | dlg.setVisible(true); 91 | }catch (Exception e){ 92 | e.printStackTrace(BurpExtender.stderr); 93 | } 94 | } 95 | }); 96 | 97 | 98 | sleepClient.addActionListener(new ActionListener() { 99 | public void actionPerformed(ActionEvent e) { 100 | try { 101 | IHttpRequestResponse iReqResp = invocation.getSelectedMessages()[0]; 102 | SleepChunkedDlg dlg = new SleepChunkedDlg(iReqResp); 103 | BurpExtender.callbacks.customizeUiComponent(dlg); 104 | dlg.setVisible(true); 105 | 106 | }catch (Exception ex){ 107 | ex.printStackTrace(BurpExtender.stderr); 108 | } 109 | } 110 | }); 111 | 112 | menus.add(chunkedMenu); 113 | return menus; 114 | } 115 | } -------------------------------------------------------------------------------- /src/main/java/burp/Transfer.java: -------------------------------------------------------------------------------- 1 | package burp; 2 | 3 | import burp.utils.Util; 4 | 5 | import java.io.UnsupportedEncodingException; 6 | import java.util.*; 7 | 8 | /** 9 | * 编码解码类,负责对目标请求进行编码解码 10 | */ 11 | public class Transfer { 12 | public static final byte http_0 = 48; 13 | public static final byte http_r = 13; // \r 14 | public static final byte http_n = 10; // \n 15 | /** 16 | * 对请求包进行chunked编码 17 | * @param requestResponse 要处理的请求响应对象 18 | * @param minChunkedLen 分块最短长度 19 | * @param maxChunkedLen 分块最长长度 20 | * @param isComment 是否添加注释 21 | * @param minCommentLen 注释最短长度 22 | * @param maxCommentLen 注释最长长度 23 | * @return 编码后的请求包 24 | * @throws UnsupportedEncodingException 25 | */ 26 | public static byte[] encoding(IHttpRequestResponse requestResponse,int minChunkedLen, int maxChunkedLen, boolean isComment,int minCommentLen,int maxCommentLen) throws UnsupportedEncodingException { 27 | byte[] request = requestResponse.getRequest(); 28 | List headers = BurpExtender.helpers.analyzeRequest(request).getHeaders(); 29 | Iterator iter = headers.iterator(); 30 | while (iter.hasNext()) { 31 | //不对请求包重复编码 32 | if (((String)iter.next()).contains("Transfer-Encoding")) { 33 | return request; 34 | } 35 | } 36 | //Add Transfer-Encoding header 37 | headers.add("Transfer-Encoding: chunked"); 38 | 39 | IRequestInfo requestInfo = BurpExtender.helpers.analyzeRequest(request); 40 | int bodyOffset = requestInfo.getBodyOffset(); 41 | int body_length = request.length - bodyOffset; 42 | byte[] byteBody = new byte[body_length]; 43 | System.arraycopy(request, bodyOffset, byteBody, 0, body_length); 44 | 45 | byte[] byte_encoding_body = splitReqBody(byteBody,minChunkedLen,maxChunkedLen,isComment,minCommentLen,maxCommentLen); 46 | return BurpExtender.helpers.buildHttpMessage(headers,byte_encoding_body); 47 | } 48 | 49 | 50 | public static byte[] joinByteArray(byte[] byte1, byte[] byte2) { 51 | byte[] bt3 = new byte[byte1.length+byte2.length]; 52 | System.arraycopy(byte1, 0, bt3, 0, byte1.length); 53 | System.arraycopy(byte2, 0, bt3, byte1.length, byte2.length); 54 | return bt3; 55 | } 56 | 57 | /** 58 | * 对编码过的请求包进行解码 59 | * @param requestResponse 已编码过的请求响应对象 60 | * @return 解码后的请求包 61 | * @throws UnsupportedEncodingException 62 | */ 63 | public static byte[] decoding(IHttpRequestResponse requestResponse) { 64 | byte[] request = requestResponse.getRequest(); 65 | 66 | // Delete Transfer-Encoding header 67 | List headers = BurpExtender.helpers.analyzeRequest(request).getHeaders(); 68 | Iterator iter = headers.iterator(); 69 | Boolean isChunked = false;//是否被分块编码过 70 | while (iter.hasNext()) { 71 | String reqHeader = iter.next().toLowerCase(); 72 | if (reqHeader.contains("transfer-encoding") && reqHeader.contains("chunked")) { 73 | iter.remove(); 74 | isChunked = true; 75 | } 76 | } 77 | //不对未编码过的请求包解码 78 | if(!isChunked){ 79 | return request; 80 | } 81 | 82 | IRequestInfo requestInfo = BurpExtender.helpers.analyzeRequest(request); 83 | int bodyOffset = requestInfo.getBodyOffset(); 84 | int body_length = request.length - bodyOffset; 85 | byte[] byteBody = new byte[body_length]; 86 | System.arraycopy(request, bodyOffset, byteBody, 0, body_length); 87 | byte[] mergeReqBody = mergeReqBody(byteBody); 88 | 89 | return BurpExtender.helpers.buildHttpMessage(headers,mergeReqBody); 90 | } 91 | 92 | 93 | /** 94 | * 将request body分块 95 | * @param reqBody 96 | * @param minChunkedLen 97 | * @param maxChunkedLen 98 | * @param isComment 99 | * @param minCommentLen 100 | * @param maxCommentLen 101 | * @return 102 | */ 103 | public static byte[] splitReqBody(byte[] reqBody,int minChunkedLen,int maxChunkedLen,boolean isComment,int minCommentLen,int maxCommentLen){ 104 | List bytes_list = Util.getByteRandomLenList(reqBody,minChunkedLen,maxChunkedLen); 105 | byte[] byte_encoding_body = new byte[0]; 106 | for(byte[] b:bytes_list){ 107 | // 当注释开启,同时不存在不可见字符时,才会添加注释 108 | if(isComment && !Util.isIncludeInviChar(reqBody)){ 109 | int commentLen = Util.getRandomNum(minCommentLen,maxCommentLen); 110 | String comment = String.format("%s;%s",Util.decimalToHex(b.length),Util.getRandomString(commentLen)); 111 | byte_encoding_body = joinByteArray(byte_encoding_body,comment.getBytes()); 112 | }else{ 113 | byte_encoding_body = joinByteArray(byte_encoding_body,Util.decimalToHex(b.length).getBytes()); 114 | } 115 | byte_encoding_body = joinByteArray(byte_encoding_body,"\r\n".getBytes()); 116 | byte_encoding_body = joinByteArray(byte_encoding_body,b); 117 | byte_encoding_body = joinByteArray(byte_encoding_body,"\r\n".getBytes()); 118 | } 119 | byte_encoding_body = joinByteArray(byte_encoding_body,"0\r\n\r\n".getBytes()); 120 | return byte_encoding_body; 121 | } 122 | 123 | 124 | /** 125 | * 将分块的req body合并 126 | * @param chunkedReqBody 127 | * @return 128 | */ 129 | public static byte[] mergeReqBody(byte[] chunkedReqBody){ 130 | byte[] mergeBody = new byte[0]; 131 | int j = 0; 132 | 133 | for(int i = 0;i < chunkedReqBody.length; i++){ 134 | if(i+1 <= chunkedReqBody.length 135 | && chunkedReqBody[i] == "\r".getBytes()[0] 136 | && chunkedReqBody[i+1] == "\n".getBytes()[0]){ 137 | 138 | // 获取分块长度 139 | int length = i - j; 140 | byte[] chunkedLen = new byte[length]; 141 | System.arraycopy(chunkedReqBody, j, chunkedLen, 0, length); 142 | j = i + 2; 143 | int cLen; 144 | String strChunkedLen = new String(chunkedLen); 145 | if(strChunkedLen.contains(";")){// 如果存在注释 146 | cLen = Util.hexToDecimal(strChunkedLen.substring(0,strChunkedLen.indexOf(";"))); 147 | }else{ 148 | cLen = Util.hexToDecimal(strChunkedLen); 149 | } 150 | 151 | // 根据分块长度获取分块内容 152 | byte[] chunked = new byte[cLen]; 153 | System.arraycopy(chunkedReqBody, j, chunked, 0, cLen); 154 | mergeBody = joinByteArray(mergeBody,chunked); 155 | j = j + cLen + 2; 156 | i = j; 157 | continue; 158 | } 159 | 160 | // 处理结尾0\n\n 161 | if(chunkedReqBody[i] == http_0 162 | && chunkedReqBody[i+1] == http_r 163 | && chunkedReqBody[i+2] == http_n 164 | && chunkedReqBody[i+2] == http_r 165 | && chunkedReqBody[i+3] == http_n){ 166 | break; 167 | } 168 | } 169 | return mergeBody; 170 | } 171 | 172 | 173 | 174 | /** 175 | * 通过数据包头部是否存在Transfer-Encoding头,来判断其是否被编码 176 | * @param requestResponse 177 | * @return 是否被编码 178 | */ 179 | public static boolean isChunked(IHttpRequestResponse requestResponse){ 180 | byte[] request = requestResponse.getRequest(); 181 | List headers = BurpExtender.helpers.analyzeRequest(request).getHeaders(); 182 | Iterator iter = headers.iterator(); 183 | while (iter.hasNext()) { 184 | String reqHeader = iter.next().toLowerCase(); 185 | if (reqHeader.contains("transfer-encoding") && reqHeader.contains("chunked")) { 186 | return true; 187 | } 188 | } 189 | return false; 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /src/main/java/burp/sleepchunked/ChunkedInfoEntity.java: -------------------------------------------------------------------------------- 1 | package burp.sleepchunked; 2 | 3 | public class ChunkedInfoEntity { 4 | private int id = -1; 5 | private byte[] chunkedContent = new byte[0]; 6 | private int chunkedLen = 0; 7 | private int sleepTime = 0; 8 | private String status = "unkown"; 9 | 10 | public int getId() { 11 | return id; 12 | } 13 | 14 | public void setId(int id) { 15 | this.id = id; 16 | } 17 | 18 | public byte[] getChunkedContent() { 19 | return chunkedContent; 20 | } 21 | 22 | public void setChunkedContent(byte[] chunkedContent) { 23 | this.chunkedContent = chunkedContent; 24 | } 25 | 26 | public int getChunkedLen() { 27 | return chunkedLen; 28 | } 29 | 30 | public void setChunkedLen(int chunkedLen) { 31 | this.chunkedLen = chunkedLen; 32 | } 33 | 34 | public int getSleepTime() { 35 | return sleepTime; 36 | } 37 | 38 | public void setSleepTime(int sleepTime) { 39 | this.sleepTime = sleepTime; 40 | } 41 | 42 | public String getStatus() { 43 | return status; 44 | } 45 | 46 | public void setStatus(String status) { 47 | this.status = status; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/burp/sleepchunked/SleepChunkedDlg.java: -------------------------------------------------------------------------------- 1 | package burp.sleepchunked; 2 | 3 | import burp.*; 4 | import burp.utils.DateUtil; 5 | import burp.utils.GBC; 6 | import burp.utils.Util; 7 | 8 | import java.awt.*; 9 | import java.awt.event.ActionEvent; 10 | import java.awt.event.ActionListener; 11 | import java.awt.event.WindowEvent; 12 | import java.awt.event.WindowListener; 13 | import javax.swing.*; 14 | import javax.swing.border.EmptyBorder; 15 | import javax.swing.event.ChangeEvent; 16 | import javax.swing.event.ChangeListener; 17 | 18 | public class SleepChunkedDlg extends JDialog { 19 | private final IHttpRequestResponse iReqResp; 20 | private JPanel contentPane; 21 | private JLabel lbHost; 22 | private final JSpinner spMinChunkedLen = new JSpinner(new SpinnerNumberModel(5, 1, 1000, 1)); 23 | private final JLabel lbCommentLenRangeSymbols = new JLabel("-"); 24 | private final JSpinner spMaxChunkedLen = new JSpinner(new SpinnerNumberModel(25, 1, 1000, 1)); 25 | private JLabel lbUsername; 26 | private final JSpinner spMinSleepTime = new JSpinner(new SpinnerNumberModel(0, 0, 50000, 1)); 27 | private final JLabel lbSleepTimeRangeSymbols = new JLabel("-"); 28 | private final JSpinner spMaxSleepTime = new JSpinner(new SpinnerNumberModel(1000, 0, 50000, 1)); 29 | private JCheckBox cbSocks5Proxy; 30 | private JTextField tfProxyHost; 31 | private JTextField tfProxyPort; 32 | private JButton btnSend; 33 | private JButton btnClear; 34 | private JSplitPane splitPane; 35 | public ChunkedLogTable logTable; 36 | public JLabel lbMinMaxTotalTime; 37 | public JLabel lbRequestCount; 38 | private JLabel lbChunkedLenMinMax; 39 | public JLabel lbTotalChunked; 40 | public JLabel lbTotalTime; 41 | 42 | public IMessageEditor requestViewer; 43 | public IMessageEditor responseViewer; 44 | 45 | private int minChunked; 46 | private int maxChunked; 47 | 48 | public double minTotalTime; 49 | private double maxTotalTime; 50 | private JProgressBar pgBar; 51 | 52 | 53 | 54 | private SleepChunkedWorker worker; 55 | 56 | 57 | public SleepChunkedDlg(final IHttpRequestResponse iReqResp) { 58 | this.iReqResp = iReqResp; 59 | this.setLayout(new GridBagLayout()); 60 | String title = String.format("sleep chunked sender (%s)", Util.getUrlFormIReqRsp(this.iReqResp)); 61 | this.setTitle(title); 62 | contentPane = new JPanel(); 63 | GBC gbclist = new GBC(0, 0).setFill(GBC.BOTH).setWeight(100, 100); 64 | this.add(contentPane,gbclist); 65 | contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); 66 | contentPane.setLayout(new BorderLayout(0, 0)); 67 | 68 | //////////////////////////////////////////////////////////////////// 69 | // topPanel start 70 | //////////////////////////////////////////////////////////////////// 71 | JPanel topPanel = new JPanel(); 72 | GridBagLayout gridBagLayout = new GridBagLayout(); 73 | gridBagLayout.columnWidths = new int[] { 0, 0 }; 74 | gridBagLayout.rowHeights = new int[] { 40, 32, 0, 0 }; 75 | gridBagLayout.columnWeights = new double[] { 1.0D, Double.MIN_VALUE }; 76 | gridBagLayout.rowWeights = new double[] { 0.0D, 0.0D, 1.0D, Double.MIN_VALUE }; 77 | topPanel.setLayout(gridBagLayout); 78 | 79 | JPanel ConfigPanel = new JPanel(); 80 | GridBagConstraints gbc_panel = new GridBagConstraints(); 81 | gbc_panel.insets = new Insets(5, 5, 5, 5); 82 | gbc_panel.fill = 2; 83 | gbc_panel.gridx = 0; 84 | gbc_panel.gridy = 0; 85 | topPanel.add(ConfigPanel, gbc_panel); 86 | 87 | GridBagLayout gbl_panel = new GridBagLayout(); 88 | gbl_panel.columnWidths = new int[] { 40, 100, 0, 39, 33, 25, 0, 0, 0 }; 89 | gbl_panel.rowHeights = new int[] { 0, 0 }; 90 | gbl_panel.columnWeights = new double[] { 0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D,0.0D, 0.0D, 0.0D, 0.0D, 1.0D, 0.0D,0.0D, Double.MIN_VALUE }; 91 | gbl_panel.rowWeights = new double[] { 0.0D, Double.MIN_VALUE }; 92 | ConfigPanel.setLayout(gbl_panel); 93 | 94 | lbHost = new JLabel("chunked length:"); 95 | GridBagConstraints gbc_lbHost = new GridBagConstraints(); 96 | gbc_lbHost.fill = 2; 97 | gbc_lbHost.insets = new Insets(0, 0, 0, 5); 98 | gbc_lbHost.gridx = 0; 99 | gbc_lbHost.gridy = 0; 100 | ConfigPanel.add(lbHost, gbc_lbHost); 101 | 102 | 103 | GridBagConstraints gbc_tfHost = new GridBagConstraints(); 104 | gbc_tfHost.fill = 2; 105 | gbc_tfHost.insets = new Insets(0, 0, 0, 5); 106 | gbc_tfHost.gridx = 1; 107 | gbc_tfHost.gridy = 0; 108 | ConfigPanel.add(spMinChunkedLen, gbc_tfHost); 109 | 110 | 111 | GridBagConstraints gbc_lbPort = new GridBagConstraints(); 112 | gbc_lbPort.fill = 2; 113 | gbc_lbPort.insets = new Insets(0, 0, 0, 5); 114 | gbc_lbPort.gridx = 2; 115 | gbc_lbPort.gridy = 0; 116 | ConfigPanel.add(lbCommentLenRangeSymbols, gbc_lbPort); 117 | 118 | 119 | GridBagConstraints gbc_tfPort = new GridBagConstraints(); 120 | gbc_tfPort.fill = 2; 121 | gbc_tfPort.insets = new Insets(0, 0, 0, 5); 122 | gbc_tfPort.gridx = 3; 123 | gbc_tfPort.gridy = 0; 124 | ConfigPanel.add(spMaxChunkedLen, gbc_tfPort); 125 | 126 | lbUsername = new JLabel("sleep time"); 127 | GridBagConstraints gbc_lbUsername = new GridBagConstraints(); 128 | gbc_lbUsername.fill = 2; 129 | gbc_lbUsername.insets = new Insets(0, 0, 0, 5); 130 | gbc_lbUsername.gridx = 4; 131 | gbc_lbUsername.gridy = 0; 132 | ConfigPanel.add(lbUsername, gbc_lbUsername); 133 | 134 | 135 | GridBagConstraints gbc_tfUsername = new GridBagConstraints(); 136 | gbc_tfUsername.fill = 2; 137 | gbc_tfUsername.insets = new Insets(0, 0, 0, 5); 138 | gbc_tfUsername.gridx = 5; 139 | gbc_tfUsername.gridy = 0; 140 | ConfigPanel.add(spMinSleepTime, gbc_tfUsername); 141 | 142 | 143 | GridBagConstraints gbc_lbPassword = new GridBagConstraints(); 144 | gbc_lbPassword.fill = 2; 145 | gbc_lbPassword.insets = new Insets(0, 0, 0, 5); 146 | gbc_lbPassword.gridx = 6; 147 | gbc_lbPassword.gridy = 0; 148 | ConfigPanel.add(lbSleepTimeRangeSymbols, gbc_lbPassword); 149 | 150 | 151 | GridBagConstraints gbc_tfPassword = new GridBagConstraints(); 152 | gbc_tfPassword.fill = 2; 153 | gbc_tfPassword.insets = new Insets(0, 0, 0, 5); 154 | gbc_tfPassword.gridx = 7; 155 | gbc_tfPassword.gridy = 0; 156 | ConfigPanel.add(spMaxSleepTime, gbc_tfPassword); 157 | 158 | GridBagConstraints gbc_lb1 = new GridBagConstraints(); 159 | gbc_lb1.anchor = 15; 160 | gbc_lb1.insets = new Insets(0, 0, 0, 5); 161 | gbc_lb1.gridx = 12; 162 | gbc_lb1.gridy = 0; 163 | ConfigPanel.add(new JLabel(""), gbc_lb1); 164 | 165 | btnSend = new JButton("Start"); 166 | btnSend.addActionListener(new ActionListener() { 167 | public void actionPerformed(ActionEvent e) { 168 | try { 169 | if(btnSend.getText().equals("Start")) { 170 | btnSend.setText("Stop"); 171 | SleepSendConfig sleepSendConfig = getSleepSendConfig(); 172 | worker = new SleepChunkedWorker(iReqResp, sleepSendConfig); 173 | worker.execute(); 174 | }else{ 175 | worker.cancel(true); 176 | btnSend.setText("Start"); 177 | } 178 | }catch (Throwable throwable){ 179 | btnSend.setText("Start"); 180 | throwable.printStackTrace(BurpExtender.stderr); 181 | } 182 | } 183 | }); 184 | 185 | GridBagConstraints gbc_btnConn = new GridBagConstraints(); 186 | gbc_btnConn.fill = 2; 187 | gbc_btnConn.insets = new Insets(0, 0, 0, 5); 188 | gbc_btnConn.gridx = 13; 189 | gbc_btnConn.gridy = 0; 190 | ConfigPanel.add(btnSend, gbc_btnConn); 191 | 192 | btnClear = new JButton("Clear"); 193 | btnClear.addActionListener(new AbstractAction() { 194 | @Override 195 | public void actionPerformed(ActionEvent e) { 196 | int n = JOptionPane.showConfirmDialog(null, "Are you sure you want to clear the data?", "Passvie Scan Client prompt", JOptionPane.YES_NO_OPTION); 197 | if(n == 0) { 198 | logTable.getChunkedLogModel().getChunkedInfos().clear(); 199 | logTable.getChunkedLogModel().fireTableDataChanged();//通知模型更新 200 | logTable.updateUI();//刷新表格 201 | responseViewer.setMessage("".getBytes(),false); 202 | } 203 | } 204 | }); 205 | GridBagConstraints gbc_btnClear = new GridBagConstraints(); 206 | gbc_btnClear.fill = 2; 207 | gbc_btnClear.insets = new Insets(0, 0, 0, 5); 208 | gbc_btnClear.gridx = 14; 209 | gbc_btnClear.gridy = 0; 210 | ConfigPanel.add(btnClear, gbc_btnClear); 211 | //////////////////////////////////////////////////////////////////// 212 | 213 | JPanel FilterPanel = new JPanel(); 214 | GridBagConstraints gbc_panel_1 = new GridBagConstraints(); 215 | gbc_panel_1.insets = new Insets(0, 5, 5, 5); 216 | gbc_panel_1.fill = 2; 217 | gbc_panel_1.gridx = 0; 218 | gbc_panel_1.gridy = 1; 219 | topPanel.add(FilterPanel, gbc_panel_1); 220 | GridBagLayout gbl_panel_1 = new GridBagLayout(); 221 | gbl_panel_1.columnWidths = new int[] { 40, 225, 0, 0, 0 }; 222 | gbl_panel_1.rowHeights = new int[] { 0, 0 }; 223 | gbl_panel_1.columnWeights = new double[] {0.0D, 0.0D, 0.0D, 0.0D,0.1D,0.0D, 0.0D, 0.0D,0.0D,0.0D,0.0D,0.0D,0.0D,Double.MIN_VALUE }; 224 | gbl_panel_1.rowWeights = new double[] { 0.0D, Double.MIN_VALUE }; 225 | FilterPanel.setLayout(gbl_panel_1); 226 | 227 | 228 | int second_row_gridx = 0; 229 | cbSocks5Proxy = new JCheckBox("socks5 proxy host:"); 230 | GridBagConstraints gbc_enable_socks5 = new GridBagConstraints(); 231 | gbc_enable_socks5.insets = new Insets(0, 0, 0, 5); 232 | //gbc_enable_socks5.anchor = 13; 233 | gbc_enable_socks5.fill = 2; 234 | gbc_enable_socks5.gridx = second_row_gridx; 235 | gbc_enable_socks5.gridy = 0; 236 | FilterPanel.add(cbSocks5Proxy, gbc_enable_socks5); 237 | second_row_gridx++; 238 | 239 | 240 | tfProxyHost = new JTextField(10); 241 | tfProxyHost.setText("127.0.0.1"); 242 | tfProxyHost.setEnabled(false); 243 | GridBagConstraints gbc_tfDomain = new GridBagConstraints(); 244 | gbc_tfDomain.insets = new Insets(0, 0, 0, 5); 245 | gbc_tfDomain.fill = 2; 246 | gbc_tfDomain.gridx = second_row_gridx; 247 | gbc_tfDomain.gridy = 0; 248 | FilterPanel.add(tfProxyHost, gbc_tfDomain); 249 | second_row_gridx++; 250 | 251 | 252 | JLabel lbExcludeSuffix = new JLabel("port:"); 253 | GridBagConstraints gbc_lbExcludeSuffix = new GridBagConstraints(); 254 | gbc_lbExcludeSuffix.insets = new Insets(0, 0, 0, 5); 255 | gbc_lbExcludeSuffix.fill = 2; 256 | gbc_lbExcludeSuffix.gridx = second_row_gridx; 257 | gbc_lbExcludeSuffix.gridy = 0; 258 | FilterPanel.add(lbExcludeSuffix, gbc_lbExcludeSuffix); 259 | second_row_gridx++; 260 | 261 | tfProxyPort = new JTextField(5); 262 | tfProxyPort.setText("1080"); 263 | tfProxyPort.setEnabled(false); 264 | GridBagConstraints gbc_tfExcludeSuffix = new GridBagConstraints(); 265 | gbc_tfExcludeSuffix.insets = new Insets(0, 0, 0, 5); 266 | gbc_tfExcludeSuffix.fill = 2; 267 | gbc_tfExcludeSuffix.gridx = second_row_gridx; 268 | gbc_tfExcludeSuffix.gridy = 0; 269 | FilterPanel.add(tfProxyPort, gbc_tfExcludeSuffix); 270 | second_row_gridx++; 271 | 272 | 273 | GridBagConstraints gbc_vb = new GridBagConstraints(); 274 | gbc_vb.insets = new Insets(0, 0, 0, 5); 275 | gbc_vb.fill = 2; 276 | gbc_vb.gridx = second_row_gridx; 277 | gbc_vb.gridy = 0; 278 | FilterPanel.add(Box.createVerticalBox(), gbc_vb); 279 | second_row_gridx++; 280 | 281 | JLabel lbRequest = new JLabel("body size:"); 282 | GridBagConstraints gbc_lbRequest = new GridBagConstraints(); 283 | gbc_lbRequest.insets = new Insets(0, 0, 0, 5); 284 | gbc_lbRequest.fill = 2; 285 | gbc_lbRequest.gridx = second_row_gridx; 286 | gbc_lbRequest.gridy = 0; 287 | FilterPanel.add(lbRequest, gbc_lbRequest); 288 | second_row_gridx++; 289 | 290 | 291 | int reqBodyLen = Util.getReqBodyLenFormIReqRsp(iReqResp); 292 | lbRequestCount = new JLabel(String.valueOf(reqBodyLen)); 293 | lbRequestCount.setForeground(new Color(0,0,255)); 294 | GridBagConstraints gbc_lbRequestCount = new GridBagConstraints(); 295 | gbc_lbRequestCount.insets = new Insets(0, 0, 0, 5); 296 | gbc_lbRequestCount.fill = 2; 297 | gbc_lbRequestCount.gridx = second_row_gridx; 298 | gbc_lbRequestCount.gridy = 0; 299 | FilterPanel.add(lbRequestCount, gbc_lbRequestCount); 300 | second_row_gridx++; 301 | 302 | GridBagConstraints gbc_vb2 = new GridBagConstraints(); 303 | gbc_vb2.insets = new Insets(0, 0, 0, 5); 304 | gbc_vb2.fill = 2; 305 | gbc_vb2.gridx = second_row_gridx; 306 | gbc_vb2.gridy = 0; 307 | FilterPanel.add(Box.createVerticalBox(), gbc_vb); 308 | second_row_gridx++; 309 | 310 | JLabel lbSucces = new JLabel("sented chunked:"); 311 | GridBagConstraints gbc_lbSucces = new GridBagConstraints(); 312 | gbc_lbSucces.insets = new Insets(0, 0, 0, 5); 313 | gbc_lbSucces.fill = 2; 314 | gbc_lbSucces.gridx = second_row_gridx; 315 | gbc_lbSucces.gridy = 0; 316 | FilterPanel.add(lbSucces, gbc_lbSucces); 317 | second_row_gridx++; 318 | 319 | 320 | lbTotalChunked = new JLabel("0"); 321 | lbTotalChunked.setForeground(new Color(0, 255, 0)); 322 | GridBagConstraints gbc_lbSuccesCount = new GridBagConstraints(); 323 | gbc_lbSuccesCount.insets = new Insets(0, 0, 0, 5); 324 | gbc_lbSuccesCount.fill = 2; 325 | gbc_lbSuccesCount.gridx = second_row_gridx; 326 | gbc_lbSuccesCount.gridy = 0; 327 | FilterPanel.add(lbTotalChunked, gbc_lbSuccesCount); 328 | second_row_gridx++; 329 | 330 | 331 | lbChunkedLenMinMax = new JLabel(); 332 | lbChunkedLenMinMax.setForeground(new Color(0, 255, 0)); 333 | GridBagConstraints gbc_chunkedlen_minmax = new GridBagConstraints(); 334 | gbc_chunkedlen_minmax.insets = new Insets(0, 0, 0, 5); 335 | gbc_chunkedlen_minmax.fill = 2; 336 | gbc_chunkedlen_minmax.gridx = second_row_gridx; 337 | gbc_chunkedlen_minmax.gridy = 0; 338 | FilterPanel.add(lbChunkedLenMinMax, gbc_chunkedlen_minmax); 339 | second_row_gridx++; 340 | 341 | GridBagConstraints gbc_vb3 = new GridBagConstraints(); 342 | gbc_vb3.insets = new Insets(0, 0, 0, 5); 343 | gbc_vb3.fill = 2; 344 | gbc_vb3.gridx = second_row_gridx; 345 | gbc_vb3.gridy = 0; 346 | FilterPanel.add(Box.createVerticalBox(), gbc_vb3); 347 | second_row_gridx++; 348 | 349 | lbTotalTime = new JLabel("send time:"); 350 | GridBagConstraints gbc_lbFail = new GridBagConstraints(); 351 | gbc_lbFail.insets = new Insets(0, 0, 0, 5); 352 | gbc_lbFail.fill = 2; 353 | gbc_lbFail.gridx = second_row_gridx; 354 | gbc_lbFail.gridy = 0; 355 | FilterPanel.add(lbTotalTime, gbc_lbFail); 356 | second_row_gridx++; 357 | 358 | lbTotalTime = new JLabel("0s"); 359 | lbTotalTime.setForeground(new Color(255, 0, 0)); 360 | GridBagConstraints gbc_lbFailCount = new GridBagConstraints(); 361 | gbc_lbFailCount.insets = new Insets(0, 0, 0, 5); 362 | gbc_lbFailCount.fill = 2; 363 | gbc_lbFailCount.gridx = second_row_gridx; 364 | gbc_lbFailCount.gridy = 0; 365 | FilterPanel.add(lbTotalTime, gbc_lbFailCount); 366 | second_row_gridx++; 367 | 368 | lbMinMaxTotalTime = new JLabel(); 369 | lbMinMaxTotalTime.setForeground(new Color(255, 0, 0)); 370 | GridBagConstraints gbc_minmax_totaltime = new GridBagConstraints(); 371 | gbc_minmax_totaltime.insets = new Insets(0, 0, 0, 5); 372 | gbc_minmax_totaltime.fill = 2; 373 | gbc_minmax_totaltime.gridx = second_row_gridx; 374 | gbc_minmax_totaltime.gridy = 0; 375 | FilterPanel.add(lbMinMaxTotalTime, gbc_minmax_totaltime); 376 | second_row_gridx++; 377 | 378 | contentPane.add(topPanel,BorderLayout.NORTH); 379 | //////////////////////////////////////////////////////////////////// 380 | // topPanl end 381 | //////////////////////////////////////////////////////////////////// 382 | 383 | splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT); 384 | contentPane.add(splitPane, BorderLayout.CENTER); 385 | 386 | SleepSendTableModel model = new SleepSendTableModel(); 387 | logTable = new ChunkedLogTable(model); 388 | logTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); 389 | 390 | 391 | JTabbedPane tabs = new JTabbedPane(); 392 | requestViewer = BurpExtender.callbacks.createMessageEditor(null, false); 393 | responseViewer = BurpExtender.callbacks.createMessageEditor(null, false); 394 | 395 | tabs.addTab("Request", requestViewer.getComponent()); 396 | tabs.addTab("Response", responseViewer.getComponent()); 397 | splitPane.setTopComponent(tabs); 398 | 399 | JScrollPane jspLogTable = new JScrollPane(logTable); 400 | splitPane.setBottomComponent(jspLogTable); 401 | 402 | 403 | pgBar = new JProgressBar(); 404 | pgBar.setMinimum(0); 405 | pgBar.setMaximum(reqBodyLen + 1); 406 | contentPane.add(pgBar,BorderLayout.SOUTH); 407 | 408 | BurpExtender.callbacks.customizeUiComponent(topPanel); 409 | BurpExtender.callbacks.customizeUiComponent(btnSend); 410 | BurpExtender.callbacks.customizeUiComponent(splitPane); 411 | BurpExtender.callbacks.customizeUiComponent(contentPane); 412 | 413 | //this.pack(); 414 | this.setSize(1150,800); 415 | Dimension screensize=Toolkit.getDefaultToolkit().getScreenSize(); 416 | this.setBounds(screensize.width/2-this.getWidth()/2,screensize.height/2-this.getHeight()/2,this.getWidth(),this.getHeight()); 417 | 418 | initAction(); 419 | SwingUtilities.invokeLater(new Runnable() { 420 | @Override 421 | public void run() { 422 | byte[] request = iReqResp.getRequest(); 423 | requestViewer.setMessage(request,true); 424 | splitPane.setDividerLocation(0.5); 425 | calcTotalChunked(); 426 | calcTotalTime(); 427 | 428 | Double[] columnWidths = {0.05d,0.5d,0.1d,0.1d,0.25d}; 429 | Util.resizeTableColumnWidth(logTable,columnWidths); 430 | } 431 | }); 432 | } 433 | 434 | public SleepChunkedWorker getWorker() { 435 | return worker; 436 | } 437 | 438 | public class ChangeListenerImpl implements ChangeListener{ 439 | @Override 440 | public void stateChanged(ChangeEvent e) { 441 | int minChunkedLen = (Integer)spMinChunkedLen.getValue(); 442 | int maxChunkedLen = (Integer)spMaxChunkedLen.getValue(); 443 | 444 | if(minChunkedLen > maxChunkedLen){ 445 | spMinChunkedLen.setValue(maxChunkedLen); 446 | } 447 | 448 | 449 | int minSleepTime = (Integer)spMinSleepTime.getValue(); 450 | int maxSleepTime = (Integer)spMaxSleepTime.getValue(); 451 | if(minSleepTime > maxSleepTime){ 452 | spMinSleepTime.setValue(maxSleepTime); 453 | } 454 | 455 | 456 | calcTotalChunked(); 457 | calcTotalTime(); 458 | } 459 | } 460 | 461 | 462 | private void initAction(){ 463 | this.addWindowListener(new CloseDialogActionListener(this)); 464 | ChangeListenerImpl changeListener = new ChangeListenerImpl(); 465 | spMinChunkedLen.addChangeListener(changeListener); 466 | spMaxChunkedLen.addChangeListener(changeListener); 467 | spMinSleepTime.addChangeListener(changeListener); 468 | spMaxSleepTime.addChangeListener(changeListener); 469 | cbSocks5Proxy.addActionListener(new ActionListener() { 470 | @Override 471 | public void actionPerformed(ActionEvent e) { 472 | if(cbSocks5Proxy.isSelected()){ 473 | tfProxyHost.setEnabled(true); 474 | tfProxyPort.setEnabled(true); 475 | }else{ 476 | tfProxyHost.setEnabled(false); 477 | tfProxyPort.setEnabled(false); 478 | } 479 | } 480 | }); 481 | 482 | } 483 | 484 | 485 | private SleepSendConfig getSleepSendConfig(){ 486 | SleepSendConfig config = new SleepSendConfig(); 487 | 488 | int minChunkedLen = (Integer)spMinChunkedLen.getValue(); 489 | int maxChunkedLen = (Integer)spMaxChunkedLen.getValue(); 490 | int minSleepTime = (Integer)spMinSleepTime.getValue(); 491 | int maxSleepTime = (Integer)spMaxSleepTime.getValue(); 492 | 493 | config.setMinChunkedLen(minChunkedLen); 494 | config.setMaxChunkedLen(maxChunkedLen); 495 | config.setMinSleepTime(minSleepTime); 496 | config.setMaxSleepTime(maxSleepTime); 497 | config.setLbTotalChunked(lbTotalChunked); 498 | config.setLbTotalTime(lbTotalTime); 499 | config.setChunkedLogTable(logTable); 500 | config.setResponseViewer(responseViewer); 501 | config.setPgBar(pgBar); 502 | config.setBtnSend(btnSend); 503 | 504 | config.setEnableSocks5Proxy(cbSocks5Proxy.isSelected()); 505 | config.setProxyHost(tfProxyHost.getText()); 506 | 507 | int proxyPort = 0; 508 | 509 | try { 510 | proxyPort = Integer.valueOf(tfProxyPort.getText()); 511 | if(proxyPort<0 || proxyPort > 65535){ 512 | JOptionPane.showMessageDialog(this,"chunked coding converter","port must be 0~65536",JOptionPane.ERROR); 513 | return null; 514 | } 515 | }catch (Exception e){ 516 | JOptionPane.showMessageDialog(this,"chunked coding converter",e.getMessage(),JOptionPane.ERROR); 517 | return null; 518 | } 519 | 520 | config.setProxyPort(proxyPort); 521 | return config; 522 | } 523 | 524 | 525 | 526 | 527 | private void calcTotalChunked(){ 528 | double reqBodyLen = Util.getReqBodyLenFormIReqRsp(iReqResp) * 1.0; 529 | minChunked = getInt(reqBodyLen/ ((Integer) spMaxChunkedLen.getValue())); 530 | if(minChunked == 0){ 531 | minChunked = 1; 532 | } 533 | maxChunked = getInt(reqBodyLen / ((Integer) spMinChunkedLen.getValue())); 534 | String chunkedLenMinMax = String.format("(%d ~ %d)",minChunked,maxChunked); 535 | lbChunkedLenMinMax.setText(chunkedLenMinMax); 536 | } 537 | 538 | private void calcTotalTime(){ 539 | int minSleepTime = (Integer)spMinSleepTime.getValue(); 540 | if(minSleepTime == 0){ 541 | minSleepTime = 1; 542 | } 543 | minTotalTime = (minChunked + 1) * minSleepTime; 544 | maxTotalTime = (maxChunked + 1) * (Integer)spMaxSleepTime.getValue(); 545 | String minMaxTotalTime = String.format("(%s ~ %s)", DateUtil.ms2str(minTotalTime),DateUtil.ms2str(maxTotalTime)); 546 | lbMinMaxTotalTime.setText(minMaxTotalTime); 547 | } 548 | 549 | public JLabel getLbTotalChunked(){ 550 | return lbTotalChunked; 551 | } 552 | 553 | 554 | public static int getInt(double number){ 555 | int newNumber = (int)number; 556 | if(number > newNumber){ 557 | return newNumber + 1; 558 | }else{ 559 | return newNumber; 560 | } 561 | } 562 | 563 | private class CloseDialogActionListener implements WindowListener{ 564 | SleepChunkedDlg sleepSendDlg; 565 | public CloseDialogActionListener(SleepChunkedDlg sleepSendDlg){ 566 | this.sleepSendDlg = sleepSendDlg; 567 | } 568 | 569 | @Override 570 | public void windowOpened(WindowEvent e) { 571 | 572 | } 573 | 574 | @Override 575 | public void windowClosing(WindowEvent e) { 576 | int n = JOptionPane.showConfirmDialog(sleepSendDlg, "Are you sure you want to close the current window?", "sleep send client prompt", JOptionPane.YES_NO_OPTION); 577 | if(n == JOptionPane.OK_OPTION) { 578 | if(sleepSendDlg.getWorker() != null){ 579 | sleepSendDlg.getWorker().cancel(true); 580 | } 581 | }else{ 582 | sleepSendDlg.setVisible(true); 583 | } 584 | } 585 | 586 | @Override 587 | public void windowClosed(WindowEvent e) { 588 | 589 | } 590 | 591 | @Override 592 | public void windowIconified(WindowEvent e) { 593 | 594 | } 595 | 596 | @Override 597 | public void windowDeiconified(WindowEvent e) { 598 | 599 | } 600 | 601 | @Override 602 | public void windowActivated(WindowEvent e) { 603 | 604 | } 605 | 606 | @Override 607 | public void windowDeactivated(WindowEvent e) { 608 | 609 | } 610 | } 611 | } -------------------------------------------------------------------------------- /src/main/java/burp/sleepchunked/SleepChunkedSender.java: -------------------------------------------------------------------------------- 1 | package burp.sleepchunked; 2 | 3 | import burp.BurpExtender; 4 | import burp.Transfer; 5 | import burp.utils.DateUtil; 6 | import burp.utils.Util; 7 | 8 | import javax.net.ssl.*; 9 | import javax.swing.*; 10 | import java.io.*; 11 | import java.net.*; 12 | import java.util.HashMap; 13 | import java.util.LinkedHashMap; 14 | import java.util.List; 15 | import java.util.Map; 16 | import java.util.concurrent.ExecutorService; 17 | import java.util.concurrent.Executors; 18 | 19 | // https://www.iteye.com/problems/42407 20 | public class SleepChunkedSender { 21 | private SleepSendConfig sleepSendConfig; 22 | private ExecutorService executorService = Executors.newSingleThreadExecutor(); 23 | private String url; 24 | private String host; 25 | private int port; 26 | private boolean isSSL; 27 | private LinkedHashMap headers = new LinkedHashMap(); 28 | private byte[] reqBody; 29 | private int totalLen; // 要分块内容的总长度 30 | private int sentedLen; // 已经发送数据的长度 31 | 32 | public SleepChunkedSender(String url, LinkedHashMap headers, byte[] reqBody, SleepSendConfig config) throws MalformedURLException { 33 | this.url = url; 34 | if(url.startsWith("https://")){ 35 | isSSL = true; 36 | }else{ 37 | isSSL = false; 38 | } 39 | URL u = new URL(this.url); 40 | this.host = u.getHost(); 41 | 42 | if(u.getPort() != -1){ 43 | this.port = u.getPort(); 44 | }else if(isSSL){ 45 | this.port = 443; 46 | }else{ 47 | this.port = 80; 48 | } 49 | 50 | this.headers = headers; 51 | this.headers.put("Transfer-Encoding","chunked"); 52 | this.headers.remove("Content-Length"); 53 | //this.headers.remove("Connection"); 54 | //this.headers.put("Connection","keep-alive"); 55 | //this.headers.put("Connection","close"); 56 | this.reqBody = reqBody; 57 | this.totalLen = reqBody.length; 58 | this.sleepSendConfig = config; 59 | } 60 | 61 | 62 | public byte[] send() throws Exception{ 63 | this.sentedLen = 0; 64 | JProgressBar pgBar = sleepSendConfig.getPgBar(); 65 | pgBar.setValue(sentedLen); 66 | // connect 67 | Socket socket = null; 68 | if(sleepSendConfig.isEnableSocks5Proxy()){ 69 | SocketAddress addr = new InetSocketAddress(sleepSendConfig.getProxyHost(), sleepSendConfig.getProxyPort()); 70 | Proxy proxy = new Proxy(Proxy.Type.SOCKS, addr); 71 | socket = new Socket(proxy); 72 | }else{ 73 | socket = new Socket(); 74 | } 75 | 76 | InetSocketAddress address = new InetSocketAddress(host, port); 77 | try { 78 | if (isSSL) { 79 | X509TrustManagerImpl x509m = new X509TrustManagerImpl(); 80 | // 获取一个SSLContext实例 81 | SSLContext sslContext = SSLContext.getInstance("SSL"); 82 | // 初始化SSLContext实例 83 | sslContext.init(null, new TrustManager[]{x509m}, new java.security.SecureRandom()); 84 | socket.connect(address); 85 | socket = sslContext.getSocketFactory().createSocket(socket, address.getHostName(), address.getPort(), true); 86 | } else { 87 | socket.connect(address); 88 | } 89 | }catch (Throwable e){ 90 | String msg = Util.getThrowableInfo(e); 91 | ChunkedInfoEntity chunkedInfoEntity = new ChunkedInfoEntity(); 92 | chunkedInfoEntity.setId(-1); 93 | chunkedInfoEntity.setChunkedContent("-".getBytes()); 94 | chunkedInfoEntity.setChunkedLen(0); 95 | chunkedInfoEntity.setSleepTime(0); 96 | chunkedInfoEntity.setStatus("Connect error: " + msg); 97 | printLog(chunkedInfoEntity); 98 | return msg.getBytes(); 99 | } 100 | 101 | 102 | OutputStream osw = socket.getOutputStream(); 103 | // send request header 104 | try { 105 | osw.write(String.format("%s\r\n", headers.get("top")).getBytes()); 106 | for (Map.Entry header : headers.entrySet()) { 107 | if (header.getKey().contains("top")) { 108 | continue; 109 | } 110 | osw.write(String.format("%s: %s\r\n", header.getKey(), header.getValue()).getBytes()); 111 | } 112 | osw.write("\r\n".getBytes()); 113 | osw.flush(); 114 | }catch (Throwable e){ 115 | String msg = Util.getThrowableInfo(e); 116 | ChunkedInfoEntity chunkedInfoEntity = new ChunkedInfoEntity(); 117 | chunkedInfoEntity.setId(0); 118 | chunkedInfoEntity.setChunkedContent("-".getBytes()); 119 | chunkedInfoEntity.setChunkedLen(0); 120 | chunkedInfoEntity.setSleepTime(0); 121 | chunkedInfoEntity.setStatus("send request header error: " + msg); 122 | printLog(chunkedInfoEntity); 123 | return msg.getBytes(); 124 | } 125 | 126 | // send request body 127 | ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(reqBody); 128 | byte[] buffer = new byte[calcRandomChunkedLen()]; 129 | int id = 1; 130 | boolean isError = false; 131 | String errorMsg = ""; 132 | final String startTime = DateUtil.getNowTime(); 133 | while (byteArrayInputStream.read(buffer) != -1){ 134 | final ChunkedInfoEntity chunkeInfoEntity = new ChunkedInfoEntity(); 135 | chunkeInfoEntity.setId(id); 136 | try { 137 | // 发送分块长度 138 | final String chunkedLen = Util.decimalToHex(buffer.length) + "\r\n"; 139 | chunkeInfoEntity.setChunkedLen(buffer.length); 140 | osw.write(chunkedLen.getBytes()); 141 | osw.flush(); 142 | 143 | // 发送分块内容 144 | byte[] chunked = Transfer.joinByteArray(buffer, "\r\n".getBytes()); 145 | //BurpExtender.stdout.println(new String(chunked)); 146 | chunkeInfoEntity.setChunkedContent(buffer); 147 | osw.write(chunked); 148 | osw.flush(); 149 | chunkeInfoEntity.setStatus("ok"); 150 | this.sentedLen += buffer.length; 151 | pgBar.setValue(this.sentedLen); 152 | // 延时 153 | int sleeptime = Util.getRandom(sleepSendConfig.getMinSleepTime(), sleepSendConfig.getMaxSleepTime()); 154 | chunkeInfoEntity.setSleepTime(sleeptime); 155 | Thread.sleep(sleeptime); 156 | }catch (Throwable throwable){ 157 | chunkeInfoEntity.setStatus("fail " + throwable.getMessage()); 158 | isError = true; 159 | errorMsg = Util.getThrowableInfo(throwable); 160 | } 161 | 162 | printLog(chunkeInfoEntity); 163 | 164 | double time = DateUtil.betweenMs(startTime, DateUtil.getNowTime()); 165 | sleepSendConfig.getLbTotalTime().setText(DateUtil.ms2str(time)); 166 | 167 | buffer = new byte[calcRandomChunkedLen()]; 168 | sleepSendConfig.getLbTotalChunked().setText(String.valueOf(id)); 169 | id ++; 170 | 171 | if(isError){ 172 | break; 173 | } 174 | } 175 | 176 | if(!isError) { 177 | osw.write("0\r\n\r\n".getBytes()); 178 | osw.flush(); 179 | pgBar.setValue(totalLen); 180 | sleepSendConfig.getResponseViewer().setMessage("Reading Response, please wait...".getBytes(),false); 181 | byte[] result = readFullHttpResponse(socket.getInputStream()); 182 | pgBar.setValue(totalLen + 1); 183 | if(result.length == 0){ 184 | return "read response is null".getBytes(); 185 | }else{ 186 | return result; 187 | } 188 | }else{ 189 | return errorMsg.getBytes(); 190 | } 191 | } 192 | 193 | 194 | public int calcRandomChunkedLen() throws Exception { 195 | int randomLen = Util.getRandom(sleepSendConfig.getMinChunkedLen(),sleepSendConfig.getMaxChunkedLen()); 196 | if(this.sentedLen + randomLen > this.totalLen){ 197 | randomLen = this.totalLen - this.sentedLen; 198 | } 199 | return randomLen; 200 | } 201 | 202 | 203 | public void printLog(final ChunkedInfoEntity chunkeInfoEntity){ 204 | executorService.submit(new Runnable() { 205 | @Override 206 | public void run() { 207 | try { 208 | List chunkedInfos = sleepSendConfig.getChunkedLogTable().getChunkedLogModel().getChunkedInfos(); 209 | synchronized (chunkedInfos) { 210 | int row = chunkedInfos.size(); 211 | chunkedInfos.add(chunkeInfoEntity); 212 | sleepSendConfig.getChunkedLogTable().getChunkedLogModel().fireTableRowsInserted(row, row); 213 | } 214 | }catch (Throwable throwable){ 215 | throwable.printStackTrace(BurpExtender.stderr); 216 | } 217 | } 218 | }); 219 | } 220 | 221 | 222 | public static byte[] readFullHttpResponse(InputStream inputStream) throws IOException, InterruptedException { 223 | ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 224 | byte[] buffer = new byte[1]; 225 | boolean isChunked = false; //是否是分块回传 226 | int contentLength = 0; 227 | int acceptedLength = 0; 228 | boolean proccessedHeader = false; //是否处理过header 229 | 230 | while (true){ 231 | int flag = inputStream.read(buffer); 232 | outputStream.write(buffer); 233 | byte[] readedContent = outputStream.toByteArray(); 234 | if(!proccessedHeader && Util.bytesEndWith(readedContent,"\r\n\r\n".getBytes())){ 235 | Map headers = new HashMap(); 236 | String responseHeader = new String(readedContent); 237 | for(String header:responseHeader.split("\r\n")){ 238 | if(header.contains(":")){ 239 | String reqHeaderKey = header.substring(0,header.indexOf(":")).trim(); 240 | String reqHeaderValue = header.substring(header.indexOf(":")+1,header.length()).trim(); 241 | headers.put(reqHeaderKey,reqHeaderValue); 242 | } 243 | } 244 | 245 | if(headers.containsKey("Content-Length")){ 246 | contentLength = Integer.valueOf((String)headers.get("Content-Length")); 247 | }else if(headers.containsKey("Transfer-Encoding") && headers.get("Transfer-Encoding").equals("chunked")){ 248 | isChunked = true; 249 | } 250 | proccessedHeader = true; 251 | } 252 | 253 | if(isChunked){ 254 | if(Util.bytesEndWith(readedContent,"\r\n0\r\n\r\n".getBytes())) { 255 | break; 256 | } 257 | }else if(contentLength != 0){ 258 | if(acceptedLength == contentLength){ 259 | break; 260 | } 261 | acceptedLength ++; 262 | }else if(flag == -1){ 263 | break; 264 | } 265 | } 266 | return outputStream.toByteArray(); 267 | } 268 | } 269 | -------------------------------------------------------------------------------- /src/main/java/burp/sleepchunked/SleepChunkedWorker.java: -------------------------------------------------------------------------------- 1 | package burp.sleepchunked; 2 | 3 | import burp.*; 4 | 5 | import javax.swing.*; 6 | import java.util.Iterator; 7 | import java.util.LinkedHashMap; 8 | import java.util.List; 9 | 10 | public class SleepChunkedWorker extends SwingWorker { 11 | private IHttpRequestResponse iReqResp; 12 | private SleepSendConfig sleepSendConfig; 13 | 14 | public SleepChunkedWorker(IHttpRequestResponse iReqResp, SleepSendConfig config){ 15 | this.iReqResp = iReqResp; 16 | this.sleepSendConfig = config; 17 | } 18 | 19 | protected Object doInBackground() throws Exception { 20 | this.sleepSendConfig.getChunkedLogTable().getChunkedLogModel().getChunkedInfos().clear(); 21 | sleepSendConfig.getChunkedLogTable().getChunkedLogModel().fireTableDataChanged();//通知模型更新 22 | sleepSendConfig.getChunkedLogTable().updateUI();//刷新表格 23 | sleepSendConfig.getResponseViewer().setMessage("".getBytes(),true); 24 | 25 | byte[] request = iReqResp.getRequest(); 26 | List headers = BurpExtender.helpers.analyzeRequest(request).getHeaders(); 27 | Iterator iter = headers.iterator(); 28 | LinkedHashMap mapHeaders = new LinkedHashMap(); 29 | while (iter.hasNext()) { 30 | //不对请求包重复编码 31 | String item = iter.next(); 32 | if (item.contains(":")) { 33 | String key = item.substring(0, item.indexOf(":")); 34 | String value = item.substring(item.indexOf(":") + 1, item.length()); 35 | mapHeaders.put(key.trim(), value.trim()); 36 | }else if(item.contains("HTTP/")){ 37 | mapHeaders.put("top",item); 38 | } 39 | } 40 | 41 | IHttpService httpService = iReqResp.getHttpService(); 42 | IRequestInfo requestInfo = BurpExtender.helpers.analyzeRequest(httpService,request); 43 | 44 | String url = requestInfo.getUrl().toString(); 45 | int bodyOffset = requestInfo.getBodyOffset(); 46 | int body_length = request.length - bodyOffset; 47 | byte[] byteBody = new byte[body_length]; 48 | System.arraycopy(request, bodyOffset, byteBody, 0, body_length); 49 | 50 | SleepChunkedSender socketSleepClient = new SleepChunkedSender(url,mapHeaders,byteBody,sleepSendConfig); 51 | byte[] result = socketSleepClient.send(); 52 | sleepSendConfig.getResponseViewer().setMessage(result, true); 53 | 54 | sleepSendConfig.getBtnSend().setText("Start"); 55 | // 完成最后一步进度的设置 56 | JProgressBar pgBar = sleepSendConfig.getPgBar(); 57 | pgBar.setValue(request.length + 1); 58 | return null; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/burp/sleepchunked/SleepSendConfig.java: -------------------------------------------------------------------------------- 1 | package burp.sleepchunked; 2 | 3 | import burp.ChunkedLogTable; 4 | import burp.IMessageEditor; 5 | 6 | import javax.swing.*; 7 | 8 | public class SleepSendConfig { 9 | private int minChunkedLen; 10 | private int maxChunkedLen; 11 | private int minSleepTime; 12 | private int maxSleepTime; 13 | private boolean enableSocks5Proxy; 14 | private String proxyHost; 15 | private int proxyPort; 16 | private JLabel lbTotalChunked; 17 | private JLabel lbTotalTime; 18 | private ChunkedLogTable chunkedLogTable; 19 | private JProgressBar pgBar; 20 | private IMessageEditor responseViewer; 21 | private JButton btnSend; 22 | 23 | public int getMinChunkedLen() { 24 | return minChunkedLen; 25 | } 26 | 27 | public void setMinChunkedLen(int minChunkedLen) { 28 | this.minChunkedLen = minChunkedLen; 29 | } 30 | 31 | public int getMaxChunkedLen() { 32 | return maxChunkedLen; 33 | } 34 | 35 | public void setMaxChunkedLen(int maxChunkedLen) { 36 | this.maxChunkedLen = maxChunkedLen; 37 | } 38 | 39 | public int getMinSleepTime() { 40 | return minSleepTime; 41 | } 42 | 43 | public void setMinSleepTime(int minSleepTime) { 44 | this.minSleepTime = minSleepTime; 45 | } 46 | 47 | public int getMaxSleepTime() { 48 | return maxSleepTime; 49 | } 50 | 51 | public void setMaxSleepTime(int maxSleepTime) { 52 | this.maxSleepTime = maxSleepTime; 53 | } 54 | 55 | public boolean isEnableSocks5Proxy() { 56 | return enableSocks5Proxy; 57 | } 58 | 59 | public void setEnableSocks5Proxy(boolean enableSocks5Proxy) { 60 | this.enableSocks5Proxy = enableSocks5Proxy; 61 | } 62 | 63 | public String getProxyHost() { 64 | return proxyHost; 65 | } 66 | 67 | public void setProxyHost(String proxyHost) { 68 | this.proxyHost = proxyHost; 69 | } 70 | 71 | public int getProxyPort() { 72 | return proxyPort; 73 | } 74 | 75 | public void setProxyPort(int proxyPort) { 76 | this.proxyPort = proxyPort; 77 | } 78 | 79 | public JLabel getLbTotalChunked() { 80 | return lbTotalChunked; 81 | } 82 | 83 | public void setLbTotalChunked(JLabel lbTotalChunked) { 84 | this.lbTotalChunked = lbTotalChunked; 85 | } 86 | 87 | public JLabel getLbTotalTime() { 88 | return lbTotalTime; 89 | } 90 | 91 | public void setLbTotalTime(JLabel lbTotalTime) { 92 | this.lbTotalTime = lbTotalTime; 93 | } 94 | 95 | public ChunkedLogTable getChunkedLogTable() { 96 | return chunkedLogTable; 97 | } 98 | 99 | public void setChunkedLogTable(ChunkedLogTable chunkedLogTable) { 100 | this.chunkedLogTable = chunkedLogTable; 101 | } 102 | 103 | public IMessageEditor getResponseViewer() { 104 | return responseViewer; 105 | } 106 | 107 | public void setResponseViewer(IMessageEditor responseViewer) { 108 | this.responseViewer = responseViewer; 109 | } 110 | 111 | public JProgressBar getPgBar() { 112 | return pgBar; 113 | } 114 | 115 | public void setPgBar(JProgressBar pgBar) { 116 | this.pgBar = pgBar; 117 | } 118 | 119 | public JButton getBtnSend() { 120 | return btnSend; 121 | } 122 | 123 | public void setBtnSend(JButton btnSend) { 124 | this.btnSend = btnSend; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/main/java/burp/sleepchunked/SleepSendTableModel.java: -------------------------------------------------------------------------------- 1 | package burp.sleepchunked; 2 | 3 | 4 | import javax.swing.table.AbstractTableModel; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.Vector; 8 | 9 | public class SleepSendTableModel extends AbstractTableModel { 10 | private Vector title = new Vector(); 11 | private List chunkedInfos = new ArrayList(); 12 | 13 | public SleepSendTableModel() { 14 | title.clear(); 15 | title.add("id"); 16 | title.add("chunked content"); 17 | title.add("chunked length"); 18 | title.add("sleep time (ms)"); 19 | title.add("status"); 20 | } 21 | 22 | @Override 23 | public String getColumnName(int column) { 24 | return title.get(column); 25 | } 26 | 27 | @Override 28 | public int getColumnCount() { 29 | return title.size(); 30 | } 31 | 32 | 33 | @Override 34 | public int getRowCount() { 35 | return chunkedInfos.size(); 36 | } 37 | 38 | @Override 39 | public Object getValueAt(int row, int column) { 40 | ChunkedInfoEntity alertEntity = chunkedInfos.get(row); 41 | switch (column) { 42 | case 0: 43 | return alertEntity.getId(); 44 | case 1: 45 | return new String(alertEntity.getChunkedContent()); 46 | case 2: 47 | return alertEntity.getChunkedLen(); 48 | case 3: 49 | return alertEntity.getSleepTime(); 50 | case 4: 51 | return alertEntity.getStatus(); 52 | default: 53 | return ""; 54 | } 55 | } 56 | 57 | public List getChunkedInfos() { 58 | return chunkedInfos; 59 | } 60 | 61 | 62 | // 这个引起了界面混乱。 63 | // /** 64 | // * 让使Swing中JTable中的列按各列的数据类型排序 65 | // * 66 | // * @Reference http://blog.sina.com.cn/s/blog_54b09dc90100ao7d.html 67 | // * @param columnIndex 68 | // * @return 69 | // */ 70 | // @Override 71 | // public Class getColumnClass(int columnIndex) { 72 | // return getValueAt(0,columnIndex).getClass(); 73 | // } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/burp/sleepchunked/X509TrustManagerImpl.java: -------------------------------------------------------------------------------- 1 | package burp.sleepchunked; 2 | 3 | import javax.net.ssl.X509TrustManager; 4 | import java.security.cert.CertificateException; 5 | import java.security.cert.X509Certificate; 6 | 7 | public class X509TrustManagerImpl implements X509TrustManager { 8 | @Override 9 | public X509Certificate[] getAcceptedIssuers() { 10 | return null; 11 | } 12 | 13 | @Override 14 | public void checkServerTrusted(X509Certificate[] chain, 15 | String authType) throws CertificateException { 16 | } 17 | 18 | @Override 19 | public void checkClientTrusted(X509Certificate[] chain, 20 | String authType) throws CertificateException { 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/burp/utils/DateUtil.java: -------------------------------------------------------------------------------- 1 | package burp.utils; 2 | 3 | import java.text.ParseException; 4 | import java.text.SimpleDateFormat; 5 | import java.util.Date; 6 | 7 | public class DateUtil { 8 | private static SimpleDateFormat df = new SimpleDateFormat("YYYY/MM/dd HH:mm:ss"); 9 | public static double betweenMs(String startTime, String nowTime){ 10 | double diff = 0; 11 | try { 12 | double NTime = (double)df.parse(nowTime).getTime(); 13 | //从对象中拿到时间 14 | double OTime = (double)df.parse(startTime).getTime(); 15 | diff = NTime-OTime; 16 | } catch (ParseException e) { 17 | e.printStackTrace(); 18 | } 19 | return diff; 20 | } 21 | 22 | public static String getNowTime(){ 23 | return df.format(new Date()); 24 | } 25 | 26 | public static String ms2str(double ms){ 27 | String res = null; 28 | if(ms >= 1000*60){ 29 | double m = ms/(1000*60); 30 | res = String.format("%.2fm",m); 31 | }else if(ms >= 1000){ 32 | double s = ms/1000; 33 | res = String.format("%.1fs",s); 34 | }else{ 35 | res = String.format("%.1fms",ms); 36 | } 37 | return res; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/burp/utils/GBC.java: -------------------------------------------------------------------------------- 1 | package burp.utils; 2 | 3 | import java.awt.*; 4 | 5 | public class GBC extends GridBagConstraints 6 | { 7 | public GBC(int gridx, int gridy) 8 | { 9 | this.gridx = gridx; 10 | this.gridy = gridy; 11 | } 12 | public GBC(int gridx, int gridy, int gridwidth, int gridheight) 13 | { 14 | this.gridx = gridx; 15 | this.gridy = gridy; 16 | this.gridwidth = gridwidth; 17 | this.gridheight = gridheight; 18 | } 19 | public GBC setFill(int fill) 20 | { 21 | this.fill = fill; 22 | return this; 23 | } 24 | public GBC setWeight(double weightx,double weighty) 25 | { 26 | this.weightx = weightx; 27 | this.weighty = weighty; 28 | return this; 29 | } 30 | public GBC setAnchor(int anchor) 31 | { 32 | this.anchor = anchor; 33 | return this; 34 | } 35 | public GBC setInsets(int top, int left, int bottom, int right) 36 | { 37 | this.insets = new Insets(top, left, bottom, right); 38 | return this; 39 | } 40 | public GBC setIpad(int ipadx,int ipady) 41 | { 42 | this.ipadx = ipadx; 43 | this.ipady = ipady; 44 | return this; 45 | } 46 | } -------------------------------------------------------------------------------- /src/main/java/burp/utils/Util.java: -------------------------------------------------------------------------------- 1 | package burp.utils; 2 | 3 | import burp.BurpExtender; 4 | import burp.IHttpRequestResponse; 5 | import burp.IHttpService; 6 | import burp.IRequestInfo; 7 | 8 | import javax.swing.*; 9 | import javax.swing.table.JTableHeader; 10 | import javax.swing.table.TableColumn; 11 | import java.io.PrintWriter; 12 | import java.io.StringWriter; 13 | import java.math.BigInteger; 14 | import java.util.ArrayList; 15 | import java.util.Enumeration; 16 | import java.util.List; 17 | import java.util.Random; 18 | 19 | public class Util { 20 | /** 21 | * 把原始字符串分割成指定长度的字符串列表 22 | * 23 | * @param inputString 原始字符串 24 | * @param length 指定长度 25 | * @return 26 | */ 27 | public static List getStrList(String inputString, int length) { 28 | int size = inputString.length() / length; 29 | if (inputString.length() % length != 0) { 30 | size += 1; 31 | } 32 | return getStrList(inputString, length, size); 33 | } 34 | 35 | 36 | /** 37 | * 把原始字符串分割成指定长度的字符串列表 38 | * 39 | * @param inputString 原始字符串 40 | * @param length 指定长度 41 | * @param size 指定列表大小 42 | * @return 43 | */ 44 | public static List getStrList(String inputString, int length, int size) { 45 | List list = new ArrayList(); 46 | for (int index = 0; index < size; index++) { 47 | String childStr = substring(inputString, index * length,(index + 1) * length); 48 | list.add(childStr); 49 | } 50 | return list; 51 | } 52 | 53 | /** 54 | * 把原始字符串分割成指定范围的随着长度字符串列表 55 | * @param str 要分割的字符串 56 | * @param minLen 随机最小长度 57 | * @param maxLen 随机最大长度 58 | * @return 59 | */ 60 | public static List getStrRandomLenList(String str, int minLen, int maxLen){ 61 | List list_str = new ArrayList(); 62 | int sum = 0; 63 | while (sum getByteRandomLenList(byte[] data, int minLen, int maxLen){ 74 | List list_str = new ArrayList(); 75 | int sum = 0; 76 | while (sum < data.length){ 77 | int l = getRandomNum(minLen,maxLen); 78 | if(sum + l > data.length){ 79 | l = data.length - sum; 80 | } 81 | byte[] byteBody = new byte[l]; 82 | System.arraycopy(data, sum, byteBody, 0, byteBody.length); 83 | list_str.add(byteBody); 84 | sum += l; 85 | } 86 | return list_str; 87 | } 88 | 89 | 90 | /** 91 | * 分割字符串,如果开始位置大于字符串长度,返回空 92 | * 93 | * @param str 原始字符串 94 | * @param f 开始位置 95 | * @param t 结束位置 96 | * @return 97 | */ 98 | public static String substring(String str, int f, int t) { 99 | if (f > str.length()) 100 | return null; 101 | if (t > str.length()) { 102 | return str.substring(f, str.length()); 103 | } else { 104 | return str.substring(f, t); 105 | } 106 | } 107 | 108 | 109 | /** 110 | * 获取随机字符串 111 | * @param length 112 | * @return 113 | */ 114 | public static String getRandomString(int length) { 115 | String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"; 116 | Random random = new Random(); 117 | char[] text = new char[length]; 118 | for (int i = 0; i < length; i++) { 119 | text[i] = str.charAt(random.nextInt(str.length())); 120 | } 121 | return new String(text); 122 | } 123 | 124 | /** 125 | * 获取min到max范围的随机数 126 | * @param min 最小数 127 | * @param max 最大数 128 | * @return 在min到max之间的一个随机数 129 | */ 130 | public static Integer getRandomNum(int min,int max) { 131 | Random random = new Random(); 132 | int num = random.nextInt(max) % (max - min + 1) + min; 133 | return num; 134 | } 135 | 136 | /** 137 | * 将10进制转换为16进制 138 | * @param decimal 10进制 139 | * @return 16进制 140 | */ 141 | public static String decimalToHex(int decimal) { 142 | String hex = Integer.toHexString(decimal); 143 | return hex.toUpperCase(); 144 | } 145 | 146 | /** 147 | * 将16进制转10进制 148 | * @param hex 149 | * @return 150 | */ 151 | public static int hexToDecimal(String hex){ 152 | BigInteger bigInteger = new BigInteger(hex,16); 153 | return bigInteger.intValue(); 154 | } 155 | 156 | 157 | /** 158 | * 判断数据中是否包含不可见字符 159 | * @param data 要判断的数据 160 | * @return 是否包含不可见字符 161 | */ 162 | public static boolean isIncludeInviChar(byte[] data){ 163 | for(int i=0;i 127){ 167 | return true; 168 | } 169 | } 170 | 171 | return false; 172 | } 173 | 174 | 175 | public static String getUrlFormIReqRsp(IHttpRequestResponse iHttpRequestResponse){ 176 | IHttpService httpService = iHttpRequestResponse.getHttpService(); 177 | byte[] request = iHttpRequestResponse.getRequest(); 178 | IRequestInfo requestInfo = BurpExtender.helpers.analyzeRequest(httpService,request); 179 | String url = requestInfo.getUrl().toString(); 180 | return url; 181 | } 182 | 183 | public static int getReqBodyLenFormIReqRsp(IHttpRequestResponse iHttpRequestResponse){ 184 | byte[] request = iHttpRequestResponse.getRequest(); 185 | IRequestInfo requestInfo = BurpExtender.helpers.analyzeRequest(request); 186 | int bodyOffset = requestInfo.getBodyOffset(); 187 | int body_length = request.length - bodyOffset; 188 | return body_length; 189 | } 190 | 191 | 192 | public static int getRandom(int min,int max) throws Exception { 193 | if(max min"); 195 | } 196 | Random random = new Random(); 197 | int randomNum = random.nextInt(max) % (max - min + 1) + min; 198 | return randomNum; 199 | } 200 | 201 | 202 | public static String getThrowableInfo(Throwable throwable){ 203 | StringWriter writer = new StringWriter(); 204 | PrintWriter printWriter = new PrintWriter(writer); 205 | throwable.printStackTrace(printWriter); 206 | return writer.toString(); 207 | } 208 | 209 | public static boolean bytesEndWith(byte[] bytes, byte[] end){ 210 | int endLen = end.length; 211 | int bytesLen = bytes.length; 212 | 213 | for(int i=1;i?@[\\\\]^_`{|}~ \\t\\n"; 6 | data = "\r\n"; 7 | System.out.println(Util.isIncludeInviChar(data.getBytes())); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/test/TransferTest.java: -------------------------------------------------------------------------------- 1 | import burp.Transfer; 2 | 3 | public class TransferTest { 4 | public static void TestMergeReqBody(){ 5 | byte[] byteBody = "1\r\na\r\n5\r\nab\r\nc\r\n3\r\nbbb0\n\n".getBytes(); 6 | byte[] newBody = Transfer.mergeReqBody(byteBody); 7 | System.out.println(new String(newBody)); 8 | } 9 | 10 | public static void TestSplitReqBody(){ 11 | String reqbody = "{\n" + 12 | " \"a\":1,\n" + 13 | " \"b\":{\"c\":\"xxxx\"}\n" + 14 | "}"; 15 | byte[] byteBody = reqbody.getBytes(); 16 | byte[] newBody = Transfer.splitReqBody(byteBody,1,2,false,0,0); 17 | System.out.println(new String(newBody)); 18 | System.out.println("---------------------"); 19 | newBody = Transfer.mergeReqBody(newBody); 20 | System.out.println(new String(newBody)); 21 | 22 | } 23 | 24 | public static void TestOk(){ 25 | String body = "3;IWFbM4mTXBxSq7cjU2ZOrdg\r\n" + 26 | "ser\r\n" + 27 | "1;XcM0dC2gATfT2cMaX\r\n" + 28 | "v\r\n" + 29 | "1;HL3RZyqc2kk5E2ZRu0djQOu\r\n" + 30 | "i\r\n" + 31 | "3;AwPNeJDu\r\n" + 32 | "ce=\r\n" + 33 | "1;kvFfaa9\r\n" + 34 | "h\r\n" + 35 | "1;VwZXqUfdKcL\r\n" + 36 | "t\r\n" + 37 | "3;g0IdgC\r\n" + 38 | "tps\r\n" + 39 | "2;EHIqC5t\r\n" + 40 | "%3\r\n" + 41 | "3;6P49NW26kLv\r\n" + 42 | "A%2\r\n" + 43 | "1;Mg1IZGijv5keoWV3Pex\r\n" + 44 | "F\r\n" + 45 | "2;gYn0nPRoS5xfLEvE\r\n" + 46 | "%2\r\n" + 47 | "1;XqBYhlH0KbqUD1TKk\r\n" + 48 | "F\r\n" + 49 | "1;ToE8BVCsBm5VKj0C\r\n" + 50 | "y\r\n" + 51 | "2;2FLXZwRSXUAQ6ilT5pggbHUE\r\n" + 52 | "un\r\n" + 53 | "1;BZoEH3S3GqHU4Gqj0QxKj3\r\n" + 54 | ".\r\n" + 55 | "1;F5ddaFsfKx1MTjMEedJh\r\n" + 56 | "s\r\n" + 57 | "2;eqijFldn5Cga4tLA\r\n" + 58 | "cn\r\n" + 59 | "3;Vcb0BzTALRJKv6ji9duogGfwO\r\n" + 60 | "yw.\r\n" + 61 | "2;BVGq0Efdg\r\n" + 62 | "co\r\n" + 63 | "2;fvCiZ\r\n" + 64 | "m%\r\n" + 65 | "3;12ViYBzk3q67b\r\n" + 66 | "2Fp\r\n" + 67 | "1;Lb1uT4\r\n" + 68 | "o\r\n" + 69 | "1;brgH3py6bSqWI1qK\r\n" + 70 | "r\r\n" + 71 | "3;pNtzewGd2XM3lAH\r\n" + 72 | "tal\r\n" + 73 | "3;5NAfSvlZmv0D\r\n" + 74 | "%2F\r\n" + 75 | "0\n" + 76 | "\n"; 77 | 78 | byte[] newBody = Transfer.mergeReqBody(body.getBytes()); 79 | System.out.println(new String(newBody)); 80 | 81 | } 82 | 83 | public static void main(String[] args) { 84 | // TestMergeReqBody(); 85 | // TestSplitReqBody(); 86 | TestOk(); 87 | } 88 | } 89 | 90 | 91 | -------------------------------------------------------------------------------- /src/main/test/burp/sleepchunked/SocketSleepClientTest.java: -------------------------------------------------------------------------------- 1 | package burp.sleepchunked; 2 | 3 | import javax.net.ssl.SSLContext; 4 | import javax.net.ssl.TrustManager; 5 | import java.io.*; 6 | import java.net.*; 7 | 8 | import static burp.sleepchunked.SleepChunkedSender.readFullHttpResponse; 9 | 10 | public class SocketSleepClientTest { 11 | 12 | 13 | @org.junit.Test 14 | public void send() throws Exception { 15 | X509TrustManagerImpl x509m = new X509TrustManagerImpl(); 16 | // 获取一个SSLContext实例 17 | SSLContext sslContext = SSLContext.getInstance("SSL"); 18 | // 初始化SSLContext实例 19 | sslContext.init(null, new TrustManager[] { x509m }, new java.security.SecureRandom()); 20 | 21 | String prxyhost = "127.0.0.1"; 22 | int prxyport = 1188; 23 | SocketAddress addr = new InetSocketAddress(prxyhost, Integer.valueOf(prxyport)); 24 | Proxy proxy = new Proxy(Proxy.Type.SOCKS, addr); 25 | Socket socket = new Socket(proxy); 26 | 27 | InetSocketAddress address = new InetSocketAddress("2021.ip138.com", 443); 28 | socket.connect(address); 29 | 30 | Socket sslSocket = sslContext.getSocketFactory().createSocket(socket,address.getHostName(), address.getPort(), true); 31 | 32 | //sslSocket.connect(new InetSocketAddress("www.baidu.com",443)); 33 | OutputStream osw = sslSocket.getOutputStream(); 34 | osw.write("GET / HTTP/1.1\r\n".getBytes()); 35 | osw.write("Host: 2021.ip138.com\r\n".getBytes()); 36 | osw.write("Connection: close\r\n\r\n".getBytes()); 37 | osw.flush(); 38 | 39 | byte[] result = readFullHttpResponse(sslSocket.getInputStream()); 40 | System.out.println(new String(result)); 41 | } 42 | 43 | 44 | 45 | public static void sendUrl() throws IOException { 46 | byte[] test = "abcdefq".getBytes(); 47 | ByteArrayInputStream inputStream = new ByteArrayInputStream(test); 48 | ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 49 | byte[] buffer = new byte[1]; 50 | while (inputStream.read(buffer) != -1){ 51 | byteArrayOutputStream.write(buffer); 52 | System.out.println(new String(byteArrayOutputStream.toByteArray())); 53 | } 54 | } 55 | 56 | 57 | 58 | 59 | public static void main(String[] args) throws IOException { 60 | sendUrl(); 61 | } 62 | 63 | 64 | } --------------------------------------------------------------------------------