Automated Java Uninstaller v2

If you’ve not read it, please read my original post on this subject before continuing.

The java uninstaller I posted works a treat most of the time, but not always.  We have a number of machines with Java v1.8 Update 74 on that refuse to uninstall it – even via Programs & Features the Windows installer progress box just sits there.

Process Explorer shows something interesting at this point:
Java Issue

The Windows Installer process, MsiExec.exe, has launched Java Web Start which has then opened a process called JP2Launcher.exe.  I’ve no idea what that is trying to do.  I tried a Fiddler trace of it and it caught nothing.  Whatever it is doing, killing the process allows the uninstall of Java to then continue successfully.

As a result, I’ve made an extended version of my Java Uninstaller script that will kill any instances of this process shortly after they appear.  Here it is:

Rem Remove all versions of Java x86 and x64

On Error Resume Next

Const HKEY_LOCAL_MACHINE = &H80000002
Const WINDOW_HIDDEN = 0
Const WAIT_ON_RETURN = True
Const wbemFlagReturnWhenComplete = 0

Const intJP2KillDelay = 5

Dim objSWbemServices

Set objWshShell = WScript.CreateObject("WScript.Shell")
Set objStdReg = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv")
Rem Need Debug privileges to terminate processes we do not own.
Set objSWbemServices = GetObject("winmgmts:{impersonationLevel=impersonate,(Debug)}!\\.\root\cimv2")

Rem MsiExec.exe sometimes launches JavaWS.exe which launches JP2Launcher.exe and blocks uninstall until the latter is killed.
Set objWMISink = WScript.CreateObject("WbemScripting.SWbemSink","SINK_")
strWQL = "SELECT * FROM __InstanceCreationEvent WITHIN 3 WHERE TargetInstance ISA 'Win32_Process' AND TargetInstance.Name = 'JP2Launcher.exe'"
objSWbemServices.ExecNotificationQueryAsync objWMISink, strWQL

For i = 1 To 2
	If i = 1 Then
		strKeyPath = "Software\Microsoft\Windows\CurrentVersion\Uninstall"
	Else
		strKeyPath = "Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
	End If

	objStdReg.EnumKey HKEY_LOCAL_MACHINE, strKeyPath, arrSubKeys
	If Not IsNull(arrSubKeys) Then
		For Each strSubKey In arrSubKeys
			Rem Ensure is a GUID key
			If Left(strSubKey, 1) = "{" Then
				strSubKeyPath = strKeyPath & "\" & strSubKey
				objStdReg.GetStringValue HKEY_LOCAL_MACHINE, strSubKeyPath, "DisplayName", strDisplayName
				If Not IsNull(strDisplayName) Then
					intJavaIndex = InStr(LCase(strDisplayName), "java")
					If intJavaIndex > 0 Then
						intUpdateIndex = InStr(LCase(strDisplayName), "update")
						Rem Effectively make the check to be for "*java*update*"
						If intUpdateIndex > intJavaIndex Then
							strCmd = "MsiExec.exe /X " & strSubKey & " /quiet /norestart"
							intRC = objWshShell.Run(strCmd, WINDOW_HIDDEN, WAIT_ON_RETURN)
						End If
					End If
				End If
			End If
		Next
	End If
Next

objWMISink.Cancel
Set objWMISink = Nothing
WScript.Quit

Sub SINK_OnObjectReady(objNextObject, objWbemAsyncContext)
	Rem Kill JP2Launcher.exe processes after a delay (in case it's meant to launch)

	On Error Resume Next

	intPID = objNextObject.TargetInstance.ProcessID
	strPath = objNextObject.TargetInstance.ExecutablePath
	WScript.Sleep intJP2KillDelay * 1000

	Rem Check that process is still running but can't assume the PID has not been reused
	strWQL = "SELECT * FROM Win32_Process WHERE ProcessID = " & intPID
	Set colProcesses = objSWbemServices.ExecQuery(strWQL,, wbemFlagReturnWhenComplete)
	If colProcesses.Count = 0 Then
		rem Already closed
		Exit Sub
	End If
	For Each objProcess In colProcesses
		Rem Will only ever be one match with a given PID!
		If objProcess.ExecutablePath <> strPath Then
			rem Is a different process
			Exit Sub
		End If
	Next

	objNextObject.TargetInstance.Terminate
End Sub

The extra code watches for the creation of a process called JP2Launcher.exe and then kills it after a short delay.  For a comprehensive explanation of how this works, I direct you to this excellent article here.

Firstly, an SWbemSink object is created to determine what code is called when events we’re interested in are raised.  You’ll see I specify the prefix “SINK_” that is to be used in the names of the subroutines called:

Set objWMISink = WScript.CreateObject("WbemScripting.SWbemSink","SINK_")

Next I construct a WQL query that every 3 seconds, looks to see if an event has been raised for the creation of a new instance of a Win32_Process whose name is JP2Launcher.exe:

strWQL = "SELECT * FROM __InstanceCreationEvent WITHIN 3 WHERE TargetInstance ISA 'Win32_Process' AND TargetInstance.Name = 'JP2Launcher.exe'"

Given that description, you can work out how to alter the syntax of that query to meet your requirements.  The query and the Sink object are then passed as parameters to a special WMI call called an Asynchronous (i.e. Runs in the background) Notification Query:

objSWbemServices.ExecNotificationQueryAsync objWMISink, strWQL

If and when a matching process is instantiated, this generates an event known as “OnObjectReady” and this, along with the prefix I specified earlier, causes the sink object to call the subroutine SINK_OnObjectReady.

Note the syntax for getting at the properties of the new Win32_Process from inside that subroutine:

intPID = objNextObject.TargetInstance.ProcessID
intPID = objNextObject.TargetInstance.ProcessID
strPath = objNextObject.TargetInstance.ExecutablePath

After a short delay (in case there are circumstances where this process should legitimately appear and then soon disappear during uninstall), the process is killed by calling its Terminate method:

objNextObject.TargetInstance.Terminate

You’ll see in the code I’ve added in an extra check first to see if the process with the same ProcessID still exists and whether it’s pointing at the same executable before I kill it.  This is in case the process had closed and then by chance a new process had been created with the same ID.  I suspect that even if this were the case, that the call to Terminate would just throw an error as the original Process object would be gone and it wouldn’t try and touch the new one, but since I can’t really test this, I’m just being careful!

One last thing to note is that the WMI object used has to have Debug privileges to be able to kill processes launched under a different user context:

Set objSWbemServices = GetObject("winmgmts:{impersonationLevel=impersonate,(Debug)}!\\.\root\cimv2")

Automated Java Uninstall

Tags

,

I’ve recently had to face the thorny issue of upgrading Java in our environment and wanting to be able to do this remotely and silently.  The main problem was working out how to remove the existing version(s) first.

There are MANY scripts online that offer to do this, ranging from huge BAT files to short PowerShell scripts.  There was one particular solution I looked at that was a mammoth batch file which looked really promising and incredibly thorough.  I went through it line by line and then I came across lines like the following that do the uninstall:

wmic.exe product where filter clause call uninstall /nointeractive

I would assume that “product” is the alias for Win32_Product and I’ve read many articles (e.g. This one) about how you should not query that class as it triggers a repair of all your MSIs!  I’ve seen that happen when I tried to use that class in the past and sometimes it was not pleasant and broke things.  I decided to roll my own script instead.

Our environment is such that I can’t use PowerShell [on enough of our kit] and so I’ve gone for VBScript.  It’s not designed to be able to remove all possible versions, but removes the ones we have scattered around.  As long as it can be uninstalled by MsiExec and is labelled under Programs & Features with a name that matches “*Java*Update*”, then this ought to remove it.  Use entirely at your own risk!  I hope you find it helpful.

rem Remove all versions of Java x86 and x64

Const HKEY_LOCAL_MACHINE = &H80000002
Const WINDOW_HIDDEN = 0
Const WAIT_ON_RETURN = True

Set objWshShell = WScript.CreateObject("WScript.Shell")
Set objStdReg = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv")

For i = 1 To 2
	If i = 1 Then
		strKeyPath = "Software\Microsoft\Windows\CurrentVersion\Uninstall"
	Else
		strKeyPath = "Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
	End If

	objStdReg.EnumKey HKEY_LOCAL_MACHINE, strKeyPath, arrSubKeys
	If Not IsNull(arrSubKeys) Then
		For Each strSubKey In arrSubKeys
			Rem Ensure is a GUID key
			If Left(strSubKey, 1) = "{" Then
				strSubKeyPath = strKeyPath & "\" & strSubKey
				objStdReg.GetStringValue HKEY_LOCAL_MACHINE, strSubKeyPath, "DisplayName", strDisplayName
				If Not IsNull(strDisplayName) Then
					intJavaIndex = InStr(LCase(strDisplayName), "java")
					If intJavaIndex > 0 Then
						intUpdateIndex = InStr(LCase(strDisplayName), "update")
						rem Effectively make the check to be for "*java*update*"
						If intUpdateIndex > intJavaIndex Then
							strCmd = "MsiExec.exe /X " & strSubKey & " /quiet /norestart"
							intRC = objWshShell.Run(strCmd, WINDOW_HIDDEN, WAIT_ON_RETURN)
						End If
					End If
				End If
			End If
		Next
	End If
Next

WScript.Quit

Conexant Keylogger

Tags

,

You may have heard that HP have been found to have some laptops that were shipping with what is in effect a keylogger!  The affected models have a Conexant audio chip whose driver includes hotkey functionality for microphone muting.  Unfortunately this was left in debugging mode and as a result logged all keypresses to a file locally!  HP’s official security bulletin is here.

Some of our laptops were affected and our antivirus started detecting it as “Conexant MicTray Keylogger”.  Just the thing to scare our users with after the recent news over the WannaCry v2 ransomware…

Rather than push a 200MB driver update to them all, I shut them up remotely with the following little batch file I pushed out over SCCM.

@echo off
taskkill.exe /im:MicTray.exe /f >nul 2>&1
taskkill.exe /im:MicTray64.exe /f >nul 2>&1
del /F c:\Windows\System32\MicTray.exe >nul 2>&1
del /F c:\Windows\System32\MicTray64.exe >nul 2>&1
del /F "c:\Program Files\Conexant\Install\Audio\MicTray\MicTray\MicTray.exe" >nul 2>&1
del /F "c:\Program Files\Conexant\Install\Audio\MicTray\MicTray\MicTray64.exe" >nul 2>&1
del /F c:\Users\Public\MicTray.log >nul 2>&1
exit

In retrospect, I’m glad that’s the solution I took, as the first update HP released to fix the issue apparently didn’t even remove the functionality, it just turned it off – but it could then be re-enabled with a registry value change!  Since our users don’t use the mics on their laptops, I’m leaving the thing deleted as above.

Interesting PowerShell Remoting Issue

Tags

,

I saw an odd error message today whilst testing PSRemoting on a couple of PCs, a process which involved my disabling and re-enabling it.  It brought up an interesting problem I thought worth sharing.

I have a Group Policy Object with a Computer Startup script that looks for missing PowerShell Remoting Endpoints (i.e. PSSession Configurations such as “Microsoft.PowerShell”) and re-runs Enable-PSRemoting if required to fix them.  If you look at my earlier post, you’ll see why I ended up with such a config.  I thought this would ensure remoting would always work for PCs in this particular Organisational Unit.

Here’s the error I got trying to remote to one PC that had had Remoting expressly disabled but had then been put back in the OU that should have re-enabled it again but clearly hadn’t done so successfully:

1-EnterPsSession

Testing WSMan connectivity showed that side of things was working:

2-TestWSMan

Both expected Session Configurations were also present but I decided to investigate them closer with the following command.

Get-PSSessionConfiguration | Format-List -Property *

Going down each property in turn on the two PCs I spotted a difference in the rather unfriendly SecurityDescriptorSddl property.  Fortunately this is interpreted into something more meaningful in the Permission property which of course was the last one of over 30 in the list!  Picking that one out, here’s how it looked on a working PC:

3-Permissions-Working

And here’s how it looked on the faulty PC:

4-Permissions-Failing

This Denied Network access entry could also be seen using the GUI equivalent:

5-Permissions-UI

I thought it odd that there was a Deny entry in there but I fixed it with an Enable-PSRemoting again (which would actually would have been the first fix I’d have tried, except I wanted to try and work out exactly why it was broken).

The explanation of course is that I hadn’t looked into the details of exactly what Disable-PSRemoting might do.  From the documentation comes the phrase:

Disable-PSRemoting blocks remote access to all session configurations on the local computer. This prevents remote users from creating temporary or persistent sessions to the local computer. Disable-PSRemoting does not prevent users of the local computer from creating sessions (“PSSessions”) on the local computer or remote computers.

If you look at the Examples in that cmdlet’s help, you will see how the Network Deny we’ve seen gets put in.  It’s more of a Deny-PSRemoting than a Disable-PSRemoting!

Looks as though I need to alter my Startup script to make a check for these denies as well as just a check to see if the endpoints exist, as a Disable-PSRemoting makes them still exist, just no longer work remotely…!

Windows 10 build 1703 RSAT Fail

Tags

,

I upgraded my Windows 10 Pro Build 1607 work PC to Build 1703 this week.  At the start of the install process, it warned me that it was going to remove a display language and I’d have to reinstall it afterwards.  I’m using en-GB.

Once the upgrade was done, I found that RSAT was no longer installed and its pinned shortcuts on Start were blank with odd text across them.  I reinstalled RSAT (incidentally I’ve read that there will not be a Build 1703 of RSAT and that you just use Build 1607).  It reinstalled suspiciously quickly and the problem remained; including after reboot.

I remember similar issues with previous builds involving having to get the en-US display language installed again as a fix.  Unfortunately I could not persuade it to do so – the relevant part of the GUI kept saying that I needed to connect to the Internet – despite Windows Update working fine!  I think our web filtering proxy software was probably blocking its access in some way.

I eventually had to give up and leave it for another day and so rolled back to Build 1607 (which was quite a quick and painless process).

Later, back at home, I installed the en-US Display Language into my home PC and used Process Monitor to see exactly what got downloaded and installed.  The file was:

C:\Windows\SoftwareDistribution\Download\4b5f7f550123f7e8a15edef6d60b110f\lp.cab

I took that CAB file to work today and re-upgraded my PC to Build 1703.  I then ran LPKSETUP.exe which you use to install Display Languages:

LPKSetup1

After browsing to the CAB file it happily reinstalled the en-US pack, though this was quite a slow process:

LPKSetup2

Once done, the problem with my shortcuts remained, so I reinstalled RSAT and this time all my pinned shortcuts came back to life (without a further reboot).

I did try and reproduce all this again in a VM at home, hoping to get some more screenshots and to sniff out the URL too but the problem did not occur.  I’m guessing it must be something to do with differences in the locale of the ISO used between work and home.

I hope the above helps someone else!

Aside

Why Learn PowerShell?

In case you’re wondering why PowerShell is worth learning, here for example are problems I quickly solved at work just today using only basic PowerShell:

  1. List all enabled Active Directory user accounts with no email address configured.
  2. Given a spreadsheet of 600+ accounts with valid email addresses now listed beside them, update AD user account properties accordingly.
  3. Given a list of users who have left the organisation,  disable their AD accounts and move them to a specific OU (for deletion in the future).
  4. Search an Organisational Unit full of disabled user accounts for any that were still in a particular group.

These tasks were all trivial in PowerShell!  What are you waiting for?  Get learning!

PayPal’s Emails Encourage Dangerous Habits

Tags

, ,

I’ve recently got fed up going round and round in circles with PayPal trying to get them to admit that their own emails are not actually phishing scams!

Yes, you read that right.  The problem is that PayPal’s own email campaigns encourage users to click on links to domains that look to the suspicious eye like a phishing scam.  PayPal’s own spoof detection service identifies these emails as “likely fraudulent” and if you contact PayPal directly, they’ll repeatedly deny all knowledge of the domains in question being their own.

Let’s have a look into this sorry story…

Firstly, here’s the start of a typical example email, sent to me on March 3rd from “PayPal@mail.paypal.co.uk”:

paypal-01-email

Unlike normal phishing emails, this email addresses me by my full name and is literate.  The problem comes if you assess the target domain of the “Log In Now” button.  Here’s the tooltip:

paypal-02-tooltip

Destination address “epl.paypal-communication.com” looks suspiciously like a typical phishing domain.  Any security-aware user ought not to click on such a link.  I don’t particularly want to be visiting a site that for all I know might be serving up ransomware via an exploit kit!

I had a look online and found discussion at https://www.paypal-community.com/  which included references to this target domain with users asking after it because they were suspicious.  Here’s what one user said:

paypal-03-chat1

And another:

paypal-04-chat2

And a third:

paypal-05-chat3

And the response from the PayPal moderator? (Details hidden to save the blushes.)

paypal-06-chat4mod

I decided to dig around a bit.  A WHOIS on the domain said it is registered to PayPal (via a company called MarkMonitor who protect brands):

paypal-07-whois

Then I looked at the SSL certificate of the domain:

paypal-08-ssl

That is an Extended Validation SSL certificate issued by DigiCert to PayPal.

At this point I was sure it had to be legitimate and so contacted PayPal support and told them the story so far.  In my message I included the following:

On the assumption that this is indeed genuine, can I suggest that perhaps you ensure that all emails you send with links in, go only to paypal.com or paypal.co.uk?! Otherwise, you’re making it very difficult for users to tell what is legitimate and what is not.

For my trouble I got a standard automated reply with general educational info on phishing emails and the comment, “If we haven’t answered your question, please reply to this email and our team will answer you as soon as possible”.

If they’d bothered to read my email properly they’d have known I had gone beyond that stage.  This sort of automated response irrespective of what you’ve said – especially since you have to reply to it to even get a human response – is the ideal way to frustrate your customers!

I also forwarded the email to their spoof detection service (in my case spoof@paypal.co.uk).  Here’s the reply I got:

paypal-09-spoof

Unbelievable!  And how indecisive is “likely fraudulent” anyway?!  I tested the actual link in the email by running Chrome inside Sandboxie for added safety.  It redirected to paypal.com which suggests all is well.  Replying to the automated support email, I gave them the newer information and the verdict of their spoof service and asked them to look into it.  I got the following response.  I’ve just shown the start as you’ll get the idea…

paypal-10-reply1

Feeling increasingly exasperated, I emailed back and said that either the domain was legitimately theirs, or DigiCert had issued an EV SSL certificate in their name to a third party, “which would be a major security issue and absolutely catastrophic for their business too!”.  I encouraged them to escalate it.

The reply asked for me to forward them the email:

paypal-11-reply2

I tried to cut a corner as I’d deleted the email by then:

Please can youi simply clarify whether a link to https://epl.paypal-communication.com is a valid destination address to have in an email from PayPal.  There is every sign that it is (the domain appears to be registered to PayPal!) …

The reponse was, shall we say, “frustrating”:

paypal-13-reply4

I emailed straight back:

I have not said I received an email saying there is suspicious activity in my account.  You too have now said that the email is not from PayPal.  In that case, please can you explain why the link it asks me to log in to is at a domain formally registered to PayPal and with a PayPal SSL certificate on it?

Needless to say, every single message was from a different person – no attempt to take ownership of a problem and run with it.

I eventually got a phonecall and was passed from person to person three times.  Everyone sounded quite interested in and intrigued by the story and the technical details.  I’m sure one of them said they were basically told to deny any domain that did not end paypal.com or paypal.co.uk but he was clearly struggling to deny the domain I was telling him about!  I was told I would hear back.  I left the phonecall feeling happier that this would be escalated to someone in the know.  A few days later I prodded them for an update and told them I’d had another similar email.  I finally got a new reply in my PayPal message centre.  It took things to a whole new level of ridiculousness:

paypal-15-reply6

That last sentence shows how much I’ve been wasting my time.  How can they possibly say a subdomain of paypal.co.uk is not theirs?  I first decided to prove that that domain could receive email:

paypal-16-dns

As we will see in a minute, the result was quite instructive.  If you also do a SmartWHOIS to find who is responsible for the IP block that the epl.paypal-communication.com domain is on, you get the following:

paypal-17-smartwhois

“Epsilon Data Mangement” owns the IP block and judging by the Mail Exchanger record name, runs the mail server and presumably is the explanation for the “epl.” at the start of the main domain name that set this hunt all off.  So, who are Epsilon Data Management?  Here’s part of what their website says they do:

paypal-18-epsilon

This all sounds very like the sort of emails that contain these links!

I’d sent one more email to PayPal which included this rebuttal to their latest claim:

I’ve confirmed that there is a DNS MX Record for domain “mail.paypal.co.uk” which shows it is a legitimate domain that can receive email. Also, since it is a child domain of paypal.co.uk, it MUST by definition belong to the same owners as “paypal.co.uk”!  So how can you say it does not belong to PayPal?

 I got one more message from PayPal before I gave up in disgust:

paypal-20-reply8

After some more hunting around the PayPal site, I found one more thing of interest – on PayPal’s “List of Third Parties (other than PayPal Customers) with Whom Personal Information May be Shared” page:

paypal-21-thirdparties

Quote: “To execute outbound communciation campaigns including but not limited to email and push notifications.”

The story doesn’t end here.  I tried taking it to Twitter and sending Direct Messages to @AskPayPal (PayPal Support).  I gave a very brief version of the case and at their request sent a screenshot of one of the emails – with the tooltip link visible.  I also sent a screenshot of the SSL certificate.  I got a much more positive response:

PayPal-22-Twitter1.png

I provided some more info, including about Epsilon.  I got another reply:

paypal-23-twitter2

And the next reponse, which unfortuantely was from someone else?

paypal-24-twitter3

I managed not to die of frustration when told to forward it to the spoof service again.  But then, there was final bit of acceptance:

paypal-25-twitter4

And that’s where it ends. …

And this is a company I’m entrusting with access to my money?  The left hand doesn’t seem to know what the right hand is doing – in fact, it just denies all knowledge of its existence despite all evidence to the contrary.  That coupled with the generally poor support experience leaves me … shall we say … “not overly-enamoured” of PayPal now.

The Twitter chat had closed with the following.

paypal-26-twitter5

 I couldn’t bring myself to click on it…


Update – June 2017

The last couple of emails I’ve received from PayPal have still contained the same domain in the Login links but at least their Spoof service is no longer reporting them as being likely fraudulent.  Their current educational information about spotting phishing attacks encourages you to see if they address you by name.  I’ve received plenty of phishing emails that know my full name and one piece of spam knew my full postal address too..!  Their educational info also lists various things their emails won’t ask you to do or type in.  They do also encourage you to login directly via their site but it would be far better if they included no login button in their mass emails at all!

Physical RAM full on File Server

Tags

Had an interesting situation today on an old FileServer that’s still on Server 2008 R2 and only has 4GB of RAM.  While BackupExec is doing a full backup, the server absolutely crawls and becomes sluggish for users.  I struggled to RDP to it to investigate – it kept timing out.

Here’s what I eventually saw in Task Manager:

metadata1-taskmgr-physicalram

As you can see from the bottom of the window, Physical Memory is 91% used but with the processes sorted by memory use, the greediest is merely the AntiVirus with not even a quarter of a GB consumed.

The Performance tab was not much more revealing:

metadata2-taskmgr-commit

Here you can see that the total Commited RAM was not even 1.5GB of the 8GB limit (physical RAM + paging file).  Still though, you can see the RAM is well and truly taken up by something.  Incidentally, network traffic was minimal – indeed the backup was struggling at a slow speed.

Next stop was Sysinternals’ Process Explorer’s System Information window:

metadata3-procexp-sysinfo

This reveals (at bottom left) that there is nearly 3GB of physical RAM used by the cache.

Finally, I loaded Sysinternals’ RAMMap:

metadata4-rammap

This shows quite clearly that the RAM is used by an entry labelled “Metafile”.  This refers to NTFS Metadata such as the MFT (Master File Table) amongst other things.  Given that a 1TB data volume was being backed up, I guess it’s not surprising that so much NTFS Metadata is being accessed.

I found online that you can verify the size of the MFT using fsutil.exe:

metadata5-fsutil

Note the line “Mft Valid Data Length”.  You can convert that to decimal by entering into Windows Calculator.  I couldn’t bring myself to screenshot the awful Mickey Mouse App version on Windows 10, so here it is on the server:

metadata6-calc1-hex

After entering Programmer mode and selecting the Hex radiobutton, you type in the value and then click Dec to convert it to Decimal.

metadata7-calc2-dec

That gives a value which when converted from bytes equates to about 2.3GB for the MFT alone.

Obviously, we have to feed this server more RAM and see how it gets on…!