Qakbot / Qbot
Qakbot config extraction
- Overview
- Expected C2 Config
- Helper Functions
- String Tables
- Decrypt RSA Public Key
- RC4 Decryption
- Config Extraction
- TODO
Expected C2 Config
The following are c2 IPs that we expect to be in the config based on our sandbox output.
32.221.229.7:443
140.82.49.12:443
24.152.219.253:995
182.56.99.126:443
76.169.147.192:32103
218.101.110.3:995
89.101.97.139:443
82.152.39.39:443
176.24.150.197:443
96.37.113.36:993
68.186.192.69:443
59.88.168.108:443
75.110.250.187:443
182.191.92.203:995
89.165.88.95:443
103.142.10.177:443
45.9.20.200:2211
24.95.61.62:443
194.36.28.26:443
78.101.82.198:2222
37.211.157.100:61202
70.163.1.219:443
31.215.99.73:443
103.143.8.71:6881
59.6.7.83:61200
63.153.187.104:443
14.96.79.22:61202
93.48.80.198:995
24.53.49.240:443
94.200.181.154:995
149.135.101.20:443
24.178.196.158:2222
209.210.95.228:32100
78.101.82.198:443
67.209.195.198:443
96.80.109.57:995
80.14.196.176:2222
38.70.253.226:2222
24.222.20.254:443
217.165.123.47:61200
74.15.2.252:2222
217.128.93.27:2222
102.65.38.67:443
190.73.3.148:2222
79.167.192.206:995
95.5.133.68:995
114.79.148.170:443
120.150.218.241:995
186.64.87.213:443
65.100.174.110:443
96.21.251.127:2222
136.232.34.70:443
63.143.92.99:995
136.143.11.232:443
39.49.27.10:995
111.125.245.116:995
41.228.22.180:443
217.164.247.241:2222
83.110.107.123:443
76.25.142.196:443
74.5.148.57:443
65.128.74.102:443
67.165.206.193:993
173.21.10.71:2222
71.74.12.34:443
94.60.254.81:443
23.233.146.92:443
73.151.236.31:443
79.160.207.214:443
213.120.26.24:443
89.137.52.44:443
75.188.35.168:443
109.12.111.14:443
106.51.48.170:50001
68.204.7.158:443
78.101.82.198:995
80.6.192.58:443
41.96.250.164:995
114.79.145.28:443
188.54.96.91:443
105.198.236.99:995
50.238.6.36:443
65.100.174.110:8443
70.51.134.181:2222
117.248.109.38:21
86.98.53.83:443
182.176.180.73:443
217.165.11.65:61200
103.143.8.71:995
50.237.134.22:995
187.189.86.168:443
100.1.119.41:443
2.178.67.97:61202
86.198.237.51:2222
88.253.171.236:995
73.171.4.177:443
40.134.247.125:995
72.252.201.34:995
190.39.205.165:443
187.172.146.123:443
92.167.4.71:2222
189.30.244.252:995
105.111.124.76:443
84.199.230.66:443
14.96.67.177:443
182.56.57.23:995
87.70.93.215:443
93.48.58.123:2222
73.5.119.219:443
75.169.58.229:32100
173.71.147.134:995
69.46.15.180:443
23.82.128.108:443
5.36.7.212:443
200.75.131.234:443
82.77.137.101:995
187.201.90.81:443
24.55.112.61:443
201.172.31.95:443
216.238.72.121:443
216.238.71.31:995
207.246.112.221:443
207.246.112.221:995
216.238.72.121:995
216.238.71.31:443
27.223.92.142:995
24.229.150.54:995
117.198.149.221:443
def unhex(hex_string):
import binascii
if type(hex_string) == str:
return binascii.unhexlify(hex_string.encode('utf-8'))
else:
return binascii.unhexlify(hex_string)
def tohex(data):
import binascii
if type(data) == str:
return binascii.hexlify(data.encode('utf-8'))
else:
return binascii.hexlify(data)
key = unhex('efb05bc91c9c83400d08dd5087959b8b72a7a75b36b8d290c42ddbc22d292414ed86a03f3672a15b8da8bae6c737a55506eb623c9735a5fb41f213f30e4816fc32d9c4ecf873b394b869545cc2f382562e46cad089290ba543bd0000a990b9399a24d735')
data = unhex('8cdf29ac4ff9f136646bb803eff0f7e75cc2df3e0de8b1f38a7996ad4307416c88bdee6b6426f238ecc69483bf52a51844aa2f6ff247d39222973d96762d2d9150b8a98b8d1a9df1c00c5479918af1224b2b98bfe65d2ef910c49ce7149e2aa8df257578b13ff5f0e9a517dfc25b7bcb9fe08143bcec48514114bec9e66b6133f31ed1e5d385b558d63a609f3e71fe56d794329d75872e0978885bb4a5808f12c1f1e42c2c3fae86f13f4128b98cd9487fcd30bdb8f2119655dbcd0f5f4ddd3df7e7b5ef1ecba71759dbb3fc8842acc24f4d457388e8d411530ac460fbdbc983b5418b307e8e594ae446c0893782639f202d6e9932b8b29cd616cbf18302352ab681e32f0023b2b5896a31f90af3bbf509875dd0df1f526db020f3ec9be81fc3893e4eddd2c38b6b8f956c7b6148bae9d70902419315e2ccdfba8a5ec62769980d5ae369f2922f967c847d68529954bcaa889d01efc7c8103a39b6f3de0a001abab9f94c57a53898df8203ec2caedb653d3a8575b7a7c3a6579795031388e0c8e908ebf0750c1426b5ab850f042a846bbff097c3f705fd7036d93a19a707fdde71c04bd63e7a4ed902eb9c91f804d1fe960e3b5cec90e4312e16abb3e2486cc030bd86c033a56cfdf329236cb13c87fcf6ea15c2882b5cc8b7f7c40888bb5e5d4179bfe9cf4b132ef222fefff5b1f103f91a688e264efe43c0a824866683202d6e99328ead82cb41ecc4d6391132b69af62f2e33b9b5fb1a398b27d183b07e9a65eff725605ab23ff3b0c7d80bd4d33e5b8be0cca95ea9a3034c5c71edd1f26c775cc423e8a8cc84b437c62665990b4ce31bc08324f276947b2138994abcff899301ddbadd11315c84b2ce056b46e4b4e5450bd120cd8bc536b932f9fb25367fb43ee3e0f6fb5cc2df3e0ddda6f8a15fbea34107416c88bdd7564417d233ecdad1c8a24fc06e639f1659e556c48b6f976b96353a628f5cb0a28ad616cbf18319353fa996f6354f36bea5fb4c25c03bd8d4d33ab968e9f125636da97ee2edfe8b11d5de2b428be0bea041b7c26c656841bec3f26c6620ee1dc4e4ffe6b45fc922679b0b12f359c9fb329767867e2966951cbda880f805d8fdcb0c7a39ba96b93f5d23b9a2ff076edd26868cdd3fa87bf9ed34236da53587a4a9b84692916c0e81e290a55bbca15e5b526cc3e3d85a0d13d73cfeded99ee952dd303d8a145bf446d78d20dc768b6b48798c57b7c498c556c0b4cc003939ffa8a7661c22f0f5b91b6f9f668dddd476ec2caee76f2838ef34a8b0ffd672f4d2395bd1a6c3a540abae485a677b83f5c5514272f632e3dbce87f737e627638a16599710f6823286769e5c277988178597958b24fcc38e5d0839ba83ee395c23b8feec516ea566eec1956bff789ca96f2708b033f4fdf2ee1ec3893e4eddd2f1b45db7ab4e48507d82e88f471b01c934eec3cd87b15288336a8a11549766eabd15a552a14b14419345eff0dfca3ddcf0dd351935a181ed254120bef0c8477fcc0edc83c73abb79c0d0307446b82487e2e8b92d94957552d4be90e17ea2b1594c494682e9d41a6a21d828dae7edd0f36bdd226f91034ef31bc08324f261966966738457f985a8bc5391dcf3251900e780a0760120eafffd092ed66392999079ec6fbea36f6928ff75f4b79bf81cdfcf3069dabde2a048a99d4050537a8986f35a4252ce39e7fff7af9452d7236f88071caa15e29e35bd71996b2b62d410aead829514dee0cb53767ce4d3a02d472bbab5fb5a64cb22c986df358579eae62c3061b020e2e7e8e41cc6d33e4b998eccea71fea1424650488eefcd4904508851decdcec6a855cf0574840159e44685c661b57687412a7c9951adecce8f1addf9df04202ff881ed395a1aa9b9e45f399f14d4818369964ceeec23687bae72ae9ffef900f5c22f43cabcb0f90db4a04779567b8ee3d34c1831d33eecdcdfcee512d6772acb0c49fb5989db2f877fdf2e2663901bd9b39c9b12c3badc05385cb196ee334d32ead0de40659671e2acdf36b969e8e6325e71ae24e2f89bd80bd4f014618ee690a240b4ac034c5c71edc7d65e4506f22dee86df9ea237ce3074850750a4078b9f2d9e13d65d31658857b49683970796c8eb102728a79eb164722ba5b2fa5065c66dd897d55ba779e8e230643bef7ee3f9f78b31c8c92f53d6a6bd9054aba7170945649deac95c5706c834e387c2cbb040d27860841051ba40d797249c709c6a2d72fc1789b6839f01d2f9fe003839b1dbfa6e186fef8cc0477fc031d38ac47b8c64ecef2f7f6daf0ceef0e3fb1ec8d53e18ddaaf5c44cbfb44c594d27dfa8c4535a72f214cbfceda79572f9186f881053e45ac38f1da57a9d6a27618f129da18a9d1dd7f1ca351124a19ff7254729a4a3d5796ad12bceefd36195409ca613747ba935eac7f4e40682fb3e4ec8beffb648a9ec485141148cf5d757591dca23a3ccd68ac712f62c759f0751c55aca8f64ae768b7e24798e57abea898016b3fccc1d242fc2a0ed305a31aba2ec7546cc20cf80c334af689ca6107f67ba22e6f8dde21ec2d47e6af1bce4a15fb5a75909616c9deacf4d5300fd32e8d0ca8aa845c07b6393073cc44cd68f249f20c10e2c61995cbead829d5dd6ecdd52302ba381e9324f23a7bfe7076edd26868bc72ca868ffeb257f26b828e295cce21c94950466d0abe3ad4ebaae604c497b9fffa04b4f02c466bdd09fd6f36fa57055921148f258f7942e8636af5d31658857b4f7dea40bc4fdc2082638ec96fa332e31bea3e859629671938bdc37c932f8e2340d69ae27effaf4e01389c3375ab89ef1b75999ad425d7164b9efcd5a3621e417c8ebeec6ed17e30749a6426bfe5b96c91ea2619c6d2d658f5dabc4a19709daf8d4087b69ecc3a27e792fa4b4e65e78850de9cf8675f827bcf136373fea7eb7bcbbcc17c4cc34198ae2a1f41deaf21c09627d9fe3c6504e5d966ca398bab1ae59966759bb1053f450d68841a57a9d3d7a49b85baaafa88a1ac5f1b8273531a7f3e4254629b9a4ec5b38976dd897d55b9a6ce5cd25795ab820e8e7efe21cc0a7080c909fdcff16959516121f58baafa068673ea138b7f4d28fa552d7336f874c4fee46d68841a15cb55a1f57ae778589859b01dce7d70f20008f9ae1244135a5b6fd094acb37d4a2d137be7deee61c5e78a41ee2e19bd817d3873454d285dd8d7ebeb05b404771cdbb80785306ee39e7cdd992ef15d23c68860551e3469fd961d433d175217b8c57abb7839612c7fdd7071839b496ee6b472bbab5fb5a64cb22c98acd7a9540b2df656e67b224dbf6f2e6049585723cebb7e4e44eb4ae6b4048719ea69d1f5910cb0cc0e1e983b541cc3663c52744f256f48e24806adb2c1b739057bab0ccd253f5e6d704741f8bbedd124f32ab96e0456e8514d58ac23ee952fdee252d35fd77a2e6bca95bade134449897f1a745fbad4f43627d81e380565852c234e1eed38aa244af3a64812455fb508bb82e826adb2c6d65de1bd38a898007b3f5d90c363fa696e73f4821a2b9e04661ce2fd081df34bc6cedf133797da829f1e2e3f20bc6dd5b75d9a2e4ad42b5ee694c57779fefd04b5f1dcf77dbcdd482a845890363991155f85b89b22f8167926224529d46bce8a59600c7f5d4050733b781e1330216abb3e2486cc00ddc82d55b9a65eff725605ab23ff395c8ce3ee2e40f1692f2d6966296e26c47507dbbefd24a4522d334e9ddd992c712f62c759f0751c55aca8f64ae408a7d1f59ab04ed98819711c0edd60a7a39ba9682214728a3beec5d25c12fd1eff334a471fded244161b33587c6dec737e4f37b1c9894c28b60fb9544471726b2c9d05a4413d532e3cfe99fb443c038069c0b52e441c4cb1d9676956f3d7a88328b8ba3ac2ff0ddf53f665c8192f2224729a4d0da664df114fcbdf5078475fff12f7e67bb24dbc2f2e516c8d02816fcb7f6a143bfa75f75776494c8c54b363cf50edeede8c88376f155458a1248fe5acbd7059760907c2166885bb6aac0bc16c5fddb0c1d18eebee3385b20abb3fd5c79c03191a1d136ac30cccd10496dab39e4f0d2cf5ef4c22940d1b1f5e87eafa3595c571483f2c4535a5cc537e1a8eeb49272a50647bd2358fa5ccba82480659a6d2d38994abcffbf9905e0f1ca1f3d3fa7dde72e4b46e4b5f14c0bcc2edc88d574a36cf9e4407a65b433a7e5e9e411c2d42816dbb3fca80db8b048485071cda1c5474613cf3fad8a9fb5e517877055c945369751cc88319e728a40297b9932f9a29e971e9394cd1a312ea79df4784a2aa6d0fc5b67c82cd3c1d437a51cd5ed297961bc3ceeeff2e51587c33a42d9b0f1b748f5ec03294777bef0c37745068f3ef5cdbac3944ed62163863053f84180a7128b60876b2525ce6e96aa89bc01dae2dd3a3128b783ac335623ca92f05d6ee326d38cd575ac64f983176466ee62d8c5e9e416d2c42f36ef81f3b644abb6037a487188f6801a4378f23ef988d584ad60e81c558e104afe56c0db7cd254967a07749657bab0c4da04dafad50e3928b1c9a0760866e8abe0447bc031ce80de3abd75f3ed0c687eb83cbafcf6fb17d5d43458d9a6f5b90c879e0375017782e9d463551bcc2dbf8a93ec9452d1756989086ce55ac69e328133ce2e0f73887dbbae899b079bb6cf003a31a59ef6251434a5bffd7568cc2ecbdd8a0ca072afb11f5d7ab233e2e6e8a95badc22944eab7e4b15fb5e210094b7687d6d2505517d228a3ebc883a643c07d24ce111ebb15cb8e2d9e3fd3603d7ad012b7b180d179e4c7fb1b3d2cb6ddd13a4b23baf0bb193b9549ee8ac47baf6ff3a37d2d4baf35e6e1fec410cdc2384290f0c3a75fb2b259404a73c3c0c9535321d828f9cdd7a9a55dc03672c94b36f146cad505977f967a2d50955ebceccedd0091bdb800393da596ad314720cab1eb4a6fc025da87d931a270f1ed2f7d79af23f3e0edfc0adedd5b44d7bde4987ebea1585b4d6094c5c5514217d3698d8de99fb443c03854840d48b269f68232a55ca4387c4a9141aba5c29d0bd694e41a326eec97ee3a2e27abb2ea4d6ec025da87d932a377f0ee2e6267ad21f5e6effe07d1d0234fc1a8909344b5f11f76667d82f5a01a452ed222fedcdf8bf405f95575830750fb0697d5259e7ff3')
# Create string table function
def print_strings_table(strings_key, strings_data):
strings_out = []
for i in range(len(data)):
strings_out.append(strings_key[i%90] ^ strings_data[i])
strings_table = bytes(strings_out).decode('latin1')
# Print strings table
for s in strings_table.split('\x00'):
print(s)
print_strings_table(key, data)
# Create string lookup function
def string_lookup(strings_key, strings_data, offset):
strings_out = []
for i in range(len(data)):
strings_out.append(strings_key[i%len(key)] ^ strings_data[i])
strings_table = bytes(strings_out)[offset:].decode('latin1')
return strings_table.split("\x00")[0]
print("\n\nString lookup(%d): %s" % (0, string_lookup(key, data, 0)))
key = unhex('09bcba05a9423e4ad9256dea6dd6916dbfd2d242e45801f25905afde20b6f88e34d60f78a26a952d8f646efba3467cc65e11720d1559bfc27de9a9b12b5644a2444f8cbb7423ee77544330eb389f0c8214f4b35399147d1dcda0')
data = unhex('2ccf9a278d674d6ae40531c848a5cd4f84f2f462c07d72d05975c0a945c48be651ba6356c712f02dfc07068fc23517b570740a683576fcb01888ddd40b7916f7646dc2ef5462bb231c0c62a26cc650d14da7e716d4365d329ee329f3f456fd036c1ef90a39a44df3e44d90868062c67d72d0792ae18e0099be8e67b3631e821ef05efb4428baea0a39827f30530d452bd0a50f88c4f54a2225a20926efc91b5081112043478357fe61eb34dbd23ff5142f78a98041ddce25ff2b4c3e906a56bb289bc46dd1b7a662883762933562ddb155c6f8dd7b905b2fe338d071c20d0d89cc3513a02a4d25647b3dd0b50ec9e7e5771531d0362ae2cf22469c043d2c5eb768ed63e47d98d61ff067091da8d27bd3c825db274d77fe001ecd4db3e31f82f7b662883d6fcf7c70af8d45da9eae40b37c0c8225de038f051c8b836b1dc67c3401516620ccb618849a83772527ca302effd0070d8b0f316110c47bed69e36091937ccb415d3f83f429fdef51e10d6c038d7c31b93485c528f2f0f26d903621d72a2580aa5296daab47f42f57f129b562c1272bdb8c1c5ce90d455228256bcaf858d99bc40b7901f6646abc890119cb47663630985bf778e3679fc07dfc6c183de2e46cd0df71cc62110cf90a39a44df3e46dcca0a4328b2b75dc3c7dcae546c491ea55fb7811cc00f04efb0b1cd6cb2310b63b635f3e2777daba18d2cfc34232258f3326e2d111409a18266e588e54ef69f039c2877dfc6c181dbfcf7cc8df25d9305724ad25039901b9fe06caa2f26f952d64802071d6ae458bb9c278f6220ccb07f042fa1053ca936623aa3a7002234a2ddcb2538dca9f743b37c6273ca29e0723801b2026439f18b068ed7995da3dc6600f68bed47a9c9564c52e613eab501e9e1ed6a4558ee0d271d36938f27769c1b520d89dfa47a26e0c8247fb4ce0640dc1ff160ea9396313605138cba37d88dd9f4e2e2182613ab69e0103cc52276110c4719f50d16d87c736f4274f419ac967d8d572da12513dbc573e8208bafd31c9e3fc72b8286e853c77dcb645da94a051ae6a78c307e659fd010f968d2210aa5e7f1779352fd6a70ac986d0473a44d33326e2c80042ee52276315db0ce722a761d49663ad6c5338b8807bd9c93f89674d6aaa4005b519b3e21985f2f737c43b6e9c2a71dc8154d38bfa0ef62a1c821cf849ea100b98d72318fc7e34162d762bdaa3098cd9c3443521d13775ac9e10238d1a30631f8818ec69f614d49c30b9641473aa8e6cc4df25842c1e7cf9145fdd43e6bf5d91e3f264c478758b29608ffc05c5a4dd4da57b1dcf59a771ec0502988d2304a37c314c2d377ccce07db5fac8582221cf777dd0ec1d4d8a18233060844ffa7ed17c91df3fc5624c33fdfc79d3cd60db31562fb549438f15b3913ef0948615a50a44ae146cccac4fc597e8408a5811cc0efa5afc382d8ed13419a82a47177f6630d0ac21bbdcdf2b3c0cda253cf8ff17479d5e3b0e53d652e964b56390e63be1770e79b99209ddc871c0245f29ad0b089208edfc01c8a08d3189286dc92a64c2ae4cd3c3fd55b86b1acd12ae4efa070594cc6b47b03763077e150fd6b0099cc8dd2b0636cd2226e0de3d4e8f103113519f509f5acb46a0e612d5392d5ecdc979dfd56bcf2b596af64401866db8f4199fa1ba23963d01b36a4099ea6583cdd144a4342ee005ed7be6000b94a3630fe602335628667982e221b5f5930e2518fe1813b79b5203ca52271f12eb17eb38826691d420ef664e2fe3c571d99a28da623e')
print_strings_table(key, data)
#print("\n\nString lookup(%d): %s" % (1246, string_lookup(key, data, 1246)))
string_lookup(key, data, 708)
key = unhex('60441b6a08752e227c50334a08122d395a')
data = unhex('50c61a483878282b56d67bccff1f2c3861411b698a7421224cd232400a902c386087aa879d75c99ad8e04da00fecffa6838a0df6c32da3251b749690f07c6d027e3a0b5f1e1ac2522a396702b35bc678b0defb6a2b21e8a69b668a06c48612b593c4495f476d5697d5719c35b7125a4a25b62a44244188381473f8acca2a414c20b49e16dc57378d2f742b77aa0b059c2582068062d5bdb42bf959b0fc89fe6cdddb9965248ecda9ea64103bbfc6b53d14bbee029a68e7f382bcc1ab20a4d6d776359d0b6a1b4fdb71ec45093199a066c70119e1cac7164bbb41af1a35b076b667022298addc67a9e71ca25e9e7eca2c592d1ec28a501394b7a36fde1ed22e5746fe08172aa6ef0685c5d59c98b0658f1f4cb9a5506f0d5c31177379f91569473f46186b08740000')
out = []
for i in range(len(data)):
out.append(key[i % len(key)] ^ data[i])
tohex(bytes(out))
def rc4crypt(data, key):
#If the input is a string convert to byte arrays
if type(data) == str:
data = data.encode('utf-8')
if type(key) == str:
key = key.encode('utf-8')
x = 0
box = list(range(256))
for i in range(256):
x = (x + box[i] + key[i % len(key)]) % 256
box[i], box[x] = box[x], box[i]
x = 0
y = 0
out = []
for c in data:
x = (x + 1) % 256
y = (y + box[x]) % 256
box[x], box[y] = box[y], box[x]
out.append(c ^ box[(box[x] + box[y]) % 256])
return bytes(out)
import pefile
import hashlib
import struct
SAMPLE_FILE_PATH = '/tmp/qakbot.bin'
data = open(SAMPLE_FILE_PATH, 'rb').read()
pe = pefile.PE(data=data)
# Get the encrypted config from resource
rt_string_idx = [
entry.id for entry in
pe.DIRECTORY_ENTRY_RESOURCE.entries
].index(pefile.RESOURCE_TYPE['RT_RCDATA'])
rt_string_directory = pe.DIRECTORY_ENTRY_RESOURCE.entries[rt_string_idx]
resource_data = None
# The resource name is hardcoded -- needs to be dynamic
for entry in rt_string_directory.directory.entries:
if str(entry.name) == '3719':
data_rva = entry.directory.entries[0].data.struct.OffsetToData
size = entry.directory.entries[0].data.struct.Size
resource_data = pe.get_memory_mapped_image()[data_rva:data_rva+size]
# Build decryption key -- change to dynamic extraction
key_string = rb'\System32\WindowsPowerShell\v1.0\powershell.exe'
m = hashlib.sha1()
m.update(key_string)
key_bytes = m.digest()
out = rc4crypt(resource_data, key_bytes)
# Config has a SHA1 intergrity check followed by binary ip addresses
print("Config SHA1: %s" % tohex(out[:20]))
ip_table = out[21:]
for ptr in range(0,len(ip_table),7):
ip_string = "%d.%d.%d.%d" % (ord(ip_table[ptr:ptr+1]),
ord(ip_table[ptr+1:ptr+2]),
ord(ip_table[ptr+2:ptr+3]),
ord(ip_table[ptr+3:ptr+4]))
port_string = struct.unpack('>H', ip_table[ptr+4:ptr+6])[0]
print("%s:%s" % (ip_string,port_string))