How can I can list of alerts associated with scan rules in OWASP ZAP? - owasp

I want to get the list of alerts in a tabular form like below. I copy the URL's in the alerts and manually prepare such a tabular table myself. However, I need to do this automatically or semi-automatically (at least)
Alert Name URL Scan Type Scan_Name WASCID CWEID
---------- --------------- --------- --------- ----- ------

You can export the report in XML and apply any kind of XSL transform to it that you might like.
You could pull the XML report into Excel (or whatever spreadsheet program) and manipulate it.
You could pull alerts from the web API and have them in XML or json and process them however you like programmatically.
You could write a standalone script (within ZAP) to traverse the Alerts tree and output the details tab delimited in the script console pane. For example:
extAlert = org.parosproxy.paros.control.Control.getSingleton().
getExtensionLoader().getExtension(
org.zaproxy.zap.extension.alert.ExtensionAlert.NAME)
extPscan = org.parosproxy.paros.control.Control.getSingleton().
getExtensionLoader().getExtension(
org.zaproxy.zap.extension.pscan.ExtensionPassiveScan.NAME);
var pf = Java.type("org.parosproxy.paros.core.scanner.PluginFactory");
printHeaders();
if (extAlert != null) {
var Alert = org.parosproxy.paros.core.scanner.Alert;
var alerts = extAlert.getAllAlerts();
for (var i = 0; i < alerts.length; i++) {
var alert = alerts[i]
printAlert(alert);
}
}
function printHeaders() {
print('AlertName\tSource:PluginName\tWASC\tCWE');
}
function printAlert(alert) {
var scanner = '';
// If the session is loaded in ZAP and one of the extensions that provided a plugin for the
// existing alerts is missing (ex. uninstalled) then plugin (below) will be null, and hence scanner will end-up being empty
if (alert.getSource() == Alert.Source.ACTIVE) {
plugin = pf.getLoadedPlugin(alert.getPluginId());
if (plugin != null) {
scanner = plugin.getName();
}
}
if (alert.getSource() == Alert.Source.PASSIVE && extPscan != null) {
plugin = extPscan.getPluginPassiveScanner(alert.getPluginId());
if (plugin != null) {
scanner = plugin.getName();
}
}
print(alert.getName() + '\t' + alert.getSource() + ':' + scanner + '\t' + alert.getWascId() + '\t' + alert.getCweId());
// For more alert properties see https://static.javadoc.io/org.zaproxy/zap/2.7.0/org/parosproxy/paros/core/scanner/Alert.html
}
Produces script console output like (note the 2nd, 6th, and 7th rows the specific alert name differs from the general scanner name):
Alert_Name Source:PluginName WASC CWE
Cross Site Scripting (DOM Based) ACTIVE:Cross Site Scripting (DOM Based) 8 79
Non-Storable Content PASSIVE:Content Cacheability 13 524
Content Security Policy (CSP) Header Not Set PASSIVE:Content Security Policy (CSP) Header Not Set 15 16
Server Leaks Version Information via "Server" HTTP Response Header Field PASSIVE:HTTP Server Response Header Scanner 13 200
Server Leaks Information via "X-Powered-By" HTTP Response Header Field(s) PASSIVE:Server Leaks Information via "X-Powered-By" HTTP Response Header Field(s) 13 200
Non-Storable Content PASSIVE:Content Cacheability 13 524
Timestamp Disclosure - Unix PASSIVE:Timestamp Disclosure 13 200
Which pastes well in Excel:
Detailed steps:
(This assumes ZAP is running, and the session you want information for is open/loaded).
1. Goto the scripts tree (behind the Sites Tree) [if you can't see it
click the plus sign near the Sites Tree tab and add "Scripts"].
2. In the Scripts tree right click "Standalone" and select "New Script":
give it a name and select the JavaScript Script Engine ("EcmaScript
: Oracle Nashorn") [no Template is necessary]. Click "Save" on the New
Script dialog.
3. In the new script window (in the request/response area) paste the script
from the answer.
4. Run it (the blue triangle play button above the script
entry pane).
5. The results will display in the output pane below the
script.
6. Copy/paste the output into Excel.

Related

My google sheets function does the job when run from editor but gives different outcome when trigered by Form submit

I have a google form and a sheet that collects the responses which of course always appear at the bottom. I have been using the following script to copy the last response (which is always on the last row) from the Response sheet (Form Responses 2) to row two of another sheet (All Responses). When run by a trigger on Form Submit the script inserts a blank row into All Responses, then the copied values into another row above the blank row. Please can you help and tell me why and how I might change the script so the blank row is not added:
function CopyLastrowformresponse () {
var ss = SpreadsheetApp.getActive();
var AR = ss.getSheetByName("All Responses");
var FR = ss.getSheetByName("Form responses 2");
var FRlastrow = FR.getLastRow();
AR.insertRowBefore(2);
FR.getRange(FRlastrow, 1, FRlastrow, 22).copyTo(AR.getRange("A2"), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
}
A few things could be going on here.
You're getting a number of rows equal to FRlastrow, when I think you only want to be getting 1 row.
Apps Script has buggy behavior with onFormSubmit() triggers, so you may to check duplicate triggers (see this answer).
The script isn't fully exploiting the event object provided by onFormSubmit(). Specifically, rather than getting the last row from one sheet, you could use e.values, which is the same data.
I would change the script to be something like this:
function CopyLastrowformresponse (e) {
if (e.values && e.values[1] != "") { // assuming e.values[1] (the first question) is required
SpreadsheetApp.getActive()
.getSheetByName("All Responses")
.insertRowBefore(2)
.getRange(2, 1, 1, e.values.length)
.setValues([e.values]);
}
}
But, ultimately, if all you want to do is simply reverse the order of the results, then I'd ditch Apps Script altogether and just use the =SORT() function.
=SORT('Form responses 2'!A:V, 'Form responses 2'!A:A, FALSE)

Count redirects in jmeter

At the moment im usig HTTP request sampler with 'Follow Redirects' enabled and want to keep it that way. As a secondary check besides assertion i want to count the number of redirects as well, but i dont want to implement this solution.
Is there a way when i can use only 1 HTTP sampler and a postprocessor (beanshell for now) and fetch this information? Im checking SamplerResult documentation , but cant find any method which would give back this information for me.
I heard Groovy is new black moreover users are encouraged to use JSR223 Test Elements and __groovy() function since JMeter 3.1 as Beanshell performs not that well so you can count the redirects as follows:
Add JSR223 PostProcessor as a child of your HTTP Request sampler
Put the following code into "Script" area:
int redirects = 0;
def range = new IntRange(false, 299, 400)
prev.getSubResults().each {
if (range.contains(it.getResponseCode() as int)) {
redirects++;
}
}
log.info('Redirects: ' + redirects)
Once you run your test you will be able to see the number of occurred redirects in jmeter.log file:
Add the following Regular Expression Extractor as a child of your sampler:
Apply to: Main sample and sub-samples
Field to check: Response code
Regular Expression: (\d+)
Template: $1$
Match No.: -1
Then add a BeanShell Post Processor also as a child of the sampler and add the following to the script area:
int matchNr = Integer.parseInt(vars.get("MyVar_matchNr"));// MyVar is the name of the variable of the above regular expression extractor
int counter = 0;
for(i=1; i <= matchNr; i++){
String x = vars.get("MyVar_"+i);
if(x.equals("302")){
counter = counter + 1;
}}
log.info(Label + ": Number of redirects = " + String.valueOf(counter));// The output will be printed in the log like this(BeanShell PostProcessor: Number of redirects = 3 ) so you might want to change the name of the beanshell post processor to the same name of your sampler.
Then you can see the number of redirects for the sampler in the log.

Setting StrongAuthenticationUserDetails PhoneNumber for AzureAD via Powershell?

That title really flows.
When setting up computers for use with Azure Active Directory, we would have IT do initial setup and config. This included the first sign in and joining to Azure Active Directory. When signing in it forces you to select a verification method. We would use our desk phone or cell phone for ease.
The time has come for us to update that second factor phone number. I know of a way to manually do it via the Azure AD Web UI, but I am looking for a scripted way to set that number in PowerShell.
Here is how I retrieve the number via PowerShell.
Get-msoluser -UserPrincipalName "email#emailaddress.com" | Select-Object -ExpandProperty StrongAuthenticationUserDetails
That code returns this info:
ExtensionData : System.Runtime.Serialization.ExtensionDataObject
AlternativePhoneNumber :
Email :
OldPin :
PhoneNumber : +1 5554445555
Pin :
However, there seems to be no similar option for setting the StrongAuthenticationUserDetails.
All my searches just turned up how to bulk enable 2-factor authentication, which is not what I want to do. I want to leave the StrongAuthentication the same while only updating the phone number.
As I said in comment, it appears there is read-only access for powershell.
There is even opened ticket for that on Azure feedback.
There is a plan to do it, but no ETA. My guess is that you will have to wait if you want to use powershell only.
As workaround, you could use powershell & watir for .NET OR Watin with Watin recorder to automatize it via Internet Explorer. As I don't have a testing Azure; I can not create workable code for you.
Using Watin and powershell - you could check: https://cmille19.wordpress.com/2009/09/01/internet-explorer-automation-with-watin/
The following text and code, I wanted to backup it here, was taken from the above page (all credits to the author):
Next click the record button and click the HTML element you want to
automate. Then stop the WatIN recorder and click copy code to
clipboard icon. This will produce some C# code that just needs to be
translated into PowerShell:
// Windows
WatiN.Core.IE window = new WatiN.Core.IE();
// Frames
Frame frame_sd_scoreboard = window.Frame(Find.ByName("sd") && Find.ByName("scoreboard"));
// Model
Element __imgBtn0_button = frame_sd_scoreboard.Element(Find.ByName("imgBtn0_button"));
// Code
__imgBtn0_button.Click();
window.Dispose();
So, I now know the name of the button and that it is 3 frames deep. A
little WatIN object exploration later, I came up with the follow
script, which clicks a button every 50 mintues.
#Requires -version 2.0
#powershell.exe -STA
[Reflection.Assembly]::LoadFrom( "$ProfileDirLibrariesWatiN.Core.dll" ) | out-null
$ie = new-object WatiN.Core.IE("https://sd.acme.com/CAisd/pdmweb.exe")
$scoreboard = $ie.frames | foreach {$_.frames } | where {$_.name –eq ‘sd’} | foreach {$_.frames } | where {$_.name –eq ‘scoreboard’}
$button = $scoreboard.Element("imgBtn0_button")
while ($true)
{
$button.Click()
#Sleep for 50 minutes
[System.Threading.Thread]::Sleep(3000000)
}
Disclaimer: the code is provided as-is. It might happen that it'll stop working in case MS changes Azure Portal interface.
I'm using the following Greasemonkey script to update alternate email and phone (phone can be updated via Graph API now so the script will be useful for email only):
// ==UserScript==
// #name Unnamed Script 548177
// #version 1
// #grant none
// #namespace https://portal.azure.com
// ==/UserScript==
(function(){
document.addEventListener('keydown', function(e) {
// press alt+shift+g
if (e.keyCode == 71 && e.shiftKey && !e.ctrlKey && e.altKey && !e.metaKey) {
const url = document.URL;
const regex = /https:\/\/portal.azure.com\/#blade\/Microsoft_AAD_IAM\/UserDetailsMenuBlade\/UserAuthMethods\/userId\/[\w-]+\/adminUnitObjectId[\/]*\?\w+=(\d{9})&\w+=([\w\.-#]+)/;
const params = url.match(regex);
const allAuthRows = document.getElementsByClassName('ext-userauthenticationmethods-section-row');
const authRowsArray = Array.from(allAuthRows);
let emailRow;
let phoneRow;
let i;
for (i =0; i < authRowsArray.length; i++) {
if (authRowsArray[i].childNodes[1].childNodes[1].childNodes[0].data === 'Email') {
emailRow = authRowsArray[i]
}
if (authRowsArray[i].childNodes[1].childNodes[1].childNodes.length > 1) {
if (authRowsArray[i].childNodes[1].childNodes[1].childNodes[1].childNodes[0].data === 'Phone') {
phoneRow = authRowsArray[i]
}
}
}
const emailInput = emailRow.childNodes[3].childNodes[1].childNodes[1].childNodes[0].childNodes[0].childNodes[0].childNodes[2];
const phoneInput = phoneRow.childNodes[3].childNodes[1].childNodes[1].childNodes[0].childNodes[0].childNodes[0].childNodes[2];
const event = new Event('input', {
'bubbles': true,
'cancelable': true
});
if (params[1] !== '000000000') {
phoneInput.value = `+48 ${params[1]}`;
phoneInput.dispatchEvent(event);
}
if (params[2] !== 'null') {
emailInput.value = params[2];
emailInput.dispatchEvent(event);
}
setTimeout(() => {
const buttonArr = document.getElementsByClassName('azc-toolbarButton-container fxs-portal-hover');
const saveButton = Array.from(buttonArr).find(e => e.title === 'Save');
saveButton.click();
} , 2000);
}
}, false);
})();
It requires you to open Azure portal with querystring like this (I do it with PowerShell):
https://portal.azure.com/#blade/Microsoft_AAD_IAM/UserDetailsMenuBlade/UserAuthMethods/userId/$($u.ObjectId)/adminUnitObjectId/?param1=$newPhone&param2=$newMail
How to use it:
open only one tab at a time, otherwise you'll receive Unable to sign-in error
from time to time you'll receive that error anyway, so just wait
to trigger the script press Alt+Shift+g after the site is loaded (you can change the shortcut in first if)
once the data is updated and saved, press Ctrl+w to close the current tab and press Alt+Tab to switch to previous window (should be PowerShell)
you're still free to use the code to update the phone. Make sure to change country code (currently +48 for Poland)

How to mail a screen captured image using corona SDK

I am new to corona SDK, but I've managed to capture my app scene using the following code:
local function captureArea()
local myCaptureImage = display.captureBounds(display.currentStage.contentBounds, true)
myCaptureImage:removeSelf()
myCaptureImage = nil
end
bg:addEventListener("tap",captureArea)
This works perfectly.
Now I need to send the captured image(with a specific name, say: screen_1.png) to my friend via email. I've used Composing E-mail and SMS for refference, but I fail to understand how I can add this saved image in the attachment field of mail options.
Please give me a proper solution that how can I attach and send the above saved image via email.
display.captureBounds is good for saving the whole screen to the directory. But it usually saves the file with increase in last index. So it may be difficult to read them correctly. So I prefer display.save. But it is not a straight way.
For doing this, you have to:
First create a localgroup.
Then add the screen objects to that group.
Return the display group
Use display.save to save the entire group displayed.
Create mail option and add attachment image from baseDirectory
Call mail Popup
I am giving a sample here:
-- creating the display group --
local localGroup = display.newGroup()
-- creating display objects and adding it to the group --
local bg = display.newRect(0,0,_w,_h)
bg.x = 160
bg.y = 240
bg:setFillColor(150)
localGroup:insert(bg)
local rect = display.newRect(0,0,50,50)
rect.x = 30+math.random(260)
rect.y = 30+math.random(420)
localGroup:insert(rect)
-- Then do as follows --
local function takePhoto_andSendMail()
-- take screen shot to baseDirectory --
local baseDir = system.DocumentsDirectory
display.save( localGroup, "myScreenshot.jpg", baseDir )
-- Create mail options --
local options =
{
to = { "krishnarajsalim#gmail.com",},
subject = "My Level",
body = "Add this...",
attachment =
{
{ baseDir=system.DocumentsDirectory, filename="myScreenshot.jpg", type="image" },
},
}
-- Send mail --
native.showPopup("mail", options)
end
rect:addEventListener("tap",takePhoto_andSendMail)
This will do it...
Keep coding........ :)

Selenium IDE - always fail on any 500 error

Is there an easy way to tell Selenium IDE that any action that results in a http 500 response means the test failed?
I have tests that are 75 page requests long. Sometimes, I get a crash and burn somewhere in the middle, but the tests come back green.
Taking a look at selenium-api.js, I saw that there is a parameter ignoreResponseCode in the signature of the doOpen method in selenium-api.js :
Selenium.prototype.doOpen = function(url, ignoreResponseCode) {
This parameter is used by the browserbot object :
if (!((self.xhrResponseCode >= 200 && self.xhrResponseCode <= 399) || self.xhrResponseCode == 0)) {
// TODO: for IE status like: 12002, 12007, ... provide corresponding statusText messages also.
LOG.error("XHR failed with message " + self.xhrStatusText);
e = "XHR ERROR: URL = " + self.xhrOpenLocation + " Response_Code = " + self.xhrResponseCode + " Error_Message = " + self.xhrStatusText;
self.abortXhr = false;
self.isXhrSent = false;
self.isXhrDone = false;
self.xhrResponseCode = null;
self.xhrStatusText = null;
throw new SeleniumError(e);
}
I've tried calling the open function from selenium IDE with value = false and this results in an error (test failed).
My PHP test page was :
<?php
header('HTTP/1.1 500 Simulated 500 error');
?>
And this results in :
For me, this solves the problem of checking HTTP response status.
Make a JavaScript file called "user-extensions.js" and add it to the Selenium-IDE under Options > Options. If you are running Selenium RC, pass it into the parameter when starting up your server in the jar command. There should be a user extensions javascript file attribute.
Then close and restart Selenium-IDE. The User-Extensions file is cached when the IDE starts up.
Add this code to your Selenium user-extensions.js file to make a custom command called "AssertLocationPart". As you know "assertLocation" and "storeLocation" are standard commands. I tried to reduce the extra line of code to storeLocation just by getting the href in the custom function. I wasn't able to get the doAssertValue command to work. I'll have to post my own question for that. That's why it's commented out. For now, just use "this.doStore" instead. And add an extra line to your script after your custom AssertLocationPart command. Since we're not actually doing an assertion in the custom function/command, we should call it "storeLocationPart" (function would be named "doStoreLocationPart"), not "assertLocationPart" (function would be named "doAssertLocationPart"), and just pass in the first parameter. But if you can get the doAssert* to work, please let me know. I'll mess with it another day since I need to do this same thing for work.
Selenium.prototype.doAssertLocationPart = function(partName,assertTo) {
var uri = selenium.browserbot.getCurrentWindow().document.location.href;
//alert("URI = " + uri);
var partValue = parseUri(uri,partName);
//alert("Part '" + partName + "' = " + partValue);
//this.doAssertValue(partValue,assertTo);
this.doStore(partValue,"var_"+partName);
};
// Slightly modified function based on author's original:
// http://badassery.blogspot.com/2007/02/parseuri-split-urls-in-javascript.html
//
// parseUri JS v0.1, by Steven Levithan (http://badassery.blogspot.com)
// Splits any well-formed URI into the following parts (all are optional):
//
// - source (since the exec() method returns backreference 0 [i.e., the entire match] as key 0, we might as well use it)
// - protocol (scheme)
// - authority (includes both the domain and port)
// - domain (part of the authority; can be an IP address)
// - port (part of the authority)
// - path (includes both the directory path and filename)
// - directoryPath (part of the path; supports directories with periods, and without a trailing backslash)
// - fileName (part of the path)
// - query (does not include the leading question mark)
// - anchor (fragment)
//
function parseUri(sourceUri,partName){
var uriPartNames = ["source","protocol","authority","domain","port","path","directoryPath","fileName","query","anchor"];
var uriParts = new RegExp("^(?:([^:/?#.]+):)?(?://)?(([^:/?#]*)(?::(\\d*))?)?((/(?:[^?#](?![^?#/]*\\.[^?#/.]+(?:[\\?#]|$)))*/?)?([^?#/]*))?(?:\\?([^#]*))?(?:#(.*))?").exec(sourceUri);
var uri = {};
for(var i = 0; i < 10; i++){
uri[uriPartNames[i]] = (uriParts[i] ? uriParts[i] : "");
if (uriPartNames[i] == partName) {
return uri[uriPartNames[i]]; // line added by MacGyver
}
}
// Always end directoryPath with a trailing backslash if a path was present in the source URI
// Note that a trailing backslash is NOT automatically inserted within or appended to the "path" key
if(uri.directoryPath.length > 0){
uri.directoryPath = uri.directoryPath.replace(/\/?$/, "/");
if (partName == "directoryPath") {
return uri.directoryPath; // line added by MacGyver
}
}
return uri;
}
Then add this to your web.config file and make sure customErrors is turned off. Since you have a 500 error, it will redirect the user to the default page. Feel free to add a custom page for a 500 HTTP status code if you want to be specific in your Selenium scripts.
<customErrors mode="On" defaultRedirect="/ErrorHandler.aspx">
<error statusCode="401" redirect="/AccessDenied.aspx" />
<error statusCode="403" redirect="/AccessDenied.aspx" />
<error statusCode="404" redirect="/PageNotFound.aspx" />
</customErrors>
This is what your commands will look like in the IDE:
Make sure you're on this page (or something similar) before running the script:
https://localhost/ErrorHandler.aspx?aspxerrorpath=/path/pathyouweretryingtoviewinwebapp.aspx
Log shows that it passed!
[info] Executing: |storeLocation | var_URI | |
[info] Executing: |echo | ${var_URI} | |
[info] echo: https://localhost/ErrorHandler.aspx?aspxerrorpath=//path/pathyouweretryingtoviewinwebapp.aspx
[info] Executing: |assertLocationPart | fileName | ErrorHandler.aspx |
[info] Executing: |assertExpression | ${var_fileName} | ErrorHandler.aspx |
Using the error handler from my previous answer:
Command: assertLocation
Target: regexp:^(https://localhost/ErrorHandler.aspx).*$
Or (per your comment) it's inverse if you don't have error handling turned on, use AssertNotLocation. This may require more work on the person writing the scripts. You'd have to keep track of all pages.
More on pattern matching:
http://seleniumhq.org/docs/02_selenium_ide.html#matching-text-patterns
http://www.codediesel.com/testing/selenium-ide-pattern-matching/