-
Notifications
You must be signed in to change notification settings - Fork 0
/
Get-CruftyWebFiles.ps1
174 lines (160 loc) · 7.72 KB
/
Get-CruftyWebFiles.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# CruftyWebFiles
# All care, no responsibility accepted by TristanK
# 1.01 2016-11-25
# 1.02 2016-12-09 Merry Xmas
#
# Tries to identify extraneous stuff on an IIS web server in servable content areas
# i.e. those which are linked from apps attached to a website
# Hopefully doesn't become part of the cruft afterwards
#
# Cruft isn't always fatal, but it's always evil.
#
# doesn't have loop detection yet, so if it runs forever, it's your fault. Ctrl+C.
param(
[string]
$OutputCSVFile = ".\Cruft.csv",
[string]
$DomainName = "TESTDOMAIN", # for >> DOMAIN << \username abuse detection
[string]
$WebsiteName = ""
)
Import-Module WebAdministration
function StoreCruft
{
param
(
[string] $Website,
$Application,
$FileName,
$ServableName,
$Severity,
$Issue,
$Notes
)
# build PS object for pipeline
$Object = New-Object PSObject
$Object | add-member Noteproperty Website $Website
$Object | add-member Noteproperty Application $Application
$Object | add-member Noteproperty FileName $FileName
$Object | add-member Noteproperty ServableName $ServableName
$Object | add-member Noteproperty Severity $Severity
$Object | add-member Noteproperty Notes $Notes
if([string]::IsNullOrEmpty($OutputCSVFile)){
$Object
}
else{
$Object | Export-Csv -Append -NoTypeInformation -Path $OutputCSVFile
$Object
}
}
# Apps - list of websites (/ app) or apps to scan. Must reside on local box. If not set, scans all.
function Get-CruftyFiles{
param(
[Parameter(
Position=0,
Mandatory=$true,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)
]
[Alias('Path')]
[String[]]$FolderPath
)
process {
$FolderPath = [System.Environment]::ExpandEnvironmentVariables($FolderPath)
$servableFileTypes=("txt","xml") # maybe INF, but not .ini, .config by default
$Severities = @{"Critical" = 0; "High" = 1; "Medium" = 2; "Low" = 3; "Informational" = 4; "Other" = 5}
# higher confidence it's a bad word = higher severity. Still needs a human to look at it.
$passwordy = @{ "$DomainName[\\]\S*" = $Severities["Critical"]; # regex matches likely to be bad
"password[\:\=]\S*" = $Severities["Critical"] ;
"username[\:\=]\S*" = $Severities["Critical"];
"pwd" = $Severities["High"];
"password" = $Severities["High"];
"$DomainName" = $Severities["High"];
"username" = $Severities["High"];
"pass" = $Severities["Medium"] ;
"user" = $Severities["Medium"] # getting to the edge of medium due to likely harmless use
}
$extracrufty=("readme.*","sample.*","example.*","demo.*") # can replace with TXT etc if too noisy
foreach($path in $FolderPath)
{
Write-Host -ForegroundColor Black -BackgroundColor DarkGray $path
# look for serious problem file types - possible leaks of config / passwords / etc
foreach ($filetype in $servableFileTypes){
$coll = gci -Path $path -Filter "*.$filetype" -Recurse
#write-host $path $coll
foreach($item in $coll){
Write-Host $item.FullName
$item | Add-Member -Name "Severity" -MemberType NoteProperty -Value $Severities["Informational"]
$item | Add-Member -Name "BadData" -MemberType NoteProperty -Value ""
foreach($searchitem in $passwordy.Keys){
$badInfo = Select-String -Path $item.FullName -Pattern $searchitem -AllMatches # (remove -Allmatches for speed over accuracy)
$item.BadData += "$searchitem=$($badInfo.Matches.Count);"
if($badInfo.Matches.Count -gt 0){
if([string]::IsNullOrEmpty($item.Severity)){
$item.Severity = $passwordy[$searchitem]
}
if($item.Severity -gt $passwordy[$searchitem]){
$item.Severity = $passwordy[$searchitem]
}
}
}
}
$coll
}# end foreach
foreach ($filename in $extracrufty){
$coll = gci -Path $path -Filter "$filename" -Recurse
#write-host $path $coll
foreach($item in $coll){
Write-Host $item.FullName
$item | Add-Member -Name "Severity" -MemberType NoteProperty -Value $Severities["Low"]
$item | Add-Member -Name "BadData" -MemberType NoteProperty -Value "LooksCrufty"
}
$coll
}# end foreach
}
}
}
## actual script start
if([string]::IsNullOrEmpty($WebsiteName)){
$sites = Get-Website # "Default Web Site" # TESTING ONLY
}
else{
$sites = Get-Website $WebsiteName
}
foreach ($site in $sites){
Write-host -ForegroundColor Black -BackgroundColor Green $site.name
#get first site binding to hopefully provide a request framework
$requestablehopefully=$site.bindings.Collection[0].bindingInformation.ToString()
# todo: Binding interpreter to pick most-likely-servable binding and convert to URL
$apps = Get-WebApplication -Site $site.name
$vdirs = Get-WebVirtualDirectory -Site $site.name
# do the site itself, root app isn't an app in PS land.
$basePath = [System.Environment]::ExpandEnvironmentVariables($site.physicalPath.ToString())
$cruftyFiles = $site.physicalPath.ToString() | Get-CruftyFiles
foreach($cruftyFile in $cruftyFiles){
$relativePath = $cruftyFile.FullName.ToLower().Replace($basePath.ToLower(),"");
$relativePath = $relativePath.Replace("\","/");
$srvable = "$($requestablehopefully)$relativePath"
StoreCruft -Website $site.name -Application "/" -FileName $cruftyFile.FullName -ServableName "$srvable" -Severity $cruftyFile.Severity -Notes $cruftyFile.BadData
}
foreach($app in $apps){
$cruftyFiles = $app.physicalPath.ToString() | Get-CruftyFiles
foreach($cruftyFile in $cruftyFiles){
$basePath = [System.Environment]::ExpandEnvironmentVariables($app.physicalPath.ToString())
$relativePath = $cruftyFile.FullName.ToLower().Replace($basePath.ToLower(),"");
$relativePath = $relativePath.Replace("\","/");
$srvable = "$($requestablehopefully)$($app.path)$($relativePath)"
StoreCruft -Website $site.name -Application $app.path -FileName $cruftyFile.FullName -ServableName "$srvable" -Severity $cruftyFile.Severity -Notes $cruftyFile.BadData
}
}
foreach($app in $vdirs){ #cheating
$cruftyFiles = $app.physicalPath.ToString() | Get-CruftyFiles
foreach($cruftyFile in $cruftyFiles){
$basePath = [System.Environment]::ExpandEnvironmentVariables($app.physicalPath.ToString())
$relativePath = $cruftyFile.FullName.ToLower().Replace($basePath.ToLower(),"");
$relativePath = $relativePath.Replace("\","/");
$srvable = "$($requestablehopefully)$($app.path)/$($relativePath)"
StoreCruft -Website $site.name -Application $app.path -FileName $cruftyFile.FullName -ServableName "$srvable" -Severity $cruftyFile.Severity -Notes $cruftyFile.BadData
}
}
}