Getting Started with Recon-ng

When preparing for a penetration test, there is quite possibly nothing more important than reconnaissance. There are a variety of tools in the security space that aid in the process of both active and passive recon, but there is one that stands out to me as a leader: recon-ng. Built by none other than the legendary Tim Tomes, @lanmaster53, recon-ng is an open-source product built from the ground up to be a powerful recon tool. It’s interface will be very familiar to you if you have used Metasploit before. Recon-ng’s open marketplace will allow you to find nearly any module to fit your needs. And if you can’t find a module, you can always roll your own.

Watch the Video on YouTube

If you would rather follow along with a video, you can catch a video of this post on my YouTube channel.

Installing Recon-ng On Ubuntu

You can install recon-ng using apt on Debian-based systems, however I don’t recommend it, as it is stale. Instead, I recommend pulling from source and then hosting in a docker container. In this manner, you will stay up to date and isolate your system from the various Python dependencies without having to use virtualenv.

This post will not go over the details for installing and configuring Docker. If you need assistance, see the Docker installation and post-installation documentation.

I recommend installing in the /opt directory.

$ mkdir ~/.recon-ng
$ cd /opt
$ sudo git clone
$ cd recon-ng
$ docker build --rm -t recon-ng .

Now, add a few aliases to the bottom of your .bashrc file to allow convenient launching of recon-ng and recon-web:

If Bash isn’t your shell of preference, update your respective shell’s resource file accordingly. For example, if you are using Z Shell, update the .zshrc file.

alias recon-ng='docker run --rm -it -p 5000:5000 -v /opt/recon-ng:/recon-ng -v ~/.recon-ng:/root/.recon-ng --entrypoint "./recon-ng" recon-ng'
alias recon-web='docker run --rm -it -p 5000:5000 -v /opt/recon-ng:/recon-ng -v ~/.recon-ng:/root/.recon-ng --entrypoint "./reon-web" recon-ng --host'

Close and reopen the terminal. You can now launch recon-ng by simply typing the following:

$ recon-ng

We’ll be dealing with recon-web at a later time.

Recon-ng Workspaces

Recon-ng launches you into the default workspace when you first open the application. A workspace is essentially a project containing all of the domains, hosts, ports, vulnerabilities, and the like that you have discovered during your recon. Stuffing all of your work into the default workspace is not recommended, so I highly recommend you get into the habit of loading or creating a specific workspace as soon as you load recon-ng.

Let’s create a new workspace by typing:

[recon-ng][default] > workspaces create test-workspace
[recon-ng][test-workspace] >

Notice that the prompt changed, indicating that we moved from the default workspace to the test-workspace workspace.

We can list out the workspaces by typing:

[recon-ng][test-workspace] > workspaces list

 | Workspaces     | Modified            |
 | default        | 2021-02-24 23:13:28 |
 | test-workspace | 2021-02-25 01:20:18 |

As you can see, this command displays both the default and test-workspace workspaces. We can switch back to the default workspace by typing:

[recon-ng][test-workspace] > workspaces load default
[recon-ng][default] >

And, once again, the prompt changes indicating that we are back in the default workspace.

Recon-ng stores all of the workspaces on the file system, under the .recon-ng folder that we created during the setup process. If we type the following:

$ cd ~/.recon-ng/workspaces
$ ls
default  test-workspace

You’ll see that there is a directory for each workspace. If we navigate into the test-workspace and look at the files, we’ll see that there is a single SQLite file containing the data for the workspace:

$ cd test-workspace
$ ls
$ file data.db
data.db: SQLite 3.x database, user version 10, last written using SQLite version 3034001

Exiting out of our secondary terminal and returning to recon-ng, we can use the workspaces remove command in order to delete our test workspace:

[recon-ng][default] > workspaces remove test-workspace
[recon-ng][default] > workspaces list

| Workspaces | Modified            |
| default    | 2021-02-24 23:13:28 |

The workspaces list command indicates that the test-workspace workspace was successfully deleted.

Recon-ng Database Schema

Recon-ng data is incredibly easy to work with. If you recall from the previous section, each workspace contains its own SQLite database. The schema of this database can be viewed with the following command:

db schema

This query will return 13 different tables that can store everything from domains and hosts to contacts and credentials. We’ll dive into each of these over the next several posts, so don’t worry about the details at this point.

Each table will have a notes field for you to capture pertinent information and a module field that recon-ng will use to track the source of the information. Although not listed, each table also contains a rowid field – a numeric index that automatically increments with each new record.

Recon-ng grants you the ability to interact with each of these tables. We can, for instance, insert records, remove records, or even query records using SQL syntax.

Let’s setup a new test workspace so that we can add some example data.

workspaces create db-test

The Domains Table

The domains table is the simplest table in the recon-ng database. It contains four fields:

  • rowid: The unique identifier for this domain.
  • domain: The name of the domain.
  • notes: Any notes of interest for this domain.
  • module: Indicates the module of origin, or user_defined if you supplied it yourself.

The domains table is useful for defining the scope of your penetration test.

Inserting a Domain

Let’s add a domain to our table. To insert, we use the db insert command, which has the following syntax:

db insert <table> [<values>]

The values parameter is a tilde (‘~’) delimited list of strings, one value for each column in the table. The order of the columns is the same as the order returned by the db schema command. The only difference is that you do not supply either the rowid or the module.

The domains table has four fields, but we don’t specify either rowid or module. So, we’ll specify the domain and notes separated by a tilde character. Let’s add as the domain and ‘This is a test’ for a note.

[recon-ng][db-test] > db insert domains is a test
[*] 1 rows affected.

Executing this command indicated that we added a single row to the domains table.

Querying the Domains

Let’s now query the table to see the newly added record. We can use the db query command to do this. It has the following syntax:

db query <sql>

We can execute any arbitrary SQL command using this method. You’ll need to be familiar with T-SQL syntax (especially concerning SQLite) in order to write effective queries. For our simple example, we’ll simply query all columns for the domains table:

[recon-ng][db-test] > db query SELECT * FROM domains;

| domain      | notes          | module       |
| | This is a test | user_defined |

[*] 1 rows returned

Note that the rowid wasn’t returned in the above query. That may prove a bit problematic as it is needed to accomplish a number of tasks. To reconcile this, we can include the rowid in the list of columns when we perform the query:

[recon-ng][db-test] > db query SELECT rowid, * FROM domains;

| rowid | domain      | notes          | module       |
| 1     | | This is a test | user_defined |

[*] 1 rows returned

Updating the Notes

If we want to create or modify a note after we have created a record, recon-ng makes this simple with the db notes command. The syntax is as follows:

db notes <table> [<rowid(s)> <note>]

It is situations like this that having the rowids of the records of interest proves invaluable. You can attach a note to a range of records, by specifying a range of rowids (e.g., 1-20), or you can specify a single row id.

Let’s change the note to read ‘This is only a test’

[recon-ng][db-test] > db notes domains 1 This is only a test
[*] 1 rows affected.

Running the query again shows that the notes were updated:

[recon-ng][db-test] > db query SELECT rowid, * FROM domains;

| rowid | domain      | notes               | module       |
| 1     | | This is only a test | user_defined |

[*] 1 rows returned

Deleting the Domain

Finally, we can use the db command to delete a single domain or a range of domains based upon rowid. The syntax for deleting records is:

db delete <table> [<rowid(s)>]

As in the previous command, this can be a range of rowids (e.g., 1-20), or a single rowid.

To delete our domain, we merely have to type:

[recon-ng][db-test] > db delete domains 1
[*] 1 rows affected.

And when we query the list of domains, we can confirm that the domain was deleted:

[recon-ng][db-test] > db query SELECT rowid, * FROM domains;
[*] No data returned.


In this post, we dove into the process of installing and running recon-ng on an Ubuntu system. I also introduced the concepts of workspaces and various database commands. In the next post, we’ll dive into the marketplace, where we can find and use modules that perform a variety of active and passive recon tasks.

Additional Resources for Recon-ng

  1. The Recon-ng Framework, GitHub.
  2. Technical Information Gathering with Recon-ng, Pluralsight.


Photo by Sergiu Nista on Unsplash

Leave a Reply