package asppack2; //for the database connection in test only import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.net.CookieHandler; import java.net.CookieManager; import java.net.CookiePolicy; import java.net.HttpCookie; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.net.URLEncoder; import java.util.Iterator; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.security.*; import java.security.cert.CertificateException; import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateNotYetValidException; import java.security.cert.X509Certificate; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; /* * Gets the cookie_string from an Asp.Net session * * For use when content-lengths are known or can be deciphered. * Can also be used to get the viewstate, html, and event validation code. * Contains a base 64 decoder for decoding viewstates into useable information. (custom decoder removes all unknown characters) * * By: Andrew S. Evans * */ public class asp_grab { private String host; private String authority; private String cookies; private CookieManager mgr; private String[] headers; private String[] values; private String method; private String the_url; private String html; private String url_params; private static int[] toInt = new int[128]; private final static char[] ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" .toCharArray(); public asp_grab() { // TODO empty costructor } public asp_grab(String[] inheaders, String[] invalues, String inurl) { // TODO actual constructor // initialize base 64 string // applied to overall values (adding i) to get appropriate Character for (int i = 0; i < ALPHABET.length; i++) { toInt[ALPHABET[i]] = i; } // the cookie manager // a precaution, works with HttpURLConnection to get any cookies mgr = new CookieManager(); mgr.setCookiePolicy(CookiePolicy.ACCEPT_ALL); CookieHandler.setDefault(mgr); values = invalues; headers = inheaders; method = "GET"; the_url = inurl; url_params = null; host = null; authority = null; } public asp_grab(String[] inheaders, String[] invalues, String inmethod, String inurl) { // TODO actual constructor // initialize base 64 int string // applied to overall values (adding i) to get appropriate Character for (int i = 0; i < ALPHABET.length; i++) { toInt[ALPHABET[i]] = i; } // the cookie manager // a precaution, works with HttpURLConnection to get any cookies mgr = new CookieManager(); mgr.setCookiePolicy(CookiePolicy.ACCEPT_ALL); CookieHandler.setDefault(mgr); values = invalues; headers = inheaders; method = inmethod; the_url = inurl; url_params = null; host = null; authority = null; } public asp_grab(String[] inheaders, String[] invalues, String inmethod, String inurl, String inurl_params) { // TODO actual constructor // initialize base 64 int string // applied to overall values (adding i) to get appropriate Character for (int i = 0; i < ALPHABET.length; i++) { toInt[ALPHABET[i]] = i; } // the cookie manager // a precaution, works with HttpURLConnection to get any cookies mgr = new CookieManager(); mgr.setCookiePolicy(CookiePolicy.ACCEPT_ALL); CookieHandler.setDefault(mgr); // initialize other values values = invalues; headers = inheaders; method = inmethod; the_url = inurl; url_params = inurl_params; host = null; authority = null; } public void reset_cookies() { new_cookies(); } public void set_cookies(String incookies) { cookies = incookies; } public String cookiegrab() { return cookies; } private void new_cookies() { // the cookie manager // a precaution, works with HttpURLConnection to get any cookies mgr.getCookieStore().removeAll(); mgr = new CookieManager(); mgr.setCookiePolicy(CookiePolicy.ACCEPT_ALL); CookieHandler.setDefault(mgr); } public void set_url_params(String inurl_params) { // TODO sets the url_params url_params = inurl_params; } public String get_secured() { // TOD Get a Self written secured page return get_manager(); } public void set_host(String inhost) { host = inhost; } public void set_authority(String inauthority) { authority = inauthority; } public String get_authority() { return authority; } public String get_host() { return host; } public String get_cookies() { // TODO Method to call to get the page and cookies when a certificate is // self-signed by the site return getAspsessions(); } public void set_html(String inhtml) { // TODO set the html html = inhtml; } public void set_url(String inurl) { // TODO set the url the_url = inurl; } public void set_method(String inmethod) { // TODO set the method type method = inmethod; } public void set_header_names(String[] innames) { // TODO add new header names array headers = innames; } public void set_values(String[] invalues) { // TODO add new header values array values = invalues; } public String get_redirect_path() { // TODO return a redirect return get_redirects(); } public String get_url_params() { // TODO return url params return url_params; } public String get_html() { // TODO return the html content return html; } public String get_server_faces() { // TODO return a javax server faces viewstate if (html == null) return null; else return get_state(html, "(?<=id=\"javax.faces.ViewState\" value=\").*?\\/>"); } public void encode_url_params(String[] innames, String[] invals) { // TODO encode the url parameters int length = innames.length; url_params = ""; for (int i = 0; i < length; i++) { try { if (i == 0) url_params = URLEncoder.encode(innames[i], "UTF-8") + "=" + URLEncoder.encode(invals[i], "UTF-8"); else url_params += "&" + URLEncoder.encode(innames[i], "UTF-8") + "=" + URLEncoder.encode(invals[i], "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } } public int get_param_size() { return url_params.length(); } public String get_server_faces_decoded() { String ret_string = null; if (html == null) { return null; } else { try { ret_string = new String(decode(get_state(html, "(?<=id=\"javax.faces.ViewState\" value=\").*?\\/>")), "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } return ret_string; } public String get_decoded_viewstate() { String ret_string = null; if (html == null) { return null; } try { ret_string = new String(decode(get_state(html, "(?<=id=\"__VIEWSTATE\" value=\").*?\\/>")), "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return ret_string; } public String get_previous_page() { if (html == null) { return null; } return get_state(html, "(?<=id=\"__PREVIOUSPAGE\" value=\").*?\\/>"); } public String get_viewstate() { // TODO return the viewstate if (html == null) { return null; } return get_state(html, "(?<=id=\"__VIEWSTATE\" value=\").*?\\/>"); } public String get_event_validation() { // TODO return the event validation if (html == null) { return null; } return get_state(html, "(?<=id=\"__EVENTVALIDATION\" value=\").*?\\/>"); } private String get_redirects() { // TODO Auto-generated method stub String redirect_path = null; if (html == null) { return null; } else { redirect_path = match_one_regex(html, "(?<=href=\").*?(?=\")"); } return redirect_path; } private static byte[] decode(String s) { // TODO decode Base 64 into a byte array // find the ending positions number of characters int delta = s.endsWith("==") ? 2 : s.endsWith("=") ? 1 : 0; // set up the byte array which is going to be 75% of base 64 - the // difference byte[] buffer = new byte[s.length() * 3 / 4 - delta]; // offset to replace the char with a byte int mask = 0xFF; // run down list of bytes and perform the transformation // letters are represented by two bytes corresponding to ascii but one // is generated per loop int index = 0; for (int i = 0; i < s.length(); i += 4) { // get the first two ints int c0 = toInt[s.charAt(i)]; int c1 = toInt[s.charAt(i + 1)]; // place the proper byte in the array with shifting first and second // bits buffer[index++] = (byte) (((c0 << 2) | (c1 >> 4)) & mask); // if the buffer is full return it if (index >= buffer.length) { return buffer; } // get the next character int c2 = toInt[s.charAt(i + 2)]; // repeat the mask operations bit shift second <-- 4 OR 3rd shift // -->2 AND mask buffer[index++] = (byte) (((c1 << 4) | (c2 >> 2)) & mask); if (index >= buffer.length) { return buffer; } // perform the same with a 3rd char to create 4th bit int c3 = toInt[s.charAt(i + 3)]; buffer[index++] = (byte) (((c2 << 6) | c3) & mask); } // return if reach here return buffer; } private String match_one_regex(String inhtml, String inpattern) { // TODO match a regex pattern Pattern p = Pattern.compile(inpattern, Pattern.MULTILINE); Matcher m = p.matcher(inhtml); String result = null; while (m.find()) { result = m.group().trim(); } return result; } private String get_state(String inhtml, String regex) { // TODO encapsulate the get state for security, returns the state // trimming whitespaces String state; // extracts the view state or event validation code state = match_one_regex(inhtml, regex); state = state.replace("\"", "").replace("/>", "").trim(); return state; } public String get_SSL() { return get_ssl_page(); } private String get_ssl_page() { // TODO manually get SSL pages, Preferred method over Trust Manager // for use when the certificate is signed by a trusted authority // uses a basic HttpsUrlConnection try { // url URL url = new URL(the_url); // connection HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); // set the ssl provider to be sun Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider()); // set the request headers for (int i = 0; i < values.length; i++) { if (values[i] != null) conn.setRequestProperty(headers[i], values[i]); } // set up browser conn.setInstanceFollowRedirects(false); conn.setUseCaches(false); // set the method type if (method != null) { conn.setRequestMethod(method); if (method.compareTo("POST") == 0) { conn.setDoOutput(true); conn.setDoInput(true); conn.setInstanceFollowRedirects(false); if (url_params != null) { DataOutputStream wr = new DataOutputStream( conn.getOutputStream()); wr.writeBytes(url_params); wr.flush(); wr.close(); } } } BufferedReader br = new BufferedReader(new InputStreamReader( conn.getInputStream())); String line = ""; html = ""; while ((line = br.readLine()) != null) { html = html + line + "\n"; } br.close(); conn.getContent(); cookies = format_cookies(mgr.getCookieStore().getCookies()); conn.disconnect(); } catch (IOException e) { e.printStackTrace(); } return html; } /** * Gets a page using custom verification for self-signed certificates. Use * Sparingly and wisely. Be Careful. This is a disclaimer. * * @return */ @SuppressWarnings("restriction") private String get_manager() { // TODO Use a Trust Manager that accepts only a Certain Host Provider // for Self-signed certificates // All certificates must match the signing authority and host. There is // no leeway here! // Worst case scenarios should use this generic method. Otherwise try // adding the cert to a trust store try { // create the socket factory Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider()); /* * This pretty much overrides the trust manager and allows for the * use of personal verification This code verifies the host, * authority, and certificates manually and with the aid of a * decryption tool. If the site is not trustworthy, do not use this * method. */ // creates an all-trusting trustmanager which allows for // self-verification TrustManager[] tm = new TrustManager[] { new X509TrustManager() { public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return null; } } }; // creates the SSL context for use in setting up the SSL handler final SSLContext ssl_context_handler = SSLContext .getInstance("SSL"); // initializes ssl_context_handler .init(null, tm, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(ssl_context_handler .getSocketFactory()); // sets the SSL Socket factory HttpsURLConnection.setDefaultSSLSocketFactory(ssl_context_handler .getSocketFactory()); // url URL url = new URL(the_url); // connection HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); // set up browser conn.setInstanceFollowRedirects(false); conn.setUseCaches(false); for (int i = 0; i < values.length; i++) { if (values[i] != null) conn.setRequestProperty(headers[i], values[i]); } // set the method type if (method != null) { conn.setRequestMethod(method); // if the method is a POST, set the appropriate headers and // write out the POST parameters to the // output stream if (method.compareTo("POST") == 0) { conn.setDoOutput(true); conn.setDoInput(true); conn.setInstanceFollowRedirects(false); if (url_params != null) { // the output stream, nothing is coming in yet DataOutputStream wr = new DataOutputStream( conn.getOutputStream()); wr.writeBytes(url_params); wr.flush(); wr.close(); } } } // create the input buffer which opens the connection for reading BufferedReader br = new BufferedReader(new InputStreamReader( conn.getInputStream())); /* * This is where the socket is vulnerable and bits should not be * accepted for a MIME attack;etc. Verification can occur here sinc * the certificate is obtained here. Do not proceed without a valid * certificate from a trusted authority. * * For non-Pentaho programs, it may be ok to place this code in a * separate method although thatwould require passing the connection * information between class methods in a public class. */ // get the certificates java.security.cert.Certificate[] certs = conn .getServerCertificates(); // personal verification for the certificate to handle self signed // X509 certificates // a host name must be provided // a certificate signer name must be provided // to be secure, these must be found elsewhere (to download the // certificate go to the web page in a browser and click the lock // icon or etc.) // This avoids a keystore and the slower SSL client under Pentaho // loop through the certificates verifying that each is valid and // contains a trusted host and authority // provided by the user who should ensure that they are trustworthy for (java.security.cert.Certificate cert : certs) { // handle verification for X509 if (cert.getType().compareTo("X.509") == 0 | cert.getType().compareTo("X509") == 0) { // certify from preset authorities after getting X509 typed // cert X509Certificate c = (X509Certificate) cert; // get the peer name // requires the existence of an OU String CN = conn.getPeerPrincipal().getName(); int a, b = 0; a = CN.indexOf("CN="); b = CN.indexOf(",", a); if (b > a & a != -1) { CN = CN.substring((a + 3), b); } // get the authority // requires the existence of an OU String Issuer = c.getIssuerDN().getName(); a = 0; b = 0; a = Issuer.indexOf("CN="); b = Issuer.indexOf(",", a); if (b > a & a != -1) { Issuer = Issuer.substring((a + 3), b); } // get the IssuerX500 Principal which should match the other // principal // requires the existence of an OU String IssuerX500 = c.getIssuerX500Principal().getName(); a = 0; b = 0; a = IssuerX500.indexOf("CN="); b = IssuerX500.indexOf(",", a); if (b > a & a != -1) { IssuerX500 = IssuerX500.substring((a + 3), b); } // verify that the issuer, issuer principal, and peer // principal are valid // this can prevent MIME attacks for the most part but BE // CAREFUL try { if (CN.compareTo(host) == 0 & (Issuer.compareTo(authority) == 0 & IssuerX500 .compareTo(authority) == 0)) { // if valid verify the certificate try { c.checkValidity(); } catch (CertificateExpiredException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (CertificateNotYetValidException e) { // TODO Auto-generated catch block e.printStackTrace(); } } else { // if the authority or host names do not match then // the Invalid Exception is thrown throw new Invalid509Exception(); } } catch (Invalid509Exception e) { e.printStackTrace(); System.exit(-1); } } else { // perform typical certificate verification // this is a back up used to catch misuse of the method // If this works, please try using the getSSL() method which // uses less code try { cert.verify(cert.getPublicKey()); } catch (InvalidKeyException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (CertificateException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchProviderException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SignatureException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /* * Continue reading if the socket connection is secure */ String line = ""; html = ""; while ((line = br.readLine()) != null) { html = html + line + "\n"; } conn.getContent(); cookies = format_cookies(mgr.getCookieStore().getCookies()); } catch (MalformedURLException e) { e.printStackTrace(); } catch (SSLPeerUnverifiedException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (KeyManagementException e) { // TODO Auto-generated catch block e.printStackTrace(); } return cookies; } private String getAspsessions() { // TODO return the cookie string // try and catch block to get the pages try { /* get the starting page and its view state using a GET command */ // this can be re-used since base 64 decoding is used by ASP .Net // set up the initial GET URL url = new URL(the_url); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(10000); // set up browser conn.setInstanceFollowRedirects(false); conn.setUseCaches(false); for (int i = 0; i < values.length; i++) { if (values[i] != null) conn.setRequestProperty(headers[i], values[i]); } // set the method type if (method != null) { conn.setRequestMethod(method); if (method.compareTo("POST") == 0) { conn.setDoOutput(true); conn.setDoInput(true); conn.setInstanceFollowRedirects(false); } } if (url_params != null) { DataOutputStream wr = new DataOutputStream( conn.getOutputStream()); wr.writeBytes(url_params); wr.flush(); wr.close(); } BufferedReader br = new BufferedReader(new InputStreamReader( conn.getInputStream())); String line = ""; html = ""; int i = 0; while ((i = br.read()) != -1) { html += (char) i; } conn.getContent(); } catch (MalformedURLException e) {// TODO failed to form url e.printStackTrace(); } catch (IOException e) { // TODO failed to read site e.printStackTrace(); } // return the cookie string return format_cookies(mgr.getCookieStore().getCookies()); } private String format_cookies(List<HttpCookie> incookies) { String cookie_string = null; HttpCookie c = null; Iterator<HttpCookie> it = incookies.iterator(); while (it.hasNext()) { c = it.next(); try { // add the cookie to the list in the appropriate UTF-8 encoded // format // separated by a semi-colon if (cookie_string == null) { cookie_string = URLEncoder.encode(c.getName(), "UTF-8"); } else { cookie_string += URLEncoder.encode(c.getName(), "UTF-8"); } cookie_string += "=" + URLEncoder.encode(c.getValue(), "UTF-8") + URLEncoder.encode(";", "UTF-8") + ";"; } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } return cookie_string; } public String url_encode(String inurl, String inparameter) { String url = inurl; try { if (url == null) { url = URLEncoder.encode(inparameter, "UTF-8"); } else { url += URLEncoder.encode(inparameter, "UTF-8"); ; } } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return url; } public String get_user_agent() { // TODO returns a random user agent string int random = (int) Math.floor(Math.random() * 10); // a string of user agents String[] agent = new String[10]; agent[0] = "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:22.0) Gecko/20100101 Firefox/22.0"; agent[5] = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; chromeframe/28.0.1500.71)"; agent[6] = "Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3"; agent[1] = "Opera/9.80 (Windows NT 6.0) Presto/2.12.388 Version/12.14"; agent[3] = "Mozilla/5.0 (X11; Linux x86_64; rv:10.0.11) Gecko/20100101 conkeror/1.0pre (Debian-1.0~~pre+git120527-1)"; agent[7] = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/5.0; TheWorld)"; agent[2] = "Enigma Browser"; agent[4] = "Mozilla/5.0 (X11; U; Linux; de-DE) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.8.0"; agent[8] = "Mozilla/5.0 (compatible; MSIE 9.0; AOL 9.7; AOLBuild 4343.19; Windows NT 6.1; WOW64; Trident/5.0; FunWebProducts)"; agent[9] = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1pre) Gecko/20090629 Vonkeror/1.0"; return agent[random]; } /** * @param args */ public static void main(String[] args) { // TODO For Testing } }