the only good website on the internet quaso.engineering
at main 135 lines 4.5 kB view raw view rendered
1--- 2title: Writing A Simple Ruby Script To Automate Nmap 3hero: ruby-nmap-thumb.png 4--- 5 6An nmap scan should always be the first thing to do when you start a box, and since I'm too lazy to write `nmap -sV -sC -oA initial box_ip` (and I want a progress bar instead of having to constantly press a button to see progress), we're just going to write a script to do it for us. 7 8I'm using Ruby for this because I think it's just as readable as Python (so I don't have to explain as much) and because I'm not bothered to learn how to do this in Python, which means that this is the first time I've ever shown code on this website that isn't Python. 9 10Anyway, to do this we will use [a class from Ruby's standard library called PTY](https://ruby-doc.org/stdlib-2.4.1/libdoc/pty/rdoc/PTY.html). `PTY` allows you to spawn an external process and then interact with that process by using puts to write to it's `stdin` and gets to read from it's `stdout`. 11 12```ruby 13#!/usr/bin/ruby 14 15require 'pty' 16cmd = "nmap -sV #{ARGV[0]}" 17 18PTY.spawn( cmd ) do |stdout, stdin, pid| 19 loop do 20 stdin.puts ' ' 21 puts stdout.gets.chomp 22 sleep 0.1 23 end 24end 25``` 26 27This is our initial code. It runs nmap with the box IP as an argument and every 0.1 seconds, it sends a space character to stdin and prints stdout so we can see the progress of the scan. This works but right now we are only running nmap with -sV, so now we should add all the arguments we need. 28 29```ruby 30#!/usr/bin/ruby 31 32require 'pty' 33require 'fileutils' 34 35FileUtils.mkdir_p 'nmap' 36cmd = "nmap -sV -sC -oA nmap/initial #{ARGV[0]}" 37 38PTY.spawn( cmd ) do |stdout, stdin, pid| 39 loop do 40 stdin.puts ' ' 41 puts stdout.gets.chomp 42 43 running = %x[ ps -p #{pid} -o comm= ] 44 if running.include? "defunct" 45 break 46 end 47 48 sleep 0.1 49 end 50end 51``` 52 53Now we are creating a folder where all the nmap scripts will be stored using the library 'fileutils' and we've edited the 'cmd' variable to use all the arguments. I've also added a check to see if nmap has finshed in order to break out of the loop by checking if the process name includes the words 'defunct'. 54 55If you run this you will see that stdout becomes very messy as the progress is constantly being called. Let's get that progress bar working. 56 57```ruby 58#!/usr/bin/ruby 59 60require 'pty' 61require 'fileutils' 62require 'progress_bar' 63 64FileUtils.mkdir_p 'nmap' 65cmd = "nmap -sV -sC -oA nmap/initial #{ARGV[0]}" 66 67$syn_bar = ProgressBar.new 68$srv_bar = ProgressBar.new 69$nse_bar = ProgressBar.new 70 71$syn_progress = 0 72$srv_progress = 0 73$nse_progress = 0 74 75$step = "init" 76 77def increment_bar(stdout) 78 new_status = stdout.match(/[[:digit:]]{1,2}\.[[:digit:]]{2}/) 79 new_status ? new_status = new_status[0].to_i : return 80 81 if stdout.include? "SYN Stealth Scan" 82 if $step != "syn" 83 puts "Step 1/3 [SYN Stealth Scan]" 84 $step = "syn" 85 end 86 87 inc_amount = new_status - $syn_progress 88 $syn_progress = new_status 89 $syn_bar.increment! inc_amount 90 elsif stdout.include? "Service" 91 if $step != "srv" 92 puts "Step 2/3 [Service Scan]" 93 $step = "srv" 94 end 95 96 inc_amount = new_status - $srv_progress 97 $srv_progress = new_status 98 $srv_bar.increment! inc_amount 99 elsif stdout.include? "NSE Timing" 100 if $step != "nse" && $step != 'init' 101 # NSE Timing shows up before it actually begins 102 puts "Step 3/3 [NSE]" 103 $step = "nse" 104 end 105 106 inc_amount = new_status - $nse_progress 107 $nse_progress = new_status 108 $nse_bar.increment! inc_amount 109 end 110end 111 112PTY.spawn( cmd ) do |stdout, stdin, pid| 113 loop do 114 stdin.puts ' ' 115 response = stdout.gets.chomp 116 117 increment_bar(response) 118 119 running = %x[ ps -p #{pid} -o comm= ] 120 if running.include? "defunct" 121 break 122 end 123 124 sleep 0.1 125 end 126end 127``` 128 129This is a really quick and dirty way of getting a progress bar using the library `progress_bar`. Make sure to install it with: 130 131 gem install progress_bar 132 133Obviously I'm not super proud this script, it's actually pretty terrible for my standards, so much so that I don't want to explain it. But it does what I wanted it to and only took me 5 minutes to write. Someday I may comeback to it to clean up all the repeating code and stop using so many global variables (but I say that about all the code I write, so whatever). 134 135Now I can move save this as `/opt/scan-box` and call it with `/opt/scan-box box_ip`. You could also put it in `/bin` so you can call it with just `scan-box box_ip`, but I don't like doing that.