erebe / wstunnel

Tunnel all your traffic over Websocket or HTTP2 - Bypass firewalls/DPI - Static binary available
BSD 3-Clause "New" or "Revised" License
4.31k stars 370 forks source link

Extra layer of stealth - content-length with auto counted content length. #231

Closed AnorBanantje closed 8 months ago

AnorBanantje commented 9 months ago

Is your feature request related to a problem? Please describe. Auto add content-length with right number of length to make traffic more hidden in http2

Describe the solution you'd like when you add flag --enable-content-length header content-length: (right number of length counted by wstunnel) is added to every request

Describe alternatives you've considered I through that i can set static number but it is easy to detect with inspection that content-length does not match real length but tried it too.

content-length: 0 = can't connect to ssh after wstunnel

content-length: 1000 = can connect but can't execute commands ( error )

content-length: 5000 = can connect + can execute commands but error when use sock proxy to browse internet

content-length: 19503829(random big number) = can everything but i think it could be too easy detected.

erebe commented 9 months ago

Hello,

It is not possible for wstunnel to pre-set the content-length headers. As it depends on the amount of traffic you transfer in the tunnel, it cannot be known in advance to be set in the header request.

Your only solution is to set a big number indeed. If you are afraid of it to be too noticeable, you can randomize it :)

AnorBanantje commented 9 months ago

hmm looks like only wstunnel self closes connection when content-length is too low for connection or when connected and number of packets which are sent is bigger than content-length than wstunnel server drop connection.

i started wstunnel local .\wstunnel.exe server http://127.0.0.1:8000 and redirected traffic to my ssh depends from wstunnel client --http-headers content-length:0 it couldn't make connection , made connection and droped it.

Is maybe possible to set attribute with wstunnel server --ignore-content-length which ignores content-length or removes it inside wstunnel and then parse further request?

Alternative could be HAProxy between frontend HAproxy and wstunnel which removes this header but it wil be overkill for so little task and haproxy gets timeouts when work in layer 7 with wstunnel hmm

Then eventually we could use random number here which help gets through firewall but is ignored in wstunnel server. wstunnel client --set-content-length 1000 --content-length-variation 500 (which could get random values between 500 and 1500

but only --ignore-content-length could "be need to have" for firewall bypass. Of course if it is possible. client side we could alltime set self --http-headers content-length:1294

erebe commented 9 months ago

Sadly, I can't remove the handling of the content-type from wstunnel, as it is directly backed into the HTTP library, and I don't have anyway to control its behavior on that point.

I think you are fine setting a random big number as content-length

AnorBanantje commented 9 months ago

I made change to hyper 1.1.0 and added it to cargo

hyper = { version = "1.1.0", features = ["client", "http1", "http2"] }

hyper = { git = "https://github.com/AnorBanantje/hyper.git", branch = "master", features = ["client", "http1", "http2", "server"] }

Weird is that that is same version like official 1.1.0 but i need to add here as feature server with official it wasn't needed and i get yet 4 errors...

Looks like hyper official is not same as hyper from source or i don't have enough skills to fix it :P Added here one commit to remove content-length check but i can't test it because of this errors.

Main errros are: 1 x the trait hyper::rt::io::Read is not implemented for Upgraded 3 x the trait hyper::rt::io::Write is not implemented for Upgraded

EDIT: Tried too official v1.1.0 from source code again same errors:

hyper = { git = "https://github.com/hyperium/hyper.git", tag = "v1.1.0", features = ["client", "http1", "http2"] }

Compilation LOG: github makes it weird...

error[E0277]: the trait boundUpgraded: hyper::rt::io::Read` is not satisfied --> src\tunnel\transport\websocket.rs:113:40 113 let msg = match self.inner.read_frame(&mut frame_reader).await { ^^^^^^^^^^ the trait hyper::rt::io::Read is not implemented for Upgraded
= help: the following other types implement trait `hyper::rt::io::Read`:
          TokioIo<T>
          Box<T>
          hyper::upgrade::Upgraded
          Pin<P>
          &mut T
= note: required for `TokioIo<Upgraded>` to implement `AsyncRead`
= note: 1 redundant requirement hidden
= note: required for `tokio::io::ReadHalf<TokioIo<Upgraded>>` to implement `AsyncRead`
= note: required for `tokio::io::ReadHalf<TokioIo<Upgraded>>` to implement `AsyncReadExt`

note: required by a bound in WebSocketRead::<S>::read_frame --> C:\Users\lap.cargo\git\checkouts\fastwebsockets-85b6c46666330e06\ca6fe98\src\lib.rs:301:8 | 296 | pub async fn read_frame<R, E>( | ---------- required by a bound in this associated function ... 301 | S: AsyncReadExt + Unpin, | ^^^^^^^^^^^^ required by this bound in WebSocketRead::<S>::read_frame

error[E0277]: the trait bound Upgraded: hyper::rt::io::Write is not satisfied --> src\tunnel\transport\websocket.rs:48:14 48 .write_frame(Frame::binary(Payload::BorrowedMut(&mut buf[..read_len]))) ^^^^^^^^^^^ the trait hyper::rt::io::Write is not implemented for Upgraded
= help: the following other types implement trait `hyper::rt::io::Write`:
          TokioIo<T>
          Box<T>
          hyper::upgrade::Upgraded
          Pin<P>
          &mut T
= note: required for `TokioIo<Upgraded>` to implement `AsyncWrite`
= note: 1 redundant requirement hidden
= note: required for `tokio::io::WriteHalf<TokioIo<Upgraded>>` to implement `AsyncWrite`
= note: required for `tokio::io::WriteHalf<TokioIo<Upgraded>>` to implement `AsyncWriteExt`

note: required by a bound in WebSocketWrite::<S>::write_frame --> C:\Users\lap.cargo\git\checkouts\fastwebsockets-85b6c46666330e06\ca6fe98\src\lib.rs:348:8 | 343 | pub async fn write_frame( | ----------- required by a bound in this associated function ... 348 | S: AsyncWriteExt + Unpin, | ^^^^^^^^^^^^^ required by this bound in WebSocketWrite::<S>::write_frame

error[E0277]: the trait bound Upgraded: hyper::rt::io::Write is not satisfied --> src\tunnel\transport\websocket.rs:77:14 77 .write_frame(Frame::new(true, OpCode::Ping, None, Payload::BorrowedMut(&mut []))) ^^^^^^^^^^^ the trait hyper::rt::io::Write is not implemented for Upgraded
= help: the following other types implement trait `hyper::rt::io::Write`:
          TokioIo<T>
          Box<T>
          hyper::upgrade::Upgraded
          Pin<P>
          &mut T
= note: required for `TokioIo<Upgraded>` to implement `AsyncWrite`
= note: 1 redundant requirement hidden
= note: required for `tokio::io::WriteHalf<TokioIo<Upgraded>>` to implement `AsyncWrite`
= note: required for `tokio::io::WriteHalf<TokioIo<Upgraded>>` to implement `AsyncWriteExt`

note: required by a bound in WebSocketWrite::<S>::write_frame --> C:\Users\lap.cargo\git\checkouts\fastwebsockets-85b6c46666330e06\ca6fe98\src\lib.rs:348:8 | 343 | pub async fn write_frame( | ----------- required by a bound in this associated function ... 348 | S: AsyncWriteExt + Unpin, | ^^^^^^^^^^^^^ required by this bound in WebSocketWrite::<S>::write_frame

error[E0277]: the trait bound Upgraded: hyper::rt::io::Write is not satisfied --> src\tunnel\transport\websocket.rs:87:38 87 if let Err(err) = self.inner.write_frame(Frame::close(1000, &[])).await { ^^^^^^^^^^^ the trait hyper::rt::io::Write is not implemented for Upgraded
= help: the following other types implement trait `hyper::rt::io::Write`:
          TokioIo<T>
          Box<T>
          hyper::upgrade::Upgraded
          Pin<P>
          &mut T
= note: required for `TokioIo<Upgraded>` to implement `AsyncWrite`
= note: 1 redundant requirement hidden
= note: required for `tokio::io::WriteHalf<TokioIo<Upgraded>>` to implement `AsyncWrite`
= note: required for `tokio::io::WriteHalf<TokioIo<Upgraded>>` to implement `AsyncWriteExt`

note: required by a bound in WebSocketWrite::<S>::write_frame --> C:\Users\lap.cargo\git\checkouts\fastwebsockets-85b6c46666330e06\ca6fe98\src\lib.rs:348:8 | 343 | pub async fn write_frame( | ----------- required by a bound in this associated function ... 348 | S: AsyncWriteExt + Unpin, | ^^^^^^^^^^^^^ required by this bound in WebSocketWrite::<S>::write_frame

For more information about this error, try rustc --explain E0277. error: could not compile wstunnel (bin "wstunnel") due to 4 previous errors`