# Extract password candidates from application-database-credentials.json + try local root / create DB. $ErrorActionPreference = "Continue" $mysql = "C:\yutongda\tools\mysql-8.0.39-winx64\bin\mysql.exe" $credPath = "C:\yutongda\secure\application-database-credentials.json" Write-Output "=== application-database-credentials.json keys (no values) ===" $j = Get-Content $credPath -Raw | ConvertFrom-Json function Show-Keys($obj, $prefix) { foreach ($p in $obj.PSObject.Properties) { $name = if ($prefix) { "$prefix.$($p.Name)" } else { $p.Name } if ($null -eq $p.Value) { Write-Output (" $name = null"); continue } if ($p.Value -is [string]) { Write-Output (" $name string len=" + $p.Value.Length) } elseif ($p.Value -is [ValueType]) { Write-Output (" $name = " + $p.Value) } elseif ($p.Value -is [System.Collections.IEnumerable] -and -not ($p.Value -is [string])) { $i = 0 foreach ($item in $p.Value) { if ($item -is [psobject]) { Show-Keys $item ("$name[$i]") } else { Write-Output (" $name[$i] type=" + $item.GetType().Name) } $i++ } } elseif ($p.Value -is [psobject]) { Show-Keys $p.Value $name } else { Write-Output (" $name type=" + $p.Value.GetType().Name) } } } Show-Keys $j "" # Collect all string values that look like passwords $cands = New-Object System.Collections.Generic.List[string] function Collect-Strings($obj) { foreach ($p in $obj.PSObject.Properties) { if ($p.Value -is [string] -and $p.Value.Length -ge 4 -and $p.Value.Length -le 128) { if ($p.Name -match '(?i)pass|secret|pwd|root|token') { $cands.Add($p.Value) } elseif ($p.Value -match '[^a-zA-Z0-9./:@_-]' -or $p.Value.Length -ge 12) { # heuristic: long or special-char strings as candidates if ($p.Name -match '(?i)pass|secret|pwd|credential') { $cands.Add($p.Value) } } } elseif ($p.Value -is [psobject]) { Collect-Strings $p.Value } elseif ($p.Value -is [System.Collections.IEnumerable] -and -not ($p.Value -is [string])) { foreach ($item in $p.Value) { if ($item -is [psobject]) { Collect-Strings $item } } } } } Collect-Strings $j # Also MYSQL_PASSWORD from .env and secrets json $envText = Get-Content "E:\wwwroot\.env" -Raw if ($envText -match '(?m)^MYSQL_PASSWORD=(.+)$') { $cands.Add($Matches[1].Trim()) } $sec = Get-Content "E:\wwwroot\ops\inquiry_robot_db_secrets.json" -Raw | ConvertFrom-Json if ($sec.mysql_password) { $cands.Add([string]$sec.mysql_password) } # Try as root Write-Output ("cand_count=" + $cands.Count) $hitRoot = $false $seen = @{} foreach ($p in $cands) { if ($seen.ContainsKey($p)) { continue } $seen[$p] = $true $out = & $mysql -uroot "-p$p" -e "SELECT 'root_ok' AS r" 2>&1 | Out-String if ($out -match "root_ok") { Write-Output ("ROOT_HIT len=" + $p.Length) Set-Content -Path "E:\wwwroot\ops\.mysql_root_stash.tmp" -Value $p -Encoding ascii -NoNewline $hitRoot = $true break } } if (-not $hitRoot) { Write-Output "ROOT_NO_HIT" } # Try each username/password pair from credentials against local mysql for CREATE privilege Write-Output "=== try app users on local 127.0.0.1 ===" function Try-User($user, $pass) { if ([string]::IsNullOrWhiteSpace($user) -or [string]::IsNullOrWhiteSpace($pass)) { return } $sqlFile = [System.IO.Path]::GetTempFileName() + ".sql" Set-Content -Path $sqlFile -Value "SELECT CURRENT_USER() AS u; SHOW GRANTS;" -Encoding ascii $out = & $mysql -h127.0.0.1 "-u$user" "-p$pass" --batch --raw -e "source $sqlFile" 2>&1 | Out-String if ($out -notmatch "ERROR" -and $out -match "Grants for|CURRENT_USER|@") { Write-Output ("USER_OK user=" + $user + " passLen=" + $pass.Length) ($out -split "`r?`n" | Where-Object { $_ -match "GRANT|CURRENT_USER|@" } | Select-Object -First 12) | ForEach-Object { " " + $_ } } else { # retry simpler one-liner without source $out2 = & $mysql -h127.0.0.1 "-u$user" "-p$pass" -e "SELECT 1 AS ok" 2>&1 | Out-String if ($out2 -match "(?m)^1\s*$|ok") { Write-Output ("USER_OK_SIMPLE user=" + $user + " passLen=" + $pass.Length) $g = & $mysql -h127.0.0.1 "-u$user" "-p$pass" -e "SHOW GRANTS" 2>&1 | Out-String ($g -split "`r?`n" | Where-Object { $_ -match "GRANT" } | Select-Object -First 8) | ForEach-Object { " " + $_ } } else { $err = ($out2 -split "`r?`n" | Where-Object { $_ -match "ERROR" } | Select-Object -First 1) Write-Output ("USER_FAIL user=" + $user + " " + $err) } } Remove-Item $sqlFile -ErrorAction SilentlyContinue } # Walk JSON for user/password pairs heuristically function Walk-Pairs($obj, $ctxUser) { $user = $ctxUser $pass = $null foreach ($p in $obj.PSObject.Properties) { if ($p.Name -match '(?i)^(username|user|mysql_user|db_user)$' -and $p.Value -is [string]) { $user = $p.Value } if ($p.Name -match '(?i)^(password|pass|mysql_password|db_password)$' -and $p.Value -is [string]) { $pass = $p.Value } } if ($user -and $pass) { Try-User $user $pass } foreach ($p in $obj.PSObject.Properties) { if ($p.Value -is [psobject]) { Walk-Pairs $p.Value $user } elseif ($p.Value -is [System.Collections.IEnumerable] -and -not ($p.Value -is [string])) { foreach ($item in $p.Value) { if ($item -is [psobject]) { Walk-Pairs $item $user } } } } } Walk-Pairs $j $null # Also try inquiry_robot from secrets against local and remote $irUser = [string]$sec.mysql_user $irPass = [string]$sec.mysql_password Write-Output "=== inquiry_robot against local/remote ===" Try-User $irUser $irPass $outR = & $mysql -h10.206.0.14 "-u$irUser" "-p$irPass" -e "SELECT 'remote_ok' AS r" 2>&1 | Out-String if ($outR -match "remote_ok") { Write-Output "REMOTE_IR_OK" } else { Write-Output ("REMOTE_IR_FAIL " + (($outR -split "`r?`n" | Where-Object { $_ -match "ERROR" } | Select-Object -First 1))) } # Also try ytd_jeecg from credentials against local for CREATE DATABASE Write-Output "=== login-path / defaults ===" $mylogin = Join-Path $env:APPDATA "MySQL\.mylogin.cnf" Write-Output ("mylogin_exists=" + (Test-Path $mylogin)) Get-ChildItem "C:\yutongda\secure" -Filter "*mysql*" -ErrorAction SilentlyContinue | ForEach-Object { $_.Name } Get-ChildItem "C:\yutongda\secure" -Filter "*root*" -ErrorAction SilentlyContinue | ForEach-Object { $_.Name } Write-Output "=== phase-c script mentions ===" Select-String -Path "C:\yutongda\ops\phase-c-secure-app-db-credentials.ps1" -Pattern "root|CREATE DATABASE|inquiry|password" | Select-Object -First 20 | ForEach-Object { $_.Line.Trim().Substring(0, [Math]::Min(120, $_.Line.Trim().Length)) } # Who listens 3306 Write-Output "=== 3306 owner ===" Get-NetTCPConnection -LocalPort 3306 -State Listen -ErrorAction SilentlyContinue | Select-Object -First 3 LocalAddress,OwningProcess | ForEach-Object { $p = Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue "{0} pid={1} path={2}" -f $_.LocalAddress, $_.OwningProcess, $p.Path }