├── VERSION ├── cert └── .blank ├── logs ├── .blank └── jobs │ └── .blank ├── control ├── tmp │ └── .blank ├── analysis │ └── .blank ├── hashes │ └── .blank ├── outfiles │ └── .blank ├── status │ └── .blank ├── wordlists │ ├── .blank │ └── password.gz └── rules │ ├── toggles1.rule │ ├── leetspeak.rule │ ├── hob064.rule │ ├── combinator.rule │ ├── toggles2.rule │ ├── best64.rule │ ├── LowUtil.rule │ ├── specific.rule │ ├── oscommerce.rule │ ├── T0XlC-insert_space_and_special_0_F.rule │ └── toggles3.rule ├── hashes └── demo_hash_list.txt ├── .eslintignore ├── public ├── css │ ├── bootstrap-cust.css │ ├── jquery.bs_pagination.min.css │ ├── jquery.bs_grid.min.css │ ├── hashviewStyle.css │ ├── jquery.bs_grid.css │ ├── jquery.jui_filter_rules.bs.min.css │ └── jquery.bs_grid.bs2.css ├── img │ ├── glyphicons-halflings.png │ └── glyphicons-halflings-white.png ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 ├── bootstrap-3.3.4-dist │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ └── glyphicons-halflings-regular.woff2 │ └── js │ │ └── npm.js ├── js │ ├── mapload.js │ ├── modules.js │ ├── npm.js │ ├── en.min.js │ └── jui_filter_rules │ │ └── localization │ │ └── en.min.js └── oclHashcat.log ├── tests └── fakehashcat.bin ├── .csslintrc ├── config.ru ├── main.rb ├── helpers ├── test_helper.rb ├── tasks.rb ├── init.rb ├── sessions.rb ├── sanitization.rb ├── hc_stdout_parser.rb ├── sinatra_ssl.rb ├── email.rb ├── compute_task_keyspace.rb ├── smartWordlist.rb ├── cracked_importer.rb ├── status.rb └── build_crack_cmd.rb ├── config ├── agent_config.travis.json ├── database.travis.yml ├── database.yml.example └── resque_schedule.yml ├── jobs ├── init.rb ├── wordlistChecksum.rb ├── ruleImporter.rb ├── clean_up.rb └── wordlistImporter.rb ├── Procfile ├── views ├── upload_single.haml ├── agent_edit.haml ├── job_hub_permission_check.haml ├── login.haml ├── wordlist_add.haml ├── search.haml ├── account_list.haml ├── verify_filetypes.haml ├── register.haml ├── job_hub_check.haml ├── job_local_check.haml ├── wordlist_list.haml ├── customer_edit.haml ├── hashfile_list.haml ├── assign_tasks.haml ├── hub.haml ├── verify_hashtypes.haml ├── customer_list.haml ├── search_post.haml ├── account_edit.haml ├── layout.haml ├── task_list.haml ├── rule_list.haml ├── job_edit.haml ├── agent_list.haml └── job_list.haml ├── routes ├── init.rb ├── agents.rb ├── register.rb ├── hashfiles.rb ├── login.rb ├── wordlists.rb ├── accounts.rb ├── rules.rb ├── main.rb ├── downloads.rb └── tasks.rb ├── .travis.yml ├── Gemfile ├── .gitignore ├── .codeclimate.yml ├── README.md ├── hashview.rb ├── models └── master.rb ├── .eslintrc ├── db └── migrations │ └── 001_sequel.rb └── Gemfile.lock /VERSION: -------------------------------------------------------------------------------- 1 | 0.7.3 -------------------------------------------------------------------------------- /cert/.blank: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /logs/.blank: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /control/tmp/.blank: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /logs/jobs/.blank: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /control/analysis/.blank: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /control/hashes/.blank: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /control/outfiles/.blank: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /control/status/.blank: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /control/wordlists/.blank: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /hashes/demo_hash_list.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | **/*{.,-}min.js 2 | -------------------------------------------------------------------------------- /public/css/bootstrap-cust.css: -------------------------------------------------------------------------------- 1 | .chooseFile{ 2 | 3 | } 4 | -------------------------------------------------------------------------------- /tests/fakehashcat.bin: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | echo "fake hashcat binary" 3 | -------------------------------------------------------------------------------- /control/wordlists/password.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-Cyberdefense/hashview/HEAD/control/wordlists/password.gz -------------------------------------------------------------------------------- /.csslintrc: -------------------------------------------------------------------------------- 1 | --exclude-exts=.min.css 2 | --ignore=adjoining-classes,box-model,ids,order-alphabetical,unqualified-attributes 3 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | #root = ::File.dirname(__FILE__) 2 | #require ::File.join( root, 'hashview' ) 3 | require './hashview' 4 | run HashView 5 | -------------------------------------------------------------------------------- /public/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-Cyberdefense/hashview/HEAD/public/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /main.rb: -------------------------------------------------------------------------------- 1 | puts "\nIMPORTANT NOTE:\nas of 0.5.1-beta hashview is ran with the following command:\n 2 | RACK_ENV=production ruby hashview.rb\n\n" 3 | -------------------------------------------------------------------------------- /public/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-Cyberdefense/hashview/HEAD/public/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-Cyberdefense/hashview/HEAD/public/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-Cyberdefense/hashview/HEAD/public/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-Cyberdefense/hashview/HEAD/public/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-Cyberdefense/hashview/HEAD/public/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /control/rules/toggles1.rule: -------------------------------------------------------------------------------- 1 | T0 2 | T1 3 | T2 4 | T3 5 | T4 6 | T5 7 | T6 8 | T7 9 | T8 10 | T9 11 | TA 12 | TB 13 | TC 14 | TD 15 | TE 16 | -------------------------------------------------------------------------------- /helpers/test_helper.rb: -------------------------------------------------------------------------------- 1 | # test_helper.rb 2 | require 'minitest/autorun' 3 | require 'rack/test' 4 | require 'factory_girl' 5 | 6 | require File.expand_path '../../hashview.rb', __FILE__ -------------------------------------------------------------------------------- /public/bootstrap-3.3.4-dist/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-Cyberdefense/hashview/HEAD/public/bootstrap-3.3.4-dist/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /public/bootstrap-3.3.4-dist/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-Cyberdefense/hashview/HEAD/public/bootstrap-3.3.4-dist/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /public/bootstrap-3.3.4-dist/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-Cyberdefense/hashview/HEAD/public/bootstrap-3.3.4-dist/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /public/bootstrap-3.3.4-dist/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-Cyberdefense/hashview/HEAD/public/bootstrap-3.3.4-dist/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /config/agent_config.travis.json: -------------------------------------------------------------------------------- 1 | { 2 | "ip": "127.0.0.1", 3 | "port": "4567", 4 | "uuid": "0cea5500-cc00-0000-b000-bb9946644000", 5 | "hc_binary_path": "tests/fakehashcat.bin", 6 | "type": "master" 7 | } 8 | -------------------------------------------------------------------------------- /jobs/init.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | require_relative 'wordlistImporter' 3 | require_relative 'background_worker' 4 | require_relative 'wordlistChecksum' 5 | require_relative 'clean_up' 6 | require_relative 'ruleImporter' -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | redis: redis-server 2 | mgmt-worker: TERM_CHILD=1 COUNT=5 QUEUE=management rake resque:workers 3 | hashcat-worker: TERM_CHILD=1 COUNT=1 QUEUE=hashcat rake resque:work 4 | background-worker: QUEUE=* rake resque:scheduler 5 | web: ruby ./hashview.rb 6 | -------------------------------------------------------------------------------- /helpers/tasks.rb: -------------------------------------------------------------------------------- 1 | helpers do 2 | def assignTasksToJob(tasks, job_id) 3 | tasks.each do |task_id| 4 | jobtask = Jobtasks.new 5 | jobtask.job_id = job_id 6 | jobtask.task_id = task_id 7 | jobtask.save 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /public/css/jquery.bs_pagination.min.css: -------------------------------------------------------------------------------- 1 | .row-space{margin-top:15px !important}.pagination_custom{margin:0}.small-input{width:50px !important}@media(min-width:768px){.row-space{margin-top:15px !important}}@media(min-width:992px){.row-space{margin-top:0 !important}}@media(min-width:1200px){.row-space{margin-top:0 !important}} -------------------------------------------------------------------------------- /public/js/mapload.js: -------------------------------------------------------------------------------- 1 | var map; 2 | function initialize() { 3 | var mapOptions = { 4 | zoom: 8, 5 | center: new google.maps.LatLng(-34.397, 150.644) 6 | }; 7 | map = new google.maps.Map(document.getElementById('map-canvas'), 8 | mapOptions); 9 | } 10 | 11 | google.maps.event.addDomListener(window, 'load', initialize); 12 | 13 | -------------------------------------------------------------------------------- /helpers/init.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | require_relative 'email' 3 | require_relative 'hashimporter' 4 | require_relative 'hc_stdout_parser' 5 | require_relative 'sinatra_ssl' 6 | require_relative 'sessions' 7 | require_relative 'status' 8 | require_relative 'sanitization' 9 | require_relative 'build_crack_cmd' 10 | require_relative 'tasks' 11 | require_relative 'cracked_importer' 12 | require_relative 'compute_task_keyspace' 13 | require_relative 'smartWordlist' -------------------------------------------------------------------------------- /config/database.travis.yml: -------------------------------------------------------------------------------- 1 | production: 2 | adapter: mysql 3 | host: "localhost" 4 | port: 3306 5 | user: "root" 6 | password: "" 7 | database: "hashview" 8 | 9 | development: 10 | adapter: mysql 11 | host: "localhost" 12 | port: 3306 13 | user: "root" 14 | password: "" 15 | database: "hashview_dev" 16 | 17 | test: 18 | adapter: mysql 19 | host: "localhost" 20 | port: 3306 21 | user: "root" 22 | password: "" 23 | database: "hashview_test" 24 | -------------------------------------------------------------------------------- /helpers/sessions.rb: -------------------------------------------------------------------------------- 1 | helpers do 2 | # Return if the user has a valid session or not 3 | def validSession? 4 | Sessions.isValid?(session[:session_id]) 5 | end 6 | 7 | # Get the current users, username 8 | def getUsername 9 | Sessions.getUsername(session[:session_id]) 10 | end 11 | 12 | def agentAuthorized(uuid) 13 | auth = Agents.exclude(Sequel.like(:status, 'Pending')).where(:uuid => uuid).first 14 | 15 | auth ? true : false 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /control/rules/leetspeak.rule: -------------------------------------------------------------------------------- 1 | ## rule: leetspeak single 2 | ## limits: none 3 | ## example: john ---> j0hn 4 | ## extras: case original, lower, upper 5 | 6 | sa4 7 | sa@ 8 | sb6 9 | sc< 10 | sc{ 11 | se3 12 | sg9 13 | si1 14 | si! 15 | so0 16 | sq9 17 | ss5 18 | ss$ 19 | st7 20 | st+ 21 | sx% 22 | 23 | ## rule: leetspeak multi 24 | ## limits: none 25 | ## example: johnbox ---> j0hnbox 26 | ## extras: all case variants 27 | 28 | sa@sc 1.4.7' 16 | gem 'sinatra-flash' 17 | gem 'haml' 18 | gem 'data_mapper' 19 | gem 'sequel' 20 | gem 'data_objects' 21 | gem 'redis' 22 | gem 'resque' 23 | gem 'resque-scheduler' 24 | gem 'resque-web' 25 | gem 'json' 26 | gem 'pony' 27 | gem 'bcrypt' 28 | gem 'mysql' 29 | gem 'foreman' 30 | gem 'rest-client' 31 | #gem 'digest' 32 | gem 'logger' 33 | 34 | 35 | -------------------------------------------------------------------------------- /helpers/sanitization.rb: -------------------------------------------------------------------------------- 1 | helpers do 2 | # Take you to the var wash baby 3 | def varWash(params) 4 | params.keys.each do |key| 5 | params[key] = cleanString(params[key]) if params[key].is_a?(String) 6 | params[key] = cleanArray(params[key]) if params[key].is_a?(Array) 7 | end 8 | end 9 | 10 | def cleanString(text) 11 | return text.gsub(/[<>'"()\/\\;#&]*/i, '') unless text.nil? 12 | end 13 | 14 | def cleanArray(array) 15 | clean_array = [] 16 | array.each do |entry| 17 | clean_array.push(cleanString(entry)) 18 | end 19 | clean_array 20 | end 21 | 22 | end 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | db/master.db 2 | config/database.yml 3 | cert/* 4 | !cert/.blank 5 | .DS_Store 6 | *.swp 7 | *.swo 8 | config/agent_config.json 9 | config/hub_config.json 10 | control/outfiles/* 11 | !control/outfiles/.blank 12 | control/hashes/* 13 | !control/hashes/.blank 14 | control/analysis/* 15 | !control/analysis/.blank 16 | control/status/* 17 | !control/status/.blank 18 | control/wordlists/* 19 | !control/wordlists/.blank 20 | !control/wordlists/password.gz 21 | control/tmp/* 22 | !control/tmp/.blank 23 | logs/*.log 24 | !logs/.blank 25 | logs/jobs/* 26 | !logs/jobs/.blank 27 | *.pot 28 | *.restore 29 | *.idea 30 | dump.rdb 31 | -------------------------------------------------------------------------------- /public/css/jquery.bs_grid.min.css: -------------------------------------------------------------------------------- 1 | /* 2 | * bs_grid v0.9.2 CSS ********************************************************** 3 | * Minified using http://gpbmike.github.io/refresh-sf/ 4 | */ 5 | .tools{height:38px}.col-checkbox{margin-top:0 !important}.columns-label{margin-top:3px;margin-bottom:3px;font-weight:normal}.columns-li-padding{padding:3px 20px}.sorting-name{display:inline-block;padding-left:20px;margin-top:3px;margin-bottom:3px;vertical-align:middle}.selected-rows{margin-left:5px;margin-right:2px;text-align:right}.th-common{cursor:pointer}.no-records-found{text-align:center}.pagination-container{padding:7px 7px 5px 7px !important}.filters-container{padding:0 7px 10px 7px !important}.filters-button{margin:0 3px} -------------------------------------------------------------------------------- /views/agent_edit.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | %body 4 | %p 5 | .span15 6 | %br 7 | .container 8 | - if @agent 9 | %h2 Edit an Existing Agent 10 | %br 11 | .row 12 | .col-md-10 13 | %form{class: 'form-horizontal', action: "/agents/#{@agent.id}/edit", method: 'post'} 14 | .form-group 15 | %label.control-label.col-xs-2{for: ''} Agent Name 16 | .col-xs-10 17 | %input{type: 'textbox', class: 'form-control', name: 'name', id: 'name', value: "#{@agent.name}"} 18 | .form-group 19 | .col-xs-offset-2.col-xs-10 20 | %button.btn.btn-primary{type: 'submit'} Update -------------------------------------------------------------------------------- /public/js/en.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * bs_grid v0.9.2 localization - ENGLISH *************************************** 3 | * Minified using http://gpbmike.github.io/refresh-sf/ 4 | */ 5 | var rsc_bs_dg={columns:"Columns",columns_show_row_numbers:"Row numbers",columns_default:"Default",sorting:"Sorting",sort_ascending:"  ",sort_descending:"  ",sort_none:"  ",sorting_default:"Default",filters:"Filters",filters_apply:"Apply",filters_reset:"Reset",select:"Select",select_all_in_page:"All in page",deselect_all_in_page:"None in page",select_inverse_in_page:"Inverse",deselect_all:"Deselect all",row_index_header:"#",no_records_found:"No records found"}; -------------------------------------------------------------------------------- /views/job_hub_permission_check.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | %body 4 | .span15 5 | .container 6 | .col-md-12 7 | .row 8 | .page-header 9 | %h1 10 | Hub Check 11 | .row 12 | .col-md-10 13 | Would you like to check to see if Hashview Hub has these hashes already cracked? Note if you click 'check', only the HASHES will be submitted online. 14 | Click 'skip' to skip this step 15 | %br 16 | %br 17 | .container 18 | .row 19 | .col-md-12.pull-right 20 | %a.btn.btn-success{href: "/jobs/hub_check?job_id=#{@jobs.id}"} 21 | Check 22 | %a.btn.btn-primary{href: "/jobs/assign_tasks?job_id=#{@jobs.id}"} 23 | Skip 24 | -------------------------------------------------------------------------------- /views/login.haml: -------------------------------------------------------------------------------- 1 | .container 2 | .row 3 | .col-md-offset-2.col-md-8 4 | %form{action: '/login', method: 'post'} 5 | %legend 6 | %h1 Login 7 | %p 8 | .form-group 9 | .row 10 | .col-xs-2 11 | %label.control-label.col-xs-2{for: ''} Username 12 | .col-xs-6 13 | %input.control-label{type: 'textbox', class: 'form-control', name: 'username', id: 'username'} 14 | %p 15 | .row 16 | .col-xs-2 17 | %label.control-label.col-xs-2{for: ''} Password 18 | .col-xs-6 19 | %input.control-label{type: 'password', class: 'form-control', name: 'password', id: 'password'} 20 | %p 21 | .row 22 | .col-xs-offset-2.col-xs-8 23 | %button.btn.btn-primary{type: 'submit'} Login 24 | -------------------------------------------------------------------------------- /views/wordlist_add.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | %body 4 | .span15 5 | .container 6 | %h2 Upload Wordlist 7 | %br 8 | .row 9 | .col-md-10 10 | %form{class: 'form-horizontal', action: '/wordlists/upload/', method: 'post', enctype: 'multipart/form-data'} 11 | .form-group 12 | %label.control-label.col-xs-2{for: ''} Name: 13 | .col-xs-10 14 | %input{type: 'textbox', class: 'form-control', name: 'name', id: 'name'} 15 | .form-group 16 | %label.control-label.col-xs-2 Upload File: 17 | .col-xs-10 18 | %input{type: 'file', name: 'file', class: 'inputFiles_cust'} 19 | .form-group 20 | .col-xs-offset-2.col-xs-10 21 | %br 22 | %button.btn.btn-primary{type: 'submit'} Upload 23 | -------------------------------------------------------------------------------- /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | --- 2 | engines: 3 | csslint: 4 | enabled: true 5 | duplication: 6 | enabled: true 7 | config: 8 | languages: 9 | - ruby 10 | - javascript 11 | - python 12 | - php 13 | eslint: 14 | enabled: true 15 | fixme: 16 | enabled: true 17 | rubocop: 18 | enabled: true 19 | checks: 20 | Rubocop/Metrics/LineLength: 21 | enabled: false 22 | Rubocop/Metrics/AbcSize: 23 | enabled: false 24 | Rubocop/Metrics/MethodLength: 25 | enabled: false 26 | Rubocop/Style/GuardClause: 27 | enabled: false 28 | Rubocop/Metrics/CyclomaticComplexity: 29 | enabled: false 30 | ratings: 31 | paths: 32 | - "**.css" 33 | - "**.inc" 34 | - "**.js" 35 | - "**.jsx" 36 | - "**.module" 37 | - "**.php" 38 | - "**.py" 39 | - "**.rb" 40 | exclude_paths: 41 | - config/ 42 | - tests/ 43 | -------------------------------------------------------------------------------- /control/rules/hob064.rule: -------------------------------------------------------------------------------- 1 | ############################################# 2 | # *** Hob0's QUICK Rules for Conquest *** # 3 | # *** Updated: 1/27/16 *** # 4 | ############################################# 5 | : 6 | r 7 | T0 8 | u 9 | ] 10 | d 11 | $! 12 | $! $! 13 | $@ 14 | $# 15 | $$ 16 | $% 17 | $^ 18 | $& 19 | $* 20 | $. 21 | $? 22 | $1 $! 23 | $! $1 24 | @a @e @i @o @u 25 | @a @e @i @o @u $! 26 | $0 27 | $1 28 | $2 29 | $3 30 | $4 31 | $5 32 | $6 33 | $7 34 | $8 35 | $9 36 | $2 $0 $1 $5 37 | $2 $0 $1 $6 38 | $2 $0 $1 $6 $! 39 | $1 $5 40 | $1 $6 $! 41 | $1 $4 42 | $1 $1 43 | $1 $2 44 | $0 $1 45 | $0 $0 46 | $2 $3 47 | $6 $9 48 | $7 $7 49 | $9 $9 50 | $1 $2 $3 51 | $1 $2 $3 $4 52 | ^6 ^1 ^0 ^2 53 | ^6 ^1 54 | ^1 55 | ^! 56 | so0 57 | si1 58 | si! 59 | se3 60 | ss$ 61 | sa@ 62 | so0 si1 63 | so0 sa@ 64 | so0 sa4 65 | so0 se3 66 | so0 si1 se3 ss$ sa@ 67 | so0 si1 se3 ss$ sa@ $! 68 | so0 si1 se3 ss$ sa@ $1 $6 69 | -------------------------------------------------------------------------------- /control/rules/combinator.rule: -------------------------------------------------------------------------------- 1 | ## rule: case recovery 2 | ## limits: capitalized rules only char positions 3 to 7 3 | ## example: annalove ---> AnnaLove 4 | ## extras: none 5 | 6 | : 7 | l 8 | c 9 | u 10 | 11 | c T3 12 | c T4 13 | c T5 14 | c T6 15 | c T7 16 | 17 | ## rule: experienced effective 18 | ## limits: none 19 | ## example: FringeDevision ---> fringedevision2009 20 | ## extras: lower case only 21 | 22 | l $1 23 | l $2 24 | l $1$2$3 25 | l $2$0$0$7 26 | l $2$0$0$8 27 | l $2$0$0$9 28 | 29 | ## rule: hyphen variety 30 | ## limits: insert at char positions 3 to 7 31 | ## example: theobserver ---> the observer 32 | ## extras: lower case only 33 | 34 | l i3 35 | l i4 36 | l i5 37 | l i6 38 | l i7 39 | l i3& 40 | l i4& 41 | l i5& 42 | l i6& 43 | l i7& 44 | l i3+ 45 | l i4+ 46 | l i5+ 47 | l i6+ 48 | l i7+ 49 | l i3- 50 | l i4- 51 | l i5- 52 | l i6- 53 | l i7- 54 | l i3. 55 | l i4. 56 | l i5. 57 | l i6. 58 | l i7. 59 | 60 | -------------------------------------------------------------------------------- /views/search.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | %body 4 | .span15 5 | .container 6 | .col-md-12 7 | .row 8 | .page-header 9 | %h1 10 | Search 11 | .container 12 | .row 13 | .col-md-12 14 | %form{action: '/search', method: 'post'} 15 | .form-group.col-xs-2 16 | %select.form-control{id: 'search_type', name: 'search_type'} 17 | %option{value: 'username', name: 'search_type', type: 'button'} Username 18 | %option{value: 'hash', name: 'search_type', type: 'button'} Hash 19 | %option{value: 'password', name: 'search_type', type: 'button'} Password 20 | .form-group.col-md-8 21 | %input{type: 'textbox', class: 'form-control', name: 'value', id: 'value', placeholder: 'Search for...'} 22 | .form-group.col-xs-2 23 | %button.btn.btn-primary{type: 'submit'} Search 24 | -------------------------------------------------------------------------------- /jobs/wordlistChecksum.rb: -------------------------------------------------------------------------------- 1 | # this job generates checksums for each wordlist 2 | # 3 | module WordlistChecksum 4 | @queue = :management 5 | def self.perform() 6 | require_relative '../models/master' 7 | # Setup Logger 8 | logger_wordlistchecksum = Logger.new('logs/jobs/wordlistchecksum.log', 'daily') 9 | if ENV['RACK_ENV'] == 'development' 10 | logger_wordlistchecksum.level = Logger::DEBUG 11 | else 12 | logger_wordlistchecksum.level = Logger::INFO 13 | end 14 | 15 | logger_wordlistchecksum.debug('Wordlist Checksum Class() - has started') 16 | 17 | # Identify all wordlists without checksums 18 | @wordlist = Wordlists.where(checksum: nil).all 19 | @wordlist.each do |wl| 20 | # generate checksum 21 | logger_wordlistchecksum.info('generating checksum for: ' + wl.path.to_s) 22 | checksum = Digest::SHA2.hexdigest(File.read(wl.path)) 23 | 24 | # save checksum to database 25 | wl.checksum = checksum 26 | wl.save 27 | end 28 | 29 | logger_wordlistchecksum.debug('Wordlist Checksum Class() - has completed') 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /routes/agents.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | get '/agents/list' do 3 | @agents = Agents.all 4 | haml :agent_list 5 | end 6 | 7 | get '/agents/create' do 8 | haml :agent_edit 9 | end 10 | 11 | get '/agents/:id/edit' do 12 | @agent = Agents.first(id: params[:id]) 13 | haml :agent_edit 14 | end 15 | 16 | post '/agents/:id/edit' do 17 | agent = Agents.first(id: params[:id]) 18 | agent.name = params['name'] 19 | agent.save 20 | redirect to('/agents/list') 21 | end 22 | 23 | get '/agents/:id/delete' do 24 | agent = Agents.first(id: params[:id]) 25 | agent.destroy 26 | redirect to('/agents/list') 27 | end 28 | 29 | get '/agents/:id/authorize' do 30 | agent = Agents.first(id: params[:id]) 31 | agent.status = 'Authorized' 32 | agent.save 33 | redirect to('/agents/list') 34 | end 35 | 36 | get '/agents/:id/deauthorize' do 37 | agent = Agents.first(id: params[:id]) 38 | if agent.status == 'Working' 39 | flash[:warning] = 'Agent was working. The active task was not stopped and you will not receive the results.' 40 | end 41 | agent.status = 'Pending' 42 | agent.save 43 | redirect to('/agents/list') 44 | end -------------------------------------------------------------------------------- /config/resque_schedule.yml: -------------------------------------------------------------------------------- 1 | # This is a schedule for TestJob (see jobs/test_job.rb) 2 | # you can crib from this config 3 | #do_test_job: 4 | # # you can use rufus-scheduler "every" syntax in place of cron if you prefer 5 | # # every: 1h 6 | # # By default the job name (hash key) will be taken as worker class name. 7 | # # If you want to have a different job name and class name, provide the 'class' option 8 | # #cron: "*/1 * * * *" 9 | # every: 2s 10 | # class: TestJob 11 | # queue: management 12 | # args: 13 | # description: "This job queues all content for indexing in solr" 14 | 15 | # schedule for wordlist importer 16 | do_wordlist_importer: 17 | every: 60s 18 | class: "WordlistImporter" 19 | queue: management 20 | description: "This job automatically imports wordlists if placed in controls/wordlists dir" 21 | 22 | do_rulelist_importer: 23 | every: 10s 24 | class: "RuleImporter" 25 | queue: management 26 | description: "This job automatically imports rule files if placed in controls/rules dir" 27 | 28 | # schedule for cleanup task 29 | do_cleanUp: 30 | every: 1d 31 | class: 'CleanUp' 32 | queue: management 33 | description: 'This job automatically deletes old files on the file system if found to be older than X hours' 34 | -------------------------------------------------------------------------------- /helpers/hc_stdout_parser.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | helpers do 3 | def hashcatParser(file) 4 | status = {} 5 | begin 6 | File.open(file).each_line do |line| 7 | if line.start_with?('Time.Started.') 8 | status['Time_Started'] = line.split(': ')[-1].strip 9 | elsif line.start_with?('Time.Estimated.') 10 | status['Time_Estimated'] = line.split(': ')[-1].strip 11 | elsif line.start_with?('Recovered.') 12 | status['Recovered'] = line.split(': ')[-1].strip 13 | elsif line.start_with?('Input.Mode.') 14 | status['Input_Mode'] = line.split(': ')[-1].strip 15 | elsif line.start_with?('Guess_Mask') 16 | status['Guess_Mask'] = line.split(': ')[-1].strip 17 | elsif line.start_with?('Speed.Dev.') 18 | item = line.split(': ') 19 | gpu = item[0].gsub!('Speed.Dev.', 'Speed Dev ').gsub!('.', '') 20 | status[gpu] = line.split(': ')[-1].strip 21 | elsif line.start_with?('HWMon.Dev.') 22 | item = line.split('.: ') 23 | gpu = item[0].gsub!('HWMon.Dev.', 'HWMon Dev ').gsub!('.', '') 24 | status[gpu] = line.split('.: ')[-1].strip 25 | end 26 | end 27 | rescue SystemCallError => e 28 | puts e 29 | end 30 | status 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /helpers/sinatra_ssl.rb: -------------------------------------------------------------------------------- 1 | # encoding utf-8 2 | require 'webrick/https' 3 | 4 | module Sinatra 5 | class Application 6 | def self.run! 7 | 8 | # Check to see if SSL cert is present, if not generate 9 | unless File.exist?('cert/server.crt') 10 | # Generate Cert 11 | system('openssl req -x509 -nodes -days 365 -newkey RSA:2048 -subj "/CN=US/ST=Minnesota/L=Duluth/O=potatoFactory/CN=hashview" -keyout cert/server.key -out cert/server.crt') 12 | end 13 | 14 | set :ssl_certificate, 'cert/server.crt' 15 | set :ssl_key, 'cert/server.key' 16 | set :bind, '0.0.0.0' 17 | set :port, '4567' 18 | 19 | certificate_content = File.open(ssl_certificate).read 20 | key_content = File.open(ssl_key).read 21 | 22 | server_options = { 23 | Host: bind, 24 | Port: port, 25 | SSLEnable: true, 26 | SSLCertificate: OpenSSL::X509::Certificate.new(certificate_content), 27 | SSLPrivateKey: OpenSSL::PKey::RSA.new(key_content) 28 | } 29 | 30 | Rack::Handler::WEBrick.run self, server_options do |server| 31 | [:INT, :TERM].each { |sig| trap(sig) { server.stop } } 32 | server.threaded = settings.threaded if server.respond_to? :threaded= 33 | set :running, true 34 | end 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /public/css/hashviewStyle.css: -------------------------------------------------------------------------------- 1 | /* Custom Classes */ 2 | 3 | /* Layout */ 4 | .vCenter{ 5 | display: flex; 6 | align-items: center; 7 | justify-content: center; 8 | flex-direction: row; 9 | } 10 | /* used for all messages that dissolve in layout template */ 11 | .alertfade{ 12 | } 13 | 14 | /* used for analytics d3 layouts */ 15 | .bar { 16 | fill: '#0000FF'; 17 | } 18 | 19 | li.borderless { 20 | border-top: 0 none; 21 | border-bottom: 0 none; 22 | } 23 | 24 | /* choose files */ 25 | .inputFiles_cust::-webkit-file-upload-button { 26 | visibility: hidden; 27 | padding-right:30px; 28 | } 29 | .inputFiles_cust::before { 30 | content: 'Choose Files'; 31 | display: inline-block; 32 | background: -webkit-linear-gradient(top, #f9f9f9, #e3e3e3); 33 | border: 1px solid #999; 34 | border-radius: 3px; 35 | padding: 5px 8px; 36 | outline: none; 37 | white-space: nowrap; 38 | -webkit-user-select: none; 39 | cursor: pointer; 40 | text-shadow: 1px 1px #fff; 41 | font-weight: 700; 42 | font-size: 10pt; 43 | } 44 | .inputFiles_cust:hover::before { 45 | border-color: black; 46 | } 47 | .inputFiles_cust:active::before { 48 | background: -webkit-linear-gradient(top, #e3e3e3, #f9f9f9); 49 | } 50 | 51 | /* used for fixed width labels on dashboard */ 52 | .labelfixedwidth { 53 | min-width: 80px; 54 | display: inline-block 55 | } 56 | -------------------------------------------------------------------------------- /views/account_list.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | %body 4 | .span15 5 | .container 6 | .col-md-12 7 | .row 8 | .page-header 9 | %h1 10 | Accounts 11 | .row 12 | .col-md-10.pull-left 13 | These are awesome people that use Hashview. 14 | .col-md-2.pull-right 15 | %a.btn.btn-primary.pull-right{href: '/accounts/create'} 16 | Add User 17 | %br 18 | %br 19 | .container 20 | .row 21 | .col-md-12 22 | .table 23 | %table{class: 'table table-striped'} 24 | %thead 25 | %tr 26 | %th 27 | %b Name 28 | %th 29 | %b Control 30 | %tbody 31 | - if @users 32 | - @users.each do |user| 33 | %tr 34 | %td #{user.username} 35 | %td 36 | %a.btn.btn-warning{href: "/accounts/edit/#{user.id}"} 37 | %i.glyphicon.glyphicon-cog{title: 'Edit'} 38 | %a.btn.btn-danger{href: "/accounts/delete/#{user.id}"} 39 | %i.glyphicon.glyphicon-trash{title: 'Delete'} 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hashview 2 | [![Build Status](https://travis-ci.org/hashview/hashview.svg?branch=master)](https://travis-ci.org/hashview/hashview) 3 | 4 | >**Hashview** is a tool for security professionals to help organize and automate the repetitious tasks related to password cracking. Hashview is a web application that manages hashcat (https://hashcat.net) commands. Hashview strives to bring constiency in your hashcat tasks while delivering analytics with pretty pictures ready for ctrl+c, ctrl+v into your reports. 5 | 6 | ### Requirements 7 | 8 | 1. Hashcat installed and working (https://hashcat.net/hashcat/) 9 | 2. Hashcat installed and working (just double checking) 10 | 3. A working RVM environment (https://rvm.io/rvm/install) 11 | 12 | ## Installation 13 | 14 | Involves installing mysql, resque, and a ruby app (see wiki) 15 | [Installation Instructions](https://github.com/hashview/hashview/wiki/01_Installing-Hashview) 16 | 17 | ### Developing and Contributing 18 | 19 | Please see the [Contribution Guide](https://github.com/hashview/hashview/wiki/Contributing) for how to develop and contribute. 20 | If you have any problems, please consult [Issues](https://github.com/hashview/hashview/issues) page first. If you don't see a related issue, feel free to add one and we'll help. 21 | 22 | ### Authors 23 | 24 | Contact us on Twitter 25 | @caseycammilleri 26 | @jarsnah12 27 | -------------------------------------------------------------------------------- /control/rules/toggles2.rule: -------------------------------------------------------------------------------- 1 | T0 2 | T1 3 | T2 4 | T3 5 | T4 6 | T5 7 | T6 8 | T7 9 | T8 10 | T9 11 | TA 12 | TB 13 | TC 14 | TD 15 | TE 16 | T0T1 17 | T0T2 18 | T0T3 19 | T0T4 20 | T0T5 21 | T0T6 22 | T0T7 23 | T0T8 24 | T0T9 25 | T0TA 26 | T0TB 27 | T0TC 28 | T0TD 29 | T0TE 30 | T1T2 31 | T1T3 32 | T1T4 33 | T1T5 34 | T1T6 35 | T1T7 36 | T1T8 37 | T1T9 38 | T1TA 39 | T1TB 40 | T1TC 41 | T1TD 42 | T1TE 43 | T2T3 44 | T2T4 45 | T2T5 46 | T2T6 47 | T2T7 48 | T2T8 49 | T2T9 50 | T2TA 51 | T2TB 52 | T2TC 53 | T2TD 54 | T2TE 55 | T3T4 56 | T3T5 57 | T3T6 58 | T3T7 59 | T3T8 60 | T3T9 61 | T3TA 62 | T3TB 63 | T3TC 64 | T3TD 65 | T3TE 66 | T4T5 67 | T4T6 68 | T4T7 69 | T4T8 70 | T4T9 71 | T4TA 72 | T4TB 73 | T4TC 74 | T4TD 75 | T4TE 76 | T5T6 77 | T5T7 78 | T5T8 79 | T5T9 80 | T5TA 81 | T5TB 82 | T5TC 83 | T5TD 84 | T5TE 85 | T6T7 86 | T6T8 87 | T6T9 88 | T6TA 89 | T6TB 90 | T6TC 91 | T6TD 92 | T6TE 93 | T7T8 94 | T7T9 95 | T7TA 96 | T7TB 97 | T7TC 98 | T7TD 99 | T7TE 100 | T8T9 101 | T8TA 102 | T8TB 103 | T8TC 104 | T8TD 105 | T8TE 106 | T9TA 107 | T9TB 108 | T9TC 109 | T9TD 110 | T9TE 111 | TATB 112 | TATC 113 | TATD 114 | TATE 115 | TBTC 116 | TBTD 117 | TBTE 118 | TCTD 119 | TCTE 120 | TDTE 121 | -------------------------------------------------------------------------------- /public/js/jui_filter_rules/localization/en.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jui_filter_rules v1.0.7 simple localization - ENGLISH *********************** 3 | */ 4 | var rsc_jui_fr={no_filters_found:"No filters defined",rules_group_AND:"all rules",rules_group_OR:"any rule",rule:"rule",group:"group",tools_please_select:"»",rule_insert_before:"insert before",rule_insert_after:"insert after",rule_insert_inside:"insert inside",rule_clear:"clear",rule_delete:"delete",group_insert_before:"insert before",group_insert_after:"insert after",group_insert_inside:"insert inside",group_delete:"delete",filter_please_select:"» select",operator_equal:"equal",operator_not_equal:"not_equal",operator_in:"in",operator_not_in:"not in",operator_less:"less",operator_less_or_equal:"less or equal",operator_greater:"greater",operator_greater_or_equal:"greater or equal",operator_between:"between",operator_not_between:"not between",operator_begins_with:"begins with",operator_not_begins_with:"does not begin with",operator_contains:"contains",operator_not_contains:"does not contain",operator_ends_with:"ends with",operator_not_ends_with:"does not end with",operator_is_empty:"is empty",operator_is_not_empty:"is not empty",operator_is_null:"is null",operator_is_not_null:"is not null",error_no_value_given:"Value not given",error_invalid_number:"Value is not numeric",error_invalid_datetime:"Invalid date format",error_converting_value:"Error converting value"}; -------------------------------------------------------------------------------- /views/verify_filetypes.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | %body 4 | .span15 5 | .container 6 | .col-md-12 7 | .row 8 | .page-header 9 | %h1 10 | Verify File Format 11 | .row 12 | .col-md-10.pull-left 13 | Select the format these hashes are written as. 14 | %br 15 | %br 16 | .container 17 | .col-md-12 18 | .row 19 | %form{class: 'form-horizontal', action: '/customers/upload/verify_filetype', method: 'post'} 20 | .form-group 21 | %label.control-label.col-xs-2{for: ''} Select Hash File Type: 22 | .col-xs-4 23 | %select.form-control{name: 'filetype'} 24 | %option{value: 'none', name: 'filetype', type: 'button'} - SELECT - 25 | - @filetypes.each do |type| 26 | %option{value: "#{type}", name: 'filetype', type: 'button'} #{type} 27 | %input{type: 'hidden', name: 'hashid', value: "#{params[:hashid].to_s}"} 28 | .form-group 29 | .col-xs-offset-2.col-xs-10 30 | %input{type: 'hidden', name: 'job_id', value: "#{params[:job_id].to_s}"} 31 | %input{type: 'hidden', name: 'customer_id', value: "#{params[:customer_id].to_s}"} 32 | %button.btn.btn-primary{type: 'submit'} Confirm 33 | -------------------------------------------------------------------------------- /views/register.haml: -------------------------------------------------------------------------------- 1 | .container 2 | .row 3 | .col-md-offset-2.col-md-8 4 | %form{action: '/register', method: 'post'} 5 | %legend 6 | %h1 Create a New Admin Account 7 | %p 8 | .form-group 9 | .row 10 | .col-xs-2 11 | %label.control-label.col-xs-2{for: ''} Username 12 | .col-xs-6 13 | %input.control-label{type: 'textbox', class: 'form-control', name: 'username', id: 'username'} 14 | %p 15 | .row 16 | .col-xs-2 17 | %label.control-label.col-xs-2{for: ''} Password 18 | .col-xs-6 19 | %input.control-label{type: 'password', class: 'form-control', name: 'password', id: 'password'} 20 | %p 21 | .row 22 | .col-xs-2 23 | %label.control-label.col-xs-2{for: ''} Confirm Password 24 | .col-xs-6 25 | %input.control-label{type: 'password', class: 'form-control', name: 'confirm', id: 'confirm'} 26 | %p 27 | .row 28 | .col-xs-2 29 | %label.control-label.col-xs-2{for: ''} Email Address (optional) 30 | .col-xs-6 31 | %input.control-label{type: 'textbox', class: 'form-control', name: 'email', id: 'email'} 32 | %p 33 | .row 34 | .col-xs-offset-2.col-xs-8 35 | %button.btn.btn-primary{type: 'submit'} Create 36 | -------------------------------------------------------------------------------- /views/job_hub_check.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | %body 4 | .span15 5 | .container 6 | .col-md-12 7 | .row 8 | .page-header 9 | %h1 10 | Hub Check 11 | .row 12 | .col-md-10 13 | The following hashes are already cracked on Hashview Hub. Click reveal to show it now or click continue. 14 | %br 15 | %br 16 | .container 17 | .row 18 | .col-md-12 19 | .table 20 | %table{class: 'table table-striped'} 21 | %thead 22 | %tr 23 | %th 24 | %b Type 25 | %th 26 | %b Cipher Text 27 | %tbody 28 | - @results.each do |entry| 29 | -if entry['show_results'] == '1' 30 | %tr 31 | %td #{modeToFriendly(entry['hashtype'].to_s)} 32 | %td #{entry['ciphertext']} 33 | %tr 34 | %td 35 | %td 36 | %td 37 | .container 38 | .row 39 | .col-md-12 40 | %a.btn.btn-success{href: "/hub/hash/reveal/hashfile/#{@jobs.hashfile_id}?job_id=#{@jobs.id}"} 41 | Reveal All 42 | %a.btn.btn-primary{href: "/jobs/assign_tasks?job_id=#{@jobs.id}"} 43 | Continue 44 | -------------------------------------------------------------------------------- /routes/register.rb: -------------------------------------------------------------------------------- 1 | get '/register' do 2 | @users = User.all 3 | @settings = Settings.first 4 | # Prevent registering of multiple admins 5 | redirect to('/') unless @users.empty? 6 | 7 | haml :register 8 | end 9 | 10 | post '/register' do 11 | varWash(params) 12 | if !params[:username] || params[:username].nil? || params[:username].empty? 13 | flash[:error] = 'You must have a username.' 14 | redirect to('/register') 15 | end 16 | 17 | if !params[:password] || params[:password].nil? || params[:password].empty? 18 | flash[:error] = 'You must have a password.' 19 | redirect to('/register') 20 | end 21 | 22 | if !params[:confirm] || params[:confirm].nil? || params[:confirm].empty? 23 | flash[:error] = 'You must have a password.' 24 | redirect to('/register') 25 | end 26 | 27 | # validate that no other user account exists 28 | @users = User.all 29 | if @users.empty? 30 | if params[:password] != params[:confirm] 31 | flash[:error] = 'Passwords do not match.' 32 | redirect to('/register') 33 | else 34 | new_user = User.new 35 | new_user.username = params[:username] 36 | new_user.password = params[:password] 37 | new_user.email = params[:email] unless params[:email].nil? || params[:email].empty? 38 | new_user.admin = 't' 39 | new_user.id = 1 # since this is the first user 40 | new_user.save 41 | flash[:success] = "User #{params[:username]} created successfully" 42 | end 43 | end 44 | 45 | redirect to('/login') 46 | end -------------------------------------------------------------------------------- /routes/hashfiles.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | get '/hashfiles/list' do 3 | @hub_settings = HubSettings.first 4 | @customers = Customers.order(Sequel.asc(:name)).all 5 | @hashfiles = Hashfiles.all 6 | @cracked_status = {} 7 | @local_cracked_cnt = {} 8 | @local_uncracked_cnt = {} 9 | 10 | @hashfiles.each do |hashfile| 11 | hashfile_cracked_count = HVDB.fetch('SELECT COUNT(h.originalhash) as count FROM hashes h LEFT JOIN hashfilehashes a ON h.id = a.hash_id WHERE (a.hashfile_id = ? AND h.cracked = 1)', hashfile.id)[:count] 12 | hashfile_cracked_count = hashfile_cracked_count[:count] 13 | hashfile_total_count = HVDB.fetch('SELECT COUNT(h.originalhash) as count FROM hashes h LEFT JOIN hashfilehashes a ON h.id = a.hash_id WHERE a.hashfile_id = ?', hashfile.id)[:count] 14 | hashfile_total_count = hashfile_total_count[:count] 15 | @local_cracked_cnt[hashfile.id] = hashfile_cracked_count.to_s 16 | @local_uncracked_cnt[hashfile.id] = hashfile_total_count.to_i - hashfile_cracked_count.to_i 17 | @cracked_status[hashfile.id] = hashfile_cracked_count.to_s + '/' + hashfile_total_count.to_s 18 | end 19 | 20 | haml :hashfile_list 21 | end 22 | 23 | get '/hashfiles/delete' do 24 | varWash(params) 25 | 26 | hashfilehashes = HVDB[:hashfilehashes] 27 | hashfilehashes.filter(hashfile_id: params[:hashfile_id]).delete 28 | 29 | hashfile = HVDB[:hashfiles] 30 | hashfile.filter(id: params[:hashfile_id]).delete 31 | 32 | flash[:success] = 'Successfully removed hashfile.' 33 | 34 | redirect to('/hashfiles/list') 35 | end -------------------------------------------------------------------------------- /views/job_local_check.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | %body 4 | .span15 5 | .container 6 | .col-md-12 7 | .row 8 | .page-header 9 | %h1 10 | Local Check 11 | .row 12 | .col-md-10 13 | The following hashes are already cracked in Hashview's Local database! 14 | %br 15 | %br 16 | .container 17 | .row 18 | .col-md-12 19 | .table 20 | %table{class: 'table table-striped'} 21 | %thead 22 | %tr 23 | %th 24 | %b Username 25 | %th 26 | %b Type 27 | %th 28 | %b Cipher Text 29 | %th 30 | %b Plain Text 31 | %tbody 32 | - if @previously_cracked 33 | - @previously_cracked.each do |entry| 34 | %tr 35 | %td #{entry[:username]} 36 | %td #{modeToFriendly(entry[:hashtype].to_s)} 37 | %td #{entry[:originalhash]} 38 | %td #{entry[:plaintext]} 39 | - else 40 | %tr 41 | %td 42 | %td 43 | %td 44 | %td 45 | .container 46 | .row 47 | .col-md-12 48 | %a.btn.btn-primary{href: "#{@url}"} 49 | Next 50 | -------------------------------------------------------------------------------- /helpers/email.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | require 'pony' 3 | def sendEmail(recipient, sub, msg) 4 | smtp_settings = Settings.first 5 | smtp_server, smtp_port = smtp_settings.smtp_server.split(':') 6 | use_tls = true if smtp_settings.smtp_use_tls == '1' 7 | use_tls = false if smtp_settings.smtp_use_tls == '0' 8 | 9 | if smtp_settings.smtp_auth_type != 'None' 10 | Pony.options = { 11 | :via => :smtp, 12 | :via_options => { 13 | :from => smtp_settings.smtp_sender.to_s, 14 | :address => smtp_server.to_s, 15 | :port => smtp_port.to_s, 16 | :enable_starttls_auto => use_tls.to_s, 17 | :user_name => smtp_settings.smtp_user.to_s, 18 | :password => smtp_settings.smtp_pass.to_s, 19 | :authentication => smtp_settings.smtp_auth_type.to_s, 20 | :domain => 'hashview.localdomain' 21 | } 22 | } 23 | else 24 | Pony.options = { 25 | :via => :smtp, 26 | :via_options => { 27 | :address => smtp_server.to_s, 28 | :port => smtp_port.to_s, 29 | :enable_starttls_auto => false 30 | } 31 | } 32 | end 33 | 34 | if smtp_settings.smtp_sender.nil? || smtp_settings.smtp_sender.empty? 35 | sender_addr = 'no-reply@hashview' 36 | else 37 | sender_addr = smtp_settings.smtp_sender.to_s 38 | end 39 | 40 | Pony.mail :to => recipient, 41 | :from => sender_addr, 42 | :subject => sub, 43 | :body => msg 44 | end 45 | -------------------------------------------------------------------------------- /views/wordlist_list.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | %body 4 | .span15 5 | .container 6 | .col-md-12 7 | .row 8 | .page-header 9 | %h1 10 | Wordlists 11 | .row 12 | .col-md-10.pull-left 13 | Wordlists are used in dictionary attacks. Hashview comes preloaded with one wordlist, but you can upload more by clicking the 'Upload Wordlist' button to the left or by dropping the files to /[install path]/control/wordlists/. 14 | .col-md-2.pull-right 15 | %a.btn.btn-primary.pull-right{href: '/wordlists/add'} 16 | Upload Wordlist 17 | %br 18 | .container 19 | .row 20 | .col-md-12 21 | .table 22 | %table{class: 'table table-striped'} 23 | %thead 24 | %tr 25 | %th 26 | %b Name 27 | %th 28 | %b Size 29 | %th 30 | %b Action 31 | %tbody 32 | - if @wordlists 33 | - @wordlists.each do |wordlist| 34 | %tr 35 | %td #{wordlist.name} 36 | %td #{wordlist.size} 37 | %td 38 | - unless wordlist.name == 'Smart Wordlist' 39 | %a.btn.btn-danger{href: "/wordlists/delete/#{wordlist.id}"} 40 | %i.glyphicon.glyphicon-trash{title: 'Delete'} -------------------------------------------------------------------------------- /control/rules/best64.rule: -------------------------------------------------------------------------------- 1 | ## nothing, reverse, case... base stuff 2 | : 3 | r 4 | u 5 | T0 6 | 7 | ## simple number append 8 | $0 9 | $1 10 | $2 11 | $3 12 | $4 13 | $5 14 | $6 15 | $7 16 | $8 17 | $9 18 | 19 | ## special number append 20 | $0 $0 21 | $0 $1 22 | $0 $2 23 | $1 $1 24 | $1 $2 25 | $1 $3 26 | $2 $1 27 | $2 $2 28 | $2 $3 29 | $6 $9 30 | $7 $7 31 | $8 $8 32 | $9 $9 33 | $1 $2 $3 34 | 35 | ## high frequency append 36 | $e 37 | $s 38 | 39 | ## high frequency overwrite at end 40 | ] $a 41 | ] ] $s 42 | ] ] $a 43 | ] ] $e $r 44 | ] ] $i $e 45 | ] ] ] $o 46 | ] ] ] $y 47 | ] ] ] $1 $2 $3 48 | ] ] ] $m $a $n 49 | ] ] ] $d $o $g 50 | 51 | ## high frequency prepend 52 | ^1 53 | ^e ^h ^t 54 | 55 | ## high frequency overwrite at start 56 | o0d 57 | o0m o1a 58 | 59 | ## leetify 60 | so0 61 | si1 62 | se3 63 | 64 | ## simple extracts 65 | D2 66 | D2 D2 67 | D3 68 | D4 69 | 70 | ## undouble word 71 | '5 D3 72 | '5 $1 73 | 74 | ## removes suffixes from 'strongified' passwords in dict 75 | ] 76 | ] ] 77 | ] ] ] 78 | ] ] ] d 79 | ] ] D1 ] 80 | 81 | ## rotates 82 | +5 ] } } } } '4 83 | x02 { { { { { { 84 | } ] ] { 85 | } } -0 x12 86 | } } } 87 | } } } } '4 88 | } } } } } '5 89 | } } } } } } Y4 '4 d 90 | 91 | ## unknown 92 | *04 +0 '4 93 | *05 x03 d '3 p1 94 | +0 +0 +0 +0 +0 +0 +0 +0 95 | +0 +0 +0 x12 96 | Z4 '8 x42 97 | Z5 '6 x31 ] p1 98 | Z5 *75 '5 { x02 99 | d x28 Y4 '4 d 100 | f *A5 '8 x14 101 | p2 '7 p1 x58 102 | x14 d p2 '6 103 | -------------------------------------------------------------------------------- /hashview.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | require 'sinatra' 3 | require 'sinatra/flash' 4 | require 'haml' 5 | require 'resque' 6 | require 'resque/server' 7 | require 'logger' 8 | 9 | require_relative 'models/master' 10 | require_relative 'helpers/init' 11 | require_relative 'routes/init' 12 | require_relative 'jobs/init' 13 | 14 | # Enable sessions 15 | enable :sessions 16 | 17 | # Presume production if not told otherwise 18 | if ENV['RACK_ENV'].nil? 19 | set :environment, :production 20 | ENV['RACK_ENV'] = 'production' 21 | end 22 | 23 | if isOldVersion? 24 | # puts 'You need to perform some upgrade steps. Check instructions here" 25 | puts "\n\nYour installation is out of date, please run the following upgrade task.\n" 26 | puts "RACK_ENV=#{ENV['RACK_ENV']} rake db:upgrade\n\n\n" 27 | exit 28 | end 29 | 30 | # make sure the binary path is set in the configuration file 31 | options = JSON.parse(File.read('config/agent_config.json')) 32 | if options['hc_binary_path'].empty? || options['hc_binary_path'].nil? 33 | puts '!!!!!!!!!! ERROR !!!!!!!!!!!!!!' 34 | puts '[!] You must defined the full path to your hashcat binary. Do this in your config/agent_config.json file' 35 | puts '!!!!!!!!!! ERROR !!!!!!!!!!!!!!' 36 | exit 0 37 | end 38 | 39 | # Check for valid session before proccessing 40 | before /^(?!\/(login|register|logout|v1\/))/ do 41 | @settings = Settings.first 42 | if !validSession? 43 | redirect to('/login') 44 | end 45 | end 46 | 47 | # Set our key limit size 48 | Rack::Utils.key_space_limit = 68719476736 49 | 50 | # start our local agent 51 | Resque.enqueue(LocalAgent) -------------------------------------------------------------------------------- /public/css/jquery.bs_grid.css: -------------------------------------------------------------------------------- 1 | /* 2 | * bs_grid v0.9.2 CSS ********************************************************** 3 | */ 4 | 5 | /* 6 | DO NOT CHANGE this file, as it will be overwritten in next update. 7 | Write your own classes in other css file. 8 | */ 9 | 10 | /* bootstrap "xs": Extra small devices (phones, less than 768px) */ 11 | /* No media query since this is the default in Bootstrap */ 12 | 13 | .tools { 14 | height: 38px; 15 | } 16 | 17 | .col-checkbox { 18 | margin-top: 0 !important; 19 | } 20 | 21 | .columns-label { 22 | margin-top: 3px; 23 | margin-bottom: 3px; 24 | font-weight: normal; 25 | } 26 | 27 | .columns-li-padding { 28 | padding: 3px 20px; 29 | } 30 | 31 | .sorting-name { 32 | display: inline-block; 33 | padding-left: 20px; 34 | margin-top: 3px; 35 | margin-bottom: 3px; 36 | vertical-align: middle; 37 | } 38 | 39 | .selected-rows { 40 | margin-left: 5px; 41 | margin-right: 2px; 42 | text-align: right; 43 | } 44 | 45 | .th-common { 46 | cursor: pointer; 47 | } 48 | 49 | .no-records-found { 50 | text-align: center; 51 | } 52 | 53 | .pagination-container { 54 | padding: 7px 7px 5px 7px !important; 55 | } 56 | 57 | .filters-container { 58 | padding: 0 7px 10px 7px !important; 59 | } 60 | 61 | .filters-button { 62 | margin: 0 3px; 63 | } 64 | 65 | /* bootstrap "sm": Small devices (tablets, 768px and up) */ 66 | @media (min-width: 768px) { 67 | 68 | } 69 | 70 | /* bootstrap "md": Medium devices (desktops, 992px and up) */ 71 | @media (min-width: 992px) { 72 | 73 | } 74 | 75 | /* bootstrap "lg": Large devices (large desktops, 1200px and up) */ 76 | @media (min-width: 1200px) { 77 | 78 | } -------------------------------------------------------------------------------- /jobs/ruleImporter.rb: -------------------------------------------------------------------------------- 1 | module RuleImporter 2 | @queue = :management 3 | 4 | def self.perform() 5 | sleep(rand(10)) 6 | require_relative '../models/master' 7 | logger_ruleimporter = Logger.new('logs/jobs/ruleImporter.log', 'daily') 8 | if ENV['RACK_ENV'] == 'development' 9 | logger_ruleimporter.level = Logger::DEBUG 10 | else 11 | logger_ruleimporter.level = Logger::INFO 12 | end 13 | 14 | logger_ruleimporter.debug('Rule Importer Class() - has started') 15 | 16 | # Identify all rules in directory 17 | @files = Dir.glob(File.join('control/rules/', '*.rule')) 18 | @files.each do |path_file| 19 | rule_entry = Rules.first(path: path_file) 20 | unless rule_entry 21 | # Get Name 22 | name = path_file.split('/')[-1] 23 | logger_ruleimporter.info('Importing new Rule ""' + name + '"" into HashView.') 24 | 25 | # Adding to DB 26 | rule_file = Rules.new 27 | rule_file.lastupdated = Time.now 28 | rule_file.name = name 29 | rule_file.path = path_file 30 | rule_file.size = 0 31 | rule_file.checksum = Digest::SHA2.hexdigest(File.read(path_file)) 32 | rule_file.save 33 | 34 | end 35 | end 36 | 37 | @files = Dir.glob(File.join('control/rules/', '*.rule')) 38 | @files.each do |path_file| 39 | rule_file = Rules.first(path: path_file) 40 | if rule_file.size == '0' 41 | size = File.foreach(path_file).inject(0) do |c| 42 | c + 1 43 | end 44 | rule_file.size = size 45 | rule_file.save 46 | end 47 | end 48 | 49 | logger_ruleimporter.debug('Rule Importer Class() - has completed') 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /public/css/jquery.jui_filter_rules.bs.min.css: -------------------------------------------------------------------------------- 1 | /* 2 | * jui_filter_rules v1.0.7 CSS (for Bootstrap) ********************************* 3 | * Minified using http://gpbmike.github.io/refresh-sf/ 4 | */ 5 | .filter_rules_container{padding:10px 0}.rules_group_container{padding:0;margin:0}.rules_group_header{padding:5px 0}.rules_group_body{padding:0;margin:0}.rules_group_condition_container{display:inline-block;padding:0}.rules_group_condition_list{border:1px solid}.rules_group_tools_container{display:inline-block;padding:0;margin-left:5px}.rules_group_tools_list{border:1px solid;padding:2px;margin:0;width:35px}.rules_list{width:auto!important;list-style-type:none;padding:0 0 0 25px;border-left:dotted 1px!important;border-right:none!important;border-top:none!important;border-bottom:none!important}.rules_list_li{margin:0 0 2px!important;padding:0!important;display:block!important}.rules_list_error_li{background-color:#df0202!important}.filter_container{display:inline-block;padding:5px 5px 5px 0;vertical-align:top}.operators_list_container{display:inline-block;padding:5px;vertical-align:top}.filter_value_container{display:inline-block;padding:5px}.filter_input_number{width:80px}.filter_input_checkbox{margin:0 5px 0 0;display:inline!important}.filter_input_radio{margin:0 5px 0 0}.filter_select{margin:0 5px}.filter_group_list{list-style-type:none;padding:0}.filter_group_list_item_horizontal{display:inline!important;margin:0 5px;padding:0}.filter_group_list_item_vertical{display:block!important;margin:0 0 5px 5px!important;padding:0!important}.rule_tools_container{display:inline-block!important;padding:5px!important;vertical-align:top!important}.rule_tools_list{padding:0;margin:0;width:35px}.no_filters_found{text-align:center;margin-top:10px;margin-left:auto;margin-right:auto}@media \0screen{.rules_group_tools_list{border:1px solid;padding:2px;margin:0;width:auto}.rule_tools_list{padding:0;margin:0;width:auto}} -------------------------------------------------------------------------------- /routes/login.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | get '/login' do 3 | @users = User.all 4 | @settings = Settings.first 5 | if @users.empty? 6 | redirect('/register') 7 | else 8 | haml :login 9 | end 10 | end 11 | 12 | get '/logout' do 13 | varWash(params) 14 | if session[:session_id] 15 | sess = Sessions.first(session_key: session[:session_id]) 16 | sess.destroy if sess 17 | end 18 | redirect to('/') 19 | end 20 | 21 | post '/login' do 22 | varWash(params) 23 | if !params[:username] || params[:username].nil? 24 | flash[:error] = 'You must supply a username.' 25 | redirect to('/login') 26 | end 27 | 28 | if !params[:password] || params[:password].nil? 29 | flash[:error] = 'You must supply a password.' 30 | redirect to('/login') 31 | end 32 | 33 | @user = User.first(username: params[:username]) 34 | 35 | if @user 36 | usern = User.authenticate(params['username'], params['password']) 37 | 38 | # if usern and session[:session_id] 39 | unless usern.nil? 40 | # only delete session if one exists 41 | if session[:session_id] 42 | # replace the session in the session table 43 | # TODO : This needs an expiration, session fixation 44 | @del_session = Sessions.first(username: usern) 45 | @del_session.destroy if @del_session 46 | end 47 | # Create new session 48 | @curr_session = Sessions.create(username: usern, session_key: session[:session_id]) 49 | @curr_session.save 50 | 51 | redirect to('/home') 52 | end 53 | flash[:error] = 'Invalid credentials.' 54 | redirect to('/login') 55 | else 56 | flash[:error] = 'Invalid credentials.' 57 | redirect to('/login') 58 | end 59 | end 60 | 61 | get '/protected' do 62 | return 'This is a protected page, you must be logged in.' 63 | end 64 | 65 | get '/not_authorized' do 66 | return 'You are not authorized.' 67 | end 68 | -------------------------------------------------------------------------------- /views/customer_edit.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | /https://jsfiddle.net/vigneshmoha/bbxMe/2/ 4 | %body 5 | %p 6 | .span15 7 | %br 8 | .container 9 | - if @customer 10 | %h2 Edit an Existing Customer 11 | %br 12 | .row 13 | .col-md-10 14 | %form{class: 'form-horizontal', action: "/customers/edit/#{@customer.id}", method: 'post'} 15 | .form-group 16 | %label.control-label.col-xs-2{for: ''} Customer Name 17 | .col-xs-10 18 | %input{type: 'textbox', class: 'form-control', name: 'name', id: 'name', value: "#{@customer.name}"} 19 | .form-group 20 | %label.control-label.col-xs-2{for: ''} Customer Description 21 | .col-xs-10 22 | %input{type: 'textbox', class: 'form-control', name: 'desc', id: 'desc', value: "#{@customer.description}"} 23 | .form-group 24 | .col-xs-offset-2.col-xs-10 25 | %button.btn.btn-primary{type: 'submit'} Update 26 | - else 27 | %h2 Add a new Customer 28 | %br 29 | .row 30 | .col-md-10 31 | %form{class: 'form-horizontal', action: '/customers/create', method: 'post'} 32 | .form-group 33 | %label.control-label.col-xs-2{for: ''} Customer Name 34 | .col-xs-10 35 | %input{type: 'textbox', class: 'form-control', name: 'name', id: 'name'} 36 | .form-group 37 | %label.control-label.col-xs-2{for: ''} Customer Description 38 | .col-xs-10 39 | %input{type: 'textbox', class: 'form-control', name: 'desc', id: 'desc'} 40 | .form-group 41 | .col-xs-offset-2.col-xs-10 42 | %button.btn.btn-primary{type: 'submit'} Create 43 | 44 | -------------------------------------------------------------------------------- /views/hashfile_list.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | %body 4 | .span15 5 | .container 6 | .col-md-12 7 | .row 8 | .page-header 9 | %h1 10 | Hash Files 11 | .row 12 | .col-md-10.pull-left 13 | The following are a list of Hash Files currently configured in Hashview. All Hash Files are assigned to a single customer. Deleting a Hash File will remove it from the customer, but all cracked hashes will remain in the database. 14 | %br 15 | %br 16 | .container 17 | .row 18 | .col-md-12 19 | .table 20 | %table{class: 'table table'} 21 | %thead 22 | %tr 23 | %th 24 | %b Customer 25 | %th 26 | %b Hash File 27 | %th 28 | %b Crack Rate 29 | %th 30 | %b Control 31 | %tbody 32 | - if @customers 33 | - @customers.each do |customer| 34 | %tr 35 | %td #{customer.name} 36 | %td 37 | %td 38 | - @hashfiles.each do |hashfile| 39 | - if hashfile.customer_id.to_i == customer.id.to_i 40 | %td 41 | %td #{hashfile.name} 42 | %td 43 | #{@cracked_status[hashfile.id]} 44 | %td 45 | %a.btn.btn-primary{href: "/analytics?customer_id=#{customer.id}&hashfile_id=#{hashfile.id}"} 46 | %i.glyphicon.glyphicon-stats{title: 'Display crack stats'} 47 | %a.btn.btn-danger{href: "/hashfiles/delete?hashfile_id=#{hashfile.id}"} 48 | %i.glyphicon.glyphicon-trash{title: 'Delete'} 49 | %tr 50 | %tr 51 | -------------------------------------------------------------------------------- /helpers/compute_task_keyspace.rb: -------------------------------------------------------------------------------- 1 | # this helper generates the keyspace of a given task. Helpful when chunking the task for multiple agents. 2 | def getKeyspace(task) 3 | 4 | # get hashcat binarypath from config 5 | hashcatbinpath = JSON.parse(File.read('config/agent_config.json'))['hc_binary_path'] 6 | 7 | # is task a dictionary attack mode (-a 0) 8 | if task.hc_attackmode == 'dictionary' 9 | # TODO: 5/18/17 normally we'd check if it has rules too, but i cant get hashcat to compute keyspace with rules :-( 10 | 11 | # get wordlist path 12 | wordlist = Wordlists.first(id: task.wl_id) 13 | wl_path = wordlist.path 14 | 15 | # build hashcat keyspace command 16 | cmd = hashcatbinpath + ' ' + wl_path + ' --keyspace' 17 | 18 | elsif task.hc_attackmode == 'maskmode' 19 | 20 | # build hashcat keyspace command 21 | cmd = hashcatbinpath + ' -a 3 ' + task.hc_mask + ' --keyspace' 22 | 23 | elsif task.hc_attackmode == 'bruteforce' 24 | 25 | # do not chunk this task 26 | return 0 27 | 28 | elsif task.hc_attackmode == 'combinator' 29 | 30 | # get wordlists path. wordlists will be comma split. ex: 1,2 31 | wl = task.wl_id.split(',') 32 | wordlist1 = Wordlists.first(id: wl[0]) 33 | wordlist1_path = wordlist1.path 34 | wordlist2 = Wordlists.first(id: wl[1]) 35 | wordlist2_path = wordlist2.path 36 | 37 | # hashcat keyspace switch cannot compute in this mode. we just add the two keyspaces together 38 | cmd = hashcatbinpath + ' ' + wordlist1_path + ' --keyspace' 39 | keyspace2 = `#{cmd}` 40 | cmd = hashcatbinpath + ' ' + wordlist2_path + ' --keyspace' 41 | end 42 | 43 | # run hashcat keyspace command 44 | keyspace = `#{cmd}` 45 | # simple check to make sure we didnt error out. the keyspace switch is a little iffy. 46 | # note: anything over ?ax10 will throw a integer overflow error in hashcat 47 | unless keyspace.include?('overflow') || keyspace.include?('Usage') 48 | if keyspace2 49 | keyspace = keyspace.to_i + keyspace2.to_i 50 | end 51 | return keyspace.to_i 52 | else 53 | # zero is used to represent infinity or no chunking 54 | return 0 55 | end 56 | 57 | end -------------------------------------------------------------------------------- /routes/wordlists.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | get '/wordlists/list' do 4 | @wordlists = Wordlists.all 5 | 6 | haml :wordlist_list 7 | end 8 | 9 | get '/wordlists/add' do 10 | haml :wordlist_add 11 | end 12 | 13 | get '/wordlists/delete/:id' do 14 | varWash(params) 15 | 16 | @wordlist = Wordlists.first(id: params[:id]) 17 | if !@wordlist 18 | flash[:error] = 'No such wordlist exists. ' 19 | redirect to('/wordlists/list') 20 | else 21 | # check if wordlist is in use 22 | @task_list = Tasks.select(wl_id: @wordlist.id).all 23 | unless @task_list.empty? 24 | flash[:error] = 'This word list is associated with a task, it cannot be deleted.' 25 | redirect to('/wordlists/list') 26 | end 27 | 28 | # Remove from filesystem 29 | begin 30 | File.delete(@wordlist.path) 31 | rescue 32 | flash[:warning] = 'No file found on disk.' 33 | end 34 | 35 | # delete from db 36 | @wordlist.destroy 37 | 38 | end 39 | redirect to('/wordlists/list') 40 | end 41 | 42 | post '/wordlists/upload/' do 43 | varWash(params) 44 | if !params[:file] || params[:file].nil? 45 | flash[:error] = 'You must specify a file.' 46 | redirect to('/wordlists/add') 47 | end 48 | if !params[:name] || params[:name].empty? 49 | flash[:error] = 'You must specify a name for your wordlist.' 50 | redirect to('/wordlists/add') 51 | end 52 | 53 | # Replace white space with underscore. We need more filtering here too 54 | upload_name = params[:name] 55 | upload_name = upload_name.downcase.tr(' ', '_') 56 | 57 | # Change to date/time ? 58 | rand_str = rand(36**36).to_s(36) 59 | 60 | # Save to file 61 | file_name = "control/wordlists/wordlist-#{upload_name}-#{rand_str}.txt" 62 | 63 | wordlist = Wordlists.new 64 | wordlist.type = 'static' 65 | wordlist.name = upload_name 66 | wordlist.path = file_name 67 | wordlist.size = 0 68 | wordlist.checksum = nil 69 | wordlist.lastupdated = Time.now 70 | wordlist.save 71 | 72 | File.open(file_name, 'wb') { |f| f.write(params[:file][:tempfile].read) } 73 | Resque.enqueue(WordlistImporter) 74 | Resque.enqueue(WordlistChecksum) 75 | 76 | redirect to('/wordlists/list') 77 | end 78 | -------------------------------------------------------------------------------- /control/rules/LowUtil.rule: -------------------------------------------------------------------------------- 1 | 2 | -0 3 | +0 4 | -0-0 5 | +0+0 6 | -0-0-0 7 | +0+0+0 8 | -0-0-0-0 9 | +0+0+0+0 10 | -0-1 11 | *01 12 | +0+1 13 | -0-1-2 14 | +0+1+2 15 | -0-1-2-3 16 | +0+1+2+3 17 | *02 18 | *03 19 | *04 20 | *05 21 | *06 22 | *07 23 | *08 24 | *09 25 | -1 26 | +1 27 | -1-1 28 | +1+1 29 | -1-1-1 30 | +1+1+1 31 | -1-1-1-1 32 | +1+1+1+1 33 | -1-2 34 | *12 35 | +1+2 36 | -1-2-3 37 | +1+2+3 38 | -1-2-3-4 39 | +1+2+3+4 40 | *13 41 | *14 42 | *15 43 | *16 44 | *17 45 | *18 46 | *19 47 | -2 48 | +2 49 | -2-2 50 | +2+2 51 | -2-2-2 52 | +2+2+2 53 | -2-2-2-2 54 | +2+2+2+2 55 | -2-3 56 | *23 57 | +2+3 58 | -2-3-4 59 | +2+3+4 60 | -2-3-4-5 61 | +2+3+4+5 62 | *24 63 | *25 64 | *26 65 | *27 66 | *28 67 | *29 68 | -3 69 | +3 70 | -3-3 71 | +3+3 72 | -3-3-3 73 | +3+3+3 74 | -3-3-3-3 75 | +3+3+3+3 76 | -3-4 77 | *34 78 | +3+4 79 | -3-4-5 80 | +3+4+5 81 | -3-4-5-6 82 | +3+4+5+6 83 | *35 84 | *36 85 | *37 86 | *38 87 | *39 88 | -4 89 | +4 90 | -4-4 91 | +4+4 92 | -4-4-4 93 | +4+4+4 94 | -4-4-4-4 95 | +4+4+4+4 96 | -4-5 97 | *45 98 | +4+5 99 | -4-5-6 100 | +4+5+6 101 | -4-5-6-7 102 | +4+5+6+7 103 | *46 104 | *47 105 | *48 106 | *49 107 | -5 108 | +5 109 | -5-5 110 | +5+5 111 | -5-5-5 112 | +5+5+5 113 | -5-5-5-5 114 | +5+5+5+5 115 | -5-6 116 | *56 117 | +5+6 118 | -5-6-7 119 | +5+6+7 120 | -5-6-7-8 121 | +5+6+7+8 122 | *57 123 | *58 124 | *59 125 | -6 126 | +6 127 | -6-6 128 | +6+6 129 | -6-6-6 130 | +6+6+6 131 | -6-6-6-6 132 | +6+6+6+6 133 | -6-7 134 | *67 135 | +6+7 136 | -6-7-8 137 | +6+7+8 138 | -6-7-8-9 139 | +6+7+8+9 140 | *68 141 | *69 142 | -7 143 | +7 144 | -7-7 145 | +7+7 146 | -7-7-7 147 | +7+7+7 148 | -7-7-7-7 149 | +7+7+7+7 150 | -7-8 151 | *78 152 | +7+8 153 | -7-8-9 154 | +7+8+9 155 | *79 156 | -8 157 | +8 158 | -8-8 159 | +8+8 160 | -8-8-8 161 | +8+8+8 162 | -8-8-8-8 163 | +8+8+8+8 164 | -8-9 165 | *89 166 | +8+9 167 | -9 168 | +9 169 | -9-9 170 | +9+9 171 | -9-9-9 172 | +9+9+9 173 | -9-9-9-9 174 | +9+9+9+9 175 | >A k c 176 | >A k l 177 | >A k u 178 | -------------------------------------------------------------------------------- /jobs/clean_up.rb: -------------------------------------------------------------------------------- 1 | # this is a cleanup job to remove old files 2 | # 3 | require_relative '../helpers/status' 4 | 5 | def cleanDir(path) 6 | # Setup Logger 7 | # Not a fan of this, not sure if i can just pass the logger_cleanup object instead? 8 | logger_cleanup = Logger.new('logs/jobs/cleanup.log', 'daily') 9 | if ENV['RACK_ENV'] == 'development' 10 | logger_cleanup.level = Logger::DEBUG 11 | else 12 | logger_cleanup.level = Logger::INFO 13 | end 14 | 15 | 16 | @files = Dir.glob(File.join(path)) 17 | @files.each do |path_file| 18 | if (Time.now - File.ctime(path_file)) / (24 * 3600) > 30 # TODO Need to change to a user defined setting 19 | logger_cleanup.info('File: ' + path_file.to_s + ' is greater than 30 days old. Deleting') 20 | File.delete(path_file) 21 | end 22 | end 23 | end 24 | 25 | module CleanUp 26 | @queue = :management 27 | def self.perform() 28 | # Setup Logger 29 | logger_cleanup = Logger.new('logs/jobs/cleanup.log', 'daily') 30 | if ENV['RACK_ENV'] == 'development' 31 | logger_cleanup.level = Logger::DEBUG 32 | else 33 | logger_cleanup.level = Logger::INFO 34 | end 35 | 36 | logger_cleanup.debug('Cleanup Class() - has started') 37 | 38 | # control/tmp/* 39 | cleanDir('control/tmp/*') 40 | 41 | # control/outfiles/found_*.txt 42 | cleanDir('control/outfiles/found_*') 43 | 44 | # control/outfiles/left_*.txt 45 | cleanDir('control/outfiles/left_*') 46 | 47 | # control/hashes/hashfile_upload_* 48 | cleanDir('control/hashes/hashfile_upload_*') 49 | 50 | # control/logs/*.log 51 | cleanDir('control/logs/*.log') 52 | 53 | # control/logs/jobs/*.log 54 | cleanDir('control/logs/jobs/*.log') 55 | 56 | # TODO 57 | # Maybe do a better way of validating we're not going to delete an actively used file? 58 | unless isBusy? 59 | # control/outfiles/hc_cracked_* 60 | cleanDir('control/outfiles/hc_cracked_*') 61 | 62 | # control/outfiles/hcoutput_* 63 | cleanDir('control/outfiles/hcoutput_*') 64 | 65 | # control/hashes/hashfile_*.txt 66 | cleanDir('control/hashes/hashfile_*.txt') 67 | end 68 | 69 | logger_cleanup.debug('Cleanup Class() - has completed') 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /jobs/wordlistImporter.rb: -------------------------------------------------------------------------------- 1 | module WordlistImporter 2 | @queue = :management 3 | 4 | def self.perform() 5 | sleep(rand(10)) 6 | require_relative '../models/master' 7 | # Setup Logger 8 | logger_wordlistimporter = Logger.new('logs/jobs/wordlistImporter.log', 'daily') 9 | if ENV['RACK_ENV'] == 'development' 10 | logger_wordlistimporter.level = Logger::DEBUG 11 | else 12 | logger_wordlistimporter.level = Logger::INFO 13 | end 14 | 15 | logger_wordlistimporter.debug('Wordlist Importer Class() - has started') 16 | 17 | # Identify all wordlists in directory 18 | @files = Dir.glob(File.join('control/wordlists/', '*')) 19 | @files.each do |path_file| 20 | wordlist_entry = Wordlists.first(path: path_file) 21 | unless wordlist_entry 22 | # Get Name 23 | name = path_file.split('/')[-1] 24 | 25 | # Make sure we're not dealing with a tar, gz, tgz, etc. Not 100% accurate! 26 | unless name.match(/\.tar|\.7z|\.gz|\.tgz|\.checksum/) 27 | logger_wordlistimporter.info('Importing new wordslist "' + name + '" into HashView.') 28 | 29 | # Adding to DB 30 | wordlist = Wordlists.new 31 | wordlist.lastupdated = Time.now 32 | wordlist.type = 'static' 33 | wordlist.name = name 34 | wordlist.path = path_file 35 | wordlist.size = 0 36 | wordlist.checksum = nil 37 | wordlist.save 38 | end 39 | end 40 | end 41 | 42 | @files = Dir.glob(File.join('control/wordlists/', '*')) 43 | @files.each do |path_file| 44 | # Get Name 45 | name = path_file.split('/')[-1] 46 | unless name.match(/\.tar|\.7z|\.gz|\.tgz|\.checksum/) 47 | wordlist = Wordlists.first(path: path_file) 48 | if wordlist.size == '0' 49 | size = File.foreach(path_file).inject(0) do |c| 50 | c + 1 51 | end 52 | wordlist.size = size 53 | wordlist.save 54 | end 55 | end 56 | end 57 | 58 | # after importing all wordlists, generate checksums for each 59 | # this checksum is used to compare differences with agents 60 | Resque.enqueue(WordlistChecksum) 61 | 62 | logger_wordlistimporter.debug('Wordlist Importer Class() - has completed') 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /helpers/smartWordlist.rb: -------------------------------------------------------------------------------- 1 | def updateSmartWordlist 2 | 3 | # Set all jobqueue items that are 'queued' to 'paused' 4 | taskqueues = Taskqueues.where(status: 'Queued').all 5 | taskqueues.each do |entry| 6 | entry.status = 'Paused' 7 | entry.save 8 | end 9 | 10 | wordlist = Wordlists.first(name: 'Smart Wordlist') 11 | # Create Smart word list if one doesn't exists 12 | if wordlist.nil? 13 | wordlist = Wordlists.new 14 | wordlist.lastupdated = Time.now 15 | wordlist.type = 'dynamic' 16 | wordlist.name = 'Smart Wordlist' 17 | wordlist.path = 'control/wordlists/SmartWordlist.txt' 18 | wordlist.size = '0' 19 | wordlist.checksum = nil 20 | wordlist.save 21 | system('touch control/wordlists/SmartWordlist.txt') 22 | end 23 | 24 | # Get list of all plaintext passwords and save it to a file 25 | @customers = Customers.order(Sequel.asc(:name)).all 26 | @plaintexts = Hashes.where(cracked: 1, unique: true).order(Sequel.asc(:plaintext)).select(:plaintext).all 27 | file_name = 'control/tmp/plaintext.txt' 28 | 29 | File.open(file_name, 'w') do |f| 30 | @plaintexts.each do |entry| 31 | f.puts entry.plaintext 32 | end 33 | end 34 | 35 | # Get list of all wordlists 36 | # TODO add --parallel # 37 | # We could get this via the facter gem 38 | # Facter.value('processors'['count']) 39 | cpu_count = `cat /proc/cpuinfo | grep processor | wc -l`.to_i 40 | shell_cmd = 'sort --parallel ' + cpu_count.to_s + ' -u control/tmp/plaintext.txt ' 41 | @wordlists = Wordlists.all 42 | @wordlists.each do |entry| 43 | shell_cmd = shell_cmd + entry.path.to_s + ' ' if entry.type == 'static' 44 | end 45 | # We move to temp to prevent wordlist importer from accidentally loading the smart wordlist too early 46 | shell_cmd += '-o control/tmp/SmartWordlist.txt' 47 | p 'shell_cmd: ' + shell_cmd 48 | system(shell_cmd) 49 | 50 | shell_mv_cmd = 'mv control/tmp/SmartWordlist.txt control/wordlists/SmartWordlist.txt' 51 | system(shell_mv_cmd) 52 | 53 | # update wordlist size 54 | wordlist = Wordlists.first(name: 'Smart Wordlist') 55 | wordlist.size = '0' # trigger background job 56 | # update hashvalue 57 | wordlist.checksum = nil 58 | wordlist.save 59 | 60 | # Update checksum 61 | Resque.enqueue(WordlistChecksum) 62 | 63 | # Remove plaintext list 64 | File.delete('control/tmp/plaintext.txt') if File.exist?('control/tmp/plaintext.txt') 65 | 66 | # Update keyspace per task ( really should be done at runtime) 67 | tasks = Tasks.where(wl_id: wordlist.id).all 68 | tasks.each do |task| 69 | task.keyspace = getKeyspace(task) 70 | task.save 71 | end 72 | 73 | # resume all jobqueue items that are 'paused' to 'queued' 74 | taskqueues = Taskqueues.where(status: 'Paused').all 75 | taskqueues.each do |entry| 76 | entry.status = 'Queued' 77 | entry.save 78 | end 79 | end 80 | -------------------------------------------------------------------------------- /views/assign_tasks.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | /https://jsfiddle.net/vigneshmoha/bbxMe/2/ 4 | %body 5 | .span15 6 | .container 7 | .col-md-12 8 | .row 9 | .page-header 10 | - if params[:edit] == '1' 11 | %h1 Edit Your Assigned Tasks. 12 | - else 13 | %h1 Assign Tasks to Job: #{@job.name} 14 | .row 15 | .col-md-10.pull-left 16 | Each task will be ran once 17 | = succeed "." do 18 | %u in order selected 19 | You can create new tasks by selecting 'tasks' in the above menu. 20 | %br 21 | %br 22 | .container 23 | .row 24 | .col-md-12 25 | .table 26 | %table{class: 'table table'} 27 | %thead 28 | %tr 29 | %th 30 | %b Task Name 31 | %th 32 | %b Type 33 | %th 34 | %b Control 35 | %tbody 36 | - if @jobtasks_tasks 37 | - @jobtasks_tasks.each do |jobtask| 38 | %tr 39 | %td 40 | #{jobtask['task_name']} 41 | %td 42 | #{jobtask['task_type']} 43 | %td 44 | %a.btn.btn-success{href: "/jobs/move_task?job_id=#{@job.id}&task_id=#{jobtask['task_id']}&action=UP"} 45 | %i.glyphicon.glyphicon-chevron-up{title: 'Move Up'} 46 | %a.btn.btn-success{href: "/jobs/move_task?job_id=#{@job.id}&task_id=#{jobtask['task_id']}&action=DOWN"} 47 | %i.glyphicon.glyphicon-chevron-down{title: 'Move Down'} 48 | %a.btn.btn-danger{href: "/jobs/remove_task?job_id=#{@job.id}&jobtask_id=#{jobtask['jobtask_id']}"} 49 | %i.glyphicon.glyphicon-trash{title: 'Delete'} 50 | %tr 51 | %tr 52 | %td 53 | %label.control-label{for: ''} 54 | .btn-group 55 | .btn.btn-default.dropdown-toggle{"data-toggle" => 'dropdown'} 56 | Add Task 57 | %span.caret 58 | %ul.dropdown-menu.dropdown-menu-left 59 | - @available_tasks.each do |task| 60 | %li 61 | %a{href: "/jobs/assign_task?job_id=#{@job.id}&task_id=#{task['id']}"} #{task['name']} 62 | %td 63 | %td 64 | .container 65 | .row 66 | .col-md-12 67 | %a.btn.btn-primary{href: "/jobs/complete?job_id=#{@job.id}"} 68 | Done -------------------------------------------------------------------------------- /views/hub.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | %body 4 | .span15 5 | .container 6 | .col-md-12 7 | .row 8 | .page-header 9 | %h1 10 | Hashview Hub 11 | .row 12 | .col-md-10.pull-left 13 | Welcome to Hashview Hub. Here unlock hashes that have been cracked in the Hub. You can do so by hashfile or by hashtype. 14 | %br 15 | %br 16 | .container 17 | .row 18 | .col-md-12 19 | .table 20 | %table{class: 'table table'} 21 | %thead 22 | %tr 23 | %th 24 | %b Hash Type 25 | %th 26 | %b Crack Rate 27 | %th 28 | %b Control 29 | %tbody 30 | - if @cracked_by_hashtype_count 31 | - @cracked_by_hashtype_count.each do |hashtype, value| 32 | %tr 33 | %td 34 | #{modeToFriendly(hashtype)} 35 | %td 36 | #{value} 37 | %td 38 | %a.btn.btn-success{href: "#modal#{hashtype}", 'data-toggle' => 'modal'} 39 | %i.glyphicon.glyphicon-cloud-download{title: 'Unlock from Hashview Hub'} 40 | .modal.fade.modal{id: "modal#{hashtype}", role: 'dialog', tabindex: '-1', "aria-hidden" => 'true'} 41 | .modal-dialog.modal-lg 42 | .modal-content 43 | .modal-header 44 | %button.close{'aria-label' => 'Close', 'data-dismiss' => 'modal', type: 'button'} 45 | %span{'aria-hidden' => 'true'} × 46 | %h4.modal-title Check Hashview Hub for #{modeToFriendly(hashtype)} hashes? 47 | .modal-body 48 | %p 49 | Hashview will check the Hub for matching hashes that have already been cracked and unlock them locally. 50 | Note, this might take some time. 51 | %br 52 | .table 53 | %table{class: 'table'} 54 | %tr 55 | %td Total number of locally uncracked hashes: #{value} 56 | %tr 57 | %td 58 | .modal-footer 59 | %button.btn.btn-default{'data-dismiss' => 'modal', type: 'button'} Close 60 | %a.btn.btn-success{type: 'button', href: "/hub/hash/reveal/hashtype/#{hashtype}"} Confirm -------------------------------------------------------------------------------- /control/rules/specific.rule: -------------------------------------------------------------------------------- 1 | ## rule: switch last two chars of word with each other 2 | ## limits: words greater or equal 10 chars length 3 | ## example: johnnoble ---> johnnobel 4 | ## extras: experienced effective cases 5 | 6 | >A k l 7 | >A k u 8 | >A k c 9 | 10 | ## rule: permuted switch of chars of word with each other 11 | ## limits: char positions 0 to 9 12 | ## example: peterbishop ---> petrebishop 13 | ## extras: none 14 | 15 | *01 16 | *02 17 | *03 18 | *04 19 | *05 20 | *06 21 | *07 22 | *08 23 | *09 24 | *12 25 | *13 26 | *14 27 | *15 28 | *16 29 | *17 30 | *18 31 | *19 32 | *23 33 | *24 34 | *25 35 | *26 36 | *27 37 | *28 38 | *29 39 | *34 40 | *35 41 | *36 42 | *37 43 | *38 44 | *39 45 | *45 46 | *46 47 | *47 48 | *48 49 | *49 50 | *56 51 | *57 52 | *58 53 | *59 54 | *67 55 | *68 56 | *69 57 | *78 58 | *79 59 | *89 60 | 61 | ## rule: increase char 62 | ## limits: positions 0 to 9 63 | ## example: nina555 ---> nina666 64 | ## extras: none 65 | 66 | +0 67 | +1 68 | +2 69 | +3 70 | +4 71 | +5 72 | +6 73 | +7 74 | +8 75 | +9 76 | 77 | +0+1 78 | +1+2 79 | +2+3 80 | +3+4 81 | +4+5 82 | +5+6 83 | +6+7 84 | +7+8 85 | +8+9 86 | 87 | +0+0 88 | +1+1 89 | +2+2 90 | +3+3 91 | +4+4 92 | +5+5 93 | +6+6 94 | +7+7 95 | +8+8 96 | +9+9 97 | 98 | +0+1+2 99 | +1+2+3 100 | +2+3+4 101 | +3+4+5 102 | +4+5+6 103 | +5+6+7 104 | +6+7+8 105 | +7+8+9 106 | 107 | +0+0+0 108 | +1+1+1 109 | +2+2+2 110 | +3+3+3 111 | +4+4+4 112 | +5+5+5 113 | +6+6+6 114 | +7+7+7 115 | +8+8+8 116 | +9+9+9 117 | 118 | +0+1+2+3 119 | +1+2+3+4 120 | +2+3+4+5 121 | +3+4+5+6 122 | +4+5+6+7 123 | +5+6+7+8 124 | +6+7+8+9 125 | 126 | +0+0+0+0 127 | +1+1+1+1 128 | +2+2+2+2 129 | +3+3+3+3 130 | +4+4+4+4 131 | +5+5+5+5 132 | +6+6+6+6 133 | +7+7+7+7 134 | +8+8+8+8 135 | +9+9+9+9 136 | 137 | ## rule: decrease char 138 | ## limits: positions 0 to 9 139 | ## example: astrid0816 ---> astrid0815 140 | ## extras: none 141 | 142 | -0 143 | -1 144 | -2 145 | -3 146 | -4 147 | -5 148 | -6 149 | -7 150 | -8 151 | -9 152 | 153 | -0-1 154 | -1-2 155 | -2-3 156 | -3-4 157 | -4-5 158 | -5-6 159 | -6-7 160 | -7-8 161 | -8-9 162 | 163 | -0-0 164 | -1-1 165 | -2-2 166 | -3-3 167 | -4-4 168 | -5-5 169 | -6-6 170 | -7-7 171 | -8-8 172 | -9-9 173 | 174 | -0-1-2 175 | -1-2-3 176 | -2-3-4 177 | -3-4-5 178 | -4-5-6 179 | -5-6-7 180 | -6-7-8 181 | -7-8-9 182 | 183 | -0-0-0 184 | -1-1-1 185 | -2-2-2 186 | -3-3-3 187 | -4-4-4 188 | -5-5-5 189 | -6-6-6 190 | -7-7-7 191 | -8-8-8 192 | -9-9-9 193 | 194 | -0-1-2-3 195 | -1-2-3-4 196 | -2-3-4-5 197 | -3-4-5-6 198 | -4-5-6-7 199 | -5-6-7-8 200 | -6-7-8-9 201 | 202 | -0-0-0-0 203 | -1-1-1-1 204 | -2-2-2-2 205 | -3-3-3-3 206 | -4-4-4-4 207 | -5-5-5-5 208 | -6-6-6-6 209 | -7-7-7-7 210 | -8-8-8-8 211 | -9-9-9-9 212 | -------------------------------------------------------------------------------- /control/rules/oscommerce.rule: -------------------------------------------------------------------------------- 1 | ^0^0 2 | ^1^0 3 | ^2^0 4 | ^3^0 5 | ^4^0 6 | ^5^0 7 | ^6^0 8 | ^7^0 9 | ^8^0 10 | ^9^0 11 | ^a^0 12 | ^b^0 13 | ^c^0 14 | ^d^0 15 | ^e^0 16 | ^f^0 17 | ^0^1 18 | ^1^1 19 | ^2^1 20 | ^3^1 21 | ^4^1 22 | ^5^1 23 | ^6^1 24 | ^7^1 25 | ^8^1 26 | ^9^1 27 | ^a^1 28 | ^b^1 29 | ^c^1 30 | ^d^1 31 | ^e^1 32 | ^f^1 33 | ^0^2 34 | ^1^2 35 | ^2^2 36 | ^3^2 37 | ^4^2 38 | ^5^2 39 | ^6^2 40 | ^7^2 41 | ^8^2 42 | ^9^2 43 | ^a^2 44 | ^b^2 45 | ^c^2 46 | ^d^2 47 | ^e^2 48 | ^f^2 49 | ^0^3 50 | ^1^3 51 | ^2^3 52 | ^3^3 53 | ^4^3 54 | ^5^3 55 | ^6^3 56 | ^7^3 57 | ^8^3 58 | ^9^3 59 | ^a^3 60 | ^b^3 61 | ^c^3 62 | ^d^3 63 | ^e^3 64 | ^f^3 65 | ^0^4 66 | ^1^4 67 | ^2^4 68 | ^3^4 69 | ^4^4 70 | ^5^4 71 | ^6^4 72 | ^7^4 73 | ^8^4 74 | ^9^4 75 | ^a^4 76 | ^b^4 77 | ^c^4 78 | ^d^4 79 | ^e^4 80 | ^f^4 81 | ^0^5 82 | ^1^5 83 | ^2^5 84 | ^3^5 85 | ^4^5 86 | ^5^5 87 | ^6^5 88 | ^7^5 89 | ^8^5 90 | ^9^5 91 | ^a^5 92 | ^b^5 93 | ^c^5 94 | ^d^5 95 | ^e^5 96 | ^f^5 97 | ^0^6 98 | ^1^6 99 | ^2^6 100 | ^3^6 101 | ^4^6 102 | ^5^6 103 | ^6^6 104 | ^7^6 105 | ^8^6 106 | ^9^6 107 | ^a^6 108 | ^b^6 109 | ^c^6 110 | ^d^6 111 | ^e^6 112 | ^f^6 113 | ^0^7 114 | ^1^7 115 | ^2^7 116 | ^3^7 117 | ^4^7 118 | ^5^7 119 | ^6^7 120 | ^7^7 121 | ^8^7 122 | ^9^7 123 | ^a^7 124 | ^b^7 125 | ^c^7 126 | ^d^7 127 | ^e^7 128 | ^f^7 129 | ^0^8 130 | ^1^8 131 | ^2^8 132 | ^3^8 133 | ^4^8 134 | ^5^8 135 | ^6^8 136 | ^7^8 137 | ^8^8 138 | ^9^8 139 | ^a^8 140 | ^b^8 141 | ^c^8 142 | ^d^8 143 | ^e^8 144 | ^f^8 145 | ^0^9 146 | ^1^9 147 | ^2^9 148 | ^3^9 149 | ^4^9 150 | ^5^9 151 | ^6^9 152 | ^7^9 153 | ^8^9 154 | ^9^9 155 | ^a^9 156 | ^b^9 157 | ^c^9 158 | ^d^9 159 | ^e^9 160 | ^f^9 161 | ^0^a 162 | ^1^a 163 | ^2^a 164 | ^3^a 165 | ^4^a 166 | ^5^a 167 | ^6^a 168 | ^7^a 169 | ^8^a 170 | ^9^a 171 | ^a^a 172 | ^b^a 173 | ^c^a 174 | ^d^a 175 | ^e^a 176 | ^f^a 177 | ^0^b 178 | ^1^b 179 | ^2^b 180 | ^3^b 181 | ^4^b 182 | ^5^b 183 | ^6^b 184 | ^7^b 185 | ^8^b 186 | ^9^b 187 | ^a^b 188 | ^b^b 189 | ^c^b 190 | ^d^b 191 | ^e^b 192 | ^f^b 193 | ^0^c 194 | ^1^c 195 | ^2^c 196 | ^3^c 197 | ^4^c 198 | ^5^c 199 | ^6^c 200 | ^7^c 201 | ^8^c 202 | ^9^c 203 | ^a^c 204 | ^b^c 205 | ^c^c 206 | ^d^c 207 | ^e^c 208 | ^f^c 209 | ^0^d 210 | ^1^d 211 | ^2^d 212 | ^3^d 213 | ^4^d 214 | ^5^d 215 | ^6^d 216 | ^7^d 217 | ^8^d 218 | ^9^d 219 | ^a^d 220 | ^b^d 221 | ^c^d 222 | ^d^d 223 | ^e^d 224 | ^f^d 225 | ^0^e 226 | ^1^e 227 | ^2^e 228 | ^3^e 229 | ^4^e 230 | ^5^e 231 | ^6^e 232 | ^7^e 233 | ^8^e 234 | ^9^e 235 | ^a^e 236 | ^b^e 237 | ^c^e 238 | ^d^e 239 | ^e^e 240 | ^f^e 241 | ^0^f 242 | ^1^f 243 | ^2^f 244 | ^3^f 245 | ^4^f 246 | ^5^f 247 | ^6^f 248 | ^7^f 249 | ^8^f 250 | ^9^f 251 | ^a^f 252 | ^b^f 253 | ^c^f 254 | ^d^f 255 | ^e^f 256 | ^f^f 257 | -------------------------------------------------------------------------------- /views/verify_hashtypes.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | %body 4 | :javascript 5 | function showDiv(obj) { 6 | var Index = document.hashTypeForm.hashtype.options[document.hashTypeForm.hashtype.selectedIndex].value 7 | if(Index == "99999") 8 | { 9 | document.getElementById('manual_div').style.display = 'inline'; 10 | } 11 | else 12 | { 13 | document.getElementById('manual_div').style.display = 'none'; 14 | } 15 | } 16 | .span15 17 | .container 18 | .col-md-12 19 | .row 20 | .page-header 21 | %h1 22 | Confirm Hash Type 23 | .row 24 | .col-md-12.pull-left 25 | Hashview will attempt to automatically detect the hash type (hashcat -m). Select one of the detected hash types (there could be multiple) or choose other and select the mode you with hashcat to use. 26 | %p 27 | Note: if you select an invalid option, your crack will not complete successfully. 28 | %br 29 | %br 30 | .container 31 | .col-md-12 32 | .row 33 | %form{name: 'hashTypeForm', id: 'hashTypeForm', class: 'form-horizontal', action: '/customers/upload/verify_hashtype', method: 'post'} 34 | .form-group 35 | %label.control-label.col-xs-2{for: ''} Detected Hash(s): 36 | .col-xs-3 37 | %select.form-control{id: 'hashtype', name: 'hashtype', onchange: 'showDiv()'} 38 | - @hashtypes.each do |type| 39 | %option{value: "#{type}", name: 'hashtype', type: 'button'} #{modeToFriendly(type)} 40 | %option{value: '99999', name: 'hashtype', type: 'button'} Other 41 | %input{type: 'hidden', name: 'hashid', value: "#{params[:hashid].to_s}"} 42 | %input{type: 'hidden', name: 'filetype', value: "#{params[:filetype].to_s}"} 43 | %input{type: 'hidden', name: 'job_id', value: "#{params[:job_id].to_s}"} 44 | %input{type: 'hidden', name: 'customer_id', value: "#{params[:customer_id].to_s}"} 45 | 46 | .section 47 | %div{class: "label_leftalign field"} 48 | - if @hashtypes.size == 0 49 | #manual_div{style: 'display:inline'} 50 | %label.control-label.col-xs-2{for: ''} Enter Manual Type: 51 | .col-xs-4 52 | 53 | - else 54 | #manual_div{style: 'display:none'} 55 | %label.control-label.col-xs-2{for: ''} Enter Manual Type: 56 | .col-xs-4 57 | 58 | .form-group 59 | .col-xs-offset-2.col-xs-10 60 | %button.btn.btn-primary{type: 'submit'} Confirm 61 | -------------------------------------------------------------------------------- /views/customer_list.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | %body 4 | .span15 5 | .container 6 | .col-md-12 7 | .row 8 | .page-header 9 | %h1 10 | Customers 11 | .row 12 | .col-md-10.pull-left 13 | The following are a list of customers currently configured in Hashview. All Jobs, passwords and hashes will be assigned to a single customer. Deleting a customer will remove ALL data from the system. 14 | .col-md-2.pull-right 15 | %a.btn.btn-primary.pull-left{href: '/customers/create'} 16 | Add a New Customer 17 | %br 18 | %br 19 | .container 20 | .row 21 | .col-md-12 22 | .table 23 | %table{class: 'table table-striped'} 24 | %thead 25 | %tr 26 | %th 27 | %b Name 28 | %th 29 | %b Description 30 | %th 31 | %b Control 32 | %tbody 33 | - if @customers 34 | - @customers.each do |customer| 35 | %tr 36 | %td #{customer.name} 37 | %td #{customer.description} 38 | %td 39 | %a.btn.btn-warning{href: "/customers/edit/#{customer.id}"} 40 | %i.glyphicon.glyphicon-cog{title: 'Edit'} 41 | %a.btn.btn-danger{href: "#modal#{customer.id}", "data-toggle" => 'modal'} 42 | %i.glyphicon.glyphicon-trash{title: 'Delete'} 43 | .modal.fade.modal{id: "modal#{customer.id}", role: 'dialog', tabindex: '-1', "aria-hidden" => 'true'} 44 | .modal-dialog.modal-lg 45 | .modal-content 46 | .modal-header 47 | %button.close{"aria-label" => 'Close', "data-dismiss" => 'modal', type: 'button'} 48 | %span{"aria-hidden" => 'true'} × 49 | %h4.modal-title Remove #{customer.name}? 50 | .modal-body 51 | %p 52 | By confirming, you will delete all instances related to this customer including the following: 53 | %br 54 | .table 55 | %table{class: 'table'} 56 | %tr 57 | %td Total Associated Jobs: #{@total_jobs[customer.id]} 58 | %tr 59 | %td Total Associated HashFiles: #{@total_hashfiles[customer.id]} 60 | %tr 61 | %td 62 | .modal-footer 63 | %button.btn.btn-default{"data-dismiss" => 'modal', type: 'button'} Close 64 | %a.btn.btn-danger{type: 'button', href: "/customers/delete/#{customer.id}"} Confirm 65 | -------------------------------------------------------------------------------- /views/search_post.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | %body 4 | .span15 5 | .container 6 | .col-md-12 7 | .row 8 | .page-header 9 | %h1 10 | Search 11 | .container 12 | .row 13 | .col-md-12 14 | %form{action: '/search', method: 'post'} 15 | .form-group.col-xs-2 16 | %select.form-control{id: 'search_type', name: 'search_type'} 17 | - if params[:search_type] == 'username' 18 | %option{value: 'username', name: 'search_type', type: 'button', selected: 'selected'} Username 19 | - else 20 | %option{value: 'username', name: 'search_type', type: 'button'} Username 21 | - if params[:search_type] == 'hash' 22 | %option{value: 'hash', name: 'search_type', type: 'button', selected: 'selected'} Hash 23 | - else 24 | %option{value: 'hash', name: 'search_type', type: 'button'} Hash 25 | - if params[:search_type] == 'password' 26 | %option{value: 'password', name: 'search_type', type: 'button', selected: 'selected'} Password 27 | - else 28 | %option{value: 'password', name: 'search_type', type: 'button'} Password 29 | .form-group.col-md-8 30 | %input{type: 'textbox', class: 'form-control', name: 'value', id: 'value', placeholder: 'Search for...'} 31 | .form-group.col-xs-2 32 | %button.btn.btn-primary{type: 'submit'} Search 33 | %br 34 | %br 35 | .row 36 | .col-md-12 37 | .table 38 | %table{class: 'table table-striped'} 39 | %thead 40 | %tr 41 | %th Username 42 | %th Plaintext 43 | %th Type 44 | %th Hash 45 | %th Customer 46 | %tbody 47 | %tr 48 | - if @results 49 | - @results.each do |entry| 50 | %td #{entry['username']} 51 | %td 52 | // LC && RC 53 | - if entry['local_cracked'] == '1' and entry['hub_cracked'] == '1' 54 | #{entry['plaintext']} 55 | // LC && RU 56 | - elsif entry['local_cracked'] == '1' and entry['hub_cracked'] == '0' 57 | #{entry['plaintext']} 58 | // LU && RC 59 | - elsif entry['local_cracked'] == '0' and entry['hub_cracked'] == '1' 60 | - if entry['show_hub_results'] == '1' 61 | %a.btn.btn-success{href: "/hub/hash/reveal/hash/#{entry['id']}"} 62 | reveal 63 | - else 64 | %em uncracked 65 | // LU && RU 66 | - else 67 | %em uncracked 68 | %td #{modeToFriendly(entry['hashtype'].to_s)} 69 | %td #{entry['originalhash']} 70 | %td #{entry['name']} 71 | %tr 72 | - else 73 | %td "No Results" 74 | %tr 75 | -------------------------------------------------------------------------------- /views/account_edit.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | %body 4 | .span15 5 | %br 6 | .container 7 | - if @user 8 | %h2 Edit User 9 | - else 10 | %h2 Add User 11 | %br 12 | .row 13 | .col-md-10 14 | - if @user 15 | %form{class: 'form-horizontal', action: '/accounts/save', method: 'post'} 16 | .form-group 17 | %label.control-label.col-xs-2{for: ''} Username 18 | .col-md-6 19 | %input{type: 'textbox', class: 'form-control', name: 'username', id: 'username', value: @user.username} 20 | .form-group 21 | %label.control-label.col-xs-2{for: ''} Reset Password 22 | .col-md-6 23 | %input{type: 'password', class: 'form-control', name: 'password', id: 'password'} 24 | .form-group 25 | %label.control-label.col-xs-2{for: ''} Confirm Password 26 | .col-md-6 27 | %input{type: 'password', class: 'form-control', name: 'confirm', id: 'confirm'} 28 | .form-group 29 | %label.control-label.col-xs-2{for: ''} Email Address (optional) 30 | .col-md-6 31 | %input{type: 'textbox', class: 'form-control', name: 'email', id: 'email', value: @user.email} 32 | .form-group 33 | %label.control-label.col-xs-2{:for => ""} MFA (Google Authenticator) 34 | .col-md-6 35 | %input{:type => 'checkbox', :class => 'form-control', :name => 'mfa', :id => 'mfa', :checked => @user.mfa} 36 | - if @user.mfa 37 | .form-group 38 | %label.control-label.col-xs-2{:for => ""} QR Code 39 | .col-md-6 40 | %img{:src => @otp, :alt => "Google Authenticator QR Code" } 41 | %link{:href => "#{@otp}", :rel => "stylesheet"} 42 | 43 | .form-group 44 | .col-xs-offset-2.col-xs-10 45 | %input{type: 'hidden', name: 'account_id', value: "#{params[:account_id].to_s}"} 46 | %button.btn.btn-primary{type: 'submit'} Save 47 | - else 48 | %form{class: 'form-horizontal', action: '/accounts/create', method: 'post'} 49 | .form-group 50 | %label.control-label.col-xs-2{for: ''} Username 51 | .col-md-6 52 | %input{type: 'textbox', class: 'form-control', name: 'username', id: 'username'} 53 | .form-group 54 | %label.control-label.col-xs-2{for: ''} Password 55 | .col-md-6 56 | %input{type: 'password', class: 'form-control', name: 'password', id: 'password'} 57 | .form-group 58 | %label.control-label.col-xs-2{for: ''} Confirm Password 59 | .col-md-6 60 | %input{type: 'password', class: 'form-control', name: 'confirm', id: 'confirm'} 61 | .form-group 62 | %label.control-label.col-xs-2{for: ''} Email Address (optional) 63 | .col-md-6 64 | %input{type: 'textbox', class: 'form-control', name: 'email', id: 'email'} 65 | .form-group 66 | %label.control-label.col-xs-2{:for => ""} MFA (Google Authenticator) 67 | .col-md-6 68 | %input{:type => 'checkbox', :class => 'form-control', :name => 'mfa', :id => 'mfa'} 69 | .form-group 70 | .col-xs-offset-2.col-xs-10 71 | %button.btn.btn-primary{type: 'submit'} Create 72 | -------------------------------------------------------------------------------- /routes/accounts.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | get '/accounts/list' do 3 | @users = User.all 4 | haml :account_list 5 | end 6 | 7 | get '/accounts/create' do 8 | haml :account_edit 9 | end 10 | 11 | post '/accounts/create' do 12 | varWash(params) 13 | 14 | if params[:username].nil? || params[:username].empty? 15 | flash[:error] = 'You must have username.' 16 | redirect to('/accounts/create') 17 | end 18 | 19 | if (params[:password].nil? || params[:password].empty?) && !params[:mfa] 20 | flash[:error] = 'You must have a password.' 21 | redirect to('/accounts/create') 22 | end 23 | 24 | if params[:confirm].nil? || params[:confirm].empty? && !params[:mfa] 25 | flash[:error] = 'You must have a password.' 26 | redirect to('/accounts/create') 27 | end 28 | 29 | # validate that no other user account exists 30 | @users = User.where(username: params[:username]).all 31 | if @users.empty? 32 | if params[:password] != params[:confirm] 33 | flash[:error] = 'Passwords do not match' 34 | redirect to('/accounts/create') 35 | else 36 | new_user = User.new 37 | new_user.username = params[:username] 38 | new_user.password = params[:password] 39 | new_user.email = params[:email] unless params[:email].nil? || params[:email].empty? 40 | if params[:mfa] 41 | new_user.mfa = 't' 42 | new_user.auth_secret = ROTP::Base32.random_base32 43 | else 44 | new_user.mfa = 'f' 45 | new_user.auth_secret = '' 46 | end 47 | new_user.admin = 't' 48 | new_user.id = User.last[:id].to_i + 1 # sequel does not understand composite primary keys, and cant figure out which autoincrements 49 | new_user.save 50 | end 51 | else 52 | flash[:error] = 'User account already exists.' 53 | redirect to('/accounts/create') 54 | end 55 | redirect to('/accounts/list') 56 | end 57 | 58 | get '/accounts/edit/:account_id' do 59 | varWash(params) 60 | 61 | @user = User.first(id: params[:account_id]) 62 | data = Rack::Utils.escape(ROTP::TOTP.new(@user.auth_secret).provisioning_uri(@user.username)) 63 | @otp = "https://chart.googleapis.​com/chart?chs=200x200&chld=M|0&cht=qr&chl=#{data}" 64 | haml :account_edit 65 | end 66 | 67 | post '/accounts/save' do 68 | varWash(params) 69 | 70 | if params[:account_id].nil? || params[:account_id].empty? 71 | flash[:error] = 'Invalid account.' 72 | redirect to('/accounts/list') 73 | end 74 | 75 | if params[:username].nil? || params[:username].empty? 76 | flash[:error] = 'Invalid username.' 77 | redirect to("/accounts/edit/#{params[:account_id]}") 78 | end 79 | 80 | if params[:password] != params[:confirm] 81 | flash[:error] = 'Passwords do not match.' 82 | redirect to("/accounts/edit/#{params[:account_id]}") 83 | end 84 | 85 | user = User.first(id: params[:account_id]) 86 | user.username = params[:username] 87 | user.password = params[:password] unless params[:password].nil? || params[:password].empty? 88 | user.email = params[:email] unless params[:email].nil? || params[:email].empty? 89 | if params[:mfa] && user.auth_secret == '' 90 | user.mfa = 't' 91 | user.auth_secret = ROTP::Base32.random_base32 92 | elsif params[:mfa] 93 | user.mfa='t' 94 | else 95 | user.mfa = 'f' 96 | user.auth_secret = '' 97 | end 98 | user.save 99 | 100 | flash[:success] = 'Account successfully updated.' 101 | 102 | redirect to('/accounts/list') 103 | end 104 | 105 | get '/accounts/delete/:id' do 106 | varWash(params) 107 | 108 | @user = User.first(id: params[:id]) 109 | @user.destroy unless @user.nil? 110 | 111 | redirect to('/accounts/list') 112 | end 113 | -------------------------------------------------------------------------------- /public/css/jquery.bs_grid.bs2.css: -------------------------------------------------------------------------------- 1 | /* 2 | * bs_grid v0.9.2 CSS (for Bootstrap 2) **************************************** 3 | */ 4 | 5 | /* 6 | DO NOT CHANGE this file, as it will be overwritten in next update. 7 | Write your own classes in other css file. 8 | */ 9 | 10 | .tools { 11 | height: 32px; 12 | } 13 | 14 | .col-checkbox { 15 | margin-top: 0 !important; 16 | } 17 | 18 | .columns-label { 19 | margin-top: 3px; 20 | margin-bottom: 3px; 21 | font-weight: normal; 22 | } 23 | 24 | .columns-li-padding { 25 | padding: 3px 20px; 26 | } 27 | 28 | .sorting-name { 29 | display: inline-block; 30 | padding-left: 20px; 31 | margin-top: 3px; 32 | margin-bottom: 3px; 33 | vertical-align: middle; 34 | padding-top: 5px; 35 | } 36 | 37 | .selected-rows { 38 | margin-left: 5px; 39 | margin-right: 2px; 40 | text-align: right; 41 | } 42 | 43 | .th-common { 44 | cursor: pointer; 45 | } 46 | 47 | .no-records-found { 48 | text-align: center; 49 | } 50 | 51 | .pagination-container { 52 | padding: 7px 7px 5px 7px !important; 53 | } 54 | 55 | .filters-container { 56 | padding: 0 7px 10px 7px !important; 57 | } 58 | 59 | .filters-button { 60 | margin: 0 3px; 61 | } 62 | 63 | /* Large desktop */ 64 | @media (min-width: 1200px) { 65 | } 66 | 67 | /* Portrait tablet to landscape and desktop */ 68 | @media (min-width: 768px) and (max-width: 979px) { 69 | } 70 | 71 | /* Landscape phone to portrait tablet */ 72 | @media (max-width: 767px) { 73 | .table-responsive { 74 | width: 100%; 75 | margin-bottom: 15px; 76 | overflow-x: scroll; 77 | overflow-y: hidden; 78 | -webkit-overflow-scrolling: touch; 79 | -ms-overflow-style: -ms-autohiding-scrollbar; 80 | border: 1px solid #ddd; 81 | } 82 | .table-responsive > .table { 83 | margin-bottom: 0; 84 | } 85 | .table-responsive > .table > thead > tr > th, 86 | .table-responsive > .table > tbody > tr > th, 87 | .table-responsive > .table > tfoot > tr > th, 88 | .table-responsive > .table > thead > tr > td, 89 | .table-responsive > .table > tbody > tr > td, 90 | .table-responsive > .table > tfoot > tr > td { 91 | white-space: nowrap; 92 | } 93 | .table-responsive > .table-bordered { 94 | border: 0; 95 | } 96 | .table-responsive > .table-bordered > thead > tr > th:first-child, 97 | .table-responsive > .table-bordered > tbody > tr > th:first-child, 98 | .table-responsive > .table-bordered > tfoot > tr > th:first-child, 99 | .table-responsive > .table-bordered > thead > tr > td:first-child, 100 | .table-responsive > .table-bordered > tbody > tr > td:first-child, 101 | .table-responsive > .table-bordered > tfoot > tr > td:first-child { 102 | border-left: 0; 103 | } 104 | .table-responsive > .table-bordered > thead > tr > th:last-child, 105 | .table-responsive > .table-bordered > tbody > tr > th:last-child, 106 | .table-responsive > .table-bordered > tfoot > tr > th:last-child, 107 | .table-responsive > .table-bordered > thead > tr > td:last-child, 108 | .table-responsive > .table-bordered > tbody > tr > td:last-child, 109 | .table-responsive > .table-bordered > tfoot > tr > td:last-child { 110 | border-right: 0; 111 | } 112 | .table-responsive > .table-bordered > tbody > tr:last-child > th, 113 | .table-responsive > .table-bordered > tfoot > tr:last-child > th, 114 | .table-responsive > .table-bordered > tbody > tr:last-child > td, 115 | .table-responsive > .table-bordered > tfoot > tr:last-child > td { 116 | border-bottom: 0; 117 | } 118 | } 119 | 120 | /* Landscape phones and down */ 121 | @media (max-width: 480px) { 122 | } -------------------------------------------------------------------------------- /views/layout.haml: -------------------------------------------------------------------------------- 1 | !!! 5 2 | %html{lang: 'en'} 3 | %head 4 | %script{src: '/js/jquery-2.1.3.min.js'} 5 | %script{src: '/js/bootstrap.js'} 6 | %script{src: '/js/modules.js'} 7 | %meta{charset: 'utf-8'}/ 8 | %title HashView - Password Cracking Management Console 9 | %meta{content: '', name: 'All types of crack are welcome'}/ 10 | %link{href: "/css/#{@settings.ui_themes}.css", rel: 'stylesheet'}/ 11 | %link{href: "/css/hashviewStyle.css", rel: 'stylesheet'}/ 12 | 13 | :css 14 | .body { 15 | padding-top: 60px; 16 | padding-bottom: 40px; 17 | } 18 | .padded { 19 | padding-top: 10px; 20 | padding-bottom: 5px; 21 | padding-left: 15px; 22 | padding-right: 0px; 23 | } 24 | %link{href: "/css/bootstrap-responsive.css", :rel => "stylesheet"} 25 | %body 26 | .navbar.navbar-inverse.navbar-static-top 27 | .container 28 | %a.navbar-brand(href="/home") 29 | Hashview 30 | %button.navbar-toggle(data-toggle="collapse" data-target=".navHeaderCollapse") 31 | %span.icon-bar 32 | %span.icon-bar 33 | %span.icon-bar 34 | .collapse.navbar-collapse.navHeaderCollapse 35 | %ul.nav.navbar-nav.navbar-right.vCenter 36 | %li 37 | - if isBusy? 38 | %span.label.label-danger Busy eating 39 | - else 40 | %span.label.label-success Feed me nom nom 41 | - if validSession? 42 | %li 43 | %a(href="/jobs/list") Jobs 44 | %li 45 | %a(href="/tasks/list") Tasks 46 | - if hubEnabled? 47 | %li 48 | %a(href="/hub") Hub 49 | %li.dropdown 50 | %a.dropdown-toggle(data-toggle="dropdown" href="#") 51 | Manage 52 | %b.caret 53 | %ul.dropdown-menu 54 | %li 55 | %a(href="/customers/list") Customers 56 | %li 57 | %a(href="/wordlists/list") Wordlists 58 | %li 59 | %a(href="/rules/list") Rules 60 | %li 61 | %a(href='/hashfiles/list') Hashfiles 62 | %li 63 | %a(href='/agents/list') Agents 64 | %li.divider{role: 'separator'} 65 | %li 66 | %a(href="/analytics") Analytics 67 | %li 68 | %a(href="/search") Search 69 | %li.divider{role: 'separator'} 70 | %li 71 | %a(href='/accounts/list') User Accounts 72 | %li 73 | %a(href="/settings") Global Settings 74 | %li 75 | %a(href="/logout") Logout 76 | %li 77 | - if !validSession? 78 | %a(href="/login") Login 79 | - if flash[:info] 80 | .container 81 | .flash.alert.alert-info{role: 'info'} 82 | = flash[:info] 83 | - if flash[:error] 84 | .container 85 | .flash.alert.alert-danger{role: 'alert'} 86 | = flash[:error] 87 | - if flash[:warning] 88 | .container 89 | .flash.alert.alert-warning{role: 'warning'} 90 | = flash[:warning] 91 | - if flash[:success] 92 | .container 93 | .flash.alert.alert-success{role: 'success'} 94 | = flash[:success] 95 | %script{type: 'text/javascript'} 96 | :plain 97 | window.setTimeout(function() { 98 | $(".flash").fadeTo(500, 0).slideUp(500, function(){ 99 | $(this).remove(); 100 | }); 101 | }, 3000); 102 | = yield 103 | -------------------------------------------------------------------------------- /helpers/cracked_importer.rb: -------------------------------------------------------------------------------- 1 | # updates run time for each hashfile after a job has completed 2 | def updateDbRunTime(job_id, hashfile_id, run_time) 3 | jobtask = Jobtasks.first(id: job_id) 4 | jobtask.run_time = run_time 5 | jobtask.save 6 | 7 | hashfile = Hashfiles.first(id: hashfile_id) 8 | hashfile.total_run_time = hashfile.total_run_time + run_time.to_i 9 | hashfile.save 10 | end 11 | 12 | # imports the uploaded crackfile 13 | def importCracked(id, crack_file, run_time) 14 | # this assumes a job completed successfully. we need to add check for failures or killed processes 15 | 16 | jobtasks = Jobtasks.first(id: id) 17 | job = Jobs.first(id: jobtasks.job_id) 18 | 19 | # determine hashfile path 20 | hash_file = 'control/hashes/hashfile_' + jobtasks.job_id.to_s + '_' + jobtasks.task_id.to_s + '.txt' 21 | 22 | # obtain the hashfile type (we always assume a crackfile will contain only one type of hashes) 23 | # this isnt the best approach. consider storing hashtype in hashfiles or extract hashtype when updating a row in hashes table 24 | hashfilehash = Hashfilehashes.first(hashfile_id: job.hashfile_id) 25 | # hashfilehashes doesnt store hashtype, so obtain it from hashes table 26 | hashtype = Hashes.first(id: hashfilehash.hash_id).hashtype.to_s 27 | 28 | unless File.zero?(crack_file) 29 | File.open(crack_file).each_line do |line| 30 | hash_pass = line.split(/:/) 31 | plaintext = hash_pass[-1] # Get last entry 32 | plaintext = plaintext.chomp 33 | plaintext = plaintext.scan(/../).map { |x| x.hex.chr}.join # Convert from hex to ascii 34 | 35 | hash_pass.pop # removes tail entry which should have been the plaintext (in hex) 36 | # Handle salted hashes 37 | # There's gotta be a better way to do this 38 | if hashtype == '10' || hashtype == '20' || hashtype == '30' || hashtype == '40' || hashtype == '50' || hashtype == '60' ||hashtype == '110' || hashtype == '120' || hashtype == '121' || hashtype == '130' || hashtype == '140' || hashtype == '150' || hashtype == '160' || hashtype == '1100' || hashtype == '1410' || hashtype == '1420' || hashtype == '1430' || hashtype == '1440' || hashtype == '1450' || hashtype == '1460' || hashtype == '2811' || hashtype == '2611' || hashtype == '2711' || hashtype == '3610' || hashtype == '3710' || hashtype == '3720' || hashtype == '3910' || hashtype == '4010' || hashtype == '4110' || hashtype == '2711' || hashtype == '11000' 39 | hash = hash_pass.join(":") 40 | elsif hashtype == '5500' 41 | hash = hash_pass[3] + ':' + hash_pass[4] + ':' + hash_pass[5] 42 | elsif hashtype == '5600' 43 | hash = hash_pass[0] + ':' + hash_pass[1] + ':' + hash_pass[2] + ':' + hash_pass[3] + ':' + hash_pass[4] + ':' + hash_pass[5] 44 | elsif hashtype == '7400' 45 | parts = hash_pass[0].split('$') 46 | # p 'PARTS: ' + parts.to_s 47 | hash = '%' + parts[3].to_s + '$' + parts[4].to_s 48 | else 49 | hash = hash_pass[0] 50 | end 51 | 52 | # This will pull all hashes from DB regardless of job id 53 | if hashtype == '7400' 54 | results = HVDB.fetch('SELECT * FROM hashes WHERE (hashtype = 7400 AND originalhash like ?)', hash)[0] 55 | records = Hashes.where(id: results.id).select(:id, :cracked, :plaintext, :lastupdated) 56 | else 57 | records = Hashes.where(originalhash: hash, cracked: 0 ).select(:id, :cracked, :plaintext, :lastupdated) 58 | end 59 | # Yes its slow... we know. 60 | records.each do |entry| 61 | entry.cracked = 1 62 | entry.lastupdated = Time.now 63 | entry.plaintext = plaintext 64 | entry.save 65 | end 66 | end 67 | end 68 | 69 | puts '==== import complete ====' 70 | 71 | begin 72 | File.delete(crack_file) 73 | File.delete(hash_file) 74 | 75 | rescue SystemCallError 76 | p 'ERROR: ' + $!.to_s 77 | end 78 | 79 | # TODO this might be broken now that we are chunking 80 | updateDbRunTime(id, job.hashfile_id, run_time) 81 | end 82 | -------------------------------------------------------------------------------- /views/task_list.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | %body 4 | .span15 5 | .container 6 | .col-md-12 7 | .row 8 | .page-header 9 | %h1 10 | Tasks 11 | .row 12 | .col-md-10.pull-left 13 | Task are predefined hashcat commands. Any number of tasks can be assigned to a Job. 14 | .col-md-2.pull-right 15 | %a.btn.btn-primary.pull-right{href: '/tasks/create'} 16 | Create Task 17 | %br 18 | %br 19 | .container 20 | .row 21 | .col-md-12 22 | .table 23 | %table{class: 'table table-striped'} 24 | %thead 25 | %tr 26 | %th 27 | %b Task Name 28 | %th 29 | %b Type 30 | %th 31 | %b Controls 32 | %tbody 33 | - if @tasks 34 | - @tasks.each do |task| 35 | %tr 36 | %td #{task.name} 37 | %td #{task.hc_attackmode} 38 | %td 39 | %a.btn.btn-info{href: "#modal#{task.id}", 'data-toggle' => 'modal'} 40 | %i.glyphicon.glyphicon-info-sign{title: 'Info'} 41 | .modal.fade.modal{id: "modal#{task.id}", role: 'dialog', tabindex: '-1', 'aria-hidden' => 'true'} 42 | .modal-dialog.modal-lg 43 | .modal-content 44 | .modal-header 45 | %button.close{'aria-label' => 'Close', 'data-dismiss' => 'modal', type: 'button'} 46 | %span{'aria-hidden' => 'true'} × 47 | %h4.modal-title Task details for: #{task.name} 48 | .modal-body 49 | .row 50 | .form-group 51 | %label.control-label.col-xs-2{for: ''} Task Name 52 | .col-xs-10 53 | #{task.name} 54 | .row 55 | .form-group 56 | %label.control-label.col-xs-2{for: ''} Attack Mode 57 | .col-xs-4 58 | #{task.hc_attackmode} 59 | - if task.hc_attackmode == 'dictionary' 60 | .row 61 | .form-group 62 | %label.control-label.col-xs-2{for: ''} Wordlist 63 | .col-xs-4 64 | - @wordlists.each do |wl| 65 | - if wl.id.to_i == task.wl_id.to_i 66 | #{wl.name} 67 | -if task.hc_rule != 'none' 68 | .row 69 | .form-group 70 | %label.control-label.col-xs-2{for: ''} Dictionary Rule 71 | .col-xs-4 72 | - @rules.each do |rule| 73 | - if rule.id.to_i == task.hc_rule.to_i 74 | #{rule.name} (cnt: #{rule.size}) 75 | .row 76 | .form-group 77 | %label.control-label.col-xs-2{for: ''} Keyspace 78 | .col-xs-4 79 | - if task.keyspace.nil? 80 | Task will not be chunked 81 | - else 82 | #{task.keyspace} 83 | %a.btn.btn-warning{href: "/tasks/edit/#{task.id}"} 84 | %i.glyphicon.glyphicon-cog{title: 'Edit'} 85 | %a.btn.btn-danger{href: "/tasks/delete/#{task.id}"} 86 | %i.glyphicon.glyphicon-trash{title: 'Delete'} 87 | -------------------------------------------------------------------------------- /helpers/status.rb: -------------------------------------------------------------------------------- 1 | def isBusy? 2 | @results = `ps awwux | grep -i Hashcat | egrep -v "(grep|sudo|resque|^$)"` 3 | true if @results.length > 1 4 | end 5 | 6 | def isDevelopment? 7 | Sinatra::Base.development? 8 | end 9 | 10 | def isOldVersion? 11 | 12 | # Check to see what version the app is at 13 | application_version = File.open('VERSION') {|f| f.readline} 14 | puts 'APPLICATION VERSION: ' + application_version.to_s 15 | # application_version = application_version.to_i 16 | 17 | # Check for v0.5.1 18 | # Note this version does not have a versions column. Going forward we will check that value 19 | has_version_column = false 20 | if Settings.columns.include?(:version) 21 | has_version_column = true 22 | end 23 | 24 | if has_version_column 25 | @settings = Settings.first 26 | db_version = @settings.version 27 | puts 'DB:VERSION ' + db_version.to_s 28 | if Gem::Version.new(db_version) < Gem::Version.new(application_version) 29 | return true 30 | else 31 | return false 32 | end 33 | else 34 | puts 'No version column found. Assuming Version 0.5.1' 35 | true 36 | end 37 | end 38 | 39 | def updateTaskqueueStatus(taskqueue_id, status, agent_id) 40 | queue = Taskqueues.first(id: taskqueue_id) 41 | if queue 42 | queue.status = status 43 | queue.agent_id = agent_id 44 | queue.save 45 | 46 | # if we are setting a status to completed, check to see if this is the last task in queue. if so, set jobtask to completed 47 | if status == 'Completed' 48 | remaining_queued_tasks = Taskqueues.where(jobtask_id: queue.jobtask_id, job_id: queue.job_id, status: 'Queued').all 49 | remaining_running_tasks = Taskqueues.where(jobtask_id: queue.jobtask_id, job_id: queue.job_id, status: 'Running').all 50 | remaining_importing_tasks = Taskqueues.where(jobtask_id: queue.jobtask_id, job_id: queue.job_id, status: 'Importing').all 51 | if remaining_queued_tasks.empty? && remaining_running_tasks.empty? && remaining_importing_tasks.empty? 52 | updateJobTaskStatus(queue.jobtask_id, 'Completed') 53 | end 54 | end 55 | end 56 | end 57 | 58 | def updateJobTaskStatus(jobtask_id, status) 59 | 60 | jobtask = Jobtasks.first(id: jobtask_id) 61 | jobtask.status = status 62 | jobtask.save 63 | 64 | # if this is the last task for this current job, then set the job to be completed 65 | # find the job of the jobtask id: 66 | job = Jobs.first(id: jobtask[:job_id]) 67 | if job.status == 'Queued' 68 | job.status = 'Running' 69 | job.started_at = Time.now 70 | job.save 71 | end 72 | # find all tasks for current job: 73 | jobtasks = Jobtasks.where(job_id: job[:id]).all 74 | # if no more job are set to queue, consider the job completed 75 | done = true 76 | jobtasks.each do |jt| 77 | # if a jobtask equals one of these statuses we are not done 78 | if jt.status == 'Queued' || jt.status == 'Running' || jt.status == 'Importing' 79 | done = false 80 | break 81 | end 82 | end 83 | 84 | # Send email 85 | if job.notify_completed == true && done == true 86 | puts '===== Sending Email =====' 87 | user = User.first(username: job.last_updated_by) 88 | hashfile = Hashfiles.first(id: job.hashfile_id) 89 | customer = Customers.first(id: job.customer_id) 90 | @hash_ids = Set.new 91 | Hashfilehashes.where(hashfile_id: hashfile.id).each do |entry| 92 | @hash_ids.add(entry.hash_id) 93 | end 94 | total_cracked = Hashes.count(id: @hash_ids, cracked: 1) 95 | total = Hashes.count(id: @hash_ids, cracked: 0) 96 | if user.email 97 | sendEmail(user.email, "Your Job: #{job.name} for #{customer.name} has completed.", "#{user.username},\r\n\r\nHashview completed cracking #{hashfile.name}.\r\n\r\nTotal Cracked: #{total_cracked}.\r\nTotal Remaining: #{total}.") 98 | end 99 | puts '===== Email Sent =====' 100 | end 101 | 102 | # toggle job status 103 | if done 104 | job.status = 'Completed' 105 | job.ended_at = Time.now 106 | job.save 107 | # purge all queued tasks 108 | @taskqueues = HVDB[:taskqueues] 109 | @taskqueues.filter(job_id: job.id).delete 110 | 111 | end 112 | true 113 | end 114 | 115 | def hubEnabled? 116 | # Returns true if hub is enabled, and status is registered 117 | hub_settings = HubSettings.first 118 | hub_settings.status == 'registered' ? true : false 119 | end 120 | -------------------------------------------------------------------------------- /routes/rules.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | get '/rules/list' do 4 | @rules = Rules.all 5 | @rule_content = [] 6 | 7 | @rules.each do |rule_file| 8 | element = {} 9 | element['id'] = rule_file.id 10 | element['name'] = rule_file.name 11 | element['size'] = rule_file.size 12 | begin 13 | text = File.open(rule_file.path).read 14 | text.gsub!(/\r\n?/, "\n") 15 | rescue 16 | text = '' 17 | end 18 | @content = [] 19 | text.each_line do |line| 20 | line = line.gsub(/\s+/, '') 21 | @content.push(line) 22 | end 23 | element['content'] = @content 24 | @rule_content.push(element) 25 | end 26 | 27 | haml :rule_list 28 | end 29 | 30 | post '/rules/new' do 31 | varWash(params) 32 | 33 | if !params[:rules_file_name] || params[:rules_file_name].nil? 34 | flash[:error] = 'Your Rules file must have a name.' 35 | redirect to('/rules/list') 36 | end 37 | 38 | if params[:new_rules].nil? || params[:new_rules].empty? 39 | flash[:error] = 'You must supply at least one rule.' 40 | redirect to('/rules/list') 41 | end 42 | 43 | # Change our name 44 | name = params[:rules_file_name].gsub('\s', '_') 45 | 46 | # Check to see if we've cont a name conflict 47 | rules_file_check = Rules.first(name: name) 48 | unless rules_file_check.nil? || rules_file_check.empty? 49 | flash[:error] = 'That rules name is in use, please pick a new one.' 50 | redirect to('/rules/list') 51 | end 52 | 53 | # Create DB entry first so that our background job doesn't accidentally pull it in. 54 | rules_file = Rules.new 55 | rules_file.name = name 56 | rules_file.lastupdated = Time.now 57 | 58 | # temporarily save file for testing 59 | rules_file_path_name = "control/rules/#{name}.rule" 60 | rules_file.path = rules_file_path_name 61 | rules_file.size = 0 # note this will get updated by background task 62 | 63 | # Parse uploaded file into an array 64 | rules_array = params[:new_rules].to_s.gsub(/\x0d\x0a/, "\x0a") # in theory we shouldnt run into any false positives? 65 | File.open(rules_file_path_name, 'w') do |f| 66 | f.puts(rules_array) 67 | end 68 | 69 | rules_file.checksum = Digest::SHA2.hexdigest(File.read(rules_file_path_name)) 70 | rules_file.save 71 | 72 | flash[:success] = 'Successfully created new rule.' 73 | redirect to('/rules/list') 74 | end 75 | 76 | get '/rules/delete/:id' do 77 | varWash(params) 78 | 79 | rules_file = Rules.first(id: params[:id]) 80 | if !rules_file 81 | flash[:error] = 'No such rules file exists.' 82 | redirect to('/rules/list') 83 | else 84 | # check if rule file is in use 85 | # TODO tasks should store rules by id not name 86 | @task_list = Tasks.where(hc_rule: rules_file.name).all 87 | unless @task_list.empty? 88 | flash[:error] = 'This Rules file is associated with a task, it cannot be deleted.' 89 | redirect to('/rules/list') 90 | end 91 | 92 | # remove from filesystem 93 | begin 94 | File.delete(rules_file.path) 95 | rescue 96 | flash[:warning] = 'No file found on disk' 97 | end 98 | 99 | # delete from db 100 | rules_file.destroy 101 | 102 | end 103 | flash[:success] = 'Rules file deleted.' 104 | redirect to('/rules/list') 105 | end 106 | 107 | post '/rules/save/:id' do 108 | # varWash(params) 109 | 110 | if !params[:edit_rules] || params[:edit_rules].nil? 111 | flash[:error] = 'You must have some rules.' 112 | redirect to('/rules/list') 113 | end 114 | 115 | if !params[:id] || params[:id].nil? 116 | flash[:error] = 'Rule file must be specified' 117 | redirect to('/rules/list') 118 | end 119 | 120 | # TODO do we want to lock rule files from being edited when they're in an existing job? 121 | 122 | @rules = params[:edit_rules].split(/[\r\n]+/) 123 | 124 | # move old rule to tmp folder 125 | rules_file = Rules.first(id: params[:id]) 126 | cmd = "mv #{rules_file.path} control/tmp/#{rules_file.name}" 127 | `#{cmd}` 128 | 129 | # write to disk 130 | File.open(rules_file.path, 'w') { |f| f.puts(@rules) } 131 | 132 | # update file size 133 | size = File.foreach(rules_file.path).inject(0) do |c| 134 | c + 1 135 | end 136 | rules_file.size = size 137 | rules_file.checksum = Digest::SHA2.hexdigest(File.read(rules_file.path)) 138 | rules_file.save 139 | 140 | flash[:success] = 'Successfully uploaded rules file.' 141 | redirect to('/rules/list') 142 | end 143 | -------------------------------------------------------------------------------- /models/master.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'sequel' 3 | require 'bcrypt' 4 | require 'rotp' 5 | 6 | Sequel::Model.plugin :json_serializer 7 | 8 | # read config 9 | options = YAML.load_file('config/database.yml') 10 | 11 | # there has to be a better way to handle this shit 12 | if ENV['RACK_ENV'] == 'test' 13 | HVDB = Sequel.mysql(options['test']) 14 | HVDB.loggers << Logger.new(STDOUT) 15 | HVDB.sql_log_level = :debug 16 | elsif ENV['RACK_ENV'] == 'development' 17 | HVDB = Sequel.mysql(options['development']) 18 | #HVDB.max_connections = '10' 19 | #HVDB.pool_timeout = '600' 20 | HVDB.loggers << Logger.new(STDOUT) 21 | HVDB.sql_log_level = :debug 22 | elsif ENV['RACK_ENV'] == ('production' || 'default') 23 | HVDB = Sequel.mysql(options['production']) 24 | # HVDB.loggers << Logger.new(STDOUT) 25 | else 26 | puts 'ERROR: You must define an environment. ex: RACK_ENV=production' 27 | exit 28 | end 29 | 30 | # User class object to handle user account credentials 31 | class User < Sequel::Model(:users) 32 | plugin :validation_class_methods 33 | attr_accessor :password 34 | validates_presence_of :username 35 | 36 | def password=(pass) 37 | @password = pass 38 | self.hashed_password = User.encrypt(@password) 39 | end 40 | 41 | def self.encrypt(pass) 42 | BCrypt::Password.create(pass) 43 | end 44 | 45 | def self.authenticate(username, pass) 46 | user = User.first(username: username) 47 | if user.mfa 48 | return user.username if pass == ROTP::TOTP.new(user.auth_secret).now.to_s 49 | elsif user 50 | return user.username if BCrypt::Password.new(user.hashed_password) == pass 51 | end 52 | end 53 | 54 | def self.create_test_user(attrs = {}) 55 | user = User.new( 56 | username: 'test', 57 | admin: true, 58 | phone: '12223334444', 59 | email: 'test@localhost.com', 60 | hashed_password: BCrypt::Password.create('omgplains') 61 | ) 62 | user.save 63 | user.update(attrs) if attrs 64 | user.save 65 | return user.id 66 | end 67 | 68 | def self.delete_test_user(id) 69 | user = User.first(id: id) 70 | user.delete 71 | end 72 | 73 | def self.delete_all_users 74 | @users = User.all 75 | @users.each do |user| 76 | user.delete 77 | end 78 | end 79 | 80 | end 81 | 82 | # Class to handle authenticated sessions 83 | class Sessions < Sequel::Model(:sessions) 84 | def self.isValid?(session_key) 85 | sessions = Sessions.first(session_key: session_key) 86 | 87 | return true if sessions 88 | end 89 | 90 | def self.type(session_key) 91 | sess = Sessions.first(session_key: session_key) 92 | 93 | if sess 94 | if User.first(username: sess.username).admin 95 | return TRUE 96 | else 97 | return FALSE 98 | end 99 | end 100 | end 101 | 102 | def self.getUsername(session_key) 103 | sess = Sessions.first(session_key: session_key) 104 | 105 | return sess.username if sess 106 | end 107 | end 108 | 109 | # Each Customer record will be stored here 110 | class Customers < Sequel::Model(:customers) 111 | 112 | end 113 | 114 | class Agents < Sequel::Model(:agents) 115 | 116 | end 117 | 118 | # Each job generated by user will be stored here 119 | class Jobs < Sequel::Model(:jobs) 120 | 121 | end 122 | 123 | # Jobs will have multiple crack tasks 124 | class Jobtasks < Sequel::Model(:jobtasks) 125 | 126 | end 127 | 128 | # Task definitions 129 | class Tasks < Sequel::Model(:tasks) 130 | 131 | end 132 | 133 | # Table for handling hashes cracked and uncracked 134 | class Hashes < Sequel::Model(:hashes) 135 | 136 | end 137 | 138 | # Table for managing association between users and hashes 139 | class Hashfilehashes < Sequel::Model(:hashfilehashes) 140 | 141 | end 142 | 143 | # User Settings 144 | class Settings < Sequel::Model(:settings) 145 | 146 | end 147 | 148 | # HashCat settings 149 | class HashcatSettings < Sequel::Model(:hashcat_settings) 150 | 151 | end 152 | 153 | # Hashview Hub Settings 154 | class HubSettings < Sequel::Model(:hub_settings) 155 | 156 | end 157 | 158 | # Wordlist 159 | class Wordlists < Sequel::Model(:wordlists) 160 | 161 | end 162 | 163 | # Rules Class 164 | class Rules < Sequel::Model(:rules) 165 | 166 | end 167 | 168 | # Hashfile Class 169 | class Hashfiles < Sequel::Model(:hashfiles) 170 | 171 | end 172 | 173 | # task queue (we no logger use a resque worker) 174 | class Taskqueues < Sequel::Model(:taskqueues) 175 | 176 | end 177 | -------------------------------------------------------------------------------- /views/rule_list.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | %body 4 | .span15 5 | .container 6 | .col-md-12 7 | .row 8 | .page-header 9 | %h1 10 | Rules 11 | .row 12 | .col-md-10.pull-left 13 | Rules are a set of instructions to be combined with Wordlists. Hashview comes preloaded with common rules, but you can upload more by clicking the 'Upload Rules' button to the left or by dropping the files to /[install path]/control/rules/. 14 | .col-md-2.pull-right 15 | %a.btn.btn-primary.pull-right{href: '#modal_new', 'data-toggle' => 'modal'} 16 | New Rule File 17 | .modal.fade.modal{id: 'modal_new', role: 'dialog', tabindex: '-1', "aria-hidden" => 'true'} 18 | .modal-dialog.modal-lg 19 | .modal-content 20 | .modal-header 21 | %button.close{'aria-label' => 'Close', 'data-dismiss' => 'modal', type: 'button'} 22 | %span{"aria-hidden" => 'true'} × 23 | %h4.modal-title New Rules file 24 | .modal-body 25 | %form{name: 'new_rules_form', id: 'new_rules_form', class: 'form-horizontal', action: '/rules/new', method: 'post'} 26 | .form-group 27 | %label.control-label.col-xs-1{for: ''} Name 28 | .col-xs-11 29 | %input{type: 'textbox', name: 'rules_file_name', class: 'form-control'} 30 | .form-group 31 | .col-xs-12 32 | %textarea{name: 'new_rules', rows: '10', cols: '12', form: 'new_rules_form', class: 'form-control'} 33 | .form-group 34 | .col-xs-12 35 | %button.btn.btn-primary.pull-right{type: 'submit'} Submit 36 | %br 37 | .container 38 | .row 39 | .col-md-12 40 | .table 41 | %table{class: 'table table-striped'} 42 | %thead 43 | %tr 44 | %th 45 | %b Name 46 | %th 47 | %b Size 48 | %th 49 | %b Action 50 | %tbody 51 | - if @rule_content 52 | - @rule_content.each do |rule_file| 53 | %tr 54 | %td #{rule_file['name']} 55 | %td #{rule_file['size']} 56 | %td 57 | %a.btn.btn-warning{href: "#modal#{rule_file['id']}", "data-toggle" => 'modal'} 58 | %i.glyphicon.glyphicon-cog{title: 'Edit'} 59 | .modal.fade.modal{id: "modal#{rule_file['id']}", role: 'dialog', tabindex: '-1', "aria-hidden" => 'true'} 60 | .modal-dialog.modal-lg 61 | .modal-content 62 | .modal-header 63 | %button.close{"aria-label" => 'Close', "data-dismiss" => 'modal', type: 'button'} 64 | %span{"aria-hidden" => 'true'} × 65 | %h4.modal-title Rules for: #{rule_file['name']} 66 | .modal-body 67 | %form{name: 'edit_rules_form', id: 'edit_rules_form', class: 'form-horizontal', action: "/rules/save/#{rule_file['id']}", method: 'post'} 68 | .form-group 69 | .col-xs-12 70 | %textarea{name: 'edit_rules', rows: '10', cols: '12', class: 'form-control'} 71 | - if rule_file['content'] 72 | - rule_file['content'].each do |line| 73 | #{line} 74 | .form-group 75 | .col-xs-offset-2.col-xs-10 76 | %input{type: 'hidden', name: 'id', value: "#{rule_file['id']}"} 77 | .form-group 78 | .col-xs-12 79 | %button.btn.btn-primary.pull-right{type: 'submit'} Save 80 | %a.btn.btn-danger{href: "/rules/delete/#{rule_file['id']}"} 81 | %i.glyphicon.glyphicon-trash{title: 'Delete'} 82 | -------------------------------------------------------------------------------- /routes/main.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | get '/' do 3 | @users = User.all 4 | 5 | if @users.empty? 6 | redirect to('/register') 7 | elsif !validSession? 8 | redirect to('/login') 9 | else 10 | redirect to('/home') 11 | end 12 | end 13 | 14 | get '/home' do 15 | 16 | @jobs = Jobs.order(Sequel.asc(:queued_at)).all 17 | @jobtasks = Jobtasks.all 18 | @tasks = Tasks.all 19 | @taskqueues = Taskqueues.all 20 | @agents = Agents.all 21 | @time_now = Time.now 22 | 23 | @customers = Customers.all 24 | @active_jobs = Jobs.where(status: 'Running').select(:id, :status) 25 | 26 | # JumboTron Display 27 | # Building out an array of hashes for the jumbotron display 28 | @jumbotron = [] 29 | @jobs.each do |job| 30 | element = {} 31 | if job.status == 'Running' || job.status == 'importing' 32 | #@Customers = Customers.first(id: job.customer_id).each do |customer| 33 | @customers.each do |customer| 34 | if customer.id == job.customer_id.to_i 35 | element['customer_name'] = customer.name 36 | end 37 | end 38 | 39 | element['job_name'] = job.name 40 | 41 | @hash_ids = Array.new 42 | 43 | Hashfilehashes.where(hashfile_id: job[:hashfile_id]).select(:hash_id).each do |entry| 44 | @hash_ids.push(entry[:hash_id]) 45 | end 46 | 47 | hashfile_total = Hashes.where(id: @hash_ids) 48 | hashfile_cracked = Hashes.where(id: @hash_ids, cracked: 1) 49 | 50 | 51 | element['hashfile_cracked'] = hashfile_cracked.count 52 | element['hashfile_total'] = hashfile_total.count 53 | element['hashfile_progress'] = (hashfile_cracked.count.to_f / hashfile_total.count.to_f) * 100 54 | element['job_starttime'] = job[:started_at] 55 | 56 | time_now = Time.now 57 | if time_now.to_time - job[:started_at].to_time > 86400 58 | element['job_runtime'] = ((time_now.to_time - job[:started_at].to_time).to_f / 86400).round(2).to_s + ' Days' 59 | elsif time_now.to_time - job[:started_at].to_time > 3600 60 | element['job_runtime'] = ((time_now.to_time - job[:started_at].to_time).to_f / 3600).round(2).to_s + ' Hours' 61 | elsif time_now.to_time - job[:started_at].to_time > 60 62 | element['job_runtime'] = ((time_now.to_time - job[:started_at].to_time).to_f / 60).round(2).to_s + ' Minutes' 63 | elsif time_now.to_time - job[:started_at].to_time >= 0 64 | element['job_runtime'] = (time_now.to_time - job[:started_at].to_time).to_f.round(2).to_s + ' Seconds' 65 | else 66 | element['job_runtime'] = 'Im ready coach, just send me in.' 67 | end 68 | 69 | total_speed = 0 70 | Taskqueues.where(job_id: job[:id], status: 'Running').all.each do |queued_task| 71 | agent = Agents.first(id: queued_task[:agent_id]) 72 | 73 | if agent.benchmark 74 | # Normalizing Benchmark Speeds 75 | if agent.benchmark.include? ' H/s' 76 | speed = agent.benchmark.split[0].to_f 77 | total_speed += speed 78 | elsif agent.benchmark.include? 'kH/s' 79 | speed = agent.benchmark.split[0].to_f 80 | speed *= 1000 81 | total_speed += speed 82 | elsif agent.benchmark.include? 'MH/s' 83 | speed = agent.benchmark.split[0].to_f 84 | speed *= 1000000 85 | total_speed += speed 86 | elsif agent.benchmark.include? 'GH/s' 87 | speed = agent.benchmark.split[0].to_f 88 | speed *= 1000000000 89 | total_speed += speed 90 | elsif agent.benchmark.include? 'TH/s' 91 | speed = agent.benchmark.split[0].to_f 92 | speed *= 1000000000000 93 | total_speed += speed 94 | else 95 | total_speed += 0 96 | end 97 | end 98 | end 99 | 100 | # Convert to Human Readable Format 101 | if total_speed > 1000000000000 102 | element['job_crackrate'] = (total_speed.to_f / 1000000000000).round(2).to_s + ' TH/s' 103 | elsif total_speed > 1000000000 104 | element['job_crackrate'] = (total_speed.to_f / 1000000000).round(2).to_s + ' GH/s' 105 | elsif total_speed > 1000000 106 | element['job_crackrate'] = (total_speed.to_f / 1000000).round(2).to_s + ' MH/s' 107 | elsif total_speed > 1000 108 | element['job_crackrate'] = (total_speed.to_f / 1000).round(2).to_s + ' kH/s' 109 | elsif total_speed >= 0 110 | element['job_crackrate'] = total_speed.to_f.round(2).to_s + ' H/s' 111 | else 112 | element['job_crackrate'] = '0 H/s' 113 | end 114 | 115 | @jumbotron.push(element) 116 | end 117 | end 118 | 119 | haml :home 120 | end -------------------------------------------------------------------------------- /views/job_edit.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | %body 4 | :javascript 5 | function showDiv() { 6 | var Index = document.jobs_form.customer.options[document.jobs_form.customer.selectedIndex].value 7 | if(Index == "add_new") 8 | { 9 | document.getElementById('new_customer_div').style.display = 'inline'; 10 | } 11 | else 12 | { 13 | document.getElementById('new_customer_div').style.display = 'none'; 14 | } 15 | } 16 | .span15 17 | .container 18 | .col-md-12 19 | .row 20 | .col-md-12 21 | .page-header 22 | - if params[:edit] == '1' 23 | %h1 Edit Job 24 | - else 25 | %h1 Create a new Job 26 | .row 27 | .col-md-10 28 | Enter the name and select the customer that this job will be running for. If this is a new company, select 'add new customer'. 29 | %br 30 | %br 31 | .container 32 | .row 33 | .col-md-12 34 | %form{name: 'jobs_form', id: 'jobs_form', class: 'form-horizontal', action: '/jobs/create', method: 'post'} 35 | .form-group 36 | %label.control-label.col-xs-2{for: ''} Job Name 37 | .col-xs-6 38 | - if params[:edit] == '1' 39 | %input{type: 'textbox', class: 'form-control', name: 'job_name', id: 'name', value: "#{@job.name.to_s}"} 40 | - else 41 | %input{type: 'textbox', class: 'form-control', name: 'job_name', id: 'name'} 42 | - if !@customers.empty? 43 | .form-group 44 | %label.control-label.col-xs-2{for: ''} Customer 45 | .col-xs-6 46 | %select.form-control{id: 'customer', name: 'customer', :onchange => 'showDiv()'} 47 | - @customers.each do |customer| 48 | - if params[:edit] == '1' 49 | - if customer.id == @job.customer_id 50 | %option{value: "#{customer.id}", name: 'customer_id', type: 'button', selected: 'selected'} #{customer.name} 51 | - else 52 | %option{value: "#{customer.id}", name: 'customer_id', type: 'button'} #{customer.name} 53 | - else 54 | %option{value: "#{customer.id}", name: 'customer_id', type: 'button'} #{customer.name} 55 | %option{value: 'add_new', name: 'customer_id', type: 'button'} New Customer 56 | .section 57 | %div{class: "label_leftalign field"} 58 | #new_customer_div{:style => 'display:none'} 59 | .form-group 60 | %label.control-label.col-xs-2{for: ''} Customer Name 61 | .col-xs-6 62 | %input{type: 'textbox', class: 'form-control', name: 'cust_name', id: 'name'} 63 | .form-group 64 | %label.control-label.col-xs-2{for: ''} Customer Description 65 | .col-xs-6 66 | %input{type: 'textbox', class: 'form-control', name: 'cust_desc', id: 'desc'} 67 | - else 68 | .form-group 69 | %label.control-label.col-xs-2{for: ''} Customer Name 70 | .col-xs-6 71 | %input{type: 'textbox', class: 'form-control', name: 'cust_name', id: 'name'} 72 | .form-group 73 | %label.control-label.col-xs-2{for: ''} Customer Description 74 | .col-xs-10 75 | %input{type: 'textbox', class: 'form-control', name: 'cust_desc', id: 'desc'} 76 | .form-group 77 | %label.control-label.col-xs-2{for: ''} Notify When Completed 78 | .col-xs-1.pull-left 79 | - if params[:edit] == '1' 80 | - if @job.notify_completed == true 81 | %input.checkbox.pull-left{type: 'checkbox', name: 'notify', id: 'notify', checked: 'checked'} 82 | - else 83 | %input.checkbox.pull-left{type: 'checkbox', name: 'notify', id: 'notify'} 84 | - else 85 | %input.checkbox.pull-left{type: 'checkbox', name: 'notify', id: 'notify'} 86 | .form-group 87 | .col-xs-offset-2.col-xs-10 88 | - if params[:edit] 89 | %input{type: 'hidden', name: 'edit', value: "#{params[:edit]}"} 90 | %input{type: 'hidden', name: 'job_id', value: "#{params[:job_id]}"} 91 | %input{type: 'hidden', name: 'customer_id', value: "#{params[:customer_id]}"} 92 | %button.btn.btn-primary{type: 'submit'} Update 93 | -else 94 | %button.btn.btn-primary{type: 'submit'} Create 95 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | ecmaFeatures: 2 | modules: true 3 | jsx: true 4 | 5 | env: 6 | amd: true 7 | browser: true 8 | es6: true 9 | jquery: true 10 | node: true 11 | 12 | # http://eslint.org/docs/rules/ 13 | rules: 14 | # Possible Errors 15 | comma-dangle: [2, never] 16 | no-cond-assign: 2 17 | no-console: 0 18 | no-constant-condition: 2 19 | no-control-regex: 2 20 | no-debugger: 2 21 | no-dupe-args: 2 22 | no-dupe-keys: 2 23 | no-duplicate-case: 2 24 | no-empty: 2 25 | no-empty-character-class: 2 26 | no-ex-assign: 2 27 | no-extra-boolean-cast: 2 28 | no-extra-parens: 0 29 | no-extra-semi: 2 30 | no-func-assign: 2 31 | no-inner-declarations: [2, functions] 32 | no-invalid-regexp: 2 33 | no-irregular-whitespace: 2 34 | no-negated-in-lhs: 2 35 | no-obj-calls: 2 36 | no-regex-spaces: 2 37 | no-sparse-arrays: 2 38 | no-unexpected-multiline: 2 39 | no-unreachable: 2 40 | use-isnan: 2 41 | valid-jsdoc: 0 42 | valid-typeof: 2 43 | 44 | # Best Practices 45 | accessor-pairs: 2 46 | block-scoped-var: 0 47 | complexity: [2, 6] 48 | consistent-return: 0 49 | curly: 0 50 | default-case: 0 51 | dot-location: 0 52 | dot-notation: 0 53 | eqeqeq: 2 54 | guard-for-in: 2 55 | no-alert: 2 56 | no-caller: 2 57 | no-case-declarations: 2 58 | no-div-regex: 2 59 | no-else-return: 0 60 | no-empty-label: 2 61 | no-empty-pattern: 2 62 | no-eq-null: 2 63 | no-eval: 2 64 | no-extend-native: 2 65 | no-extra-bind: 2 66 | no-fallthrough: 2 67 | no-floating-decimal: 0 68 | no-implicit-coercion: 0 69 | no-implied-eval: 2 70 | no-invalid-this: 0 71 | no-iterator: 2 72 | no-labels: 0 73 | no-lone-blocks: 2 74 | no-loop-func: 2 75 | no-magic-number: 0 76 | no-multi-spaces: 0 77 | no-multi-str: 0 78 | no-native-reassign: 2 79 | no-new-func: 2 80 | no-new-wrappers: 2 81 | no-new: 2 82 | no-octal-escape: 2 83 | no-octal: 2 84 | no-proto: 2 85 | no-redeclare: 2 86 | no-return-assign: 2 87 | no-script-url: 2 88 | no-self-compare: 2 89 | no-sequences: 0 90 | no-throw-literal: 0 91 | no-unused-expressions: 2 92 | no-useless-call: 2 93 | no-useless-concat: 2 94 | no-void: 2 95 | no-warning-comments: 0 96 | no-with: 2 97 | radix: 2 98 | vars-on-top: 0 99 | wrap-iife: 2 100 | yoda: 0 101 | 102 | # Strict 103 | strict: 0 104 | 105 | # Variables 106 | init-declarations: 0 107 | no-catch-shadow: 2 108 | no-delete-var: 2 109 | no-label-var: 2 110 | no-shadow-restricted-names: 2 111 | no-shadow: 0 112 | no-undef-init: 2 113 | no-undef: 0 114 | no-undefined: 0 115 | no-unused-vars: 0 116 | no-use-before-define: 0 117 | 118 | # Node.js and CommonJS 119 | callback-return: 2 120 | global-require: 2 121 | handle-callback-err: 2 122 | no-mixed-requires: 0 123 | no-new-require: 0 124 | no-path-concat: 2 125 | no-process-exit: 2 126 | no-restricted-modules: 0 127 | no-sync: 0 128 | 129 | # Stylistic Issues 130 | array-bracket-spacing: 0 131 | block-spacing: 0 132 | brace-style: 0 133 | camelcase: 0 134 | comma-spacing: 0 135 | comma-style: 0 136 | computed-property-spacing: 0 137 | consistent-this: 0 138 | eol-last: 0 139 | func-names: 0 140 | func-style: 0 141 | id-length: 0 142 | id-match: 0 143 | indent: 0 144 | jsx-quotes: 0 145 | key-spacing: 0 146 | linebreak-style: 0 147 | lines-around-comment: 0 148 | max-depth: 0 149 | max-len: 0 150 | max-nested-callbacks: 0 151 | max-params: 0 152 | max-statements: [2, 30] 153 | new-cap: 0 154 | new-parens: 0 155 | newline-after-var: 0 156 | no-array-constructor: 0 157 | no-bitwise: 0 158 | no-continue: 0 159 | no-inline-comments: 0 160 | no-lonely-if: 0 161 | no-mixed-spaces-and-tabs: 0 162 | no-multiple-empty-lines: 0 163 | no-negated-condition: 0 164 | no-nested-ternary: 0 165 | no-new-object: 0 166 | no-plusplus: 0 167 | no-restricted-syntax: 0 168 | no-spaced-func: 0 169 | no-ternary: 0 170 | no-trailing-spaces: 0 171 | no-underscore-dangle: 0 172 | no-unneeded-ternary: 0 173 | object-curly-spacing: 0 174 | one-var: 0 175 | operator-assignment: 0 176 | operator-linebreak: 0 177 | padded-blocks: 0 178 | quote-props: 0 179 | quotes: 0 180 | require-jsdoc: 0 181 | semi-spacing: 0 182 | semi: 0 183 | sort-vars: 0 184 | space-after-keywords: 0 185 | space-before-blocks: 0 186 | space-before-function-paren: 0 187 | space-before-keywords: 0 188 | space-in-parens: 0 189 | space-infix-ops: 0 190 | space-return-throw-case: 0 191 | space-unary-ops: 0 192 | spaced-comment: 0 193 | wrap-regex: 0 194 | 195 | # ECMAScript 6 196 | arrow-body-style: 0 197 | arrow-parens: 0 198 | arrow-spacing: 0 199 | constructor-super: 0 200 | generator-star-spacing: 0 201 | no-arrow-condition: 0 202 | no-class-assign: 0 203 | no-const-assign: 0 204 | no-dupe-class-members: 0 205 | no-this-before-super: 0 206 | no-var: 0 207 | object-shorthand: 0 208 | prefer-arrow-callback: 0 209 | prefer-const: 0 210 | prefer-reflect: 0 211 | prefer-spread: 0 212 | prefer-template: 0 213 | require-yield: 0 214 | -------------------------------------------------------------------------------- /control/rules/T0XlC-insert_space_and_special_0_F.rule: -------------------------------------------------------------------------------- 1 | # Created by: T0XlC 2 | # All special characters shifted from position 0 to position F 3 | # In memory of d3ad0ne 4 | i0 5 | i1 6 | i2 7 | i3 8 | i4 9 | i5 10 | i6 11 | i7 12 | i8 13 | i9 14 | iA 15 | iB 16 | iC 17 | iD 18 | iE 19 | iF 20 | i0. 21 | i1. 22 | i2. 23 | i3. 24 | i4. 25 | i5. 26 | i6. 27 | i7. 28 | i8. 29 | i9. 30 | iA. 31 | iB. 32 | iC. 33 | iD. 34 | iE. 35 | iF. 36 | i0! 37 | i1! 38 | i2! 39 | i3! 40 | i4! 41 | i5! 42 | i6! 43 | i7! 44 | i8! 45 | i9! 46 | iA! 47 | iB! 48 | iC! 49 | iD! 50 | iE! 51 | iF! 52 | i0@ 53 | i1@ 54 | i2@ 55 | i3@ 56 | i4@ 57 | i5@ 58 | i6@ 59 | i7@ 60 | i8@ 61 | i9@ 62 | iA@ 63 | iB@ 64 | iC@ 65 | iD@ 66 | iE@ 67 | iF@ 68 | i0# 69 | i1# 70 | i2# 71 | i3# 72 | i4# 73 | i5# 74 | i6# 75 | i7# 76 | i8# 77 | i9# 78 | iA# 79 | iB# 80 | iC# 81 | iD# 82 | iE# 83 | iF# 84 | i0$ 85 | i1$ 86 | i2$ 87 | i3$ 88 | i4$ 89 | i5$ 90 | i6$ 91 | i7$ 92 | i8$ 93 | i9$ 94 | iA$ 95 | iB$ 96 | iC$ 97 | iD$ 98 | iE$ 99 | iF$ 100 | i0% 101 | i1% 102 | i2% 103 | i3% 104 | i4% 105 | i5% 106 | i6% 107 | i7% 108 | i8% 109 | i9% 110 | iA% 111 | iB% 112 | iC% 113 | iD% 114 | iE% 115 | iF% 116 | i0^ 117 | i1^ 118 | i2^ 119 | i3^ 120 | i4^ 121 | i5^ 122 | i6^ 123 | i7^ 124 | i8^ 125 | i9^ 126 | iA^ 127 | iB^ 128 | iC^ 129 | iD^ 130 | iE^ 131 | iF^ 132 | i0& 133 | i1& 134 | i2& 135 | i3& 136 | i4& 137 | i5& 138 | i6& 139 | i7& 140 | i8& 141 | i9& 142 | iA& 143 | iB& 144 | iC& 145 | iD& 146 | iE& 147 | iF& 148 | i0* 149 | i1* 150 | i2* 151 | i3* 152 | i4* 153 | i5* 154 | i6* 155 | i7* 156 | i8* 157 | i9* 158 | iA* 159 | iB* 160 | iC* 161 | iD* 162 | iE* 163 | iF* 164 | i0( 165 | i1( 166 | i2( 167 | i3( 168 | i4( 169 | i5( 170 | i6( 171 | i7( 172 | i8( 173 | i9( 174 | iA( 175 | iB( 176 | iC( 177 | iD( 178 | iE( 179 | iF( 180 | i0) 181 | i1) 182 | i2) 183 | i3) 184 | i4) 185 | i5) 186 | i6) 187 | i7) 188 | i8) 189 | i9) 190 | iA) 191 | iB) 192 | iC) 193 | iD) 194 | iE) 195 | iF) 196 | i0_ 197 | i1_ 198 | i2_ 199 | i3_ 200 | i4_ 201 | i5_ 202 | i6_ 203 | i7_ 204 | i8_ 205 | i9_ 206 | iA_ 207 | iB_ 208 | iC_ 209 | iD_ 210 | iE_ 211 | iF_ 212 | i0- 213 | i1- 214 | i2- 215 | i3- 216 | i4- 217 | i5- 218 | i6- 219 | i7- 220 | i8- 221 | i9- 222 | iA- 223 | iB- 224 | iC- 225 | iD- 226 | iE- 227 | iF- 228 | i0" 229 | i1" 230 | i2" 231 | i3" 232 | i4" 233 | i5" 234 | i6" 235 | i7" 236 | i8" 237 | i9" 238 | iA" 239 | iB" 240 | iC" 241 | iD" 242 | iE" 243 | iF" 244 | i0' 245 | i1' 246 | i2' 247 | i3' 248 | i4' 249 | i5' 250 | i6' 251 | i7' 252 | i8' 253 | i9' 254 | iA' 255 | iB' 256 | iC' 257 | iD' 258 | iE' 259 | iF' 260 | i0/ 261 | i1/ 262 | i2/ 263 | i3/ 264 | i4/ 265 | i5/ 266 | i6/ 267 | i7/ 268 | i8/ 269 | i9/ 270 | iA/ 271 | iB/ 272 | iC/ 273 | iD/ 274 | iE/ 275 | iF/ 276 | i0: 277 | i1: 278 | i2: 279 | i3: 280 | i4: 281 | i5: 282 | i6: 283 | i7: 284 | i8: 285 | i9: 286 | iA: 287 | iB: 288 | iC: 289 | iD: 290 | iE: 291 | iF: 292 | i0; 293 | i1; 294 | i2; 295 | i3; 296 | i4; 297 | i5; 298 | i6; 299 | i7; 300 | i8; 301 | i9; 302 | iA; 303 | iB; 304 | iC; 305 | iD; 306 | iE; 307 | iF; 308 | i0> 309 | i1> 310 | i2> 311 | i3> 312 | i4> 313 | i5> 314 | i6> 315 | i7> 316 | i8> 317 | i9> 318 | iA> 319 | iB> 320 | iC> 321 | iD> 322 | iE> 323 | iF> 324 | i0< 325 | i1< 326 | i2< 327 | i3< 328 | i4< 329 | i5< 330 | i6< 331 | i7< 332 | i8< 333 | i9< 334 | iA< 335 | iB< 336 | iC< 337 | iD< 338 | iE< 339 | iF< 340 | i0= 341 | i1= 342 | i2= 343 | i3= 344 | i4= 345 | i5= 346 | i6= 347 | i7= 348 | i8= 349 | i9= 350 | iA= 351 | iB= 352 | iC= 353 | iD= 354 | iE= 355 | iF= 356 | i0? 357 | i1? 358 | i2? 359 | i3? 360 | i4? 361 | i5? 362 | i6? 363 | i7? 364 | i8? 365 | i9? 366 | iA? 367 | iB? 368 | iC? 369 | iD? 370 | iE? 371 | iF? 372 | i0] 373 | i1] 374 | i2] 375 | i3] 376 | i4] 377 | i5] 378 | i6] 379 | i7] 380 | i8] 381 | i9] 382 | iA] 383 | iB] 384 | iC] 385 | iD] 386 | iE] 387 | iF] 388 | i0[ 389 | i1[ 390 | i2[ 391 | i3[ 392 | i4[ 393 | i5[ 394 | i6[ 395 | i7[ 396 | i8[ 397 | i9[ 398 | iA[ 399 | iB[ 400 | iC[ 401 | iD[ 402 | iE[ 403 | iF[ 404 | i0` 405 | i1` 406 | i2` 407 | i3` 408 | i4` 409 | i5` 410 | i6` 411 | i7` 412 | i8` 413 | i9` 414 | iA` 415 | iB` 416 | iC` 417 | iD` 418 | iE` 419 | iF` 420 | i0{ 421 | i1{ 422 | i2{ 423 | i3{ 424 | i4{ 425 | i5{ 426 | i6{ 427 | i7{ 428 | i8{ 429 | i9{ 430 | iA{ 431 | iB{ 432 | iC{ 433 | iD{ 434 | iE{ 435 | iF{ 436 | i0} 437 | i1} 438 | i2} 439 | i3} 440 | i4} 441 | i5} 442 | i6} 443 | i7} 444 | i8} 445 | i9} 446 | iA} 447 | iB} 448 | iC} 449 | iD} 450 | iE} 451 | iF} 452 | i0| 453 | i1| 454 | i2| 455 | i3| 456 | i4| 457 | i5| 458 | i6| 459 | i7| 460 | i8| 461 | i9| 462 | iA| 463 | iB| 464 | iC| 465 | iD| 466 | iE| 467 | iF| 468 | i0~ 469 | i1~ 470 | i2~ 471 | i3~ 472 | i4~ 473 | i5~ 474 | i6~ 475 | i7~ 476 | i8~ 477 | i9~ 478 | iA~ 479 | iB~ 480 | iC~ 481 | iD~ 482 | iE~ 483 | iF~ -------------------------------------------------------------------------------- /helpers/build_crack_cmd.rb: -------------------------------------------------------------------------------- 1 | helpers do 2 | # this function builds the main hashcat cmd we use to crack. this should be moved to a helper script soon 3 | def buildCrackCmd(job_id, task_id) 4 | cmds = [] 5 | 6 | chunk_size = Settings.first().chunk_size 7 | chunks = {} 8 | chunk_skip = 0 9 | 10 | # order of opterations -m hashtype -a attackmode is dictionary? set wordlist, set rules if exist file/hash 11 | hc_settings = HashcatSettings.first 12 | # we no loger pull hc_binpath from the db. set this to a placeholder value and each 13 | # agent will replace it with their local hc_binpath 14 | hc_binpath = '@HASHCATBINPATH@' 15 | max_task_time = hc_settings.max_task_time 16 | @task = Tasks.first(id: task_id) 17 | @job = Jobs.first(id: job_id) 18 | rules_file = Rules.first(id: @task.hc_rule) 19 | hashfile_id = @job.hashfile_id 20 | hash_id = Hashfilehashes.first(hashfile_id: hashfile_id).hash_id 21 | hashtype = Hashes.first(id: hash_id).hashtype.to_s 22 | 23 | attackmode = @task.hc_attackmode.to_s 24 | mask = @task.hc_mask 25 | 26 | # if task contains a keyspace that is gt 0 perform chunking 27 | if @task[:keyspace].nil? 28 | chunking = false 29 | elsif @task[:keyspace].to_i > 0 && @task[:keyspace].to_i > chunk_size 30 | chunking = true 31 | 32 | # build a hash containing our skip and limit values 33 | chunk_num = 0 34 | while chunk_skip < @task[:keyspace].to_i 35 | skip = chunk_skip 36 | 37 | chunks[chunk_num] = [skip, chunk_size] 38 | 39 | chunk_num += 1 40 | chunk_skip = skip + chunk_size 41 | end 42 | end 43 | 44 | if attackmode == 'combinator' 45 | wordlist_list = @task.wl_id 46 | @wordlist_list_elements = wordlist_list.split(',') 47 | wordlist_one = Wordlists.first(id: @wordlist_list_elements[0]) 48 | wordlist_two = Wordlists.first(id: @wordlist_list_elements[1]) 49 | else 50 | wordlist = Wordlists.first(id: @task.wl_id) 51 | end 52 | 53 | target_file = 'control/hashes/hashfile_' + job_id.to_s + '_' + task_id.to_s + '.txt' 54 | 55 | # we assign and write output file before hashcat. 56 | # if hashcat creates its own output it does so with 57 | # elevated permissions and we wont be able to read it 58 | crack_file = 'control/outfiles/hc_cracked_' + @job.id.to_s + '_' + @task.id.to_s + '.txt' 59 | File.open(crack_file, 'w') 60 | 61 | case attackmode 62 | when 'bruteforce' 63 | cmd = hc_binpath + ' -m ' + hashtype + ' --potfile-disable' + ' --status --status-timer=15' + ' --runtime=' + max_task_time + ' --outfile-format 5 ' + ' --outfile ' + crack_file + ' ' + ' -a 3 ' + target_file 64 | when 'maskmode' 65 | cmd = hc_binpath + ' -m ' + hashtype + ' --potfile-disable' + ' --status --status-timer=15' + ' --outfile-format 5 ' + ' --outfile ' + crack_file + ' ' + ' -a 3 ' + target_file + ' ' + mask 66 | when 'dictionary' 67 | if @task.hc_rule.nil? || @task.hc_rule == 'none' 68 | cmd = hc_binpath + ' -m ' + hashtype + ' --potfile-disable' + ' --status --status-timer=15' + ' --outfile-format 5 ' + ' --outfile ' + crack_file + ' ' + target_file + ' ' + wordlist.path 69 | else 70 | cmd = hc_binpath + ' -m ' + hashtype + ' --potfile-disable' + ' --status --status-timer=15' + ' --outfile-format 5 ' + ' --outfile ' + crack_file + ' ' + ' -r ' + rules_file.path + ' ' + target_file + ' ' + wordlist.path 71 | end 72 | when 'combinator' 73 | cmd = hc_binpath + ' -m ' + hashtype + ' --potfile-disable' + ' --status --status-timer=15' + ' --outfile-format 5 ' + ' --outfile ' + crack_file + ' ' + ' -a 1 ' + target_file + ' ' + wordlist_one.path + ' ' + ' ' + wordlist_two.path + ' ' + @task.hc_rule.to_s 74 | else 75 | puts 'INVALID ATTACK MODE: ' + attackmode.to_s 76 | end 77 | 78 | # Add global options 79 | # --opencl-device-types 80 | if hc_settings.opencl_device_types.to_s != '0' 81 | cmd += ' --opencl-device-types ' + hc_settings.opencl_device_types.to_s 82 | end 83 | 84 | # --workload-profile 85 | if hc_settings.workload_profile.to_s != '0' 86 | cmd += ' --workload-profile ' + hc_settings.workload_profile.to_s 87 | end 88 | 89 | # --gpu-temp-disable 90 | if hc_settings.gpu_temp_disable == true 91 | cmd += ' --gpu-temp-disable' 92 | end 93 | 94 | # --gpu-temp-abort 95 | if hc_settings.gpu_temp_abort.to_s != '0' 96 | cmd += ' --gpu-temp-abort=' + hc_settings.gpu_temp_abort.to_s 97 | end 98 | 99 | # --gpu-temp-retain 100 | if hc_settings.gpu_temp_retain.to_s != '0' 101 | cmd += ' --gpu-temp-retain=' + hc_settings.gpu_temp_retain.to_s 102 | end 103 | 104 | # --force 105 | if hc_settings.hc_force == true 106 | cmd += ' --force' 107 | end 108 | 109 | if hc_settings.optimized_drivers == true 110 | cmd += ' -O' 111 | end 112 | 113 | # add skip and limit if we are chunking this task 114 | if chunking == true 115 | chunks.each do |_unused, value| 116 | if attackmode == 'maskmode' || attackmode == 'dictionary' 117 | cmds << cmd + ' -s ' + value[0].to_s + ' -l ' + value[1].to_s 118 | p cmd 119 | end 120 | end 121 | else 122 | cmds << cmd 123 | end 124 | 125 | cmds 126 | end 127 | end 128 | -------------------------------------------------------------------------------- /routes/downloads.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | get '/download' do 3 | varWash(params) 4 | 5 | if params[:graph] && !params[:graph].empty? 6 | # What kind of graph data are we dealing with here 7 | if params[:graph] == '1' # Total Hashes Cracked 8 | # Do Something 9 | elsif params[:graph] == '2' # Composition Breakdown 10 | # Do Something 11 | elsif params[:graph] == '3' # Analysis Detail 12 | @filecontents = Set.new 13 | file_name = 'error.txt' 14 | if params[:customer_id] && !params[:customer_id].empty? 15 | if params[:hashfile_id] && !params[:hashfile_id].nil? 16 | # Customer and Hashfile 17 | if params[:type] == 'cracked' 18 | @results = HVDB.fetch('SELECT a.username, h.originalhash, h.plaintext FROM hashes h LEFT JOIN hashfilehashes a ON h.id = a.hash_id LEFT JOIN hashfiles f on a.hashfile_id = f.id WHERE (f.customer_id = ? AND a.hashfile_id = ? and h.cracked = 1)', params[:customer_id],params[:hashfile_id]) 19 | file_name = "found_#{params[:customer_id]}_#{params[:hashfile_id]}.txt" 20 | elsif params[:type] == 'uncracked' 21 | @results = HVDB.fetch('SELECT a.username, h.originalhash FROM hashes h LEFT JOIN hashfilehashes a ON h.id = a.hash_id LEFT JOIN hashfiles f on a.hashfile_id = f.id WHERE (f.customer_id = ? AND a.hashfile_id = ? and h.cracked = 0)', params[:customer_id],params[:hashfile_id]) 22 | file_name = "left_#{params[:customer_id]}_#{params[:hashfile_id]}.txt" 23 | else 24 | # Do Something 25 | file_name = 'error.txt' 26 | end 27 | else 28 | # Just Customer 29 | if params[:type] == 'cracked' 30 | @results = HVDB.fetch('SELECT a.username, h.originalhash, h.plaintext FROM hashes h LEFT JOIN hashfilehashes a ON h.id = a.hash_id LEFT JOIN hashfiles f on a.hashfile_id = f.id WHERE (f.customer_id = ? and h.cracked = 1)', params[:customer_id]) 31 | file_name = "found_#{params[:customer_id]}.txt" 32 | elsif params[:type] == 'uncracked' 33 | @results = HVDB.fetch('SELECT a.username, h.originalhash FROM hashes h LEFT JOIN hashfilehashes a ON h.id = a.hash_id LEFT JOIN hashfiles f on a.hashfile_id = f.id WHERE (f.customer_id = ? and h.cracked = 0)', params[:customer_id]) 34 | file_name = "left_#{params[:customer_id]}.txt" 35 | else 36 | # Do Something 37 | file_name = 'error.txt' 38 | end 39 | end 40 | else 41 | # All 42 | if params[:type] == 'cracked' 43 | @results = HVDB.fetch('SELECT a.username, h.originalhash, h.plaintext FROM hashes h LEFT JOIN hashfilehashes a ON h.id = a.hash_id LEFT JOIN hashfiles f on a.hashfile_id = f.id WHERE (h.cracked = 1)') 44 | file_name = 'found_all.txt' 45 | elsif params[:type] == 'uncracked' 46 | @results = HVDB.fetch('SELECT a.username, h.originalhash FROM hashes h LEFT JOIN hashfilehashes a ON h.id = a.hash_id LEFT JOIN hashfiles f on a.hashfile_id = f.id WHERE (h.cracked = 0)') 47 | file_name = 'left_all.txt' 48 | else 49 | # Do Something 50 | file_name = 'error.txt' 51 | end 52 | end 53 | 54 | @results.each do |entry| 55 | entry[:username].nil? ? line = '' : line = entry[:username].to_s + ':' 56 | line += entry[:originalhash].to_s 57 | line += ':' + entry[:plaintext].to_s if params[:type] == 'cracked' 58 | @filecontents.add(line) 59 | end 60 | 61 | file_name = 'control/tmp/' + file_name 62 | 63 | File.open(file_name, 'w') do |f| 64 | @filecontents.each do |entry| 65 | f.puts entry 66 | end 67 | end 68 | 69 | send_file file_name, filename: file_name, type: 'Application/octet-stream' 70 | elsif params[:graph] == '4' # Password Count by Length 71 | # Do Something 72 | elsif params[:graph] == '5' # Top 10 Passwords 73 | # Do Something 74 | elsif params[:graph] == '6' # Accounts With Weak Passwords 75 | file_name = 'error.txt' 76 | if params[:customer_id] && !params[:customer_id].empty? 77 | if params[:hashfile_id] && !params[:hashfile_id].nil? 78 | @complexity_hashes = HVDB.fetch('SELECT a.username, h.plaintext FROM hashes h LEFT JOIN hashfilehashes a ON h.id = a.hash_id WHERE (a.hashfile_id = ? AND h.cracked = 1)', params[:hashfile_id]) 79 | file_name = "Weak_Accounts_#{params[:customer_id]}_#{params[:hashfile_id]}.csv" 80 | else 81 | @complexity_hashes = HVDB.fetch('SELECT a.username, h.plaintext FROM hashes h LEFT JOIN hashfilehashes a on h.id = a.hash_id LEFT JOIN hashfiles f on a.hashfile_id = f.id WHERE (f.customer_id = ? AND h.cracked = 1)', params[:customer_id]) 82 | file_name = "Weak_Accounts_#{params[:customer_id]}.csv" 83 | end 84 | else 85 | @complexity_hashes = HVDB.fetch('SELECT a.username, h.plaintext FROM hashes h LEFT JOIN hashfilehashes a on h.id = a.hash_id LEFT JOIN hashfiles f on a.hashfile_id = f.id WHERE (h.cracked = 1)') 86 | file_name = "Weak_Accounts_all.csv" 87 | end 88 | 89 | file_name = 'control/tmp/' + file_name 90 | 91 | File.open(file_name, 'w') do |f| 92 | line = 'username,password' 93 | f.puts line 94 | @complexity_hashes.each do |entry| 95 | unless entry.plaintext.to_s =~ /^(?:(?=.*[a-z])(?:(?=.*[A-Z])(?=.*[\d\W])|(?=.*\W)(?=.*\d))|(?=.*\W)(?=.*[A-Z])(?=.*\d)).{8,}$/ 96 | line = entry.username.to_s + ',' + entry.plaintext.to_s 97 | f.puts line 98 | end 99 | end 100 | end 101 | 102 | send_file file_name, filename: file_name, type: 'Application/octet-stream' 103 | 104 | elsif params[:graph] == '7' # Top 20 Password/Hashes Shared by Users 105 | # Do something 106 | else 107 | # DO Something 108 | end 109 | end 110 | end 111 | 112 | -------------------------------------------------------------------------------- /db/migrations/001_sequel.rb: -------------------------------------------------------------------------------- 1 | Sequel.migration do 2 | change do 3 | create_table(:agents) do 4 | primary_key :id, type: :Bignum 5 | String :name, size: 100 6 | String :src_ip, size: 45 7 | String :uuid, size: 60 8 | String :status, size: 40 9 | String :hc_status, size: 6000 10 | DateTime :heartbeat 11 | String :benchmark, size: 6000 12 | String :devices, size: 6000 13 | Integer :cpu_count 14 | Integer :gpu_count 15 | end 16 | 17 | create_table(:customers) do 18 | primary_key :id, type: :Bignum 19 | String :name, size: 40 20 | String :description, size: 500 21 | end 22 | 23 | create_table(:hashcat_settings) do 24 | primary_key :id, type: :Bignum 25 | String :hc_binpath, size: 2000 26 | String :max_task_time, size: 2000 27 | Integer :opencl_device_types, default: 0 28 | Integer :workload_profile, default: 0 29 | TrueClass :gpu_temp_disable, default: false 30 | Integer :gpu_temp_abort, default: 0 31 | Integer :gpu_temp_retain, default: 0 32 | TrueClass :hc_force, default: false 33 | TrueClass :optimized_drivers, default: false 34 | end 35 | 36 | create_table(:hashes, ignore_index_errors: true) do 37 | primary_key :id 38 | DateTime :lastupdated 39 | String :originalhash, size: 1024 40 | Integer :hashtype 41 | TrueClass :cracked 42 | String :plaintext, size: 256 43 | 44 | index [:hashtype], name: :index_of_hashtypes 45 | index [:originalhash], name: :index_of_orignalhashes, unique: true 46 | end 47 | 48 | create_table(:hashfilehashes, ignore_index_errors: true) do 49 | primary_key :id, type: :Bignum 50 | Integer :hash_id 51 | String :username, size: 256 52 | Integer :hashfile_id 53 | 54 | index [:hash_id], name: :index_hashfilehashes_hash_id 55 | index [:hashfile_id], name: :index_hashfilehashes_hashfile_id 56 | end 57 | 58 | create_table(:hashfiles) do 59 | primary_key :id, type: :Bignum 60 | Integer :customer_id 61 | String :name, size: 256 62 | String :hash_str, size: 256 63 | Integer :total_run_time, default: 0 64 | end 65 | 66 | create_table(:hub_settings) do 67 | primary_key :id, type: :Bignum 68 | TrueClass :enabled 69 | String :status, default: 'unregistered', size: 50, null: false 70 | String :email, size: 50 71 | String :uuid, size: 50 72 | String :auth_key, size: 254 73 | Integer :balance, default: 0 74 | end 75 | 76 | create_table(:jobs) do 77 | primary_key :id, type: :Bignum 78 | String :name, size: 50 79 | String :last_updated_by, size: 40 80 | DateTime :updated_at, default: DateTime.parse('2017-08-03T16:06:21.000000000+0000') 81 | String :status, size: 100 82 | DateTime :queued_at 83 | DateTime :started_at 84 | DateTime :ended_at 85 | Integer :hashfile_id 86 | Integer :customer_id 87 | TrueClass :notify_completed 88 | end 89 | 90 | create_table(:jobtasks) do 91 | primary_key :id, type: :Bignum 92 | Integer :job_id 93 | Integer :task_id 94 | String :build_cmd, size: 5000 95 | String :status, size: 50 96 | Integer :run_time 97 | end 98 | 99 | create_table(:rules) do 100 | primary_key :id, type: :Bignum 101 | DateTime :lastupdated 102 | String :name, size: 256 103 | String :path, size: 2000 104 | String :size, size: 100 105 | String :checksum, size: 64 106 | end 107 | 108 | create_table(:sessions) do 109 | primary_key :id, type: :Bignum 110 | String :session_key, size: 128 111 | String :username, size: 40, null: false 112 | end 113 | 114 | create_table(:settings) do 115 | primary_key :id, type: :Bignum 116 | String :smtp_server, size: 50 117 | String :smtp_sender, size: 50 118 | String :smtp_user, size: 50 119 | String :smtp_pass, size: 50 120 | TrueClass :smtp_use_tls 121 | String :smtp_auth_type, size: 50 122 | TrueClass :clientmode 123 | String :ui_themes, default: 'Light', size: 50, null: false 124 | String :version, size: 5 125 | Bignum :chunk_size, default: 500000 126 | 127 | check Sequel::SQL::BooleanExpression.new(:>=, Sequel::SQL::Identifier.new(:chunk_size), 0) 128 | end 129 | 130 | create_table(:taskqueues) do 131 | primary_key :id, type: :Bignum 132 | Integer :jobtask_id 133 | Integer :job_id 134 | DateTime :updated_at, default: DateTime.parse('2017-08-03T16:06:21.000000000+0000') 135 | DateTime :queued_at 136 | String :status, size: 100 137 | String :agent_id, size: 2000 138 | String :command, size: 4000 139 | end 140 | 141 | create_table(:tasks, ignore_index_errors: true) do 142 | primary_key :id, type: :Bignum 143 | String :name, size: 50 144 | String :source, size: 50 145 | String :mask, size: 50 146 | String :command, size: 4000 147 | String :wl_id, size: 256 148 | String :hc_attackmode, size: 25 149 | String :hc_rule, size: 50 150 | String :hc_mask, size: 50 151 | Bignum :keyspace 152 | 153 | check Sequel::SQL::BooleanExpression.new(:>=, Sequel::SQL::Identifier.new(:keyspace), 0) 154 | 155 | index [:name, :hc_mask], name: :ix_uq, unique: true 156 | end 157 | 158 | create_table(:users) do 159 | primary_key :id, null: false, auto_increment: true 160 | String :username, size: 40, null: false 161 | String :hashed_password, size: 128 162 | TrueClass :admin 163 | DateTime :created_at, default: DateTime.parse('2017-08-03T16:06:21.000000000+0000') 164 | String :phone, size: 50 165 | String :email, size: 50 166 | TrueClass :mfa 167 | String :auth_secret, size: 50 168 | 169 | check Sequel::SQL::BooleanExpression.new(:>=, Sequel::SQL::Identifier.new(:id), 0) 170 | end 171 | 172 | create_table(:wordlists) do 173 | primary_key :id, type: :Bignum 174 | DateTime :lastupdated 175 | String :type, size: 25 176 | String :name, size: 256 177 | String :path, size: 2000 178 | String :size, size: 100 179 | String :checksum, size: 64 180 | end 181 | end 182 | end 183 | -------------------------------------------------------------------------------- /routes/tasks.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | get '/tasks/list' do 3 | @tasks = Tasks.all 4 | @wordlists = Wordlists.all 5 | @rules = Rules.all 6 | 7 | haml :task_list 8 | end 9 | 10 | get '/tasks/delete/:id' do 11 | varWash(params) 12 | 13 | @job_tasks = Jobtasks.where(task_id: params[:id]).all 14 | unless @job_tasks.empty? 15 | flash[:error] = 'That task is currently used in a job.' 16 | redirect to('/tasks/list') 17 | end 18 | 19 | @task = Tasks.first(id: params[:id]) 20 | @task.destroy if @task 21 | 22 | redirect to('/tasks/list') 23 | end 24 | 25 | get '/tasks/edit/:id' do 26 | varWash(params) 27 | @task = Tasks.first(id: params[:id]) 28 | @wordlists = Wordlists.all 29 | @hc_settings = HashcatSettings.first 30 | 31 | if @task.hc_attackmode == 'combinator' 32 | @combinator_wordlists = @task.wl_id.split(',') 33 | if @task.hc_rule =~ /--rule-left=(.*) --rule-right=(.*)/ 34 | @combinator_left_rule = $1 35 | @combinator_right_rule = $2 36 | elsif @task.hc_rule =~ /--rule-left=(.*)/ 37 | @combinator_left_rule = $1 38 | elsif @task.hc_rule =~ /--rule-right=(.*)/ 39 | @combinator_right_rule = $1 40 | end 41 | end 42 | 43 | @rules = Rules.all 44 | 45 | haml :task_edit 46 | end 47 | 48 | post '/tasks/edit/:id' do 49 | varWash(params) 50 | if !params[:name] || params[:name].nil? 51 | flash[:error] = 'The task requires a name.' 52 | redirect to("/tasks/edit/#{params[:id]}") 53 | end 54 | 55 | wordlist = Wordlists.first(id: params[:wordlist]) 56 | 57 | # must have two word lists 58 | if params[:attackmode] == 'combinator' 59 | wordlist_count = 0 60 | wordlist_list = '' 61 | rule_list = '' 62 | @wordlists = Wordlists.all 63 | @wordlists.each do |wordlist_check| 64 | params.keys.each do |key| 65 | if params[key] == 'on' && key == "combinator_wordlist_#{wordlist_check.id}" 66 | if wordlist_list == '' 67 | wordlist_list = wordlist_check.id.to_s + ',' 68 | else 69 | wordlist_list += wordlist_check.id.to_s 70 | end 71 | wordlist_count += 1 72 | end 73 | end 74 | end 75 | 76 | if wordlist_count != 2 77 | flash[:error] = 'You must specify at exactly 2 wordlists.' 78 | redirect to("/tasks/edit/#{params[:id]}") 79 | end 80 | 81 | if params[:combinator_left_rule] && !params[:combinator_left_rule].empty? && params[:combinator_right_rule] && !params[:combinator_right_rule].empty? 82 | rule_list = '--rule-left=' + params[:combinator_left_rule] + ' --rule-right=' + params[:combinator_right_rule] 83 | elsif params[:combinator_left_rule] && !params[:combinator_left_rule].empty? 84 | rule_list = '--rule-left=' + params[:combinator_left_rule] 85 | elsif params[:combinator_right_rule] && !params[:combinator_right_rule].empty? 86 | rule_list = '--rule-right=' + params[:combinator_right_rule] 87 | else 88 | rule_list = '' 89 | end 90 | end 91 | 92 | task = Tasks.first(id: params[:id]) 93 | task.name = params[:name] 94 | 95 | task.hc_attackmode = params[:attackmode] 96 | 97 | if params[:attackmode] == 'dictionary' 98 | task.wl_id = wordlist.id 99 | task.hc_rule = params[:rule].to_i 100 | task.hc_mask = 'NULL' 101 | elsif params[:attackmode] == 'maskmode' 102 | task.wl_id = 'NULL' 103 | task.hc_rule = 'NULL' 104 | task.hc_mask = params[:mask] 105 | elsif params[:attackmode] == 'combinator' 106 | task.wl_id = wordlist_list 107 | task.hc_rule = rule_list 108 | task.hc_mask = 'NULL' 109 | end 110 | task.save 111 | 112 | redirect to('/tasks/list') 113 | end 114 | 115 | get '/tasks/create' do 116 | varWash(params) 117 | @hc_settings = HashcatSettings.first 118 | 119 | @rules = Rules.all 120 | @wordlists = Wordlists.all 121 | 122 | haml :task_edit 123 | end 124 | 125 | post '/tasks/create' do 126 | varWash(params) 127 | 128 | if !params[:name] || params[:name].empty? 129 | flash[:error] = 'You must provide a name for your task!' 130 | redirect to('/tasks/create') 131 | end 132 | 133 | @tasks = Tasks.where(name: params[:name]).all 134 | unless @tasks.nil? 135 | @tasks.each do |task| 136 | if task.name == params[:name] 137 | flash[:error] = 'Name already in use, pick another' 138 | redirect to('/tasks/create') 139 | end 140 | end 141 | end 142 | 143 | wordlist = Wordlists.first(id: params[:wordlist]) 144 | 145 | # mask field cannot be empty 146 | if params[:attackmode] == 'maskmode' 147 | if !params[:mask] || params[:mask].empty? 148 | flash[:error] = 'Mask field cannot be left empty' 149 | redirect to('/tasks/create') 150 | end 151 | end 152 | 153 | # must have two word lists 154 | if params[:attackmode] == 'combinator' 155 | wordlist_count = 0 156 | wordlist_list = '' 157 | rule_list = '' 158 | @wordlists = Wordlists.all 159 | @wordlists.each do |wordlist_check| 160 | params.keys.each do |key| 161 | if params[key] == 'on' && key == "combinator_wordlist_#{wordlist_check.id}" 162 | if wordlist_list == '' 163 | wordlist_list = wordlist_check.id.to_s + ',' 164 | else 165 | wordlist_list += wordlist_check.id.to_s 166 | end 167 | wordlist_count += 1 168 | end 169 | end 170 | end 171 | 172 | if wordlist_count != 2 173 | flash[:error] = 'You must specify at exactly 2 wordlists.' 174 | redirect to('/tasks/create') 175 | end 176 | 177 | if params[:combinator_left_rule] && !params[:combinator_left_rule].empty? && params[:combinator_right_rule] && !params[:combinator_right_rule].empty? 178 | rule_list = '--rule-left=' + params[:combinator_left_rule] + ' --rule-right=' + params[:combinator_right_rule] 179 | elsif params[:combinator_left_rule] && !params[:combinator_left_rule].empty? 180 | rule_list = '--rule-left=' + params[:combinator_left_rule] 181 | elsif params[:combinator_right_rule] && !params[:combinator_right_rule].empty? 182 | rule_list = '--rule-right=' + params[:combinator_right_rule] 183 | else 184 | rule_list = '' 185 | end 186 | end 187 | 188 | task = Tasks.new 189 | task.name = params[:name] 190 | 191 | task.hc_attackmode = params[:attackmode] 192 | 193 | if params[:attackmode] == 'dictionary' 194 | task.wl_id = wordlist.id 195 | task.hc_rule = params[:rule] 196 | elsif params[:attackmode] == 'maskmode' 197 | task.hc_mask = params[:mask] 198 | elsif params[:attackmode] == 'combinator' 199 | task.wl_id = wordlist_list 200 | task.hc_rule = rule_list 201 | end 202 | 203 | # generate keyspace of new task and save to db 204 | task.keyspace = getKeyspace(task) 205 | task.save 206 | 207 | flash[:success] = "Task #{task.name} successfully created." 208 | redirect to('/tasks/list') 209 | end 210 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | actionpack (4.2.7.1) 5 | actionview (= 4.2.7.1) 6 | activesupport (= 4.2.7.1) 7 | rack (~> 1.6) 8 | rack-test (~> 0.6.2) 9 | rails-dom-testing (~> 1.0, >= 1.0.5) 10 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 11 | actionview (4.2.7.1) 12 | activesupport (= 4.2.7.1) 13 | builder (~> 3.1) 14 | erubis (~> 2.7.0) 15 | rails-dom-testing (~> 1.0, >= 1.0.5) 16 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 17 | activesupport (4.2.7.1) 18 | i18n (~> 0.7) 19 | json (~> 1.7, >= 1.7.7) 20 | minitest (~> 5.1) 21 | thread_safe (~> 0.3, >= 0.3.4) 22 | tzinfo (~> 1.1) 23 | addressable (2.4.0) 24 | ast (2.3.0) 25 | bcrypt (3.1.11) 26 | bcrypt-ruby (3.1.5) 27 | bcrypt (>= 3.1.3) 28 | builder (3.2.2) 29 | coffee-rails (4.2.1) 30 | coffee-script (>= 2.2.0) 31 | railties (>= 4.0.0, < 5.2.x) 32 | coffee-script (2.4.1) 33 | coffee-script-source 34 | execjs 35 | coffee-script-source (1.10.0) 36 | commonjs (0.2.7) 37 | concurrent-ruby (1.0.2) 38 | data_mapper (1.2.0) 39 | dm-aggregates (~> 1.2.0) 40 | dm-constraints (~> 1.2.0) 41 | dm-core (~> 1.2.0) 42 | dm-migrations (~> 1.2.0) 43 | dm-serializer (~> 1.2.0) 44 | dm-timestamps (~> 1.2.0) 45 | dm-transactions (~> 1.2.0) 46 | dm-types (~> 1.2.0) 47 | dm-validations (~> 1.2.0) 48 | data_objects (0.10.17) 49 | addressable (~> 2.1) 50 | digest (0.0.1) 51 | dm-aggregates (1.2.0) 52 | dm-core (~> 1.2.0) 53 | dm-constraints (1.2.0) 54 | dm-core (~> 1.2.0) 55 | dm-core (1.2.1) 56 | addressable (~> 2.3) 57 | dm-migrations (1.2.0) 58 | dm-core (~> 1.2.0) 59 | dm-serializer (1.2.2) 60 | dm-core (~> 1.2.0) 61 | fastercsv (~> 1.5) 62 | json (~> 1.6) 63 | json_pure (~> 1.6) 64 | multi_json (~> 1.0) 65 | dm-timestamps (1.2.0) 66 | dm-core (~> 1.2.0) 67 | dm-transactions (1.2.0) 68 | dm-core (~> 1.2.0) 69 | dm-types (1.2.2) 70 | bcrypt-ruby (~> 3.0) 71 | dm-core (~> 1.2.0) 72 | fastercsv (~> 1.5) 73 | json (~> 1.6) 74 | multi_json (~> 1.0) 75 | stringex (~> 1.4) 76 | uuidtools (~> 2.1) 77 | dm-validations (1.2.0) 78 | dm-core (~> 1.2.0) 79 | domain_name (0.5.20161129) 80 | unf (>= 0.0.5, < 1.0.0) 81 | erubis (2.7.0) 82 | execjs (2.7.0) 83 | factory_girl (4.7.0) 84 | activesupport (>= 3.0.0) 85 | fastercsv (1.5.5) 86 | foreman (0.83.0) 87 | thor (~> 0.19.1) 88 | haml (4.0.7) 89 | tilt 90 | http-cookie (1.0.3) 91 | domain_name (~> 0.5) 92 | i18n (0.7.0) 93 | jquery-rails (4.2.1) 94 | rails-dom-testing (>= 1, < 3) 95 | railties (>= 4.2.0) 96 | thor (>= 0.14, < 2.0) 97 | json (1.8.3) 98 | json_pure (1.8.6) 99 | less (2.6.0) 100 | commonjs (~> 0.2.7) 101 | less-rails (2.7.1) 102 | actionpack (>= 4.0) 103 | less (~> 2.6.0) 104 | sprockets (> 2, < 4) 105 | tilt 106 | logger (1.2.8) 107 | loofah (2.0.3) 108 | nokogiri (>= 1.5.9) 109 | mail (2.6.4) 110 | mime-types (>= 1.16, < 4) 111 | mime-types (3.1) 112 | mime-types-data (~> 3.2015) 113 | mime-types-data (3.2016.0521) 114 | mini_portile2 (2.1.0) 115 | minitest (5.9.0) 116 | mono_logger (1.1.0) 117 | multi_json (1.12.1) 118 | mysql (2.9.1) 119 | netrc (0.11.0) 120 | nokogiri (1.6.8) 121 | mini_portile2 (~> 2.1.0) 122 | pkg-config (~> 1.1.7) 123 | parallel (1.12.0) 124 | parser (2.4.0.2) 125 | ast (~> 2.3) 126 | pkg-config (1.1.7) 127 | pony (1.11) 128 | mail (>= 2.0) 129 | powerpack (0.1.1) 130 | rack (1.6.5) 131 | rack-protection (1.5.3) 132 | rack 133 | rack-test (0.6.3) 134 | rack (>= 1.0) 135 | rails-deprecated_sanitizer (1.0.3) 136 | activesupport (>= 4.2.0.alpha) 137 | rails-dom-testing (1.0.7) 138 | activesupport (>= 4.2.0.beta, < 5.0) 139 | nokogiri (~> 1.6.0) 140 | rails-deprecated_sanitizer (>= 1.0.1) 141 | rails-html-sanitizer (1.0.3) 142 | loofah (~> 2.0) 143 | railties (4.2.7.1) 144 | actionpack (= 4.2.7.1) 145 | activesupport (= 4.2.7.1) 146 | rake (>= 0.8.7) 147 | thor (>= 0.18.1, < 2.0) 148 | rainbow (2.2.2) 149 | rake 150 | rake (11.2.2) 151 | redis (3.3.2) 152 | redis-namespace (1.5.2) 153 | redis (~> 3.0, >= 3.0.4) 154 | resque (1.26.0) 155 | mono_logger (~> 1.0) 156 | multi_json (~> 1.0) 157 | redis-namespace (~> 1.3) 158 | sinatra (>= 0.9.2) 159 | vegas (~> 0.1.2) 160 | resque-scheduler (4.3.0) 161 | mono_logger (~> 1.0) 162 | redis (~> 3.3) 163 | resque (~> 1.26) 164 | rufus-scheduler (~> 3.2) 165 | resque-web (0.0.9) 166 | coffee-rails 167 | jquery-rails 168 | resque 169 | sass-rails 170 | twitter-bootstrap-rails 171 | rest-client (2.0.0) 172 | http-cookie (>= 1.0.2, < 2.0) 173 | mime-types (>= 1.16, < 4.0) 174 | netrc (~> 0.8) 175 | rotp (3.3.0) 176 | rubocop (0.51.0) 177 | parallel (~> 1.10) 178 | parser (>= 2.3.3.1, < 3.0) 179 | powerpack (~> 0.1) 180 | rainbow (>= 2.2.2, < 3.0) 181 | ruby-progressbar (~> 1.7) 182 | unicode-display_width (~> 1.0, >= 1.0.1) 183 | ruby-progressbar (1.9.0) 184 | rufus-scheduler (3.3.4) 185 | tzinfo 186 | sass (3.4.22) 187 | sass-rails (5.0.6) 188 | railties (>= 4.0.0, < 6) 189 | sass (~> 3.1) 190 | sprockets (>= 2.8, < 4.0) 191 | sprockets-rails (>= 2.0, < 4.0) 192 | tilt (>= 1.1, < 3) 193 | sequel (4.48.0) 194 | sinatra (1.4.7) 195 | rack (~> 1.5) 196 | rack-protection (~> 1.4) 197 | tilt (>= 1.3, < 3) 198 | sinatra-flash (0.3.0) 199 | sinatra (>= 1.0.0) 200 | sprockets (3.7.0) 201 | concurrent-ruby (~> 1.0) 202 | rack (> 1, < 3) 203 | sprockets-rails (3.2.0) 204 | actionpack (>= 4.0) 205 | activesupport (>= 4.0) 206 | sprockets (>= 3.0.0) 207 | stringex (1.5.1) 208 | thor (0.19.1) 209 | thread_safe (0.3.5) 210 | tilt (2.0.5) 211 | twitter-bootstrap-rails (3.2.2) 212 | actionpack (>= 3.1) 213 | execjs (>= 2.2.2, >= 2.2) 214 | less-rails (>= 2.5.0) 215 | railties (>= 3.1) 216 | tzinfo (1.2.2) 217 | thread_safe (~> 0.1) 218 | unf (0.1.4) 219 | unf_ext 220 | unf_ext (0.0.7.2) 221 | unicode-display_width (1.3.0) 222 | uuidtools (2.1.5) 223 | vegas (0.1.11) 224 | rack (>= 1.0.0) 225 | 226 | PLATFORMS 227 | ruby 228 | 229 | DEPENDENCIES 230 | bcrypt 231 | data_mapper 232 | data_objects 233 | digest 234 | factory_girl 235 | foreman 236 | haml 237 | json 238 | logger 239 | mysql 240 | pony 241 | rake 242 | redis 243 | resque 244 | resque-scheduler 245 | resque-web 246 | rest-client 247 | rotp 248 | rubocop 249 | sequel 250 | sinatra (~> 1.4.7) 251 | sinatra-flash 252 | 253 | RUBY VERSION 254 | ruby 2.2.2p95 255 | 256 | BUNDLED WITH 257 | 1.16.0 258 | -------------------------------------------------------------------------------- /views/agent_list.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | %body 4 | .span15 5 | .container 6 | .col-md-12 7 | .row 8 | .page-header 9 | %h1 10 | Agents 11 | .row 12 | .col-md-10.pull-left 13 | Agents are remote workers that process distributed hashcat jobs. 14 | .col-md-2.pull-right 15 | .well.well-sm 16 | - agents_online = 0 17 | - total_gpus = 0 18 | - total_cpus = 0 19 | - total_speed = 0 20 | - speed = 0 21 | - @agents.each do |agent| 22 | - if agent.status == 'Online' || agent.status == 'Working' || agent.status == 'Idle' 23 | - agents_online += 1 24 | - if agent.gpu_count 25 | - total_gpus += agent.gpu_count.to_i 26 | - if agent.cpu_count 27 | - total_cpus += agent.cpu_count.to_i 28 | - if agent.benchmark 29 | - if agent.benchmark.include? 'kH/s' 30 | - speed = agent.benchmark.split()[0].to_f 31 | - speed = speed * 1000 32 | - total_speed += speed 33 | - if agent.benchmark.include? 'MH/s' 34 | - speed = agent.benchmark.split()[0].to_f 35 | - speed = speed * 1000000 36 | - total_speed += speed 37 | - if agent.benchmark.include? 'GH/s' 38 | - speed = agent.benchmark.split()[0].to_f 39 | - speed = speed * 1000000000 40 | - total_speed += speed 41 | - if agent.benchmark.include? 'TH/s' 42 | - speed = agent.benchmark.split()[0].to_f 43 | - speed = speed * 1000000000000 44 | - total_speed += speed 45 | Agents online 46 | .badge #{agents_online} 47 | .p 48 | GPUs total 49 | .badge #{total_gpus} 50 | .p 51 | CPUs total 52 | .badge #{total_cpus} 53 | .p 54 | Total Speed: 55 | .p 56 | 57 | - speed_count = total_speed.to_i.to_s.size 58 | - if speed_count > 12 59 | - total_speed = total_speed / 1000000000000 60 | #{total_speed.round} TH/s 61 | - elsif speed_count > 9 62 | - total_speed = total_speed / 1000000000 63 | #{total_speed.round} GH/s 64 | - elsif speed_count > 6 65 | - total_speed = total_speed / 1000000 66 | #{total_speed.round} MH/s 67 | - elsif speed_count > 3 68 | - total_speed = total_speed / 1000000 69 | #{total_speed.round} kH/s 70 | 71 | %br 72 | %br 73 | .container 74 | .row 75 | .col-md-12 76 | .table 77 | %table{id: 'agenttable', class: 'table table-striped'} 78 | %thead 79 | %tr 80 | %th 81 | %b Agent Name 82 | %th 83 | %b Status 84 | %th 85 | %b IP 86 | %th 87 | %b Speed 88 | %th 89 | %b Last Heartbeat 90 | %th 91 | %b Controls 92 | %tbody 93 | - if @agents 94 | - @agents.each do |agent| 95 | - link = rand(36**8).to_s(36) 96 | %tr 97 | %td{class: 'accordian-toggle', "data-toggle" => 'collapse', href: "#collapse-#{link}"} #{agent.name} 98 | %td{class: 'accordian-toggle', "data-toggle" => 'collapse', href: "#collapse-#{link}"} #{agent.status} 99 | %td{class: 'accordian-toggle', "data-toggle" => 'collapse', href: "#collapse-#{link}"} #{agent.src_ip} 100 | %td{class: 'accordian-toggle', "data-toggle" => 'collapse', href: "#collapse-#{link}"} #{agent.benchmark} 101 | %td{class: 'accordian-toggle', "data-toggle" => 'collapse', href: "#collapse-#{link}"} #{agent.heartbeat} 102 | %td 103 | - if agent.src_ip == '127.0.0.1' || agent.src_ip == 'localhost' 104 | - if agent.status == 'Authorized' || agent.status == 'Online' || agent.status == 'Offline' || agent.status == 'Working' || agent.status == 'Idle' 105 | %a.btn.btn-primary.disabled{href: "/agents/#{agent.id}/deauthorize"} 106 | Deauthorize 107 | - else 108 | %a.btn.btn-primary{href: "/agents/#{agent.id}/authorize"} 109 | Authorize 110 | %a.btn.btn-warning{href: "/agents/#{agent.id}/edit"} 111 | %i.glyphicon.glyphicon-cog{title: 'Edit'} 112 | %a.btn.btn-danger.disabled{href: "/agents/#{agent.id}/delete"} 113 | %i.glyphicon.glyphicon-trash{title: 'Delete'} 114 | - else 115 | - if agent.status == 'Pending' 116 | %a.btn.btn-primary{href: "/agents/#{agent.id}/authorize"} 117 | Authorize 118 | - else 119 | %a.btn.btn-primary{href: "/agents/#{agent.id}/deauthorize"} 120 | Deauthorize 121 | %a.btn.btn-warning{href: "/agents/#{agent.id}/edit"} 122 | %i.glyphicon.glyphicon-cog{title: 'Edit'} 123 | %a.btn.btn-danger{href: "/agents/#{agent.id}/delete"} 124 | %i.glyphicon.glyphicon-trash{title: 'Delete'} 125 | - if agent.hc_status 126 | - unless agent.hc_status.empty? 127 | %tr 128 | %td{colspan: 6} 129 | %div{id: "collapse-#{link}", class: "panel-collapse collapse in"} 130 | %h4 Hashcat Status 131 | %br 132 | %table{class: 'table'} 133 | - unless agent.hc_status.empty? 134 | - JSON.parse(agent.hc_status).each do |k,v| 135 | %tr 136 | %td.col-md-4 137 | #{k} 138 | %td 139 | #{v} 140 | 141 | -------------------------------------------------------------------------------- /views/job_list.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | %body 4 | .span15 5 | .container 6 | .col-md-12 7 | .row 8 | .page-header 9 | %h1 10 | Jobs 11 | .row 12 | .col-md-10 13 | Jobs contain a series of tasks (hashcat commands). Jobs also have an associated list of hashes to crack. 14 | .col-md-2.pull-right 15 | %a.btn.btn-primary.pull-right{href: '/jobs/create'} 16 | Create a New Job 17 | %br 18 | %br 19 | .container 20 | .row 21 | .col-md-12 22 | .table 23 | %table{class: 'table table-striped'} 24 | %thead 25 | %tr 26 | %th 27 | %b Customer 28 | %th 29 | %b Name 30 | %th 31 | %b Status 32 | %th 33 | %b Last updated by 34 | %th 35 | %b Control 36 | %tbody 37 | - if @jobs 38 | - @jobs.each do |job| 39 | %tr 40 | %td #{@customer_names[job.customer_id]} 41 | %td #{job.name} 42 | - if job.status == 'Running' 43 | %td Running 44 | - elsif job.status == 'Queued' 45 | %td Queued 46 | - elsif job.status == 'Completed' 47 | %td Completed 48 | - elsif job.status == 'Importing' 49 | %td Importing 50 | - else 51 | %td Stopped 52 | %td #{job.last_updated_by} 53 | %td 54 | - if job.status == 'Running' 55 | %a.btn.btn-danger{href: "/jobs/stop/#{job.id}"} 56 | %i.glyphicon.glyphicon-stop{title: 'Running'} 57 | - elsif job.status == 'Queued' 58 | %a.btn.btn-default{href: "/jobs/stop/#{job.id}"} 59 | %i.glyphicon.glyphicon-hourglass{title: 'Queued'} 60 | - elsif job.status == 'Completed' 61 | %a.btn.btn-success{href: ''} 62 | %i.glyphicon.glyphicon-ok{title: 'Completed'} 63 | - elsif job.status == 'Importing' 64 | %a.btn.btn-default{href: '/home'} 65 | %i.glyphicon.glyphicon-hourglass{title: 'Wait'} 66 | - else 67 | %a.btn.btn-success{href: "/jobs/start/#{job.id}"} 68 | %i.glyphicon.glyphicon-play{title: 'stopped'} 69 | %a.btn.btn-primary{href: "/analytics?customer_id=#{job.customer_id}&hashfile_id=#{job.hashfile_id}"} 70 | %i.glyphicon.glyphicon-stats{title: 'Display crack stats'} 71 | %a.btn.btn-info{href: "#modal#{job.id}", "data-toggle" => 'modal'} 72 | %i.glyphicon.glyphicon-info-sign{title: 'Info'} 73 | .modal.fade.modal{id: "modal#{job.id}", role: 'dialog', tabindex: '-1', "aria-hidden" => 'true'} 74 | .modal-dialog.modal-lg 75 | .modal-content 76 | .modal-header 77 | %button.close{'aria-label' => 'Close', 'data-dismiss' => 'modal', type: 'button'} 78 | %span{'aria-hidden' => 'true'} × 79 | %h4.modal-title Job Tasks for: #{job.name} (id:#{job.id}) 80 | .modal-body 81 | %p 82 | .table 83 | %table{class: 'table table-striped'} 84 | - if @jobtasks 85 | - @jobtasks.each do |jt| 86 | - if jt.job_id == job.id 87 | - @tasks.each do |task| 88 | - if task.id == jt.task_id 89 | %tr 90 | %td 91 | .row 92 | .form-group 93 | %label.control-label.col-xs-2{for: ''} Task Name 94 | .col-xs-10 95 | #{task.name} 96 | .row 97 | .form-group 98 | %label.control-label.col-xs-2{for: ''} Attack Mode 99 | .col-xs-4 100 | #{task.hc_attackmode} 101 | - if task.hc_attackmode == 'dictionary' 102 | .row 103 | .form-group 104 | %label.control-label.col-xs-2{for: ''} Wordlist 105 | .col-xs-4 106 | #{@wordlist_id_to_name[task.wl_id]} 107 | .row 108 | .form-group 109 | %label.control-label.col-xs-2{for: ''} Dictionary Rules 110 | .col-xs-4 111 | #{task.hc_rule} 112 | - else 113 | No tasks are assigned to this job 114 | %p 115 | .modal-footer 116 | %button.btn.btn-default{"data-dismiss" => "modal", type: 'button'} Close 117 | - if job.status == 'Running' || job.status == 'Queued' 118 | %a.btn.btn-warning.disabled{href: "/jobs/create?customer_id=#{job.customer_id}&job_id=#{job.id}&edit=1"} 119 | %i.glyphicon.glyphicon-cog{title: 'Edit'} 120 | %a.btn.btn-danger.disabled{href: "/jobs/delete/#{job.id}"} 121 | %i.glyphicon.glyphicon-trash{title: 'Delete'} 122 | - else 123 | %a.btn.btn-warning{href: "/jobs/create?customer_id=#{job.customer_id}&job_id=#{job.id}&edit=1"} 124 | %i.glyphicon.glyphicon-cog{title: 'Edit'} 125 | %a.btn.btn-danger{href: "/jobs/delete/#{job.id}"} 126 | %i.glyphicon.glyphicon-trash{title: 'Delete'} 127 | -------------------------------------------------------------------------------- /control/rules/toggles3.rule: -------------------------------------------------------------------------------- 1 | T0 2 | T1 3 | T2 4 | T3 5 | T4 6 | T5 7 | T6 8 | T7 9 | T8 10 | T9 11 | TA 12 | TB 13 | TC 14 | TD 15 | TE 16 | T0T1 17 | T0T2 18 | T0T3 19 | T0T4 20 | T0T5 21 | T0T6 22 | T0T7 23 | T0T8 24 | T0T9 25 | T0TA 26 | T0TB 27 | T0TC 28 | T0TD 29 | T0TE 30 | T1T2 31 | T1T3 32 | T1T4 33 | T1T5 34 | T1T6 35 | T1T7 36 | T1T8 37 | T1T9 38 | T1TA 39 | T1TB 40 | T1TC 41 | T1TD 42 | T1TE 43 | T2T3 44 | T2T4 45 | T2T5 46 | T2T6 47 | T2T7 48 | T2T8 49 | T2T9 50 | T2TA 51 | T2TB 52 | T2TC 53 | T2TD 54 | T2TE 55 | T3T4 56 | T3T5 57 | T3T6 58 | T3T7 59 | T3T8 60 | T3T9 61 | T3TA 62 | T3TB 63 | T3TC 64 | T3TD 65 | T3TE 66 | T4T5 67 | T4T6 68 | T4T7 69 | T4T8 70 | T4T9 71 | T4TA 72 | T4TB 73 | T4TC 74 | T4TD 75 | T4TE 76 | T5T6 77 | T5T7 78 | T5T8 79 | T5T9 80 | T5TA 81 | T5TB 82 | T5TC 83 | T5TD 84 | T5TE 85 | T6T7 86 | T6T8 87 | T6T9 88 | T6TA 89 | T6TB 90 | T6TC 91 | T6TD 92 | T6TE 93 | T7T8 94 | T7T9 95 | T7TA 96 | T7TB 97 | T7TC 98 | T7TD 99 | T7TE 100 | T8T9 101 | T8TA 102 | T8TB 103 | T8TC 104 | T8TD 105 | T8TE 106 | T9TA 107 | T9TB 108 | T9TC 109 | T9TD 110 | T9TE 111 | TATB 112 | TATC 113 | TATD 114 | TATE 115 | TBTC 116 | TBTD 117 | TBTE 118 | TCTD 119 | TCTE 120 | TDTE 121 | T0T1T2 122 | T0T1T3 123 | T0T1T4 124 | T0T1T5 125 | T0T1T6 126 | T0T1T7 127 | T0T1T8 128 | T0T1T9 129 | T0T1TA 130 | T0T1TB 131 | T0T1TC 132 | T0T1TD 133 | T0T1TE 134 | T0T2T3 135 | T0T2T4 136 | T0T2T5 137 | T0T2T6 138 | T0T2T7 139 | T0T2T8 140 | T0T2T9 141 | T0T2TA 142 | T0T2TB 143 | T0T2TC 144 | T0T2TD 145 | T0T2TE 146 | T0T3T4 147 | T0T3T5 148 | T0T3T6 149 | T0T3T7 150 | T0T3T8 151 | T0T3T9 152 | T0T3TA 153 | T0T3TB 154 | T0T3TC 155 | T0T3TD 156 | T0T3TE 157 | T0T4T5 158 | T0T4T6 159 | T0T4T7 160 | T0T4T8 161 | T0T4T9 162 | T0T4TA 163 | T0T4TB 164 | T0T4TC 165 | T0T4TD 166 | T0T4TE 167 | T0T5T6 168 | T0T5T7 169 | T0T5T8 170 | T0T5T9 171 | T0T5TA 172 | T0T5TB 173 | T0T5TC 174 | T0T5TD 175 | T0T5TE 176 | T0T6T7 177 | T0T6T8 178 | T0T6T9 179 | T0T6TA 180 | T0T6TB 181 | T0T6TC 182 | T0T6TD 183 | T0T6TE 184 | T0T7T8 185 | T0T7T9 186 | T0T7TA 187 | T0T7TB 188 | T0T7TC 189 | T0T7TD 190 | T0T7TE 191 | T0T8T9 192 | T0T8TA 193 | T0T8TB 194 | T0T8TC 195 | T0T8TD 196 | T0T8TE 197 | T0T9TA 198 | T0T9TB 199 | T0T9TC 200 | T0T9TD 201 | T0T9TE 202 | T0TATB 203 | T0TATC 204 | T0TATD 205 | T0TATE 206 | T0TBTC 207 | T0TBTD 208 | T0TBTE 209 | T0TCTD 210 | T0TCTE 211 | T0TDTE 212 | T1T2T3 213 | T1T2T4 214 | T1T2T5 215 | T1T2T6 216 | T1T2T7 217 | T1T2T8 218 | T1T2T9 219 | T1T2TA 220 | T1T2TB 221 | T1T2TC 222 | T1T2TD 223 | T1T2TE 224 | T1T3T4 225 | T1T3T5 226 | T1T3T6 227 | T1T3T7 228 | T1T3T8 229 | T1T3T9 230 | T1T3TA 231 | T1T3TB 232 | T1T3TC 233 | T1T3TD 234 | T1T3TE 235 | T1T4T5 236 | T1T4T6 237 | T1T4T7 238 | T1T4T8 239 | T1T4T9 240 | T1T4TA 241 | T1T4TB 242 | T1T4TC 243 | T1T4TD 244 | T1T4TE 245 | T1T5T6 246 | T1T5T7 247 | T1T5T8 248 | T1T5T9 249 | T1T5TA 250 | T1T5TB 251 | T1T5TC 252 | T1T5TD 253 | T1T5TE 254 | T1T6T7 255 | T1T6T8 256 | T1T6T9 257 | T1T6TA 258 | T1T6TB 259 | T1T6TC 260 | T1T6TD 261 | T1T6TE 262 | T1T7T8 263 | T1T7T9 264 | T1T7TA 265 | T1T7TB 266 | T1T7TC 267 | T1T7TD 268 | T1T7TE 269 | T1T8T9 270 | T1T8TA 271 | T1T8TB 272 | T1T8TC 273 | T1T8TD 274 | T1T8TE 275 | T1T9TA 276 | T1T9TB 277 | T1T9TC 278 | T1T9TD 279 | T1T9TE 280 | T1TATB 281 | T1TATC 282 | T1TATD 283 | T1TATE 284 | T1TBTC 285 | T1TBTD 286 | T1TBTE 287 | T1TCTD 288 | T1TCTE 289 | T1TDTE 290 | T2T3T4 291 | T2T3T5 292 | T2T3T6 293 | T2T3T7 294 | T2T3T8 295 | T2T3T9 296 | T2T3TA 297 | T2T3TB 298 | T2T3TC 299 | T2T3TD 300 | T2T3TE 301 | T2T4T5 302 | T2T4T6 303 | T2T4T7 304 | T2T4T8 305 | T2T4T9 306 | T2T4TA 307 | T2T4TB 308 | T2T4TC 309 | T2T4TD 310 | T2T4TE 311 | T2T5T6 312 | T2T5T7 313 | T2T5T8 314 | T2T5T9 315 | T2T5TA 316 | T2T5TB 317 | T2T5TC 318 | T2T5TD 319 | T2T5TE 320 | T2T6T7 321 | T2T6T8 322 | T2T6T9 323 | T2T6TA 324 | T2T6TB 325 | T2T6TC 326 | T2T6TD 327 | T2T6TE 328 | T2T7T8 329 | T2T7T9 330 | T2T7TA 331 | T2T7TB 332 | T2T7TC 333 | T2T7TD 334 | T2T7TE 335 | T2T8T9 336 | T2T8TA 337 | T2T8TB 338 | T2T8TC 339 | T2T8TD 340 | T2T8TE 341 | T2T9TA 342 | T2T9TB 343 | T2T9TC 344 | T2T9TD 345 | T2T9TE 346 | T2TATB 347 | T2TATC 348 | T2TATD 349 | T2TATE 350 | T2TBTC 351 | T2TBTD 352 | T2TBTE 353 | T2TCTD 354 | T2TCTE 355 | T2TDTE 356 | T3T4T5 357 | T3T4T6 358 | T3T4T7 359 | T3T4T8 360 | T3T4T9 361 | T3T4TA 362 | T3T4TB 363 | T3T4TC 364 | T3T4TD 365 | T3T4TE 366 | T3T5T6 367 | T3T5T7 368 | T3T5T8 369 | T3T5T9 370 | T3T5TA 371 | T3T5TB 372 | T3T5TC 373 | T3T5TD 374 | T3T5TE 375 | T3T6T7 376 | T3T6T8 377 | T3T6T9 378 | T3T6TA 379 | T3T6TB 380 | T3T6TC 381 | T3T6TD 382 | T3T6TE 383 | T3T7T8 384 | T3T7T9 385 | T3T7TA 386 | T3T7TB 387 | T3T7TC 388 | T3T7TD 389 | T3T7TE 390 | T3T8T9 391 | T3T8TA 392 | T3T8TB 393 | T3T8TC 394 | T3T8TD 395 | T3T8TE 396 | T3T9TA 397 | T3T9TB 398 | T3T9TC 399 | T3T9TD 400 | T3T9TE 401 | T3TATB 402 | T3TATC 403 | T3TATD 404 | T3TATE 405 | T3TBTC 406 | T3TBTD 407 | T3TBTE 408 | T3TCTD 409 | T3TCTE 410 | T3TDTE 411 | T4T5T6 412 | T4T5T7 413 | T4T5T8 414 | T4T5T9 415 | T4T5TA 416 | T4T5TB 417 | T4T5TC 418 | T4T5TD 419 | T4T5TE 420 | T4T6T7 421 | T4T6T8 422 | T4T6T9 423 | T4T6TA 424 | T4T6TB 425 | T4T6TC 426 | T4T6TD 427 | T4T6TE 428 | T4T7T8 429 | T4T7T9 430 | T4T7TA 431 | T4T7TB 432 | T4T7TC 433 | T4T7TD 434 | T4T7TE 435 | T4T8T9 436 | T4T8TA 437 | T4T8TB 438 | T4T8TC 439 | T4T8TD 440 | T4T8TE 441 | T4T9TA 442 | T4T9TB 443 | T4T9TC 444 | T4T9TD 445 | T4T9TE 446 | T4TATB 447 | T4TATC 448 | T4TATD 449 | T4TATE 450 | T4TBTC 451 | T4TBTD 452 | T4TBTE 453 | T4TCTD 454 | T4TCTE 455 | T4TDTE 456 | T5T6T7 457 | T5T6T8 458 | T5T6T9 459 | T5T6TA 460 | T5T6TB 461 | T5T6TC 462 | T5T6TD 463 | T5T6TE 464 | T5T7T8 465 | T5T7T9 466 | T5T7TA 467 | T5T7TB 468 | T5T7TC 469 | T5T7TD 470 | T5T7TE 471 | T5T8T9 472 | T5T8TA 473 | T5T8TB 474 | T5T8TC 475 | T5T8TD 476 | T5T8TE 477 | T5T9TA 478 | T5T9TB 479 | T5T9TC 480 | T5T9TD 481 | T5T9TE 482 | T5TATB 483 | T5TATC 484 | T5TATD 485 | T5TATE 486 | T5TBTC 487 | T5TBTD 488 | T5TBTE 489 | T5TCTD 490 | T5TCTE 491 | T5TDTE 492 | T6T7T8 493 | T6T7T9 494 | T6T7TA 495 | T6T7TB 496 | T6T7TC 497 | T6T7TD 498 | T6T7TE 499 | T6T8T9 500 | T6T8TA 501 | T6T8TB 502 | T6T8TC 503 | T6T8TD 504 | T6T8TE 505 | T6T9TA 506 | T6T9TB 507 | T6T9TC 508 | T6T9TD 509 | T6T9TE 510 | T6TATB 511 | T6TATC 512 | T6TATD 513 | T6TATE 514 | T6TBTC 515 | T6TBTD 516 | T6TBTE 517 | T6TCTD 518 | T6TCTE 519 | T6TDTE 520 | T7T8T9 521 | T7T8TA 522 | T7T8TB 523 | T7T8TC 524 | T7T8TD 525 | T7T8TE 526 | T7T9TA 527 | T7T9TB 528 | T7T9TC 529 | T7T9TD 530 | T7T9TE 531 | T7TATB 532 | T7TATC 533 | T7TATD 534 | T7TATE 535 | T7TBTC 536 | T7TBTD 537 | T7TBTE 538 | T7TCTD 539 | T7TCTE 540 | T7TDTE 541 | T8T9TA 542 | T8T9TB 543 | T8T9TC 544 | T8T9TD 545 | T8T9TE 546 | T8TATB 547 | T8TATC 548 | T8TATD 549 | T8TATE 550 | T8TBTC 551 | T8TBTD 552 | T8TBTE 553 | T8TCTD 554 | T8TCTE 555 | T8TDTE 556 | T9TATB 557 | T9TATC 558 | T9TATD 559 | T9TATE 560 | T9TBTC 561 | T9TBTD 562 | T9TBTE 563 | T9TCTD 564 | T9TCTE 565 | T9TDTE 566 | TATBTC 567 | TATBTD 568 | TATBTE 569 | TATCTD 570 | TATCTE 571 | TATDTE 572 | TBTCTD 573 | TBTCTE 574 | TBTDTE 575 | TCTDTE 576 | -------------------------------------------------------------------------------- /public/oclHashcat.log: -------------------------------------------------------------------------------- 1 | TOP911baf00 START 2 | TOP911baf00 attack_mode 3 3 | TOP911baf00 attack_kern 3 4 | TOP911baf00 benchmark 0 5 | TOP911baf00 benchmark_mode 1 6 | TOP911baf00 bitmap_min 16 7 | TOP911baf00 bitmap_max 24 8 | TOP911baf00 debug_mode 0 9 | TOP911baf00 eula 0 10 | TOP911baf00 force 0 11 | TOP911baf00 gpu_accel 0 12 | TOP911baf00 gpu_async 0 13 | TOP911baf00 gpu_loops 0 14 | TOP911baf00 gpu_temp_abort 90 15 | TOP911baf00 gpu_temp_disable 0 16 | TOP911baf00 gpu_temp_retain 80 17 | TOP911baf00 hash_mode 1000 18 | TOP911baf00 hex_charset 0 19 | TOP911baf00 hex_salt 0 20 | TOP911baf00 hex_wordlist 0 21 | TOP911baf00 increment 0 22 | TOP911baf00 increment_max 54 23 | TOP911baf00 increment_min 1 24 | TOP911baf00 keyspace 0 25 | TOP911baf00 left 0 26 | TOP911baf00 logfile_disable 0 27 | TOP911baf00 loopback 0 28 | TOP911baf00 markov_classic 0 29 | TOP911baf00 markov_disable 0 30 | TOP911baf00 markov_threshold 0 31 | TOP911baf00 outfile_autohex 1 32 | TOP911baf00 outfile_check_timer 5 33 | TOP911baf00 outfile_format 3 34 | TOP911baf00 potfile_disable 1 35 | TOP911baf00 powertune_enable 0 36 | TOP911baf00 scrypt_tmto 0 37 | TOP911baf00 quiet 0 38 | TOP911baf00 remove 1 39 | TOP911baf00 remove_timer 60 40 | TOP911baf00 restore 0 41 | TOP911baf00 restore_disable 0 42 | TOP911baf00 restore_timer 60 43 | TOP911baf00 rp_gen 0 44 | TOP911baf00 rp_gen_func_max 4 45 | TOP911baf00 rp_gen_func_min 1 46 | TOP911baf00 rp_gen_seed 0 47 | TOP911baf00 runtime 0 48 | TOP911baf00 segment_size 32 49 | TOP911baf00 show 0 50 | TOP911baf00 status 0 51 | TOP911baf00 status_automat 0 52 | TOP911baf00 status_timer 5 53 | TOP911baf00 usage 0 54 | TOP911baf00 username 0 55 | TOP911baf00 version 0 56 | TOP911baf00 weak_hash_threshold 100 57 | TOP911baf00 workload_profile 2 58 | TOP911baf00 limit 0 59 | TOP911baf00 skip 0 60 | TOP911baf00 separator : 61 | TOP911baf00 gpu_devices 1,2,4 62 | TOP911baf00 outfile /home/audit/demo/cracked/demo.txt 63 | TOP911baf00 rule_buf_l : 64 | TOP911baf00 rule_buf_r : 65 | TOP911baf00 session oclHashcat 66 | TOP911baf00 target /home/audit/demo/hashes/demo.pwdump-ntlmonly.txt 67 | TOP911baf00 hashlist_mode 4 68 | TOP911baf00 hashlist_format 0 69 | TOP911baf00 SUBd3d9aabb START 70 | TOP911baf00 SUBd3d9aabb mask ?1 71 | TOP911baf00 SUBd3d9aabb status-after-work 2 72 | TOP911baf00 SUBd3d9aabb runtime_start 1451427531 73 | TOP911baf00 SUBd3d9aabb runtime_stop 1451427531 74 | TOP911baf00 SUBd3d9aabb STOP 75 | TOP911baf00 SUBb06f60aa START 76 | TOP911baf00 SUBb06f60aa mask ?1?2 77 | TOP911baf00 SUBb06f60aa status-after-work 2 78 | TOP911baf00 SUBb06f60aa runtime_start 1451427532 79 | TOP911baf00 SUBb06f60aa runtime_stop 1451427532 80 | TOP911baf00 SUBb06f60aa STOP 81 | TOP911baf00 SUB7708d329 START 82 | TOP911baf00 SUB7708d329 mask ?1?2?2 83 | TOP911baf00 SUB7708d329 status-after-work 2 84 | TOP911baf00 SUB7708d329 runtime_start 1451427532 85 | TOP911baf00 SUB7708d329 runtime_stop 1451427532 86 | TOP911baf00 SUB7708d329 STOP 87 | TOP911baf00 SUBbf781ce2 START 88 | TOP911baf00 SUBbf781ce2 mask ?1?2?2?2 89 | TOP911baf00 SUBbf781ce2 status-after-work 2 90 | TOP911baf00 SUBbf781ce2 runtime_start 1451427532 91 | TOP911baf00 SUBbf781ce2 runtime_stop 1451427532 92 | TOP911baf00 SUBbf781ce2 STOP 93 | TOP911baf00 SUBc2ab25f2 START 94 | TOP911baf00 SUBc2ab25f2 mask ?1?2?2?2?2 95 | TOP911baf00 SUBc2ab25f2 status-after-work 2 96 | TOP911baf00 SUBc2ab25f2 runtime_start 1451427532 97 | TOP911baf00 SUBc2ab25f2 runtime_stop 1451427532 98 | TOP911baf00 SUBc2ab25f2 STOP 99 | TOP911baf00 SUB679c3e2e START 100 | TOP911baf00 SUB679c3e2e mask ?1?2?2?2?2?2 101 | TOP911baf00 SUB679c3e2e status-after-work 2 102 | TOP911baf00 SUB679c3e2e runtime_start 1451427533 103 | TOP911baf00 SUB679c3e2e runtime_stop 1451427533 104 | TOP911baf00 SUB679c3e2e STOP 105 | TOP911baf00 SUB8c3f1f03 START 106 | TOP911baf00 SUB8c3f1f03 mask ?1?2?2?2?2?2?2 107 | TOP911baf00 SUB8c3f1f03 status-after-work 6 108 | TOP911baf00 proc_start 1451427527 109 | TOP911baf00 proc_stop 1451427535 110 | TOP911baf00 STOP 111 | TOP5d6e5189 START 112 | TOP5d6e5189 attack_mode 3 113 | TOP5d6e5189 attack_kern 3 114 | TOP5d6e5189 benchmark 0 115 | TOP5d6e5189 benchmark_mode 1 116 | TOP5d6e5189 bitmap_min 16 117 | TOP5d6e5189 bitmap_max 24 118 | TOP5d6e5189 debug_mode 0 119 | TOP5d6e5189 eula 0 120 | TOP5d6e5189 force 0 121 | TOP5d6e5189 gpu_accel 0 122 | TOP5d6e5189 gpu_async 0 123 | TOP5d6e5189 gpu_loops 0 124 | TOP5d6e5189 gpu_temp_abort 90 125 | TOP5d6e5189 gpu_temp_disable 0 126 | TOP5d6e5189 gpu_temp_retain 80 127 | TOP5d6e5189 hash_mode 1000 128 | TOP5d6e5189 hex_charset 0 129 | TOP5d6e5189 hex_salt 0 130 | TOP5d6e5189 hex_wordlist 0 131 | TOP5d6e5189 increment 0 132 | TOP5d6e5189 increment_max 54 133 | TOP5d6e5189 increment_min 1 134 | TOP5d6e5189 keyspace 0 135 | TOP5d6e5189 left 0 136 | TOP5d6e5189 logfile_disable 0 137 | TOP5d6e5189 loopback 0 138 | TOP5d6e5189 markov_classic 0 139 | TOP5d6e5189 markov_disable 0 140 | TOP5d6e5189 markov_threshold 0 141 | TOP5d6e5189 outfile_autohex 1 142 | TOP5d6e5189 outfile_check_timer 5 143 | TOP5d6e5189 outfile_format 3 144 | TOP5d6e5189 potfile_disable 1 145 | TOP5d6e5189 powertune_enable 0 146 | TOP5d6e5189 scrypt_tmto 0 147 | TOP5d6e5189 quiet 0 148 | TOP5d6e5189 remove 1 149 | TOP5d6e5189 remove_timer 60 150 | TOP5d6e5189 restore 0 151 | TOP5d6e5189 restore_disable 0 152 | TOP5d6e5189 restore_timer 60 153 | TOP5d6e5189 rp_gen 0 154 | TOP5d6e5189 rp_gen_func_max 4 155 | TOP5d6e5189 rp_gen_func_min 1 156 | TOP5d6e5189 rp_gen_seed 0 157 | TOP5d6e5189 runtime 0 158 | TOP5d6e5189 segment_size 32 159 | TOP5d6e5189 show 0 160 | TOP5d6e5189 status 0 161 | TOP5d6e5189 status_automat 0 162 | TOP5d6e5189 status_timer 5 163 | TOP5d6e5189 usage 0 164 | TOP5d6e5189 username 0 165 | TOP5d6e5189 version 0 166 | TOP5d6e5189 weak_hash_threshold 100 167 | TOP5d6e5189 workload_profile 2 168 | TOP5d6e5189 limit 0 169 | TOP5d6e5189 skip 0 170 | TOP5d6e5189 separator : 171 | TOP5d6e5189 gpu_devices 1,2,4 172 | TOP5d6e5189 outfile /home/audit/demo/cracked/demo.txt 173 | TOP5d6e5189 rule_buf_l : 174 | TOP5d6e5189 rule_buf_r : 175 | TOP5d6e5189 session oclHashcat 176 | TOP5d6e5189 target /home/audit/demo/hashes/demo.pwdump-ntlmonly.txt 177 | TOP5d6e5189 hashlist_mode 4 178 | TOP5d6e5189 hashlist_format 0 179 | TOP5d6e5189 SUB6f3963ed START 180 | TOP5d6e5189 SUB6f3963ed mask ?1 181 | TOP5d6e5189 SUB6f3963ed status-after-work 2 182 | TOP5d6e5189 SUB6f3963ed runtime_start 1451437540 183 | TOP5d6e5189 SUB6f3963ed runtime_stop 1451437540 184 | TOP5d6e5189 SUB6f3963ed STOP 185 | TOP5d6e5189 SUBbe84ad14 START 186 | TOP5d6e5189 SUBbe84ad14 mask ?1?2 187 | TOP5d6e5189 SUBbe84ad14 status-after-work 2 188 | TOP5d6e5189 SUBbe84ad14 runtime_start 1451437540 189 | TOP5d6e5189 SUBbe84ad14 runtime_stop 1451437540 190 | TOP5d6e5189 SUBbe84ad14 STOP 191 | TOP5d6e5189 SUBacec2713 START 192 | TOP5d6e5189 SUBacec2713 mask ?1?2?2 193 | TOP5d6e5189 SUBacec2713 status-after-work 2 194 | TOP5d6e5189 SUBacec2713 runtime_start 1451437540 195 | TOP5d6e5189 SUBacec2713 runtime_stop 1451437540 196 | TOP5d6e5189 SUBacec2713 STOP 197 | TOP5d6e5189 SUBbefd0722 START 198 | TOP5d6e5189 SUBbefd0722 mask ?1?2?2?2 199 | TOP5d6e5189 SUBbefd0722 status-after-work 2 200 | TOP5d6e5189 SUBbefd0722 runtime_start 1451437541 201 | TOP5d6e5189 SUBbefd0722 runtime_stop 1451437541 202 | TOP5d6e5189 SUBbefd0722 STOP 203 | TOP5d6e5189 SUB75479d2d START 204 | TOP5d6e5189 SUB75479d2d mask ?1?2?2?2?2 205 | TOP5d6e5189 SUB75479d2d status-after-work 2 206 | TOP5d6e5189 SUB75479d2d runtime_start 1451437541 207 | TOP5d6e5189 SUB75479d2d runtime_stop 1451437541 208 | TOP5d6e5189 SUB75479d2d STOP 209 | TOP5d6e5189 SUBaca04129 START 210 | TOP5d6e5189 SUBaca04129 mask ?1?2?2?2?2?2 211 | TOP5d6e5189 SUBaca04129 status-after-work 2 212 | TOP5d6e5189 SUBaca04129 runtime_start 1451437541 213 | TOP5d6e5189 SUBaca04129 runtime_stop 1451437541 214 | TOP5d6e5189 SUBaca04129 STOP 215 | TOP5d6e5189 SUBb092bfaf START 216 | TOP5d6e5189 SUBb092bfaf mask ?1?2?2?2?2?2?2 217 | TOP5d6e5189 SUBb092bfaf status-after-work 6 218 | TOP5d6e5189 proc_start 1451437539 219 | TOP5d6e5189 proc_stop 1451437547 220 | TOP5d6e5189 STOP 221 | --------------------------------------------------------------------------------