# frozen_string_literal: true
#
# Copyright (c) 2006-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
#
# Ronin is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ronin is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ronin. If not, see .
#
require 'ronin/cli/file_processor_command'
require 'ronin/cli/pattern_options'
require 'command_kit/colors'
module Ronin
class CLI
module Commands
#
# Greps for common patterns in a file/stream.
#
# ## Usage
#
# ronin grep [options] [FILE ...]
#
# ## Options
#
# -N, --number Searches for all numbers
# -X, --hex-number Searches for all hexadecimal numbers
# -V, --version-number Searches for all version numbers
# -w, --word Searches for all words
# --mac-addr Searches for all MAC addresses
# -4, --ipv4-addr Searches for all IPv4 addresses
# -6, --ipv6-addr Searches for all IPv6 addresses
# -I, --ip Searches for all IP addresses
# -H, --host Searches for all host names
# -D, --domain Searches for all domain names
# --uri Searches for all URIs
# -U, --url Searches for all URLs
# --user-name Searches for all user names
# -E, --email-addr Searches for all email addresses
# --obfuscated-email-addr Searches for all obfuscated email addresses
# --phone-number Searches for all phone numbers
# --ssn Searches for all Social Security Numbers (SSNs)
# --amex-cc Searches for all AMEX Credit Card numbers
# --discover-cc Searches for all Discover Card numbers
# --mastercard-cc Searches for all MasterCard numbers
# --visa-cc Searches for all VISA Credit Card numbers
# --visa-mastercard-cc Searches for all VISA MasterCard numbers
# --cc Searches for all Credit Card numbers
# --file-name Searches for all file names
# --dir-name Searches for all directory names
# --relative-unix-path Searches for all relative UNIX paths
# --absolute-unix-path Searches for all absolute UNIX paths
# --unix-path Searches for all UNIX paths
# --relative-windows-path Searches for all relative Windows paths
# --absolute-windows-path Searches for all absolute Windows paths
# --windows-path Searches for all Windows paths
# --relative-path Searches for all relative paths
# --absolute-path Searches for all absolute paths
# -P, --path Searches for all paths
# --identifier Searches for all identifier names
# --variable-name Searches for all variable names
# --variable-assignment Searches for all variable assignments
# --function-name Searches for all function names
# --md5 Searches for all MD5 hashes
# --sha1 Searches for all SHA1 hashes
# --sha256 Searches for all SHA256 hashes
# --sha512 Searches for all SHA512 hashes
# --hash Searches for all hashes
# --ssh-private-key Searches for all SSH private key data
# --dsa-private-key Searches for all DSA private key data
# --ec-private-key Searches for all EC private key data
# --rsa-private-key Searches for all RSA private key data
# -K, --private-key Searches for all private key data
# --ssh-public-key Searches for all SSH public key data
# --public-key Searches for all public key data
# --aws-access-key-id Searches for all AWS access key IDs
# --aws-secret-access-key Searches for all AWS secret access keys
# -A, --api-key Searches for all API keys
# --single-quoted-string Searches for all single-quoted strings
# --double-quoted-string Searches for all double-quoted strings
# -S, --string Searches for all quoted strings
# -B, --base64 Searches for all Base64 strings
# --c-comment Searches for all C comments
# --cpp-comment Searches for all C++ comments
# --java-comment Searches for all Java comments
# --javascript-comment Searches for all JavaScript comments
# --shell-comment Searches for all Shell comments
# --ruby-comment Searches for all Ruby comments
# --python-comment Searches for all Python comments
# --comment Searches for all comments
# -e, --regexp /REGEXP/ Custom regular expression to search for
# -o, --only-matching Only print the matching data
# -n, --line-number Print the line number for each line
# --with-filename Print the file name for each match
# -h, --help Print help information
#
# ## Arguments
#
# [FILE ...] Optional input file(s)
#
class Grep < FileProcessorCommand
include PatternOptions
include CommandKit::Colors
usage '[options] [FILE ...]'
option :only_matching, short: '-o',
desc: 'Only print the matching data'
option :line_number, short: '-n',
desc: 'Print the line number for each line'
option :with_filename, desc: 'Print the file name for each match'
description 'Searches files/input for common patterns'
man_page 'ronin-grep.1'
#
# Runs the `ronin grep` command.
#
# @param [Array] files
# Additional file arguments to grep.
#
def run(*files)
unless @pattern
print_error "must specify a pattern to search for"
exit -1
end
super(*files)
end
#
# Greps the input stream.
#
# @param [IO, StringIO] input
# The input stream to grep.
#
def process_input(input)
filename = filename_of(input)
input.each_line(chomp: true).each_with_index do |line,index|
match_line(line, filename: filename, line_number: index+1)
end
end
#
# Returns the file name for the IO stream.
#
# @param [File, IO] io
#
# @return [String]
#
def filename_of(io)
case io
when File then io.path
else '[stdin]'
end
end
#
# Attempts to match a line of text.
#
# @param [String] line
#
# @param [Hash{Symbol => Object}] kwargs
# Additional keyword arguments.
#
# @option kwargs [String] :filename
#
# @option kwargs [Integer] :line_number
#
def match_line(line,**kwargs)
index = 0
printed_prefix = false
while (match = line.match(@pattern,index))
unless printed_prefix
print_line_prefix(**kwargs)
printed_prefix = true
end
match_start, match_stop = match.offset(0)
# print the text before the match, unless --only-matching is enabled
print(line[index...match_start]) unless options[:only_matching]
print_match(match)
index = match_stop
end
unless options[:only_matching]
# print the rest of the line, if we've had at least one match
puts(line[index..]) if index > 0
end
end
#
# Optionally prints the filename or line-number prefix for a line.
#
# @param [String] filename
#
# @param [Integer] line_number
#
def print_line_prefix(filename: , line_number: )
if options[:with_filename]
print colors.magenta(filename)
print colors.cyan(':')
end
if options[:line_numbers]
print colors.green(line_number)
print colors.cyan(':')
end
end
#
# Prints the matched string w/o ANSI highlighting.
#
# @param [String] match
#
def print_match(match)
match_string = match[0]
highlighted = colors.bold(colors.red(match_string))
if options[:only_matching]
puts highlighted
else
print highlighted
end
end
end
end
end
end