{
	"id": "4e8bf38e-8f41-45bf-a3e2-35029de1dc5c",
	"created_at": "2026-04-06T01:29:13.087486Z",
	"updated_at": "2026-04-10T03:37:26.287476Z",
	"deleted_at": null,
	"sha1_hash": "b6a3a38c6d5cb78a2f337c1790f93da76d4de19f",
	"title": "A BazarLoader DGA that Breaks Down in the Summer",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 93987,
	"plain_text": "A BazarLoader DGA that Breaks Down in the Summer\r\nArchived: 2026-04-06 00:08:36 UTC\r\nAndré Tavares sent me a Bazar Loader sample whose Domain Generation Algorithm (DGA) shows some\r\ninteresting behavior. In May, it generates valid domain names with the eponymous top level domain .bazar:\r\nBut as soon as June comes around, some generated domains contain invalid characters:\r\nhttps://johannesbader.ch/blog/a-bazarloader-dga-that-breaks-during-summer-months/\r\nPage 1 of 11\n\nAnd as it gets to July, all domain names are invalid (with very few exceptions):\r\nhttps://johannesbader.ch/blog/a-bazarloader-dga-that-breaks-during-summer-months/\r\nPage 2 of 11\n\nThe DGA also fails during August and September. But when October rolls around, all domains are valid again.\r\nThis continues until next June, when the DGA has problems all over again.\r\nThis short blog post explores what causes the DGA to stop working properly in the summer, of all times.\r\nThe Sample Examined\r\nI reverse engineered the DGA of the following sample:\r\nMD5\r\n5f11f2db1295fa419b190bd7478d9b23\r\nSHA1\r\n96d6c37fa0046a8dc1c520249dc94122e0fb3f52\r\nSHA256\r\n86d2aa04988befc74eccca5d99550f67093969b31aafa11cdce3476a4c59ba74\r\nSize\r\n248 KB (254474 Bytes)\r\nCompile Timestamp\r\n2021-07-13 08:22:30 UTC\r\nhttps://johannesbader.ch/blog/a-bazarloader-dga-that-breaks-during-summer-months/\r\nPage 3 of 11\n\nLinks\r\nMalwareBazaar, Cape, VirusTotal\r\nFilename\r\n5f11f2db1295fa419b190bd7478d9b23.dll (MalwareBazaar), (VirusTotal)\r\nDetections\r\nMalwareBazaar: BazaLoader, Virustotal: 47/75 as of 2021-08-05 11:35:35 - Gen:Variant.Razy.892983\r\n(MicroWorld-eScan), Trojan.Agent (CAT-QuickHeal), Backdoor.Win64.Bazdor.ah (Sangfor),\r\nBackdoor:Win64/Bazdor.ae3c68af (Alibaba), Trojan ( 0057f6941 ) (K7GW), Trojan ( 0057f6941 )\r\n(K7AntiVirus), W64/Trojan.FRTN-3244 (Cyren), Win64/BazarLoader.AP (ESET-NOD32), generic.ml\r\n(Paloalto), Backdoor.Win64.Bazdor.ah (Kaspersky), Gen:Variant.Razy.892983 (BitDefender),\r\nWin64:DropperX-gen [Drp] (Avast), Gen:Variant.Razy.892983 (Ad-Aware), Gen:Variant.Razy.892983 (B)\r\n(Emsisoft), Trojan.Agent.Win64.8672 (Zillya), Artemis!Trojan (McAfee-GW-Edition), Trojan.Agent.dkxh\r\n(Jiangmin), TR/Redcap.ntozn (Avira), malware (ai score=88) (MAX), Win32.Troj.Undef.(kcloud)\r\n(Kingsoft), Trojan.Win64.Agent.oa (Gridinsoft), Trojan:Win64/Cobaltstrike.A!MSR (Microsoft),\r\nBackdoor.Win64.Bazdor.ah (ZoneAlarm), Gen:Variant.Razy.892983 (GData), Trojan.Win64.Convagent\r\n(VBA32), Gen:Variant.Razy.892983 (ALYac), Trojan.Bazar (Malwarebytes),\r\nTrojan.Agent!v7VRXZm6ckQ (Yandex), Trojan.Win64.Bazarloader (Ikarus), Win64:DropperX-gen [Drp]\r\n(AVG), Trj/CI.A (Panda)\r\nI have unpacked it to the following state:\r\nMD5\r\n7c64ea7c4a229414b6048d18ab0836fd\r\nSHA1\r\nf10621be9bfee0152931f7790c2cbff022611f62\r\nSHA256\r\nd15dbfb7ef0511556a3527cc98d09145a56302bdd19a6083ee6d007af3352434\r\nSize\r\n113 KB (116224 Bytes)\r\nCompile Timestamp\r\n2021-07-12 13:27:57 UTC\r\nLinks\r\nMalwareBazaar, Cape, VirusTotal\r\nDetections\r\nMalwareBazaar: BazaLoader, Virustotal: 40/75 as of 2021-08-05 19:07:37 - Trojan.Win32.Razy.4!c\r\n(Lionic), Gen:Variant.Razy.891147 (MicroWorld-eScan), Gen:Variant.Razy.891147 (FireEye),\r\nBackdoor.Bazdor.Win64.3 (Zillya), Backdoor:Win64/Bazdor.9312a6ac (Alibaba), Trojan ( 0057f6941 )\r\n(K7GW), Trojan ( 0057f6941 ) (K7AntiVirus), W64/Trojan.QFLC-7900 (Cyren), Win64/BazarLoader.AP\r\n(ESET-NOD32), Backdoor.Win64.Bazdor.ax (Kaspersky), Gen:Variant.Razy.891147 (BitDefender),\r\nGen:Variant.Razy.891147 (Ad-Aware), BehavesLike.Win64.Trojan.ch (McAfee-GW-Edition),\r\nGen:Variant.Razy.891147 (B) (Emsisoft), Trojan.Win64.Bazarloader (Ikarus), TR/Redcap.rlvgc (Avira),\r\nmalware (ai score=81) (MAX), Win32.Hack.Undef.(kcloud) (Kingsoft), Trojan.Win64.Agent.oa\r\n(Gridinsoft), Trojan:Win32/Tiggre!rfn (Microsoft), Gen:Variant.Razy.891147 (GData),\r\nhttps://johannesbader.ch/blog/a-bazarloader-dga-that-breaks-during-summer-months/\r\nPage 4 of 11\n\nBackdoor.Win64.Bazdor (VBA32), Gen:Variant.Razy.891147 (ALYac), Trojan.Bazar (Malwarebytes),\r\nWin64.Backdoor.Bazdor.Ajls (Tencent), W64/BazarLoader.AP!tr (Fortinet), Trj/CI.A (Panda)\r\nThe Domain Generation Algorithm\r\nThe DGA can be easily be located in the unpacked sample based on the .bazar TLD, for example with this Yara\r\nrule:\r\nrule BazarDGA\r\n{\r\n strings:\r\n $bazar_tld= { 2E [4-12] 62 [4-12] 61 [4-12] 7A [4-12] 61 [4-12] 72 }\r\n condition:\r\n $bazar_tld\r\n}\r\nThe rule triggers at the following location, which adds the top level domain to the generated domain (pointed to\r\nby rax ) at the end of the DGA function:\r\nHere is how the DGA works:\r\n1. BazarLoader divides the letters – except J, which was omitted for unknown reasons – into two character\r\nclasses:\r\nthe 6 vowels aeiouy\r\nthe 19 consonants bcdfghklmnpqrstvwxz\r\n2. The two sets are then combined into all 2⋅6⋅19 ordered pairs that contain one vowel and one consonant:\r\nab , ba , eb , be , ib , bi , ob , bo , …, oz , zo , uz , zu , yz , zy .\r\n3. These 228 pairs are then rearranged with a permutation that is hard-coded into the malware. The\r\npermutation is the seed of the BazarLoader DGA and offers the possibility to generate a different set of\r\ndomains with the same algorithm. The permutation is stored as an array of 228 bytes that represent the one-https://johannesbader.ch/blog/a-bazarloader-dga-that-breaks-during-summer-months/\r\nPage 5 of 11\n\nline notation of the permutation. So for example, a permutation of 27, 119, 38, … would place the first pair\r\nab at position 27, the second pair ba at 119, and so on (0 being the first position).\r\n4. Four pairs are then picked from the 228 permutated pairs, and strung together to form the 8 letter long\r\nsecond level domain. Which pairs are selected depends on the current date. The date is formatted as %m%y ,\r\nwhere %m is the zero-padded month and %y is the two digit year. For example, December 5, 2035 would\r\nbe 1235 . The four digits, e.g., 1, 2, 3 and 5, then define which pairs will be selected for the first, second,\r\nthird and fourth pair respectively.\r\n5. The first pair is selected by first splitting the pairs into groups of 19 pairs. The first digit derived from the\r\ncurrent date then serves as the index of the groups to select. Since the first digit can only be 0 or 1, only\r\ntwo groups are possible 1\r\nBazarLoader then picks a pair at random from the 19 pairs of the given group.\r\n6. The second pair is selected like the first pair, except the groups are picked based on the second date digit.\r\nThis digit can be any value from 0 to 9, so ten different groups are possible:\r\nhttps://johannesbader.ch/blog/a-bazarloader-dga-that-breaks-during-summer-months/\r\nPage 6 of 11\n\n7. For the third pair, the groups only have a size of 4 pairs. Since the third date digit represents the decade,\r\nthe same group will be selected for years to come.\r\n8. The fourth pair is also picked from groups of 4 pairs, based on the least significant digit of the year.\r\nhttps://johannesbader.ch/blog/a-bazarloader-dga-that-breaks-during-summer-months/\r\nPage 7 of 11\n\n9. The four picked pairs are concatenated into an 8-letter second level domain, and the top level domain\r\n.bazar is appended.\r\nAs can be seen from the illustrations above, pairs at higher positions are selected only as a second pair and only\r\nduring the summer months. And that is exactly what causes the bug.\r\nThe Bug - A Faulty Permutation\r\nThe DGA is implemented exactly as described above. The hard-coded permutation, however, is incorrect:\r\n 57 63 3A 29 25 0E 1E 5C 04 77 5F 37 02 03 28 51\r\n 61 28 39 64 12 1C 49 30 3D 74 06 07 49 0B 10 33\r\n 56 10 57 19 4A 3B 2C 2E 36 71 1B 68 24 15 67 5A\r\n 50 20 45 6E 4C 54 2F 2B 54 62 4A 0B 59 35 51 23\r\n 4D 08 01 45 1A 0A 7B 27 72 55 0C 08 5B 1F 60 32\r\n 3C 29 3B 2E 2A 70 3A 0F 17 48 14 2C 4B 25 4E 42\r\n 44 15 03 05 7C 26 16 06 24 5A 0D 32 46 39 35 5F\r\n 4F 6F 11 0C 34 5B 47 59 4E 42 5D 5E 1C 66 52 53\r\n 3F 30 38 21 44 18 00 58 56 1E 40 2A 4B 3E 55 13\r\n 3E 65 05 0F 1D 09 36 21 22 6D 2D 12 6A 40 17 19\r\n 3F 34 11 2F 5D 63 5E 6B 31 61 69 22 26 33 0D 7A\r\n 1D 4D 16 75 7D 0A 4F 02 07 64 79 58 14 1A 53 62\r\n 0E 41 18 01 31 2B 47 1F 76 5C 09 04 60 43 37 13\r\n 3D 3C 41 48 2D 43 52 38 73 27 23 46 4C 1B 50 6C\r\n 78 20 7E 00\r\nFor the permutation to be valid, i.e., bijective, it would need to contain all numbers from 0x00 to 0xe3 (227).\r\nBut the largest number in the above list of numbers is only 0x7E (126). Possibly the wrong data type was chosen\r\nwhen generating the permutation. For example, a signed char to store the numbers 1-228.\r\nInstead of permuting the pairs, the DGA places them all in the first 127 places. Some pairs will therefore be\r\noverwritten by another pair placed in the same spot. For instance the first pair ab is placed at position 0x57\r\n(first number of the “permutation”) . But since 0x57 appears a second time (35th number of the “permutation”),\r\nthe pair ab will be overwritten.\r\nSimilarly, all spots above 127 are never filled. So with the actual “permutation” applied, the illustration for\r\npicking the second pair looks as follows, where ? denotes undefined memory:\r\nhttps://johannesbader.ch/blog/a-bazarloader-dga-that-breaks-during-summer-months/\r\nPage 8 of 11\n\nAll pairs in July, August and September are undefined and will likely result in invalid domains. In June, only 13\r\nout of 19 pairs are undefined, hence some domains come out correct. All other months are not affected by the bug.\r\nReimplementation in Python\r\nThe following Python script will generate all possible domains for a given date. When it is run for months affected\r\nby the bug, the resulting domains will contain two ?? that represent characters from undefined memory.\r\nfrom datetime import datetime\r\nimport argparse\r\nfrom collections import namedtuple\r\nParam = namedtuple('Param', 'block idx')\r\nhttps://johannesbader.ch/blog/a-bazarloader-dga-that-breaks-during-summer-months/\r\nPage 9 of 11\n\npool = (\r\n \"yzewevmeywreomvi\"\r\n \"ekwyavygontowaer\"\r\n \"udsoyrexvuamtyse\"\r\n \"weesuvizpituiqow\"\r\n \"uzoretzemuultiaz\"\r\n \"icukoqiwolxuykos\"\r\n \"upwiymitisneroxe\"\r\n \"yxanlekyixxirasi\"\r\n \"asxoapuxqaohezwo\"\r\n \"oxdigyquziutpave\"\r\n \"zohexyvyguqyqidy\"\r\n \"ovynumunuwsusyen\"\r\n \"xaatyvusivaripfy\"\r\n \"oftesaysozuregin\"\r\n \"alifkazaadytwuub\"\r\n \"zuvoothymivazy\"\r\n)\r\npool +=(10*19*2 - len(pool))*\"?\"\r\ndef dga(date):\r\n seed = date.strftime(\"%m%Y\")\r\n params = [\r\n Param(19, 0),\r\n Param(19, 1),\r\n Param(4, 4),\r\n Param(4, 5)\r\n ]\r\n ranges = []\r\n for p in params:\r\n s = int(seed[p.idx])\r\n lower = p.block*s\r\n upper = lower + p.block\r\n ranges.append(list(range(lower, upper)))\r\n domains = set()\r\n for indices in product(*ranges):\r\n domain = \"\"\r\n for index in indices:\r\n domain += pool[index*2:index*2 + 2]\r\n domain += \".bazar\"\r\n domains.add(domain)\r\n return domains\r\nhttps://johannesbader.ch/blog/a-bazarloader-dga-that-breaks-during-summer-months/\r\nPage 10 of 11\n\nif __name__ == \"__main__\":\r\n parser = argparse.ArgumentParser()\r\n parser.add_argument(\r\n \"-d\", \"--date\", help=\"date used for seeding, e.g., 2020-06-28\",\r\n default=datetime.now().strftime('%Y-%m-%d'))\r\n args = parser.parse_args()\r\n d = datetime.strptime(args.date, \"%Y-%m-%d\")\r\n for domain in dga(d):\r\n print(domain)\r\nCharacteristics of the DGA\r\nThe following table summarizes the properties of the BazarLoader DGA when it is working as intended, i.e.,\r\nOctober through May.\r\nproperty value\r\ntype TDD (time-dependent-deterministic)\r\ngeneration scheme arithmetic\r\nseed current date\r\ndomain change frequency every month\r\nunique domains per month 5776\r\nsequence random selection, might pick domains multiple times\r\nwait time between domains none\r\ntop level domain .bazar\r\nsecond level characters a-z, without j\r\nregex [a-ik-z]{8}.bazar\r\nsecond level domain length 8\r\n1. note that the letters used in the illustrations are randomly placed and not the actual letter pairs that\r\nBazarLoader uses. ↩︎\r\nSource: https://johannesbader.ch/blog/a-bazarloader-dga-that-breaks-during-summer-months/\r\nhttps://johannesbader.ch/blog/a-bazarloader-dga-that-breaks-during-summer-months/\r\nPage 11 of 11",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://johannesbader.ch/blog/a-bazarloader-dga-that-breaks-during-summer-months/"
	],
	"report_names": [
		"a-bazarloader-dga-that-breaks-during-summer-months"
	],
	"threat_actors": [
		{
			"id": "761d1fb2-60e3-46f0-9f1c-c8a9715967d4",
			"created_at": "2023-01-06T13:46:38.269054Z",
			"updated_at": "2026-04-10T02:00:02.90356Z",
			"deleted_at": null,
			"main_name": "APT3",
			"aliases": [
				"GOTHIC PANDA",
				"TG-0110",
				"Buckeye",
				"Group 6",
				"Boyusec",
				"BORON",
				"BRONZE MAYFAIR",
				"Red Sylvan",
				"Brocade Typhoon"
			],
			"source_name": "MISPGALAXY:APT3",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "3fff98c9-ad02-401d-9d4b-f78b5b634f31",
			"created_at": "2023-01-06T13:46:38.376868Z",
			"updated_at": "2026-04-10T02:00:02.949077Z",
			"deleted_at": null,
			"main_name": "Cleaver",
			"aliases": [
				"G0003",
				"Operation Cleaver",
				"Op Cleaver",
				"Tarh Andishan",
				"Alibaba",
				"TG-2889",
				"Cobalt Gypsy"
			],
			"source_name": "MISPGALAXY:Cleaver",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "06f622cb-3a78-49cf-9a4c-a6007a69325f",
			"created_at": "2022-10-25T16:07:23.315239Z",
			"updated_at": "2026-04-10T02:00:04.537826Z",
			"deleted_at": null,
			"main_name": "APT 3",
			"aliases": [
				"APT 3",
				"Boron",
				"Brocade Typhoon",
				"Bronze Mayfair",
				"Buckeye",
				"G0022",
				"Gothic Panda",
				"Group 6",
				"Operation Clandestine Fox",
				"Operation Clandestine Fox, Part Deux",
				"Operation Clandestine Wolf",
				"Operation Double Tap",
				"Red Sylvan",
				"TG-0110",
				"UPS Team"
			],
			"source_name": "ETDA:APT 3",
			"tools": [
				"APT3 Keylogger",
				"Agent.dhwf",
				"BKDR_HUPIGON",
				"Backdoor.APT.CookieCutter",
				"Badey",
				"Bemstour",
				"CookieCutter",
				"Destroy RAT",
				"DestroyRAT",
				"DoublePulsar",
				"EXL",
				"EternalBlue",
				"HTran",
				"HUC Packet Transmit Tool",
				"Hupigon",
				"Hupigon RAT",
				"Kaba",
				"Korplug",
				"LaZagne",
				"MFC Huner",
				"OSInfo",
				"Pirpi",
				"PlugX",
				"RedDelta",
				"RemoteCMD",
				"SHOTPUT",
				"Sogu",
				"TIGERPLUG",
				"TTCalc",
				"TVT",
				"Thoper",
				"Xamtrav",
				"remotecmd",
				"shareip",
				"w32times"
			],
			"source_id": "ETDA",
			"reports": null
		}
	],
	"ts_created_at": 1775438953,
	"ts_updated_at": 1775792246,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/b6a3a38c6d5cb78a2f337c1790f93da76d4de19f.pdf",
		"text": "https://archive.orkl.eu/b6a3a38c6d5cb78a2f337c1790f93da76d4de19f.txt",
		"img": "https://archive.orkl.eu/b6a3a38c6d5cb78a2f337c1790f93da76d4de19f.jpg"
	}
}