Skip to content

Commit

Permalink
v0.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
ninoseki committed Sep 7, 2018
1 parent 33bac15 commit 0dd60bd
Show file tree
Hide file tree
Showing 14 changed files with 825 additions and 27 deletions.
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ Ryo is a yet another website recon tool powered by Ruby.
- By using [DNSDumpster](https://dnsdumpster.com/) and [FindSubdomains](https://findsubdomains.com/)
- [x] Website's technology detection
- By using [SimpleWhatWeb](https://github.com/ninoseki/SimpleWhatWeb)
- [x] Whois
- By using [DomainBigData](https://domainbigdata.com/)
- [x] Threading support
- [ ] Port scanning
- [ ] Threading support

## Installation

Expand All @@ -33,16 +35,18 @@ $ gem install ryo

```sh
$ ryo
Commands:
Commands:
ryo all URL # Run all discovery plugins against a given URL
ryo dir URL # Discover directories and files belong to a given URL
ryo help [COMMAND] # Describe available commands or one specific command
ryo subdomain URL # Discover subdomains of a given URL
ryo tech URL # Discover used technolgies of a given URL
ryo whois URL # Discover whois information of a given URL
```

```sh
# use Webrick as a local http server
# start Webrick HTTP server
# $ ruby -rwebrick -e 'WEBrick::HTTPServer.new(:DocumentRoot => "./", :Port => 8000).start'
$ ryo all http://localhost:8000 | jq .
{
Expand Down Expand Up @@ -111,6 +115,10 @@ $ ryo all http://localhost:8000 | jq .
"certainty": 100
}
]
},
"whois": {
"globa_stats": {},
"registrant": {}
}
}
```
Expand Down
3 changes: 3 additions & 0 deletions lib/ryo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
require "uri"
require "oga"

require "ryo/error"

require "ryo/client"
require "ryo/target"
require "ryo/plugin"
Expand All @@ -19,6 +21,7 @@ def self.discover(uri, options)
h[:dir] = Plugin::Dir.discover(target.uri) if options[:dir] || options[:all]
h[:subdomain] = Plugin::Subdomain.discover(target.fld) if options[:subdomain] || options[:all]
h[:tech] = Plugin::Tech.discover(target.uri) if options[:tech] || options[:all]
h[:whois] = Plugin::Whois.discover(target.domain) if options[:whois] || options[:all]
h
end
end
6 changes: 6 additions & 0 deletions lib/ryo/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ def tech(url)
puts hash.to_json
end

desc "whois URL", "Discover whois information of a given URL"
def whois(url)
hash = discover(url, whois: true)
puts hash.to_json
end

desc "all URL", "Run all discovery plugins against a given URL"
def all(url)
hash = discover(url, all: true)
Expand Down
3 changes: 3 additions & 0 deletions lib/ryo/error.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module Ryo
class NotFoundError < StandardError; end
end
Empty file removed lib/ryo/errors.rb
Empty file.
1 change: 1 addition & 0 deletions lib/ryo/plugin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
require_relative "./plugin/dir"
require_relative "./plugin/subdomain"
require_relative "./plugin/tech"
require_relative "./plugin/whois"
18 changes: 14 additions & 4 deletions lib/ryo/plugin/dir.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
# frozen_string_literal: true

require "thread"
require "thread/pool"

module Ryo
module Plugin
class Dir
attr_reader :uri
attr_reader :uri, :threads
def initialize(uri)
@uri = uri.is_a?(URI::HTTP) ? uri : URI.parse(uri)
@threads = 10
end

def paths
Expand All @@ -17,10 +21,16 @@ def url_for(path)
end

def discover
paths.map { |path| url_for(path) }.select do |url|
res = Client.http.get(url)
res.code == 200
pool = Thread.pool(threads)
results = []
paths.map { |path| url_for(path) }.each do |url|
pool.process {
res = Client.http.get(url)
results << url if res.code == 200
}
end
pool.shutdown
results
end

def self.discover(uri)
Expand Down
2 changes: 1 addition & 1 deletion lib/ryo/plugin/subdomain/find_subdomains.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def parse
return [] if table.nil?
table.css("tr")[1..-1].map do |row|
cols = row.css("td")
domain = cols.first.at_css("a").text.strip
domain = cols.first.at_css("a")&.text&.strip
ip = cols[1].at_css("a").nil? ? "N/A" : cols[1].at_css("a").text.strip
{ domain: domain, ip: ip }
end
Expand Down
64 changes: 64 additions & 0 deletions lib/ryo/plugin/whois.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
module Ryo
module Plugin
class Whois
attr_reader :domain
def initialize(domain)
@domain = domain
end

def endpoint
"https://domainbigdata.com"
end

def fetch_body
res = Client.http.get("#{endpoint}/#{domain}")
res.body.to_s
end

def doc
@doc ||= Oga.parse_html(fetch_body)
end

def parse
h = {}
h[:globa_stats] = globa_stats
h[:registrant] = registrant
h
end

def globa_stats
h = {}
h[:title] = doc.at_css("#trTitle > td:nth-child(2)")&.text
h[:date_creation] = doc.at_css("#trDateCreation > td:nth-child(2)")&.text
h[:date_creation] = doc.at_css("#trDateCreation > td:nth-child(2)")&.text
h[:web_age] = doc.at_css("#trWebAge > td:nth-child(2)")&.text
h[:ip] = doc.at_css("#trIP > td:nth-child(2)")&.text
h[:ip_geolocation] = doc.at_css("#trIPGeolocation > td:nth-child(2)")&.text&.strip
h.compact
end

def registrant
h = {}
h[:name] = doc.at_css("#trRegistrantName > td:nth-child(2) > a")&.text
h[:organization] = doc.at_css("#MainMaster_trRegistrantOrganization > td:nth-child(2) > a")&.text
h[:email] = doc.at_css("#trRegistrantEmail > td:nth-child(2)")&.text
h[:address] = doc.at_css("#trRegistrantAddress > td:nth-child(2)")&.text
h[:city] = doc.at_css("#trRegistrantCity > td:nth-child(2)")&.text
h[:state] = doc.at_css("#trRegistrantState > td:nth-child(2)")&.text
h[:country] = doc.at_css("#trRegistrantCountry > td:nth-child(2)")&.text
h[:phone] = doc.at_css("#trRegistrantTel > td:nth-child(2)")&.text
h[:fax] = doc.at_css("#trRegistrantFax > td:nth-child(2)")&.text
h[:private] = doc.at_css("#MainMaster_divRegistrantIDCard > div:nth-child(4) > table > tbody > tr:nth-child(10) > td:nth-child(2)")&.text
h.compact
end

def discover
parse
end

def self.discover(domain)
new(domain).discover
end
end
end
end
1 change: 1 addition & 0 deletions ryo.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,5 @@ Gem::Specification.new do |spec|
spec.add_dependency "oga", "~> 2.15"
spec.add_dependency "simple_whatweb", "~> 0.2"
spec.add_dependency "thor", "~> 0.19"
spec.add_dependency "thread", "~> 0.2.2"
end
15 changes: 13 additions & 2 deletions spec/cli_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@
end
describe "#tech" do
before {
allow(Ryo::Plugin::Dir).to receive(:discover).and_return({})
allow(Ryo::Plugin::Subdomain).to receive(:discover).and_return({})
allow(Ryo::Plugin::Tech).to receive(:discover).and_return({})
}
it "should output a JSON" do
Expand All @@ -34,9 +32,22 @@
expect(json).to be_a(Hash)
end
end
describe "#whois" do
before {
allow(Ryo::Plugin::Whois).to receive(:discover).and_return({})
}
it "should output a JSON" do
output = capture(:stdout) { subject.start %w(whois http://localhost) }
json = JSON.parse(output)
expect(json).to be_a(Hash)
end
end
describe "#all" do
before {
allow(Ryo::Plugin::Dir).to receive(:discover).and_return({})
allow(Ryo::Plugin::Subdomain).to receive(:discover).and_return({})
allow(Ryo::Plugin::Tech).to receive(:discover).and_return({})
allow(Ryo::Plugin::Whois).to receive(:discover).and_return({})
}
it "should output a JSON" do
output = capture(:stdout) { subject.start %w(all http://localhost) }
Expand Down
Loading

0 comments on commit 0dd60bd

Please sign in to comment.