This repository has been archived by the owner on Apr 8, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
verbind.rb
150 lines (129 loc) · 5.31 KB
/
verbind.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#!/usr/bin/env ruby
# encoding: utf-8
#
# verbind.rb - (case-study) retrieve the version of bind by
# executing a simple dns query request following the rfc standard.
#
# RFC-1035 - domain names - implementation and specification
# - http://tools.ietf.org/html/rfc1035
#
# Federico Fazzi <[email protected]>
# (c) 2015 - MIT License.
#
['socket', 'timeout'].each(&method(:require))
# Socket timeout.
TIMEOUT = 5
# Colors.
RST = "\e[0m"
GB = "\e[1;32m"
RB = "\e[1;31m"
# Execute the DNS query.
def _dns_query(host)
# RFC-1035 4.1.1 - HEADER SECTION FORMAT
# -------------------------------------------------
# 1 1 1 1 1 1
# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
# | ID |
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
# |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
# | QDCOUNT |
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
# | ANCOUNT |
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
# | NSCOUNT |
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
# | ARCOUNT |
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
# TRANSACTION ID: A 16-bit field identifying a specific
# DNS transaction. The transaction ID is created by the
# message originator and is copied by the responder into
# its response message. Using the transaction ID, the
# DNS client can match responses to its requests.
# ID: A 16-bit identifier assigned by the program that
# generates any kind of query.
payload = "\xC0\xDE"
# FLAGS: A 16-bit field containing various service flags
# that are communicated between the DNS client and the
# DNS server.
# OPCODE: (0: standard query) A 4-bit field that
# specifies kind of query in this message.
# QR, OPCODE, AA, TC, RD, RA, Z, RCODE
payload += "\x00\x00"
# QDCOUNT: (question entries) an unsigned 16-bit integer
# specifying the number of entries in the question section.
payload += "\x00\x01"
# ANCOUNT: (answer records) an unsigned 16-bit integer
# specifying the number of resource records in the answer
# section.
payload += "\x00\x00"
# NSCOUNT: (authority records) an unsigned 16-bit integer
# specifying the number of name server resource records in
# the authority records section.
payload += "\x00\x00"
# ARCOUNT: (additional records) an unsigned 16-bit integer
# specifying the number of resource records in the additional
# records section.
payload += "\x00\x00"
# RFC-1035 4.1.2 - QUESTION SECTION FORMAT
# -------------------------------------------------
# 1 1 1 1 1 1
# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
# | |
# / QNAME /
# / /
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
# | QTYPE |
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
# | QCLASS |
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
# QNAME: versionbind, variable length.
# the length of 'version' is 7-byte.
payload += "\x07"
# the 'version' in hex.
payload += "\x76\x65\x72\x73\x69\x6f\x6e"
# the length of 'bind' is 4-byte.
payload += "\x04"
# the 'bind' in hex.
payload += "\x62\x69\x6e\x64"
# terminate the qname with zero-length octet (16-bit)
payload += "\x00\x00"
# QTYPE: (10: NULL, null resource record) 16-bit unsigned.
payload += "\x10\x00"
# QCLASS: (3: CH - chaos) 16-bit unsigned.
payload += "\x03"
puts "#{GB}>#{RST} Requesting for version.bind to address: #{GB}#{host}#{RST}"
begin
socket = UDPSocket.new
socket.connect(host, 0x35)
Timeout.timeout(TIMEOUT) {
# A sendto() udp payload
# to host on port 53.
if socket.send(payload, 0, host, 0x35)
bind_version = ''
ret = socket.recv(1024)
socket.close
# Parse the bind version, skip the first 24 bytes
# that identify your version bind string and other
#`unneeded hex characters from the response.
for i in 0..ret.length - 1
if ret[i] =~ /^[[:graph:]]$/ and i > 24
bind_version += ret[i].chr
end
end
return puts "#{GB}+#{RST} Bind version found: #{GB}#{bind_version}#{RST}"
end
}
rescue SocketError, Errno::ECONNREFUSED
return puts "#{RB}- error:#{RST} connection refused (bad address?)."
rescue Timeout::Error
return puts "#{RB}- error:#{RST} connection timed out."
end
end
# Check for valid argument.
if ARGV.first.nil?
abort("usage: ruby bind-version.rb example.org")
end
_dns_query(ARGV.first)