Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How can I get the MITM certificate from a flow in a script hook? #1935

Closed
wants to merge 1 commit into from
Closed

How can I get the MITM certificate from a flow in a script hook? #1935

wants to merge 1 commit into from

Conversation

dlenski
Copy link
Contributor

@dlenski dlenski commented Feb 12, 2017

I'm using mitmdump 1.0.2 to intercept a TLS connection and log and modify it with TCP hooks (--tcp foo.host.com -s script.py).

I need to find and replace the hex/ASCII digest of the upstream server certificate with the digest of mitmproxy's generated certificate—because the client expects to receive and check the certificate hash at the application level.

I can easily get the real/upstream server certificate from flow.server_conn.cert. But how can I get the generated/MITM cert sent to the client in the TCP hooks?

def tcp_message(flow):
    d = flow.dumpfile
    m = flow.messages[-1]
    c = m.content

    real_server_hash = flow.server_conn.cert.digest('sha1').replace(b':',b'').lower()

    #####
    # FIXME: how can I figure out the hash of the certificate that mitmproxy is sending to the client?
    mitm_server_hash = b'hardcodedvaluehere'
    #####

    nc = m.content
    nc = nc.replace(real_server_hash, mitm_server_hash)
    if nc!=m.content:
        print("%s message: replaced real cert hash (%r) with mitmproxy cert hash (%r)" % ('outgoing' if m.from_client else 'incoming', real_server_hash, mitm_server_hash), file=stderr)
        m.content = nc

@dlenski
Copy link
Contributor Author

dlenski commented Jan 17, 2017

From what I can tell, the ClientConnect object only exposes the clientcert sent by the client… but it does not expose the mitmcert sent to the client.

Or am I overlooking something that I can use to get the MITM cert?

@mhils
Copy link
Member

mhils commented Jan 17, 2017

Getting the mitmproxy certificate in tcp_message seems to be too late for what you are trying to do - we have already established a TLS connection then. Is this just about a few domains or shall this work generically? For the former case, I'd recommend to just use --cert. Otherwise you probably have to monkeypatch TlsLayer._find_cert.

@dlenski
Copy link
Contributor Author

dlenski commented Jan 17, 2017

Thanks for the quick response!

Getting the mitmproxy certificate in tcp_message seems to be too late for what you are trying to do - we have already established a TLS connection then.

Would it be easier to get in tcp_start?

Is this just about a few domains or shall this work generically?
For the former case, I'd recommend to just use --cert.

Yes, I've used --cert for my individual use cases, but it would be great to be able to be able to make it work generically with the generated certs.

Otherwise you probably have to monkeypatch TlsLayer._find_cert.

Would you suggest something like this, setting the mitmcert as an attribute of server_conn?

@@ -259,21 +259,25 @@ def find_cert(self):
        # RFC 2818: If a subjectAltName extension of type dNSName is present, that MUST be used as the identity.
        # In other words, the Common Name is irrelevant then.
        if host:
            sans.add(host)
-       return self.config.certstore.get_cert(host, list(sans))
+
+       # Save the certificate sent to the client in the server_conn
+       self.server_conn.mitmcert = self.config.certstore.get_cert(host, list(sans))
+       return self.server_conn.mitmcert

@mhils
Copy link
Member

mhils commented Jan 17, 2017

If I understand you correctly, you want to modify the certificate that is shown to the client during the handshake, right? Any of the tcp_* events would be too late for this, they trigger after TLS has been negotiated. If you need to do any shenangians with the cert, do them in find_cert directly, because that directly returns the cert which is then used for the handshake. Does that make sense? :)

@dlenski
Copy link
Contributor Author

dlenski commented Jan 17, 2017

If I understand you correctly, you want to modify the certificate that is shown to the client during the handshake, right?

Aha, I should be clearer in my goal.

I don't actually need to modify the certificate that is shown to the client; I'm quite happy having mitmproxy generate certs on-the-fly, as long as I can lie about them self-consistently within each client session :-P

I just need to be able to access the MITM certificate used for the ongoing connection, so that I can generate its digest, and feed it to the client in the application-layer response.

@mhils
Copy link
Member

mhils commented Jan 17, 2017

Oh ok - makes sense now. 😄
Yes, that's something you'd want to add here the way you described above.

I'm wondering if there is a general use-case here that warrants adding this to the ServerConnection properly so that it does get persisted. @cortesi, thoughts?

@dlenski
Copy link
Contributor Author

dlenski commented Jan 17, 2017

Yes, that's something you'd want to add here the way you described above.

Great, I'll take a crack at it!

I'm wondering if there is a general use-case here that warrants adding this to the ServerConnection properly so that it does get persisted.

In my experience analyzing VPNs, peers often exchange certificates or digests at the application layer. It's often useful to know what MITM certificate we're sending to the client, so that we can inject it at the app layer as well.

@mhils mhils closed this Jan 23, 2017
@dlenski wrote:
> @mhils wrote:
> > I'm wondering if there is a general use-case here that warrants adding
> > this to the ServerConnection properly so that it does get persisted.
>
> In my experience reverse engineering VPNs, peers often exchange
> certificates or digests at the application layer.  It's often useful to
> know what MITM certificate we're sending to the client, so that we can
> inject it at the app layer as well.
@dlenski dlenski deleted the save_mitm_cert branch February 12, 2017 21:32
@dlenski dlenski restored the save_mitm_cert branch February 12, 2017 21:32
Kriechi pushed a commit that referenced this pull request Feb 21, 2017
krsoninikhil pushed a commit to krsoninikhil/mitmproxy that referenced this pull request Mar 3, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants