diff --git a/pom.xml b/pom.xml
index e1c2154..6184dc2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -151,6 +151,14 @@
2.0b5
+
+
+ commons-validator
+ commons-validator
+ 1.8.0
+
+
+
knife
diff --git a/src/burp/BurpExtender.java b/src/burp/BurpExtender.java
index 8c5243c..3bf7387 100644
--- a/src/burp/BurpExtender.java
+++ b/src/burp/BurpExtender.java
@@ -41,6 +41,7 @@
import manager.ChunkManager;
import manager.DismissedTargetsManager;
import manager.HeaderManager;
+import org.apache.commons.lang3.StringUtils;
public class BurpExtender extends GUI implements IBurpExtender, IContextMenuFactory, ITab, IHttpListener, IProxyListener, IExtensionStateListener {
@@ -54,7 +55,6 @@ public class BurpExtender extends GUI implements IBurpExtender, IContextMenuFact
public static PrintWriter stdout;
public static PrintWriter stderr;
public IContextMenuInvocation invocation;
- public int proxyServerIndex = -1;
public static String ExtensionName = "Knife";
public static String Version = bsh.This.class.getPackage().getImplementationVersion();
@@ -75,15 +75,12 @@ public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) {
configPanel.setViewportView(table);
String content = callbacks.loadExtensionSetting("knifeconfig");
- if (content != null) {
- config = new Gson().fromJson(content, Config.class);
- showToUI(config);
- } else {
- showToUI(new Gson().fromJson(initConfig(), Config.class));
+ if (StringUtils.isEmpty(content)) {
+ content = initConfig();
}
- table.setupTypeColumn();//call this function must after table data loaded !!!!
- table.tableHeaderLengthInit();
+ config = new Gson().fromJson(content, Config.class);
+ showToUI(config);
ChineseTabFactory chntabFactory = new ChineseTabFactory(null, false, helpers, callbacks);
@@ -171,7 +168,7 @@ public List createMenuItems(IContextMenuInvocation invocation) {
Iterator it = menu_item_list.iterator();
while (it.hasNext()) {
JMenuItem item = it.next();
- if (item.getText() == null || item.getText().equals("")) {
+ if (StringUtils.isEmpty(item.getText())) {
it.remove();
}
}
@@ -306,41 +303,6 @@ public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequ
}
}
- public static void confirmProxy() {
- String proxy = JOptionPane.showInputDialog("Confirm Proxy Of Burp", "127.0.0.1:8080");
- if (proxy != null) {
- BurpExtender.CurrentProxy = proxy.trim();
- }
- }
-
- public static String getProxyHost() {
- try {
- if (CurrentProxy == null || CurrentProxy.equals("") || CurrentProxy.split(":").length != 2) {
- confirmProxy();
- }
- String proxyHost = CurrentProxy.split(":")[0];
- return proxyHost;
- } catch (Exception e) {
- e.printStackTrace();
- CurrentProxy = "";//设置为空,以便重新获取。
- return null;
- }
- }
-
- public static int getProxyPort() {
- try {
- if (CurrentProxy == null || CurrentProxy.equals("") || CurrentProxy.split(":").length != 2) {
- confirmProxy();
- }
- String proxyPort = CurrentProxy.split(":")[1];
- return Integer.parseInt(proxyPort);
- } catch (Exception e) {
- e.printStackTrace();
- CurrentProxy = "";//设置为空,以便重新获取。
- return -1;
- }
- }
-
public List GetSetCookieHeaders(String cookies) {
if (cookies.startsWith("Cookie: ")) {
cookies = cookies.replaceFirst("Cookie: ", "");
diff --git a/src/burp/Proxy.java b/src/burp/Proxy.java
new file mode 100644
index 0000000..a1094df
--- /dev/null
+++ b/src/burp/Proxy.java
@@ -0,0 +1,82 @@
+package burp;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.validator.routines.DomainValidator;
+import org.apache.commons.validator.routines.InetAddressValidator;
+
+import javax.swing.*;
+
+public class Proxy {
+
+ String host;
+ int port;
+
+ public Proxy(String proxyStr) throws IllegalArgumentException {
+ if (StringUtils.isEmpty(proxyStr)) {
+ throw new IllegalArgumentException("input is empty");
+ }
+ try {
+ String[] parts = proxyStr.split(":");
+ if (parts.length != 2) {
+ throw new IllegalArgumentException("not valid host:port format");
+ }
+ host = parts[0];
+ if (!isValidIPAddress(host) && !isValidDomainName(host)) {
+ throw new IllegalArgumentException("host is not valid IP address and domain name");
+ }
+ String portStr = parts[1];
+ port = Integer.parseInt(portStr);
+ if (port >= 0 && port <= 65535) {
+ throw new IllegalArgumentException("invalid port range");
+ }
+ } catch (Exception e) {
+ throw new IllegalArgumentException(e.getMessage());
+ }
+ }
+
+ // 检查是否是合法的IP地址
+ public static boolean isValidIPAddress(String ipAddress) {
+ InetAddressValidator validator = InetAddressValidator.getInstance();
+ return validator.isValidInet4Address(ipAddress);
+ }
+
+ // 检查是否是合法的域名
+ public static boolean isValidDomainName(String domainName) {
+ DomainValidator validator = DomainValidator.getInstance();
+ return validator.isValid(domainName);
+ }
+
+ public static Proxy inputProxy() {
+ int retry = 3;
+ while (retry > 0) {
+ String proxy = JOptionPane.showInputDialog("Confirm Proxy Of Burp", "127.0.0.1:8080");
+ try {
+ return new Proxy(proxy);
+ } catch (IllegalArgumentException e) {
+ BurpExtender.getStderr().println(e);
+ retry = retry - 1;
+ }
+ }
+ return null;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ public String getProxyStr() {
+ return host + ":" + port;
+ }
+}
diff --git a/src/config/GUI.java b/src/config/GUI.java
index 6a5b46d..7ea1825 100644
--- a/src/config/GUI.java
+++ b/src/config/GUI.java
@@ -417,7 +417,10 @@ public void showToUI(Config config) {
ConfigEntry entry = new ConfigEntry().FromJson(stringEntry);
tableModel.addNewConfigEntry(entry);
}
- table.setupTypeColumn();// must setup again when data cleaned
+
+ table.setupTypeColumn();
+ //call this function must after table data loaded !!!!
+ // must setup again when data cleaned
table.tableHeaderLengthInit();
diff --git a/src/knife/FindUrlAndRequest.java b/src/knife/FindUrlAndRequest.java
index e8acefa..17a14d1 100644
--- a/src/knife/FindUrlAndRequest.java
+++ b/src/knife/FindUrlAndRequest.java
@@ -18,250 +18,241 @@
import base.RequestTask;
import base.RequestType;
-import burp.BurpExtender;
-import burp.HelperPlus;
-import burp.IBurpExtenderCallbacks;
-import burp.IContextMenuInvocation;
-import burp.IExtensionHelpers;
-import burp.IHttpRequestResponse;
-import burp.Utils;
-import burp.threadRequester;
+import burp.*;
+import org.apache.commons.lang3.StringUtils;
public class FindUrlAndRequest extends JMenuItem {
- /**
- *
- */
- private static final long serialVersionUID = 1L;
-
- //JMenuItem vs. JMenu
- public FindUrlAndRequest(BurpExtender burp){
- this.setText("^_^ Find URL And Request");
- this.addActionListener(new FindUrl_Action(burp,burp.invocation));
- }
-
- public static void main(String[] args) {
- String url = "./abac/aaa.jpg";
- if (url.startsWith("./")) {
- url = url.replaceFirst("\\./", "");
- }
- System.out.println(url);
- }
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ //JMenuItem vs. JMenu
+ public FindUrlAndRequest(BurpExtender burp) {
+ this.setText("^_^ Find URL And Request");
+ this.addActionListener(new FindUrl_Action(burp, burp.invocation));
+ }
+
+ public static void main(String[] args) {
+ String url = "./abac/aaa.jpg";
+ if (url.startsWith("./")) {
+ url = url.replaceFirst("\\./", "");
+ }
+ System.out.println(url);
+ }
}
-class FindUrl_Action implements ActionListener{
- private IContextMenuInvocation invocation;
- public IExtensionHelpers helpers;
- public PrintWriter stdout;
- public PrintWriter stderr;
- public IBurpExtenderCallbacks callbacks;
- public BurpExtender burp;
- public static final String[] blackHostList = {"www.w3.org","ns.adobe.com","iptc.org","openoffice.org"
- ,"schemas.microsoft.com","schemas.openxmlformats.org","sheetjs.openxmlformats.org"};
-
- public FindUrl_Action(BurpExtender burp,IContextMenuInvocation invocation) {
- this.burp = burp;
- this.invocation = invocation;
- this.helpers = burp.helpers;
- this.callbacks = BurpExtender.callbacks;
- this.stderr = BurpExtender.stderr;
- this.stdout = BurpExtender.stdout;
- }
-
- @Override
- public void actionPerformed(ActionEvent event) {
- Runnable requestRunner = new Runnable() {
- String siteBaseUrl = null;
- Set baseUrls = new HashSet();
- List urls = new ArrayList();
- @Override
- public void run() {
- try{
- IHttpRequestResponse[] messages = invocation.getSelectedMessages();
- if (messages == null || messages.length <=0) {
- return;
- }
-
- BlockingQueue inputQueue = new LinkedBlockingQueue();
-
- try {
- findUrls(messages[0]);
-
- if (baseUrls.size() <=0) {
- return;
- }
- String baseurl = choseAndEditBaseURL(baseUrls);
-
- if (null==baseurl) {
- return;
- }
-
- for (String url:urls) {
- if (Utils.uselessExtension(url)) {
- continue;
- }
- if (!url.startsWith("http://") && !url.startsWith("https://")) {
- if (url.startsWith("/")) {
- url = url.replaceFirst("/", "");
- }
- if (url.startsWith("./")) {
- url = url.replaceFirst("\\./", "");
- }
- url = baseurl+url; //baseurl统一以“/”结尾;url统一删除“/”的开头
- inputQueue.put(new RequestTask(url,RequestType.GET));
- inputQueue.put(new RequestTask(url,RequestType.POST));
- inputQueue.put(new RequestTask(url,RequestType.JSON));
- }
- }
- } catch (Exception e) {
- e.printStackTrace(BurpExtender.getStderr());
- }
-
- doRequest(inputQueue,siteBaseUrl);
- }
- catch (Exception e1)
- {
- e1.printStackTrace(stderr);
- }
- }
-
-
- /**
- * 根据当前web的baseUrl找JS,特征就是referer以它开头
- * @param currentBaseUrl
- * @return
- */
- public void findUrls(IHttpRequestResponse message){
- HelperPlus getter = new HelperPlus(helpers);
-
- String current_referUrl = getter.getHeaderValueOf(true,message,"Referer");
- String current_fullUrl = getter.getFullURL(message).toString();
-
- if (current_referUrl != null) {
- baseUrls.add(current_referUrl);
- }
- baseUrls.add(current_fullUrl);
-
- if (current_fullUrl != null) {
- siteBaseUrl = Utils.getBaseUrl(current_referUrl);
- }
- if (siteBaseUrl == null) {
- siteBaseUrl = Utils.getBaseUrl(current_fullUrl);
- }
-
-
- IHttpRequestResponse[] messages = BurpExtender.getCallbacks().getSiteMap(null);
- for (IHttpRequestResponse item:messages) {
- int code = getter.getStatusCode(item);
- URL url = getter.getFullURL(item);
- String referUrl = getter.getHeaderValueOf(true,item,"Referer");
- if (referUrl == null || url== null || code <=0) {
- continue;
- }
- if (!url.toString().toLowerCase().endsWith(".js")) {
- continue;
- }
- if (referUrl.toLowerCase().startsWith(siteBaseUrl.toLowerCase()+"/")) {
- byte[] respBody = getter.getBody(false, item);
- String body = new String(respBody);
- urls.addAll(Utils.grepURL(body));
- baseUrls.addAll(findPossibleBaseURL(urls));
- }
- }
- }
-
- };
- new Thread(requestRunner).start();
- }
-
-
-
-
- /**
- * 多线程执行请求
- * @param inputQueue
- */
- public void doRequest(BlockingQueue inputQueue,String referUrl) {
- String proxyHost = BurpExtender.getProxyHost();
- int proxyPort = BurpExtender.getProxyPort();
-
- if (proxyHost == null || proxyPort == -1) {
- return;
- }
-
- int max = threadNumberShouldUse(inputQueue.size());
-
- for (int i=0;i<=max;i++) {
- threadRequester requester = new threadRequester(inputQueue,proxyHost,proxyPort,referUrl,i);
- requester.start();
- }
- }
-
- /**
- * 根据已有的域名梳理,预估应该使用的线程数
- * 假设1个任务需要1秒钟。线程数在1-100之间,如何选择线程数使用最小的时间?
- * @param domains
- * @return
- */
- public static int threadNumberShouldUse(int domainNum) {
-
- int tmp = (int) Math.sqrt(domainNum);
- if (tmp <=1) {
- return 1;
- }else if(tmp>=10) {
- return 10;
- }else {
- return tmp;
- }
- }
-
- public static Set findPossibleBaseURL(List urls) {
- Set baseURLs = new HashSet();
- for (String tmpurl:urls) {
- //这部分提取的是含有协议头的完整URL地址
- if (tmpurl.toLowerCase().startsWith("http://")
- ||tmpurl.toLowerCase().startsWith("https://")){
-
- try {
- String host= new URL(tmpurl).getHost();
- if (Arrays.asList(blackHostList).contains(host)) {
- continue;
- }
- }catch(Exception E) {
- continue;
- }
-
- baseURLs.add(tmpurl);
- }
- }
- return baseURLs;
- }
-
- public static String choseAndEditBaseURL(Set inputs) {
-
- ArrayList tmpList = new ArrayList(inputs);
- Collections.sort(tmpList);
- int n = inputs.size()+1;
- String[] possibleValues = new String[n];
-
- // Copying contents of domains to arr[]
- System.arraycopy(tmpList.toArray(), 0, possibleValues, 0, n-1);
- possibleValues[n-1] = "Let Me Input";
-
- String selectedValue = (String) JOptionPane.showInputDialog(null,
- "Chose Base URL", "Chose And Edit Base URL",
- JOptionPane.INFORMATION_MESSAGE, null,
- possibleValues, possibleValues[0]);
- if (null != selectedValue) {
- String baseUrl = JOptionPane.showInputDialog("Confirm The Base URL", selectedValue);
- if (baseUrl == null) {
- return null;
- }
- if (!baseUrl.endsWith("/")) {
- baseUrl = baseUrl.trim()+"/";
- }
- return baseUrl.trim();
- }
- return selectedValue;
- }
+class FindUrl_Action implements ActionListener {
+ private IContextMenuInvocation invocation;
+ public IExtensionHelpers helpers;
+ public PrintWriter stdout;
+ public PrintWriter stderr;
+ public IBurpExtenderCallbacks callbacks;
+ public BurpExtender burp;
+ public static final String[] blackHostList = {"www.w3.org", "ns.adobe.com", "iptc.org", "openoffice.org"
+ , "schemas.microsoft.com", "schemas.openxmlformats.org", "sheetjs.openxmlformats.org"};
+
+ public FindUrl_Action(BurpExtender burp, IContextMenuInvocation invocation) {
+ this.burp = burp;
+ this.invocation = invocation;
+ this.helpers = burp.helpers;
+ this.callbacks = BurpExtender.callbacks;
+ this.stderr = BurpExtender.stderr;
+ this.stdout = BurpExtender.stdout;
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ Runnable requestRunner = new Runnable() {
+ String siteBaseUrl = null;
+ Set baseUrls = new HashSet();
+ List urls = new ArrayList();
+
+ @Override
+ public void run() {
+ try {
+ IHttpRequestResponse[] messages = invocation.getSelectedMessages();
+ if (messages == null || messages.length <= 0) {
+ return;
+ }
+
+ BlockingQueue inputQueue = new LinkedBlockingQueue();
+
+ try {
+ findUrls(messages[0]);
+
+ if (baseUrls.size() <= 0) {
+ return;
+ }
+ String baseurl = choseAndEditBaseURL(baseUrls);
+
+ if (null == baseurl) {
+ return;
+ }
+
+ for (String url : urls) {
+ if (Utils.uselessExtension(url)) {
+ continue;
+ }
+ if (!url.startsWith("http://") && !url.startsWith("https://")) {
+ if (url.startsWith("/")) {
+ url = url.replaceFirst("/", "");
+ }
+ if (url.startsWith("./")) {
+ url = url.replaceFirst("\\./", "");
+ }
+ url = baseurl + url; //baseurl统一以“/”结尾;url统一删除“/”的开头
+ inputQueue.put(new RequestTask(url, RequestType.GET));
+ inputQueue.put(new RequestTask(url, RequestType.POST));
+ inputQueue.put(new RequestTask(url, RequestType.JSON));
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace(BurpExtender.getStderr());
+ }
+
+ doRequest(inputQueue, siteBaseUrl);
+ } catch (Exception e1) {
+ e1.printStackTrace(stderr);
+ }
+ }
+
+
+ /**
+ * 根据当前web的baseUrl找JS,特征就是referer以它开头
+ * @param currentBaseUrl
+ * @return
+ */
+ public void findUrls(IHttpRequestResponse message) {
+ HelperPlus getter = new HelperPlus(helpers);
+
+ String current_referUrl = getter.getHeaderValueOf(true, message, "Referer");
+ String current_fullUrl = getter.getFullURL(message).toString();
+
+ if (current_referUrl != null) {
+ baseUrls.add(current_referUrl);
+ }
+ baseUrls.add(current_fullUrl);
+
+ if (current_fullUrl != null) {
+ siteBaseUrl = Utils.getBaseUrl(current_referUrl);
+ }
+ if (siteBaseUrl == null) {
+ siteBaseUrl = Utils.getBaseUrl(current_fullUrl);
+ }
+
+
+ IHttpRequestResponse[] messages = BurpExtender.getCallbacks().getSiteMap(null);
+ for (IHttpRequestResponse item : messages) {
+ int code = getter.getStatusCode(item);
+ URL url = getter.getFullURL(item);
+ String referUrl = getter.getHeaderValueOf(true, item, "Referer");
+ if (referUrl == null || url == null || code <= 0) {
+ continue;
+ }
+ if (!url.toString().toLowerCase().endsWith(".js")) {
+ continue;
+ }
+ if (referUrl.toLowerCase().startsWith(siteBaseUrl.toLowerCase() + "/")) {
+ byte[] respBody = getter.getBody(false, item);
+ String body = new String(respBody);
+ urls.addAll(Utils.grepURL(body));
+ baseUrls.addAll(findPossibleBaseURL(urls));
+ }
+ }
+ }
+
+ };
+ new Thread(requestRunner).start();
+ }
+
+
+ /**
+ * 多线程执行请求
+ *
+ * @param inputQueue
+ */
+ public void doRequest(BlockingQueue inputQueue, String referUrl) {
+ Proxy proxy = Proxy.inputProxy();
+ if (proxy == null) {
+ return;
+ }
+
+ int max = threadNumberShouldUse(inputQueue.size());
+
+ for (int i = 0; i <= max; i++) {
+ threadRequester requester = new threadRequester(inputQueue, proxy.getHost(), proxy.getPort(), referUrl, i);
+ requester.start();
+ }
+ }
+
+ /**
+ * 根据已有的域名梳理,预估应该使用的线程数
+ * 假设1个任务需要1秒钟。线程数在1-100之间,如何选择线程数使用最小的时间?
+ *
+ * @param domains
+ * @return
+ */
+ public static int threadNumberShouldUse(int domainNum) {
+
+ int tmp = (int) Math.sqrt(domainNum);
+ if (tmp <= 1) {
+ return 1;
+ } else if (tmp >= 10) {
+ return 10;
+ } else {
+ return tmp;
+ }
+ }
+
+ public static Set findPossibleBaseURL(List urls) {
+ Set baseURLs = new HashSet();
+ for (String tmpurl : urls) {
+ //这部分提取的是含有协议头的完整URL地址
+ if (tmpurl.toLowerCase().startsWith("http://")
+ || tmpurl.toLowerCase().startsWith("https://")) {
+
+ try {
+ String host = new URL(tmpurl).getHost();
+ if (Arrays.asList(blackHostList).contains(host)) {
+ continue;
+ }
+ } catch (Exception E) {
+ continue;
+ }
+
+ baseURLs.add(tmpurl);
+ }
+ }
+ return baseURLs;
+ }
+
+ public static String choseAndEditBaseURL(Set inputs) {
+
+ ArrayList tmpList = new ArrayList(inputs);
+ Collections.sort(tmpList);
+ int n = inputs.size() + 1;
+ String[] possibleValues = new String[n];
+
+ // Copying contents of domains to arr[]
+ System.arraycopy(tmpList.toArray(), 0, possibleValues, 0, n - 1);
+ possibleValues[n - 1] = "Let Me Input";
+
+ String selectedValue = (String) JOptionPane.showInputDialog(null,
+ "Chose Base URL", "Chose And Edit Base URL",
+ JOptionPane.INFORMATION_MESSAGE, null,
+ possibleValues, possibleValues[0]);
+ if (null != selectedValue) {
+ String baseUrl = JOptionPane.showInputDialog("Confirm The Base URL", selectedValue);
+ if (baseUrl == null) {
+ return null;
+ }
+ if (!baseUrl.endsWith("/")) {
+ baseUrl = baseUrl.trim() + "/";
+ }
+ return baseUrl.trim();
+ }
+ return selectedValue;
+ }
}