Tuesday, March 15, 2011

Episode #138: Flux This!

A Vaguely Familiar-Looking Stranger Begins:
As the scene opens, an unkempt man in tattered, dusty clothes walks forward. His wild eyes shift to and fro, barely concealed by his matted hair (what’s left of it) as he surveys the audience. He begins to speak and his creaky voice bears an uncanny resemblance to that of a long-lost friend…

Greetings, fellow Shell-Fu aficionados! Ed Skoudis here, a blast from the past, briefly back from my hiatus for this episode. I remember when we first started this blog way back, oh, about two years ago. We were so young then… na├»ve… but full of pluck and verve. Starry-eyed Paul Asadoorian had his hopes tied to building a successful commercial ferret farm, harnessing the little creatures on hamster wheels as a form of cheap electricity. Hal secretly yearned to participate in that Village People revival band that never really took off. And, Tim was but a twinkle in his father’s eyes, shortly followed by a firm slap in the face from his momma. My how long it’s been and how far we’ve come.

But, I digress. I’m here today because I was teaching my SANS Security 504 class last week, and I got a great question from a brilliant attendee. We were covering bot-net fast-flux techniques, naturally, in which a bad guy sends a phishing-style e-mail to many users, exhorting them to click on a link. Normally, the link would point directly to a web server where the bad guy had planted a fake bank, imposter e-commerce site, or other nefarious server waiting to dupe users into providing their login credentials. With the fast flux technique, however, the link in the e-mail doesn’t point directly to the fake bank. You see, sending such a link that points directly to the attacker’s website will help the good guys find where the evil site is, and get it taken down quickly. In the bad guy business, keeping your evil infrastructure resilient to take-down notices is helpful in making moolah.

To that end, attackers use the fast-flux technique. Instead of the link including a name that resolves directly to the IP address of the evil server, the link has a name that resolves via DNS to an intermediate HTTP relay, which is just a bot-infected machine that sits between the victim user and the attacker’s server. To stay one step ahead of the good guys, the attacker fluxes the DNS record so that after a short time-to-live expires (often 1 to 3 minutes), the name in the link from the phishing e-mail now resolves to a different IP address, another bot-infected machine acting as a relay. The attacker fluxes the A records in the DNS server so that the name points to a different address every minute or so, making the investigator’s job more difficult as the server appears to be jumping around from place to place, preserving the bad guy’s real server longer.

The question that popped up in class was this: Is there a free tool that simply queries DNS looking for the record for a given name every 30 seconds or so, and then displays any changes it sees over time? In class, I responded that I could create something that does that, Name-That-Tune-Style, in but a single Windows command -- a hideously ugly command, but still just in one command. Over some not-very-good hotel halibut for dinner that night, I put together the command and showed it in class the next day.

I mentioned this to Hal and Tim, and, desperate as they are for any idea whatsoever for an episode, they agreed that we should make it an episode. In our e-mail exchange, Tim asked if I’d send the command I had prepared. I told him that I’d do it as the single favor I owed him. He responded:

“That was my one favor, and I just wasted it. Dang! So much for the piggy-back ride I wanted during the week of SANS FIRE. I even had tiny matching cowboy hats.”

Tim, for a tiny cowboy hat, I’ll gladly grant you another favor. Fear not!

So, without further adieu, here is my command:

C:\> cmd.exe /v:on /c "set stuff=& for /L %i in (1,0,2) do @for /F "skip=1 
delims=" %j in ('"nslookup betty.target.tgt name.server.tgt 2>nul ^| find "Address""')
do @(set new=%j& (if NOT !stuff!==!new! (echo !date! !time! !new! & set
stuff=!new!)) & ping -n 6>nul)"

The command looks up the given name every 5 seconds (change the "6" to "31" to make it go every 30 seconds), and if the IP address changes, it prints out a date/time stamp and the new IP address or addresses associated with the name. You simply provide the name that interests you in place of “betty.target.tgt” and your name server in place of name.server.tgt. I structured the command so that it will work whether it gets a single IP address back or multiple addresses in a round-robin setup. Here is its output if there is a single name included in the answer for betty.target.tgt that is fluxing:

Fri 03/11/2011 13:11:50.95 Address:
Fri 03/11/2011 13:12:06.35 Address:
Fri 03/11/2011 13:12:47.43 Address:
Fri 03/11/2011 13:13:02.85 Address:

And, here is its output for a round-robin DNS flux (which I modeled by simply putting in www.google.com for the name we’re interested in):

Fri 03/11/2011 13:14:41.56 Addresses:,,,
Fri 03/11/2011 13:14:46.74 Addresses:,,,
Fri 03/11/2011 13:14:51.91 Addresses:,,,
Fri 03/11/2011 13:15:02.23 Addresses:,,,

Note that in the round-robin results, my command notices that a change occurred, but it cannot tell whether it was merely a change of order, or a change of addresses. Still, for fast-flux botnet that uses round-robin DNS, it is almost always a change of addresses, so my command works well for its intended use.

Now, diligent readers of this blog (both of you) will instantly be familiar with the mechanics of this command. But for those that aren’t, here’s a brief synopsis of what I’ve wrought:
  • cmd.exe /v:on /c: Turn on delayed variable expansion, so my variables can float when I refer to them as !var!.
  • set stuff=&: Clears the stuff variable, so that it contains nothing. You’ve gotta put no space between the equals sign and the &, or else stuff will contain a space. Stuff will hold my current address from the lookup.
  • for /L %i in (1,0,2) do: An infinite loop that starts counting at 1 and counts in steps of zero all the way up to 2. This keeps us spinning, kind of like the tire rims Paul has on his “babe-mobile”.
  • @: Turn off echo of commands.
  • for /F “skip=1 delims=” %j in: Set up parsing of the output of nslookup | find. If my nslookup command succeeds, find will scrape through its output looking for lines that say “Address”. There will be two such lines: one that indicates the IP address of the name server, which I want to skip (skip=1) and one that indicates the address(es) of the names we searched for. The delims= says to turn off default parsing on spaces and tabs. I want whole lines, baby!
  • ‘”…”’: This single quote / double quote combo says to run the command inside.
  • nslookup betty.target.tgt name.server.tgt 2>nul: Look up the name, and throw error messages away.
  • | find “Address”: Look for output lines that have the word “Address” in them.
  • do @(): Take the output of the nslookup | find command and do stuff with it.
  • set new=%j&: Take our output of nslookup (%j) and assign its value to the variable named new. Again, we don’t want a trailing space included in this assignment, so we follow with an & immediately.
  • (if NOT !stuff!==!new!: If our previous lookup result does not match our most recent lookup, we’ve got a change!
  • (echo !date! !time! !new!: Because we have a change, let’s display the date, time, and our new result.
  • & set stuff=!new!)): We better store our new result in stuff, so we can see if it changes going forward.
  • & ping –n 6>nul)”: Introduce a 5-second delay by pinging ourselves 6 times, before we loop back.

Gee, that was fun! Maybe I won’t wait so long for a return visit next time. So, what have you got, Village Hal and Cowboy Tim?

Tim gets out his hats and prepares to saddle up:

I am so looking forward to making SANS FIRE now! Anyone know somebody who embroiders tiny hats?

Besides a shared loved of tiny hats, we also share a similar approach on this episode. The process is to get the output, store it, wait, get more results, compare, if the results are different then show output and update the stored results. Rinse and repeat. But, unlike the cmd.exe version, we'll handle DNS Round Robin by sorting the output addresses, like this:

PS C:\> nslookup -d www.google.com 2>$null | Select-String 'internet address' |
Select-Object -Expand Line | Sort-Object

internet address =
internet address =
internet address =
internet address =
internet address =

I decided to use nslookup with the -d option. The format of nslookup is different between Windows 7/2008 and that shown above (I assume Ed used XP). Specifically, Windows 7/2008 has line breaks between each address instead of commas. Using the -d option makes finding the addresses easier since we can filter for "internet address".

The Select-String cmdlet does our filtering, but it creates a bunch of objects containing a information regarding the match, such as line number and the match pattern. The -ExpandProperty switch used with Select-Object just outputs the Line information as a scalar (not a MatchInfo object).

PS C:\> while (1) { $new = nslookup -d  betty.target.tgt name.server.tgt 2>$null |
Select-String 'internet address' | Select-Object -Expand Line | Sort-Object;
if ( compare-object $new $old ) { Get-Date; $new; $old = $new }; sleep 10 }

Saturday, March 12, 2011 12:57:58 AM
internet address =
Saturday, March 12, 2011 12:58:08 AM
internet address =

We start off with an infinite while loop, since 1 is always true. Then we set $new equal to the output of our fancy nlsookup fu. The Compare-Object cmdlet is used to compare the valued between $old and $new. If they are the same, then there is no output (null). Since a null is treated as False by the If statement, nothing happens in our command. If the variables are different, there is output from Compare-Object and the if statement takes the True path.

On the path of Truth, the date and output from nslookup are displayed. Then the value from $new is copied into $old. The $old value is used on every loop to see if our values changed. Finally, the command will sleep for 10 seconds and start again. Not too bad right?

They say it takes a village, and sometimes we are that village. But I'm not sure what takes The Village People. Hal?

Hal returns from his visit to the Y-M-C-A

If there's one thing my time in the Village People tribute band has taught me, it's that there's no problem that can't be overcome if you're wearing tight leather and cut-off t-shirts. So let me strap on my coding chaps and get down with it.

There are a number of options for doing DNS lookups from the command-line in Unix, but let's just go with the host command because it's simpler:

$ host www.google.com
Using domain server:

www.google.com is an alias for www.l.google.com.
www.l.google.com has address
www.l.google.com has address
www.l.google.com has address
www.l.google.com has address
www.l.google.com has address
www.l.google.com has address

What I really care about are the lines that read "<host> has address <address>". Unlike my co-authors, however, I don't consider round-robin DNS to be alert-worthy. So what I'd like to do is sort my results into a canonical order, meaning that I'll only raise a flag if there's an actual change to one of the IP addresses.

Not a problem:

$ host www.google.com | awk '/ has address / { print $4 }' | sort | tr \\n ' '

At this point, it's just a matter of creating a loop like the Ed and Tim did. Only mine's much prettier, of course:

$ while :; do 
new=$(host www.google.com | awk '/ has address / { print $4 }' | sort | tr \\n ' ');
[ "$new" == "$old" ] || echo $(date) -- $new;
sleep 30;

Sat Mar 12 11:41:26 PST 2011 --

No need to bother with a full-on if statement inside the loop. I'm just using the short-circuit "||" operator after the equality test. As long as $new and $old are the same, the echo statement never gets executed. But when the IP addresses change, we'll spit out the date and the new values.

The rest of the loop is very much like Tim's (or even Ed's if you don't count the fact that we don't have to ping in order to sleep for a specified period of time). We assign the value of $new to the variable "old" and sleep for our chosen interval before starting the loop all over again.

So another easy one for Unix. Now if you all will excuse me, I need to go practice my dancing. After all, you can't stop the music!