diff --git a/src/main/java/org/joychou/controller/SSRF.java b/src/main/java/org/joychou/controller/SSRF.java index e9c30d0e..12384717 100644 --- a/src/main/java/org/joychou/controller/SSRF.java +++ b/src/main/java/org/joychou/controller/SSRF.java @@ -1,19 +1,9 @@ package org.joychou.controller; -import com.squareup.okhttp.OkHttpClient; -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.methods.GetMethod; -import org.apache.commons.io.IOUtils; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.client.fluent.Request; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; import org.joychou.security.SecurityUtil; +import org.joychou.security.ssrf.SSRFException; +import org.joychou.util.HttpUtils; import org.joychou.util.WebUtils; -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.RequestMapping; @@ -21,8 +11,6 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; - -import javax.imageio.ImageIO; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.net.*; @@ -40,58 +28,58 @@ public class SSRF { private static Logger logger = LoggerFactory.getLogger(SSRF.class); - @RequestMapping("/urlConnection") - public static String ssrf_URLConnection(@RequestParam String url) { - try { - URL u = new URL(url); - URLConnection urlConnection = u.openConnection(); - BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); //send request - String inputLine; - StringBuilder html = new StringBuilder(); - while ((inputLine = in.readLine()) != null) { - html.append(inputLine); - } - in.close(); - return html.toString(); - } catch (Exception e) { - logger.error(e.toString()); - return "fail"; + @RequestMapping("/urlConnection/vuln") + public static String URLConnectionVuln(String url) { + return HttpUtils.URLConnection(url); + } + + + @RequestMapping("/urlConnection/sec") + public static String URLConnectionSec(String url) { + + // Decline not http/https protocol + if (!url.startsWith("http://") && !url.startsWith("https://")) { + return "[-] SSRF check failed"; } + + try { + SecurityUtil.startSSRFHook(); + return HttpUtils.URLConnection(url); + } catch (SSRFException | IOException e) { + return e.getMessage(); + } finally { + SecurityUtil.stopSSRFHook(); + } + } - @RequestMapping("/HttpURLConnection") + @RequestMapping("/HttpURLConnection/sec") @ResponseBody - public static String ssrf_httpURLConnection(@RequestParam String url) { + public static String httpURLConnection(@RequestParam String url) { try { - URL u = new URL(url); - URLConnection urlConnection = u.openConnection(); - HttpURLConnection httpUrl = (HttpURLConnection) urlConnection; - BufferedReader in = new BufferedReader(new InputStreamReader(httpUrl.getInputStream())); //send request - String inputLine; - StringBuilder html = new StringBuilder(); - - while ((inputLine = in.readLine()) != null) { - html.append(inputLine); - } - in.close(); - return html.toString(); - } catch (Exception e) { - logger.error(e.toString()); - return "fail"; + SecurityUtil.startSSRFHook(); + return HttpUtils.HTTPURLConnection(url); + } catch (SSRFException | IOException e) { + return e.getMessage(); + } finally { + SecurityUtil.stopSSRFHook(); } } - @RequestMapping("/Request") + // http://localhost:8080/ssrf/request/sec?url=http://www.baidu.com + @RequestMapping("/request/sec") @ResponseBody - public static String ssrf_Request(@RequestParam String url) { + public static String request(@RequestParam String url) { try { - return Request.Get(url).execute().returnContent().toString(); - } catch (Exception e) { - logger.error(e.toString()); - return "fail"; + SecurityUtil.startSSRFHook(); + return HttpUtils.request(url); + } catch (SSRFException | IOException e) { + return e.getMessage(); + } finally { + SecurityUtil.stopSSRFHook(); } } @@ -106,7 +94,7 @@ public static String ssrf_Request(@RequestParam String url) { */ @RequestMapping("/openStream") @ResponseBody - public static void ssrf_openStream(@RequestParam String url, HttpServletResponse response) throws IOException { + public static void openStream(@RequestParam String url, HttpServletResponse response) throws IOException { InputStream inputStream = null; OutputStream outputStream = null; try { @@ -136,164 +124,112 @@ public static void ssrf_openStream(@RequestParam String url, HttpServletResponse } - @RequestMapping("/ImageIO") + @RequestMapping("/ImageIO/sec") @ResponseBody - public static void ssrf_ImageIO(@RequestParam String url) { + public static String ImageIO(@RequestParam String url) { try { - URL u = new URL(url); - ImageIO.read(u); // send request - } catch (Exception e) { - logger.error(e.toString()); + SecurityUtil.startSSRFHook(); + HttpUtils.imageIO(url); + } catch (SSRFException | IOException e) { + return e.getMessage(); + } finally { + SecurityUtil.stopSSRFHook(); } + + return "ImageIO ssrf test"; } - @RequestMapping("/okhttp") + @RequestMapping("/okhttp/sec") @ResponseBody - public static void ssrf_okhttp(@RequestParam String url) throws IOException { - OkHttpClient client = new OkHttpClient(); - com.squareup.okhttp.Request ok_http = new com.squareup.okhttp.Request.Builder().url(url).build(); - client.newCall(ok_http).execute(); + public static String okhttp(@RequestParam String url) { + + try { + SecurityUtil.startSSRFHook(); + HttpUtils.okhttp(url); + } catch (SSRFException | IOException e) { + return e.getMessage(); + } finally { + SecurityUtil.stopSSRFHook(); + } + + return "okhttp ssrf test"; } /** - * http://localhost:8080/ssrf/HttpClient/sec?url=http://www.baidu.com - * - * @return The response of url param. + * http://localhost:8080/ssrf/httpclient/sec?url=http://www.baidu.com */ - @RequestMapping("/HttpClient/sec") + @RequestMapping("/httpclient/sec") @ResponseBody - public static String ssrf_HttpClient(@RequestParam String url) { - StringBuilder result = new StringBuilder(); + public static String HttpClient(@RequestParam String url) { + try { SecurityUtil.startSSRFHook(); - CloseableHttpClient client = HttpClients.createDefault(); - HttpGet httpGet = new HttpGet(url); - HttpResponse httpResponse = client.execute(httpGet); // send request - BufferedReader rd = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent())); - - String line; - while ((line = rd.readLine()) != null) { - result.append(line); - } - - // SecurityUtil.stopSSRFHook(); - return result.toString(); - - } catch (Exception e) { - return e.toString(); + return HttpUtils.httpClient(url); + } catch (SSRFException | IOException e) { + return e.getMessage(); } finally { SecurityUtil.stopSSRFHook(); } + } /** - * https://mvnrepository.com/artifact/commons-httpclient/commons-httpclient - * UserAgent: Jakarta Commons-HttpClient/3.1 (2007.08 publish) - *
* http://localhost:8080/ssrf/commonsHttpClient/sec?url=http://www.baidu.com */ @RequestMapping("/commonsHttpClient/sec") @ResponseBody public static String commonsHttpClient(@RequestParam String url) { - if (!SecurityUtil.checkSSRFByWhitehosts(url)) { - return "Bad man. I got u."; - } - - HttpClient client = new HttpClient(); - GetMethod method = new GetMethod(url); - method.setFollowRedirects(false); try { - // Send http request. - int status_code = client.executeMethod(method); - - // Only allow the url that status_code is 200. - if (status_code != HttpStatus.SC_OK) { - return "Method failed: " + method.getStatusLine(); - } - - // Read the response body. - byte[] resBody = method.getResponseBody(); - return new String(resBody); - - } catch (IOException e) { - return "Error: " + e.getMessage(); + SecurityUtil.startSSRFHook(); + return HttpUtils.commonHttpClient(url); + } catch (SSRFException | IOException e) { + return e.getMessage(); } finally { - // Release the connection. - method.releaseConnection(); + SecurityUtil.stopSSRFHook(); } - } /** - * jsoup是一款Java的HTML解析器,可直接解析某个URL地址、HTML文本内容。 - *
* http://localhost:8080/ssrf/Jsoup?url=http://www.baidu.com
*/
- @RequestMapping("/Jsoup")
+ @RequestMapping("/Jsoup/sec")
@ResponseBody
public static String Jsoup(@RequestParam String url) {
+
try {
- Document doc = Jsoup.connect(url)
- .userAgent(
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) "
- + "Chrome/64.0.3282.167 Safari/537.36")
- .timeout(3000)
- .cookie("name", "joychou") // request请求带的cookie
- .followRedirects(false)
- .execute().parse();
- logger.info(doc.html());
- } catch (MalformedURLException e) {
- return "exception: " + e.toString();
- } catch (IOException e) {
- logger.error(e.toString());
- return "exception: " + e.toString();
+ SecurityUtil.startSSRFHook();
+ return HttpUtils.Jsoup(url);
+ } catch (SSRFException | IOException e) {
+ return e.getMessage();
+ } finally {
+ SecurityUtil.stopSSRFHook();
}
- return "Jsoup ssrf";
}
/**
- * 用途:IOUtils可远程获取URL图片
- * 默认重定向:是
- * 封装类:URLConnection
- * http://localhost:8080/ssrf/IOUtils?url=http://www.baidu.com
+ * http://localhost:8080/ssrf/IOUtils/sec?url=http://www.baidu.com
*/
- @RequestMapping("/IOUtils")
- public static String IOUtils(@RequestParam String url) {
+ @RequestMapping("/IOUtils/sec")
+ public static String IOUtils(String url) {
+
try {
- // IOUtils.toByteArray内部用URLConnection进行了封装
- IOUtils.toByteArray(URI.create(url));
- } catch (Exception e) {
- return "exception: " + e.toString();
+ SecurityUtil.startSSRFHook();
+ HttpUtils.IOUtils(url);
+ } catch (SSRFException | IOException e) {
+ return e.getMessage();
+ } finally {
+ SecurityUtil.stopSSRFHook();
}
- return "IOUtils ssrf";
+ return "IOUtils ssrf test";
}
- /**
- * Safe code.
- * http://localhost:8080/ssrf/ImageIO/sec?url=http://www.baidu.com
- */
- @RequestMapping("/ImageIO/sec")
- public static String ImageIOSec(@RequestParam String url) {
- try {
- URL u = new URL(url);
- if (!SecurityUtil.checkSSRFWithoutRedirect(url)) {
- logger.error("[-] SSRF check failed. Original Url: " + url);
- return "SSRF check failed.";
- }
- ImageIO.read(u); // send request
- } catch (Exception e) {
- return e.toString();
- }
-
- return "ImageIO ssrf safe code.";
- }
}
diff --git a/src/main/java/org/joychou/security/SecurityUtil.java b/src/main/java/org/joychou/security/SecurityUtil.java
index a1c4cfc6..0b383f5d 100644
--- a/src/main/java/org/joychou/security/SecurityUtil.java
+++ b/src/main/java/org/joychou/security/SecurityUtil.java
@@ -126,7 +126,7 @@ public static boolean checkSSRFWithoutRedirect(String url) {
*
* @author liergou @ 2020-04-04 02:15
*/
- public static void startSSRFHook() throws NoSuchFieldException, IOException {
+ public static void startSSRFHook() throws IOException {
SocketHook.startHook();
}
diff --git a/src/main/java/org/joychou/security/ssrf/SSRFChecker.java b/src/main/java/org/joychou/security/ssrf/SSRFChecker.java
index 32373aff..3860cad9 100644
--- a/src/main/java/org/joychou/security/ssrf/SSRFChecker.java
+++ b/src/main/java/org/joychou/security/ssrf/SSRFChecker.java
@@ -132,7 +132,6 @@ static boolean isInternalIp(String strIP) {
}
ArrayListJakarta Commons-HttpClient/3.1
. Last publish at 2007.08.
+ *
+ * @param url http request url
+ * @return response
+ */
+ public static String commonHttpClient(String url) {
+
+ HttpClient client = new HttpClient();
+ GetMethod method = new GetMethod(url);
+
+ try {
+ client.executeMethod(method); // send request
+ byte[] resBody = method.getResponseBody();
+ return new String(resBody);
+
+ } catch (IOException e) {
+ return "Error: " + e.getMessage();
+ } finally {
+ // Release the connection.
+ method.releaseConnection();
+ }
+ }
+
+
+ public static String request(String url) {
+ try {
+ return Request.Get(url).execute().returnContent().toString();
+ } catch (Exception e) {
+ return e.getMessage();
+ }
+ }
+
+
+ public static String httpClient(String url) {
+
+ StringBuilder result = new StringBuilder();
+
+ try {
+
+ CloseableHttpClient client = HttpClients.createDefault();
+ HttpGet httpGet = new HttpGet(url);
+ HttpResponse httpResponse = client.execute(httpGet); // send request
+ BufferedReader rd = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent()));
+
+ String line;
+ while ((line = rd.readLine()) != null) {
+ result.append(line);
+ }
+
+ return result.toString();
+
+ } catch (Exception e) {
+ return e.getMessage();
+ }
+ }
+
+
+ public static String URLConnection(String url) {
+ try {
+ URL u = new URL(url);
+ URLConnection urlConnection = u.openConnection();
+ BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); //send request
+ String inputLine;
+ StringBuilder html = new StringBuilder();
+
+ while ((inputLine = in.readLine()) != null) {
+ html.append(inputLine);
+ }
+ in.close();
+ return html.toString();
+ } catch (Exception e) {
+ logger.error(e.getMessage());
+ return e.getMessage();
+ }
+ }
+
+
+ public static String HTTPURLConnection(String url) {
+ try {
+ URL u = new URL(url);
+ URLConnection urlConnection = u.openConnection();
+ HttpURLConnection httpUrl = (HttpURLConnection) urlConnection;
+ BufferedReader in = new BufferedReader(new InputStreamReader(httpUrl.getInputStream())); //send request
+ String inputLine;
+ StringBuilder html = new StringBuilder();
+
+ while ((inputLine = in.readLine()) != null) {
+ html.append(inputLine);
+ }
+ in.close();
+ return html.toString();
+ } catch (IOException e) {
+ logger.error(e.getMessage());
+ return e.getMessage();
+ }
+ }
+
+
+ /**
+ * Jsoup is a HTML parser about Java.
+ *
+ * @param url http request url
+ */
+ public static String Jsoup(String url) {
+ try {
+ String useragent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) " +
+ "Chrome/64.0.3282.167 Safari/537.36";
+ Document doc = Jsoup.connect(url)
+ .userAgent(useragent)
+ .timeout(3000)
+ .cookie("name", "joychou") // request cookies
+ //.followRedirects(false)
+ .execute().parse();
+ return doc.outerHtml();
+ } catch (IOException e) {
+ return e.getMessage();
+ }
+ }
+
+
+ public static void okhttp(String url) throws IOException {
+ OkHttpClient client = new OkHttpClient();
+ com.squareup.okhttp.Request ok_http = new com.squareup.okhttp.Request.Builder().url(url).build();
+ client.newCall(ok_http).execute();
+ }
+
+
+ public static void imageIO(String url) {
+ try {
+ URL u = new URL(url);
+ ImageIO.read(u); // send request
+ } catch (IOException e) {
+ logger.error(e.getMessage());
+ }
+
+ }
+
+
+ /**
+ * IOUtils which is wrapped by URLConnection can get remote pictures.
+ * The default setting of redirection is true.
+ *
+ * @param url http request url
+ */
+ public static void IOUtils(String url) {
+ try {
+ IOUtils.toByteArray(URI.create(url));
+ } catch (IOException e) {
+ logger.error(e.getMessage());
+ }
+ }
+
+
+}
diff --git a/src/main/java/org/joychou/util/WebUtils.java b/src/main/java/org/joychou/util/WebUtils.java
index 7cc16e84..4816df8e 100644
--- a/src/main/java/org/joychou/util/WebUtils.java
+++ b/src/main/java/org/joychou/util/WebUtils.java
@@ -17,6 +17,7 @@ public static String getRequestBody(HttpServletRequest request) throws IOExcepti
return convertStreamToString(in);
}
+
// https://stackoverflow.com/questions/309424/how-do-i-read-convert-an-inputstream-into-a-string-in-java
public static String convertStreamToString(java.io.InputStream is) {
java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
@@ -33,6 +34,7 @@ public static String json2Jsonp(String callback, String jsonStr) {
return HtmlUtils.htmlEscape(callback) + "(" + jsonStr + ")";
}
+
public static String getFileExtension(String fullName) {
Preconditions.checkNotNull(fullName);
String fileName = (new File(fullName)).getName();
@@ -40,10 +42,13 @@ public static String getFileExtension(String fullName) {
return dotIndex == -1 ? "" : fileName.substring(dotIndex + 1);
}
+
public static String getNameWithoutExtension(String file) {
Preconditions.checkNotNull(file);
String fileName = (new File(file)).getName();
int dotIndex = fileName.lastIndexOf('.');
return dotIndex == -1 ? fileName : fileName.substring(0, dotIndex);
}
+
+
}
diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html
index de32f6ee..671045d5 100644
--- a/src/main/resources/templates/index.html
+++ b/src/main/resources/templates/index.html
@@ -14,7 +14,7 @@
Cors
PathTraversal
SqlInject
- SSRF
+ SSRF
RCE
ooxml XXE
xlsx-streamer XXE