Base Conversions and Creating GUI Apps in PowerShell

Published: 2020-05-14
Last Updated: 2020-05-14 17:38:05 UTC
by Rob VandenBrink (Version: 1)
0 comment(s)

I don't know about you, but I find myself doing conversions from decimal to hex and binary several times per day.  For me, working out binary equivalents of decimal numbers is something I do all the time to verify subnet masks, network and broadcast addresses - also in answering "is this IP in the same subnet or in an adjacent network?"  Conversions of the same type crop up all the time in decoding constructs in packets.  Wireshark and Burp will both often anticipate what you want to do on this score, but not always.

Anyway, this all started with a twitter conversation with Lee Holmes - he said that he hasn't used Windows Calc since Powershell got "grown up" math, I said that I used calc all the time for binary <-> decimal all the time, especially if I'm on a client server (and don't have my trusty HP 35s or 16c calculator or emulator handy).  Of course, immediately after that conversation I started coding :-)

First of all ,there are more than a few ways to do base conversion in Powershell.  I'll start with the obligatory shout out to the Windows PowerShell Cookbook (I'll never get tired of O'Reilly books) - oddly enough Lee is the author of that book!
https://www.amazon.com/gp/product/B00ARN9MEK/ref=dbs_a_def_rwt_hsch_vapi_tkin_p1_i0
specifically this set of "recipes" at http://powershellcookbook.com/recipe/VoMp/convert-numbers-between-bases

The main thing to remember though is that a number is a number, and how you print it is up to you.  If you actually want to *store* a number in a different base, you need to convert it to a string value and store the string.

So to convert a number to a different base:

$result = [Convert]::ToString($Number,$BaseToConvertTo)

If you are starting with a string value in decimal, you'll want to convert it to an integer first:

$result = [Convert]::ToString([int]$NumberAsAString,$BaseToConvertTo)

Or if you are starting from some other base, you'll want to convert back.  A handy shortcut, PowerShell understands that "0x4E" is a hex 4E - we'll use that to convert from Hex number in a string to Decimal:

[Convert]::ToString("0x"+$hexnum, 10)

or, an even simpler approach (thanks Lee!):

$decnum = [int]("0x"+$hexnum)

or Binary to Decimal:

$decnum = [convert]::toint32($binnum,2)


Note that I converted to int32 in this case, since printing a number by default will be in decimal.

Binary to hex:
Convert to $decnum above, then convert dec to hex:

$hexnum = [convert]::tostring($decnum,16)

So fun all around, but these don't tend to roll off your fingers like using a calculator does (especially if that calculator is RPN).  Anyway, this got me to thinking about writing an actual app in Powershell, and looking at GUI support in the native language.   Yes, PowerShell does Windows!

Some snips below illustrate various windowing features.  First, a screenshot of the app to refer to:

The input box is where we input the starting value:

############################################## text box - INPUT

$TextInputBox = New-Object System.Windows.Forms.TextBox

$TextInputBox.Location = New-Object System.Drawing.Size(20,50)

$TextInputBox.Size = New-Object System.Drawing.Size(300,150)

$TextInputBox.Height = 150

$TextInputBox.font = New-Object System.Drawing.Font("Lucida Console",32,[System.Drawing.FontStyle]::Regular)

$Form.Controls.Add($TextInputBox)

Radio buttons are easy to code up too - I use these to select the source base of the number we just typed in.  Note that we're setting the size of the box that the buttons live in as a "group box".  Sizes are all defined, and the fonts and font size are as well.  This code all works as-is on a 4k screen, I haven't tried it at other resolutions (please let me know if it works without tinkering on different res screens?):

############################################## group boxes

$groupBox = New-Object System.Windows.Forms.GroupBox

$groupBox.Location = New-Object System.Drawing.Size(350,20)

$groupBox.size = New-Object System.Drawing.Size(500,400)

$groupBox.text = "Source Base"

$groupbox.font = New-Object System.Drawing.Font("Lucida Console",16,[System.Drawing.FontStyle]::Regular)

$Form.Controls.Add($groupBox)

##############################################

############################################## radio buttons

$RadioButton1 = New-Object System.Windows.Forms.RadioButton

$RadioButton1.Location = new-object System.Drawing.Point(15,50)

$RadioButton1.size = New-Object System.Drawing.Size(800,70)

$RadioButton1.Checked = $true

$RadioButton1.Text = "Decimal (0d)"

$groupBox.Controls.Add($RadioButton1)

 

$RadioButton2 = New-Object System.Windows.Forms.RadioButton

$RadioButton2.Location = new-object System.Drawing.Point(15,130)

$RadioButton2.size = New-Object System.Drawing.Size(800,70)

$RadioButton2.Text = "Hexadecimal (0x)"

$groupBox.Controls.Add($RadioButton2)


The "GO" button takes the values entered and sends it off to be converted in every-which format in a function:

############################################## GO button

$Button = New-Object System.Windows.Forms.Button

$Button.Location = New-Object System.Drawing.Size(100,150)

$Button.Size = New-Object System.Drawing.Size(220,70)

$Button.Font = New-Object System.Drawing.Font("Lucida Console",16,[System.Drawing.FontStyle]::Regular)

$Button.Text = "CONVERT"

$Button.Add_Click({SrcBase $TextInputBox.Text})

$Form.Controls.Add($Button)


Finally, outputting the number to an output box is easy too.  First create the output box:

##############################################  text fields - OUTPUT

$outputBox = New-Object System.Windows.Forms.TextBox

$outputBox.Location = New-Object System.Drawing.Size(100,475)

$outputBox.Size = New-Object System.Drawing.Size(1000,300)

$outputBox.MultiLine = $True

$outputBox.Font = New-Object System.Drawing.Font("Lucida Console",32,[System.Drawing.FontStyle]::Regular)

$Form.Controls.Add($outputBox)

Then calculate what goes into it (the "GO" function), then output the result:

$NL = "`r`n"

$TAB="`t"

$result = $NL+"BIN (0b)"+$TAB + $binnum +$NL+"HEX (0x)"+$TAB + $hexnum+$NL+ "DEC (0d)"+$TAB+ $decnum

$outputBox.AppendText($result)


Just for fun, I added ASCII conversions too:
decimal to ascii:  [char][int]$decnum

ascii to decimal can be more fun - first convert it to a list of numbers:
$list = [int[]][char[]]$asciistring

Then in a loop convert each list number to hex or binary string representation:
       $d = $list[$i]
       $h = [convert]::tostring($d,16)
       $b = [convert]::tostring($d,2)

The ASCII conversion will convert a string-to-values (yes you can use longer strings, but you'll need to scroll to see the results), but values-to-strings is a single unicode character proposition (so the input values are 0-65535 or 0x0000 -0xFFFF)

As in most GUI apps, this is more or less 20 lines of code and 150-ish lines of formatting, I/O, and yes, input validation - I do check if the value input is valid for the source base.

What I haven't tackled correctly yet is screen resolution.  At the moment this little app all hard-coded for a 4k screen, so it's not going to render all that well on other resolutions, especially with lower pixel counts.  The better approach would be to set all of the size and position numbers to variables, and get the screen resolution during startup.

For a single screen, that's easy - WMI is your go-to:

(Get-WmiObject -Class Win32_VideoController) | select CurrentHorizontalResolution,CurrentVerticalResolution

CurrentHorizontalResolution CurrentVerticalResolution

--------------------------- -------------------------

                       3840                      2160

This is a bit more involved for a multiple screen system:

Add-Type -AssemblyName System.Windows.Forms

[System.Windows.Forms.Screen]::AllScreens.workingarea | select width,height

Width Height

----- ------

 3840   2080

 3840   2080

 3840   2080

With this information in hand, the plan is to change each size / position number to a list of values, so that you can then set a "$res" variable to then use as an index to each list to get the right value for the current screen.

As with everything I post, the source for this is in my github, at https://github.com/robvandenbrink

Got a neat idea that a GUI app in Powershell would be just the ticket for?  Or better yet, a link to your github for one that you've written?  Please, share using our comment form!  If it's an idea that appeals, it might become a future post!

Want to dig deeper into PowerShell with a security focus?  Check out SANS SEC505 - you can take it online at the SANSFIRE conference, which is virtual this year ( https://www.sans.org/event/sansfire-2020/course/securing-windows-with-powershell ). If you've taken SEC505 before, re-read the current description, it looks like there's a ton of new content!

===============
Rob VandenBrink
www.coherentsecurity.com

Keywords:
0 comment(s)

Patch Tuesday Revisited - CVE-2020-1048 isn't as "Medium" as MS Would Have You Believe

Published: 2020-05-14
Last Updated: 2020-05-14 14:36:19 UTC
by Rob VandenBrink (Version: 1)
0 comment(s)

Looking at our patch Tuesday list, I looked a bit closer at CE-2020-1048 (Print Spooler Privilege Escalation) and Microsoft's ratings for that one.  Microsoft rated this as:

Disclosed: NO
Exploited: NO
Exploitability (old and new versions)

Unfortunately, this vulnerabiltiy was actually disclosed to Microsoft by the research community (see below), so the code to exploit it absolutely does exist and was disclosed, and a full write-up was posted as soon as the patch came out:
https://windows-internals.com/printdemon-cve-2020-1048/

Long story short, on an unpatched system, you can plant a persistent backdoor on a target host with this one-liner in PowerShell:

Add-PrinterPort -Name c:\windows\system32\ualapi.dll
Then "print" an MZ file (DOS excecutable) to that printer to light it up.

As noted, this backdoor is persistent, and will remain in place even after you apply the patch!

Moral of the story?  For me, there are a couple of them:

  • Don't put too much stock in risk ratings assigned to patches.  "Lows" and "Mediums" can bite you just as badly as vulnerabilities rated as "High".  This goes for patches as well as scan results or pentest results.  If your policy is to patch only Severe and High rated issues, you'll pay for that eventually.
  • Also, it's a good thing that more vendors are going to monolithic patching.  If you apply the current patch set from Microsoft, you get them all - there's no more "cherry picking" allowed!

Anymore, if you see resistence to resolving any security issues in your organization (even lows and mediums), my take would be to tackle this in your Corporate Policies.  To help to ensure that any security issues are resolved - whether via patching or correcting a config issue, have your policy call for a formal sign-off for the decision to NOT fix each of those issues.  You'll find that management will be reluctant to put in writing "we're choosing to not fix this problem".

Kudos to @peleghd (Peleg Hadar) and Tomer Bar of @safebreach for the initial research and disclosure to Microsoft (acknowledgements here: https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-1048 )
Also Yarden Shafir and Alex Ionescu of Winsider for related research and the detailed post referenced in this article.

===============
Rob VandenBrink
www.coherentsecurity.com

0 comment(s)
ISC Stormcast For Thursday, May 14th 2020 https://isc.sans.edu/podcastdetail.html?id=6996

Comments


Diary Archives