Skip to content
This repository has been archived by the owner on Apr 22, 2020. It is now read-only.
/ cherry.cr Public archive

⚠️ Unavailable - Crystal Man-in-the-middle Toolkit

License

Notifications You must be signed in to change notification settings

636f7079/cherry.cr

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Cherry.cr - Man-in-the-middle Toolkit

Description

  • Because Crystal language is missing most OpenSSL bindings (libCrypto, libSSL).
  • Of course, Crystal official is always busy, it will not help you solve these problems.
    • In despair, I came across openssl.cr, which is a shabby OpenSSL binding.
    • This OpenSSL repository was last updated 5 years ago, Fortunately, most of its features are not completely broken.
    • So I started to test slowly and repair the broken things, And refer to Ruby prototype for redesign.
    • It took one month to fix most of the problems, and finally it was available after three months.
  • I think if I was using Rust then I would n’t have encountered these problems.
    • But this allows me to learn a lot, I hope it can help more people.
  • That's it, Thanks for using, If you encounter any problems, please let me know.

Warning

  • This is a non-thread safe version, if you need thread safety, use 636f7374 / cherry.cr repository.
  • Do not use this repository unless you fully understand manual memory management.
  • Improper use is likely to cause the program to crash, If you haven't used it, I suggest you start simple.

Features

  • OpenSSL

    • Lib (libCrypto, libSSL)
      • There are many bindings in it, many related to loading / reading certificates.
      • libCrypto: (I.e. bio_*, evp_*, rsa_*, dsa_*, pem_*, asn1_*, x509_*).
      • libSSL: (I.e. ssl_ctx_use_certificate, ssl_ctx_use_privatekey).
    • Asn1 (Integer, Time)
      • Integer: Certificate serial number, very useful.
      • Time: Certificate validity period, very useful.
    • Bio (MemBIO)
      • MemBIO: OpenSSL memory buffer, Essential when making Certificate / (Private / Public) keys.
    • Nid
      • Certificate subject id flag, Essential when making Certificate.
      • NID: (I.e. subject_alt_name, ext_usage, usage).
    • Pkey (PKey, DSA, RSA)
      • Essential when (create / read) Public / Private Key.
      • I encountered a memory leak problem here, it has been fixed.
    • SSL (Context, Server, SuperContext, SuperSocket)
      • Context: Support loading certificate / private key files from memory (with garbage collection).
      • Super*: Slightly complicated but worth it, low memory usage.
      • SuperContext: You need to manually free the memory allocation.
      • SuperSocket: You need to manually free the memory allocation.
    • X509 (ExtensionFactory, Request, SuperCertificate, SuperName).
      • ExtensionFactory: Certificate Subject Add / Remove, very important.
      • Request: I don't seem to use it, but I also made.
      • SuperCertificate: You need to manually free the memory allocation, Generate certificate requires it.
      • SuperName: You need to manually free the memory allocation.
      • SuperName: issuer_name, subject_name, Generate certificate requires it.
  • MITM

    • Mitm Slightly complicated but worth it, low memory usage.
    • Client: Wrapper for SuperSocket::Client.
    • Server: Wrapper for SuperSocket::Server.
    • Context: Convenient and fast certificate generation, for Man-in-the-middle.
    • All of these, You need to manually free the memory allocation.
  • HTTP

    • Client
      • If you use SuperContext as Context, it will use SuperSocket.
      • All of these, You need to manually free the memory allocation.

Tips

  • This project is currently in WIP (Work In Progress), it may have some undiscovered problems.
  • This repository contains OpenSSL and Network components.
    • Crystal network components are highly integrated with OpenSSL.
  • Why use Super_*?
    • By using Super_ *, you can reduce memory usage, You don't want your application to take up too much memory.
    • But you have to manage the memory manually, please free the memory allocation manually when you don't need it.
    • If you free the same memory multiple times, your program will crash.
    • When using Fiber, please use it with Channel (It will protect you from free the same memory multiple times).
  • Travis-CI appears to be malfunctioning and this repository cannot be detected.
  • For a better future of the project, I decided to change the MIT license to the GPLv3 license.

Next

  • More specification tests.
  • Troubleshooting Deep Memory Errors / Memory Leaks (More stress tests?)
  • Remove redundant / irrelevant code (SuperContext, SuperSocket).
  • ...

Usage

  • Simple Mitm Server (Need to be used with Orange.cr)
require "base64"
require "orange"
require "cherry"

# This is a simple design, please do not use it directly.

def handle_client(context, client : Orange::Socket)
  return client.close unless request = client.request_payload

  STDOUT.puts [client]

  case {client.tunnel_mode, client.traffic_type}
  when {true, Orange::Traffic::HTTPS}
    client = MITM::Server.upgrade client, request, context

    buffer = uninitialized UInt8[4096_i32]
    length = client.read buffer.to_slice
    puts String.new buffer.to_slice[0_i32, length]
  end

  # But you have to manage the memory manually, please free the memory allocation manually when you don't need it.
  # If you free the same memory multiple times, your program will crash.
  # When using `Fiber`, please use it with `Channel` (It will protect you from free the same memory multiple times).

  client.close
  tls_free client
end

def tls_free(socket : IO)
  case socket
  when Orange::Client
    socket = socket.wrapped
  end

  socket.all_free if socket.responds_to? :all_free
end

# Durian
servers = [] of Tuple(Socket::IPAddress, Durian::Protocol)
servers << Tuple.new Socket::IPAddress.new("8.8.8.8", 53_i32), Durian::Protocol::UDP
servers << Tuple.new Socket::IPAddress.new("1.1.1.1", 53_i32), Durian::Protocol::UDP
resolver = Durian::Resolver.new servers
resolver.ip_cache = Durian::Resolver::Cache::IPAddress.new

# Orange
tcp_server = TCPServer.new "0.0.0.0", 1234_i32
orange = Orange::Server.new tcp_server, resolver
orange.authentication = Orange::Authentication::None
orange.client_timeout = Orange::TimeOut.new
orange.remote_timeout = Orange::TimeOut.new

certificate = Base64.decode_string "Something..."
private_key = Base64.decode_string "Something..."
context = MITM::Context.new certificate, private_key

# Authentication (Optional)
# orange.authentication = Orange::Authentication::Basic
# orange.on_auth = ->(user_name : String, password : String) do
#  STDOUT.puts [user_name, password]
#  Orange::Verify::Pass
# end

loop do
  socket = orange.accept?

  spawn do
    next unless client = socket
    next unless client = orange.process client

    handle_client context, client
  end
end
  • Simple HTTP Client

    • ...

Used as Shard

Add this to your application's shard.yml:

dependencies:
  cherry:
    github: 64726f70/cherry.cr

Installation

$ git clone https://github.com/64726f70/cherry.cr.git

Development

$ make test

References

Related

Credit

Contributors

Name Creator Maintainer Contributor
64726f70
datanoise

License

  • MIT License