/** * @author Abeer Alhuzali * * This class reads/extracts information from a Z3 model * * e.g of a Z3 model: * SAT (or UNSAT or UNKNOWN) * var : value * var2 : value2 * * e.g: * * v-ok ************************ >> SAT ------------------------ x : string -> "af" ************************ &0.0188589096069& * For more information, please read "NAVEX: Precise and Scalable Exploit Generation for Dynamic Web Applications" * */ package navex.solver; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.net.URLEncoder; import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map.Entry; import java.util.stream.Collectors; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.utils.URIBuilder; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import edu.uci.ics.crawler4j.fetcher.PageFetcher; import edu.uci.ics.crawler4j.util.*; public class SolverModel { private static final Logger logger = LoggerFactory.getLogger(SolverModel.class); public enum solTypes{ SAT, UNSAT, UNKNOWN; } String url; public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } String solution; public String getSolution() { return solution; } public void setSolution(String solution) { this.solution = solution; } HashMap <String , String> varValue; private HashMap<String, String> traceVarValue; private List<NameValuePair> nvps; public void setNvps(List<NameValuePair> nvps2) { this.nvps = nvps2; } public List<NameValuePair> getNvps() { return nvps; } public HashMap<String, String> getTraceVarValue() { return traceVarValue; } public HashMap<String, String> getVarValue() { return varValue; } public void setVarValue(HashMap<String, String> varValue) { this.varValue = varValue; } public void addVarValue(String var, String value) { if (varValue == null) varValue = new HashMap <String , String>(); this.varValue.put(var, value) ; } public SolverModel() { this.solution = null; this.varValue = new HashMap <String , String>(); this.traceVarValue = new HashMap <String , String>(); this.nvps= new ArrayList <NameValuePair>(); this.getMap = new HashMap<String, String> (); this.url = null; } public List <NameValuePair> main(String[] args, PageFetcher pageFetcher) throws ClientProtocolException, IOException, URISyntaxException{ String file = args[0]; String method = args[1]; String action = args[2]; String modelType = args[3]; //either trace or form or static List <NameValuePair> ret = null; System.out.println("The model for the file "+file); this.processSolverModel(file); if (modelType.equals("trace") || modelType.equals("static") ) traceModelPreprocessing(); ret= this.genHttpRequestFromModel(method, action, modelType, pageFetcher); return ret; } @Override public String toString() { return "SolverModel [solution=" + solution + ", varValue=" + varValue + "]"; } public void processSolverModel(String file){ logger.debug("Reading the file :"+ file); try { FileReader fr = new FileReader(file); BufferedReader bis = new BufferedReader(fr); String line = null;//bis.readLine(); while((line=bis.readLine()) != null) { System.out.println("line is :"+line); line= line.trim(); if (line.startsWith(">> ")){ if (line.equals(">> SAT") || line.trim().equals(">> UNKNOWN") || line.trim().equals(">> UNSAT") ) { this.setSolution(line.split(">>")[1].trim()); System.out.println("the model Solution is "+this.getSolution()); } } if (this.getSolution() != null && this.getSolution().equals("SAT")){ String[] tuples = line.split(" : "); if (tuples.length > 1) { if (tuples[0].startsWith("p1b")) continue; String value = tuples[1].split("->")[1].trim(); if (value.trim().startsWith("\"") && value.trim().endsWith("\"")) { value= value.substring(1,value.length()-1 ); } this.addVarValue(tuples[0].trim(), value); System.out.println("the model var-value pair is <"+tuples[0].trim()+","+ value+">"); } } } try{ fr.close(); bis.close(); } catch(Exception e) { logger.debug( " Exception while closing teh file " + file); } } catch (IOException e1) { e1.printStackTrace(); } System.out.println("the model solution is ::::"+this.getSolution()); } public void traceModelPreprocessing(){ for (Entry<String, String> map : this.getVarValue().entrySet()){ if (map.getKey().startsWith("$_GET") || map.getKey().startsWith("$_POST") || map.getKey().startsWith("$_SESSION") || map.getKey().startsWith("$_REQUEST") || map.getKey().startsWith("$HTTP_GET") || map.getKey().startsWith("$HTTP_POST")) { this.addTraceVarValue(map.getKey(), map.getValue()); } } } public void addTraceVarValue(String key, String value) { if (traceVarValue == null) traceVarValue = new HashMap <String , String>(); this.traceVarValue.put(key, value) ; } public List <NameValuePair> genHttpRequestFromModel(String method, String action, String modelType, PageFetcher pageFetcher) throws ClientProtocolException, IOException, URISyntaxException{ if (this.getSolution() == null){ System.out.println("The model does not have a solution"); return null; } if (!this.getSolution().equals("SAT")) { System.out.println("The model is not SAT"); return null; } if (this.getVarValue().isEmpty() ){ System.out.println("The model is Empty !!!!"); return null; } if (method.equalsIgnoreCase("post")){ System.out.println("preparing for a post request to "+action); return postHttpRequest(action, modelType, pageFetcher); } else if (method.equalsIgnoreCase("get")){ System.out.println("preparing for a get request to "+action); return getHttpRequest(action, modelType, pageFetcher); } else if (method.equalsIgnoreCase("request")){ //requestHttpRequest(action); } else if (modelType == "static" && method == ""){ List <NameValuePair> nvps = new ArrayList <NameValuePair>(); HashMap<String, String> getMap = new HashMap<String, String>(); for (Entry<String, String> map : this.getTraceVarValue().entrySet()){ if (map.getKey().contains("$_GET")){ String key= map.getKey().replace("$_GET_", "").replace("]", ""); getMap.put(key,map.getValue()); } else if (map.getKey().contains("$_POST")){ String key= map.getKey().replace("$_POST_", "").replace("]", ""); //postMap.put(key,map.getValue()); nvps.add(new BasicNameValuePair(key, map.getValue())); } else if (map.getKey().contains("$HTTP_GET_VARS")){ String key= map.getKey().replace("$HTTP_GET_VARS_", "").replace("]", ""); getMap.put(key,map.getValue()); } else if (map.getKey().contains("$HTTP_POST_VARS")){ String key= map.getKey().replace("$HTTP_POST_VARS_", "").replace("]", ""); nvps.add(new BasicNameValuePair(key, map.getValue())); } } this.setNvps(nvps); String newUrl = staticGetMap(action, getMap); this.setGetMap(getMap); this.setUrl(newUrl); return nvps; } return null; } HashMap<String, String> getMap; public HashMap<String, String> getGetMap() { return getMap; } private void setGetMap(HashMap<String, String> getMap) { this.getMap = getMap; } private String staticGetMap(String action , HashMap<String, String> getMap) { //Augment the action with the get params that we got for the trace String actionAug = ""; for (Entry<String, String> map : getMap.entrySet()){ try { actionAug+=map.getKey()+"="+URLEncoder.encode(map.getValue(), "UTF-8")+"&"; } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } if(actionAug.lastIndexOf("&") != -1) {actionAug= actionAug.substring(0,actionAug.lastIndexOf("&") ); action = action.concat("?").concat(actionAug); } return action; } private void requestHttpRequest(String action) { // TODO Auto-generated method stub } private List <NameValuePair> getHttpRequest(String action, String modelType, PageFetcher pageFetcher) throws ClientProtocolException, IOException, URISyntaxException { List <NameValuePair> nvps = new ArrayList <NameValuePair>(); HashMap<String, String> getMap = new HashMap<String, String>(); String data=""; String responseBody =""; URIBuilder u = new URIBuilder(); u.setScheme("http"); action= action.replace("http://", ""); u.setHost(action); if(modelType.equals("form")){ for (Entry<String, String> map : this.getVarValue().entrySet()){ u.setParameter(map.getKey(), map.getValue()); } } else { for (Entry<String, String> map : this.getTraceVarValue().entrySet()){ if (map.getKey().contains("$_GET")){ String key= map.getKey().replace("$_GET[", "").replace("]", ""); getMap.put(key,map.getValue()); } } String actionAug = ""; for (Entry<String, String> map : getMap.entrySet()){ u.setParameter(map.getKey(), map.getValue()); } } URI uri = u.build(); try{ logger.debug("The uri is : "+uri.toString()); //if (uri.startsWith(" http://http//")) //httpGet. HttpGet httpGet = new HttpGet(uri); logger.debug("The uri scheme is : "+uri.getScheme()); logger.debug("The get request is : "+httpGet.getURI()); CloseableHttpResponse response2 = pageFetcher.httpClient.execute(httpGet, pageFetcher.getConfig().getHttpClientContext()); try { logger.debug("Status Code : "+response2.getStatusLine()); HttpEntity entity2 = response2.getEntity(); // do something useful with the response body // and ensure it is fully consumed responseBody = EntityUtils.toString(entity2); EntityUtils.consume(entity2); } finally { response2.close(); } } finally { // httpclient.close(); } return null; } private List<NameValuePair> postHttpRequest(String action, String modelType, PageFetcher pageFetcher) throws ClientProtocolException, IOException { List <NameValuePair> nvps = new ArrayList <NameValuePair>(); HashMap<String, String> postMap = new HashMap<String, String>(); HashMap<String, String> getMap = new HashMap<String, String>(); String responseBody=""; if(modelType.equals("form")) for (Entry<String, String> map : this.getVarValue().entrySet()){ nvps.add(new BasicNameValuePair(map.getKey(), map.getValue())); } else { for (Entry<String, String> map : this.getTraceVarValue().entrySet()){ if (map.getKey().contains("$_GET")){ String key= map.getKey().replace("$_GET[", "").replace("]", ""); getMap.put(key,map.getValue()); } else if (map.getKey().contains("$_POST")){ String key= map.getKey().replace("$_POST[", "").replace("]", ""); postMap.put(key,map.getValue()); } } for (Entry<String, String> map : postMap.entrySet()){ nvps.add(new BasicNameValuePair(map.getKey(), map.getValue())); } //Augment the action with the get params we got for the trace String actionAug = ""; for (Entry<String, String> map : getMap.entrySet()){ actionAug+=map.getKey()+"="+URLEncoder.encode(map.getValue(), "UTF-8")+"&"; } if (actionAug.lastIndexOf("&") != -1) actionAug= actionAug.substring(0,actionAug.lastIndexOf("&") ); if (action.contains("?")) action = action.concat("&").concat(actionAug); else action = action.concat("?").concat(actionAug); } try{ HttpPost httpPost = new HttpPost(action); httpPost.setEntity(new UrlEncodedFormEntity(nvps)); logger.debug("The request is : "+httpPost.toString()); CloseableHttpResponse response2 = pageFetcher.httpClient.execute(httpPost, pageFetcher.getConfig().getHttpClientContext()); try { logger.debug("Status Code : "+response2.getStatusLine()); HttpEntity entity2 = response2.getEntity(); // do something useful with the response body // and ensure it is fully consumed responseBody = EntityUtils.toString(entity2); EntityUtils.consume(entity2); } finally { response2.close(); } } finally { //httpclient.close(); } return nvps; } }