Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
T
Titanium-Web-Proxy
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Titanium-Web-Proxy
Commits
122feb3b
Commit
122feb3b
authored
Jun 27, 2017
by
Honfika
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Parse Ssl client hello
parent
629ba957
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
257 additions
and
34 deletions
+257
-34
MainWindow.xaml.cs
Examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml.cs
+20
-19
SessionListItem.cs
Examples/Titanium.Web.Proxy.Examples.Wpf/SessionListItem.cs
+6
-2
CustomBufferedPeekStream.cs
Titanium.Web.Proxy/Helpers/CustomBufferedPeekStream.cs
+58
-0
CustomBufferedStream.cs
Titanium.Web.Proxy/Helpers/CustomBufferedStream.cs
+10
-0
ConnectRequest.cs
Titanium.Web.Proxy/Http/ConnectRequest.cs
+63
-0
ConnectResponse.cs
Titanium.Web.Proxy/Http/ConnectResponse.cs
+1
-0
HeaderCollection.cs
Titanium.Web.Proxy/Http/HeaderCollection.cs
+9
-0
HttpsTools.cs
Titanium.Web.Proxy/Http/HttpsTools.cs
+88
-12
RequestHandler.cs
Titanium.Web.Proxy/RequestHandler.cs
+1
-1
Titanium.Web.Proxy.csproj
Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
+1
-0
No files found.
Examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml.cs
View file @
122feb3b
...
...
@@ -16,6 +16,7 @@ using System.Windows.Navigation;
using
System.Windows.Shapes
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Http
;
using
Titanium.Web.Proxy.Models
;
namespace
Titanium.Web.Proxy.Examples.Wpf
...
...
@@ -71,7 +72,10 @@ namespace Titanium.Web.Proxy.Examples.Wpf
proxyServer
.
TrustRootCertificate
=
true
;
proxyServer
.
ForwardToUpstreamGateway
=
true
;
var
explicitEndPoint
=
new
ExplicitProxyEndPoint
(
IPAddress
.
Any
,
8000
,
true
);
var
explicitEndPoint
=
new
ExplicitProxyEndPoint
(
IPAddress
.
Any
,
8000
,
true
)
{
//IncludedHttpsHostNameRegex = new string[0],
};
proxyServer
.
AddEndPoint
(
explicitEndPoint
);
proxyServer
.
BeforeRequest
+=
ProxyServer_BeforeRequest
;
proxyServer
.
BeforeResponse
+=
ProxyServer_BeforeResponse
;
...
...
@@ -101,10 +105,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
SessionListItem
item
;
if
(
sessionDictionary
.
TryGetValue
(
e
,
out
item
))
{
item
.
Response
.
ResponseStatusCode
=
e
.
WebSession
.
Response
.
ResponseStatusCode
;
item
.
Response
.
ResponseStatusDescription
=
e
.
WebSession
.
Response
.
ResponseStatusDescription
;
item
.
Response
.
HttpVersion
=
e
.
WebSession
.
Response
.
HttpVersion
;
item
.
Response
.
ResponseHeaders
.
AddHeaders
(
e
.
WebSession
.
Response
.
ResponseHeaders
);
item
.
Response
=
e
.
WebSession
.
Response
;
item
.
Update
();
}
});
...
...
@@ -132,10 +133,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
SessionListItem
item2
;
if
(
sessionDictionary
.
TryGetValue
(
e
,
out
item2
))
{
item2
.
Response
.
ResponseStatusCode
=
e
.
WebSession
.
Response
.
ResponseStatusCode
;
item2
.
Response
.
ResponseStatusDescription
=
e
.
WebSession
.
Response
.
ResponseStatusDescription
;
item2
.
Response
.
HttpVersion
=
e
.
WebSession
.
Response
.
HttpVersion
;
item2
.
Response
.
ResponseHeaders
.
AddHeaders
(
e
.
WebSession
.
Response
.
ResponseHeaders
);
item2
.
Response
=
e
.
WebSession
.
Response
;
item2
.
Update
();
item
=
item2
;
}
...
...
@@ -165,16 +163,13 @@ namespace Titanium.Web.Proxy.Examples.Wpf
{
Number
=
lastSessionNumber
,
SessionArgs
=
e
,
Request
=
{
Method
=
e
.
WebSession
.
Request
.
Method
,
RequestUri
=
e
.
WebSession
.
Request
.
RequestUri
,
HttpVersion
=
e
.
WebSession
.
Request
.
HttpVersion
,
},
// save the headers because TWP will set it to null in Dispose
RequestHeaders
=
e
.
WebSession
.
Request
.
RequestHeaders
,
ResponseHeaders
=
e
.
WebSession
.
Response
.
ResponseHeaders
,
Request
=
e
.
WebSession
.
Request
,
Response
=
e
.
WebSession
.
Response
,
};
item
.
Request
.
RequestHeaders
.
AddHeaders
(
e
.
WebSession
.
Request
.
RequestHeaders
);
if
(
e
is
TunnelConnectSessionEventArgs
||
e
.
WebSession
.
Request
.
UpgradeToWebSocket
)
{
e
.
DataReceived
+=
(
sender
,
args
)
=>
...
...
@@ -232,9 +227,14 @@ namespace Titanium.Web.Proxy.Examples.Wpf
data
=
data
.
Take
(
truncateLimit
).
ToArray
();
}
//restore the headers
typeof
(
Request
).
GetProperty
(
nameof
(
Request
.
RequestHeaders
)).
SetValue
(
session
.
Request
,
session
.
RequestHeaders
);
typeof
(
Response
).
GetProperty
(
nameof
(
Response
.
ResponseHeaders
)).
SetValue
(
session
.
Response
,
session
.
ResponseHeaders
);
//string hexStr = string.Join(" ", data.Select(x => x.ToString("X2")));
TextBoxRequest
.
Text
=
session
.
Request
.
HeaderText
+
session
.
Request
.
Encoding
.
GetString
(
data
)
+
(
truncated
?
Environment
.
NewLine
+
$"Data is truncated after
{
truncateLimit
}
bytes"
:
null
);
(
truncated
?
Environment
.
NewLine
+
$"Data is truncated after
{
truncateLimit
}
bytes"
:
null
)
+
(
session
.
Request
as
ConnectRequest
)?.
ClientHelloInfo
;
data
=
session
.
ResponseBody
??
new
byte
[
0
];
truncated
=
data
.
Length
>
truncateLimit
;
...
...
@@ -245,7 +245,8 @@ namespace Titanium.Web.Proxy.Examples.Wpf
//hexStr = string.Join(" ", data.Select(x => x.ToString("X2")));
TextBoxResponse
.
Text
=
session
.
Response
.
HeaderText
+
session
.
Response
.
Encoding
.
GetString
(
data
)
+
(
truncated
?
Environment
.
NewLine
+
$"Data is truncated after
{
truncateLimit
}
bytes"
:
null
);
(
truncated
?
Environment
.
NewLine
+
$"Data is truncated after
{
truncateLimit
}
bytes"
:
null
)
+
(
session
.
Response
as
ConnectResponse
)?.
ServerHelloInfo
;
}
}
}
Examples/Titanium.Web.Proxy.Examples.Wpf/SessionListItem.cs
View file @
122feb3b
...
...
@@ -78,9 +78,13 @@ namespace Titanium.Web.Proxy.Examples.Wpf
public
byte
[]
ResponseBody
{
get
;
set
;
}
public
Request
Request
{
get
;
set
;
}
=
new
Request
();
public
Request
Request
{
get
;
set
;
}
public
Response
Response
{
get
;
set
;
}
=
new
Response
();
public
Response
Response
{
get
;
set
;
}
public
HeaderCollection
RequestHeaders
{
get
;
set
;
}
public
HeaderCollection
ResponseHeaders
{
get
;
set
;
}
public
event
PropertyChangedEventHandler
PropertyChanged
;
...
...
Titanium.Web.Proxy/Helpers/CustomBufferedPeekStream.cs
0 → 100644
View file @
122feb3b
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
using
System.Threading.Tasks
;
namespace
Titanium.Web.Proxy.Helpers
{
class
CustomBufferedPeekStream
{
private
readonly
CustomBufferedStream
baseStream
;
private
int
position
;
public
CustomBufferedPeekStream
(
CustomBufferedStream
baseStream
,
int
startPosition
=
0
)
{
this
.
baseStream
=
baseStream
;
position
=
startPosition
;
}
public
async
Task
<
bool
>
EnsureBufferLength
(
int
length
)
{
var
val
=
await
baseStream
.
PeekByteAsync
(
length
-
1
);
return
val
!=
-
1
;
}
public
byte
ReadByte
()
{
return
baseStream
.
PeekByteFromBuffer
(
position
++);
}
public
int
ReadInt16
()
{
int
i1
=
ReadByte
();
int
i2
=
ReadByte
();
return
(
i1
<<
8
)
+
i2
;
}
public
int
ReadInt24
()
{
int
i1
=
ReadByte
();
int
i2
=
ReadByte
();
int
i3
=
ReadByte
();
return
(
i1
<<
16
)
+
(
i2
<<
8
)
+
i3
;
}
public
byte
[]
ReadBytes
(
int
length
)
{
var
buffer
=
new
byte
[
length
];
for
(
int
i
=
0
;
i
<
buffer
.
Length
;
i
++)
{
buffer
[
i
]
=
ReadByte
();
}
return
buffer
;
}
}
}
Titanium.Web.Proxy/Helpers/CustomBufferedStream.cs
View file @
122feb3b
...
...
@@ -305,6 +305,16 @@ namespace Titanium.Web.Proxy.Helpers
return
streamBuffer
[
bufferPos
+
index
];
}
public
byte
PeekByteFromBuffer
(
int
index
)
{
if
(
bufferLength
<=
index
)
{
throw
new
Exception
(
"Index is out of buffer size"
);
}
return
streamBuffer
[
bufferPos
+
index
];
}
public
byte
ReadByteFromBuffer
()
{
if
(
bufferLength
==
0
)
...
...
Titanium.Web.Proxy/Http/ConnectRequest.cs
View file @
122feb3b
...
...
@@ -8,5 +8,68 @@ namespace Titanium.Web.Proxy.Http
{
public
class
ConnectRequest
:
Request
{
public
ClientHelloInfo
ClientHelloInfo
{
get
;
set
;
}
}
public
class
ClientHelloInfo
{
public
int
MajorVersion
{
get
;
set
;
}
public
int
MinorVersion
{
get
;
set
;
}
public
byte
[]
Random
{
get
;
set
;
}
public
DateTime
Time
{
get
{
DateTime
time
=
DateTime
.
MinValue
;
if
(
Random
.
Length
>
3
)
{
time
=
new
DateTime
(
1970
,
1
,
1
,
0
,
0
,
0
,
0
,
DateTimeKind
.
Utc
)
.
AddSeconds
(((
uint
)
Random
[
3
]
<<
24
)
+
((
uint
)
Random
[
2
]
<<
16
)
+
((
uint
)
Random
[
1
]
<<
8
)
+
(
uint
)
Random
[
0
]).
ToLocalTime
();
}
return
time
;
}
}
public
byte
[]
SessionId
{
get
;
set
;
}
private
static
string
SslVersionToString
(
int
major
,
int
minor
)
{
string
str
=
"Unknown"
;
if
(
major
==
3
&&
minor
==
3
)
str
=
"TLS/1.2"
;
else
if
(
major
==
3
&&
minor
==
2
)
str
=
"TLS/1.1"
;
else
if
(
major
==
3
&&
minor
==
1
)
str
=
"TLS/1.0"
;
else
if
(
major
==
3
&&
minor
==
0
)
str
=
"SSL/3.0"
;
else
if
(
major
==
2
&&
minor
==
0
)
str
=
"SSL/2.0"
;
return
$"
{
major
}
.
{
minor
}
(
{
str
}
)"
;
}
/// <summary>
/// Returns a <see cref="System.String" /> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String" /> that represents this instance.
/// </returns>
public
override
string
ToString
()
{
var
sb
=
new
StringBuilder
();
sb
.
AppendLine
(
"A SSLv3-compatible ClientHello handshake was found. Titanium extracted the parameters below."
);
sb
.
AppendLine
();
sb
.
AppendLine
(
$"Version:
{
SslVersionToString
(
MajorVersion
,
MinorVersion
)}
"
);
sb
.
AppendLine
(
$"Random:
{
string
.
Join
(
" "
,
Random
.
Select
(
x
=>
x
.
ToString
(
"X2"
)))}
"
);
sb
.
AppendLine
(
$"\"Time\":
{
Time
}
"
);
sb
.
AppendLine
(
$"SessionID:
{
string
.
Join
(
" "
,
SessionId
.
Select
(
x
=>
x
.
ToString
(
"X2"
)))}
"
);
return
sb
.
ToString
();
}
}
}
Titanium.Web.Proxy/Http/ConnectResponse.cs
View file @
122feb3b
...
...
@@ -8,5 +8,6 @@ namespace Titanium.Web.Proxy.Http
{
public
class
ConnectResponse
:
Response
{
public
string
ServerHelloInfo
{
get
;
set
;
}
}
}
Titanium.Web.Proxy/Http/HeaderCollection.cs
View file @
122feb3b
...
...
@@ -215,6 +215,15 @@ namespace Titanium.Web.Proxy.Http
return
false
;
}
/// <summary>
/// Removes all the headers.
/// </summary>
public
void
Clear
()
{
Headers
.
Clear
();
NonUniqueHeaders
.
Clear
();
}
internal
string
GetHeaderValueOrNull
(
string
headerName
)
{
HttpHeader
header
;
...
...
Titanium.Web.Proxy/Http/HttpsTools.cs
View file @
122feb3b
...
...
@@ -3,54 +3,130 @@ using System.Collections.Generic;
using
System.Linq
;
using
System.Text
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Helpers
;
namespace
Titanium.Web.Proxy.Http
{
class
HttpsTools
{
public
static
async
Task
<
bool
>
IsClientHello
(
CustomBufferedStream
clientStream
)
public
static
async
Task
<
bool
>
IsClientHello
(
CustomBufferedStream
clientStream
,
TunnelConnectSessionEventArgs
connectArgs
)
{
//detects the HTTPS ClientHello message as it is described in the following url:
//https://stackoverflow.com/questions/3897883/how-to-detect-an-incoming-ssl-https-handshake-ssl-wire-format
var
request
=
(
ConnectRequest
)
connectArgs
.
WebSession
.
Request
;
int
recordType
=
await
clientStream
.
PeekByteAsync
(
0
);
if
(
recordType
==
0x80
)
{
var
peekStream
=
new
CustomBufferedPeekStream
(
clientStream
,
1
);
//SSL 2
int
length
=
await
clientStream
.
PeekByteAsync
(
1
);
int
length
=
peekStream
.
ReadByte
(
);
if
(
length
<
9
)
{
// Message body too short.
return
false
;
}
if
(
await
clientStream
.
PeekByteAsync
(
2
)
!=
0x01
)
if
(
peekStream
.
ReadByte
(
)
!=
0x01
)
{
// should be ClientHello
return
false
;
}
int
majorVersion
=
await
clientStream
.
PeekByteAsync
(
3
);
int
minorVersion
=
await
clientStream
.
PeekByteAsync
(
4
);
int
majorVersion
=
clientStream
.
ReadByte
(
);
int
minorVersion
=
clientStream
.
ReadByte
(
);
return
true
;
}
else
if
(
recordType
==
0x16
)
{
//SSL 3.0 or TLS 1.0, 1.1 and 1.2
int
majorVersion
=
await
clientStream
.
PeekByteAsync
(
1
);
int
minorVersion
=
await
clientStream
.
PeekByteAsync
(
2
);
var
peekStream
=
new
CustomBufferedPeekStream
(
clientStream
,
1
);
//should contain at least 43 bytes
int
requiredLength
=
43
;
// 2 version + 2 length + 1 type + 3 length(?) + 2 version + 32 random + 1 sessionid length
if
(!
await
peekStream
.
EnsureBufferLength
(
requiredLength
))
{
return
false
;
}
int
length1
=
await
clientStream
.
PeekByteAsync
(
3
);
int
length2
=
await
clientStream
.
PeekByteAsync
(
4
);
int
length
=
(
length1
<<
8
)
+
length2
;
//SSL 3.0 or TLS 1.0, 1.1 and 1.2
int
majorVersion
=
peekStream
.
ReadByte
(
);
int
minorVersion
=
peekStream
.
ReadByte
()
;
if
(
await
clientStream
.
PeekByteAsync
(
5
)
!=
0x01
)
int
length
=
peekStream
.
ReadInt16
();
if
(
peekStream
.
ReadByte
()
!=
0x01
)
{
// should be ClientHello
return
false
;
}
length
=
peekStream
.
ReadInt24
();
majorVersion
=
peekStream
.
ReadByte
();
minorVersion
=
peekStream
.
ReadByte
();
byte
[]
random
=
peekStream
.
ReadBytes
(
32
);
length
=
peekStream
.
ReadByte
();
requiredLength
+=
length
+
2
;
// sessionid + 2 data length
if
(!
await
peekStream
.
EnsureBufferLength
(
requiredLength
))
{
return
false
;
}
byte
[]
sessionId
=
peekStream
.
ReadBytes
(
length
);
length
=
peekStream
.
ReadInt16
();
requiredLength
+=
length
+
1
;
// data + data2 length
if
(!
await
peekStream
.
EnsureBufferLength
(
requiredLength
))
{
return
false
;
}
byte
[]
data
=
peekStream
.
ReadBytes
(
length
);
length
=
peekStream
.
ReadByte
();
if
(
length
<
1
)
{
return
false
;
}
requiredLength
+=
length
;
// data2
if
(!
await
peekStream
.
EnsureBufferLength
(
requiredLength
))
{
return
false
;
}
byte
[]
data2
=
peekStream
.
ReadBytes
(
length
);
byte
[]
data3
=
null
;
if
(
majorVersion
>
3
||
majorVersion
==
3
&&
minorVersion
>=
1
)
{
requiredLength
+=
2
;
if
(
await
peekStream
.
EnsureBufferLength
(
requiredLength
))
{
length
=
peekStream
.
ReadInt16
();
requiredLength
+=
length
;
if
(
await
peekStream
.
EnsureBufferLength
(
requiredLength
))
{
data3
=
peekStream
.
ReadBytes
(
length
);
}
}
}
request
.
ClientHelloInfo
=
new
ClientHelloInfo
{
MajorVersion
=
majorVersion
,
MinorVersion
=
minorVersion
,
Random
=
random
,
SessionId
=
sessionId
,
};
return
true
;
}
...
...
Titanium.Web.Proxy/RequestHandler.cs
View file @
122feb3b
...
...
@@ -116,7 +116,7 @@ namespace Titanium.Web.Proxy
connectArgs
.
WebSession
.
Response
=
CreateConnectResponse
(
version
);
await
WriteResponse
(
connectArgs
.
WebSession
.
Response
,
clientStreamWriter
);
bool
isClientHello
=
await
HttpsTools
.
IsClientHello
(
clientStream
);
bool
isClientHello
=
await
HttpsTools
.
IsClientHello
(
clientStream
,
connectArgs
);
if
(
TunnelConnectResponse
!=
null
)
{
...
...
Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
View file @
122feb3b
...
...
@@ -89,6 +89,7 @@
<Compile
Include=
"Extensions\TcpExtensions.cs"
/>
<Compile
Include=
"Helpers\BufferPool.cs"
/>
<Compile
Include=
"Helpers\CustomBinaryReader.cs"
/>
<Compile
Include=
"Helpers\CustomBufferedPeekStream.cs"
/>
<Compile
Include=
"Helpers\CustomBufferedStream.cs"
/>
<Compile
Include=
"Helpers\Firefox.cs"
/>
<Compile
Include=
"Helpers\HttpHelper.cs"
/>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment