Comprehensive Bash Scripting in Kali Linux
n this tutorial, you'll see how you can create scripting commands using Bash. Why Bash scripting? The universality of Bash allows us, penetration testers, to execute powerful terminal commands without having to install a compiler or an integrated development environment (IDE). To develop a Bash script, all you need is a text editor, and you're good to go. When to use Bash scripts? This is an important question that needs to be addressed before this season begins! Bash is not designed to develop complex tools. If you're going to do that, it's best to use Python (the basic concepts of Python are covered in the later sections of this book).
Bash is for small, fast tools that are used when you want to save time (for example, you write the same commands in a bash script to avoid repeating the same commands). This chapter will not only teach you the Bash scripting language, but beyond that, it will also show you the ideology of programming. If you're new to the world of programming, this chapter is a good starting point for you to understand how programming languages work (they have a lot in common).
In this chapter, you will learn:
■ Printing to the screen using Bash
■ Using variables
■ Using script parameters
■ Handling user input
■ Creating functions
■ Using conditional if statements
■ Using while and for loops
Basic Bash Scripting
Figure 2.1 summarizes all the commands, so you can use it as a reference to understand all the content of this chapter. In summary, basic Bash scripting is divided into the following categories:
■ Variables
■ Functions
■ User input
■ Script output
■ Parameters
Printing to the Screen in Bash
There are two common ways to write to the terminal command line output using Bash scripting. The first method is simple to use the echo statement we saw in the previous chapter (we'll put the amount of text inside single or double quotations):
$echo 'message to print.'
The second method is the printf command; this command is more flexible than echo because it allows you to format the string you want to print:
$printf 'message to print'
The former formula is pretty simple; in fact, Printf allows you to format strings well (not just for printing; it's more than that). Let's see an example:
if we want to represent the number of live hosts on a network, we can use the following pattern:
root@kali:~# printf "%s %d\n" "Number of live hosts:" 15
Number of live hosts: 15
Let's break down the command to better understand what's happening:
■ : It means that we enter a string (text) in this position
■ : It means that we
enter an integer (decimal number) in this position ■ : It means that after printing, we want to move to the new line%s
%d
\n
Also note that we use double quotations instead of single quotations. Double quotations allow us to have more flexibility in manipulating strings than single quotations. So, most of the time we can use double quotations for printf (we rarely need to use single quotations). To format a string using the printf command, you can use the following templates:
■ : String (texts)
■ : Integer (numbers)
■ : Decimal (including positive and negative numbers)
■ : Hexadecimal
■ : New
line ■ : Back to the beginning of the line
■ : Horizontal tab%s
%d
%f
%x
\n
\r
\t
Variables
What is a variable and why does every programming language use it? Think of a variable as a storage area where you can store values such as strings and numbers. The goal is to use them frequently in your program, and this concept applies to any programming language (not just Bash scripting). A variable name can only contain an alphanumeric character or underline (_) (there are different naming conventions in other programming languages).
For example, if you want to store the router's IP address in a variable, you'll first create a file named (Bash scripts will run out of files), and inside the file, you'll enter the following code:var.sh
.sh
#!/bin/bash
#Simple program with a variable
ROUTERIP="10.0.0.1"
printf "The router IP address: $ROUTERIP\n"
Explaining your first Bash script:
■ It's known as Bash shebang; we need to put it at the beginning to tell Kali Linux what interpreter to use to parse the script file (we'll use the same concept in chapter 18, "Pentest Automation with Python", with the Python programming language). The second line is to show that this is a comment (comments are commands that the author puts in the code or script for later reference).
■ The name is variable and its value.
■ Finally, we use the printf function to print the value to the output page.#!/bin/bash
#
ROUTERIP
10.0.0.1
To run it, first make sure you give it the necessary permissions (look at the output below to see what happens if you don't). Since we're in the same directory (/root), we'll use to run it:./var.sh
root@kali:~# ./var.sh
bash: ./var.sh: Permission denied
root@kali:~# chmod +x var.sh
root@kali:~# ./var.sh
The router IP address: 10.0.0.1
Congratulations, you've built your first Bash script! Now let's say we want this script to run automatically without needing to specify its path in the system. To do this, we need to add it to the variable. In our case, we will add to the variable so that we can save our own scripts in this directory. First, open the file using any text editor. Once the file is uploaded, scroll down and add the line highlighted in Figure 2.2.$PATH
/opt
$PATH
.bashrc
Changes cause it to be added to the variable. At this point, save the file and close all terminals. Open the terminal window again and copy the script file to the folder. From now on, there is no need to enter its path; we just run it by typing in the name of the script (no need to run again; the execution license is already set):/opt
$PATH
/opt
var.sh
chmod
root@kali:~# cp var.sh /opt/
root@kali:~# cd /opt
root@kali:/opt# ls -la | grep "var.sh"
-rwxr-xr-x 1 root root 110 Sep 28 11:24 var.sh
root@kali:/opt# var.sh
The router IP address: 10.0.0.1
Commands Variable
Sometimes you may want to run commands and store their output in a variable. Most of the time, the goal is to manipulate the output content of the command. Here we have a simple command that runs the command and filters out the names of files that have the word "simple" in them using the command. (Don't worry, you'll see more complex scenarios in the later sections of this chapter.ls
grep
#!/bin/bash
LS_CMD=$(ls | grep 'simple')
printf "$LS_CMD\n"
The results of running the script will look like this:
root@kali:/opt# simplels.sh
simpleadd.sh
simplels.sh
Script Parameters
Sometimes, you need to give parameters to your Bash script. To do this, you need to separate each parameter with spaces, and then you can manipulate these parameters inside the Bash script. Let's build a simple calculator() that adds two numbers together:simpleadd.sh
#!/bin/bash
num1
NUM1=$1
# num2
NUM2=$2
#total
TOTAL=$(($NUM1 + $NUM2))
echo '########################'
printf "%s %d\n" "The total is =" $TOTAL
echo '########################'
In the previous script you can see that we accessed the first parameter using the command and the second parameter using (you can add as many parameters as you want). Now let's add up the two numbers using our new script (note that I'll be saving my scripts in the folder from now on):$1
$2
/opt
root@kali:/opt# simpleadd.sh 5 2
########################
The total is = 7
########################
There is a limitation in the previous script; this script can only add two numbers. If you want more flexibility and can add from two to five, then we can use the default parameter feature. In other words, by default all parameter values are set to zero and are added up after the user enters the actual value:
#!/bin/bash
NUM1=${1:-0}
#num2
NUM2=${2:-0}
#num3
NUM3=${3:-0}
#num4
NUM4=${4:-0}
#num5
NUM5=${5:-0}
# total
TOTAL=$(($NUM1 + $NUM2 + $NUM3 + $NUM4 + $NUM5))
echo '########################'
printf "%s %d\n" "The total is =" $TOTAL
echo '########################'
To understand how this script works, let's look at the variable as an example (the same concept applies to the other five variables). We instruct it to read the first parameter from the terminal and set it to zero if it wasn't entered by the user, as it came in.
Using the default variables, we are no longer limited to adding up five numbers; we can now add as many numbers as we want, but the maximum number will be five (in the example below, we add up three):NUM1
:-0
root@kali:~# simpleadd.sh 2 4 4
########################
The total is = 10
########################
Tips
If you want to know the number of parameters entered in the script, you can use it to get the total number. Based on the previous example, the value would be equal to three because we have submitted three arguments to the script. If you add the following line after the line:$#
$#
printf
printf "%s %d\n" "The total number of params =" $#
You should see something like the following in the terminal window:
root@kali:~# simpleadd.sh 2 4 4
########################
The total is = 10
The total number of params = 3
########################
User Input
Another way to interact with the inputs provided via the shell script is to use the function. The best way to explain this is to use examples. We will ask the user to enter their first and last name, and then we will print their full name on the screen:read
#!/bin/bash
read -p "Please enter your first name:" FIRSTNAME
read -p "Please enter your last name:" LASTNAME
printf "Your full name is: $FIRSTNAME $LASTNAME\n"
To run it, we just enter the name of the script (we no longer need to submit parameters like before). As soon as we enter the name of the script, the messages we defined in the previous script will appear to us:
root@kali:~# nameprint.sh
Please enter your first name:Gus
Please enter your last name:Khawaja
Your full name is: Gus Khawaja
Functions
Functions are a way of organizing your Bash script into logical sections rather than having a messy structure (which programmers call spaghetti code). Let's reorganize (rewrite) the previous calculator app to make it look better.
This Bash script (in Figure 2.3) is divided into three sections:
■ In the first part, all global variables are created. Global variables are accessible within any function you create. For example, we can use all the variables declared in the example within the function.
■ Then, we build functions and divide our programs into logical sections. The function only prints the text that we give it. We use to access the parameter value that is sent to this function (which is the string).
■ Finally, we call each function sequentially (each with its name). First, we print the header, then we add up the numbers, and finally we print the results.NUM
add
print_custom()
$1
CALCULATOR
Conditions and Loops
Now that you have learned the basics of Bash scripting, we can introduce more advanced techniques. When you write programs in most programming languages (such as PHP, Python, C, C++, C#, etc.) as well as Bash scripting, you will encounter conditions (if statements) and loops, as shown in Figure 2.4.
Conditions
An if command works as follows:
if [[ مقایسه ]]
then
True, do something
else
False, Do something else
fi
If you've noticed, the best way to explain this pattern is through examples. Let's build an application that pings a host using Nmap and displays the status of the machine depending on the condition (the host is up or down):
#!/bin/bash
# Nmap
### ###
# IP
IP_ADDRESS=$1
function ping_host(){
ping_cmd=$(nmap -sn $IP_ADDRESS | grep 'Host is up' | cut -d '(' -f 1)
}
function print_status(){
if [[ -z $ping_cmd ]]
then
echo 'Host is down'
else
echo 'Host is up'
fi
}
ping_host
print_status
The command either returns an empty string if the host is down or returns the value "Host is up" if it responds. (Try running the full nmap command in your terminal window to see the differences. In the bet, the option checks if the string is empty; if yes, then "Host is down" is printed and if not "Host is up" is printed:nmap
$IP_ADDRESS
if
-z
root@kali:~# simpleping.sh 10.0.0.11
Host is down
root@kali:~# simpleping.sh 10.0.0.1
Host is up
Other conditional commands
But what about other conditional commands? In fact, you can compare numeric, textual, or file values, as shown in Tables 2.1, 2.2, and 2.3.
Loops
You can write loops in two different ways: using loops or using loops. Most programming languages use the same pattern of loops. So, if you understand how loops work in Bash, the same concept will be applicable in languages like Python. The ring acts on the following structure:while
for
while
while [[ do ]]
do
do something
done
The best way to explain a loop is through a counter from 1 to 10. We'll build an app that displays a progress bar:
#!/bin/bash
COUNTER=1
BAR='##########'
while [[ $COUNTER -lt 11 ]]
do
echo -ne "\r${BAR:0:COUNTER}"
sleep 1
COUNTER=$(( $COUNTER +1 ))
done
Notice that the condition() in the loop follows the same rules as the bet. Since we want the counter to stop at the number 10, we will use the following mathematical formula: . Each time the counter is raised, the progress bar is displayed. To make this app even more engaging, we pause it for a second before moving on to the next issue.[[ $COUNTER -lt 11 ]]
while
if
counter<11
On the other hand, the loop acts in the following pattern:for
for ... in [345]
do
something
done
We'll use the same example as before, but this time we'll use the loop. You will find that the loop is more flexible than the loop. (Honestly, I rarely use rings.) Also, you don't need to increase the index counter; this will be done automatically for you:for
for
while
while
#!/bin/bash
#نوار پیشرفت با حلقه For
#نوار
BAR='##########'
for COUNTER in {1..10}
do
echo -ne "\r${BAR:0:$COUNTER}"
sleep 1
done
File Iteration Duplicate Files
To read a text file in Bash using a loop, you can do this:for
for line in $(cat filename)
do
do something
done
In the example below, we'll store a list of IP addresses in a file called. We then use the Nmap ping app we built earlier to check if each IP address is high or low. In addition, we will also look at the DNS name of each IP address:ips.txt
#!/bin/bash
read -p "Enter the IP addresses file name / path:" FILE_PATH_NAME
function check_host(){
if [[ -n $IP_ADDRESS ]]
then
ping_cmd=$(nmap -sn $IP_ADDRESS | grep 'Host is up' | cut -d '(' -f 1)
echo '------------------------------------------------'
if [[ -z $ping_cmd ]]
then
printf "$IP_ADDRESS is down\n"
else
printf "$IP_ADDRESS is up\n"
dns_name
fi
fi
}
function dns_name(){
dns_name=$(host $IP_ADDRESS)
printf "$dns_name\n"
}
for ip in $(cat $FILE_PATH_NAME)
do
IP_ADDRESS=$ip
check_host
done
If you have followed this chapter carefully, you should be able to understand everything in the previous code. The main difference with this app is that I've used tab spacing to make the script look cleaner. The previous example covers most of what we've done so far, including the following:
- User input
- Announcing Variables
- Using Functions
- Use Terms
if
- Repeat loops
- Print to Screen
Summary
I hope you've done all the practice this season, especially if you're new to programming. Many of the concepts mentioned are applicable to different programming languages, so consider the exercises as an opportunity to learn the basics. Personally, I use Bash scripting for small, fast-paced scenarios. If you want to build more complex programs, you can do so using Python. Don't worry! In those courses, you will learn about Python so that you can solve any position you want in your career as a penetration tester. Finally, this chapter covered a lot of information about Bash scripting.
However, there is more information than what is given in this chapter. In practice, I use internet search engines to quickly find Bash scripting sources. In fact, there is no need to memorize everything you learned in this article.
No comments:
Post a Comment