use of com.jsql.model.bean.util.Header in project jsql-injection by ron190.
the class InjectionModel method testParameters.
/**
* Verify if injection works for specific Method using 3 modes: standard (last param), injection point
* and full params injection. Special injections like JSON and SOAP are checked.
* @param methodInjection currently tested (Query, Request or Header)
* @param paramsAsString to verify if contains injection point
* @param params from Query, Request or Header as a list of key/value to be tested for insertion character ;
* Mode standard: last param, mode injection point: no test, mode full: every params.
* @return true if injection didn't failed
* @throws JSqlException when no params' integrity, process stopped by user, or injection failure
*/
public boolean testParameters(MethodInjection methodInjection, String paramsAsString, List<SimpleEntry<String, String>> params) throws JSqlException {
boolean hasFoundInjection = false;
// or method is selected by user.
if (!PreferencesUtil.isCheckingAllParam() && ConnectionUtil.getMethodInjection() != methodInjection) {
return hasFoundInjection;
}
// Force injection method of model to current running method
ConnectionUtil.setMethodInjection(methodInjection);
// Default injection: last param tested only and no injection point
if (!methodInjection.isCheckingAllParam() && !paramsAsString.contains(InjectionModel.STAR)) {
// Injection point defined on last parameter
params.stream().reduce((a, b) -> b).ifPresent(e -> e.setValue(e.getValue() + InjectionModel.STAR));
// Will check param value by user.
// Notice options 'Inject each URL params' and 'inject JSON' must be checked both
// for JSON injection of last param
hasFoundInjection = this.testStrategies(IS_PARAM_BY_USER, !IS_JSON, params.stream().reduce((a, b) -> b).get());
// Injection by injection point
} else if (paramsAsString.contains(InjectionModel.STAR)) {
LOGGER.info("Checking single " + methodInjection.name() + " parameter with injection point at *");
// Will keep param value as is,
// Does not test for insertion character (param is null)
hasFoundInjection = this.testStrategies(!IS_PARAM_BY_USER, !IS_JSON, null);
// Injection of every params: isCheckingAllParam() == true.
// Params are tested one by one in two loops:
// - inner loop erases * from previous param
// - outer loop adds * to current param
} else {
// inner loop will erase mark * otherwise
for (SimpleEntry<String, String> paramBase : params) {
// For standard value mark * is simply added to the end of its value.
for (SimpleEntry<String, String> paramStar : params) {
if (paramStar == paramBase) {
// Will test if current value is a JSON entity
Object jsonEntity = null;
try {
// Test for JSON Object: {...}
jsonEntity = new JSONObject(paramStar.getValue());
} catch (JSONException exceptionJSONObject) {
try {
// Test for JSON Array: [...]
jsonEntity = new JSONArray(paramStar.getValue());
} catch (JSONException exceptionJSONArray) {
// Not a JSON entity
}
}
// Define a tree of JSON attributes with path as the key: root.a => value of a
List<SimpleEntry<String, String>> attributesJson = JsonUtil.loopThroughJson(jsonEntity, "root", null);
// Marks * are erased between each tests.
if (PreferencesUtil.isCheckingAllJSONParam() && !attributesJson.isEmpty()) {
// Loop through each JSON values
for (SimpleEntry<String, String> parentXPath : attributesJson) {
// Erase previously defined *
JsonUtil.loopThroughJson(jsonEntity, "root", null);
// Add * to current parameter's value
JsonUtil.loopThroughJson(jsonEntity, "root", parentXPath);
// Replace param value by marked one.
// paramStar and paramBase are the same object
paramStar.setValue(jsonEntity.toString());
try {
LOGGER.info("Checking JSON " + methodInjection.name() + " parameter " + parentXPath.getKey() + "=" + parentXPath.getValue().replace(InjectionModel.STAR, ""));
// Test current JSON value marked with * for injection
// Keep original param
hasFoundInjection = this.testStrategies(IS_PARAM_BY_USER, IS_JSON, paramBase);
// Injection successful
break;
} catch (JSqlException e) {
// Injection failure
LOGGER.warn("No " + methodInjection.name() + " injection found for JSON " + methodInjection.name() + " parameter " + parentXPath.getKey() + "=" + parentXPath.getValue().replace(InjectionModel.STAR, ""), e);
} finally {
// Erase * at the end of each params
params.stream().forEach(e -> e.setValue(e.getValue().replaceAll(Pattern.quote(InjectionModel.STAR) + "$", "")));
// Erase * from JSON if failure
if (!hasFoundInjection) {
paramStar.setValue(paramStar.getValue().replace("*", ""));
}
}
}
// Standard non JSON injection
} else {
// Add * to end of value
paramStar.setValue(paramStar.getValue() + InjectionModel.STAR);
try {
LOGGER.info("Checking " + methodInjection.name() + " parameter " + paramBase.getKey() + "=" + paramBase.getValue().replace(InjectionModel.STAR, ""));
// Test current standard value marked with * for injection
// Keep original param
hasFoundInjection = this.testStrategies(IS_PARAM_BY_USER, !IS_JSON, paramBase);
// Injection successful
break;
} catch (JSqlException e) {
// Injection failure
LOGGER.warn("No " + methodInjection.name() + " injection found for parameter " + paramBase.getKey() + "=" + paramBase.getValue().replace(InjectionModel.STAR, "") + " (" + e.getMessage() + ")", e);
} finally {
// Erase * at the end of each params
params.stream().forEach(e -> e.setValue(e.getValue().replaceAll(Pattern.quote(InjectionModel.STAR) + "$", "")));
}
}
}
}
// If injection successful then add * at the end of value
if (hasFoundInjection) {
paramBase.setValue(paramBase.getValue().replace("*", "") + "*");
break;
}
}
}
return hasFoundInjection;
}
use of com.jsql.model.bean.util.Header in project jsql-injection by ron190.
the class RessourceAccess method runCommandShell.
/**
* @param urlCommand
* @return
* @throws IOException
*/
private static String runCommandShell(String urlCommand) throws IOException {
HttpURLConnection connection;
String url = urlCommand;
connection = (HttpURLConnection) new URL(url).openConnection();
connection.setReadTimeout(ConnectionUtil.getTimeout());
connection.setConnectTimeout(ConnectionUtil.getTimeout());
String pageSource = null;
try {
pageSource = ConnectionUtil.getSource(connection);
} catch (Exception e) {
pageSource = "";
}
Matcher regexSearch = Pattern.compile("(?s)<" + DataAccess.LEAD + ">(.*)<" + DataAccess.TRAIL + ">").matcher(pageSource);
regexSearch.find();
String result;
// IllegalStateException #1544: catch incorrect execution
try {
result = regexSearch.group(1);
} catch (IllegalStateException e) {
// Fix return null from regex
result = "";
LOGGER.warn("Incorrect response from Web shell", e);
}
Map<Header, Object> msgHeader = new EnumMap<>(Header.class);
msgHeader.put(Header.URL, url);
msgHeader.put(Header.POST, "");
msgHeader.put(Header.HEADER, "");
msgHeader.put(Header.RESPONSE, HeaderUtil.getHttpHeaders(connection));
msgHeader.put(Header.SOURCE, pageSource);
Request request = new Request();
request.setMessage(Interaction.MESSAGE_HEADER);
request.setParameters(msgHeader);
MediatorModel.model().sendToViews(request);
// TODO optional
return result;
}
use of com.jsql.model.bean.util.Header in project jsql-injection by ron190.
the class ConnectionUtil method getSource.
public static String getSource(String url, boolean lineFeed) throws IOException {
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setReadTimeout(ConnectionUtil.getTimeout());
connection.setConnectTimeout(ConnectionUtil.getTimeout());
connection.setUseCaches(false);
connection.setRequestProperty("Pragma", "no-cache");
connection.setRequestProperty("Cache-Control", "no-cache");
connection.setRequestProperty("Expires", "-1");
Map<Header, Object> msgHeader = new EnumMap<>(Header.class);
msgHeader.put(Header.URL, url);
msgHeader.put(Header.RESPONSE, HeaderUtil.getHttpHeaders(connection));
String pageSource = null;
try {
if (lineFeed) {
pageSource = ConnectionUtil.getSourceLineFeed(connection);
} else {
pageSource = ConnectionUtil.getSource(connection);
}
} catch (IOException e) {
throw e;
} finally {
msgHeader.put(Header.SOURCE, pageSource);
// Inform the view about the log infos
Request request = new Request();
request.setMessage(Interaction.MESSAGE_HEADER);
request.setParameters(msgHeader);
MediatorModel.model().sendToViews(request);
}
// TODO optional
return pageSource.trim();
}
use of com.jsql.model.bean.util.Header in project jsql-injection by ron190.
the class HeaderUtil method checkResponseHeader.
/**
* Verify the headers received after a request, detect authentication response and
* send the headers to the view.
* @param connection contains headers response
* @param urlByUser the website to request
* @throws IOException when an error occurs during connection
*/
@SuppressWarnings("unchecked")
public static void checkResponseHeader(HttpURLConnection connection, String urlByUser) throws IOException {
// TODO Extract
Map<Header, Object> msgHeader = new EnumMap<>(Header.class);
msgHeader.put(Header.URL, urlByUser);
msgHeader.put(Header.RESPONSE, HeaderUtil.getHttpHeaders(connection));
Map<String, String> mapResponse = (Map<String, String>) msgHeader.get(Header.RESPONSE);
if (Pattern.matches("4\\d\\d", Integer.toString(connection.getResponseCode())) && mapResponse.containsKey("WWW-Authenticate") && mapResponse.get("WWW-Authenticate") != null && mapResponse.get("WWW-Authenticate").startsWith("Basic ")) {
LOGGER.warn("Basic Authentication detected.\n" + "Please define and enable authentication information in the panel Preferences.\n" + "Or open Advanced panel, add 'Authorization: Basic b3N..3Jk' to the Header, replace b3N..3Jk with the string 'osUserName:osPassword' encoded in Base64. You can use the Coder in jSQL to encode the string.");
} else if (Pattern.matches("4\\d\\d", Integer.toString(connection.getResponseCode())) && mapResponse.containsKey("WWW-Authenticate") && "NTLM".equals(mapResponse.get("WWW-Authenticate"))) {
LOGGER.warn("NTLM Authentication detected.\n" + "Please define and enable authentication information in the panel Preferences.\n" + "Or add username, password and domain information to the URL, e.g. http://domain\\user:password@127.0.0.1/[..]");
} else if (Pattern.matches("4\\d\\d", Integer.toString(connection.getResponseCode())) && mapResponse.containsKey("WWW-Authenticate") && mapResponse.get("WWW-Authenticate") != null && mapResponse.get("WWW-Authenticate").startsWith("Digest ")) {
LOGGER.warn("Digest Authentication detected.\n" + "Please define and enable authentication information in the panel Preferences.");
} else if (Pattern.matches("4\\d\\d", Integer.toString(connection.getResponseCode())) && mapResponse.containsKey("WWW-Authenticate") && "Negotiate".equals(mapResponse.get("WWW-Authenticate"))) {
LOGGER.warn("Negotiate Authentication detected.\n" + "Please add username, password and domain information to the URL, e.g. http://domain\\user:password@127.0.0.1/[..]");
} else if (Pattern.matches("1\\d\\d", Integer.toString(connection.getResponseCode()))) {
LOGGER.trace("Found status HTTP " + connection.getResponseCode() + " Informational");
} else if (Pattern.matches("2\\d\\d", Integer.toString(connection.getResponseCode()))) {
LOGGER.debug("Found status HTTP " + connection.getResponseCode() + " Success");
} else if (Pattern.matches("3\\d\\d", Integer.toString(connection.getResponseCode()))) {
LOGGER.warn("Found status HTTP " + connection.getResponseCode() + " Redirection");
if (!PreferencesUtil.isFollowingRedirection()) {
LOGGER.warn("If injection fails please test again with option 'Follow HTTP redirection' enabled.");
} else {
LOGGER.info("Redirecting to the next page...");
}
} else if (Pattern.matches("4\\d\\d", Integer.toString(connection.getResponseCode()))) {
LOGGER.warn("Found status HTTP " + connection.getResponseCode() + " Client Error");
} else if (Pattern.matches("5\\d\\d", Integer.toString(connection.getResponseCode()))) {
LOGGER.warn("Found status HTTP " + connection.getResponseCode() + " Server Error");
} else {
LOGGER.trace("Found status HTTP " + connection.getResponseCode() + " Unknown");
}
// Request the web page to the server
Exception exception = null;
StringBuilder pageSource = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
char[] buffer = new char[4096];
while (reader.read(buffer) > 0) {
pageSource.append(buffer);
}
reader.close();
} catch (IOException errorInputStream) {
exception = errorInputStream;
InputStream errorStream = connection.getErrorStream();
if (errorStream != null) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(errorStream))) {
char[] buffer = new char[4096];
while (reader.read(buffer) > 0) {
pageSource.append(buffer);
}
reader.close();
} catch (Exception errorErrorStream) {
exception = new IOException("Exception reading Error Stream", errorErrorStream);
}
}
}
if (PreferencesUtil.isNotTestingConnection()) {
if (exception != null) {
LOGGER.debug("Connection test disabled, ignoring response HTTP " + connection.getResponseCode() + "...");
}
exception = null;
} else if (exception != null) {
LOGGER.info("Please select option 'Disable connection test' and run again");
}
// Form parsing;
// TODO Extract
Elements elementsForm = Jsoup.parse(pageSource.toString()).select("form");
StringBuilder result = new StringBuilder();
Map<Element, List<Element>> mapForms = new HashMap<>();
for (Element form : elementsForm) {
mapForms.put(form, new ArrayList<>());
result.append("\n<form action=\"");
result.append(form.attr("action"));
result.append("\" method=\"");
result.append(form.attr("method"));
result.append("\" />");
for (Element input : form.select("input")) {
result.append("\n <input name=\"");
result.append(input.attr("name"));
result.append("\" value=\"");
result.append(input.attr("value"));
result.append("\" />");
mapForms.get(form).add(input);
}
Collections.reverse(mapForms.get(form));
}
if (!elementsForm.isEmpty()) {
if (!PreferencesUtil.isParsingForm()) {
if (connection.getResponseCode() != 200) {
LOGGER.trace("Found " + elementsForm.size() + " ignored <form> in HTML body:" + result);
LOGGER.info("WAF can detect missing form parameters, you may enable 'Add <input> parameters' in Preferences and retry");
} else {
LOGGER.trace("Found " + elementsForm.size() + " <form> in HTML body while status 200 Success:" + result);
}
} else {
LOGGER.debug("Found " + elementsForm.size() + " <form> in HTML body, adding input(s) to requests:" + result);
for (Entry<Element, List<Element>> form : mapForms.entrySet()) {
for (Element input : form.getValue()) {
if ("get".equalsIgnoreCase(form.getKey().attr("method"))) {
ParameterUtil.getQueryString().add(0, new SimpleEntry<String, String>(input.attr("name"), input.attr("value")));
} else if ("post".equalsIgnoreCase(form.getKey().attr("method"))) {
ParameterUtil.getRequest().add(0, new SimpleEntry<String, String>(input.attr("name"), input.attr("value")));
}
}
}
}
}
// Csrf
// TODO Extract
Optional<SimpleEntry<String, String>> optionalTokenCsrf = Jsoup.parse(pageSource.toString()).select("input").select("[name=csrf_token], [name=csrfToken]").stream().findFirst().map(input -> new SimpleEntry<String, String>(input.attr("name"), input.attr("value")));
if (optionalTokenCsrf.isPresent()) {
SimpleEntry<String, String> tokenCsrfFound = optionalTokenCsrf.get();
if (PreferencesUtil.isProcessingCsrf()) {
LOGGER.debug("Found Csrf token " + tokenCsrfFound.getKey() + "=" + tokenCsrfFound.getValue() + " in HTML body, adding token to querystring, request and header");
ConnectionUtil.setTokenCsrf(tokenCsrfFound);
} else {
LOGGER.warn("Found Csrf token '" + tokenCsrfFound.getKey() + "=" + tokenCsrfFound.getValue() + "' in HTML body");
exception = new IOException("please activate Csrf processing in Preferences");
}
}
msgHeader.put(Header.SOURCE, pageSource.toString());
// Inform the view about the log infos
Request request = new Request();
request.setMessage(Interaction.MESSAGE_HEADER);
request.setParameters(msgHeader);
MediatorModel.model().sendToViews(request);
if (exception != null) {
throw new IOException(exception);
}
}
use of com.jsql.model.bean.util.Header in project jsql-injection by ron190.
the class SuspendableGetVendor method run.
/**
*/
@Override
public Vendor run(Object... args) throws StoppedByUserSlidingException {
Vendor vendor = null;
if (MediatorModel.model().getVendorByUser() != Vendor.AUTO) {
vendor = MediatorModel.model().getVendorByUser();
LOGGER.info(I18n.valueByKey("LOG_DATABASE_TYPE_FORCED_BY_USER") + " [" + vendor + "]");
} else {
// Parallelize the search and let the user stops the process if needed.
// SQL: force a wrong ORDER BY clause with an inexistent column, order by 1337,
// and check if a correct error message is sent back by the server:
// Unknown column '1337' in 'order clause'
// or supplied argument is not a valid MySQL result resource
ExecutorService taskExecutor = Executors.newCachedThreadPool(new ThreadFactoryCallable("CallableGetVendor"));
CompletionService<CallablePageSource> taskCompletionService = new ExecutorCompletionService<>(taskExecutor);
for (String insertionCharacter : new String[] { "'\"#-)'\"" }) {
taskCompletionService.submit(new CallablePageSource(insertionCharacter, insertionCharacter));
}
int total = 1;
while (0 < total) {
if (this.isSuspended()) {
throw new StoppedByUserSlidingException();
}
try {
CallablePageSource currentCallable = taskCompletionService.take().get();
total--;
String pageSource = currentCallable.getContent();
for (Vendor vendorTest : Stream.of(Vendor.values()).skip(1).toArray(Vendor[]::new)) {
if (pageSource.matches("(?si).*(" + vendorTest.instance().fingerprintErrorsAsRegex() + ").*")) {
vendor = vendorTest;
LOGGER.debug("Found database [" + vendor + "]");
break;
}
}
} catch (InterruptedException | ExecutionException e) {
LOGGER.error("Interruption while determining the type of database", e);
}
}
// End the job
try {
taskExecutor.shutdown();
taskExecutor.awaitTermination(15, TimeUnit.SECONDS);
} catch (InterruptedException e) {
LOGGER.error(e.getMessage(), e);
Thread.currentThread().interrupt();
}
if (vendor == null) {
vendor = Vendor.MYSQL;
LOGGER.warn(I18n.valueByKey("LOG_DATABASE_TYPE_NOT_FOUND") + " [" + vendor + "]");
} else {
LOGGER.info(I18n.valueByKey("LOG_USING_DATABASE_TYPE") + " [" + vendor + "]");
Map<Header, Object> msgHeader = new EnumMap<>(Header.class);
msgHeader.put(Header.URL, ConnectionUtil.getUrlBase() + ParameterUtil.getQueryStringAsString());
msgHeader.put(Header.VENDOR, vendor);
Request requestDatabaseIdentified = new Request();
requestDatabaseIdentified.setMessage(Interaction.DATABASE_IDENTIFIED);
requestDatabaseIdentified.setParameters(msgHeader);
MediatorModel.model().sendToViews(requestDatabaseIdentified);
}
}
Request requestSetVendor = new Request();
requestSetVendor.setMessage(Interaction.SET_VENDOR);
requestSetVendor.setParameters(vendor);
MediatorModel.model().sendToViews(requestSetVendor);
return vendor;
}
Aggregations