gitrob 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +47 -0
- data/Rakefile +2 -0
- data/bin/gitrob +258 -0
- data/gitrob.gemspec +36 -0
- data/lib/gitrob.rb +116 -0
- data/lib/gitrob/github/blob.rb +41 -0
- data/lib/gitrob/github/http_client.rb +127 -0
- data/lib/gitrob/github/organization.rb +93 -0
- data/lib/gitrob/github/repository.rb +72 -0
- data/lib/gitrob/github/user.rb +78 -0
- data/lib/gitrob/observers/sensitive_files.rb +82 -0
- data/lib/gitrob/progressbar.rb +52 -0
- data/lib/gitrob/util.rb +11 -0
- data/lib/gitrob/version.rb +3 -0
- data/lib/gitrob/webapp.rb +76 -0
- data/models/blob.rb +35 -0
- data/models/finding.rb +14 -0
- data/models/organization.rb +32 -0
- data/models/repo.rb +22 -0
- data/models/user.rb +28 -0
- data/patterns.json +303 -0
- data/public/fonts/glyphicons-halflings-regular.eot +0 -0
- data/public/fonts/glyphicons-halflings-regular.svg +229 -0
- data/public/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/public/fonts/glyphicons-halflings-regular.woff +0 -0
- data/public/javascripts/bootstrap.min.js +7 -0
- data/public/javascripts/gitrob.js +75 -0
- data/public/javascripts/jquery-2.1.1.min.js +4 -0
- data/public/javascripts/lang-apollo.js +2 -0
- data/public/javascripts/lang-basic.js +3 -0
- data/public/javascripts/lang-clj.js +18 -0
- data/public/javascripts/lang-css.js +2 -0
- data/public/javascripts/lang-dart.js +3 -0
- data/public/javascripts/lang-erlang.js +2 -0
- data/public/javascripts/lang-go.js +1 -0
- data/public/javascripts/lang-hs.js +2 -0
- data/public/javascripts/lang-lisp.js +3 -0
- data/public/javascripts/lang-llvm.js +1 -0
- data/public/javascripts/lang-lua.js +2 -0
- data/public/javascripts/lang-matlab.js +6 -0
- data/public/javascripts/lang-ml.js +2 -0
- data/public/javascripts/lang-mumps.js +2 -0
- data/public/javascripts/lang-n.js +4 -0
- data/public/javascripts/lang-pascal.js +3 -0
- data/public/javascripts/lang-proto.js +1 -0
- data/public/javascripts/lang-r.js +2 -0
- data/public/javascripts/lang-rd.js +1 -0
- data/public/javascripts/lang-scala.js +2 -0
- data/public/javascripts/lang-sql.js +2 -0
- data/public/javascripts/lang-tcl.js +3 -0
- data/public/javascripts/lang-tex.js +1 -0
- data/public/javascripts/lang-vb.js +2 -0
- data/public/javascripts/lang-vhdl.js +3 -0
- data/public/javascripts/lang-wiki.js +2 -0
- data/public/javascripts/lang-xq.js +3 -0
- data/public/javascripts/lang-yaml.js +2 -0
- data/public/javascripts/prettify.js +30 -0
- data/public/javascripts/run_prettify.js +34 -0
- data/public/stylesheets/bootstrap.min.css +7 -0
- data/public/stylesheets/bootstrap.min.css.vanilla +5 -0
- data/public/stylesheets/gitrob.css +88 -0
- data/public/stylesheets/prettify.css +51 -0
- data/spec/lib/gitrob/observers/sensitive_files_spec.rb +558 -0
- data/spec/spec_helper.rb +127 -0
- data/views/blob.erb +22 -0
- data/views/index.erb +32 -0
- data/views/layout.erb +30 -0
- data/views/organization.erb +126 -0
- data/views/repository.erb +51 -0
- data/views/user.erb +51 -0
- metadata +317 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2644a28d02e265e64b4217080b1b3dece92f499d
|
4
|
+
data.tar.gz: e6540cad01070d9bc0c7329c90e70ce0f498b53b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: df03cc1140011bfacab7d828b31af4c2ed62acd3d86ffbdaf1ab33c40a5ba580b1aaac24b2cef43ba400926c9d2f108a6439474a311fe6554db49fc0cce6437e
|
7
|
+
data.tar.gz: 772f06c99dd5b3c3012e676629fad0cdfc0478f3dfa0e066647828adb910a32b13b0be1314143389a7520295a29223624a1698da5fe6c07450462026df29f682
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Michael Henriksen
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# Gitrob
|
2
|
+
|
3
|
+
Developers generally like to share their code, and many of them do so by open sourcing it on GitHub, a social code hosting and collaboration service. Many companies also use GitHub as a convenient place to host both private and public code repositories by creating GitHub organizations where employees can be joined.
|
4
|
+
|
5
|
+
Sometimes employees might publish things that should not be publicly available, things that contain sensitive information or things that could even lead to direct compromise of a system. This can happen by accident or because the employee does not know the sensitivity of the information.
|
6
|
+
|
7
|
+
Gitrob is a command line tool that can help organizations and security professionals find such sensitive information. The tool will iterate over all public organization and member repositories and match filenames against a range of patterns for files, that typically contain sensitive or dangerous information.
|
8
|
+
|
9
|
+
Read the [blog post](http://michenriksen.com/blog/gitrob-putting-the-open-source-in-osint/) for more information and screenshots.
|
10
|
+
|
11
|
+
## How it works
|
12
|
+
|
13
|
+
Looking for sensitive information in GitHub repositories is not a new thing, it has been [known for a while](http://blog.conviso.com.br/2013/06/github-hacking-for-fun-and-sensitive.html) that things such as private keys and credentials can be found with GitHub's search functionality, however Gitrob makes it easier to focus the effort on a specific organization.
|
14
|
+
|
15
|
+
The first thing the tool does is to collect all public repositories of the organization itself. It then goes on to collect all the organization members and their public repositories, in order to compile a list of repositories that might be related or have relevance to the organization.
|
16
|
+
|
17
|
+
When the list of repositories has been compiled, it proceeds to gather all the filenames in each repository and runs them through a series of observers that will flag the files, if they match any patterns of known sensitive files. This step might take a while if the organization is big or if the members have a lot of public repositories.
|
18
|
+
|
19
|
+
All of the members, repositories and files will be saved to a PostgreSQL database. When everything has been sifted through, it will start a Sinatra web server locally on the machine, which will serve a simple web application to present the collected data for analysis.
|
20
|
+
|
21
|
+
## Installation
|
22
|
+
|
23
|
+
Gitrob is written in Ruby and requires at least version 1.9.3 or above. If you are on an older version, it is very easy to install newer versions with [RVM](http://rvm.io/). If you are installing Gitrob on [Kali](http://www.kali.org/), you are almost good to go, you just need to update Bundler with `gem install bundler` and install a PostgreSQL dependency with `apt-get install libpq-dev` in a terminal.
|
24
|
+
|
25
|
+
Gitrob is a Ruby gem, so installation is a simple `gem install gitrob` in a terminal. This will automatically install all the code dependencies as well.
|
26
|
+
|
27
|
+
A [PostgreSQL](http://www.postgresql.org/) database is also needed for Gitrob to store its data. Installing PostgreSQL is pretty straight forward; here is an installation guide for [Mac OS X](http://www.gotealeaf.com/blog/how-to-install-postgresql-on-a-mac) and one for [Ubuntu/Debian](https://www.digitalocean.com/community/tutorials/how-to-install-and-use-postgresql-on-ubuntu-14-04) based Linux. If you're installing Gitrob on Kali, you already have PostgreSQL installed, however you need to start the server with `service postgresql start` in a terminal.
|
28
|
+
|
29
|
+
The last thing we need is a GitHub access token in order to be able to talk to their API. The easiest way is to create a [personal access token](https://github.com/settings/applications). If you plan on using Gitrob extensively or on a very big organization, it might be necessary to have multiple access tokens to prevent running into rate limiting, but they need to be from different user accounts.
|
30
|
+
|
31
|
+
When everything is ready, simply run `gitrob --configure` and you will be presented with a configuration wizard that asks you for database connection details and GitHub access tokens. All of this configuration can be changed by running the same command again. The configuration will be saved in `~/.gitrobrc` - and yes, Gitrob is looking for this file too so watch out.
|
32
|
+
|
33
|
+
When everything is set up, you can start analyzing organizations by running `gitrob -o <orgname>` in a terminal. To see options, use `gitrob --help`.
|
34
|
+
|
35
|
+
## Contributing
|
36
|
+
|
37
|
+
Gitrob should be considered Beta and there is probably a good amount of bugs. Bug reports and suggestions for improvements are welcome!
|
38
|
+
|
39
|
+
Another way to help out is to contribute new patterns for sensitive files. If you know of any sensitive files that are not already identified, please submit them in a pull request. I am especially interested in sensitive web framework files and configuration files. Have a look at the [patterns.json](https://github.com/michenriksen/gitrob/blob/master/patterns.json) file to see what is already looked for.
|
40
|
+
|
41
|
+
### How to make a pull request:
|
42
|
+
|
43
|
+
1. Fork it ( https://github.com/michenriksen/gitrob/fork )
|
44
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
45
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
46
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
47
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/bin/gitrob
ADDED
@@ -0,0 +1,258 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# coding: utf-8
|
3
|
+
|
4
|
+
require 'gitrob'
|
5
|
+
|
6
|
+
class App
|
7
|
+
include Methadone::Main
|
8
|
+
|
9
|
+
leak_exceptions true
|
10
|
+
|
11
|
+
main do
|
12
|
+
Thread.abort_on_exception = true
|
13
|
+
Paint.mode = 0 if options.include?('no-color')
|
14
|
+
|
15
|
+
puts Paint[Gitrob::banner, :bright, :blue] unless options.include?('no-banner')
|
16
|
+
Gitrob::status("Starting Gitrob version #{Gitrob::VERSION} at #{Time.now.strftime("%Y-%m-%d %I:%S %Z")}")
|
17
|
+
|
18
|
+
if !Gitrob::agreement_accepted?
|
19
|
+
puts Gitrob::agreement
|
20
|
+
print Paint["\n\nDo you agree to the terms of use? [y/n]: ", :bright, :green]
|
21
|
+
choice = $stdin.gets.chomp
|
22
|
+
if %w{y yes}.include?(choice)
|
23
|
+
Gitrob::agreement_accepted
|
24
|
+
else
|
25
|
+
Gitrob::fatal("Exiting Gitrob.")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
if !Gitrob::configured? || options.include?('configure')
|
30
|
+
Gitrob::status("Starting Gitrob configuration wizard\n\n")
|
31
|
+
|
32
|
+
hostname = ask("#{Paint[" Enter PostgreSQL hostname:", :bright, :white]} ") { |q| q.default = "localhost" }
|
33
|
+
port = ask("#{Paint[" Enter PostgreSQL port:", :bright, :white]} ", Integer) { |q| q.default = 5432; q.in = 1..65535 }
|
34
|
+
username = ask("#{Paint[" Enter PostgreSQL username:", :bright, :white]} ")
|
35
|
+
password = ask("#{Paint[" Enter PostgreSQL password for #{username} (masked):", :bright, :white]} ") { |q| q.echo = 'x' }
|
36
|
+
database = ask("#{Paint[" Enter PostgreSQL database name:", :bright, :white]} ") { |q| q.default = 'gitrob' }
|
37
|
+
|
38
|
+
access_tokens = Array.new
|
39
|
+
while access_tokens.uniq.empty?
|
40
|
+
access_tokens = ask(Paint[" Enter GitHub access tokens (blank line to stop):", :bright, :white],
|
41
|
+
lambda { |ans| ans =~ /[a-f0-9]{40}/ ? ans : nil } ) do |q|
|
42
|
+
q.gather = ""
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
config = {
|
47
|
+
'sql_connection_uri' => "postgres://#{username}:#{password}@#{hostname}:#{port}/#{database}",
|
48
|
+
'github_access_tokens' => access_tokens.uniq
|
49
|
+
}
|
50
|
+
|
51
|
+
Gitrob::task("Saving configuration to file...") do
|
52
|
+
Gitrob::save_configuration!(config)
|
53
|
+
end
|
54
|
+
|
55
|
+
exit unless options['organization']
|
56
|
+
end
|
57
|
+
|
58
|
+
Gitrob::task("Loading configuration...") do
|
59
|
+
Gitrob::load_configuration!
|
60
|
+
end
|
61
|
+
|
62
|
+
Gitrob::task("Preparing SQL database...") do
|
63
|
+
Gitrob::prepare_database!
|
64
|
+
end
|
65
|
+
|
66
|
+
if options['reset-db']
|
67
|
+
Gitrob::task("Resetting database tables...") do
|
68
|
+
DataMapper::auto_migrate!
|
69
|
+
end
|
70
|
+
exit
|
71
|
+
end
|
72
|
+
|
73
|
+
if options['delete']
|
74
|
+
Gitrob::delete_organization(options['delete'])
|
75
|
+
exit
|
76
|
+
end
|
77
|
+
|
78
|
+
if options['start-server']
|
79
|
+
Gitrob::status("Starting web application on http://#{options['bind-address']}:#{options['port']}/...")
|
80
|
+
puts "\n\n"
|
81
|
+
Gitrob::WebApp.run!(:port => options['port'].to_i, :bind => options['bind-address'])
|
82
|
+
exit
|
83
|
+
end
|
84
|
+
|
85
|
+
org_name = options['organization']
|
86
|
+
repo_count = 0
|
87
|
+
members = Array.new
|
88
|
+
http_client = Gitrob::Github::HttpClient.new({:access_tokens => Gitrob::configuration['github_access_tokens']})
|
89
|
+
observers = Gitrob::Observers.constants.collect { |c| Gitrob::Observers::const_get(c) }
|
90
|
+
|
91
|
+
Gitrob::task("Loading file patterns...") do
|
92
|
+
Gitrob::Observers::SensitiveFiles::load_patterns!
|
93
|
+
end
|
94
|
+
|
95
|
+
begin
|
96
|
+
org = Gitrob::Github::Organization.new(org_name, http_client)
|
97
|
+
|
98
|
+
Gitrob::delete_organization(org.login)
|
99
|
+
|
100
|
+
Gitrob::task("Collecting organization repositories...") do
|
101
|
+
repo_count = org.repositories.count
|
102
|
+
end
|
103
|
+
rescue Gitrob::Github::HttpClient::ClientError => e
|
104
|
+
if e.status == 404
|
105
|
+
Gitrob::fatal("Cannot find GitHub organization with that name; exiting.")
|
106
|
+
else
|
107
|
+
raise e
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
Gitrob::task("Collecting organization members...") do
|
112
|
+
members = org.members
|
113
|
+
end
|
114
|
+
|
115
|
+
progress = Gitrob::ProgressBar.new("Collecting member repositories...",
|
116
|
+
:total => members.count
|
117
|
+
)
|
118
|
+
thread_pool = Thread.pool(options['threads'].to_i)
|
119
|
+
|
120
|
+
members.each do |member|
|
121
|
+
thread_pool.process do
|
122
|
+
if member.repositories.count > 0
|
123
|
+
repo_count += member.repositories.count
|
124
|
+
progress.log("Collected #{Gitrob::Util::pluralize(member.repositories.count, 'repository', 'repositories')} from #{Paint[member.username, :bright, :white]}")
|
125
|
+
end
|
126
|
+
progress.increment
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
thread_pool.shutdown
|
131
|
+
|
132
|
+
if repo_count.zero?
|
133
|
+
Gitrob::fatal("Organization has no repositories to check; exiting.")
|
134
|
+
end
|
135
|
+
|
136
|
+
progress = Gitrob::ProgressBar.new("Processing repositories...",
|
137
|
+
:total => repo_count
|
138
|
+
)
|
139
|
+
|
140
|
+
db_org = org.save_to_database!
|
141
|
+
thread_pool = Thread.pool(options['threads'].to_i)
|
142
|
+
|
143
|
+
org.repositories.each do |repo|
|
144
|
+
thread_pool.process do
|
145
|
+
begin
|
146
|
+
if repo.contents.count > 0
|
147
|
+
db_repo = repo.save_to_database!(db_org)
|
148
|
+
findings = 0
|
149
|
+
|
150
|
+
repo.contents.each do |blob|
|
151
|
+
db_blob = blob.to_model(db_org, db_repo)
|
152
|
+
|
153
|
+
observers.each do |observer|
|
154
|
+
observer.observe(db_blob)
|
155
|
+
end
|
156
|
+
|
157
|
+
db_blob.findings.each do |f|
|
158
|
+
db_blob.findings_count += 1
|
159
|
+
findings += 1
|
160
|
+
f.organization = db_org
|
161
|
+
f.repo = db_repo
|
162
|
+
end
|
163
|
+
|
164
|
+
db_blob.save
|
165
|
+
end
|
166
|
+
progress.log("Processed #{Gitrob::Util::pluralize(repo.contents.count, 'file', 'files')} from #{Paint[repo.full_name, :bright, :white]} with #{findings.zero? ? 'no findings' : Paint[Gitrob::Util.pluralize(findings, 'finding', 'findings'), :yellow]}")
|
167
|
+
end
|
168
|
+
progress.increment
|
169
|
+
rescue Exception => e
|
170
|
+
progress.log_error("Encountered error when processing #{Paint[repo.full_name, :bright, :white]} (#{e.class.name})")
|
171
|
+
progress.increment
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
org.members.each do |member|
|
177
|
+
thread_pool.process do
|
178
|
+
begin
|
179
|
+
db_user = member.save_to_database!(db_org)
|
180
|
+
|
181
|
+
member.repositories.each do |repo|
|
182
|
+
if repo.contents.count > 0
|
183
|
+
db_repo = repo.save_to_database!(db_org, db_user)
|
184
|
+
findings = 0
|
185
|
+
|
186
|
+
repo.contents.each do |blob|
|
187
|
+
db_blob = blob.to_model(db_org, db_repo)
|
188
|
+
|
189
|
+
observers.each do |observer|
|
190
|
+
observer.observe(db_blob)
|
191
|
+
end
|
192
|
+
|
193
|
+
db_blob.findings.each do |f|
|
194
|
+
db_blob.findings_count += 1
|
195
|
+
findings += 1
|
196
|
+
f.organization = db_org
|
197
|
+
f.repo = db_repo
|
198
|
+
f.user = db_user
|
199
|
+
end
|
200
|
+
|
201
|
+
db_blob.save
|
202
|
+
end
|
203
|
+
progress.log("Processed #{Gitrob::Util::pluralize(repo.contents.count, 'file', 'files')} from #{Paint[repo.full_name, :bright, :white]} with #{findings.zero? ? 'no findings' : Paint[Gitrob::Util.pluralize(findings, 'finding', 'findings'), :yellow]}")
|
204
|
+
end
|
205
|
+
progress.increment
|
206
|
+
end
|
207
|
+
rescue Exception => e
|
208
|
+
progress.log_error("Encountered error when processing #{Paint[repo.full_name, :bright, :white]} (#{e.class.name})")
|
209
|
+
progress.increment
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
thread_pool.shutdown
|
215
|
+
|
216
|
+
if !options.include?('no-server')
|
217
|
+
Gitrob::status("Starting web application on port #{options['port']}...")
|
218
|
+
Gitrob::status("Browse to http://#{options['bind-address']}:#{options['port']}/ to see results!")
|
219
|
+
puts "\n\n"
|
220
|
+
Gitrob::WebApp.run!(:port => options[:port].to_i, :bind => options['bind-address'])
|
221
|
+
exit
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
version Gitrob::VERSION
|
226
|
+
description "Reconnaissance tool for GitHub organizations."
|
227
|
+
|
228
|
+
options['bind-address'] = '127.0.0.1'
|
229
|
+
options['port'] = 9393
|
230
|
+
options['threads'] = 3
|
231
|
+
|
232
|
+
on('-o', '--organization NAME', "Name of GitHub organization")
|
233
|
+
on('-s', '--start-server', "Start web server, don't run any checks")
|
234
|
+
on('-p', '--port PORT', "Port to bind web server to")
|
235
|
+
on('-b', '--bind-address ADDRESS', "Address to bind web server to")
|
236
|
+
on('-t', '--threads THREADS', "Number of threads to use")
|
237
|
+
on('--delete NAME', "Delete an organization in the database")
|
238
|
+
on('--reset-db', "Resets the database")
|
239
|
+
on('--configure', "Start configuration wizard")
|
240
|
+
on('--no-server', "Don't start the server when finished")
|
241
|
+
on('--no-color', "Don't colorize output")
|
242
|
+
on('--no-banner', "Don't print Gitrob banner")
|
243
|
+
|
244
|
+
begin
|
245
|
+
go!
|
246
|
+
rescue Gitrob::Github::HttpClient::MissingAccessTokensError
|
247
|
+
Gitrob::fatal("Configuration file does not contain any GitHub access tokens. Run Gitrob with --configure flag to set it up.")
|
248
|
+
rescue Gitrob::Github::HttpClient::AccessTokensDepletedError
|
249
|
+
Gitrob::fatal("All GitHub access tokens under rate limiting. Go have a cup of coffee and try again.")
|
250
|
+
rescue Gitrob::Github::HttpClient::RequestError => e
|
251
|
+
Gitrob::fatal("A request to the GitHub API failed: #{e.message}")
|
252
|
+
rescue Interrupt
|
253
|
+
print "\b\b\n"; # Remove ^C from screen
|
254
|
+
Gitrob::fatal("Caught interrupt; exiting.")
|
255
|
+
rescue => e
|
256
|
+
Gitrob::fatal("An error occurred: #{e.class.name}: #{e.message}")
|
257
|
+
end
|
258
|
+
end
|
data/gitrob.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'gitrob/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "gitrob"
|
8
|
+
spec.version = Gitrob::VERSION
|
9
|
+
spec.authors = ["Michael Henriksen"]
|
10
|
+
spec.email = ["michenriksen@neomailbox.ch"]
|
11
|
+
spec.summary = %q{Reconnaissance tool for GitHub organizations.}
|
12
|
+
spec.description = %q{Reconnaissance tool for GitHub organizations.}
|
13
|
+
spec.homepage = "https://github.com/michenriksen/gitrob"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "httparty", "~> 0.13"
|
22
|
+
spec.add_dependency "methadone", "~> 1.7"
|
23
|
+
spec.add_dependency "highline", "~> 1.6"
|
24
|
+
spec.add_dependency "paint", "~> 0.8"
|
25
|
+
spec.add_dependency "ruby-progressbar", "~> 1.6"
|
26
|
+
spec.add_dependency "thread", "~> 0.1"
|
27
|
+
spec.add_dependency "sinatra", "~> 1.4"
|
28
|
+
spec.add_dependency "thin", "~> 1.6"
|
29
|
+
spec.add_dependency "datamapper", "~> 1.2"
|
30
|
+
spec.add_dependency "dm-postgres-adapter"
|
31
|
+
|
32
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
33
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
34
|
+
spec.add_development_dependency "rspec", "~> 3.1"
|
35
|
+
spec.add_development_dependency "webmock", "~> 1.20"
|
36
|
+
end
|
data/lib/gitrob.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'cgi'
|
3
|
+
|
4
|
+
require 'methadone'
|
5
|
+
require 'highline/import'
|
6
|
+
require 'thread/pool'
|
7
|
+
require 'httparty'
|
8
|
+
require 'ruby-progressbar'
|
9
|
+
require 'paint'
|
10
|
+
require 'sinatra/base'
|
11
|
+
require 'data_mapper'
|
12
|
+
|
13
|
+
require 'gitrob/version'
|
14
|
+
require 'gitrob/util'
|
15
|
+
require 'gitrob/progressbar'
|
16
|
+
require 'gitrob/github/http_client'
|
17
|
+
require 'gitrob/github/repository'
|
18
|
+
require 'gitrob/github/blob'
|
19
|
+
require 'gitrob/github/organization'
|
20
|
+
require 'gitrob/github/user'
|
21
|
+
require 'gitrob/observers/sensitive_files'
|
22
|
+
require 'gitrob/webapp'
|
23
|
+
|
24
|
+
require "#{File.dirname(__FILE__)}/../models/organization"
|
25
|
+
require "#{File.dirname(__FILE__)}/../models/repo"
|
26
|
+
require "#{File.dirname(__FILE__)}/../models/user"
|
27
|
+
require "#{File.dirname(__FILE__)}/../models/blob"
|
28
|
+
require "#{File.dirname(__FILE__)}/../models/finding"
|
29
|
+
|
30
|
+
module Gitrob
|
31
|
+
def self.task(message)
|
32
|
+
print " #{Paint['[*]', :bright, :blue]} #{Paint[message, :bright, :white]}"
|
33
|
+
yield
|
34
|
+
puts Paint[" done", :bright, :green]
|
35
|
+
rescue => e
|
36
|
+
puts Paint[" failed", :bright, :red]
|
37
|
+
puts "#{Paint[' [!]', :bright, :red]} #{Paint[e.class, :bright, :white]}: #{e.message}"
|
38
|
+
exit!
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.status(message)
|
42
|
+
puts " #{Paint['[*]', :bright, :blue]} #{Paint[message, :bright, :white]}"
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.fatal(message)
|
46
|
+
puts " #{Paint['[!]', :bright, :red]} #{Paint[message, :bright, :white]}"
|
47
|
+
exit!
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.prepare_database!
|
51
|
+
DataMapper::Model.raise_on_save_failure = true
|
52
|
+
DataMapper::Property.auto_validation(false)
|
53
|
+
DataMapper.setup(:default, configuration['sql_connection_uri'])
|
54
|
+
DataMapper.finalize
|
55
|
+
DataMapper.auto_upgrade!
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.delete_organization(org)
|
59
|
+
orgs = Gitrob::Organization.all(:login => org)
|
60
|
+
if orgs.count > 0
|
61
|
+
task("Deleting existing #{org} organization...") do
|
62
|
+
orgs.destroy
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.agreement_accepted?
|
68
|
+
File.exists?("#{File.dirname(__FILE__)}/../agreement")
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.agreement
|
72
|
+
"\n#{self.license}\n\n" +
|
73
|
+
|
74
|
+
Paint["Gitrob is designed for security professionals. If you use any information\n" +
|
75
|
+
"found through this tool for malicious purposes that are not authorized by\n" +
|
76
|
+
"the organization, you are violating the terms of use and license of this\n" +
|
77
|
+
"tool. By typing y/yes, you agree to the terms of use and that you will use\n" +
|
78
|
+
"this tool for lawful purposes only.",
|
79
|
+
:bright, :red]
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.agreement_accepted
|
83
|
+
File.open("#{File.dirname(__FILE__)}/../agreement", 'w') { |file| file.write("user accepted") }
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.license
|
87
|
+
File.read("#{File.dirname(__FILE__)}/../LICENSE.txt")
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.configured?
|
91
|
+
File.exists?("#{Dir.home}/.gitrobrc")
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.configuration
|
95
|
+
@config ||= load_configuration!
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.load_configuration!
|
99
|
+
YAML.load_file("#{Dir.home}/.gitrobrc")
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.save_configuration!(config)
|
103
|
+
@config = config
|
104
|
+
File.open("#{Dir.home}/.gitrobrc", 'w') { |f| f.write YAML.dump(config) }
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.banner
|
108
|
+
<<-BANNER
|
109
|
+
_ _ _
|
110
|
+
___|_| |_ ___ ___| |_
|
111
|
+
| . | | _| _| . | . |
|
112
|
+
|_ |_|_| |_| |___|___|
|
113
|
+
|___| #{Paint["By @michenriksen", :bright, :white]}
|
114
|
+
BANNER
|
115
|
+
end
|
116
|
+
end
|