├── .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 | 
14 |
15 | 
16 |
17 | 延时分块传输
18 |
19 | 
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 | }
--------------------------------------------------------------------------------