0

I'm writing MITM ssl proxy using indy. i use IdHTTPserver component with self signed certificate for proxy server, and on event of CommandOther i do TcpCleint request to site and return data in HTTPServer. But problem is, some scripts, especially JS and some pictures from web pages not being loaded at all, or load after timeout, so i recieve html code in browser, but crippled by not working js (mostly). Here's my code for CommandOther:

procedure TForm3.IdHTTPServer1CommandOther(AContext: TIdContext;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var

client: TIdTCPClient;
Headers, headers1: TIdHeaderList;
s, ResponseCode, ResponseText: string;
req,req2:string;
Size: Int64;
Strm,strm2: TIdTCPStream;
ssl: TIdSSLIOHandlerSocketOpenSSL;
clientcount:integer;

  begin
  Memo3.lines.Add('start');


client := TIdtCPClient.Create(nil);

ssl := TIdSSLIOHandlerSocketOpenSSL.Create(client);
client.IOHandler := ssl;

s := ARequestInfo.URI;
client.Host := Fetch(s, ':', True);
client.Port := StrToIntDef(s, 443);


client.ConnectTimeout := 2000;

s := '';
Memo3.lines.Add('connecting');


client.UseNagle:=true;

client.Connect;

 //here i handle CONNECT command
 AResponseInfo.ResponseNo := 200;
  AResponseInfo.ResponseText := 'Connection established';
     aresponseinfo.WriteHeader;


  // activate SSL between this proxy and the client
  TIdSSLIOHandlerSocketOpenSSL(AContext.Connection.Socket).PassThrough
  := false;
Memo3.lines.Add('connected');

 while AContext.Connection.Connected and Client.Connected do
  begin
  try



          memo4.Lines.Add('---start header-------');
  headers1 := TIdHeaderList.Create(QuoteHTTP);

    headers1.FoldLength := MaxInt;




    repeat
      s := AContext.Connection.IOHandler.ReadLn;
                 Memo4.lines.Add(s);
      headers1.Add(s);
      if s = '' then

        Break;

    until False;

  client.WriteHeader(headers1);
   memo4.Lines.Add('-----header written-----');


   memo5.Lines.Add('----------');
  if Headers1.IndexOfName('Content-Length') <> -1 then
      begin
      strm2:=TIdTCPStream.Create(client);
      memo5.Lines.Add('post');
        Size := StrToInt64(Headers1.Values['Content-Length']);


        if Size > 0 then
          AContext.Connection.IOHandler.ReadStream(Strm2, Size, False);
      end;




       memo4.Lines.Add('---response headers-------');
  Headers := TIdHeaderList.Create(QuoteHTTP);
  try
    Headers.FoldLength := MaxInt;

    repeat
      s := client.IOHandler.ReadLn;
             Memo4.lines.Add(s);
      acontext.Connection.IOHandler.WriteLn(s);
      Headers.Add(s);
      if s = '' then

        Break;

    until False;
        memo4.Lines.Add('---respone headers read-------');

    Strm := TIdTCPStream.Create(AContext.Connection);
    try


      if Pos('chunked', Headers.Values['Transfer-Encoding']) <> 0 then
      begin
      memo4.Lines.Add('chunked');


        repeat
          s := client.IOHandler.ReadLn;
          AContext.Connection.IOHandler.WriteLn(s);
          Size := StrToInt64('$' + Fetch(s, ';'));
          if Size = 0 then
            Break;
          client.IOHandler.ReadStream(Strm, Size, False);
          s := client.IOHandler.ReadLn;
          AContext.Connection.IOHandler.WriteLn(s);
        until False;

        repeat
          s := client.IOHandler.ReadLn;
          AContext.Connection.IOHandler.WriteLn(s);
        until s = '';
      end
      else if Headers.IndexOfName('Content-Length') <> -1 then
      begin
        Size := StrToInt64(Headers.Values['Content-Length']);


        end;
        if Size > 0 then
          client.IOHandler.ReadStream(Strm, Size, False);
      end
      else
      begin
      memo5.Lines.Add('big read(');
        AResponseInfo.CloseConnection := true;

        try
          client.IOHandler.ReadStream(Strm, -1, True);
        except
          on E: EIdSocketError do
          begin

            raise;
          end;
        end;
      end;
    finally

      Strm.Free;

    end;
  finally
    Headers.Free;
     strm2.Free;
       headers1.Free;
  end;

finally
client.Disconnect;

end;

client.Free;


      end;

      end;
JoshSterling
  • 29
  • 1
  • 3
  • 2
    Did you configure your web browser to accept your certificate? Most web browsers do not accept self-signed certificates by default. Also, the correct way to manually respond to a request in `TIdHTTPServer` is `AResponseInfo.WriteHeader()` and `AResponseInfo.WriteContent()`, not `AContext.Connection.IOHandler.WriteLn();` Also, your code suggests you are processing `CONNECT` requests, is that right? Is there a reason why you are using `TIdHTTPServer` to handle that manually, instead of using `TIdHTTPProxyServer`? The code you have shown is not how a `CONNECT` request should be handled. – Remy Lebeau Oct 05 '19 at 01:45
  • @Remy Indeed i added root cert to exceptions, and i have no issues with ssl in browser. And yes, i'm trying to process CONNECT, because actually i have HTTPproxyserver, it creates new http server and forwards requests to it, so HTTPserver is set up with right certificate. The goal is: HTTPProxy accept connection, generates cert and creates HTTPserver with correct cert and forwards request to it. – JoshSterling Oct 05 '19 at 16:16
  • The way `CONNECT` works, the client performs the SSL/TLS handshake with the target server after the proxy makes the tunnel. The client verifies the target server's certificate. The proxy can't fake that certificate, if it does, the client will fail validation and close the connection (if it cares about proper security at all). I don't understand what you are trying to accomplish. – Remy Lebeau Oct 05 '19 at 16:59
  • @remy proxy just forwards transparent traffic to idhttpserver, which is set up with correct certificate for that domain. HTTPproxy doent negotiate ssl connection, it adds idhttpserver as a chain for proxyfyng. So idhttpserver with receive CONNECT request and handle it – JoshSterling Oct 05 '19 at 20:00
  • I still don't see why you are using `TIdHTTPServer` instead of `TIdHTTPProxyServer`, and why you have a transparent proxy in front of the HTTP proxy, that seems kind of redundant, unless the client and HTTP proxy are on different networks being bridged by the transparent proxy. What is your end goal with all this proxying? – Remy Lebeau Oct 06 '19 at 00:23
  • @Remy The goal is to intercept and modify data send to browser by SSL. transparent proxy just sets correct certificate for TIdHTTPServer which does interception – JoshSterling Oct 06 '19 at 09:19
  • why do you need 2 proxies? Why not have the HTTP server make its own certificate? Your setup sounds more complicated than it needs to be – Remy Lebeau Oct 06 '19 at 15:43
  • @remy i've found no way to dynamically setup certificate. i will appreciate if you will show how. It's very difficult to find good documentation on this matter( – JoshSterling Oct 06 '19 at 16:02
  • how is the transparent proxy setting the certificate for the HTTP proxy to begin with? You haven't shown your transparent proxy code at all. I still don't understand what you are trying to do. A `CONNECT` client WILL NOT negotiate an SSL/TLS handshake with the proxy it is `CONNECT`ing through, only with the target HTTP server it is `CONNECT`ing to. So all this code is moot. Your HTTP proxy **can't** intercept HTTPS traffic this way. SSL/TLS is *designed* to thwart such a Mitm. I don't think you understand how SSL/TLS and `CONNECT` actually work, especially in relation to each other. – Remy Lebeau Oct 06 '19 at 16:48
  • The only way to make this work is for your HTTP proxy to act as an origin server without `CONNECT`, not as a passthrough to an origin server. The client will negotiate an SSL/TLS handshake with an origin server that has a valid certificate. Not with a proxy with a fake certificate. – Remy Lebeau Oct 06 '19 at 16:48
  • @remy well, i changed code a bit, it's in update; Connect is being handled in idhttpserver. i'm getting all the correct data, and i'm getting html code in browser, everything seems fine, but only some certain scripts on web pages are failing to load. it almost seems like lag in getting data from IdTcpClient is to big. – JoshSterling Oct 07 '19 at 00:55
  • the code you have shown WILL NOT work for handling a `CONNECT` request for an HTTPS resource, only for an HTTP resource. You need to rethink your whole approach for HTTPS – Remy Lebeau Oct 07 '19 at 03:03
  • @remy Please, can you show me how to handle it properly? I going nuts trying to find any info on this matter.. – JoshSterling Oct 08 '19 at 22:27
  • Once the `CONNECT` handler establishes the TCP tunnel, it can't make ANY assumptions about the content of the connections in both directlons, it MUST pass raw data back and forth as-is, which means you can't use things like `ReadLn()` and `WriteLn()`, especially when dealing with SSL/TLS since the connection will be encrypted frames. I suggest you have a look at the source code for `TIdHTTPProxyServer`, which already handles `CONNECT`. – Remy Lebeau Oct 08 '19 at 22:38

0 Answers0