Welcome back to another installment of Programming Thursdays, my fellow red teamers and pen testers! Today, we’ll be diving deep into the world of Nim, a programming language that’s both powerful and versatile. With a syntax similar to Python and the ability to generate efficient, native code, Nim is the perfect tool for hackers looking to expand their arsenal.

So, let’s buckle up and dive into the world of Nim!

Introduction to Nim

Nim is a statically typed, compiled language that focuses on efficiency, expressiveness, and elegance. It boasts an easy-to-read syntax and produces efficient native code by leveraging a variety of backends, including C, C++, and JavaScript. Nim is suitable for a wide range of applications, from embedded systems to web development, and has seen increasing adoption in the security community.

Some key features of Nim include:

  • Statically typed with type inference
  • Compile-time metaprogramming
  • Efficient garbage collection
  • First-class concurrency support
  • Extensive standard library

Getting Started with Nim

To get started with Nim on your preferred platform, follow the steps outlined below:

Windows

  1. Download the latest Nim installer for Windows from the official website.
  2. Run the installer and follow the on-screen instructions to install Nim.
  3. Add the Nim installation path (e.g., C:\Nim\bin) to the PATH environment variable.
  4. Open a command prompt and verify the installation by running nim --version.

Linux

  1. Install Nim using your package manager, if available, or download the latest Nim tarball from the official website.
# For Ubuntu/Debian
sudo apt-get install nim

# For Fedora
sudo dnf install nim

# For Arch Linux
sudo pacman -S nim
  1. If you downloaded the tarball, extract it and run the install.sh script:
tar xvf nim-x.y.z.tar.xz
cd nim-x.y.z
./install.sh /path/to/install/nim
  1. Add the Nim installation path (e.g., /path/to/install/nim/bin) to the PATH environment variable.
  2. Open a terminal and verify the installation by running nim --version.

macOS

  1. Install Nim using Homebrew, or download the latest Nim tarball from the official website.
brew install nim
  1. If you downloaded the tarball, extract it and run the install.sh script:
tar xvf nim-x.y.z.tar.xz
cd nim-x.y.z
./install.sh /path/to/install/nim
  1. Add the Nim installation path (e.g., /path/to/install/nim/bin) to the PATH environment variable.
  2. Open a terminal and verify the installation by running nim --version.

Once Nim is installed and configured on your system, you can start writing and compiling Nim programs. To compile a Nim program, simply run nim compile <filename.nim> in your terminal or command prompt.

Basics of Nim

Variables and Data Types

Nim is statically typed, but thanks to its type inference capabilities, we don’t always have to explicitly specify the type of a variable. Let’s take a look at some of the basic data types in Nim and how to declare variables.

Integer Types

Nim has several integer types, including int, int8, int16, int32, and int64. The int type is the most commonly used and has a size that depends on the target platform. To declare an integer variable, you can use the var keyword:

var x: int = 42
var y = 7  # Type inference!

Floating-Point Types

Nim supports two floating-point types: float32 and float64. The default float type is an alias for float64. Here’s how to declare a floating-point variable:

var z: float = 3.14
var w = 2.718  # Type inference!

Boolean Types

The bool type in Nim can hold true or false values. Here’s an example of declaring a boolean variable:

var loggedIn: bool = false
var isAdmin = true  # Type inference!

Strings

Nim supports two types of strings: string and cstring. The string type is used for mutable strings, while cstring is used for immutable, null-terminated strings. Here’s an example of declaring a string variable:

var greeting: string = "Hello, world!"
var name = "Alice"  # Type inference!

Operators

Nim provides a rich set of operators, including arithmetic, comparison, logical, and bitwise operators. The syntax of these operators is similar to other popular languages like C and Python.

Arithmetic Operators

Nim supports the usual arithmetic operators: +, -, *, /, and %. Here’s an example:

var a = 10
var b = 3

var add = a + b
var sub = a - b
var mul = a * b
var div = a / b
var mod = a % b

Comparison Operators

Comparison operators in Nim include ==, !=, <, >, <=, and >=. Here’s an example:

var x = 42
var y = 13

var eq = x == y
var ne = x != y
var lt = x < y
var gt = x > y
var le = x <= y
var ge = x >= y

Logical Operators

Nim has three logical operators: and, or, and not. These operators are used to combine boolean expressions. Here’s an example:

var a = true
var b = false

var c = a and b
var d = a or b
var e = not a

Bitwise Operators

Nim supports bitwise operators like &, |, ^, ~, <<, and >>. Here’s an example:

var x = 0b1100
var y = 0b1010

var andOp = x & y
var orOp = x | y
var xorOp = x ^ y
var notOp = ~x
var leftShift = x << 2
var rightShift = x >> 2

Control Structures

Nim provides several control structures, including if, elif, else, case, while, for, and block. Let’s explore these control structures with some examples.

If, Elif, and Else

The if, elif, and else statements are used for conditional branching. Here’s an example:

var score = 85

if score >= 90:
  echo "A"
elif score >= 80:
  echo "B"
elif score >= 70:
  echo "C"
else:
  echo "F"

Case

The case statement is used for multi-way branching, similar to the switch statement in other languages. Here’s an example:

var day = "Monday"

case day
of "Monday", "Tuesday", "Wednesday", "Thursday", "Friday":
  echo "Weekday"
of "Saturday", "Sunday":
  echo "Weekend"
else:
  echo "Invalid day"

While

The while statement is used for loops with a condition. Here’s an example:

var i = 0

while i < 10:
  echo i
  i += 1

For

The for statement is used for iterating over a range or a sequence. Here’s an example:

for i in 0 .. 9:
  echo i

Block

The block statement is used to group statements together. This can be useful for controlling the scope of variables. Here’s an example:

block:
  var x = 42
  echo x

# x is not accessible here

Functions

Nim supports both procedural and functional programming styles. Functions in Nim are defined using the proc keyword, and they can return a value using the result variable. Here’s an example of a simple function:

proc add(a: int, b: int): int =
  result = a + b

echo add(3, 5)  # Output: 8

Nim also supports higher-order functions and closures. Here’s an example of a higher-order function and a closure:

import math

proc apply(func: proc(x: float): float, x: float): float =
  result = func(x)

proc square(x: float): float =
  result = x * x

echo apply(square, 4)  # Output: 16

let add = (x: float, y: float) => x + y
echo add(3, 5)  # Output: 8

Nim in the World of Pen Testing and Red Teaming

Nim’s performance, expressiveness, and versatility make it a great language for pen testing and red teaming. Let’s explore some specific use cases and code examples relevant to pen testers and red teamers.

Writing a Simple Port Scanner

A port scanner is a fundamental tool in a pen tester’s toolbox. With Nim’s powerful standard library, we can write a simple port scanner in just a few lines of code:

import os, net, asyncdispatch

proc scanPort(host: string, port: Port): Future[bool] {.async.} =
  try:
    let sock = await connect(host, port)
    sock.close()
    return true
  except CatchableError:
    return false

proc main() =
  let host = "scanme.nmap.org"
  let ports = @[21, 22, 23, 25, 80, 110, 443]

  for port in ports:
    let isOpen = waitFor(scanPort(host, port))
    if isOpen:
      echo "Port ", port, " is open"

main()

Crafting Custom HTTP Requests

Crafting custom HTTP requests is a common task in web application testing. Nim’s httpclient module makes this easy. Here’s an example of how to send a custom HTTP request with modified headers and inspect the response:

import httpclient

proc main() =
  let client = newHttpClient()
  client.headers = newHttpHeaders({ "User-Agent": "Nim-RedTeam" })

  let response = client.get("http://example.com")
  echo response.status
  echo response.headers
  echo response.body

  client.close()

main()

Developing Custom Command and Control (C2) Servers

Creating custom C2 servers is an important skill for red teamers. Nim’s asyncdispatch and net modules provide everything we need to develop a simple C2 server:

import os, strutils, asyncdispatch, asyncnet

const
  address = "0.0.0.0"
  port = 1337

proc handleClient(client: AsyncSocket) {.async.} =
  let remoteAddr = client.getAddr()
  echo "Client connected: ", remoteAddr

  try:
    while true:
      let data = await client.recvLine()
      if data.len == 0: break

      echo "Received: ", data
      let response = "ACK: " & data
      await client.send(response & "\c\L")

  except CatchableError as e:
    echo "Error: ", e.msg

  echo "Client disconnected: ", remoteAddr
  client.close()

proc main() =
  let server = newAsyncSocket()
  server.bindAddr(Port(port), address)
  server.listen()

  echo "C2 server listening on ", address, ":", port

  while true:
    let client = waitFor server.accept()
    asyncCheck handleClient(client)

main()

Pros and Cons of Nim for Pen Testers and Red Teamers

Nim has several advantages and disadvantages for pen testers and red teamers. Let’s explore some of the pros and cons of using Nim in the context of security testing and offensive operations.

Pros

  • Performance: Nim’s ability to generate efficient, native code makes it an excellent choice for high-performance applications, such as network scanners, fuzzers, and payload execution.
  • Expressiveness: Nim’s elegant syntax and powerful metaprogramming capabilities allow for concise, readable code that is easy to understand and maintain.
  • Cross-Platform: Nim can target multiple platforms, including Windows, Linux, macOS, and even JavaScript. This versatility makes it an attractive choice for developing cross-platform tools and payloads.
  • Extensive Standard Library: Nim’s standard library provides a wide range of functionality, from networking and file I/O to cryptography and regular expressions, making it easy to write powerful security tools.
  • Concurrency Support: Nim has first-class support for concurrency with asynchronous I/O and parallelism, enabling the development of fast and responsive tools and exploits.

Cons

  • Less Mature Ecosystem: Although Nim has a growing community and library ecosystem, it is not as mature or extensive as other popular languages like Python or C++. This may limit the availability of third-party libraries or tools that are directly related to pen testing or red teaming.
  • Less Community Knowledge: As a less popular language, there may be fewer resources and tutorials available for learning Nim in the context of pen testing and red teaming.
  • Less Stealthy: Nim’s relatively unique syntax may make it easier for defenders to identify and attribute malicious code written in Nim, as opposed to more common languages like C, C++, or Python.

When comparing Nim to other popular languages for pen testing and red teaming, it’s essential to consider the specific use cases and requirements of your projects. Here’s a brief comparison of Nim with some other popular languages:

Nim vs. Python

  • Python has a more mature ecosystem and a larger community, which can be beneficial for finding security-related libraries and tools.
  • Nim’s performance and concurrency support can be an advantage over Python in some situations, particularly for high-performance applications like network scanners or fuzzers.
  • Python is more widely recognized and stealthier than Nim, as Python code is more likely to blend in with legitimate software.

Nim vs. C/C++

  • Nim’s syntax is more concise and expressive than C/C++, making it easier to write and maintain code.
  • C/C++ has a more mature ecosystem for security-related libraries and tools, which can be advantageous for pen testers and red teamers.
  • Nim’s performance is generally comparable to C/C++ due to its ability to generate native code, but C/C++ may have an edge in specific low-level situations, such as writing shellcode or developing kernel exploits.

Nim vs. Go

  • Nim’s syntax is generally considered more elegant and expressive than Go, making it easier to write and maintain code.
  • Go has a more mature ecosystem for security-related libraries and tools, which can be advantageous for pen testers and red teamers.
  • Both Nim and Go have excellent performance and concurrency support, making them suitable for high-performance applications.

Conclusion

The Nim programming language offers a unique blend of performance, expressiveness, and versatility that can make it an attractive choice for pen testers and red teamers. While it may not have the same ecosystem maturity or community support as other more popular languages, Nim’s strengths can provide a valuable alternative in certain situations. Its powerful features, such as native code generation, first-class concurrency support, and cross-platform capabilities, make it well-suited for developing high-performance security tools and exploits.

In this article, we covered the basics of Nim’s syntax and core concepts, explored some specific use cases and code examples relevant to pen testing and red teaming, and discussed the pros and cons of using Nim in the context of security testing and offensive operations. We also compared Nim to other popular languages, highlighting the unique strengths and weaknesses of each.

By considering the specific requirements of your projects and evaluating the benefits and drawbacks of different programming languages, you can make an informed decision about whether Nim is the right choice for your pen testing or red teaming needs. Ultimately, the key is to be flexible and adaptable, continuously learning and experimenting with new languages and tools to stay ahead in the ever-evolving world of cybersecurity.