Threat Research

SpyEye’s Auto Transfer System (ATS)

By Kyle Yang | November 18, 2010

In our previous blog post SpyEye Exposes Mules, we discussed SpyEye’s mule-related policies/strategies, based on the fraudulent fund transfer logs and then drops data on the log server. In this post, we will have a look at the gears under the bonnet.

The system in charge of initiating the money transfers from victims’ accounts to mules’ accounts is an essential component of the SpyEye Trojan. It is called by its author “ATS”, for “Auto Transfer System”, and essentially consists in Javascript code. In the bot version we dissected (1.2.92, according to the metadata hardcoded in the binary), it can be found in a text file called webinjects.txt (after decryption&decompression). The latter includes what the authors deem “anti report” features, which taints the apparent account balance and transfer summary table in order to hide the fraudulent transfer to the eyes of the victim - thereby effectively delaying the fraud report.

The ATS has a specific routine for each specific bank it is targeting - which is logical: each bank has a different web interface for online banking. But roughly, the work flow looks like the following:

1. Security questions injection

Upon the victim logging in the online banking interface, one of the injected script asks the user additional questions, such as “Full Security Number”, and “Date of Birth”. Since the injection is done on the fly from within the victim’s browser, it seems to the victim that such questions are actually pushed by the bank’s site, and thus are perfectly legitimate. Likely, the answers to these questions are used by the bank to confirm the transfers initiated online, as a “second factor of authentication”. If the victim inputs her “Full Security Number”, the ATS is launched.

Bank Injection

2. Computing the maximum transferable amount

Upon launching, the ATS parses the webpage for the key sentence “This table shows the current balance of all your accounts”, in order to gather the list of accounts it can potentially initiate transfers from. In addition, it checks whether the user has a mortgage account. If it is the case, and if its transferable amount is bigger than 5000, the ATS sets the mortgage transferable amount to 4900, and adds it with other the balance of the other accounts (visa, master,cash, saving) to calculate the total account balance (max transferable amount). At last, it sets the mortgage transferable flag to 1 to indicate there is a mortgage account that’s available for plunder.

3. Requesting a suitable mule

Immediately after, the maximum transferable amount is reported to the ATS Web Admin Panel on the log server, via an HTTP query:

http://[ATS Admin Panel address]?action=get&max_sum=[max transferable amount]&pkey=[access key]&ssid=[Number(current date)]

The server responds with the data record of whom it thinks may be a suitable mule to transfer the stolen money to, under the form:

Status|Drop Name|Transfer Memo|Drop Account Number|Drop Sort Code|Min Limit|Max Limit|Percent

Examples of such records appear in screenshots of the ATS Web Admin Panel in our previous post.

Note:If the ‘max transferable amount’ is lower than all “min limit” of the records on the server, the server response will be [EMPTY]. And, the bot will send a report to the server with the message “Drop table is empty, or no suitable drop”.

4. Computing the effective amount to transfer

Based on the maximum transferable amount (computed in 2.) and the mule’s Min Limit, Max Limit, and Percent (received above), the ATS determines a the actual amount to transfer. Basically, this amount will be [max transferable amount][Percent], unless the max transferable amount exceeds the mule’s Max limit - in which case it will be [Max Limit][Percent].

For our technical-oriented readers, the whole algorithm is given below, with our added comments (the original script is in blue):

//step 1: if (can_it) { //can_it is the mortgage existence flag var b = max_sum + it_max_sum // max_sum is the aggregate balance of all accounts besides mortgage //it_max_sum is the balance for mortgage // b is the max transferable amount } else { var b = max_sum } //step 2: if (b < min_limit) { // max transferable amount is lower than mule’s Min Limit bot => the following mesage is sent back to the server return_msg += "ChooseTransferAmount(): accounts balances is lower than Min. Limit|"; return false } else if (b >= min_limit && b < max_limit) { a = CalcPercent(b, percent) // if max transferable amount sits between Min Limit and Max Limit, a = [max transferable amount] * [Percent] } else if (b >= max_limit) { a = CalcPercent(max_limit, percent) // If max transferable amount >= Max Limit, a = [Max Limit] * [Percent] } //step 3: if (max_sum >= a) { transfered_amount = a; can_it = false; // other accounts balance is enough for fraud transfer. hence, can_it = false, and the transfer amount is a. return true } else { //not enough it_transfered_amount = a - max_sum; transfered_amount = a; // Here the script sets the other accounts’ transfer amount to a, while logically it should be set to max_sum. Likely a bug. can_it = true; return true }

As a last step in the transfer amount computation, the ATS seeks the “day limit”, by parsing the page for specific markers (dependant on each bank). This is the total amount that can be transferred online per day. If the transfer amount computed above is higher than the “day limit”, the transfer amount is reduced by 10%. This is an other oddity, as nothing guarantees that this will result in something below the day limit.

5. Doing the transfer

At this point, the payment form is filled and submitted by the ATS. We do not have evidence of that yet, but the security questions that could arise at this point may be answered thanks to the data the victim provided in 1. above.

6. Reporting to the log server

As can be seen on the screenshots in our previous post, the transaction details are then reported to the log server. This includes (drop stands for mule):

transfer account name transfer account number balance brief bankingID date of birth return message drop name drop sort code drop account number transfer amount transfer memo

As a conclusion, it can be noted that unlike what we conjectured in our previous post, the percentage in the mules records is not what is left to (or taken from) the mule by the botmaster after the final wire-money transfer. Its utility is however not very clear: it is mule-specific, not victim-specific, so its function cannot be to keep the transaction under the radar on the victim’s side. And if its function were to keep the transaction under the radar on the mule’s side, why not directly reflecting this in the mule’s Max Limit? The key we miss to solve this might be the way “Max Limits” are assigned to mules: is it arbitrary, or does it come from a computation (or raw data)? We’re open to suggestions!

-- Guillaume / Kyle

Join the Discussion