Saturday, June 11, 2016

Enable copy-paste on a bill-payment website (Updated December 2016)

Why?
Typing is prone to mistakes, that's why most sites will ask you to enter in crucial data twice, just to make sure you have entered it in correctly.... but blocking paste on a website because you are afraid that users will use it for evil is dumb, and it's been proven dumb by all tested metrics. Blocking paste actually decreases security, as now users will probably choose a more simple passwords/etc as they can't paste complex ones. It's not like these are missile codes (relevant XKCD). It's especially dumb when you need to enter a checking account number and routing number twice as it's easy to mistype/transpose something (even twice). It's much better to be able to paste in your bank account code from a password manager like lastpass/keepass/onepass.
This method used below will disable the javascript function from erasing the pasted data, thus allowing you to past in you check information into the crappy payment website for the County of Sacramento Utilities Department.

Disclaimer
The information is provided “AS IS” with no warranties, and confers no rights. Use at your own risk.

How?
For this guide we will be using the greasemonkey/Tampermonkey plugin with Firefox/Chrome to allow us to use paste on the stupid fucking website for the county of Sacramento, California Department of Utilities bill payment.
  • Firefox - Install Greasemonkey
    • From within the Firefox browser, go here: https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/
    • Click the "+ Add to firefox" button
    • Confirm the install by click on on "Install"
    • Restart firefox to complete the install
  • Chrome - Install Tampermonkey
    • From within the Chrome browser, go here: https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo
    • Click the "+ Add to Chrome" button
    • Click the "Add extension" button
  • Install the script by:
    • Option 1: Using the code directly form Github:
    • Option 2: Manually for Firefox+Greasemonkey (no automatic updates with this method)
      • Click on the greasemonkey drop-down arrow, and select "New user script...".
      • In the new window, enter the following:
         
        Name:    Official Payments Copy-Paste
        Namespace: officialpayments.BrianCanFixIT
        Description: officialpayments.com Allow copy-paste into check information confirmation fields
        Includes (One per line): https://www.officialpayments.com/*
         
        Name:    Sacramento County Payments Enable Paste
        Namespace: paymentexpress.BrianCanFixIT
        Description: payment-express.net Allow paste into check account information fields
        Includes (One per line): https://www.payment-express.net/*
         
      • Then click the "OK" button.
      • Append the following to the generated code:
        
        var scriptCode = new Array();
        scriptCode.push('function clearPaste(x){}' );
        var script = document.createElement('script');
        script.innerHTML = scriptCode.join('\n');
        scriptCode.length = 0;
        document.getElementsByTagName('head')[0].appendChild(script);
        
        document.getElementById("control-group-ec_account_number").className = document.getElementById("control-group-ec_account_number").className.replace(" js-noclip ", " ");
        document.getElementById("ec_account_number").className = document.getElementById("ec_account_number").className.replace(" js-noclip ", " ");
        document.getElementById("control-group-ec_confirm_account_number").className = document.getElementById("control-group-ec_confirm_account_number").className.replace(" js-noclip ", " ");
        document.getElementById("ec_confirm_account_number").className = document.getElementById("ec_confirm_account_number").className.replace(" js-noclip ", " ");
         
    • Option 2: Manually for Chrome+Tampermonkey (no automatic updates with this method)
      • Click on the Tampermonkey icon, and select "+ Add a new script".
      • In the new window, enter the following:
         
        // ==UserScript==
        // @name        Official Payments Copy-Paste
        // @namespace   officialpayments.BrianCanFixIT
        // @description  officialpayments.com Allow copy-paste into check information confirmation fields
        // @include     https://www.officialpayments.com/*
        // @version     1.6
        // @grant       none
        // ==/UserScript==
        
        var scriptCode = new Array();   // this is where we are going to build our new script
        // here's the build of the new script, one line at a time
        //basically we're going to overwrite the functions that prevents you from doing a copy-paste, with one that does nothing
        scriptCode.push('function clearPaste(x){}'        );
        // now, we put the script in a new script element in the DOM
        var script = document.createElement('script');    // create the script element
        script.innerHTML = scriptCode.join('\n');         // add the script code to it
        scriptCode.length = 0;                            // recover the memory we used to build the script
        // this is sort of hard to read, because it's doing 2 things:
        // 1. finds the first <head> tag on the page
        // 2. adds the new script just before the </head> tag
        document.getElementsByTagName('head')[0].appendChild(script);
         
         
        // ==UserScript==
        // @name        Sacramento County Payments Enable Paste
        // @namespace   paymentexpress.BrianCanFixIT
        // @description payment-express.net Allow paste into check account information fields
        // @downloadURL https://gist.github.com/BrianCanFixIT/2f3635f9d047316954943ba50c17a9f7/raw/payment_express.user.js
        // @include     https://www.payment-express.net/*
        // @version     1.1
        // @grant       none
        // It's too bad that people create crappy websites that encourage user-error and make things harder for people to use.
        // The script below will remove the class "js-noclip" from the form/input fields; this class prevents pasting into the
        // 'Account #' and 'Confirm Account #' fields. All other protections are kept in place (no copying data from the fields,
        // obviscation of the fields, etc). This is a very simple script and as you can see beloe the only change is to find and
        // replace the 'js-noclip' class with nothing.
        // ==/UserScript==
        
        document.getElementById("control-group-ec_account_number").className = document.getElementById("control-group-ec_account_number").className.replace(" js-noclip ", " ");
        document.getElementById("ec_account_number").className = document.getElementById("ec_account_number").className.replace(" js-noclip ", " ");
        document.getElementById("control-group-ec_confirm_account_number").className = document.getElementById("control-group-ec_confirm_account_number").className.replace(" js-noclip ", " ");
        document.getElementById("ec_confirm_account_number").className = document.getElementById("ec_confirm_account_number").className.replace(" js-noclip ", " ");
        
        
      • Then click on the "Save" icon.
  • Using the script
    • The script only loads when on the "www.officialpayments.com" "www.payment-express.com" website.
    • You may ow use the paste function on this website without having to do anything else.
Questions?
Q: What happens if the County of Sacramento changes the code on their website and breaks this script/disables paste again?
A (short): You can disable the script, and I'll update my code to work again as soon as I find out.
A (long): It is unlikely that they will do this again well.... somewhat likely as preventing paste causes more security problems... that said, I'll update the code on github if they do disable paste in a new way. If they update again, so will I... it would be an arm's race that would cause them more pain then good no matter what.

Q: What if there a problem with the script?
A: Disable the script, and let me know by email, briancanfixit@gmail.com

Q: How are you securing the gist to make sure no one else takes it over and sabotage it?
A: I'm glad you're paranoid, you should be. I use a random unique password for that github account that is stored in a password manager protected by two-factor authentication. I also do not click on links in email, nor do I open untrusted files on my primary system (that's what a VM is for).

Q: How can I trust that you won't sell your github account or sabotage the gist yourself.
A: I won't, but you can't trust everyone; that's why there is the manual install option up there.

Friday, January 8, 2016

Automating WSUS cleanup and maintenance with a scheduled Powershell cleanup script

Finished product first: WSUS-Cleanup.ps1

$logfile="C:\Scripts\Logs\WSUS-Cleanup.log"

$ErrorActionPreference="SilentlyContinue"
Stop-Transcript | out-null
$ErrorActionPreference = "Continue"
Start-Transcript -path $logfile
$Error.Clear()

Write-Output "$((get-date).ToLongTimeString()) $server - WSUS Cleanup starting..."
Invoke-WsusServerCleanup -CleanupObsoleteUpdates -CleanupUnneededContentFiles -CompressUpdates -DeclineExpiredUpdates -DeclineSupersededUpdates
Write-Output "$((get-date).ToLongTimeString()) $server - WSUS Cleanup complete."

Stop-Transcript
$emailbody = Get-Content $logfile | Out-String
$emailsubject = "WSUS cleanup report on $Env:ComputerName"
if ($error -ne $null){ $emailsubject = "WSUS cleanup report ERROR on $Env:ComputerName"}

Send-MailMessage `
    -From "$env:COMPUTERNAME-alert@contoso.com" `
    -To "Brian Admin <briancanfixit@gmail.com>", "Other Admin <none@contoso.com>" `
    -Subject "$emailsubject" `
    -Body "$emailbody" `
    -SmtpServer "mail.contoso.com"





Where to save this script?

I like to have my script saved to C:\Scripts\ and limit access to said folder to only authorized staff/processes. 

Windows Task Scheduler runs it every Wednesday at 2am

  1. Run Windows Task Scheduler
  2. Click "Create Basic Task..."
  3. Name the task "WSUS Cleanup" or similar, Click "Next >"
  4. Weekly, Click "Next >"
  5. Check the Wednesday checkbox, enter the time of 2:00am, Click "Next >"
  6. Use the default of "Start a Program", Click "Next >"
  7. For "Program/Script" enter:
    powershell
  8. For "Add Arguments" enter:
    -command "C:\Scripts\WSUS-Cleanup.ps1" -ExecutionPolicy Bypass
  9. Click "Next >"
  10. Click "Finish"
  11. Click on the newly created task and click "Properties"
  12. Under General, Click "Change User or Group...", enter in "SYSTEM" and click "OK"*
  13. Under Settings, "Stop the task if it runs longer than:" drop-down, select "2 Hours", Click "OK"
*=Always remember to limit file access to these scripts to prevent an authorized user from adding malicious code.

So what does it look like?

Email just after Patch Tuesday:

**********************
Windows PowerShell transcript start
Start time: 20151215074723
Username: CONTOSO\SYSTEM
RunAs User: CONTOSO\SYSTEM
Machine: WSUS (Microsoft Windows NT 6.3.9600.0)
Host Application: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.EXE -command C:\Scripts\WSUS-Cleanup.ps1 -ExecutionPolicy Bypass
Process ID: 73016
**********************
Transcript started, output file is C:\Scripts\WSUS-Cleanup.log
7:47:23 AM  - WSUS Cleanup starting...
Obsolete Updates Deleted:0
Expired Updates Declined: 0
Obsolete Updates Deleted:96
Updates Compressed:1559
Diskspace Freed:2796151652
7:51:06 AM  - WSUS Cleanup complete.
**********************
Windows PowerShell transcript end
End time: 20151215075106
**********************

Normal Email: 

**********************
Windows PowerShell transcript start
Start time: 20151014020013
Username: CONTOSO\SYSTEM
RunAs User: CONTOSO\SYSTEM
Machine: WSUS (Microsoft Windows NT 6.3.9600.0)
Host Application: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.EXE -command C:\Scripts\WSUS-Cleanup.ps1 -ExecutionPolicy Bypass
Process ID: 3124
**********************
Transcript started, output file is C:\Scripts\WSUS-Cleanup.log
2:00:14 AM  - WSUS Cleanup starting...
Obsolete Updates Deleted:0
Expired Updates Declined: 0
Obsolete Updates Deleted:0
Updates Compressed:4
Diskspace Freed:17829289
2:00:24 AM  - WSUS Cleanup complete.
**********************
Windows PowerShell transcript end
End time: 20151014020024
**********************

Script Breakdown

$logfile="C:\Scripts\Logs\WSUS-Cleanup.log"
Set the location of the log file that we will email later.

$ErrorActionPreference="SilentlyContinue"
Stop-Transcript | out-null
$ErrorActionPreference = "Continue"
Start-Transcript -path $logfile
$Error.Clear()

Here we stop the transcript and tell powershell to continue if any errors happen. We then Tell powershell to continue normally if an error happens and start the transcript. We also clear any errors that may exist.

Write-Output "$((get-date).ToLongTimeString()) $server - WSUS Cleanup starting..."

Log the Date & Time. I like to include everything as part of a larger string in double-quotes, this is why you must use the $( to escape the variable when referencing a property. If you use single quotes then it means something totally different to powershell. and you can't escape
 

Invoke-WsusServerCleanup -CleanupObsoleteUpdates -CleanupUnneededContentFiles -CompressUpdates -DeclineExpiredUpdates -DeclineSupersededUpdates
Here is the one big command that does what we came here for.
It's fairly self-explanatory and does the following 5 tasks:
-CleanupObsoleteUpdates
-CleanupUnneededContentFiles
-CompressUpdates
-DeclineExpiredUpdates
-DeclineSupersededUpdates

Write-Output "$((get-date).ToLongTimeString()) $server - WSUS Cleanup complete."
Log the Date & Time




Stop-Transcript
Stop logging everything
 

$emailbody = Get-Content $logfile | Out-String
We'll get the file contents of our log file saves as a string (it would normally use an array of strings) to use at the Email body.

$emailsubject = "WSUS cleanup report on $Env:ComputerName"

The Subject of our Email will include the computer name.
 
if ($error -ne $null){ $emailsubject = "WSUS cleanup report ERROR on $Env:ComputerName"}

If there was an error during the WSUS cleanup process, then change the subject of the email message.

Send-MailMessage `
    -From "$env:COMPUTERNAME-alert@contoso.com" `
    -To "Brian Admin <briancanfixit@gmail.com>", "Other Admin <none@contoso.com>" `
    -Subject "$emailsubject" `
    -Body "$emailbody" `
    -SmtpServer "mail.contoso.com"

Send the email message, note the back-ticks ` and the end of the lines... that basically means the powershell command spans the next line break.

And that's it. Hopefully it has helped you out. At the very least it will help me remember how I've done this before.