/// <summary> /// Adds the request to the proxy data store /// </summary> protected void AddRequestToDataStore() { TVRequestInfo currDataStoreRequestInfo = new TVRequestInfo(); currDataStoreRequestInfo.RequestLine = _requestInfo.RequestLine; currDataStoreRequestInfo.Description = _requestDescription; currDataStoreRequestInfo.RequestTime = _currentRequestTime; currDataStoreRequestInfo.ThreadId = Utils.GetCurrentWin32ThreadId().ToString(); currDataStoreRequestInfo.IsHttps = _requestInfo.IsSecure; currDataStoreRequestInfo.Host = _requestInfo.Host; int reqId = TrafficDataStore.AddRequestInfo(currDataStoreRequestInfo); if (reqId != -1) { _currentRequestResponseBytes = new RequestResponseBytes(); _currentRequestResponseBytes.AddToRequest(_requestInfo.ToArray(false)); //saving the request in a direct to site format, since it will come //in proxy format GET http://site.com/ rather than GET /, //if we need a server to connect to the target the client will handle that TrafficDataStore.SaveRequest(reqId, _currentRequestResponseBytes); _currDataStoreRequestInfo = TrafficDataStore.GetRequestInfo(reqId); } }
/// <summary> /// Triggered before the response is sent back to the client /// </summary> /// <param name="responseInfo"></param> /// <returns></returns> protected override HttpResponseInfo OnBeforeResponseToClient(HttpResponseInfo responseInfo) { if (_responseReplacements != null && _responseReplacements.Count > 0) { string response = responseInfo.ToString(); bool wasReplaced = false; foreach (string key in _responseReplacements.Keys) { if (Utils.IsMatch(response, key)) { response = Utils.ReplaceGroups(response, key, _responseReplacements[key]); HttpServerConsole.Instance.WriteLine(LogMessageType.Information, "Response replacement applied for pattern: '{0}'", key); wasReplaced = true; } } if (wasReplaced) { //remove chunked encoding response = Regex.Replace(response, "Transfer-Encoding:\\s?chunked\\r\\n", "", RegexOptions.IgnoreCase); responseInfo = new HttpResponseInfo(response); } } if (!_isNonEssential) { //update tracked paterns from the response PatternTracker.Instance.UpdatePatternValues(responseInfo); } if (CurrDataStoreRequestInfo != null) { //trap the response (this will only occur if the trap is enabled) if (HttpTrap.Instance.TrapResponses) { TrafficDataStore.SaveResponse(CurrDataStoreRequestInfo.Id, responseInfo.ToArray()); if (HttpTrap.Instance.TrapResponse(CurrDataStoreRequestInfo, responseInfo)) { responseInfo = new HttpResponseInfo(TrafficDataStore.LoadResponseData(CurrDataStoreRequestInfo.Id)); if (responseInfo.ResponseBody != null && responseInfo.ResponseBody.IsChunked == false) { responseInfo.Headers["Content-Length"] = responseInfo.ResponseBody.Length.ToString(); } } } if (_trackRequestContext) { //replace the request with its request id //store information about where the request was found in previous traffic responses stored in the //current traffic file TrackRequestContext(_requestInfo); } } return(responseInfo); }
protected override HttpRequestInfo OnBeforeRequestToSite(HttpRequestInfo requestInfo) { requestInfo = base.OnBeforeRequestToSite(requestInfo); if (!_isNonEssential) { bool mutated; requestInfo = _parentProxy.HandleRequest(requestInfo, out mutated); if (mutated) { CurrDataStoreRequestInfo.Description = "Custom Test"; } TrafficDataStore.SaveRequest(CurrDataStoreRequestInfo.Id, requestInfo.ToArray(false)); TrafficDataStore.UpdateRequestInfo(CurrDataStoreRequestInfo); } return(requestInfo); }
protected override HttpResponseInfo OnBeforeResponseToClient(HttpResponseInfo responseInfo) { responseInfo = base.OnBeforeResponseToClient(responseInfo); if (!_isNonEssential) { //validate if the test was successful if (_parentProxy.ValidateResponse(responseInfo)) { //the test was found CurrDataStoreRequestInfo.Description = "Vulnerable Response"; TrafficDataStore.UpdateRequestInfo(CurrDataStoreRequestInfo); } } return(responseInfo); }
/// <summary> /// Writes a CRWAE message to the client when response is not available from server /// </summary> /// <param name="statusCode">HTTP status code for the response</param> /// <param name="reason">Brief explanation of error</param> /// <param name="serviceCode">ID of the CRAWE message</param> /// <param name="args">Message args</param> protected virtual void ReturnHttpErrorResponse(HttpStatusCode statusCode, string reason, ServiceCode serviceCode, params object [] args) { byte[] messageBytes = HttpErrorResponse.GenerateHttpErrorResponse(statusCode, reason, serviceCode, args); if (!TryWriteToStream(messageBytes)) { return; } //add the response if we are adding requests to the data source if (_currDataStoreRequestInfo != null) { _currDataStoreRequestInfo.ResponseStatus = statusCode.ToString(); _currDataStoreRequestInfo.ResponseTime = DateTime.Now; TrafficDataStore.SaveResponse(_currDataStoreRequestInfo.Id, messageBytes); _currDataStoreRequestInfo = null; } ClientStreamWrapper.Close(); }
/// <summary> /// Writes a response to the client stream /// </summary> /// <param name="responseInfo"></param> protected virtual void ReturnResponse(HttpResponseInfo responseInfo) { HttpServerConsole.Instance.WriteLine(LogMessageType.Information, "Sending response: {0} for request: {1}", responseInfo.StatusLine, _requestInfo.RequestLine); if (_currDataStoreRequestInfo != null) { _currDataStoreRequestInfo.ResponseStatus = responseInfo.Status.ToString(); _currDataStoreRequestInfo.ResponseTime = DateTime.Now; } //process response headers if (responseInfo.Status == 401) { //we need to send the proxy support header/ or overwrite the existing proxy support header responseInfo.Headers["Proxy-Support"] = "Session-Based-Authentication"; } //if connection is close disconnect, or if the client sent us a connection close message if (String.Compare(responseInfo.Headers[CONNECTION_HEADER], "close", true) == 0 || String.Compare(_requestInfo.Headers[CONNECTION_HEADER], "close", true) == 0) { _isClose = true; } byte[] responseHead = HandleResponseByteChunk(responseInfo.ResponseHead); if (!TryWriteToStream(responseHead)) { return; } ; // Return the substitute response body if (responseInfo.ResponseBody.IsChunked) { byte[] chunk; byte[] chunkBuf; while ((chunk = responseInfo.ResponseBody.ReadChunk()) != null) { //write the chunk size line chunkBuf = Constants.DefaultEncoding.GetBytes(String.Format("{0:x}\r\n", chunk.Length)); chunkBuf = HandleResponseByteChunk(chunkBuf); if (!TryWriteToStream(chunkBuf)) { return; } //write the chunk chunk = HandleResponseByteChunk(chunk); if (!TryWriteToStream(chunk)) { return; } chunkBuf = Constants.DefaultEncoding.GetBytes("\r\n"); chunkBuf = HandleResponseByteChunk(chunkBuf); if (!TryWriteToStream(chunkBuf)) { return; } } //write a last chunk with the value 0 // write the last chunk size chunkBuf = Constants.DefaultEncoding.GetBytes("0\r\n\r\n"); chunkBuf = HandleResponseByteChunk(chunkBuf); if (!TryWriteToStream(chunkBuf)) { return; } } else { byte[] buffer = responseInfo.ResponseBody.ToArray(); if (buffer != null) { buffer = HandleResponseByteChunk(buffer); if (!TryWriteToStream(buffer)) { return; } } } //cleanup the request info _requestBuilder = new ByteArrayBuilder(); if (_currDataStoreRequestInfo != null) { TrafficDataStore.SaveResponse(_currDataStoreRequestInfo.Id, _currentRequestResponseBytes); } _currDataStoreRequestInfo = null; _currentRequestResponseBytes = null; //close the connection if the request had a connection close header if (_isClose) { ClientStreamWrapper.Close(); } else { _isBusy = false; ClientStreamWrapper.BeginRead(Buffer, 0, Buffer.Length, new AsyncCallback(OnRead), ClientStreamWrapper); } }
private void TrackRequestContext(HttpRequestInfo requestInfo) { foreach (TrackingPattern pattern in _autoTrackingPatternList.Values) { string rawRequest = requestInfo.ToString(); string needle = Utils.RegexFirstGroupValue(rawRequest, pattern.RequestPattern); if (String.IsNullOrWhiteSpace(needle)) { continue; } //first search for the path of the current request in responses LineMatches results = SearchParameterValue(needle); if (results.Count == 0) { needle = Utils.UrlDecode(needle); results = SearchParameterValue(needle); } //if any of the two searches returned results if (results.Count != 0) { //get the last match to extract the request context var match = results[results.Count - 1]; CurrDataStoreRequestInfo.RefererId = match.RequestId; //replace the path in the match string requestContext = match.Line.Replace(needle, REQ_CONTEXT_ID); if (requestContext.Length > MAX_REQUEST_CONTEXT_SIZE) { requestContext = TrimRequestContext(requestContext); } //also replace hexadecimal values requestContext = Regex.Replace(requestContext, HEX_REGEX, HEX_VAL); //escape the line requestContext = Regex.Escape(requestContext); //insert the group requestContext = requestContext.Replace(REQ_CONTEXT_ID, RX_GROUP); //insert the HEX regex requestContext = requestContext.Replace(HEX_VAL, HEX_REGEX); CurrDataStoreRequestInfo.RequestContext = requestContext; CurrDataStoreRequestInfo.TrackingPattern = pattern.Name; TrafficDataStore.UpdateRequestInfo(CurrDataStoreRequestInfo); string originalPath = requestInfo.Path; CurrDataStoreRequestInfo.UpdatedPath = originalPath; //change the path of the request HttpRequestInfo newReq = new HttpRequestInfo(requestInfo.ToArray(false), false); //we are only replacing the last portion of the path and the query string to prevent relative path issues and also cookie path issues int lastIndexOfSlash = originalPath.LastIndexOf('/'); if (lastIndexOfSlash >= 0) { originalPath = originalPath.Substring(0, lastIndexOfSlash + 1); } newReq.Path = String.Format("{0}{1}{2}", originalPath, REQ_ID_STRING, CurrDataStoreRequestInfo.Id); TrafficDataStore.SaveRequest(CurrDataStoreRequestInfo.Id, newReq.ToArray(false)); HttpServerConsole.Instance.WriteLine ("Found request context for request '{0}' id: {1}, referer id:{2}", requestInfo.Path, CurrDataStoreRequestInfo.Id, CurrDataStoreRequestInfo.RefererId); HttpServerConsole.Instance.WriteLine (requestContext); return; //we can only have one tracking pattern per request } } }
/// <summary> /// Triggered before the request is sent to the site /// </summary> /// <param name="requestInfo"></param> /// <returns></returns> protected override HttpRequestInfo OnBeforeRequestToSite(HttpRequestInfo requestInfo) { bool wasModified = false; if (_requestReplacements != null) { string request = requestInfo.ToString(); foreach (string key in _requestReplacements.Keys) { if (Utils.IsMatch(request, key)) { request = Utils.ReplaceGroups(request, key, _requestReplacements[key]); wasModified = true; HttpServerConsole.Instance.WriteLine(LogMessageType.Information, "Request replacement applied for pattern: '{0}'", key); } } if (wasModified) { requestInfo = new HttpRequestInfo(request, false); //update the content length if (requestInfo.ContentData != null) { requestInfo.Headers["Content-Length"] = requestInfo.ContentData.Length.ToString(); } requestInfo.IsSecure = ClientStreamWrapper.IsSecure; } } if (!_isNonEssential) { var originalRawRequest = requestInfo.ToString(); //update tracked values string updatedRequest = PatternTracker.Instance.UpdateRequest(originalRawRequest); updatedRequest = UpdateDynamicPatterns(updatedRequest); if (!originalRawRequest.Equals(updatedRequest)) { bool isSecure = requestInfo.IsSecure; requestInfo = new HttpRequestInfo(updatedRequest, false); requestInfo.IsSecure = isSecure; wasModified = true; } if (wasModified) { //update the request in the file TrafficDataStore.SaveRequest(CurrDataStoreRequestInfo.Id, Constants.DefaultEncoding.GetBytes(updatedRequest)); } } if (CurrDataStoreRequestInfo != null) { //see if the request was trapped if (HttpTrap.Instance.TrapRequests && HttpTrap.Instance.TrapRequest(CurrDataStoreRequestInfo, requestInfo)) { //then we need to update the request info from the data source requestInfo = new HttpRequestInfo(TrafficDataStore.LoadRequestData(CurrDataStoreRequestInfo.Id), false); //update the content length if (requestInfo.ContentData != null) { requestInfo.Headers["Content-Length"] = requestInfo.ContentData.Length.ToString(); } requestInfo.IsSecure = ClientStreamWrapper.IsSecure; } } return(requestInfo); }