Note: You are viewing an old version of this page. View the current version.

require 'openssl'
require 'socket'
require 'zlib'

BAD_PORTS = [ 0, 25, 135, 139, 445 ]

def packet(generation, ip, time)
  a = [ generation ]
  a.concat(ip.split('.').map(&:to_i))
  a << time
  p = a.pack('C5N')
  a << Zlib.crc32(p)
  a.pack('C5NN')
end

def encrypt(packet, key)
  key.private_encrypt(packet)
end

def fmt(packet)
  out = []
  idx = 0
  stack = packet.unpack('C*')
  while a = stack.shift
    b = stack.shift
    c = stack.shift
    one = ( a << 4 ) + ( b & 0xf )
    two = ( ( b & 0x0f ) << 8 ) + c
    out << ( ( one << 4 ) + idx )
    idx += 1
    out << ( ( two << 4 ) + idx )
    idx += 1
  end
  out
end

# Returns true if the packet contains no bad ports; false if it does
def check(packet, bad_ports)
  bad_ports - packet == bad_ports
end

def knock(ip, key)
  time = Time.now.to_i
  generation = 0
  packet = nil
  until packet && check(packet, BAD_PORTS)
    packet = fmt(encrypt(packet(generation, ip, time), key))
    generation += 1
  end

  sock = UDPSocket.new
  packet.each {|port|
    sock.send('', 0, ip, port)
  }
end

key = OpenSSL::PKey::RSA.new(192)
ip = '127.0.0.1'

knock(ip)