Reversing string by separator in bash

In the recon phase of a bughunt it’s not uncommon to get a ton of subdomains all varying in their levels of depth. We might get foo.bar.com as a result, but we might also get server1.res.lv3.dna.nl.foo.bar.com as a result. What you might know, is that DNS is resolved backwards. So when you’re surfing to coolsite.google.com, the DNS conversation goes a bit like this:

1
2
3
4
5
Hey .com, do you know where com.google is?
Sure, here have the address!
Hey com.google, do you know where com.google.coolsite is?
Sure, here is the address!
The address is <insert ip>

As you can see, we start with the tail and work our way up. And incidentally it’s also a lot easier to write recon tools that work with DNS if you reverse the DNS name first.

Normal reversing of a string is easily done with the rev command in linux, but this reverses the entire string. So rev hello.world would return dlrow.olleh. But we want to divide up the DNS name by the dots, and reverse the separate parts. Something which, in javascript, would be as simple as:

1
"bar.foo.com".split(".").reverse().join(".")

Bash is a different beast though. Not quite that easy, but still manageable. We can use bash to pipe some commands together to achieve the same result.

The functions

Here are the functions. Paste them in your .bashrc or what-have-you (I load every fun part of bash separately, as you can see in my dotfiles). If you don’t want to have the reverse_by_separator function, just fill in . wherever you see “${2}” and you’ll have a function which only reverses a string by the dot.

1
2
3
4
5
6
7
reversedns () {
reverse_by_separator "${1}" "."
}

reverse_by_separator () {
tr "${2}" $'\n' <<< "${1}" | tac | paste -s -d "${2}"
}

Here are the chunks of the command, explained to the best of my ability:

1
tr '.' '$\n' <<< "foo.bar.com"

Feed “foo.bar.com” to the tr command via a heredoc line to prevent unnecesary subprocesses. Then use tr to translate the “.” into a newline ‘$\n’. Resulting in:

1
2
3
foo
bar
com

We then feed it to tac which reverses files line-by-line:

1
2
3
com
bar
foo

And this result we feed into paste, which – you guessed it – pastes the lines together one-at-a-time because of the -s flag, and because we use the ‘.’ as delimiter, we end up with:

1
com.bar.foo

Bash working it’s magic. Or well, no. Linux system design and tools working their magic, and the shell bringing it all together. But you catch my drift!

Just wanted to share this, as creating these small bash onelines brings me joy.