This website uses cookies. By continuing to browse this website, you accept our use of cookies and our Cookie Policy. Close

Learn, connect, and collaborate at the Cyber Voices Zero Trust Summit. October 27th.

Thursday, Feb 25, 2016

Locky's New DGA - Seeding the New Domains [RUSSIA UPDATE: 26/FEB/16]

Share

Nicholas Griffin Security Researcher

As of February 24, 2016, the Locky malware has incorporated a new domain generation algorithm (DGA).

Forcepoint recently blogged about the original DGA, where the algorithm was provided in C along with future domains to be used. We also reverse engineered the new DGA here in Forcepoint security labs.  We have now decided to publish this new DGA, which is more robust and less deterministic. Because of the changes we have observed, we believe that is is highly likely that the Locky developers will not change this algorithm again for the foreseeable future.

Forcepoint are actively collaborating with trusted industry partners and government agencies on sharing information regarding Locky.

Seeded DGA

We have reverse engineered and re-implemented the new algorithm which can be seen below. The DGA now relies upon a hard-coded seed in the malware's base configuration. This seed can be changed at any time by the author or operator. For the sample we analyzed on February 24 (SHA1 e8ea52e0d43f9420a65993a4123fc15d64bc880e) this seed had the value of 7. However, for the sample we analyzed on February 25 (SHA1 2ddd654437a48974f241f81a9d645a7374b82bec) this seed had the value of 9.

The Locky developers and/or operators can change this seed every day if they wish, and of course can register the domains in advance. The authors knew that their original DGA had a limited time-span when the seed was deterministic, as vendors could preemptively block and sinkhole future domains. The new seed in the configuration creates a bigger challenge for those responsible for protecting against this type of malicous code. It is not possible to know which 32-bit seed will be used on which day.

Here is the new Locky DGA represented in C:

// pos should be between 0 and 7, cfgseed is the DGA seed which we have seen as both 7 and 9 to date
char *LockyDGA(int pos, int cfgseed, SYSTEMTIME SystemTime)
{
	char *domain;
	int modConst1 = 0xB11924E1;
	int modConst2 = 0x27100001;
	int modConst3 = 0x2709A354;
	int modYear, modMonth, modDay;
	int modBase = 0, i = 0, genLength = 0;
	unsigned int x = 0, y = 0, z = 0;
	unsigned int modFinal = 0;
	unsigned int seed = cfgseed;
	char tldchars[29] = "rupweuinytpmusfrdeitbeuknltf";
  
	// Perform some funky shifts (now modified with the seed in the base config)
	modYear = __ROR4__(modConst1 * (SystemTime.wYear + 0x1BF5), 7);
	modYear = __ROR4__(modConst1 * (modYear + seed + modConst2), 7);
	modDay = __ROR4__(modConst1 * (modYear + ((unsigned int)SystemTime.wDay >> 1) + modConst2), 7);
	modMonth = __ROR4__(modConst1 * (modDay + SystemTime.wMonth + modConst3), 7);
 
	// Shift the seed
	seed = __ROL4__(seed, 17);
 
	// Finalize the modifier
	modBase = __ROL4__(pos & 7, 21);
	modFinal = __ROR4__(modConst1 * (modMonth + modBase + seed + modConst2), 7);
	modFinal += 0x27100001;
 
	// Length without TLD (SLD length)
	genLength = modFinal % 11 + 5;
  
	if (genLength)
	{
		// Allocate full length including TLD and null terminator
		domain = (char *)malloc(genLength + 4);
  
		// Generate domain string before TLD
		do
		{
			x = __ROL4__(modFinal, i);
			y = __ROR4__(modConst1 * x, 7);
			z = y + modConst2;
			modFinal = z;
			domain[i++] = z % 25 + 97; // Keep within lowercase a-z range
		}
		while (i < genLength);
 
		// Add a '.' before the TLD
		domain[i] = '.';
 
		// Generate the TLD from a hard-coded key-string of characters
		x = __ROR4__(modConst1 * modFinal, 7);
		y = (x + modConst2) % ( (sizeof(tldchars) - 1) / 2 );
 
		domain[i + 1] = tldchars[2 * y];
		domain[i + 2] = tldchars[2 * y + 1];
		domain[i + 3] = 0; // Null-terminate
	}
	return domain;
}

Locky Base Configuration

Locky's configuration includes options for the DGA seed, how long to delay execution for, and which affiliate is tied to the sample. The full base configuration can be understood by showing a C-style representation of the structure:

typedef struct lockycfg_t
{
  // Types are guessed, integers could be DWORDs (so this may not be 64-bit compatible)
  
  int           AffiliateID;          // An identifier for which operator is tied to this Locky variant (i.e. 3)
  unsigned int  DGASeed;              // The DGA seed (i.e. 7 or 9 etc.)
  int           DelaySeconds;         // How long (in seconds) to delay execution via Sleep() (i.e. 30)
  
  char          bFakeSvchost;         // Copy to %TEMP% and launch as svchost.exe? (0 or 1)
  char          bUsePersistenceKey;   // Install persistence registry key? (0 or 1)
  char          bIgnoreRussian;       // Exit & clean up system if Russian language/locale detected? (0 or 1)
  
  char          servers[128];         // Hard-coded command-and-control servers (IPs separated with a comma)
}lockycfg_s;

Russian System Exclusion

[UPDATE: 26/FEB/16] As of 25/FEB/16, Locky added one additional member to its configuration structure as seen above. The new member, defined as 'bIgnoreRussian' is an option which defines whether or not to execute the file encryption procedures on Russian Locale OR Language (ID 0x19) machines. The samples seen so far have this value set to 1. Locky will therefore delete itself and terminate execution if the machine is set to a Russian locale or language.

Future Domains

We have generated a list of the future domains for the rest of February and the whole of March based on a seed value of 7. Please note that a seed value of 9 has also been seen, which this list does not include.

24/25 Feb 2016:  
  
bkadufmdyf[.pm]
kpvoxwgf[.pm]
fysck[.fr]
hsasjielgfkneh[.ru]
qquvjijtvatj[.in]
edmgbqygn[.de]
nbavfpb[.uk]
wyusb[.yt]
  
26/27 Feb 2016:  
  
yuljfxdf[.pm]
bvtavc[.nl]
ktovxeteqtwtcsh[.yt]
xyfnvvbuovcd[.be]
hwsdymcytd[.yt]
cgwlamg[.pw]
ehfjt[.pm]
nfacehihugohhi[.nl]
  
28/29 Feb 2016:  
  
cproso[.pm]
lnjrmdjyidprrse[.de]
nortkbiqhtdgd[.de]
ixwllqpbog[.in]
rvkgvjbp[.it]
ficpn[.fr]
ogworigxknalsd[.eu]
qaekmjxgrtcs[.de]
  
1 March 2016:  
  
prydlvlxw[.be]
rsimigt[.us]
bqvcl[.in]
ovmspedrbkxlj[.ru]
xthppvomcxu[.be]
aupgcrvfm[.us]
uemtsb[.uk]
echmfrnyuwrlmas[.uk]
  
2/3 March 2016:  
  
jaliqnp[.yt]
ejpmaxavyptyqnc[.pw]
nhkpknfyjnoqp[.ru]
iqountnrqs[.ru]
krpphdlu[.yt]
tpkmyc[.ru]
hubvdqgfcoierc[.pw]
qsaifcyuopyv[.de]
  
4/5 March 2016:  
  
bxlrnw[.pw]
vhpurxfuohbqso[.fr]
ffkseaisuicb[.eu]
hgspblbnex[.yt]
cppvgch[.in]
lnkva[.pw]
ysbfaksqohpmf[.in]
iqvcaeogjeg[.it]
  
6/7 March 2016:  
  
spxst[.us]
nycbuwfisadao[.be]
wwpyvxnihcm[.fr]
yxxpmghmx[.uk]
thcfqk[.it]
dfwqdyjrtyiuaij[.pm]
qrokkqdsmtxa[.us]
apgodprqgy[.eu]
  
8/9 March 2016:  
  
djcbwpykgnsdikb[.pm]
fkkdmvsjnnptv[.yt]
athfaulmew[.pw]
cupggwpf[.pm]
lsotcg[.in]
gcsxwslqsvbhpr[.pw]
ivtlxgqfkiyj[.it]
dfxvcvxfa[.be]
  
10/11 March 2016:  
  
kfifrxqke[.in]
fogyrq[.uk]
ombqnwvepxjeufs[.tf]
qnjoimqcqkokt[.yt]
lpmxewicfk[.us]
uubnggrp[.in]
woiwpu[.fr]
rxmbadyblcuoat[.in]
  
12/13 March 2016:  
  
dlhhgett[.us]
mqvubo[.de]
haageiedrybojk[.tf]
jtlqoqfaykdj[.uk]
edpglqefm[.it]
nbdwqkj[.fr]
pcmfx[.de]
klqqvsewphwko[.it]
  
14/15 March 2016:  
  
vqmkfujpobvu[.us]
xkxapdrojh[.nl]
stckmju[.yt]
uulhq[.fr]
esyjyjiklwnbhd[.tf]
ycdntrbxkuw[.de]
bdlpmukcp[.eu]
vmpthc[.it]
  
16/17 March 2016:  
  
ddutcdmfvmbaaba[.be]
mbikamdjklmce[.de]
hkmaebphml[.yt]
jetxtfwv[.pw]
enxme[.us]
nllwyhyrvsdodo[.fr]
pmttrjeukjnl[.yt]
kvxcsnink[.yt]
  
18/19 March 2016:  
  
vopbboe[.tf]
fmktk[.pw]
avppvitupmdtm[.tf]
cwxghlngfxo[.nl]
wguofdum[.it]
yhdrnk[.ru]
ifxjoqrmcmajhjf[.ru]
docniprmgcxm[.be]
  
20/21 March 2016:  
  
adrefp[.ru]
jinpjwfrsjpmjgu[.us]
ekqmsioexowp[.uk]
glrbxuhejj[.de]
buvpbsq[.pw]
dvehl[.pw]
mtygfrrwfppuvv[.us]
hdvmubmbyxs[.nl]
  
22/23 March 2016:  
  
radqq[.tf]
bfyilphwkctxdf[.us]
vhcrhadppxa[.it]
xidmofnsc[.ru]
srlkgw[.pw]
ustmanuqnxxhlmj[.pm]
eqplamxxqghrd[.tf]
yamyqrhatl[.de]
  
24/25 March 2016:  
  
jxeepaassngeetq[.in]
sdsyswxogrhjf[.tf]
nfvdvistdi[.nl]
pgeeucpt[.uk]
yercwd[.nl]
mqjlvimienyxwr[.fr]
voebnwfybwkg[.pw]
qximfakki[.fr]
  
26/27 March 2016:  
  
xjneysaum[.us]
hhbrghm[.eu]
jijps[.in]
ernthxdqkbuoi[.tf]
npixhjhhmpm[.uk]
burfvaac[.pm]
ksmbxx[.in]
mtuamviphwoapcq[.uk]
  
28/29 March 2016:  
  
jjrlgvdlqurpa[.pm]
shmcsgbpypg[.fr]
uivmeislw[.eu]
prsobv[.pm]
ypnlcncyegxteub[.in]
bqvjrrodkfhjg[.it]
vaaytyxqyl[.eu]
fxnitwaq[.fr]
  
30/31 March 2016:  
  
pvmyilqakqqkl[.in]
kfqoruddyo[.nl]
myxmilto[.it]
hicqd[.us]
qnqlfdthdyidbw[.be]
shxppmfnhjao[.pm]
nqcxfhycl[.in]
wowkllj[.it]

Summary

The Locky author has shown an understanding of the problem with their initial DGA and has modified their DGA algorithm to be more secure. The Locky developers and/or operators now have the ability to change the seed every day and generate a completely different set of domains. The impact of which is that preemptive protection is made more challenging. The seed value cannot be known until a physical sample is seen, at which point it may be too late to block the traffic solely based on the domains  This is an illustration, if one were needed, that it is important not to rely solely on blocking the DGA domains.  Especially because they may not even be used if the malware is able to contact its hard-coded command-and-control servers.

Forcepoint will continue to monitor Locky closely.  We will also continue to collaborate and share information with our trusted industry partners and government agencies.

Contributors: Nick Griffin, Andy Settle

Tags Ransomware

About the Author

NG

Nicholas Griffin

Security Researcher