Security Research

Feeling even Locky-er

Feeling even Locky-er


The Locky administrator panel

During our research, using non-invasive methods, we were able to acquire the Locky index,php file along with some additional files, One of the other files we were able to capture for analysis was the administrative panel code, admin.php.

In researching the administrator panel code we found the system is designed to work using an affiliate mechanism. The fees are deducted from the affiliates’ gathered Bitcoins.  This fee can be set in the database on a per user basis.

Of particular note, this means the actor(s) can sell this capability as a service, with the code developers deriving a percentage of each transaction. They may already have been doing so.

Program initiation

Admin.php appears to be the web page for a web server using the PHP protocol.  The header for the program mirrors index.php. The script first requires files located in a directory contained in a PHP constant “__DIR__”.  This code first instantiates the PHP session framework.  The PHP manual explains session support as a way to preserve certain data across subsequent accesses, enabling users to build more customized applications and increase website appeal It then makes a call to open the database in the same way the outward facing index.php does.

Next, the code attempts to load the user's information from the database based on the variable $uid in the session.

        $userinfo = db_query_single('SELECT * FROM users WHERE id=?', $_SESSION['uid']);

       if (!$userinfo || !$userinfo['enabled']) goto not_logged_in;

       $is_admin = $userinfo['name'] == 'admin';

If $userinfo is empty, or the userinfo attribute “enabled” is not set, the program jumps out to a label  - not_logged_in.  While an interesting programming construct, it is not completely unheard of. The more interesting find is the next line, which specifically checks the username against a hardcoded value. If there is a match it will set a special flag - $is_admin, with the exception that it does not write out the HTTP header.

What do you want to do today

The bulk of the program logic resides in a loop predicated upon a variable named $type, which is passed via the POST method.  Valid types are:

  • login
  • logout
  • withdraw
  • builder
  • build
  • stats
  • bots

While the options appear slim, the ramifications of those options tell us a great deal about the program’s development and how it may be being used in the criminal underground.


The login code in this section is a variation of the (previously discussed) initialization code based upon variables passed via the POST method.

if (empty($_POST['login']) || empty($_POST['password'])) exit;

if (empty($_POST['action']) || $_POST['action'] != 'login') exit;

$userinfo = db_query_single('SELECT id,pass,enabled FROM users WHERE name=?', $_POST['login']);

if (!$userinfo || !$userinfo['enabled']) exit;

if (!password_verify($_POST['password'], $userinfo['pass'])) exit;

$_SESSION['uid'] = $userinfo['id'];            

header("Location: $self?type=stats");

Perhaps the most interesting aspect to this code is the fact that if the user is not “enabled” they cannot login. This supports our theory this is an affiliated-based model where the administrator can enable and disable accounts.


The stats action is the most telling. This software is designed to show a user his/her information based upon a variable - $affid (probably short for affiliate id) or, if your account has the special flag “$is_admin” set, you can see all the information in the database, grouped by $affid.

The stats program allows us to see into the database by first defining a SQL string for reuse, called columns.

$columns = 'count(id) as Total, count(NULLIF(completed,0)) as Completed, count(visited) as Visited,count(NULLIF(btc_payed,0)) as Paid,sum(btc_payed) as `Amount BTC`'; 

Based on this snippet we conclude the database has columns named:

  • id
  • completed
  • visited
  • btc_payed

These columns appear to be associated with “clients” (as defined by code), or what we term “victims”.

Next, the stats program sets up the retrieval of the information for display using the code below:

if ($is_admin)


$total = db_query("SELECT affid as User, $columns FROM clients GROUP BY affid");


foreach ($total as &$row) {

       $user = db_query_single('SELECT name FROM users WHERE id=?', $row['User']);

       $row['User'] = $user ? $user['name'] : '??? ['.$row['User'].']';

       $row['Amount BTC'] = format_btc(strval($row['Amount BTC']));


} else {

       $total = db_query("SELECT $columns FROM clients WHERE affid=?", $_SESSION['uid']);

       foreach ($total as &$row) $row['Amount BTC'] = format_btc(strval($row['Amount BTC']));


This demonstrates all information is retrieved from the database and grouped or sorted by the database column “affid” if the $is_admin flag is set.  Otherwise, only the information for the specific “affid” is retrieved.  While we do not know how affiliates are being recruited, or how many affiliates are active, it is clear the system was designed with an affiliate/”malware as a service” model in mind.

Looking at the is_admin code is shows there are at least two tables;

  • clients
  • users

In examining the the code we see that the administrator’s view has the total number of “clients” for each “user”, along with the total amount of Bitcoins the “user” has in their cumulative “client” wallets.

If the logged in user does not have the $is_admin flag set, the following code is executed:;

$total = db_query("SELECT $columns FROM clients WHERE affid=?", $_SESSION['uid']);

foreach ($total as &$row) $row['Amount BTC'] = format_btc(strval($row['Amount BTC']));

In contrast, this code only shows the “user” or “affiliate” the total Bitcoin amount generated.

Once the data is loaded into the appropriate variables it displays the data to the user.

A third table of data, - wallet performance – is revealed if the user has the administrator flag set .  Based on the code, the administrator’s screen would look similar to Figure 1.







Figure 1 Administrator’s screen tracking wallet performance

It is assumed that the print_table() function is used to optimize the wrapping of links around various forms of data thus allowing the users to perform certain actions.

The most important finding fromour analysis is the deliberate fee-based design with the capability to set each “user” fee. This becomes important with the withdraw function.

Builder and Build

Figure 2 reveals the builder page as a simple form allowing a user to paste one or more “Server IP's” which are submitted back to the web program during a “build”. It is assumed from this design that the user will submit a list of IP addresses into the box and press the “Get Bot EXE” button.  Pressing this button recalls the page with the action changed to “build”, triggering the action type “build” code.









Figure 2 Builder page

The code for the action build first explodes the submitted iplist, then generates a temporary directory using “bot” as part of the name.  Once the directory is created, the function make_bot_exe() is called with the name of the directory, the user, and an array of server IP addresses.

In order to see what is happening it is necessary to correlate this to the activity of the bot itself.  Given there is only one filename created, it appears this function is designed to allow a user to configure a bot to use multiple C2 servers. The output is a single file deposited in the directory BOT_EXES_PATH with a filename of “Locky_MD5substring.exe” where MD5subtring represents the first 8 Bytes of the MD5 hash of the file.

If the file is created successfully the program executes an HTTP “Location:” directive and points the user's browser at BOT_EXES_URL/Locky_MD5substring.exe.  This would download the executable directly to the user’s computer to be saved.


The console interface is designed to allow the affiliate to withdraw Bitcoins their bots have generated.

This section of code starts by establishing a $limit.  This limit is not allowed to be less than 10 nor greater than 50,000. There is also an $offset variable used to determine where in a multipage list the user is, to facilitate proper display and navigation. The program establishes a default sort order and sets the mode to “all” and the filter to “1”.

Next, the program setup a SQL query as has been done before;

$columns = 'id, registered as Registered, visited as Visited, ip, affid as User, completed as IsCompleted, lang as Lang, is_server as IsServer, corporate as IsInDomain, os_ver as Os, is_x64 as IsX64, btc_address as Address, btc_needed as `Needed BTC`, btc_payed as `Paid BTC`';

This provides more information about the client’s table.  .

  • registered (first visit)?
  • visited (last visit)?
  • ip
  • affid
  • completed ?
  • language
  • is_server
  • corporate (is the machine part of an AD)?
  • os_ver
  • is_x64
  • btc_address
  • btc_needed
  • btc_payed

Most of the data is self-explanatory. Once again, correlation of this data with the client software enables us to understand what is stored in registered, visited and completed.

Again, the console is set up to retrieve all records sorted by the $order variable, set initially to sort by “registered and id”. If the administrator bit is set, all records are retrieved, otherwise only the records for the logged in user (affiliate) are displayed.

The data is then displayed to the user with embedded links to enabling the user to check the wallet of the specific bot.

Withdraw (Show Me the Money)

The console allows both, users and the administrator, to view and effect Bitcoin withdrawals from the wallets associated with each client/victim. The code provides a list of the columns to be retrieved.

$columns = 'date as Date, user as User, address as Address, amount as `Amount BTC`, sent as `Sent BTC`, txfee as `TxFee BTC`, txid as TxId';

These fields appear in a new table named btc_withdraw:

  • date
  • user
  • addresses
  • amount
  • sent
  • TxFee
  • TxId

The administrator sees all transactions, while the user can only access their transactions.  The result would be a screen similar to Figure 3. The data includes an embedded link to to allow the user to check the wallet of the specific bot and the Transaction information by TxID.






Figure 3 Bitcoin withdraw table 


While our research is ongoing, we are aware of the urgent need to share our findings as we go. The information provided here may be used by investigators to piece together the client and server side activities.  We will continue to post additional findings as they become available. Continue to watch this space.

Both, index.php and admin.php, are provided here in text format to further aid researchers.

If you are a victim of this malware and are in the United States we remind you that extortion is a crime.  Contact your local FBI office for guidance.

Appendix A – admin.php

The admin.php file captured from the server is attached to this blog.


  • HPE Security Research
0 Kudos
About the Author