diff --git a/build.gradle b/build.gradle index c0bd27756b..dea94eb99c 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:1.4.0-beta6' + classpath 'com.android.tools.build:gradle:1.5.0' } } diff --git a/cSploit/build.gradle b/cSploit/build.gradle index ffa986128a..e86b784a2c 100644 --- a/cSploit/build.gradle +++ b/cSploit/build.gradle @@ -4,7 +4,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:1.4.0-beta6' + classpath 'com.android.tools.build:gradle:1.5.0' } } @@ -21,10 +21,10 @@ allprojects { apply plugin: 'com.android.application' dependencies { - compile 'com.android.support:support-v4:23.0.1' - compile 'com.android.support:appcompat-v7:23.0.1' - compile 'com.android.support:design:23.0.1' - compile 'com.android.support:preference-v7:23.0.1' + compile 'com.android.support:support-v4:23.1.1' + compile 'com.android.support:appcompat-v7:23.1.1' + compile 'com.android.support:design:23.1.1' + compile 'com.android.support:preference-v7:23.1.1' compile 'org.apache.commons:commons-compress:1.10' compile 'commons-net:commons-net:3.3' compile 'com.github.zafarkhaja:java-semver:0.9.0' @@ -37,7 +37,7 @@ dependencies { android { compileSdkVersion 23 - buildToolsVersion '23.0.1' + buildToolsVersion '23.0.2' compileOptions { sourceCompatibility JavaVersion.VERSION_1_7 @@ -52,8 +52,8 @@ android { defaultConfig { minSdkVersion 9 targetSdkVersion 22 - versionCode 4 - versionName "1.6.2" + versionCode 6 + versionName "1.6.6-rc.2" if(System.getenv("NIGHTLY_BUILD")) { versionName += "+" + System.getenv("NIGHTLY_BUILD_COMMIT").substring(0, 7) } diff --git a/cSploit/res/layout/plugin_inspector.xml b/cSploit/res/layout/plugin_inspector.xml index 1c9ee175ef..026735c44a 100644 --- a/cSploit/res/layout/plugin_inspector.xml +++ b/cSploit/res/layout/plugin_inspector.xml @@ -6,19 +6,6 @@ android:paddingTop="16sp" android:id="@+id/whatever"> - - + + + \ No newline at end of file diff --git a/cSploit/res/values/strings.xml b/cSploit/res/values/strings.xml index d03780c5c9..43af23b7c5 100644 --- a/cSploit/res/values/strings.xml +++ b/cSploit/res/values/strings.xml @@ -529,4 +529,5 @@ Select %s ? https://github.com/cSploit/android/issues Before opening a new issue, please, take the time to read the already open issues, probably it\' s already open. If it\' s not open we\'ll need as much information as you can get, so please, read this guide in order to know how to report a bug properly.

]]>
+ must be empty or an old installation directory. diff --git a/cSploit/src/org/csploit/android/MainActivity.java b/cSploit/src/org/csploit/android/MainActivity.java index 0d1a076b98..6d1e400cde 100644 --- a/cSploit/src/org/csploit/android/MainActivity.java +++ b/cSploit/src/org/csploit/android/MainActivity.java @@ -280,6 +280,8 @@ private void onCoreBeating() { } private void onCoreUpdated() { + System.onCoreInstalled(); + if (startCore()) { onCoreBeating(); } else if (isRootMissing) { @@ -612,7 +614,6 @@ public void onInputEntered(String input) { @Override public void run() { System.addOrderedTarget(target); - mTargetAdapter.update(null, null); } }); } else @@ -887,16 +888,20 @@ public View getView(int position, View convertView, ViewGroup parent) { } public void clearSelection() { - for (Target t : list) - t.setSelected(false); + synchronized (this) { + for (Target t : list) + t.setSelected(false); + } notifyDataSetChanged(); if (mActionMode != null) mActionMode.finish(); } public void toggleSelection(int position) { - Target t = list.get(position); - t.setSelected(!t.isSelected()); + synchronized (this) { + Target t = list.get(position); + t.setSelected(!t.isSelected()); + } notifyDataSetChanged(); if (mActionMode != null) { if (getSelectedCount() > 0) @@ -908,27 +913,34 @@ public void toggleSelection(int position) { public int getSelectedCount() { int i = 0; - for (Target t : list) - if (t.isSelected()) - i++; + synchronized (this) { + for (Target t : list) + if (t.isSelected()) + i++; + } return i; } public ArrayList getSelected() { ArrayList result = new ArrayList(); - for (Target t : list) - if (t.isSelected()) - result.add(t); + synchronized (this) { + for (Target t : list) + if (t.isSelected()) + result.add(t); + } return result; } public int[] getSelectedPositions() { - int[] res = new int[getSelectedCount()]; + int[] res; int j = 0; - for (int i = 0; i < list.size(); i++) - if (list.get(i).isSelected()) - res[j++] = i; + synchronized (this) { + res = new int[getSelectedCount()]; + for (int i = 0; i < list.size(); i++) + if (list.get(i).isSelected()) + res[j++] = i; + } return res; } @@ -948,13 +960,17 @@ public void update(Observable observable, Object data) { public void run() { if(lv == null) return; - int start = lv.getFirstVisiblePosition(); - for(int i=start, j=lv.getLastVisiblePosition();i<=j;i++) - if(target==list.get(i)){ - View view = lv.getChildAt(i-start); - getView(i, view, lv); - break; - } + + synchronized (this) { + int start = lv.getFirstVisiblePosition(); + int end = Math.min(lv.getLastVisiblePosition(), list.size()); + for (int i = start; i <= end; i++) + if (target == list.get(i)) { + View view = lv.getChildAt(i - start); + getView(i, view, lv); + break; + } + } } }); @@ -962,7 +978,9 @@ public void run() { @Override public void run() { - list = System.getTargets(); + synchronized (this) { + list = System.getTargets(); + } notifyDataSetChanged(); } diff --git a/cSploit/src/org/csploit/android/SettingsActivity.java b/cSploit/src/org/csploit/android/SettingsActivity.java index 4a64f9787a..dbb71f2026 100644 --- a/cSploit/src/org/csploit/android/SettingsActivity.java +++ b/cSploit/src/org/csploit/android/SettingsActivity.java @@ -214,14 +214,84 @@ public void onEnd(int exitCode) { } } + private boolean isDirectoryEmptyOrWithVersion(File folder) { + String[] files = folder.list(); + + if(files.length > 0) { + for(String fname : files) { + if("VERSION".equals(fname)) { + return true; + } + } + return false; + } + + return true; + } + + private ExecChecker getCheckerForKey(String key) { + switch (key) { + case "RUBY_DIR": + return ExecChecker.ruby(); + case "MSF_DIR": + return ExecChecker.msf(); + } + return null; + } + + private String getCurrentPathForKey(String key) { + switch (key) { + case "RUBY_DIR": + return System.getRubyPath(); + case "MSF_DIR": + return System.getMsfPath(); + } + return null; + } + + private boolean shallAskForDelete(String key) { + return key.equals("RUBY_DIR") || key.equals("MSF_DIR"); + } + + /** + * check if selected directory is valid for the given key. + * @param key to be updated + * @param path of the chosen directory + * @return true if {@code path} is valid, false otherwise + */ + private boolean canChangeDirectoryTo(String key, String path) { + File folder = new File(path); + ExecChecker checker = getCheckerForKey(key); + String oldPath = getCurrentPathForKey(key); + String toastMessage = null; + boolean valid = false; + boolean checkEmptyOrVersion = shallAskForDelete(key); + + if (!folder.exists()) { + toastMessage = getString(R.string.pref_folder) + " " + path + " " + getString(R.string.pref_err_exists); + } else if (!folder.canWrite()) { + toastMessage = getString(R.string.pref_folder) + " " + path + " " + getString(R.string.pref_err_writable); + } else if (checker != null && !checker.canExecuteInDir(path)) { + toastMessage = getString(R.string.pref_folder) + " " + path + " " + getString(R.string.pref_err_executable); + } else if (checkEmptyOrVersion && !isDirectoryEmptyOrWithVersion(folder)) { + toastMessage = getString(R.string.pref_folder) + " " + path + " " + getString(R.string.pref_err_empty_or_old); + } else if (oldPath == null || !oldPath.equals(path)) { + valid = true; + } + + if(toastMessage != null) { + Toast.makeText(getContext(), toastMessage, Toast.LENGTH_LONG).show(); + } + + return valid; + } + @Override public void onActivityResult(int requestCode, int resultCode, Intent intent) { if (requestCode == DirectoryPicker.PICK_DIRECTORY && resultCode != RESULT_CANCELED) { Bundle extras = intent.getExtras(); String path; String key; - File folder; - String oldPath = null; if (extras == null) { Logger.debug("null extra: " + intent); @@ -236,35 +306,18 @@ public void onActivityResult(int requestCode, int resultCode, Intent intent) { return; } - folder = new File(path); - ExecChecker checker = null; - - - if (key.equals("RUBY_DIR")) { - oldPath = System.getRubyPath(); - checker = ExecChecker.ruby(); - } else if (key.equals("MSF_DIR")) { - oldPath = System.getMsfPath(); - checker = ExecChecker.msf(); - } - - if (!folder.exists()) - Toast.makeText(getActivity(), getString(R.string.pref_folder) + " " + path + " " + getString(R.string.pref_err_exists), Toast.LENGTH_SHORT).show(); - - else if (!folder.canWrite()) - Toast.makeText(getActivity(), getString(R.string.pref_folder) + " " + path + " " + getString(R.string.pref_err_writable), Toast.LENGTH_SHORT).show(); + if(canChangeDirectoryTo(key, path)) { - else if (checker != null && !checker.canExecuteInDir(path)) - Toast.makeText(getActivity(), getString(R.string.pref_folder) + " " + path + " " + getString(R.string.pref_err_executable), Toast.LENGTH_LONG).show(); - else { - //noinspection ConstantConditions getPreferenceManager().getSharedPreferences().edit().putString(key, path).commit(); - if (oldPath != null && !oldPath.equals(path)) { - File current = new File(oldPath); - if (current.exists() && current.isDirectory() && current.listFiles().length > 2) { - wipe_prompt_older(current); + if(shallAskForDelete(key)) { + String oldPath = getCurrentPathForKey(key); + if(oldPath != null) { + File current = new File(oldPath); + if(current.exists() && current.isDirectory() && current.list().length > 0) { + wipe_prompt_older(current); + } } } } diff --git a/cSploit/src/org/csploit/android/core/System.java b/cSploit/src/org/csploit/android/core/System.java index 2c144bb62d..a5b320aabb 100644 --- a/cSploit/src/org/csploit/android/core/System.java +++ b/cSploit/src/org/csploit/android/core/System.java @@ -87,6 +87,8 @@ import java.util.List; import java.util.Map; import java.util.Observer; +import java.util.SortedSet; +import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.GZIPInputStream; @@ -111,7 +113,7 @@ public class System private static WifiLock mWifiLock = null; private static WakeLock mWakeLock = null; private static Network mNetwork = null; - private static final List mTargets = new ArrayList<>(); + private static final SortedSet mTargets = new TreeSet<>(); private static Target mCurrentTarget = null; private static Map mServices = null; private static Map mPorts = null; @@ -195,22 +197,30 @@ public static void init(Context context) throws Exception{ uncaughtReloadNetworkMapping(); - ThreadHelper.getSharedExecutor().execute(new Runnable() { - @Override - public void run() { - preloadServices(); - preloadVendors(); - } - }); - } - catch(Exception e){ - if(!(e instanceof NoRouteToHostException)) + if(isCoreInstalled()) + beginLoadServicesAndVendors(); + } catch (Exception e) { + if (!(e instanceof NoRouteToHostException)) errorLogging(e); throw e; } } + private static void beginLoadServicesAndVendors() { + ThreadHelper.getSharedExecutor().execute(new Runnable() { + @Override + public void run() { + preloadVendors(); + preloadServices(); + } + }); + } + + public static void onCoreInstalled() { + beginLoadServicesAndVendors(); + } + public static void reloadTools() { getTools().reload(); } @@ -816,20 +826,11 @@ public static void loadSession(String filename) throws Exception{ // read targets int targets = Integer.parseInt(reader.readLine()); - for(int i = 0; i < targets; i++){ - Target target = new Target(reader); - - if(!hasTarget(target)){ - System.addOrderedTarget(target); - } else{ - synchronized (mTargets) { - for (int j = 0; j < mTargets.size(); j++) { - if (mTargets.get(j) != null && mTargets.get(j).equals(target)) { - mTargets.set(j, target); - break; - } - } - } + + synchronized (mTargets) { + for (int i = 0; i < targets; i++) { + Target target = new Target(reader); + mTargets.add(target); } } @@ -1026,23 +1027,16 @@ public static boolean addOrderedTarget(Target target){ if(target == null) return false; - synchronized (mTargets) { - if(mTargets.contains(target)) { - return false; - } + boolean changed; - for (int i = 0; i < mTargets.size(); i++) { - if (mTargets.get(i).comesAfter(target)) { - mTargets.add(i, target); - Services.getNetworkRadar().onNewTargetFound(target); - return true; - } + synchronized (mTargets) { + changed = mTargets.add(target); + if(changed) { + Services.getNetworkRadar().onNewTargetFound(target); + notifyTargetListChanged(); } - - mTargets.add(target); - Services.getNetworkRadar().onNewTargetFound(target); - return true; } + return changed; } public static boolean hasTarget(Target target){ @@ -1069,16 +1063,9 @@ public static Target getTargetByAddress(String address){ } public static Target getTargetByAddress(InetAddress address) { - int i, size; - synchronized (mTargets) { - - size = mTargets.size(); - - for(i=0;i { private InetAddress mAddress = null; private byte[] mHardware = null; @@ -99,14 +102,19 @@ else if(mHardware != null && endpoint.mHardware != null) { return mAddress.equals(endpoint.getAddress()); } - public InetAddress getAddress(){ - return mAddress; - } + @Override + public int compareTo(@NonNull Endpoint another) { + if(mHardware != null && another.mHardware != null) { + if(NetworkHelper.compareByteArray(mHardware, another.mHardware) == 0) { + return 0; + } + } - public long getAddressAsLong(){ - byte[] baddr = mAddress.getAddress(); + return NetworkHelper.compareInetAddresses(mAddress, another.mAddress); + } - return ((baddr[0] & 0xFFl) << 24) + ((baddr[1] & 0xFFl) << 16) + ((baddr[2] & 0xFFl) << 8) + (baddr[3] & 0xFFl); + public InetAddress getAddress(){ + return mAddress; } public void setAddress(InetAddress address){ diff --git a/cSploit/src/org/csploit/android/net/IP4Address.java b/cSploit/src/org/csploit/android/net/IP4Address.java index 8186028895..71f2f4dfb9 100644 --- a/cSploit/src/org/csploit/android/net/IP4Address.java +++ b/cSploit/src/org/csploit/android/net/IP4Address.java @@ -23,11 +23,11 @@ import java.net.UnknownHostException; import java.nio.ByteOrder; -public class IP4Address +public class IP4Address implements Comparable { private byte[] mByteArray = null; private String mString = ""; - private int mInteger = 0; + private final int mInteger; private InetAddress mAddress = null; public static int ntohl(int n){ @@ -125,6 +125,11 @@ public boolean equals(InetAddress address){ return mAddress.equals(address); } + @Override + public int compareTo(IP4Address another) { + return mInteger - another.mInteger; + } + public int getPrefixLength(){ int bits, i, n = mInteger; diff --git a/cSploit/src/org/csploit/android/net/Network.java b/cSploit/src/org/csploit/android/net/Network.java index 971948a1db..9d64cbc577 100644 --- a/cSploit/src/org/csploit/android/net/Network.java +++ b/cSploit/src/org/csploit/android/net/Network.java @@ -24,6 +24,7 @@ import android.net.NetworkInfo; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; +import android.support.annotation.NonNull; import org.apache.commons.net.util.SubnetUtils; @@ -36,7 +37,7 @@ import org.csploit.android.core.Logger; import org.csploit.android.core.System; -public class Network +public class Network implements Comparable { public enum Protocol{ TCP, @@ -265,4 +266,12 @@ public InetAddress getLocalAddress(){ public NetworkInterface getInterface(){ return mInterface; } + + @Override + public int compareTo(@NonNull Network another) { + if(mBase.equals(another.mBase)) { + return mNetmask.getPrefixLength() - another.mNetmask.getPrefixLength(); + } + return mBase.compareTo(another.mBase); + } } diff --git a/cSploit/src/org/csploit/android/net/RemoteReader.java b/cSploit/src/org/csploit/android/net/RemoteReader.java index bd2954d97f..7b6ca8809f 100644 --- a/cSploit/src/org/csploit/android/net/RemoteReader.java +++ b/cSploit/src/org/csploit/android/net/RemoteReader.java @@ -357,7 +357,6 @@ public void run() { boolean isError; InputStream stream; Notifier notifier; - URL url; running = true; @@ -385,23 +384,28 @@ public void run() { stream = null; try { - url = new URL(task.getUrl()); - } catch (MalformedURLException e) { - notifiers.execute(new Notifier(task, ("Bad URL: " + task.getUrl()).getBytes(), true)); - continue; - } + String url = task.getUrl(); - if(!url.getHost().equals(host)) { - Logger.error(String.format("RemoteReader[%s]: URL '%s' does not belong to me", host, task.getUrl())); - notifiers.execute(new Notifier(task, "Host mismatch".getBytes(), true)); - continue; - } + Logger.info("fetching '" + url + "'"); - Logger.info("fetching '" + url.toString() + "'"); + URL current = new URL(url); - try { - connection = url.openConnection(); - stream = connection.getInputStream(); + for(int i=0;i<30;i++) { + connection = current.openConnection(); + stream = connection.getInputStream(); + + if(!(connection instanceof HttpURLConnection)) + break; + + HttpURLConnection httpURLConnection = (HttpURLConnection) connection; + int code = httpURLConnection.getResponseCode(); + + if(code != HttpURLConnection.HTTP_MOVED_PERM && code != HttpURLConnection.HTTP_MOVED_TEMP ) + break; + + String location = connection.getHeaderField("Location"); + current = new URL(current, location); + } } catch (IOException e) { if (connection != null && connection instanceof HttpURLConnection) { stream = ((HttpURLConnection) connection).getErrorStream(); diff --git a/cSploit/src/org/csploit/android/net/Target.java b/cSploit/src/org/csploit/android/net/Target.java index 6b20888b38..63f17df623 100644 --- a/cSploit/src/org/csploit/android/net/Target.java +++ b/cSploit/src/org/csploit/android/net/Target.java @@ -19,6 +19,7 @@ package org.csploit.android.net; import android.os.StrictMode; +import android.support.annotation.NonNull; import org.csploit.android.R; import org.csploit.android.core.Logger; @@ -39,7 +40,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -public class Target +public class Target implements Comparable { public enum Type{ @@ -440,8 +441,34 @@ public boolean hasAlias(){ return mAlias != null && !mAlias.isEmpty(); } - public boolean comesAfter(Target target){ - return mType != Type.NETWORK && (mType != Type.ENDPOINT || target.getType() == Type.ENDPOINT && mEndpoint.getAddressAsLong() > target.getEndpoint().getAddressAsLong()); + @Override + public int compareTo(@NonNull Target another) { + if(mType != another.mType) { + if(mType == Type.NETWORK) { + return -1; + } else if (mType == Type.REMOTE) { + return +1; + } else if (another.mType == Type.NETWORK){ + return +1; + } else { // another is REMOTE + return -1; + } + } + if(mType == Type.NETWORK) { + return mNetwork.compareTo(another.mNetwork); + } else if(mType == Type.REMOTE){ + return mHostname.compareTo(another.mHostname); + } else { + try { + if (mEndpoint.getAddress().equals(System.getNetwork().getGatewayAddress())) + return -1; + else if (mEndpoint.getAddress().equals(System.getNetwork().getLocalAddress())) + return +1; + } catch (Exception e) { + System.errorLogging(e); + } + return mEndpoint.compareTo(another.mEndpoint); + } } public Target(Network net){ @@ -483,7 +510,6 @@ else if(mType == Type.REMOTE) return mHostname.equals(target.getHostname()); } - return false; } diff --git a/cSploit/src/org/csploit/android/net/datasource/Rapid7.java b/cSploit/src/org/csploit/android/net/datasource/Rapid7.java index fe5b1202a4..50df7e55ea 100644 --- a/cSploit/src/org/csploit/android/net/datasource/Rapid7.java +++ b/cSploit/src/org/csploit/android/net/datasource/Rapid7.java @@ -211,6 +211,10 @@ public static void beginFetchReferences(RemoteReader.Job job, Target.Exploit exp public void onContentFetched(byte[] content) { MsfExploit result = parsePage(new String(content)); + + if(result == null) + return; + result.copyTo(exploit); receiver.onFoundItemChanged(exploit); @@ -308,9 +312,11 @@ private void parseSearchResults(String html) { private void parseExploit(String html) { MsfExploit exploit = ExploitReceiver.parsePage(html); - exploit.setPort(port); + if(exploit != null) { + exploit.setPort(port); - receiver.onItemFound(exploit); + receiver.onItemFound(exploit); + } } @Override @@ -338,7 +344,7 @@ public String toString() { public void beginSearch(RemoteReader.Job job, String query, Target.Port port, Search.Receiver receiver) { String url; - url = "http://www.rapid7.com/db/search?q="; + url = "https://www.rapid7.com/db/search?q="; try { url += URLEncoder.encode(query, "UTF-8"); diff --git a/cSploit/src/org/csploit/android/net/http/RequestParser.java b/cSploit/src/org/csploit/android/net/http/RequestParser.java index f189ac0a16..47775edd7f 100644 --- a/cSploit/src/org/csploit/android/net/http/RequestParser.java +++ b/cSploit/src/org/csploit/android/net/http/RequestParser.java @@ -22,11 +22,14 @@ import org.csploit.android.core.Logger; import org.csploit.android.net.ByteBuffer; +import org.csploit.android.net.http.proxy.DNSCache; import java.net.HttpCookie; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class RequestParser { @@ -45,30 +48,30 @@ public class RequestParser private static final String[] TLD = { ".com.ac", ".edu.ac", ".gov.ac", - ".net.ac", ".mil.ac", ".org.ac", ".ad", ".nom.ad", ".ae", + ".net.ac", ".mil.ac", ".org.ac", ".nom.ad", ".ad", ".net.ae", ".gov.ae", ".org.ae", ".mil.ae", ".sch.ae", ".ac.ae", - ".pro.ae", ".name.ae", ".aero", ".af", ".gov.af", ".edu.af", - ".net.af", ".com.af", ".ag", ".com.ag", ".org.ag", ".net.ag", - ".co.ag", ".nom.ag", ".ai", ".off.ai", ".com.ai", ".net.ai", - ".org.ai", ".gov.al", ".edu.al", ".org.al", ".com.al", ".net.al", - ".tirana.al", ".soros.al", ".upt.al", ".am", ".an", ".com.an", - ".net.an", ".org.an", ".edu.an", ".co.ao", ".ed.ao", ".gv.ao", + ".pro.ae", ".name.ae", ".ae", ".aero", ".gov.af", ".edu.af", + ".net.af", ".com.af", ".af", ".com.ag", ".org.ag", ".net.ag", + ".co.ag", ".nom.ag", ".ag", ".off.ai", ".com.ai", ".net.ai", + ".org.ai", ".ai", ".gov.al", ".edu.al", ".org.al", ".com.al", ".net.al", + ".tirana.al", ".soros.al", ".upt.al", ".am", ".com.an", + ".net.an", ".org.an", ".edu.an", ".an", ".co.ao", ".ed.ao", ".gv.ao", ".it.ao", ".og.ao", ".pb.ao", ".com.ar", ".gov.ar", ".int.ar", ".mil.ar", ".net.ar", ".org.ar", ".iris.arpa", ".uri.arpa", - ".urn.arpa", ".as", ".at", ".gv.at", ".ac.at", ".co.at", ".or.at", - ".priv.at", ".asn.au", ".com.au", ".net.au", ".id.au", ".org.au", + ".urn.arpa", ".as", ".gv.at", ".ac.at", ".co.at", ".or.at", + ".priv.at", ".at", ".asn.au", ".com.au", ".net.au", ".id.au", ".org.au", ".csiro.au", ".oz.au", ".info.au", ".conf.au", ".act.au", ".nsw.au", ".nt.au", ".qld.au", ".sa.au", ".tas.au", ".vic.au", ".wa.auFor", ".gov.au", ".and", ".act", ".nsw", ".nt", ".qld", - ".sa", ".tas", ".vic", ".wa", ".aw", ".com.aw", ".ax", ".az", + ".sa", ".tas", ".vic", ".wa", ".com.aw", ".aw", ".ax", ".com.az", ".net.az", ".int.az", ".gov.az", ".biz.az", ".org.az", - ".edu.az", ".mil.az", ".pp.az", ".name.az", ".info.az", ".com.bb", + ".edu.az", ".mil.az", ".pp.az", ".name.az", ".info.az", ".az", ".com.bb", ".edu.bb", ".gov.bb", ".net.bb", ".org.bb", ".com.bd", ".edu.bd", ".net.bd", ".gov.bd", ".org.bd", ".mil.bd", ".ac.be", ".gov.bf", ".possibly", ".com.bm", ".edu.bm", ".org.bm", ".gov.bm", ".net.bm", - ".com.bn", ".edu.bn", ".org.bn", ".net.bn", ".bo", ".com.bo", + ".com.bn", ".edu.bn", ".org.bn", ".net.bn", ".com.bo", ".org.bo", ".net.bo", ".gov.bo", ".gob.bo", ".edu.bo", ".tv.bo", - ".mil.bo", ".int.bo", ".agr.br", ".am.br", ".art.br", ".edu.br", + ".mil.bo", ".int.bo", ".bo", ".agr.br", ".am.br", ".art.br", ".edu.br", ".com.br", ".coop.br", ".esp.br", ".far.br", ".fm.br", ".gov.br", ".imb.br", ".ind.br", ".inf.br", ".mil.br", ".net.br", ".org.br", ".psi.br", ".rec.br", ".srv.br", ".tmp.br", ".tur.br", ".tv.br", @@ -77,71 +80,71 @@ public class RequestParser ".eti.br", ".fnd.br", ".fot.br", ".fst.br", ".ggf.br", ".jor.br", ".lel.br", ".mat.br", ".med.br", ".mus.br", ".not.br", ".ntr.br", ".odo.br", ".ppg.br", ".pro.br", ".psc.br", ".qsl.br", ".slg.br", - ".trd.br", ".vet.br", ".zlg.br", ".dpn.br", ".nom.br", ".bs", - ".com.bs", ".net.bs", ".org.bs", ".bt", ".com.bt", ".edu.bt", - ".gov.bt", ".net.bt", ".org.bt", ".bw", ".co.bw", ".org.bw", - ".gov.by", ".mil.by", ".ca", ".ab.ca", ".bc.ca", ".mb.ca", + ".trd.br", ".vet.br", ".zlg.br", ".dpn.br", ".nom.br", + ".com.bs", ".net.bs", ".org.bs", ".bs", ".com.bt", ".edu.bt", + ".gov.bt", ".net.bt", ".org.bt", ".bt", ".co.bw", ".org.bw", ".bw", + ".gov.by", ".mil.by", ".ab.ca", ".bc.ca", ".mb.ca", ".nb.ca", ".nf.ca", ".nl.ca", ".ns.ca", ".nt.ca", ".nu.ca", - ".on.ca", ".pe.ca", ".qc.ca", ".sk.ca", ".yk.ca", ".cc", ".co.cc", - ".cd", ".com.cd", ".net.cd", ".org.cd", ".ch", ".com.ch", - ".net.ch", ".org.ch", ".gov.ch", ".co.ck", ".others", ".cn", + ".on.ca", ".pe.ca", ".qc.ca", ".sk.ca", ".yk.ca", ".ca", ".co.cc", ".cc", + ".com.cd", ".net.cd", ".org.cd", ".cd", ".com.ch", + ".net.ch", ".org.ch", ".gov.ch", ".ch", ".co.ck", ".others", ".ac.cn", ".com.cn", ".edu.cn", ".gov.cn", ".net.cn", ".org.cn", ".ah.cn", ".bj.cn", ".cq.cn", ".fj.cn", ".gd.cn", ".gs.cn", ".gz.cn", ".gx.cn", ".ha.cn", ".hb.cn", ".he.cn", ".hi.cn", ".hl.cn", ".hn.cn", ".jl.cn", ".js.cn", ".jx.cn", ".ln.cn", ".nm.cn", ".nx.cn", ".qh.cn", ".sc.cn", ".sd.cn", ".sh.cn", ".sn.cn", ".sx.cn", ".tj.cn", ".xj.cn", ".xz.cn", ".yn.cn", - ".zj.cn", ".com.co", ".edu.co", ".org.co", ".gov.co", ".mil.co", + ".zj.cn", ".cn", ".com.co", ".edu.co", ".org.co", ".gov.co", ".mil.co", ".net.co", ".nom.co", ".ac.cr", ".co.cr", ".ed.cr", ".fi.cr", - ".go.cr", ".or.cr", ".sa.cr", ".cu", ".com.cu", ".edu.cu", - ".org.cu", ".net.cu", ".gov.cu", ".inf.cu", ".cx", ".gov.cx", + ".go.cr", ".or.cr", ".sa.cr", ".com.cu", ".edu.cu", + ".org.cu", ".net.cu", ".gov.cu", ".inf.cu", ".cu", ".gov.cx", ".cx", ".com.cy", ".biz.cy", ".info.cy", ".ltd.cy", ".pro.cy", ".net.cy", ".org.cy", ".name.cy", ".tm.cy", ".ac.cy", ".ekloges.cy", - ".press.cy", ".parliament.cy", ".dm", ".com.dm", ".net.dm", - ".org.dm", ".edu.dm", ".gov.dm", ".edu.do", ".gov.do", ".gob.do", + ".press.cy", ".parliament.cy", ".com.dm", ".net.dm", + ".org.dm", ".edu.dm", ".gov.dm", ".dm", ".edu.do", ".gov.do", ".gob.do", ".com.do", ".org.do", ".sld.do", ".web.do", ".net.do", ".mil.do", - ".art.do", ".dz", ".com.dz", ".org.dz", ".net.dz", ".gov.dz", - ".edu.dz", ".asso.dz", ".pol.dz", ".art.dz", ".ec", ".com.ec", + ".art.do", ".com.dz", ".org.dz", ".net.dz", ".gov.dz", + ".edu.dz", ".asso.dz", ".pol.dz", ".art.dz", ".dz", ".com.ec", ".info.ec", ".net.ec", ".fin.ec", ".med.ec", ".pro.ec", ".org.ec", - ".edu.ec", ".gov.ec", ".mil.ec", ".ee", ".com.ee", ".org.ee", - ".fie.ee", ".pri.ee", ".eun.eg", ".edu.eg", ".sci.eg", ".gov.eg", - ".com.eg", ".org.eg", ".net.eg", ".mil.eg", ".es", ".com.es", - ".nom.es", ".org.es", ".gob.es", ".edu.es", ".com.et", ".gov.et", + ".edu.ec", ".gov.ec", ".mil.ec", ".ec",".com.ee", ".org.ee", + ".fie.ee", ".pri.ee", ".ee", ".eun.eg", ".edu.eg", ".sci.eg", ".gov.eg", + ".com.eg", ".org.eg", ".net.eg", ".mil.eg", ".com.es", + ".nom.es", ".org.es", ".gob.es", ".edu.es", ".es", ".com.et", ".gov.et", ".org.et", ".edu.et", ".net.et", ".biz.et", ".name.et", ".info.et", - ".fi", ".aland.fi", ".biz.fj", ".com.fj", ".info.fj", ".name.fj", + ".aland.fi", ".fi", ".biz.fj", ".com.fj", ".info.fj", ".name.fj", ".net.fj", ".org.fj", ".pro.fj", ".ac.fj", ".gov.fj", ".mil.fj", ".school.fj", ".co.fk", ".org.fk", ".gov.fk", ".ac.fk", ".nom.fk", - ".net.fk", ".fr", ".tm.fr", ".asso.fr", ".nom.fr", ".prd.fr", - ".presse.fr", ".com.fr", ".gouv.fr", ".ge", ".com.ge", ".edu.ge", - ".gov.ge", ".org.ge", ".mil.ge", ".net.ge", ".pvt.ge", ".gg", - ".co.gg", ".net.gg", ".org.gg", ".com.gh", ".edu.gh", ".gov.gh", - ".org.gh", ".mil.gh", ".gi", ".com.gi", ".ltd.gi", ".gov.gi", + ".net.fk", ".tm.fr", ".asso.fr", ".nom.fr", ".prd.fr", + ".presse.fr", ".com.fr", ".gouv.fr", ".fr", ".com.ge", ".edu.ge", + ".gov.ge", ".org.ge", ".mil.ge", ".net.ge", ".pvt.ge", ".ge", + ".co.gg", ".net.gg", ".org.gg", ".gg", ".com.gh", ".edu.gh", ".gov.gh", + ".org.gh", ".mil.gh", ".gh", ".com.gi", ".ltd.gi", ".gov.gi", ".mod.gi", ".edu.gi", ".org.gi", ".com.gn", ".ac.gn", ".gov.gn", - ".org.gn", ".net.gn", ".gp", ".or", ".org.gp", ".gr", ".com.gr", - ".edu.gr", ".net.gr", ".org.gr", ".gov.gr", ".hk", ".com.hk", - ".edu.hk", ".gov.hk", ".idv.hk", ".net.hk", ".org.hk", ".hn", + ".org.gn", ".net.gn", ".gn", ".or", ".org.gp", ".gp", ".com.gr", + ".edu.gr", ".net.gr", ".org.gr", ".gov.gr", ".gr", ".com.hk", + ".edu.hk", ".gov.hk", ".idv.hk", ".net.hk", ".org.hk", ".hk", ".com.hn", ".edu.hn", ".org.hn", ".net.hn", ".mil.hn", ".gob.hn", - ".hr", ".iz.hr", ".from.hr", ".name.hr", ".com.hr", ".ht", + ".hn", ".iz.hr", ".from.hr", ".name.hr", ".com.hr", ".hr", ".com.ht", ".net.ht", ".firm.ht", ".shop.ht", ".info.ht", ".pro.ht", ".adult.ht", ".org.ht", ".art.ht", ".pol.ht", ".rel.ht", ".asso.ht", ".perso.ht", ".coop.ht", ".med.ht", ".edu.ht", - ".gouv.ht", ".hu", ".co.hu", ".info.hu", ".org.hu", ".priv.hu", + ".gouv.ht", ".ht", ".co.hu", ".info.hu", ".org.hu", ".priv.hu", ".sport.hu", ".tm.hu", ".agrar.hu", ".bolt.hu", ".casino.hu", ".city.hu", ".erotica.hu", ".erotika.hu", ".film.hu", ".forum.hu", ".games.hu", ".hotel.hu", ".ingatlan.hu", ".jogasz.hu", ".konyvelo.hu", ".lakas.hu", ".media.hu", ".news.hu", ".reklam.hu", ".sex.hu", ".shop.hu", ".suli.hu", ".szex.hu", ".tozsde.hu", - ".utazas.hu", ".video.hu", ".ac.id", ".co.id", ".or.id", ".go.id", - ".ie", ".gov.ie", ".ac.il", ".co.il", ".org.il", ".net.il", + ".utazas.hu", ".video.hu", ".hu", ".ac.id", ".co.id", ".or.id", ".go.id", + ".gov.ie", ".ie", ".ac.il", ".co.il", ".org.il", ".net.il", ".gov.il", ".muni.il", ".idf.il", ".co.im", ".ltd.co.im", ".plc.co.im", ".net.im", ".gov.im", ".org.im", ".nic.im", ".ac.im", - ".in", ".co.in", ".firm.in", ".net.in", ".org.in", ".gen.in", + ".co.in", ".firm.in", ".net.in", ".org.in", ".gen.in", ".ind.in", ".nic.in", ".ac.in", ".edu.in", ".res.in", ".gov.in", - ".mil.in", ".ir", ".ac.ir", ".co.ir", ".gov.ir", ".net.ir", - ".org.ir", ".sch.ir", ".it", ".gov.it", "...", ".je", ".co.je", - ".net.je", ".org.je", ".edu.jm", ".gov.jm", ".com.jm", ".net.jm", - ".org.jm", ".jo", ".com.jo", ".org.jo", ".net.jo", ".edu.jo", - ".gov.jo", ".mil.jo", ".jp", ".ac.jp", ".ad.jp", ".co.jp", + ".mil.in", ".in", ".ac.ir", ".co.ir", ".gov.ir", ".net.ir", + ".org.ir", ".sch.ir", ".ir", ".gov.it", ".it", ".co.je", + ".net.je", ".org.je", ".je", ".edu.jm", ".gov.jm", ".com.jm", ".net.jm", + ".org.jm", ".com.jo", ".org.jo", ".net.jo", ".edu.jo", + ".gov.jo", ".mil.jo", ".jo", ".ac.jp", ".ad.jp", ".co.jp", ".ed.jp", ".go.jp", ".gr.jp", ".lg.jp", ".ne.jp", ".hokkaido.jp", ".aomori.jp", ".iwate.jp", ".miyagi.jp", ".akita.jp", ".yamagata.jp", ".fukushima.jp", ".ibaraki.jp", ".tochigi.jp", @@ -155,30 +158,30 @@ public class RequestParser ".kochi.jp", ".fukuoka.jp", ".saga.jp", ".nagasaki.jp", ".kumamoto.jp", ".oita.jp", ".miyazaki.jp", ".kagoshima.jp", ".okinawa.jp", ".sapporo.jp", ".sendai.jp", ".yokohama.jp", - ".kawasaki.jp", ".nagoya.jp", ".kobe.jp", ".kitakyushu.jp", + ".kawasaki.jp", ".nagoya.jp", ".kobe.jp", ".kitakyushu.jp", ".jp", ".per.kh", ".com.kh", ".edu.kh", ".gov.kh", ".mil.kh", ".net.kh", - ".org.kh", ".kr", ".co.kr", ".or.kr", ".com.kw", ".edu.kw", - ".gov.kw", ".net.kw", ".org.kw", ".mil.kw", ".ky", ".edu.ky", - ".gov.ky", ".com.ky", ".org.ky", ".net.ky", ".org.kz", ".edu.kz", + ".org.kh", ".co.kr", ".or.kr", ".kr", ".com.kw", ".edu.kw", + ".gov.kw", ".net.kw", ".org.kw", ".mil.kw", ".edu.ky", + ".gov.ky", ".com.ky", ".org.ky", ".net.ky", ".ky", ".org.kz", ".edu.kz", ".net.kz", ".gov.kz", ".mil.kz", ".com.kz", ".net.lb", ".org.lb", ".gov.lb", ".edu.lb", ".com.lb", ".com.lc", ".org.lc", ".edu.lc", - ".gov.lc", ".li", ".com.li", ".net.li", ".org.li", ".gov.li", - ".lk", ".gov.lk", ".sch.lk", ".net.lk", ".int.lk", ".com.lk", + ".gov.lc", ".com.li", ".net.li", ".org.li", ".gov.li", ".li", + ".gov.lk", ".sch.lk", ".net.lk", ".int.lk", ".com.lk", ".org.lk", ".edu.lk", ".ngo.lk", ".soc.lk", ".web.lk", ".ltd.lk", - ".assn.lk", ".grp.lk", ".hotel.lk", ".com.lr", ".edu.lr", - ".gov.lr", ".org.lr", ".net.lr", ".org.ls", ".co.ls", ".lt", - ".gov.lt", ".mil.lt", ".lu", ".gov.lu", ".mil.lu", ".org.lu", - ".net.lu", ".lv", ".com.lv", ".edu.lv", ".gov.lv", ".org.lv", - ".mil.lv", ".id.lv", ".net.lv", ".asn.lv", ".conf.lv", ".ly", + ".assn.lk", ".grp.lk", ".hotel.lk", ".lk", ".com.lr", ".edu.lr", + ".gov.lr", ".org.lr", ".net.lr", ".org.ls", ".co.ls", + ".gov.lt", ".mil.lt", ".lt", ".gov.lu", ".mil.lu", ".org.lu", + ".net.lu", ".lu", ".com.lv", ".edu.lv", ".gov.lv", ".org.lv", + ".mil.lv", ".id.lv", ".net.lv", ".asn.lv", ".conf.lv", ".lv", ".com.ly", ".net.ly", ".gov.ly", ".plc.ly", ".edu.ly", ".sch.ly", - ".med.ly", ".org.ly", ".id.ly", ".ma", ".co.ma", ".net.ma", - ".gov.ma", ".org.ma", ".mc", ".tm.mc", ".asso.mc", ".mg", + ".med.ly", ".org.ly", ".id.ly", ".ly", ".co.ma", ".net.ma", + ".gov.ma", ".org.ma", ".ma", ".tm.mc", ".asso.mc", ".mc", ".org.mg", ".nom.mg", ".gov.mg", ".prd.mg", ".tm.mg", ".com.mg", - ".edu.mg", ".mil.mg", ".army.mil", ".navy.mil", ".mk", ".com.mk", - ".org.mk", ".mo", ".com.mo", ".net.mo", ".org.mo", ".edu.mo", - ".gov.mo", ".weather.mobi", ".music.mobi", ".mt", ".org.mt", - ".com.mt", ".gov.mt", ".edu.mt", ".net.mt", ".mu", ".com.mu", - ".co.mu", ".aero.mv", ".biz.mv", ".com.mv", ".coop.mv", ".edu.mv", + ".edu.mg", ".mil.mg", ".mg", ".army.mil", ".navy.mil", ".com.mk", + ".org.mk", ".mk", ".com.mo", ".net.mo", ".org.mo", ".edu.mo", + ".gov.mo", ".mo", ".weather.mobi", ".music.mobi", ".org.mt", + ".com.mt", ".gov.mt", ".edu.mt", ".net.mt", ".mt", ".com.mu", + ".co.mu", ".mu", ".aero.mv", ".biz.mv", ".com.mv", ".coop.mv", ".edu.mv", ".gov.mv", ".info.mv", ".int.mv", ".mil.mv", ".museum.mv", ".name.mv", ".net.mv", ".org.mv", ".pro.mv", ".ac.mw", ".co.mw", ".com.mw", ".coop.mw", ".edu.mw", ".gov.mw", ".int.mw", @@ -186,12 +189,12 @@ public class RequestParser ".org.mx", ".edu.mx", ".gob.mx", ".com.my", ".net.my", ".org.my", ".gov.my", ".edu.my", ".mil.my", ".name.my", ".edu.ng", ".com.ng", ".gov.ng", ".org.ng", ".net.ng", ".gob.ni", ".com.ni", ".edu.ni", - ".org.ni", ".nom.ni", ".net.ni", ".nl", ".no", ".mil.no", + ".org.ni", ".nom.ni", ".net.ni", ".nl", ".mil.no", ".stat.no", ".kommune.no", ".herad.no", ".priv.no", ".vgs.no", ".fhs.no", ".museum.no", ".fylkesbibl.no", ".folkebibl.no", - ".idrett.no", ".com.np", ".org.np", ".edu.np", ".net.np", - ".gov.np", ".mil.np", ".nr", ".gov.nr", ".edu.nr", ".biz.nr", - ".info.nr", ".org.nr", ".com.nr", ".net.nr", ".ac.nz", ".co.nz", + ".idrett.no", ".no", ".com.np", ".org.np", ".edu.np", ".net.np", + ".gov.np", ".mil.np", ".gov.nr", ".edu.nr", ".biz.nr", + ".info.nr", ".org.nr", ".com.nr", ".net.nr", ".nr", ".ac.nz", ".co.nz", ".cri.nz", ".gen.nz", ".geek.nz", ".govt.nz", ".iwi.nz", ".maori.nz", ".mil.nz", ".net.nz", ".org.nz", ".school.nz", ".com.om", ".co.om", ".edu.om", ".ac.com", ".sch.om", ".gov.om", @@ -199,55 +202,55 @@ public class RequestParser ".pro.om", ".med.om", ".com.pa", ".ac.pa", ".sld.pa", ".gob.pa", ".edu.pa", ".org.pa", ".net.pa", ".abo.pa", ".ing.pa", ".med.pa", ".nom.pa", ".com.pe", ".org.pe", ".net.pe", ".edu.pe", ".mil.pe", - ".gob.pe", ".nom.pe", ".pf", ".com.pf", ".org.pf", ".edu.pf", - ".com.pg", ".net.pg", ".ph", ".com.ph", ".gov.ph", ".pk", + ".gob.pe", ".nom.pe", ".com.pf", ".org.pf", ".edu.pf", ".pf", + ".com.pg", ".net.pg", ".com.ph", ".gov.ph", ".ph", ".com.pk", ".net.pk", ".edu.pk", ".org.pk", ".fam.pk", ".biz.pk", ".web.pk", ".gov.pk", ".gob.pk", ".gok.pk", ".gon.pk", ".gop.pk", - ".gos.pk", ".pl", ".com.pl", ".biz.pl", ".net.pl", ".art.pl", + ".gos.pk", ".pk", ".com.pl", ".biz.pl", ".net.pl", ".art.pl", ".edu.pl", ".org.pl", ".ngo.pl", ".gov.pl", ".info.pl", ".mil.pl", ".waw.pl", ".warszawa.pl", ".wroc.pl", ".wroclaw.pl", ".krakow.pl", ".poznan.pl", ".lodz.pl", ".gda.pl", ".gdansk.pl", ".slupsk.pl", ".szczecin.pl", ".lublin.pl", ".bialystok.pl", - ".olsztyn.pl.torun.pl", ".more...", ".pr", ".biz.pr", ".com.pr", + ".olsztyn.pl.torun.pl", ".pl", ".biz.pr", ".com.pr", ".edu.pr", ".gov.pr", ".info.pr", ".isla.pr", ".name.pr", - ".net.pr", ".org.pr", ".pro.pr", ".law.pro", ".med.pro", - ".cpa.pro", ".ps", ".edu.ps", ".gov.ps", ".sec.ps", ".plo.ps", - ".com.ps", ".org.ps", ".net.ps", ".pt", ".com.pt", ".edu.pt", - ".gov.pt", ".int.pt", ".net.pt", ".nome.pt", ".org.pt", ".publ.pt", - ".net.py", ".org.py", ".gov.py", ".edu.py", ".com.py", ".ro", + ".net.pr", ".org.pr", ".pro.pr", ".pr", ".law.pro", ".med.pro", + ".cpa.pro", ".edu.ps", ".gov.ps", ".sec.ps", ".plo.ps", + ".com.ps", ".org.ps", ".net.ps", ".ps", ".com.pt", ".edu.pt", + ".gov.pt", ".int.pt", ".net.pt", ".nome.pt", ".org.pt", ".publ.pt", ".pt", + ".net.py", ".org.py", ".gov.py", ".edu.py", ".com.py", ".com.ro", ".org.ro", ".tm.ro", ".nt.ro", ".nom.ro", ".info.ro", - ".rec.ro", ".arts.ro", ".firm.ro", ".store.ro", ".www.ro", ".ru", + ".rec.ro", ".arts.ro", ".firm.ro", ".store.ro", ".www.ro", ".ro", ".com.ru", ".net.ru", ".org.ru", ".pp.ru", ".msk.ru", ".int.ru", - ".ac.ru", ".rw", ".gov.rw", ".net.rw", ".edu.rw", ".ac.rw", - ".com.rw", ".co.rw", ".int.rw", ".mil.rw", ".gouv.rw", ".com.sa", + ".ac.ru", ".ru", ".gov.rw", ".net.rw", ".edu.rw", ".ac.rw", + ".com.rw", ".co.rw", ".int.rw", ".mil.rw", ".gouv.rw", ".rw", ".com.sa", ".edu.sa", ".sch.sa", ".med.sa", ".gov.sa", ".net.sa", ".org.sa", - ".pub.sa", ".com.sb", ".gov.sb", ".net.sb", ".edu.sb", ".sc", - ".com.sc", ".gov.sc", ".net.sc", ".org.sc", ".edu.sc", ".sd", + ".pub.sa", ".com.sb", ".gov.sb", ".net.sb", ".edu.sb", + ".com.sc", ".gov.sc", ".net.sc", ".org.sc", ".edu.sc", ".sc", ".com.sd", ".net.sd", ".org.sd", ".edu.sd", ".med.sd", ".tv.sd", - ".gov.sd", ".info.sd", ".se", ".org.se", ".pp.se", ".tm.se", + ".gov.sd", ".info.sd", ".sd", ".org.se", ".pp.se", ".tm.se", ".brand.se", ".parti.se", ".press.se", ".komforb.se", ".kommunalforbund.se", ".komvux.se", ".lanarb.se", ".lanbib.se", ".naturbruksgymn.se", ".sshn.se", ".fhv.se", ".fhsk.se", ".fh.se", ".ab.se", ".c.se", ".d.se", ".e.se", ".f.se", ".g.se", ".h.se", ".i.se", ".k.se", ".m.se", ".n.se", ".o.se", ".s.se", ".t.se", - ".u.se", ".w.se", ".x.se", ".y.se", ".z.se", ".ac.se", ".bd.se", - ".sg", ".com.sg", ".net.sg", ".org.sg", ".gov.sg", ".edu.sg", - ".per.sg", ".idn.sg", ".edu.sv", ".com.sv", ".gob.sv", ".org.sv", + ".u.se", ".w.se", ".x.se", ".y.se", ".z.se", ".ac.se", ".bd.se", ".se", + ".com.sg", ".net.sg", ".org.sg", ".gov.sg", ".edu.sg", + ".per.sg", ".idn.sg", ".sg", ".edu.sv", ".com.sv", ".gob.sv", ".org.sv", ".red.sv", ".gov.sy", ".com.sy", ".net.sy", ".ac.th", ".co.th", - ".in.th", ".go.th", ".mi.th", ".or.th", ".net.th", ".tj", ".ac.tj", + ".in.th", ".go.th", ".mi.th", ".or.th", ".net.th", ".ac.tj", ".biz.tj", ".com.tj", ".co.tj", ".edu.tj", ".int.tj", ".name.tj", - ".net.tj", ".org.tj", ".web.tj", ".gov.tj", ".go.tj", ".mil.tj", + ".net.tj", ".org.tj", ".web.tj", ".gov.tj", ".go.tj", ".mil.tj", ".tj", ".com.tn", ".intl.tn", ".gov.tn", ".org.tn", ".ind.tn", ".nat.tn", ".tourism.tn", ".info.tn", ".ens.tn", ".fin.tn", ".net.tn", ".to", - ".gov.to", ".tp", ".gov.tp", ".com.tr", ".info.tr", ".biz.tr", + ".gov.to", ".gov.tp", ".tp", ".com.tr", ".info.tr", ".biz.tr", ".net.tr", ".org.tr", ".web.tr", ".gen.tr", ".av.tr", ".dr.tr", ".bbs.tr", ".name.tr", ".tel.tr", ".gov.tr", ".bel.tr", ".pol.tr", - ".mil.tr", ".edu.tr", ".tt", ".co.tt", ".com.tt", ".org.tt", + ".mil.tr", ".edu.tr", ".co.tt", ".com.tt", ".org.tt", ".net.tt", ".biz.tt", ".info.tt", ".pro.tt", ".name.tt", ".edu.tt", - ".gov.tt", ".tv", ".gov.tv", ".tw", ".edu.tw", ".gov.tw", + ".gov.tt", ".tt", ".gov.tv", ".tv", ".edu.tw", ".gov.tw", ".mil.tw", ".com.tw", ".net.tw", ".org.tw", ".idv.tw", ".game.tw", - ".ebiz.tw", ".club.tw", ".co.tz", ".ac.tz", ".go.tz", ".or.tz", - ".ne.tz", ".ua", ".com.ua", ".gov.ua", ".net.ua", ".edu.ua", + ".ebiz.tw", ".club.tw", ".tw", ".co.tz", ".ac.tz", ".go.tz", ".or.tz", + ".ne.tz", ".com.ua", ".gov.ua", ".net.ua", ".edu.ua", ".org.uaGeographical", ".cherkassy.ua", ".ck.ua", ".chernigov.ua", ".cn.ua", ".chernovtsy.ua", ".cv.ua", ".crimea.ua", ".dnepropetrovsk.ua", ".dp.ua", ".donetsk.ua", ".dn.ua", ".if.ua", @@ -258,12 +261,12 @@ public class RequestParser ".poltava.ua", ".pl.ua", ".rovno.ua", ".rv.ua", ".sebastopol.ua", ".sumy.ua", ".ternopil.ua", ".te.ua", ".uzhgorod.ua", ".vinnica.ua", ".vn.ua", ".zaporizhzhe.ua", ".zp.ua", - ".zhitomir.ua", ".zt.ua", ".ug", ".co.ug", ".ac.ug", ".sc.ug", - ".go.ug", ".ne.ug", ".or.ug", ".ac.uk", ".co.uk", ".gov.uk", + ".zhitomir.ua", ".zt.ua", ".ua", ".co.ug", ".ac.ug", ".sc.ug", + ".go.ug", ".ne.ug", ".or.ug", ".ug", ".ac.uk", ".co.uk", ".gov.uk", ".ltd.uk", ".me.uk", ".mil.uk", ".mod.uk", ".net.uk", ".nic.uk", ".nhs.uk", ".org.uk", ".plc.uk", ".police.uk", ".bl.uk", ".icnet.uk", ".jet.uk", ".nel.uk", ".nls.uk", - ".parliament.uk.sch.uk", ".uses", ".level", ".domains", ".us", + ".parliament.uk.sch.uk", ".uses", ".level", ".domains", ".ak.us", ".al.us", ".ar.us", ".az.us", ".ca.us", ".co.us", ".ct.us", ".dc.us", ".de.us", ".dni.us", ".fed.us", ".fl.us", ".ga.us", ".hi.us", ".ia.us", ".id.us", ".il.us", ".in.us", @@ -273,12 +276,12 @@ public class RequestParser ".nm.us", ".nsn.us", ".nv.us", ".ny.us", ".oh.us", ".ok.us", ".or.us", ".pa.us", ".ri.us", ".sc.us", ".sd.us", ".tn.us", ".tx.us", ".ut.us", ".vt.us", ".va.us", ".wa.us", ".wi.us", - ".wv.us", ".wy.us", ".edu.uy", ".gub.uy", ".org.uy", ".com.uy", + ".wv.us", ".wy.us", ".us", ".edu.uy", ".gub.uy", ".org.uy", ".com.uy", ".net.uy", ".mil.uy", ".vatican.va", ".com.ve", ".net.ve", - ".org.ve", ".info.ve", ".co.ve", ".web.ve", ".vi", ".com.vi", - ".org.vi", ".edu.vi", ".gov.vi", ".vn", ".com.vn", ".net.vn", + ".org.ve", ".info.ve", ".co.ve", ".web.ve", ".com.vi", + ".org.vi", ".edu.vi", ".gov.vi", ".vi", ".com.vn", ".net.vn", ".org.vn", ".edu.vn", ".gov.vn", ".int.vn", ".ac.vn", ".biz.vn", - ".info.vn", ".name.vn", ".pro.vn", ".health.vn", ".com.ye", + ".info.vn", ".name.vn", ".pro.vn", ".health.vn", ".vn", ".com.ye", ".net.ye", ".ac.yu", ".co.yu", ".org.yu", ".edu.yu", ".ac.za", ".city.za", ".co.za", ".edu.za", ".gov.za", ".law.za", ".mil.za", ".nom.za", ".org.za", ".school.za", ".alt.za", ".net.za", @@ -288,26 +291,38 @@ public class RequestParser public static String getBaseDomain(String hostname){ - String domain = ""; - // if hostname is an IP address return that address if(Patterns.IP_ADDRESS.matcher(hostname).matches()) return hostname; + String cached_domain = DNSCache.getInstance().getRootDomain(hostname); + if (cached_domain != null) { + return cached_domain; + } + for(String tld : TLD){ if(hostname.endsWith(tld)){ String[] host_parts = hostname.split("\\."), tld_parts = tld.split("\\."); int itld = tld_parts.length, ihost = host_parts.length, - i = 0, - stop = ihost - 1; + i = 0; + + if ((ihost - itld) == 0 || ihost == 2) + return hostname; + + StringBuilder sb = new StringBuilder(); - domain = ""; - for(i = ihost - itld; i <= stop; i++){ - domain += host_parts[i] + (i == stop ? "" : "."); + for(i = ihost - itld; i < ihost; i++){ + sb.append(host_parts[i]); + if(i < ihost - 1) { + sb.append("."); + } } + String domain = sb.toString(); + + DNSCache.getInstance().addRootDomain(domain); return domain; } } @@ -316,14 +331,15 @@ public static String getBaseDomain(String hostname){ nextIndex = hostname.indexOf('.'), lastIndex = hostname.lastIndexOf('.'); - while(nextIndex < lastIndex){ + while(nextIndex < lastIndex) { startIndex = nextIndex + 1; nextIndex = hostname.indexOf('.', startIndex); } - if(startIndex > 0) + if(startIndex > 0) { + DNSCache.getInstance().addRootDomain(hostname.substring(startIndex)); return hostname.substring(startIndex); - + } else return hostname; } @@ -478,4 +494,48 @@ public static ArrayList getCookiesFromHeaders(ArrayList head return null; } + + /** + * extract the charset encoding from the HTTP response headers. + * + * @param contentType content-type header to be parsed + * @return returns the charset encoding if we've found it, or null. + */ + public static String getCharsetFromHeaders(String contentType){ + if (contentType != null && contentType.toLowerCase().trim().contains("charset=")){ + String[] parts = contentType.toLowerCase().trim().split("="); + if (parts.length > 0) + return parts[1]; + } + + return null; + } + + /** + * extract the charset encoding of a web site from the headers. + * + * @param body html body of the site to be parsed + * @return returns the charset encoding if we've found it, or null. + */ + public static String getCharsetFromBody(String body) { + if (body != null) { + int headEnd = body.toLowerCase().trim().indexOf(""); + + // return null if there's no head tags + if (headEnd == -1) + return null; + + String body_head = body.toLowerCase().substring(0, headEnd); + + Pattern p = Pattern.compile("charset=([\"\'a-z0-9A-Z-]+)"); + Matcher m = p.matcher(body_head); + String str_match = ""; + if (m.find()) { + str_match = m.toMatchResult().group(1); + return str_match.replaceAll("[\"']", ""); + } + } + + return null; + } } diff --git a/cSploit/src/org/csploit/android/net/http/proxy/DNSCache.java b/cSploit/src/org/csploit/android/net/http/proxy/DNSCache.java index b8f474e264..3303ae0f5d 100644 --- a/cSploit/src/org/csploit/android/net/http/proxy/DNSCache.java +++ b/cSploit/src/org/csploit/android/net/http/proxy/DNSCache.java @@ -18,30 +18,60 @@ */ package org.csploit.android.net.http.proxy; +import org.csploit.android.core.Logger; + import java.io.IOException; import java.net.InetAddress; import java.net.Socket; +import java.util.ArrayList; import java.util.HashMap; import javax.net.SocketFactory; -import org.csploit.android.core.Logger; - public class DNSCache { - private static DNSCache mInstance = null; + private static DNSCache mInstance = new DNSCache(); - private HashMap mCache = null; + private final HashMap mCache; + private final ArrayList mRootDomainCache; public static DNSCache getInstance(){ - if(mInstance == null) - mInstance = new DNSCache(); - return mInstance; } - public DNSCache(){ - mCache = new HashMap(); + private DNSCache() { + mCache = new HashMap<>(); + mRootDomainCache = new ArrayList<>(); + } + + /** + * checks if a domain ends with an already intercepted root domain. + * + * @param hostname hostname to check + * @return String the root domain or null + */ + public String getRootDomain(String hostname){ + synchronized (mRootDomainCache) { + for (String rootDomain : mRootDomainCache) { + if (hostname.endsWith(rootDomain)) { + return rootDomain; + } + } + } + + return null; + } + + /** + * Adds a root domain extracted from the domain of a request, + * to the list of intercepted root domains. + * + * @param rootdomain Root domain to add to the list + */ + public void addRootDomain(String rootdomain){ + synchronized (mRootDomainCache) { + mRootDomainCache.add(rootdomain); + } } private InetAddress getAddress(String server) throws IOException{ diff --git a/cSploit/src/org/csploit/android/net/http/proxy/StreamThread.java b/cSploit/src/org/csploit/android/net/http/proxy/StreamThread.java index 54928d2b94..918b0a9963 100644 --- a/cSploit/src/org/csploit/android/net/http/proxy/StreamThread.java +++ b/cSploit/src/org/csploit/android/net/http/proxy/StreamThread.java @@ -18,16 +18,17 @@ */ package org.csploit.android.net.http.proxy; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - +import org.csploit.android.core.Logger; import org.csploit.android.core.Profiler; import org.csploit.android.core.System; -import org.csploit.android.core.Logger; import org.csploit.android.net.ByteBuffer; import org.csploit.android.net.http.RequestParser; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + public class StreamThread implements Runnable { private final static String[] FILTERED_CONTENT_TYPES = new String[] @@ -159,7 +160,27 @@ public void run(){ headers = patched; - mBuffer.setData((headers + HEAD_SEPARATOR + body).getBytes()); + // try to get the charset encoding from the HTTP headers. + String charset = RequestParser.getCharsetFromHeaders(contentType); + + // if we haven't found the charset encoding on the HTTP headers, try it out on the body. + if (charset == null) { + charset = RequestParser.getCharsetFromBody(body); + } + + if (charset != null) { + try { + mBuffer.setData((headers + HEAD_SEPARATOR + body).getBytes(charset)); + } + catch (UnsupportedEncodingException e){ + Logger.error("UnsupportedEncoding: " + e.getLocalizedMessage()); + mBuffer.setData((headers + HEAD_SEPARATOR + body).getBytes()); + } + } + else { + // if we haven't found the charset encoding, just handle it on ByteBuffer() + mBuffer.setData((headers + HEAD_SEPARATOR + body).getBytes()); + } mWriter.write(mBuffer.getData()); mWriter.flush(); diff --git a/cSploit/src/org/csploit/android/plugins/mitm/Sniffer.java b/cSploit/src/org/csploit/android/plugins/mitm/Sniffer.java index 0a3ab1f76b..3599384249 100644 --- a/cSploit/src/org/csploit/android/plugins/mitm/Sniffer.java +++ b/cSploit/src/org/csploit/android/plugins/mitm/Sniffer.java @@ -22,6 +22,7 @@ import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; +import android.os.FileObserver; import android.support.v7.app.AppCompatActivity; import android.text.Html; import android.view.LayoutInflater; @@ -38,10 +39,12 @@ import android.widget.Toast; import android.widget.ToggleButton; +import org.apache.commons.compress.utils.IOUtils; import org.csploit.android.ActionActivity; import org.csploit.android.R; import org.csploit.android.core.Child; import org.csploit.android.core.ChildManager; +import org.csploit.android.core.Logger; import org.csploit.android.core.System; import org.csploit.android.gui.dialogs.ConfirmDialog; import org.csploit.android.gui.dialogs.ErrorDialog; @@ -49,7 +52,7 @@ import org.csploit.android.plugins.mitm.SpoofSession.OnSessionReadyListener; import org.csploit.android.tools.TcpDump; -import java.io.File; +import java.io.*; import java.net.InetAddress; import java.util.ArrayList; import java.util.Collections; @@ -79,6 +82,7 @@ public class Sniffer extends AppCompatActivity implements AdapterView.OnItemClic private boolean mDumpToFile = false; private String mPcapFileName = null; private Child mTcpdumpProcess = null; + private FileObserver mFileActivity = null; public class AddressStats implements Comparable{ public String mAddress = ""; @@ -334,7 +338,7 @@ public void onClick(View v){ @Override public void onConfirm(){ mDumpToFile = true; - mPcapFileName = (new File(System.getStoragePath(), "csploit-sniff-" + java.lang.System.currentTimeMillis() + ".pcap")).getAbsolutePath(); + mPcapFileName = (new File(Sniffer.this.getCacheDir(), "csploit-sniff-" + java.lang.System.currentTimeMillis() + ".pcap")).getAbsolutePath(); } @Override @@ -397,11 +401,38 @@ public boolean onOptionsItemSelected(MenuItem item){ } } + private void movePcapFileFromCacheToStorage() { + File inputFile = new File(mPcapFileName); + InputStream in = null; + OutputStream out = null; + + try { + in = new FileInputStream(inputFile); + out = new FileOutputStream(new File(System.getStoragePath(),new File(mPcapFileName).getName())); + IOUtils.copy(in, out); + } catch (IOException e) { + System.errorLogging(e); + } finally { + IOUtils.closeQuietly(in); + IOUtils.closeQuietly(out); + inputFile.delete(); + } + } + private void setStoppedState(){ if(mTcpdumpProcess != null) { mTcpdumpProcess.kill(); mTcpdumpProcess = null; } + + if(mDumpToFile) { + if (mFileActivity != null) { + mFileActivity.stopWatching(); + mFileActivity = null; + movePcapFileFromCacheToStorage(); + } + } + Sniffer.this.runOnUiThread(new Runnable() { @Override public void run() { @@ -415,6 +446,44 @@ public void run() { }); } + private void addNewTarget (final AddressStats stats){ + Sniffer.this.runOnUiThread(new Runnable() { + @Override + public void run() { + mAdapter.addStats(stats); + mAdapter.notifyDataSetChanged(); + } + }); + } + + private void updateStats (final AddressStats stats, final long len){ + Sniffer.this.runOnUiThread(new Runnable() { + @Override + public void run() { + long deltat; + stats.mBytes += len; + + deltat = (java.lang.System.currentTimeMillis() - stats.mSampledTime); + + if (deltat >= mSampleTime) { + stats.mBandwidth = (stats.mBytes - stats.mSampledBytes) / deltat; + stats.mSampledTime = java.lang.System.currentTimeMillis(); + stats.mSampledBytes = stats.mBytes; + } + mAdapter.notifyDataSetChanged(); + } + }); + } + + private void showMessage (final String text){ + Sniffer.this.runOnUiThread(new Runnable() { + @Override + public void run() { + Toast.makeText(Sniffer.this, text, Toast.LENGTH_LONG).show(); + } + }); + } + private void setSpoofErrorState(final String error){ Sniffer.this.runOnUiThread(new Runnable(){ @Override @@ -425,10 +494,59 @@ public void run(){ }); } + /** + * Monitor a pcap file for changes, in order to let the user know that the capture is running. + */ + private void startMonitoringPcapFile(){ + final String str_address = (System.getCurrentTarget().getType() == Target.Type.NETWORK) ? System.getCurrentTarget().getDisplayAddress().split("/")[0] : System.getCurrentTarget().getDisplayAddress(); + + final File pcapfile = new File(mPcapFileName); + try{ + pcapfile.createNewFile(); + }catch(IOException io) + { + Toast.makeText(this, "File not created: " + io.getLocalizedMessage(), Toast.LENGTH_LONG).show(); + return; + } + + mFileActivity = new FileObserver(mPcapFileName) { + @Override + public void onEvent(int event, String s) { + switch (event){ + case FileObserver.CLOSE_WRITE: + showMessage(getString(R.string.saved) + ":\n" + mPcapFileName); + break; + case FileObserver.MODIFY: + + AddressStats stats = mAdapter.getStats(str_address); + updateStats(stats, pcapfile.length()); + break; + case FileObserver.OPEN: + showMessage(getString(R.string.dumping_traffic_to) + mPcapFileName); + break; + default: + break; + } + } + }; + final AddressStats stats = new AddressStats(str_address); + stats.mBytes = 0; + stats.mSampledTime = java.lang.System.currentTimeMillis(); + addNewTarget(stats); + // android docs: The monitored file or directory must exist at this time,or else no events will be reported + mFileActivity.startWatching(); + } + private void setStartedState(){ + if (mRunning) + setStoppedState(); - if(mDumpToFile) - Toast.makeText(Sniffer.this, getString(R.string.dumping_traffic_to) + mPcapFileName, Toast.LENGTH_SHORT).show(); + if(mDumpToFile) { + mSampleTime = 100; + startMonitoringPcapFile(); + } + else + mSampleTime = 1000; try { mSpoofSession.start(new OnSessionReadyListener(){ @@ -453,7 +571,6 @@ public void onSessionReady(){ @Override public void onPacket(InetAddress src, InetAddress dst, int len) { long now = java.lang.System.currentTimeMillis(); - long deltat; AddressStats stats = null; String stringAddress = null; @@ -472,25 +589,11 @@ public void onPacket(InetAddress src, InetAddress dst, int len) { stats.mBytes = len; stats.mSampledTime = now; } else { - stats.mBytes += len; - - deltat = (now - stats.mSampledTime); - - if (deltat >= mSampleTime) { - stats.mBandwidth = (stats.mBytes - stats.mSampledBytes) / deltat; - stats.mSampledTime = java.lang.System.currentTimeMillis(); - stats.mSampledBytes = stats.mBytes; - } + updateStats(stats, len); } final AddressStats fstats = stats; - Sniffer.this.runOnUiThread(new Runnable() { - @Override - public void run() { - mAdapter.addStats(fstats); - mAdapter.notifyDataSetChanged(); - } - }); + addNewTarget(fstats); } }); } catch( ChildManager.ChildNotStartedException e ) { diff --git a/cSploit/src/org/csploit/android/services/receivers/MsfRpcdServiceReceiver.java b/cSploit/src/org/csploit/android/services/receivers/MsfRpcdServiceReceiver.java index d832e90f62..63dacf81ac 100644 --- a/cSploit/src/org/csploit/android/services/receivers/MsfRpcdServiceReceiver.java +++ b/cSploit/src/org/csploit/android/services/receivers/MsfRpcdServiceReceiver.java @@ -2,6 +2,7 @@ import android.app.Activity; import android.app.NotificationManager; +import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -68,7 +69,7 @@ private void showToastForStatus(Context context, MsfRpcdService.Status status) { } private void updateNotificationForStatus(Context context, MsfRpcdService.Status status) { - NotificationCompat.Builder mBuilder = + NotificationCompat.Builder builder = new NotificationCompat.Builder(context) .setSmallIcon(R.drawable.exploit_msf) .setContentTitle(context.getString(R.string.msf_status)) @@ -76,8 +77,13 @@ private void updateNotificationForStatus(Context context, MsfRpcdService.Status .setContentText(context.getString(status.getText())) .setColor(ContextCompat.getColor(context, status.getColor())); + PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, + new Intent(), PendingIntent.FLAG_UPDATE_CURRENT); + + builder.setContentIntent(pendingIntent); + NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); - mNotificationManager.notify(MSF_NOTIFICATION, mBuilder.build()); + mNotificationManager.notify(MSF_NOTIFICATION, builder.build()); } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 714c31b24f..4b8a3c2dae 100755 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu Sep 24 21:38:44 PDT 2015 +#Thu Nov 19 16:09:54 PST 2015 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.7-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.9-all.zip