My Network Scanner aka Hacking 101 in VB.NET

Scanner-library1-in-windows8.gif

Scanner-library-in-windows8.gif
 
Now that we have an address and subnet, we know exactly what we can do as far as pinging. The next step is to actually start the ping.

We can define a ping as follows:

Dim png As New Net.NetworkInformation.Ping

The Ping.Send method has several overloaded methods but the one that we will use here is Ping.Send(IPAddress). All send methods return a PingReply structure which contains the address and round trip time. So we can send a ping and get a reply which can then be analyzed.

PingReply = png.Send(PingAddress) ' ping the IP and capture the responce

From the address we can then determine the node name like so:

        Dim IpToDomainName As IPHostEntry = Dns.GetHostEntry(IP)
        'return information about a particular address
      Return (IpToDomainName.HostName) ' the name of that node is in that info


Putting all that together we get the following code snippet.

        Static row As Long
        Dim pr As PingReply ' pinging an address returns a structure called ping reply
        Dim ComputerName As String = ""
        Timer1.Enabled = False ' since we are doing this periodically on a timer, just disable the timer while we are in here to prevent re-entry
        ' turn the timer back on when we leave. This ensures the fastest turn around
        If DataGridView1.ColumnCount < 3 Then ' initialize the colums of the grid view
            DataGridView1.Columns.Add("Column1", "IP")
            DataGridView1.Columns.Add("Column1", "Time")
            DataGridView1.Columns.Add("Column1", "Name")
        End If

        If txtIP.Text <> "" Then ' if there is an IP selected
            If PingAddress = "" Then ' if the ping address is empty
                PingAddress = txtIP.Text ' fill it from the text box otherwise just ping the address in the box (for inrementing the address
                If Not FindAddressBytes() Then ' convert the IP address into a four byte array
                    Exit Sub 'if that didn't work . . .  give up
                End If
            End If
        Else
            PingAddress = ""
        End If
        Try
            ToolStripStatusLabel2.Text = "initializing" ' inform the user
            RebuildPingAddress() ' this reconverts the address from four byte array back to a string (after we have automatically incremented it
            txtIP.Text = PingAddress ' show the user where we are
            ' we are now ready to send a ping to see if anyone is home
            'Dim png As New Net.NetworkInformation.Ping
            pr = png.Send(PingAddress) ' ping the IP and capture the responce
            ToolStripStatusLabel2.Text = "pinging " & PingAddress
            If pr.Status = IPStatus.Success Then ' if the responce was good
                DataGridView1.Rows.Add() ' we should add a new row to the grid view
                DataGridView1.Rows(row).Cells(0).Value = pr.Address ' and fill that row in with address
                DataGridView1.Rows(row).Cells(1).Value = pr.RoundtripTime.ToString & " ms" ' round trip time
                ' we should now show the name of the device / computer at that address
                ComputerName = DoGetHostEntry(pr.Address.ToString)
                DataGridView1.Rows(row).Cells(2).Value = ComputerName ' display that nodes name
                'b = pr.Buffer ' the buffer contains the returned data from the ping (most often just a series of bytes
                If Not active Then ' allow the user to cancel
                    ToolStripStatusLabel2.Text = "User Canceled"
                    Exit Sub

                End If

So we have 'pinged' our own address and found that we are there. It didn't take all that code to figure that out. What we would like to know is whether or not there are others on the same network. That's the same only a different address. If we knew all the addresses that were on the network, we would just make a list and ping them but we don't. Therefore we must ping all addresses that are within the range of our subnet by incrementing the address after each ping. If the ping is successful then we add that info to the list and keep going.

Of course 'if it is worth doing, it is worth overdoing . . . we might like to see what ports are open and thus vulnerable. This can be done in the straightforward / slow manner by trying to open every port from 0 to 65535. If it connects then that port is open. If an error occurs that port is not open. Opening a port that is available is quite quick. If all ports were open this would be fast and furious but any time the port is not open, it takes atleast a second to throw an error, So we are looking at more that 65000 seconds to check a normal node and there are usually more than one nodes.

I think I just fell asleep thinking about all that waiting . . . excuse me while I make some coffee.

If you are only checking a few of the more commonm nodes there is no need to get fancy so lets look at the easy way first.
To check to see if a port is open you can use the TCPClient.Connect method:

'instanciate a new instance of the TCPClient Class
' try to use the connect method to connect to the particular port on the particular address
' if the connection worked
' close the connection since we really don't need to do anything more
' mark the status as connected
' if an exception occured then  the port os not open
' clear the error for general principals
' mark it as not open
Dim TCP As TcpClient = New TcpClient()

Try

TCP.Connect(IPAddress, p.Portid)

If TCP.Connected Then

    TCP.Close()

    ClassStatus = ClassStatusEnum.DoneConnected

End If

Catch ex As Exception
      Err.Clear()
      ClassStatus = ClassStatusEnum.DoneNotConnected
End Try

Of course we now need to write code that checks each port one at a time to see if the call (to the previous code) suceeded in connecting. Pretty straight forward, so I won't go deeply into the details except that you need to pass it two lists of PortStruct (Int32 PortNumber, and String PortUsage ). The first list is a list of ports to check passed by value. The second is a list to be filled in of ports that are open and is therefore passed by referance (pointer). Check each port in sequence and if it connected add it to the list of open ports and voila (as they say somewhere).

    Private Function SlowCheckThem(ByVal PortsToTest As List(Of PortStruct), ByVal openPorts As List(Of PortStruct)) As Boolean
        Dim rv As Boolean = False
        Dim c() As clsCheckPort = Nothing ' create an array of clsCheckPort
        Dim prt As PortStruct
        Dim j As Integer = 0
        Dim ThreadArray() As Thread ' Create an array of Threads

        Try

            For Each p As PortStruct In PortsToTest ' check each port
                ReDim Preserve c(j) ' instanciate a clsCheckPort for each port to check
                ReDim Preserve ThreadArray(j) ' instanciate a threasd for each port to check
                c(j) = New clsCheckPort(PingAddress, p.PortId)
                c(j).CheckPort() ' start the thread . . . passing the port structure to the thread
                j += 1
                Application.DoEvents()
            Next
            For i As Integer = 0 To j - 1 ' check each instance of the class
                If c(i).CheckStatus = clsCheckPort.ClassStatusEnum.DoneConnected Then 'if the status nis done and connected
                    prt.PortId = c(i).Port ' create and fill in a structure
                    prt.PortUse = c(i).PortUse
                    openPorts.Add(prt) ' to add it to the openPorts list
                End If
                Application.DoEvents()
            Next
            rv = True
        Catch ex As Exception

        End Try
        Return rv
    End Function

If you want to check a lot of ports (for instance . . . all of them), you won't use the previous method. You will want to create a bunch (an array) of threads that will each check one port. Give it a small amount of time to finish checking and then check the results.

    Private Function CheckThem(ByVal PortsToTest As List(Of PortStruct), ByVal openPorts As List(Of PortStruct)) As Boolean
        Dim rv As Boolean = False
        Dim c() As clsCheckPort = Nothing ' create an array of clsCheckPort
        Dim prt As PortStruct
        Dim j As Integer = 0
        Dim ThreadArray() As Thread ' Create an array of Threads

        Try

            For Each p As PortStruct In PortsToTest ' check each port
                ReDim Preserve c(j)
                ReDim Preserve ThreadArray(j)
                c(j) = New clsCheckPort(PingAddress, p.PortId) ' instanciate a clsCheckPort for each port to check
                ThreadArray(j) = New Thread(AddressOf c(j).CheckPort) ' instanciate a threasd for each port to check
                ThreadArray(j).Start() ' start the thread
                j += 1
                Application.DoEvents()
            Next
            Wait(1000) ' give the last thread a moment ot complete
            For i As Integer = 0 To j - 1 ' check each instance of the class
                If c(i).CheckStatus = clsCheckPort.ClassStatusEnum.DoneConnected Then 'if the status nis done and connected
                    prt.PortId = c(i).Port ' create and fill in a structure
                    prt.PortUse = c(i).PortUse
                    openPorts.Add(prt) ' to add it to the openPorts list
                End If
                Application.DoEvents()
            Next
            rv = True
        Catch ex As Exception

        End Try
        Return rv
    End Function

To check many ports efficiently and quickly we pass a different function the same lists as before. In the function we first create an array of the class that does the work and then we create an array of threads to do the work. Loop through and start all the threads. While you are busy starting one thread, the previous thread will have been working its magic. If it connects, it will probably be done before you call the next thread. if not . . . who cares?

When you finish calling the last thread, just wait for a moment (a few milliseconds) to let the last few threads connect if they can. Then start checking the class array to see who has connected. Fill the open list in and voila (as they say somewhere else). The rest is just normal code.