1+ param (
2+ [Parameter (Mandatory = $true )]
3+ [string ]$CsvPath
4+ )
5+
6+ # --- Output file with timestamp ---
7+ $outputFile = " crt_results_$ ( Get-Date - Format ' yyyyMMdd_HHmmss' ) .csv"
8+ $results = @ ()
9+
10+ Write-Host " ========== START =========="
11+ Write-Host " => Input CSV: $CsvPath "
12+ Write-Host " => Output CSV: $outputFile "
13+
14+ # --- Validate CSV ---
15+ if (-not (Test-Path $CsvPath )) {
16+ Write-Host " [ERROR] CSV file not found!"
17+ exit
18+ }
19+
20+ # --- Load CSV ---
21+ $rows = Import-Csv - Path $CsvPath
22+ Write-Host " => Rows loaded: $ ( $rows.Count ) "
23+
24+ # --- Port test ---
25+ function Test-Port {
26+ param (
27+ [string ]$Target ,
28+ [int ]$Port ,
29+ [int ]$TimeoutMs = 3000
30+ )
31+
32+ try {
33+ $client = New-Object System.Net.Sockets.TcpClient
34+ $iar = $client.BeginConnect ($Target , $Port , $null , $null )
35+
36+ if (-not $iar.AsyncWaitHandle.WaitOne ($TimeoutMs , $false )) {
37+ $client.Close ()
38+ return $false
39+ }
40+
41+ $client.EndConnect ($iar )
42+ $client.Close ()
43+ return $true
44+ }
45+ catch {
46+ return $false
47+ }
48+ }
49+
50+ # --- Get HTTP title ---
51+ function Get-HttpTitle {
52+ param (
53+ [string ]$Url
54+ )
55+
56+ try {
57+ Write-Host " [DEBUG] Fetching $Url "
58+
59+ $resp = Invoke-WebRequest - Uri $Url - TimeoutSec 10 - ErrorAction Stop
60+
61+ if ($resp.Content -match " <title>(.*?)</title>" ) {
62+ return $matches [1 ].Trim()
63+ }
64+ else {
65+ return " "
66+ }
67+ }
68+ catch {
69+ return " "
70+ }
71+ }
72+
73+ # --- Query crt.sh ---
74+ function Invoke-CrtQuery {
75+ param ($Domain )
76+
77+ $url = " https://crt.sh/?q=$Domain &output=json"
78+
79+ for ($i = 1 ; $i -le 3 ; $i ++ ) {
80+ Write-Host " => Attempt $i /3 : $url "
81+
82+ try {
83+ $response = Invoke-WebRequest - Uri $url - TimeoutSec 30
84+
85+ if ($response.StatusCode -eq 200 ) {
86+ $jsonText = $response.Content -replace " }\s*{" , " },{"
87+ $jsonText = " [$jsonText ]"
88+ return $jsonText | ConvertFrom-Json
89+ }
90+ }
91+ catch {
92+ Write-Host " [ERROR] $ ( $_.Exception.Message ) "
93+ }
94+
95+ Start-Sleep - Seconds 2
96+ }
97+
98+ return $null
99+ }
100+
101+ # --- Extract domains ---
102+ function Extract-Domains {
103+ param ($JsonData )
104+
105+ $domains = New-Object System.Collections.Generic.HashSet[string ]
106+
107+ foreach ($entry in $JsonData ) {
108+ if ($entry.name_value ) {
109+ $names = $entry.name_value -split " `n "
110+
111+ foreach ($n in $names ) {
112+ $clean = $n.Trim ().ToLower()
113+
114+ if ($clean -match ' ^[a-zA-Z0-9\.\-\*]+\.[a-zA-Z]{2,}$' ) {
115+ $clean = $clean -replace ' ^\*\.' , ' '
116+ $domains.Add ($clean ) | Out-Null
117+ }
118+ }
119+ }
120+ }
121+
122+ return $domains
123+ }
124+
125+ # --- MAIN LOOP ---
126+ $index = 0
127+
128+ foreach ($row in $rows ) {
129+
130+ $index ++
131+ Write-Host " `n =============================="
132+ Write-Host " => Processing row #$index "
133+
134+ if (-not $row .' Asset Name' ) {
135+ Write-Host " [WARNING] No Asset Name column, skipping"
136+ continue
137+ }
138+
139+ $domain = $row .' Asset Name' .Trim().ToLower()
140+ Write-Host " => Domain: $domain "
141+
142+ # --- Query crt.sh ---
143+ $json = Invoke-CrtQuery - Domain $domain
144+
145+ if (-not $json ) {
146+ Write-Host " [WARNING] No crt.sh data"
147+ continue
148+ }
149+
150+ $foundDomains = Extract- Domains - JsonData $json
151+ $newDomains = $foundDomains | Where-Object { $_ -ne $domain }
152+
153+ foreach ($nd in $newDomains ) {
154+ Write-Host " => NEW DOMAIN: $nd "
155+ }
156+
157+ $allDomains = @ ($domain ) + $newDomains
158+
159+ foreach ($d in $allDomains ) {
160+
161+ Write-Host " `n => Checking $d "
162+
163+ # --- Ports ---
164+ $p80 = Test-Port - Target $d - Port 80
165+ $p443 = Test-Port - Target $d - Port 443
166+ $p22 = Test-Port - Target $d - Port 22
167+ $p3389 = Test-Port - Target $d - Port 3389
168+
169+ $r80 = if ($p80 ) { " OK" } else { " NA" }
170+ $r443 = if ($p443 ) { " OK" } else { " NA" }
171+ $r22 = if ($p22 ) { " OK" } else { " NA" }
172+ $r3389 = if ($p3389 ) { " OK" } else { " NA" }
173+
174+ # --- Titles ---
175+ $title80 = if ($p80 ) { Get-HttpTitle " http://$d " } else { " " }
176+ $title443 = if ($p443 ) { Get-HttpTitle " https://$d " } else { " " }
177+
178+ Write-Host " RESULT => $d : 80 $r80 | 443 $r443 | 22 $r22 | 3389 $r3389 "
179+
180+ if ($title80 ) { Write-Host " Title(80): $title80 " }
181+ if ($title443 ) { Write-Host " Title(443): $title443 " }
182+
183+ # --- Save ---
184+ $results += [PSCustomObject ]@ {
185+ SourceDomain = $domain
186+ DiscoveredDomain = $d
187+ IsNew = ($d -ne $domain )
188+ Port80 = $r80
189+ Port443 = $r443
190+ Port22 = $r22
191+ Port3389 = $r3389
192+ Title80 = $title80
193+ Title443 = $title443
194+ }
195+ }
196+ }
197+
198+ # --- Deduplicate ---
199+ $results = $results | Sort-Object SourceDomain, DiscoveredDomain - Unique
200+
201+ # --- Export ---
202+ Write-Host " `n => Saving results..."
203+
204+ $results | Export-Csv - Path $outputFile - NoTypeInformation - Encoding UTF8
205+
206+ Write-Host " => Done. File: $outputFile "
207+ Write-Host " ========== END =========="
0 commit comments