Sunday, May 25, 2008

So in thinking about what I have learned doing the work below...Please see my next post...To make matters worse, the pipe command does not appear in this blog.

Pinging IP subnet ranges in Powershell. This will be more difficult than...(you know the rest)..I am attempting to duplicate the functionality of my previous post.

PS D:\> $var = '192.168.0.1','192.168.0.2'

PS D:\> $var

192.168.0.1
192.168.0.2

PS D:\> $ping = new-object System.Net.NetworkInformation.Ping

PS D:\> $var foreach-object -process {$ping.Send($_)} ft -auto


Status Address RoundtripTime Options Buffer
------ ------- ------------- ------- ------
Success 192.168.0.1 1 System.Net.NetworkInformation.PingOptions {97, 98, 99, 100...}

TimedOut 0 {}

Closer yet...

PS D:\> $ping = new-object System.Net.NetworkInformation.Ping
PS D:\> $3OCT='71.0.0.'
PS D:\> 1..254 [pipe command here] foreach-object -process { if($ping.Send("$3OCT$_").status -eq "Success") {"$3OCT$_"} }


71.0.0.1
71.0.0.3
71.0.0.7
71.0.0.8
71.0.0.9
71.0.0.11


Putting this together a little bit more...

PS D:\> $3OCT = '190.10.10.'
PS D:\> function Ping-Host { begin{ $ping = new-object System.Net.NetworkInformation.Ping; } process{ if($ping.Send("$3OCT$_").status -eq "Success") {"$3OCT$_";} } }

PS D:\> 1..254 [pipe command here] Ping-Host
190.10.10.1
190.10.10.10
190.10.10.17

Looking Much Better this morning:

PS D:\> function Ping-Host { begin{ $ping = new-object System.Net.NetworkInformation.Ping; } process{ if($ping.Send("$3OCT$_","8").status -eq "Success") {"$3OCT$_"+","+($ping.Send("$3OCT$_","8").roundtriptime)+","+(date-time);} } }
PS D:\> 1..20 Ping-Host


71.0.0.1,80,05/26/2008 07:09:31
71.0.0.3,107,05/26/2008 07:09:32
71.0.0.7,97,05/26/2008 07:09:33
71.0.0.8,118,05/26/2008 07:09:33
71.0.0.11,104,05/26/2008 07:09:34

Below this 'works', but I had all kinds of issues with it and suspect that
(a) I don't understand argument and text passing in Powershell very well
(b) such skill are more idiosyncratic than they appear.

There were all kinds of issues here....lots of idiosyncratic behaviour to think about in Powershell. Actually, a whole host of Powershell topological and semantic rules exist that are not well described anywhere....


# CheckHostClassC.ps1 5:55 PM 5/26/2008 Down, dirty attempt to ping subnet. Takes two args: first three octets and wait time. Prints out IP address date, roundtriptime. No error checking.

function date-time {get-date -displayhint datetime}

function CheckHostClassC {begin {$ping = new-object System.Net.NetworkInformation.Ping; } process { if($ping.Send("$3OCT$_","$WaitTime").status -eq "Success") {"$3OCT$_"+","+($ping.Send("$3OCT$_","$WaitTime").roundtriptime)+","+(date-time);} }}

sv 3OCT $Args[0]
sv WaitTime $Args[1]

1..254 [pipe command here] CheckHostClassC

PS D:\> .\CheckHostClassC.ps1 193.172.1. 100

193.172.1.1,211,05/26/2008 18:24:37

193.172.1.3,212,05/26/2008 18:24:38

193.172.1.5,215,05/26/2008 18:24:39


Saturday, May 24, 2008

Okay, so let's try to start rewriting some CMD.EXE skillsets in Powershell. Here's something common: ping a range of subnets to see if the hosts are up and what their latency is. In CMD exe we first need some to code to produce an accurate timestamp because there is no native way to do this. Thus this complicated and idiosyncratic use of the set command to parse out time/date stamps:

:: realtd.cmd
@echo off

set realdate=%date:/=.%
set realdate=%realdate:* =%
set realtime=%time::=.%
set timestamp=%realdate%_%realtime%

Now we need some nearly unreadable spew, some help fron gawk, some hard coded ping options, a hard coded subnet range...:

:: TestSubnet.cmd
@echo off
set ThreeOctets=%1
for /l %%i in (1,1,255) do set #=%%i && call :label
goto EOF
:label @(call realtd)
@(ping -l 1 -n 1 -w 2 %ThreeOctets%.%#% | findstr Reply | gawk '{print "%timestamp%" ":" $1 ":" $3$5}' )

:EOF


and last we can put a collection of the first three octects into text file and call them like this:

for /f %i in (subnets) do call Testsubnet %i

This gives us some reasonably parseable output:

D:\>call Testsubnet 193.0.0
....
05.24.2008_19.43.04.01:Reply:193.0.0.232:time=173ms 05.24.2008_19.43.05.51:Reply:193.0.0.236:time=169ms 05.24.2008_19.43.06.01:Reply:193.0.0.238:time=171ms 05.24.2008_19.43.07.01:Reply:193.0.0.241:time=171ms

D:\>call Testsubnet 194.0.0 05.24.2008_19.43.40.01:Reply:194.0.0.53:time=100ms

Okay, so you can see quite a bit of inelegance here to start with. Let's list some issues:

(1) a separate cmd file needs to run each time to log the timestamp
(2) the ping options are hardcoded...that probably could be fixed...but more inelegance
(3) we don't really need the field 'Reply' or 'time='. but they are hard to parse out. Once again more awk or perl code would probably do this but at what cost of complexity
(4) I don't really want to have to call the file that calls THE file...I just want to point to an XML file with all the correct options....
(5) requires Cygwin or GNU-Win32 gawk in your path....

I could go on, but you get the picture. Let's assemble this tool with less complexity, more readability and more functionality in Powershell in the next post...

Sunday, May 18, 2008

The world of Windows traditional cmd line is full of cumbersome crap. Just extracting the (NBT bound) IP Address takes two lines of idiosyncratic backquotes, escaped pipes, two temp files, Finally a call to snort with BPF options:

@echo off

:: find the NBT tied IP Address
for /f "usebackq delims=:" %%i in (`ping -n 1 -l 8 %computername% ^| findstr Reply`) do @echo %%i > IPReplyString.txt

for /f "tokens=1-3" %%i in (IPReplyString.txt) do echo %%k > IP.txt

:: set the IP address to %localIP%
for /f %%i in (IP.txt) do set localIP=%%i

:: start Snort with BPF filters...
snort -l D:\SnortLogs -vdeX dst host %localIP% and !(port 53 or 80 or 110)

....

Wednesday, May 14, 2008

I will confess to being nearly a complete loser when it comes to successfully implementing sed, awk and regex. to search logs. I usually end up parsing my Authlogs with something really clueless like:

(IP Address and Port of invalid users with failed passwords)

$ grep "Failed password for invalid user" Sampleauthlog.txt | cut -b 75-110| uniq
from 202.163.221.227 port 43985 ssh
from 202.163.221.227 port 44553 ssh2
...

or (the IP Address of valid users with failed passwords )

$ grep Failed Sampleauthlog | grep -v invalid | awk '{print $11}'| uniq -c
5 202.163.221.227

I have some idea that I can break down each time, user, IP address, port, ssh type into a typical Powershell objects and do more informative and complex queries, but this needed some work:

$var=Select-string Failed SampleAuthlog.txt | Where-object {$_ -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"}

PS D:\Microsoft\Powershell> $var
SampleAuthlog.txt:3:Apr 26 01:20:29 rmfbsd sshd[30534]: Failed password for invalid user test5 from 202.163.221.227 port 43985 ssh2
SampleAuthlog.txt:5:Apr 26 01:20:32 rmfbsd sshd[11478]: Failed password for root from 202.163.221.227 port 44267 ssh2
....

Select-object $var
Select-Object : Cannot convert System.Management.Automation.PSObject to one of the following types {System.String, System.Management.Automation.ScriptBlock}.
At line:1 char:14.

One way around this is to massage a log file into a CSV format which AWK does easily, then use Powershell import-csv routine and manually add headers to the first line:


$ grep Failed authlog | grep -v invalid | awk '{print $1","$2","$3","$9","$11","$13,$15}'
Apr,26,01:20:32,root,202.163.221.227,44267
Apr,26,01:20:36,root,202.163.221.227,44411
...

$ grep Failed authlog | grep -v invalid | awk '{print $1","$2","$3","$9","$11","$13,$15}' >> /cygdrive/D/Microsoft/Powershell/Powershell.out


$PWSH = import-csv Powershell.csv
$PWSH | ft -auto
PS D:\Microsoft\Powershell> $PWSH | ft -auto

Month Day Time User IP Port
----- --- ---- ---- -- ----
Apr 26 01:20:32 root 202.163.221.227 44267
Apr 26 01:20:36 root 202.163.221.227 44411
Apr 26 01:20:47 root 202.163.221.227 44725
Apr 26 01:21:02 root 202.163.221.227 45354
...

Now we have part of an OPENBSD Authlog stored as a Powershell object. Thanks AWK!

Friday, May 9, 2008

Sequential file and Directory Creation

Sequential file and Directory Creation. Useful for Test Engineers.

creates directories

1..100 | %{ni ( "NewDirectory-{0:0}" -f $_ ) -type directory }

creates files with sequential content

1..100 | %{ni ( "NewFile-{0:0}" -f $_ ) -type "file" -value "Number $_ of 100 files."}
Use these two functions to query the supported assemblies [GAC] and .NET Collections (from Windows Powershell in Action, Bruce Payette)

function Get-Assemblies {[AppDomain]::CurrentDomain.GetAssemblies()}

function Get-Types ($Pattern=".") { Get-Assemblies | %{ $_.GetExportedTypes() } | where {$_ -match $Pattern} }

Get-Types System
Get-Types System.Collections
Get-Types System.Collections | more
Get-Types System.Collections.Specialized | more
Get-Types System.Collections.Specialized.StringDictionary
Get-Types System.Collections.Specialized.StringDictionary | gm
Get-Types System.Collections.Specialized.StringDictionary | gm | more
The "Get-WmiObject" query below retrieves information from all network adapters. Piping to a Select-Object query produced a table sorted by Adapter Index. The Win32_NetworkAdapterConfiguration provides lots of configuration data so additional Network Adapter Query functions could be derived from it.

$NetworkInfo =gwmi -query "SELECT * FROM Win32_NetworkAdapterConfiguration"

function NetworkInfoSort {$NetworkInfo | Select-Object IPAddress,Description,Index,DefaultIPGateway | sort-object Index}

PS C:\> NetworkInfoSort | ft -auto

Also useful:

gwmi -class win32_NetworkAdapterConfiguration | %{ $_.IPAddress }