How to redirect requests to another host using ZAP? - owasp

I'm new to ZAP and I don't know much about it's js/ecma scripting.
Basically, I was trying to redirect request to another host.
Say an application that is connected to the ZAP proxy makes a request in a URL:
http://www.somesite.com/path/to/a/file
but I want to change the hostname in the URL to:
another.site.com
so it will actually request to: http://www.anothersite.com/path/to/a/file
Here's the code that I was trying to work but the URL remains unchanged in the request.
function proxyRequest(msg) {
// Debugging can be done using println like this
var uri = msg.getRequestHeader().getURI().toString()
var host = msg.getRequestHeader().getURI().getHost().toString()
print('proxyResponse called for url=' + uri)
if (host == 'download.qt.io') {
uri = uri.replace('download.qt.io/online/', 'mirrors.ocf.berkeley.edu/qt/online/')
msg.getRequestHeader().setHeader('Location', uri)
print('proxyRequest changed to url=' + uri)
}
if (host == 'ftp.jaist.ac.jp') {
uri = uri.replace('ftp.jaist.ac.jp/pub/qtproject/online/', 'mirrors.ocf.berkeley.edu/qt/online/')
msg.getRequestHeader().setHeader('Location', uri)
print('proxyRequest changed to url=' + uri)
}
if (host == 'qtproject.mirror.liquidtelecom.com') {
uri = uri.replace('qtproject.mirror.liquidtelecom.com/online/', 'mirrors.ocf.berkeley.edu/qt/online/')
msg.getRequestHeader().setHeader('Location', uri)
print('proxyRequest changed to url=' + uri)
}
return true
}

Option 1: Replacer Rule
Install the Replacer addon, from the marketplace:
Goto the Tools menu and select 'Replacer Options'.
Setup a rule as shown in the following screenshot.
Save/Okay as appropriate.
Now when your browse etc all your traffic will be redirected/rewritten.
Option 2: HttpSender Script
Create a new HttpSender script, similar to the following example:
function sendingRequest(msg, initiator, helper) {
var host = msg.getRequestHeader().getURI().getHost();
if (host.equals("www.somesite.com")) {
uri = msg.getRequestHeader().getURI();
uri.setEscapedAuthority("www.anothersite.com");
msg.getRequestHeader().setURI(uri);
}
return msg;
}
function responseReceived(msg, initiator, helper) {}
Option 3: Hosts File Entry
Goto a command prompt and nslookup www.somesite.com, note the IP address (w.x.y.z).
In your hosts file, add an entry associating the noted IP (w.x.y.z) with www.anothersite.com.
(You may need to restart ZAP/browsers for this change to take effect. On linux you'll likely need to sudo to edit the file, on Windows you'll need to edit it as an admin user.)
(Further details WRT editing your hosts file: https://www.howtogeek.com/howto/27350/beginner-geek-how-to-edit-your-hosts-file/)

Related

Is it possible to secure a ColdFusion 11 REST Service with HTTP BASIC Authentication?

I am setting up a simple REST Service in ColdFusion 11. The web server is IIS 8.5 on Windows Server 2012R2.
This REST Service needs to be secured to prevent unauthorized users from accessing/writing data. For the time being, there will be only one authorized user, so I want to keep authentication/authorization as simple as possible. My initial thought is to use HTTP BASIC Authentication.
Here's the setup for the REST Service:
Source Directory: C:\web\site1\remoteapi\
REST path: inventory
To implement this, I configured the source directory of the REST Service in IIS to authorize only one user, disable Anonymous authentication, and enable Basic authentication.
When I call the source directory directly in a browser (i.e. http://site1/remoteapi/inventory.cfc?method=read), I am presented with the Basic authentication dialog.
However, when I attempt to request the REST path (http://site1/rest/inventory/), I am not challenged at all.
How can I implement HTTP BASIC authentication on the REST path?
So, due to the need to get this done without much delay, I went ahead and using some principles from Ben Nadel's website, I wrote my own authentication into the onRequestStart() method of the REST Service's Application.cfc. Here is the basic code, though it uses hard-coded values in the VARIABLES scope to validate the username and password and also does not include any actual "authorization" setting:
public boolean function onRequestStart(required string targetPage) {
LOCAL.Response = SUPER.onRequestStart(ARGUMENTS.targetpage);
if (!StructKeyExists(GetHTTPRequestData().Headers, "Authorization")) {
cfheader(
name="WWW-Authenticate",
value="Basic realm=""REST API Access"""
);
LOCAL.RESTResponse = {
status = 401,
content = {Message = "Unauthorized"}
};
restSetResponse(LOCAL.RESTResponse);
}
else {
LOCAL.IsAuthenticated = true;
LOCAL.EncodedCredentials =
GetToken( GetHTTPRequestData().Headers.Authorization, 2, " " );
// Credential string is not Base64
if ( !ArrayLen(
REMatch(
"^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$",
LOCAL.EncodedCredentials
)
)
) {
LOCAL.IsAuthenticated = false;
}
else {
// Convert Base64 to String
LOCAL.Credentials =
ToString(ToBinary( LOCAL.EncodedCredentials ));
LOCAL.Username = GetToken( LOCAL.Credentials, 1, ":" );
LOCAL.Password = GetToken( LOCAL.Credentials, 2, ":" );
if ( LOCAL.Username != VARIABLES.CREDENTIALS.Username
|| LOCAL.Password != VARIABLES.CREDENTIALS.Password
) {
LOCAL.IsAuthenticated = false;
}
}
if (!LOCAL.IsAuthenticated) {
LOCAL.Response = {
status = 403,
content = {Message = "Forbidden"}
};
restSetResponse(LOCAL.Response);
}
}
return LOCAL.Response;
}

Adding a websocket "put" request in the bootstrap.js file in sails : cannot find io

I need to call a socket request from the bootstrap.js file in sails.
The bootstrap.js file has some code checking if some game engine has updated some file. If so, it needs send a message with some updated data via socket to some defined route called "/update"... e.g.
io.socket.put('/update', {history:{sessions:[1,2,3,4]}},function gotResponse(body, response) {
console.log('Server sending request ot server ');
})
The problem is that it tells me that io is not recognised.
I tried to do npm install for both sails.io.js and socket.io-client and then write:
var io = require('sails.io.js')( require('socket.io-client') );
at the top.
Unfortunately, it gives me the following error message:
C:\Users\Evolver\Documents\programming\pipegame\game6\node_modules\socket.io-client\lib\url.js:29
if (null == uri) uri = loc.protocol + '//' + loc.host;
^
TypeError: Cannot read property 'protocol' of undefined
at url (C:\Users\Evolver\Documents\programming\pipegame\game6\node_modules\socket.io-client\lib\url.js:29:29)
at lookup (C:\Users\Evolver\Documents\programming\pipegame\game6\node_modules\socket.io-client\lib\index.js:44:16)
at goAheadAndActuallyConnect (C:\Users\Evolver\Documents\programming\pipegame\game6\node_modules\sails.io.js\sails.io.js:835:21)
at selfInvoking (C:\Users\Evolver\Documents\programming\pipegame\game6\node_modules\sails.io.js\sails.io.js:812:18)
at SailsSocket.SailsIOClient.SailsSocket._connect (C:\Users\Evolver\Documents\programming\pipegame\game6\node_modules\sails.io.js\sails.io.js:831:9)
at null._onTimeout (C:\Users\Evolver\Documents\programming\pipegame\game6\node_modules\sails.io.js\sails.io.js:1463:17)
at Timer.listOnTimeout (timers.js:92:15)
Any idea ?
Ok.
It now works, once npm install has been done for socket.io-client and sails.io.js if I do exactly the following:
var socketIOClient = require('socket.io-client');
var sailsIOClient = require('sails.io.js');
// Instantiate the socket client (`io`)
var io = sailsIOClient(socketIOClient);
io.sails.url = 'http://localhost:1337';
// then I send something via my socket
io.socket.put('/update', {history:{sessions:[1,2,3,4]}},function gotResponse(body, response) {
console.log('Server sending request ot server ');
})

Lighttpd SSL Redirect - windows

I have a home server that I want to only serve pages via https but I have run into some issues. I have been serving non secure pages OK and could access the pages both on the local network and on the web (I'm using ddns.net and have all the port forwarding covered).
I have test certificates properly installed and at the moment the redirects work fantastically on the local network but NOT from the web. Below are the two redirects I have tested - both work locally but both failed to serve secure pages from the web.
NOTE: I use a non-standard port, i.e port 1080, however as mentioned above, non-secure access is all OK so the port forwarding from my gateway router to the server is (at least I think!) fine. Also, I can only browse to the server when I concatenate the port number to the IP / name, i.e localhost:1080 or 192.168.1.1:1080 (which is fine by me) and thus the redirect filters.
In this instance, I can access the pages bot securely and insecurely from the local network but can NOT access securely from the web.
$HTTP["scheme"] == "http" {
$HTTP["host"] =~ "^(.*):1080" {
url.redirect = (".*" => "https://%1$0")
}
}
$SERVER["socket"] == ":443" {
ssl.engine = "enable"
ssl.pemfile = Var.Doo + "/server.pem"
ssl.ca-file = Var.Doo + "/ca.pem"
setenv.add-environment = ( "HTTPS" => "on" )
}
After some web research, I added a condition to the redirects to be able to handle the non-port concatenated URL, however I can neither access the pages securely nor insecurely from the web (locally still works though).
$HTTP["scheme"] == "http" {
$HTTP["host"] =~ "^(.*):1080" {
url.redirect = (".*" => "https://%1$0")
}
else $HTTP["host"] =~ ".*" {
url.redirect = (".*" => "https://%0$0")
}
}
$SERVER["socket"] == ":443" {
ssl.engine = "enable"
ssl.pemfile = Var.Doo + "/server.pem"
ssl.ca-file = Var.Doo + "/ca.pem"
setenv.add-environment = ( "HTTPS" => "on" )
}
EDIT: OK, 20 views & counting and no suggestion of an answer yet ...
I know I stated above that I believe the port forwarding is all good, but now I am having second thoughts on that. Any pointers either way?
OK, I spent some more time looking at this and managed to resolve the issue, which was two-fold.
As latterly suspected, my initial assumption that the port forwarding was OK turned out to be incorrect as I had not forwarded the secure port (which lighttpd forcefully defaults to), i.e port 443. Thus the first part of the solution was completing the port forwarding on my gateway router to include that route.
The second part of the solution is a textually minor change to the redirect code in the configuration file to filter on the ports rather than the protocol (the former code may also work but have not tested it). Here's the changed and tested code:
$SERVER["socket"] == ":443" {
ssl.engine = "enable"
ssl.pemfile = Var.Doo + "/server.pem"
ssl.ca-file = Var.Doo + "/ca.pem"
setenv.add-environment = ( "HTTPS" => "on" )
}
else $SERVER["socket"] == ":1080" {
$HTTP["host"] =~ "([^:/]+)" {
url.redirect = ( "^/(.*)" => "https://%1:443/$1" )
}
}

Spring cloud eureka client to multiple eureka servers

I am able to get the eureka server to operate in a peer to peer mode. But one thing I am curious about is how do I get a service discovery client to register to multiple eureka servers.
My use case is this:
Say I have a service registering to one of the eureka servers (e.g. server A) and that registration is replicated to its peer. The service is actually pointing at server A. If server A goes down, and the client expects to renew with server A, how do the renewal work if server A is no longer present.
Do I need to register with both and if not then how does the renewal happen if the client cannot communicate with server A. Does it have some knowledge of server B (from its initial and/or subsequent comms with A) and fail over to do its registration renewal there? That is not clear in any of the docs and I need to verify
So based on the answer, I added the following to my application.yml
eureka:
# these are settings for the client that gets services
client:
# enable these two settings if you want discovery to work
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: http://localhost:8762/eureka/, http://localhost:8761/eureka/
It only registers to the first in the comma separated list. If I switch them around the registration flips between eureka servers.
I can see that it does separate these based on comma but my guess is that Eureka does not use this underneath (from EurekaClientConfigBean.java)
#Override
public List<String> getEurekaServerServiceUrls(String myZone) {
String serviceUrls = this.serviceUrl.get(myZone);
if (serviceUrls == null || serviceUrls.isEmpty()) {
serviceUrls = this.serviceUrl.get(DEFAULT_ZONE);
}
if (serviceUrls != null) {
return Arrays.asList(serviceUrls.split(","));
}
return new ArrayList<>();
}
I just reviewed the source code for Eureka 1.1.147. It works differently that i expected but at least I know now.
You can put multiple service urls in the set
serviceUrl:
defaultZone: http://localhost:8762/eureka/, http://localhost:8761/eureka/
But the register action only uses the first one to register. There remaining are used only if attempting to contact the first fails.
from (DiscoveryClient.java)
/**
* Register with the eureka service by making the appropriate REST call.
*/
void register() {
logger.info(PREFIX + appPathIdentifier + ": registering service...");
ClientResponse response = null;
try {
response = makeRemoteCall(Action.Register);
isRegisteredWithDiscovery = true;
logger.info(PREFIX + appPathIdentifier + " - registration status: "
+ (response != null ? response.getStatus() : "not sent"));
} catch (Throwable e) {
logger.error(PREFIX + appPathIdentifier + " - registration failed"
+ e.getMessage(), e);
} finally {
if (response != null) {
response.close();
}
}
}
which calls
private ClientResponse makeRemoteCall(Action action) throws Throwable {
return makeRemoteCall(action, 0);
}
It only calls the backup when an exception is thrown in the above makeRemoteCall(action, 0) call
} catch (Throwable t) {
closeResponse(response);
String msg = "Can't get a response from " + serviceUrl + urlPath;
if (eurekaServiceUrls.get().size() > (++serviceUrlIndex)) {
logger.warn(msg, t);
logger.warn("Trying backup: " + eurekaServiceUrls.get().get(serviceUrlIndex));
SERVER_RETRY_COUNTER.increment();
return makeRemoteCall(action, serviceUrlIndex);
} else {
ALL_SERVER_FAILURE_COUNT.increment();
logger.error(
msg
+ "\nCan't contact any eureka nodes - possibly a security group issue?",
t);
throw t;
}
So you can't really register to two eureka servers simultaneously from this code. Unless I missed something.
Your client application should be provided a list of Eureka URLs. The URLs are comma separated.
Yes, as per the documentation, the flow is:
client registers to the first available eureka server
registrant information is replicated between eureka server nodes.
So multiple registration is not only not needed but should be avioded.
Please add below property in application.property or application.yml file
eureka.client.service-url.defaultZone = http://localhost:8761/eureka,http://localhost:8762/eureka
Services will be registered with both eureka server.If one eureka server is down then request will be served from other eureka server.
If you want to a workaround to register on multiple eureka servers.
please review my answer on similar question: https://stackoverflow.com/a/60714917/7982168

fiddler redirect https to localhost

I have an iPhone app that connects to an HTTPS service in Azure. I want to redirect the iPhone calls via Fiddler to http://localhost:19703 where I am running the same service on my local machine for debugging purposes. I am able to redirect the HTTPS service to another HTTPS service using the following Fiddler script. However, if I use the same script to redirect to localhost:19703, it does not work. Any ideas?
if (oSession.HTTPMethodIs("CONNECT") && (oSession.PathAndQuery == "XXXX.azurewebsites.net:443"))
{
oSession["OriginalHostname"] = oSession.hostname;
oSession.PathAndQuery = "YYYY.azurewebsites.net:443";
}
// If it's an HTTPS tunnel, override the certificate
if (oSession.HTTPMethodIs("CONNECT") && (null != oSession["OriginalHostname"]))
{
oSession["x-overrideCertCN"] = oSession["OriginalHostname"];
oSession["X-IgnoreCertCNMismatch"] = "Server's hostname may not match what we're expecting...";
}
oSession.bypassGateway = true;
Try using this approach:
static function OnBeforeRequest(oSession:Fiddler.Session) {
...
if (oSession.HostnameIs("YYYY.azurewebsites.net")) {
oSession.host = "127.0.0.1:19703";
}
...
}
Complete description of the issue is here.