diff --git a/CHANGELOG b/CHANGELOG
index 9a2e994f7..ac13c568e 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,7 @@
# Nmap Changelog ($Id$); -*-text-*-
+o [NSE] Added bitcoinrpc-info by Toni Ruottu.
+
o Added a TCP Kerberos service probe. [Patrik]
o [NSE] The targets-ipv6-multicast-*.nse scripts now scan all
diff --git a/scripts/bitcoinrpc-info.nse b/scripts/bitcoinrpc-info.nse
new file mode 100644
index 000000000..9b82876ed
--- /dev/null
+++ b/scripts/bitcoinrpc-info.nse
@@ -0,0 +1,121 @@
+description = [[
+Calls getinfo on Bitcoin daemon's JSON-RPC interface.
+]]
+
+---
+-- @usage
+-- nmap -p 8332 --script bitcoinrpc-info --script-args creds.global=:
+-- @args creds.global http credentials used for the query (user:pass)
+-- @output
+-- 8332/tcp open unknown
+-- | bitcoinrpc-info.nse:
+-- | USER: root
+-- | proxy:
+-- | connections: 36
+-- | errors:
+-- | hashespersec: 0
+-- | generate: false
+-- | keypoololdest: 1309381827
+-- | difficulty: 1379223.4296725
+-- | balance: 0
+-- | version: 32100
+-- | paytxfee: 0
+-- | testnet: false
+-- | blocks: 135041
+-- |_ genproclimit: -1
+
+author = "Toni Ruottu"
+license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
+categories = {"default", "discovery", "safe"}
+dependencies = {"http-brute"}
+
+require 'http'
+require 'shortport'
+require 'json'
+require 'creds'
+
+portrule = shortport.port_or_service(8332, "http")
+
+-- JSON-RPC helpers
+
+local function request(method, params, id)
+ json.make_array(params)
+ local req = {method = method, params = params, id = id}
+ local serial = json.generate(req)
+ return serial
+end
+
+local function response(serial)
+ local _, response = json.parse(serial)
+ local result = response["result"]
+ return result
+end
+
+local ServiceProxy = {}
+function ServiceProxy:new(host, port, path, options)
+ local o = {}
+ setmetatable(o, self)
+ self.host = host
+ self.port = port
+ self.path = path
+ self.options = options
+ self.__index = function(_, method)
+ return function(...)
+ return self:call(method, arg)
+ end
+ end
+ return o
+end
+
+function ServiceProxy:remote(req)
+ local httpdata = http.post(self.host, self.port, self.path, self.options, nil, req)
+ if stdnse.strsplit(" ", httpdata["status-line"])[2] ~= "200" then
+ return
+ end
+ local body = httpdata["body"]
+ return body
+end
+
+function ServiceProxy:call(method, args)
+ local FIRST = 1
+ local req = request(method, args, FIRST)
+ local ret = self:remote(req)
+ if not ret then
+ return
+ end
+ local result = response(ret)
+ return result
+end
+
+local function formatpairs(info)
+ local result = {}
+ for k, v in pairs(info) do
+ local line = k .. ": " .. tostring(v)
+ table.insert(result, line)
+ end
+ return result
+end
+
+local function getinfo(host, port, user, pass)
+ local auth = {username = user, password = pass}
+ local bitcoind = ServiceProxy:new(host, port, "/", {auth = auth})
+ local info = bitcoind.getinfo()
+ if not info then
+ return nil
+ end
+ local result = formatpairs(info)
+ result["name"] = "USER: " .. user
+ return result
+end
+
+action = function(host, port)
+ local response = {}
+ local c = creds.Credentials:new(creds.ALL_DATA, host, port)
+ local states = creds.State.VALID + creds.State.PARAM
+ for cred in c:getCredentials(states) do
+ local info = getinfo(host, port, cred.user, cred.pass)
+ table.insert(response, info)
+ end
+ return stdnse.format_output(true, response)
+end
+
diff --git a/scripts/script.db b/scripts/script.db
index f17034545..012f00af3 100644
--- a/scripts/script.db
+++ b/scripts/script.db
@@ -11,6 +11,7 @@ Entry { filename = "auth-spoof.nse", categories = { "malware", "safe", } }
Entry { filename = "backorifice-brute.nse", categories = { "brute", "intrusive", } }
Entry { filename = "backorifice-info.nse", categories = { "default", "discovery", "safe", } }
Entry { filename = "banner.nse", categories = { "discovery", "safe", } }
+Entry { filename = "bitcoinrpc-info.nse", categories = { "default", "discovery", "safe", } }
Entry { filename = "bittorrent-discovery.nse", categories = { "discovery", "safe", } }
Entry { filename = "broadcast-avahi-dos.nse", categories = { "broadcast", "dos", "intrusive", "vuln", } }
Entry { filename = "broadcast-db2-discover.nse", categories = { "broadcast", "safe", } }