├── README.md └── BurpExtender.java /README.md: -------------------------------------------------------------------------------- 1 | # xia SQL (瞎注) 2 | 3 | > 本插件仅只插入单引号,没有其他盲注啥的,且返回的结果需要人工介入去判断是否存在注入,如果需要所有注入都测试,请把burp的流量转发到xray。 4 | 5 | ## 注意 6 | * 默认使用jdk1.8编译 7 | * 在最新版的burp2.x中jdk为1x,会导致插件不可用,请下载jdk16版本试试,若还不行,请自行下载源码使用当前电脑的jdk1x进行编译,谢谢。 8 | 9 | *********** 10 | 11 | * burp 插件。 12 | * 在每个参数后面填加一个单引号,两个单引号,如果值为纯数字则多加一个-1、-0。 13 | * 由于不会java,且又是用java写的,代码太烂,勿喷。` 14 | * 感谢名单:Moonlit、阿猫阿狗、Shincehor、Xm17 15 | 16 | *********** 17 | 18 | ## 插件使用描述 19 | * 返回 `✔️` 代表两个单引号的长度和一个单引号的长度不一致,`表明可能存在注入`。 20 | * 返回 `✔️ ==> ?` 代表着 原始包的长度和两个单引号的长度相同且和一个单引号的长度不同,`表明很可能是注入`。 21 | * 返回 `Err` 代表响应包中含有数据库报错信息。 22 | * 返回 `diy payload` 代表自定义的payload。 23 | * 返回 `time > 3` 代表访问网站的时间大于3秒,可利用该功能配合自定义payload功能测试`时间盲注`。 24 | * 支持json格式,V1.9以上版本`已支持json多层嵌套`。 25 | * 支持参数的值是`纯数字则-1,-0`。 26 | * 支持cookie测试 27 | * 支持`右键发送到插件扫描`(哪怕之前扫描过的,仍然可以通过右键发送再次扫描)备注:右键发送一定需要有响应包,不然发不过去,这样才能对比和原数据包的长度。 28 | * 支持`自定义payload`。 29 | * 支持自定义payload中的参数值`置空`。 30 | * 监控Proxy流量。 31 | * 监控Repeater流量。 32 | * 同个数据包只扫描一次,算法:`MD5(不带参数的url+参数名+POST/GET)`。 33 | * 支持白名单功能,若多个域名请用,隔开 34 | 35 | ## 插件截图 36 | 37 | image 38 | 39 | ********** 40 | ### 2023-5-18 41 | #### xia SQL 3.3 42 | * 优化响应包的内容为图片时,忽略处理。 43 | 44 | ********** 45 | ### 2023-3-6 46 | #### xia SQL 3.2 47 | * 优化左上的两个窗口可以在内部可伸缩 48 | * 启动自定义payload后,取消内置payload。 49 | 50 | image 51 | 52 | 53 | ********** 54 | ### 2023-2-10 55 | #### xia SQL 3.1 56 | * 更新自定义数据库报错关键字。 57 | * 更新日志模式,里面输出的是哪条数据库报错关键字触发的。 58 | 59 | image 60 | 61 | image 62 | 63 | 64 | 65 | ********** 66 | ### 2023-2-8 67 | #### xia SQL 3.0 68 | * 新增匹配响应包是否有包含数据库报错关键字,如有将显示Err 69 | * 优化请求包的body内容为二进制时,过滤掉。 70 | 71 | image 72 | 73 | image 74 | 75 | 76 | ********** 77 | ### 2022-11-19 78 | #### xia SQL 2.9 79 | * 支持多个域名白名单 80 | * 优化ui 81 | 82 | image 83 | 84 | 85 | ********** 86 | ### 2022-10-17 87 | #### xia SQL 2.8 88 | * 新增自定义payload保存到本地,每次打开burp将会自动获取上次保存的payload。 89 | 90 | image 91 | 92 | 93 | ********** 94 | ### 2022-8-7 95 | #### xia SQL 2.7 96 | * 修复2.6版本处理json格式致命错误 97 | * 优化json嵌套格式处理,基本上都能正确处理,除个别极端情况 98 | * 新增响应码列 99 | * 新增白名单功能。 100 | 101 | image 102 | 103 | 104 | 105 | ********** 106 | ### 2022-6-22 107 | #### xia SQL 2.6 108 | * 新增变化中具体长度变化多少的值(如果变化的值小于等于4基本上是误报) 109 | * 修复已知bug 110 | 111 | image 112 | 113 | 114 | ********** 115 | ### 2022-6-6 116 | #### xia SQL 2.5 117 | * 修复burp2.x json嵌套bug 118 | 119 | 120 | ********** 121 | ### 2022-5-27 122 | #### xia SQL 2.4 123 | * 新增支持对cookie测试 124 | 125 | ![image](https://user-images.githubusercontent.com/30351807/170674995-f5595cc4-afe6-4d74-97d3-6175c4966519.png) 126 | 127 | 128 | ********** 129 | ### 2022-5-24 130 | #### xia SQL 2.3 131 | * 新增 状态一列,`run……` 表示正在发送相关payload,`end!` 表示已经扫描完成,`end! ✔️`表示扫描完成且结果可能存在注入。 132 | 133 | ![image](https://user-images.githubusercontent.com/30351807/169846432-106a0764-7f20-466e-831d-8b8615c9dda7.png) 134 | 135 | 136 | ********** 137 | ### 2022-5-20 138 | #### xia SQL 2.2 139 | * 优化proxy模式有时流量不过来问题。 140 | * 优化Proxy、Repeater 模式下,静态资源不处理。后缀:jpg、png、gif、css、js、pdf、mp3、mp4、avi`(右键发送不影响)` 141 | 142 | ![image](https://user-images.githubusercontent.com/30351807/169476496-e2a7351b-f701-42f8-b56b-a8d411ab6eca.png) 143 | 144 | 145 | ********** 146 | ### 2022-5-12 147 | #### xia SQL 2.1 148 | * 新增 自定义payload中参数值置空 149 | 150 | ![image](https://user-images.githubusercontent.com/30351807/168087873-1e57c10d-cf66-4783-af1e-3d075f629c4d.png) 151 | 152 | ********** 153 | ### 2022-4-25 154 | #### xia SQL 2.0 155 | * ui界面优化 156 | * 添加自定义payload功能 157 | * 自定义payload访问网站时间大于3秒,将显示 time > 3。 158 | 159 | ![image](https://user-images.githubusercontent.com/30351807/165055862-c0a3a72e-918c-47b7-84ad-f74b1cb2f365.png) 160 | 161 | ![image](https://user-images.githubusercontent.com/30351807/165055655-1ac9b40a-4c68-424a-b73e-f31b3b5f1162.png) 162 | 163 | ********** 164 | ### 2022-4-11 165 | #### xia SQL 1.9 166 | * 支持json多层嵌套 167 | * 新增列:用时,用于后期更新自定义payload时,可以查看到每个数据包所用的时间。 168 | ![image](https://user-images.githubusercontent.com/30351807/162653146-5caaf300-3b1c-4680-af06-e84364a5e3b4.png) 169 | 170 | 171 | ********** 172 | ### 2022-4-8 173 | #### xia SQL 1.8 174 | * 新增右键发送到插件扫描 175 | * 优化 监控Repeater 模式下数据包返回速度。 176 | ![image](https://user-images.githubusercontent.com/30351807/162444663-ecc491e2-9a74-4d0f-8b1f-c6ce8f61546a.png) 177 | 178 | 179 | ********** 180 | ### 2022-4-2 181 | #### xia SQL 1.7 182 | * 修复在burp2.x版本下poxry模式展示内容bug 183 | ![image](https://user-images.githubusercontent.com/30351807/161375553-cee2df69-5681-4818-95ae-0ed389795ea4.png) 184 | 185 | 186 | ********** 187 | ### 2022-3-31 188 | #### xia SQL 1.6 189 | * 更新相同数据包只扫描一次的算法,算法:MD5(不带参数的url+参数名+POST/GET) 190 | ![image](https://user-images.githubusercontent.com/30351807/161045937-d0e3584a-d610-4b26-ba33-6cc08dd9e8fa.png) 191 | 192 | 193 | ********** 194 | ### 2022-3-29 195 | #### xia SQL 1.5 196 | * 取消默认选中“监控Repeater”,增加默认选中“值是数字则进行-1、-0”。 197 | * 变更 监控Proxy模式 为被动模式,提升交互体验感。 198 | * 新增相同数据包只扫描一次。算法:MD5(url+参数名),如果是post包,值变化也不会重新扫描,需要参数名变化才会再次扫描。 199 | 200 | 201 | ********** 202 | ### 2022-2-13 203 | #### xia SQL 1.4 204 | * 更新了 一个选项,如果值是纯数字的话就进行-1,-0 205 | ![image](https://user-images.githubusercontent.com/30351807/153725862-8ec9e92f-66b5-4d5c-9c3e-fb18f5afaa94.png) 206 | 207 | 208 | ********** 209 | ### 2022-2-11 210 | #### xia SQL 1.3 211 | * 更新了 原始包的长度和两个单引号的长度相同且和一个单引号的长度不同就返回 ✔️ ==> ? 212 | 213 | ![image](https://user-images.githubusercontent.com/30351807/153590052-42293c4a-7a85-4740-b29e-209a7c27d403.png) 214 | 215 | 216 | ********** 217 | ### 2022-2-11 218 | #### xia SQL 1.2 219 | * 更新支持json格式 220 | 221 | ![image](https://user-images.githubusercontent.com/30351807/153567877-479a0e15-9d6c-43f5-84d9-80c5dfb6fd03.png) 222 | 223 | 224 | ********** 225 | ### 2022-2-10 226 | #### xia SQL 1.1 227 | * 更新了序列号 228 | * 更新了有变化 打勾 229 | * 更新了如果那个数据包没有参数,那就忽略。这样开 proxy 模式 就不会一堆包了。 230 | 231 | ![image](https://user-images.githubusercontent.com/30351807/153390045-2b3769f6-151b-45c0-a555-53cda4fef2f2.png) 232 | 233 | 234 | ********** 235 | # 图片展示 236 | 237 | ![image](https://user-images.githubusercontent.com/30351807/153139897-08e6b69b-f129-4fab-a62e-037351d7c60f.png) 238 | 239 | ![image](https://user-images.githubusercontent.com/30351807/153139950-a4f51f4b-e39d-459d-91b8-e326c2c74c29.png) 240 | 241 | 242 | ![image](https://user-images.githubusercontent.com/30351807/153139522-b9af5d35-36a3-4204-b2f4-7b6a11253d41.png) 243 | -------------------------------------------------------------------------------- /BurpExtender.java: -------------------------------------------------------------------------------- 1 | package burp; 2 | 3 | 4 | import java.io.*; 5 | import java.nio.charset.StandardCharsets; 6 | import java.security.MessageDigest; 7 | import java.awt.Component; 8 | import java.awt.event.ActionEvent; 9 | import java.awt.event.ActionListener; 10 | import java.awt.event.ItemEvent; 11 | import java.net.URL; 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | import javax.swing.JScrollPane; 15 | import javax.swing.JSplitPane; 16 | import javax.swing.JTabbedPane; 17 | import javax.swing.JTable; 18 | import javax.swing.SwingUtilities; 19 | import javax.swing.table.AbstractTableModel; 20 | import javax.swing.table.TableModel; 21 | import javax.swing.JLabel; 22 | import javax.swing.JPanel; 23 | import javax.swing.JButton; 24 | import javax.swing.JCheckBox; 25 | import java.awt.*; 26 | import java.awt.event.ItemListener; 27 | import javax.swing.JMenuItem; 28 | import java.util.regex.Matcher; 29 | import java.util.regex.Pattern; 30 | import javax.swing.JTextArea; 31 | import javax.swing.JTextField; 32 | 33 | 34 | 35 | public class BurpExtender extends AbstractTableModel implements IBurpExtender, ITab, IHttpListener,IScannerCheck, IMessageEditorController,IContextMenuFactory 36 | { 37 | private IBurpExtenderCallbacks callbacks; 38 | private IExtensionHelpers helpers; 39 | private JSplitPane splitPane; 40 | private IMessageEditor requestViewer; 41 | private IMessageEditor responseViewer; 42 | private final List log = new ArrayList();//记录原始流量 43 | private final List log2 = new ArrayList();//记录攻击流量 44 | private final List log3 = new ArrayList();//用于展现 45 | private final List log4_md5 = new ArrayList();//用于存放数据包的md5 46 | private IHttpRequestResponse currentlyDisplayedItem; 47 | public PrintWriter stdout; 48 | int switchs = 1; //开关 0关 1开 49 | int clicks_Repeater=0;//64是监听 0是关闭 50 | int clicks_Proxy=0;//4是监听 0是关闭 51 | int conut = 0; //记录条数 52 | String data_md5_id; //用于判断目前选中的数据包 53 | public AbstractTableModel model = new MyModel(); 54 | int original_data_len;//记录原始数据包的长度 55 | int is_int = 1; //开关 0关 1开;//纯数据是否进行-1,-0 56 | String temp_data; //用于保存临时内容 57 | int JTextArea_int = 0;//自定义payload开关 0关 1开 58 | String JTextArea_data_1 = "";//文本域的内容 59 | int diy_payload_1 = 1;//自定义payload空格编码开关 0关 1开 60 | int diy_payload_2 = 0;//自定义payload值置空开关 0关 1开 61 | int select_row = 0;//选中表格的行数 62 | Table logTable; //第一个表格框 63 | int is_cookie = -1;//cookie是否要注入,-1关闭 2开启。 64 | String white_URL = ""; 65 | int white_switchs = 0;//白名单开关 66 | 67 | 68 | 69 | 70 | 71 | // 72 | // implement IBurpExtender 73 | // 74 | 75 | @Override 76 | public void registerExtenderCallbacks(final IBurpExtenderCallbacks callbacks) 77 | { 78 | //输出 79 | this.stdout = new PrintWriter(callbacks.getStdout(), true); 80 | this.stdout.println("hello xia sql!"); 81 | this.stdout.println("你好 欢迎使用 瞎注!"); 82 | this.stdout.println("version:2.9"); 83 | 84 | 85 | 86 | // keep a reference to our callbacks object 87 | this.callbacks = callbacks; 88 | 89 | // obtain an extension helpers object 90 | helpers = callbacks.getHelpers(); 91 | 92 | // set our extension name 93 | callbacks.setExtensionName("xia SQL V2.9"); 94 | 95 | // create our UI 96 | SwingUtilities.invokeLater(new Runnable() 97 | { 98 | @Override 99 | public void run() 100 | { 101 | 102 | // main split pane 103 | splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); 104 | JSplitPane splitPanes = new JSplitPane(JSplitPane.VERTICAL_SPLIT); 105 | JSplitPane splitPanes_2 = new JSplitPane(JSplitPane.VERTICAL_SPLIT); 106 | 107 | // table of log entries 108 | logTable = new Table(BurpExtender.this); 109 | JScrollPane scrollPane = new JScrollPane(logTable); //给列表添加滚动条 110 | 111 | 112 | 113 | //test 114 | JPanel jp=new JPanel(); 115 | JLabel jl=new JLabel("==>"); //创建一个标签 116 | 117 | Table_log2 table=new Table_log2(model); 118 | JScrollPane pane=new JScrollPane(table);//给列表添加滚动条 119 | 120 | jp.add(scrollPane); //将表格加到面板 121 | jp.add(jl); //将标签添加到面板 122 | jp.add(pane); //将表格加到面板 123 | 124 | //侧边复选框 125 | JPanel jps=new JPanel(); 126 | jps.setLayout(new GridLayout(18, 1)); //六行一列 127 | JLabel jls=new JLabel("插件名:瞎注 author:算命縖子"); //创建一个标签 128 | JLabel jls_1=new JLabel("blog:www.nmd5.com"); //创建一个标签 129 | JLabel jls_2=new JLabel("版本:xia SQL V2.9"); //创建一个标签 130 | JLabel jls_3=new JLabel("感谢名单:Moonlit、阿猫阿狗、Shincehor"); //创建一个标签 131 | JCheckBox chkbox1=new JCheckBox("启动插件", true); //创建指定文本和状态的复选框 132 | JCheckBox chkbox2=new JCheckBox("监控Repeater"); //创建指定文本的复选框 133 | JCheckBox chkbox3=new JCheckBox("监控Proxy"); //创建指定文本的复选框 134 | JCheckBox chkbox4=new JCheckBox("值是数字则进行-1、-0",true); //创建指定文本的复选框 135 | JLabel jls_4=new JLabel("修改payload后记得点击加载"); //创建一个标签 136 | JCheckBox chkbox5=new JCheckBox("自定义payload"); //创建指定文本的复选框 137 | JCheckBox chkbox6=new JCheckBox("自定义payload中空格url编码",true); //创建指定文本的复选框 138 | JCheckBox chkbox7=new JCheckBox("自定义payload中参数值置空"); //创建指定文本的复选框 139 | JCheckBox chkbox8=new JCheckBox("测试Cookie"); //创建指定文本的复选框 140 | JLabel jls_5=new JLabel("如果需要多个域名加白请用,隔开"); //创建一个标签 141 | JTextField textField = new JTextField("填写白名单域名");//白名单文本框 142 | 143 | //chkbox4.setEnabled(false);//设置为不可以选择 144 | 145 | JButton btn1=new JButton("清空列表"); //创建JButton对象 146 | JButton btn2=new JButton("加载/重新加载payload"); //创建JButton对象 147 | JButton btn3=new JButton("启动白名单"); //处理白名单 148 | 149 | //自定义payload区 150 | JPanel jps_2=new JPanel(); 151 | jps_2.setLayout(new GridLayout(1, 1)); //六行一列 152 | JTextArea jta=new JTextArea("%df' and sleep(3)%23\n'and '1'='1",18,16); 153 | 154 | //读取ini配置文件 155 | try { 156 | BufferedReader in = new BufferedReader(new FileReader("xia_SQL_diy_payload.ini")); 157 | String str,str_data=""; 158 | while ((str = in.readLine()) != null) { 159 | str_data += str+"\n"; 160 | } 161 | jta.setText(str_data); 162 | } catch (IOException e) { 163 | } 164 | 165 | //jta.setLineWrap(true); //设置文本域中的文本为自动换行 166 | jta.setForeground(Color.BLACK); //设置组件的背景色 167 | jta.setFont(new Font("楷体",Font.BOLD,16)); //修改字体样式 168 | jta.setBackground(Color.LIGHT_GRAY); //设置背景色 169 | jta.setEditable(false);//不可编辑状态 170 | JScrollPane jsp=new JScrollPane(jta); //将文本域放入滚动窗口 171 | jps_2.add(jsp); //将JScrollPane添加到JPanel容器中 172 | 173 | //添加复选框监听事件 174 | chkbox1.addItemListener(new ItemListener() { 175 | @Override 176 | public void itemStateChanged(ItemEvent e) { 177 | if(chkbox1.isSelected()){ 178 | stdout.println("插件xia SQl启动"); 179 | switchs = 1; 180 | }else { 181 | stdout.println("插件xia SQL关闭"); 182 | switchs = 0; 183 | } 184 | 185 | } 186 | }); 187 | chkbox2.addItemListener(new ItemListener() { 188 | @Override 189 | public void itemStateChanged(ItemEvent e) { 190 | if (chkbox2.isSelected()){ 191 | stdout.println("启动 监控Repeater"); 192 | clicks_Repeater = 64; 193 | }else { 194 | stdout.println("关闭 监控Repeater"); 195 | clicks_Repeater = 0; 196 | } 197 | } 198 | }); 199 | chkbox3.addItemListener(new ItemListener() { 200 | @Override 201 | public void itemStateChanged(ItemEvent e) { 202 | if(chkbox3.isSelected()) { 203 | stdout.println("启动 监控Proxy"); 204 | clicks_Proxy = 4; 205 | }else { 206 | stdout.println("关闭 监控Proxy"); 207 | clicks_Proxy = 0; 208 | } 209 | } 210 | }); 211 | chkbox4.addItemListener(new ItemListener() { 212 | @Override 213 | public void itemStateChanged(ItemEvent e) { 214 | if(chkbox4.isSelected()) { 215 | stdout.println("启动 值是数字则进行-1、-0"); 216 | is_int = 1; 217 | }else { 218 | stdout.println("关闭 值是数字则进行-1、-0"); 219 | is_int = 0; 220 | } 221 | } 222 | }); 223 | 224 | chkbox5.addItemListener(new ItemListener() { 225 | @Override 226 | public void itemStateChanged(ItemEvent e) { 227 | if(chkbox5.isSelected()) { 228 | stdout.println("启动 自定义payload"); 229 | jta.setEditable(true); 230 | jta.setBackground(Color.WHITE); //设置背景色 231 | JTextArea_int = 1; 232 | 233 | if (diy_payload_1 == 1){ 234 | String temp_data = jta.getText(); 235 | temp_data = temp_data.replaceAll(" ","%20"); 236 | JTextArea_data_1 = temp_data; 237 | }else { 238 | JTextArea_data_1 = jta.getText(); 239 | } 240 | 241 | }else { 242 | stdout.println("关闭 自定义payload"); 243 | jta.setEditable(false); 244 | jta.setBackground(Color.LIGHT_GRAY); //设置背景色 245 | JTextArea_int = 0; 246 | } 247 | } 248 | }); 249 | 250 | chkbox6.addItemListener(new ItemListener() { 251 | @Override 252 | public void itemStateChanged(ItemEvent e) { 253 | if(chkbox6.isSelected()) { 254 | stdout.println("启动 空格url编码"); 255 | diy_payload_1 = 1; 256 | 257 | //空格url编码 258 | String temp_data = jta.getText(); 259 | temp_data = temp_data.replaceAll(" ","%20"); 260 | JTextArea_data_1 = temp_data; 261 | }else { 262 | stdout.println("关闭 空格url编码"); 263 | diy_payload_1 = 0; 264 | 265 | JTextArea_data_1 = jta.getText(); 266 | } 267 | } 268 | }); 269 | 270 | chkbox7.addItemListener(new ItemListener() { 271 | @Override 272 | public void itemStateChanged(ItemEvent e) { 273 | if(chkbox7.isSelected()) { 274 | stdout.println("启动 自定义payload参数值置空"); 275 | diy_payload_2 = 1; 276 | }else { 277 | stdout.println("关闭 自定义payload参数值置空"); 278 | diy_payload_2 = 0; 279 | } 280 | } 281 | }); 282 | 283 | chkbox8.addItemListener(new ItemListener() { 284 | @Override 285 | public void itemStateChanged(ItemEvent e) { 286 | if(chkbox8.isSelected()) { 287 | stdout.println("启动 测试Cookie"); 288 | is_cookie = 2; 289 | }else { 290 | stdout.println("关闭 测试Cookie"); 291 | is_cookie = -1; 292 | } 293 | } 294 | }); 295 | 296 | btn1.addActionListener(new ActionListener() {//清空列表 297 | @Override 298 | public void actionPerformed(ActionEvent e) { 299 | log.clear();//清除log的内容 300 | log2.clear();//清除log2的内容 301 | log3.clear();//清除log3的内容 302 | log4_md5.clear();//清除log4的内容 303 | conut = 0; 304 | fireTableRowsInserted(log.size(), log.size());//刷新列表中的展示 305 | model.fireTableRowsInserted(log3.size(), log3.size());//刷新列表中的展示 306 | } 307 | }); 308 | 309 | btn2.addActionListener(new ActionListener() {//加载自定义payload 310 | @Override 311 | public void actionPerformed(ActionEvent e) { 312 | if (diy_payload_1 == 1){ 313 | String temp_data = jta.getText(); 314 | temp_data = temp_data.replaceAll(" ","%20"); 315 | JTextArea_data_1 = temp_data; 316 | }else { 317 | JTextArea_data_1 = jta.getText(); 318 | } 319 | //写入ini配置文件 320 | try { 321 | BufferedWriter out = new BufferedWriter(new FileWriter("xia_SQL_diy_payload.ini")); 322 | out.write(JTextArea_data_1); 323 | out.close(); 324 | } catch (IOException exception) { 325 | } 326 | } 327 | }); 328 | btn3.addActionListener(new ActionListener() {//加载自定义payload 329 | @Override 330 | public void actionPerformed(ActionEvent e) { 331 | if(btn3.getText().equals("启动白名单")){ 332 | btn3.setText("关闭白名单"); 333 | white_URL = textField.getText(); 334 | white_switchs = 1; 335 | textField.setEditable(false); 336 | textField.setForeground(Color.GRAY);//设置组件的背景色 337 | }else { 338 | btn3.setText("启动白名单"); 339 | white_switchs = 0; 340 | textField.setEditable(true); 341 | textField.setForeground(Color.BLACK); 342 | } 343 | } 344 | }); 345 | 346 | jps.add(jls); 347 | jps.add(jls_1); 348 | jps.add(jls_2); 349 | jps.add(jls_3); 350 | jps.add(chkbox1); 351 | jps.add(chkbox2); 352 | jps.add(chkbox3); 353 | jps.add(chkbox4); 354 | jps.add(chkbox8); 355 | jps.add(btn1); 356 | jps.add(jls_5); 357 | jps.add(textField); 358 | jps.add(btn3); 359 | jps.add(jls_4); 360 | jps.add(chkbox5); 361 | jps.add(chkbox6); 362 | jps.add(chkbox7); 363 | jps.add(btn2); 364 | 365 | 366 | 367 | 368 | 369 | 370 | // tabs with request/response viewers 371 | JTabbedPane tabs = new JTabbedPane(); 372 | requestViewer = callbacks.createMessageEditor(BurpExtender.this, false); 373 | responseViewer = callbacks.createMessageEditor(BurpExtender.this, false); 374 | tabs.addTab("Request", requestViewer.getComponent()); 375 | tabs.addTab("Response", responseViewer.getComponent()); 376 | 377 | //jp.add(tabs); 378 | 379 | //右边 380 | splitPanes_2.setLeftComponent(jps);//上面 381 | splitPanes_2.setRightComponent(jps_2);//下面 382 | 383 | //左边 384 | splitPanes.setLeftComponent(jp);//上面 385 | splitPanes.setRightComponent(tabs);//下面 386 | 387 | //整体分布 388 | splitPane.setLeftComponent(splitPanes);//添加在左面 389 | splitPane.setRightComponent(splitPanes_2);//添加在右面 390 | splitPane.setDividerLocation(1000);//设置分割的大小 391 | 392 | // customize our UI components 393 | callbacks.customizeUiComponent(splitPane); 394 | callbacks.customizeUiComponent(logTable); 395 | callbacks.customizeUiComponent(scrollPane); 396 | callbacks.customizeUiComponent(pane); 397 | callbacks.customizeUiComponent(jps); 398 | callbacks.customizeUiComponent(jp); 399 | callbacks.customizeUiComponent(tabs); 400 | 401 | // add the custom tab to Burp's UI 402 | callbacks.addSuiteTab(BurpExtender.this); 403 | 404 | // register ourselves as an HTTP listener 405 | callbacks.registerHttpListener(BurpExtender.this); 406 | callbacks.registerScannerCheck(BurpExtender.this); 407 | callbacks.registerContextMenuFactory(BurpExtender.this); 408 | 409 | } 410 | }); 411 | } 412 | // 413 | // implement ITab 414 | // 415 | 416 | @Override 417 | public String getTabCaption() 418 | { 419 | return "xia SQL"; 420 | } 421 | 422 | @Override 423 | public Component getUiComponent() 424 | { 425 | return splitPane; 426 | } 427 | 428 | // 429 | // implement IHttpListener 430 | // 431 | 432 | 433 | 434 | 435 | @Override 436 | public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse messageInfo) 437 | { 438 | 439 | if(switchs == 1){//插件开关 440 | if(toolFlag == clicks_Repeater || toolFlag == clicks_Proxy){//监听Repeater 441 | // only process responses 442 | if (!messageIsRequest) 443 | { 444 | // create a new log entry with the message details 445 | synchronized(log) 446 | { 447 | //BurpExtender.this.checkVul(messageInfo,toolFlag); 448 | Thread thread = new Thread(new Runnable() { 449 | public void run() { 450 | try { 451 | BurpExtender.this.checkVul(messageInfo,toolFlag); 452 | } catch (Exception ex) { 453 | ex.printStackTrace(); 454 | BurpExtender.this.stdout.println(ex); 455 | } 456 | } 457 | }); 458 | thread.start(); 459 | } 460 | } 461 | } 462 | 463 | } 464 | 465 | } 466 | 467 | @Override 468 | public List doPassiveScan(IHttpRequestResponse baseRequestResponse) { 469 | return null; 470 | } 471 | 472 | @Override 473 | public List createMenuItems(final IContextMenuInvocation invocation) { 474 | //右键发送按钮功能 475 | 476 | List listMenuItems = new ArrayList(1); 477 | if(invocation.getToolFlag() == IBurpExtenderCallbacks.TOOL_REPEATER || invocation.getToolFlag() == IBurpExtenderCallbacks.TOOL_PROXY){ 478 | //父级菜单 479 | IHttpRequestResponse[] responses = invocation.getSelectedMessages(); 480 | JMenuItem jMenu = new JMenuItem("Send to xia SQL"); 481 | 482 | jMenu.addActionListener(new ActionListener() { 483 | @Override 484 | public void actionPerformed(ActionEvent e) { 485 | if(switchs == 1) { 486 | //不应在Swing事件调度线程中发出HTTP请求,所以需要创建一个Runnable并在 run() 方法中完成工作,后调用 new Thread(runnable).start() 来启动线程 487 | Thread thread = new Thread(new Runnable() { 488 | public void run() { 489 | try { 490 | BurpExtender.this.checkVul(responses[0], 1024); 491 | } catch (Exception ex) { 492 | ex.printStackTrace(); 493 | BurpExtender.this.stdout.println(ex); 494 | } 495 | } 496 | }); 497 | thread.start(); 498 | }else { 499 | BurpExtender.this.stdout.println("插件xia SQL关闭状态!"); 500 | } 501 | 502 | } 503 | }); 504 | 505 | listMenuItems.add(jMenu); 506 | 507 | 508 | } 509 | //BurpExtender.this.checkVul(responses,4); 510 | return listMenuItems; 511 | } 512 | 513 | private void checkVul(IHttpRequestResponse baseRequestResponse, int toolFlag){ 514 | 515 | int is_add; //用于判断是否要添加扫描 516 | String change_sign_1 = ""; //用于显示第一个列表框的状态 变化 部分的内容 517 | 518 | //把当前url和参数进行md5加密,用于判断该url是否已经扫描过 519 | ListparaLists= helpers.analyzeRequest(baseRequestResponse).getParameters(); 520 | temp_data = String.valueOf(helpers.analyzeRequest(baseRequestResponse).getUrl());//url 521 | //stdout.println(temp_data); 522 | String[] temp_data_strarray=temp_data.split("\\?"); 523 | String temp_data =(String) temp_data_strarray[0];//获取问号前面的字符串 524 | 525 | //检测白名单 526 | String[] white_URL_list = white_URL.split(","); 527 | int white_swith = 0; 528 | if(white_switchs == 1){ 529 | white_swith = 0; 530 | for(int i=0;i2){ 578 | is_add = 2; 579 | } 580 | //json中有列表 581 | request_datas = request_data.split("\":\\["); 582 | if(request_datas.length >1){ 583 | is_add = 2; 584 | } 585 | } catch (Exception e) { 586 | stdout.println(e); 587 | } 588 | } 589 | } 590 | } 591 | 592 | 593 | 594 | //url+参数进行编码 595 | temp_data += "+"+helpers.analyzeRequest(baseRequestResponse).getMethod(); 596 | //this.stdout.println(temp_data); 597 | this.stdout.println("\nMD5(\""+temp_data+"\")"); 598 | temp_data = MD5(temp_data); 599 | this.stdout.println(temp_data); 600 | 601 | 602 | 603 | for (Request_md5 i : log4_md5){ 604 | if(i.md5_data.equals(temp_data)){//判断md5值是否一样,且右键发送过来的请求不进行md5验证 605 | if(toolFlag == 1024){ 606 | temp_data = String.valueOf(System.currentTimeMillis()); 607 | this.stdout.println(temp_data); 608 | temp_data = MD5(temp_data); 609 | this.stdout.println(temp_data); 610 | }else { 611 | return; 612 | } 613 | 614 | 615 | } 616 | } 617 | 618 | //用于判断是否要处理这个请求 619 | if (is_add != 0){ 620 | log4_md5.add(new Request_md5(temp_data));//保存对应对md5 621 | stdout.println(is_add); 622 | stdout.println(request_data); 623 | 624 | int row = log.size(); 625 | try{ 626 | original_data_len = callbacks.saveBuffersToTempFiles(baseRequestResponse).getResponse().length;//更新原始数据包的长度 627 | stdout.println(original_data_len); 628 | if(original_data_len <= 0){ 629 | stdout.println("该数据包无响应"); 630 | return; 631 | } 632 | } catch (Exception ex) { 633 | stdout.println("该数据包无响应"); 634 | return; 635 | } 636 | 637 | log.add(new LogEntry(conut,toolFlag, callbacks.saveBuffersToTempFiles(baseRequestResponse),helpers.analyzeRequest(baseRequestResponse).getUrl(),"","","",temp_data,0,"run……",999)); 638 | conut += 1; 639 | fireTableRowsInserted(row, row); 640 | } 641 | 642 | //处理参数 643 | ListparaList= helpers.analyzeRequest(baseRequestResponse).getParameters(); 644 | byte[] new_Request = baseRequestResponse.getRequest(); 645 | int json_count = -1;//记录json嵌套次数 646 | 647 | //**************************************** 648 | // 循环获取参数 649 | //**************************************** 650 | String para_name = "";//用来记录上一次循环的参数名 651 | for (IParameter para : paraList){// 循环获取参数 652 | int switch_para = 0;//用来判断该参数是否要处理 0 要处理 1 跳过 653 | 654 | if(para.getType() == 6){ 655 | json_count += 1; 656 | } 657 | 658 | //payload 659 | ArrayList payloads = new ArrayList<>(); 660 | payloads.add("'"); 661 | payloads.add("''"); 662 | 663 | 664 | 665 | if (para.getType() == 0 || para.getType() == 1 || para.getType() == 6 || para.getType() == is_cookie){ //getTpe()就是来判断参数是在那个位置的 666 | String key = para.getName();//获取参数的名称 667 | String value = para.getValue();//获取参数的值 668 | stdout.println("\n\n原始数据:"+key+":"+value);//输出原始的键值数据 669 | 670 | if(is_int == 1){//开关,用于判断是否要开启-1、-0的操作 671 | if (value.matches("[0-9]+")) {//用于判读参数的值是否为纯数字 672 | payloads.add("-1"); 673 | payloads.add("-0"); 674 | } 675 | } 676 | 677 | //自定义payload 678 | if(JTextArea_int == 1){ 679 | String[] JTextArea_data = JTextArea_data_1.split("\n"); 680 | for(String a:JTextArea_data){ 681 | //stdout.println(a); 682 | //stdout.println("------"); 683 | payloads.add(a); 684 | } 685 | } 686 | 687 | int change = 0; //用于判断返回包长度是否一致、保存第一次请求响应的长度 688 | 689 | //**************************************** 690 | // 循环payload 691 | //**************************************** 692 | for (String payload : payloads) { 693 | int time_1 = 0,time_2 = 0; 694 | 695 | if(JTextArea_int == 1){ 696 | //自定义payload //参数值为空 697 | if(diy_payload_2 == 1){ 698 | if(payload != "'" && payload !="''" && payload != "-1" && payload != "-0"){ 699 | value = ""; 700 | } 701 | } 702 | } 703 | 704 | //stdout.println(key+":"+value+payload);//输出添加payload的键和值 705 | IHttpService iHttpService = baseRequestResponse.getHttpService(); 706 | 707 | //新的请求包 708 | IHttpRequestResponse requestResponse = null; //用于过if内的变量 709 | 710 | if(para.getType() == 6){ 711 | List headers = helpers.analyzeRequest(baseRequestResponse).getHeaders(); 712 | if(is_add ==1) { 713 | //json格式 714 | stdout.println("json"); 715 | String newBody = "{"; //json body的内容 716 | 717 | for (IParameter paras : paraList) {//循环所有参数,用来自定义json格式body做准备 718 | if (paras.getType() == 6) {//只要json格式的数据 719 | if (key == paras.getName() && value == paras.getValue()) {//判断现在的键和值是否是需要添加payload的键和值 720 | newBody += "\"" + paras.getName() + "\":" + "\"" + paras.getValue() + payload + "\",";//构造json的body 721 | } else { 722 | newBody += "\"" + paras.getName() + "\":" + "\"" + paras.getValue() + "\",";//构造json的body 723 | } 724 | } 725 | } 726 | 727 | newBody = newBody.substring(0, newBody.length() - 1); //去除最后一个, 728 | newBody += "}";//json body的内容 729 | 730 | byte[] bodyByte = newBody.getBytes(); 731 | byte[] new_Requests = helpers.buildHttpMessage(headers, bodyByte); //关键方法 732 | 733 | time_1 = (int) System.currentTimeMillis(); 734 | requestResponse = callbacks.makeHttpRequest(iHttpService, new_Requests);//发送请求 735 | time_2 = (int) System.currentTimeMillis(); 736 | }else if (is_add ==2){ 737 | //json嵌套 738 | //stdout.println("json嵌套"); 739 | 740 | request_data = request_data.replaceAll("\r","");//burp2.x json自动格式美化处理 741 | request_data = request_data.replaceAll("\n","");//burp2.x json自动格式美化处理 742 | 743 | String[] request_data_temp = request_data.split(",\"");//用于临时保存切割的post体内容 744 | String request_data_body = "";//连接字符串 745 | String request_data_body_temp = "";//修改后的body和需要临时编辑的字符串 746 | 747 | 748 | for(int i=0;i < request_data_temp.length;i++){ 749 | if(i==json_count){//判断现在修改的参数 750 | request_data_body_temp = request_data_temp[i]; 751 | 752 | stdout.println("准备修改的值:"+request_data_body_temp); 753 | while (true){ 754 | //空列表如:"test":[]跳过处理 755 | if(request_data_body_temp.contains(":[]")) { 756 | stdout.println(request_data_body_temp+"跳过"); 757 | request_data_body += "\""+request_data_temp[i]+",";//把跳过的字符串连接上 758 | json_count += 1; 759 | i += 1; 760 | request_data_body_temp = request_data_temp[i]; 761 | }else { 762 | break; 763 | } 764 | } 765 | 766 | 767 | //null、true、false等跳过处理 768 | if(request_data_body_temp.toLowerCase().contains(":null") || request_data_body_temp.toLowerCase().contains(":true") || request_data_body_temp.toLowerCase().contains(":false")) { 769 | stdout.println(request_data_body_temp+"跳过"); 770 | switch_para = 1; 771 | break; 772 | } 773 | 774 | 775 | if(request_data_body_temp.contains("\":")){ 776 | 777 | if(para.getName().equals(para_name)){ 778 | //处理json嵌套列表,这种情况只跑一次 779 | stdout.println("json嵌套列表,这个参数处理过了,跳过"); 780 | json_count -= 1; 781 | switch_para = 1; 782 | break; 783 | } 784 | 785 | //判断字符串中是否有":,如果有则为正常json内容 786 | Pattern p = Pattern.compile(".*:\\s?\\[?\\s?(.*?$)"); 787 | Matcher m = p.matcher(request_data_body_temp); 788 | if(m.find()){ 789 | request_data_body_temp = m.group(1);//获取:后面的内容 790 | } 791 | if(request_data_body_temp.contains("\"")){//判断内容是否为字符串 792 | request_data_body_temp = request_data_temp[i]; 793 | //修改内容,添加payload 794 | request_data_body_temp = request_data_body_temp.replaceAll("^(.*:.*?\")(.*?)(\"[^\"]*)$","$1$2"+payload+"$3"); 795 | stdout.println(request_data_body_temp); 796 | request_data_body+= "\""+request_data_body_temp +","; 797 | }else { 798 | request_data_body_temp = request_data_temp[i]; 799 | //修改内容,添加payload 纯数字 800 | request_data_body_temp = request_data_body_temp.replaceAll("^(.*:.*?)(\\d*)([^\"\\d]*)$","$1\"$2"+payload+"\"$3"); 801 | stdout.println(request_data_body_temp); 802 | request_data_body+= "\""+request_data_body_temp +","; 803 | } 804 | 805 | }else { 806 | stdout.println("处理过,无需处理"); 807 | switch_para = 1; 808 | if(para.getName().equals(para_name)){ 809 | //处理json嵌套列表,这种情况只跑一次 810 | stdout.println("json嵌套列表,已经处理过第一个值"); 811 | } 812 | break; 813 | 814 | /* 815 | //字符串中没有":,表示json格式中嵌套的列表 816 | 817 | if(request_data_body_temp.contains("\"")) {//判断内容是否为字符串 818 | //修改内容,添加payload 819 | request_data_body_temp = request_data_body_temp.replaceAll("^(\")(.*?)(\".*?)$","$1$2"+payload+"$3"); 820 | request_data_body+= "\""+request_data_body_temp +","; 821 | }else { 822 | //不是字符串,则为纯数字 823 | request_data_body_temp = request_data_body_temp.replaceAll("^(\\d*)(.*?)$","\"$1"+payload+"\"$2"); 824 | request_data_body+= "\""+request_data_body_temp +","; 825 | } 826 | */ 827 | } 828 | //stdout.println(request_data_body_temp); 829 | 830 | 831 | }else { 832 | request_data_body += "\""+request_data_temp[i]+","; 833 | } 834 | } 835 | 836 | if(switch_para == 1){ 837 | //跳过这个参数 838 | break; 839 | } 840 | if(para.getName().equals(para_name)){ 841 | //处理json嵌套列表,这种情况只跑一次 842 | stdout.println("json嵌套列表,已经处理过第一个值!!!!"); 843 | } 844 | 845 | 846 | request_data_body = request_data_body.substring(0, request_data_body.length() - 1); //去除最后一个, 847 | request_data_body = request_data_body.substring(1,request_data_body.length()); //去除第一个" 848 | 849 | byte[] bodyByte = request_data_body.getBytes(); 850 | byte[] new_Requests = helpers.buildHttpMessage(headers, bodyByte); //关键方法 851 | time_1 = (int) System.currentTimeMillis(); 852 | requestResponse = callbacks.makeHttpRequest(iHttpService, new_Requests);//发送请求 853 | time_2 = (int) System.currentTimeMillis(); 854 | 855 | } 856 | }else { 857 | stdout.println("普通格式"); 858 | //不是json格式 859 | IParameter newPara = helpers.buildParameter(key,value + payload, para.getType()); //构造新的参数 860 | byte[] newRequest = helpers.updateParameter(new_Request, newPara);//更新请求包的参数 861 | 862 | time_1 = (int) System.currentTimeMillis(); 863 | requestResponse = callbacks.makeHttpRequest(iHttpService, newRequest);//发送请求 864 | time_2 = (int) System.currentTimeMillis(); 865 | 866 | } 867 | 868 | //判断数据长度是否会变化 869 | String change_sign;//第二个表格中 变化 的内容 870 | if(payload == "'" || payload == "-1" || change == 0){ 871 | change = requestResponse.getResponse().length;//保存第一次请求响应的长度 872 | change_sign = ""; 873 | }else{ 874 | if(payload == "''" || payload == "-0" ){ 875 | if(change != requestResponse.getResponse().length){//判断第一次的长度和现在的是否不同 876 | if(payload == "''" && requestResponse.getResponse().length == original_data_len || payload == "-0" && requestResponse.getResponse().length == original_data_len){//判断两个单引号的长度和第一次的不一样且和原始包的长度一致 877 | //原始包的长度和两个双引号的长度相同且和一个单引号的长度不同 878 | change_sign = "✔ ==> ?"; 879 | change_sign_1 = " ✔"; 880 | }else{ 881 | //第一次的包和第二次包的长度不同 882 | change_sign = "✔ "+ (change-requestResponse.getResponse().length); 883 | change_sign_1 = " ✔"; 884 | } 885 | }else { 886 | //第一次包和第二次包的长度一样 887 | change_sign = ""; 888 | } 889 | }else { 890 | //自定义payload 891 | if(time_2-time_1 >= 3000){ 892 | //响应时间大于3秒 893 | change_sign = "time > 3"; 894 | change_sign_1 = " ✔"; 895 | }else { 896 | change_sign = "diy payload"; 897 | } 898 | } 899 | 900 | } 901 | //把响应内容保存在log2中 902 | log2.add(new LogEntry(conut,toolFlag, callbacks.saveBuffersToTempFiles(requestResponse),helpers.analyzeRequest(requestResponse).getUrl(),key,value+payload,change_sign,temp_data,time_2-time_1,"end",helpers.analyzeResponse(requestResponse.getResponse()).getStatusCode())); 903 | 904 | } 905 | } 906 | para_name = para.getName();//用于判断json嵌套里面有列表,列表中带值只跑一次 907 | stdout.println(json_count); 908 | 909 | } 910 | 911 | //用于更新是否已经跑完所有payload的状态 912 | for(int i = 0; i < log.size(); i++){ 913 | if(temp_data.equals(log.get(i).data_md5)){ 914 | log.get(i).setState("end!"+change_sign_1); 915 | //stdout.println("ok"); 916 | } 917 | } 918 | 919 | //刷新第一个列表框 920 | //BurpExtender.this.fireTableRowsInserted(log.size(), log.size()); 921 | BurpExtender.this.fireTableDataChanged(); 922 | //第一个表格 继续选中之前选中的值 923 | BurpExtender.this.logTable.setRowSelectionInterval(BurpExtender.this.select_row,BurpExtender.this.select_row); 924 | 925 | 926 | 927 | } 928 | 929 | @Override 930 | public List doActiveScan(IHttpRequestResponse baseRequestResponse, IScannerInsertionPoint insertionPoint) { 931 | return null; 932 | } 933 | 934 | @Override 935 | public int consolidateDuplicateIssues(IScanIssue existingIssue, IScanIssue newIssue) { 936 | if (existingIssue.getIssueName().equals(newIssue.getIssueName())) 937 | return -1; 938 | else return 0; 939 | } 940 | // 941 | // extend AbstractTableModel 942 | // 943 | 944 | @Override 945 | public int getRowCount() 946 | { 947 | return log.size(); 948 | 949 | } 950 | 951 | @Override 952 | public int getColumnCount() 953 | { 954 | return 5; 955 | } 956 | 957 | @Override 958 | public String getColumnName(int columnIndex) 959 | { 960 | switch (columnIndex) 961 | { 962 | case 0: 963 | return "#"; 964 | case 1: 965 | return "来源"; 966 | case 2: 967 | return "URL"; 968 | case 3: 969 | return "返回包长度"; 970 | case 4: 971 | return "状态"; 972 | default: 973 | return ""; 974 | } 975 | } 976 | 977 | @Override 978 | public Class getColumnClass(int columnIndex) 979 | { 980 | return String.class; 981 | } 982 | 983 | @Override 984 | public Object getValueAt(int rowIndex, int columnIndex) 985 | { 986 | LogEntry logEntry = log.get(rowIndex); 987 | 988 | switch (columnIndex) 989 | { 990 | case 0: 991 | return logEntry.id; 992 | case 1: 993 | return callbacks.getToolName(logEntry.tool); 994 | case 2: 995 | return logEntry.url.toString(); 996 | case 3: 997 | return logEntry.requestResponse.getResponse().length;//返回响应包的长度 998 | case 4: 999 | return logEntry.state; 1000 | default: 1001 | return ""; 1002 | } 1003 | } 1004 | 1005 | 1006 | //model2 1007 | class MyModel extends AbstractTableModel { 1008 | 1009 | @Override 1010 | public int getRowCount() 1011 | { 1012 | return log3.size(); 1013 | } 1014 | 1015 | @Override 1016 | public int getColumnCount() 1017 | { 1018 | return 6; 1019 | } 1020 | 1021 | @Override 1022 | public String getColumnName(int columnIndex) 1023 | { 1024 | switch (columnIndex) 1025 | { 1026 | case 0: 1027 | return "参数"; 1028 | case 1: 1029 | return "payload"; 1030 | case 2: 1031 | return "返回包长度"; 1032 | case 3: 1033 | return "变化"; 1034 | case 4: 1035 | return "用时"; 1036 | case 5: 1037 | return "响应码"; 1038 | default: 1039 | return ""; 1040 | } 1041 | } 1042 | 1043 | @Override 1044 | public Class getColumnClass(int columnIndex) 1045 | { 1046 | return String.class; 1047 | } 1048 | 1049 | @Override 1050 | public Object getValueAt(int rowIndex, int columnIndex) 1051 | { 1052 | LogEntry logEntry2 = log3.get(rowIndex); 1053 | 1054 | switch (columnIndex) 1055 | { 1056 | case 0: 1057 | return logEntry2.parameter; 1058 | case 1: 1059 | return logEntry2.value; 1060 | case 2: 1061 | return logEntry2.requestResponse.getResponse().length;//返回响应包的长度 1062 | case 3: 1063 | return logEntry2.change; 1064 | case 4: 1065 | return logEntry2.times; 1066 | case 5: 1067 | return logEntry2.response_code; 1068 | default: 1069 | return ""; 1070 | } 1071 | } 1072 | } 1073 | 1074 | 1075 | 1076 | 1077 | // 1078 | // implement IMessageEditorController 1079 | // this allows our request/response viewers to obtain details about the messages being displayed 1080 | // 1081 | 1082 | @Override 1083 | public byte[] getRequest() 1084 | { 1085 | return currentlyDisplayedItem.getRequest(); 1086 | } 1087 | 1088 | @Override 1089 | public byte[] getResponse() 1090 | { 1091 | return currentlyDisplayedItem.getResponse(); 1092 | } 1093 | 1094 | @Override 1095 | public IHttpService getHttpService() 1096 | { 1097 | return currentlyDisplayedItem.getHttpService(); 1098 | } 1099 | 1100 | // 1101 | // extend JTable to handle cell selection 1102 | // 1103 | 1104 | private class Table extends JTable 1105 | { 1106 | public Table(TableModel tableModel) 1107 | { 1108 | super(tableModel); 1109 | } 1110 | 1111 | @Override 1112 | public void changeSelection(int row, int col, boolean toggle, boolean extend) 1113 | { 1114 | // show the log entry for the selected row 1115 | LogEntry logEntry = log.get(row); 1116 | data_md5_id = logEntry.data_md5; 1117 | //stdout.println(log_id);//输出目前选中的行数 1118 | select_row = logEntry.id; 1119 | 1120 | log3.clear(); 1121 | for (int i = 0; i < log2.size(); i++) {//筛选出目前选中的原始数据包--》衍生出的带有payload的数据包 1122 | if(log2.get(i).data_md5==data_md5_id){ 1123 | log3.add(log2.get(i)); 1124 | } 1125 | } 1126 | //刷新列表界面 1127 | model.fireTableRowsInserted(log3.size(), log3.size()); 1128 | model.fireTableDataChanged(); 1129 | 1130 | requestViewer.setMessage(logEntry.requestResponse.getRequest(), true); 1131 | responseViewer.setMessage(logEntry.requestResponse.getResponse(), false); 1132 | currentlyDisplayedItem = logEntry.requestResponse; 1133 | 1134 | super.changeSelection(row, col, toggle, extend); 1135 | } 1136 | } 1137 | 1138 | private class Table_log2 extends JTable 1139 | { 1140 | public Table_log2(TableModel tableModel) 1141 | { 1142 | super(tableModel); 1143 | } 1144 | 1145 | @Override 1146 | public void changeSelection(int row, int col, boolean toggle, boolean extend) 1147 | { 1148 | 1149 | // show the log entry for the selected row 1150 | LogEntry logEntry = log3.get(row); 1151 | requestViewer.setMessage(logEntry.requestResponse.getRequest(), true); 1152 | responseViewer.setMessage(logEntry.requestResponse.getResponse(), false); 1153 | currentlyDisplayedItem = logEntry.requestResponse; 1154 | 1155 | super.changeSelection(row, col, toggle, extend); 1156 | } 1157 | } 1158 | 1159 | //存放数据包的md5值,用于匹配该数据包已请求过 1160 | private static class Request_md5 1161 | { 1162 | final String md5_data; 1163 | 1164 | Request_md5(String md5_data) 1165 | { 1166 | this.md5_data = md5_data; 1167 | } 1168 | } 1169 | // 1170 | // class to hold details of each log entry 1171 | // 1172 | private static class LogEntry 1173 | { 1174 | final int id; 1175 | final int tool; 1176 | final IHttpRequestResponsePersisted requestResponse; 1177 | final URL url; 1178 | final String parameter; 1179 | final String value; 1180 | final String change; 1181 | final String data_md5; 1182 | final int times; 1183 | final int response_code; 1184 | String state; 1185 | 1186 | 1187 | LogEntry(int id,int tool, IHttpRequestResponsePersisted requestResponse, URL url,String parameter,String value,String change,String data_md5,int times,String state,int response_code) 1188 | { 1189 | this.id = id; 1190 | this.tool = tool; 1191 | this.requestResponse = requestResponse; 1192 | this.url = url; 1193 | this.parameter = parameter; 1194 | this.value = value; 1195 | this.change = change; 1196 | this.data_md5 = data_md5; 1197 | this.times = times; 1198 | this.state = state; 1199 | this.response_code = response_code; 1200 | } 1201 | 1202 | public String setState(String state){ 1203 | this.state = state; 1204 | return this.state; 1205 | } 1206 | } 1207 | 1208 | public static String MD5(String key) { 1209 | char hexDigits[] = { 1210 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' 1211 | }; 1212 | try { 1213 | byte[] btInput = key.getBytes(); 1214 | // 获得MD5摘要算法的 MessageDigest 对象 1215 | MessageDigest mdInst = MessageDigest.getInstance("MD5"); 1216 | // 使用指定的字节更新摘要 1217 | mdInst.update(btInput); 1218 | // 获得密文 1219 | byte[] md = mdInst.digest(); 1220 | // 把密文转换成十六进制的字符串形式 1221 | int j = md.length; 1222 | char str[] = new char[j * 2]; 1223 | int k = 0; 1224 | for (int i = 0; i < j; i++) { 1225 | byte byte0 = md[i]; 1226 | str[k++] = hexDigits[byte0 >>> 4 & 0xf]; 1227 | str[k++] = hexDigits[byte0 & 0xf]; 1228 | } 1229 | return new String(str); 1230 | } catch (Exception e) { 1231 | return null; 1232 | } 1233 | } 1234 | 1235 | 1236 | } 1237 | --------------------------------------------------------------------------------