Tuesday, February 25, 2025

Comprehensive Bash Scripting in Kali Linux

 

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#ROUTERIP10.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/optvar.shchmod

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.lsgrep

#!/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.
NUMaddprint_custom()$1CALCULATOR

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_ADDRESSif-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:whileforwhile

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 ]]whileifcounter<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:forforwhilewhile

#!/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: