遍历一个长字符串并上传到 SQL - Python

Looping through a long string and uploading to SQL - Python

大约 2 周以来,我一直在为这个问题绞尽脑汁,但似乎想不出一种方法来做到这一点。

我的任务是创建一个脚本,该脚本可以获取机器的缓存凭据并将该数据上传到 SQL 数据库。 我已经查看了所有主要工具、mimikatz 等。但目前,我只是使用基本的命令提示符命令,"cmdkey.exe /list" 此命令是使用 "subprocess" 模块调用的,我可以获得非常好的数据,但问题是输出 returns 是一个完整的字符串。

不提供返回的敏感数据,这是数据的结构:

目标:...
类型:...
用户:...
~注意事项~

我已经能够使用内置的 "split" 函数逐行遍历字符串。我创建了一个函数,根据它是否包含特定字符串,将行的值添加到不同的列表中,例如"Target: "。由于最后的注释,没有标题,这不能正常工作。

我遇到的另一个问题是有些条目有全部 4 个字段,而有些条目只有 2 个字段,所以我不能逐行循环并将每一行逐一添加到不同的列表。

我已经能够为每一行设置一个计数,例如

0    Target: 
1    Type: Domain Extended Credentials
2    User: 
3    Saved for this logon only
4
0    Target: 
1    Type: Generic
2    Local machine persistence
3

如您所见,由于每个 "block" 显示的数据不同,行数不匹配。

困扰我的不是特定的代码,而是方法。

这就是我调用 "cmdkey.exe /list" 命令的方式。

command = ['cmdkey.exe', '/list']
result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True)
r = result.stdout
formatted = r.split("\n", 3)[-1]

基本上,我希望它逐行循环遍历一个字符串,并根据字段标题将该行添加到列表中。如果该标题没有,请添加一个空白值。

我知道这很模糊,但在寻找完成它的方法之后,我一直在努力寻找实现它的方法。在这一点上,我们也将不胜感激关于其他实现此目的的任何建议。

根据评论中的要求,添加我正在使用的数据,编辑以删除敏感数据:

Target: MicrosoftAccount:target=SSO_POP_Device
Type: Domain Extended Credentials
User: username
Saved for this logon only

Target: MicrosoftAccount:target=SSO_POP_Device
Type: Generic
Local machine persistence

Target: MicrosoftAccount:target=SSO_POP_Device
Type: Domain Password
User: domain\username
Local machine persistence

Target: LegacyGeneric:target=Slack/tokens
Type: Generic
User: tokens
Local machine persistence

Target: MicrosoftAccount:target=SSO_POP_Device
Type: Generic
Local machine persistence

Target: MicrosoftAccount:target=SSO_POP_Device
Type: Generic
User: domain\username
Local machine persistence

Target: MicrosoftAccount:target=SSO_POP_Device
Type: Generic
User: username token
Local machine persistence

Target: MicrosoftAccount:target=SSO_POP_Device
Type: Generic
Local machine persistence

Target: MicrosoftAccount:target=SSO_POP_Device
Type: Generic
User: username
Local machine persistence

Target: MicrosoftAccount:target=SSO_POP_Device
Type: Generic
User: username
Local machine persistence

Target: MicrosoftAccount:target=SSO_POP_Device
Type: Generic
User: domain\username

Target: MicrosoftAccount:target=SSO_POP_Device
Type: Generic
User: email address

Target: MicrosoftAccount:target=SSO_POP_Device
Type: Generic Certificate
User: <Certificate>

Target: MicrosoftAccount:target=SSO_POP_Device
Type: Generic

Target: MicrosoftAccount:target=SSO_POP_Device   
Type: Generic

您可以将数据读入字典,如本例所示:

def empty():
    return {'Target': '', 'Type': '', 'User': '', 'Comment': ''}


def process(record):
    item = empty()

    for line in record:
        line_items = line.split(':', 1)
        if len(line_items) == 2:
            item[line_items[0]] = line_items[1].strip()
        if len(line_items) == 1:
            item['Comment'] = line_items[0].strip()

    print('here save into SQL:')
    print('  Target:' + item['Target'])
    print('  Type:' + item['Type'])
    print('  User:' + item['User'])
    print('  Comment:' + item['Comment'])
    print('')


def main():
    lines = r.split('\n')

    record = []
    for line in lines:
        line = line.strip()
        if line != '':
            record.append(line)
        else:
            process(record)
            record = []

    process(record)


if __name__ == "__main__":
    main()

结果为:

here save into SQL:
  Target:MicrosoftAccount:target=SSO_POP_Device
  Type:Domain Extended Credentials
  User:username
  Comment:Saved for this logon only

here save into SQL:
  Target:MicrosoftAccount:target=SSO_POP_Device
  Type:Generic
  User:
  Comment:Local machine persistence

here save into SQL:
  Target:MicrosoftAccount:target=SSO_POP_Device
  Type:Domain Password
  User:domain\username
  Comment:Local machine persistence

here save into SQL:
  Target:LegacyGeneric:target=Slack/tokens
  Type:Generic
  User:tokens
  Comment:Local machine persistence

here save into SQL:
  Target:MicrosoftAccount:target=SSO_POP_Device
  Type:Generic
  User:
  Comment:Local machine persistence

here save into SQL:
  Target:MicrosoftAccount:target=SSO_POP_Device
  Type:Generic
  User:domain\username
  Comment:Local machine persistence

here save into SQL:
  Target:MicrosoftAccount:target=SSO_POP_Device
  Type:Generic
  User:username token
  Comment:Local machine persistence

here save into SQL:
  Target:MicrosoftAccount:target=SSO_POP_Device
  Type:Generic
  User:
  Comment:Local machine persistence

here save into SQL:
  Target:MicrosoftAccount:target=SSO_POP_Device
  Type:Generic
  User:username
  Comment:Local machine persistence

here save into SQL:
  Target:MicrosoftAccount:target=SSO_POP_Device
  Type:Generic
  User:username
  Comment:Local machine persistence

here save into SQL:
  Target:MicrosoftAccount:target=SSO_POP_Device
  Type:Generic
  User:domain\username
  Comment:

here save into SQL:
  Target:MicrosoftAccount:target=SSO_POP_Device
  Type:Generic
  User:email address
  Comment:

here save into SQL:
  Target:MicrosoftAccount:target=SSO_POP_Device
  Type:Generic Certificate
  User:<Certificate>
  Comment:

here save into SQL:
  Target:MicrosoftAccount:target=SSO_POP_Device
  Type:Generic
  User:
  Comment:

here save into SQL:
  Target:MicrosoftAccount:target=SSO_POP_Device
  Type:Generic
  User:
  Comment:

我将您的输入封装到一个名为 data 的变量中。

您遇到的问题是格式化数据,而不是插入 SQL。所以我现在把这个留给你了:)

#   I see that my common characters to split my data is 2 following \n
groups = data.split('\n\n')
print(groups[0])
# Target: MicrosoftAccount:target=SSO_POP_Device
# Type: Domain Extended Credentials
# User: username
# Saved for this logon only

def format_group(group):
    """ Takes a group as input, and returns a properly formatted dict for the group.
    """
    resulting_dict = {}
    for line in group.split('\n'):
        split_pos = line.find(':')
        if split_pos > -1: # ':' is found, meaning it is not a comment but actual data.
            #   The data I have contains extra spaces and tabs, so I strip it.
            clean_key = line[:split_pos].strip()
            clean_val = line[split_pos+1:].strip()

            resulting_dict[clean_key] = clean_val

    return resulting_dict

#   Using my previously defined function for each group.
new_data = [format_group(group) for group in groups]

from pprint import pprint #Something to display nicely
pprint(new_data)
# [{'Target': 'MicrosoftAccount:target=SSO_POP_Device',
#  'Type': 'Domain Extended Credentials',
#  'User': 'username'},
# {'Target': 'MicrosoftAccount:target=SSO_POP_Device', 'Type': 'Generic'},
# {'Target': 'MicrosoftAccount:target=SSO_POP_Device',
#  'Type': 'Domain Password',
#  'User': 'domain\username'},
# {'Target': 'LegacyGeneric:target=Slack/tokens',
#  'Type': 'Generic',
#  'User': 'tokens'},
# {'Target': 'MicrosoftAccount:target=SSO_POP_Device', 'Type': 'Generic'},
# {'Target': 'MicrosoftAccount:target=SSO_POP_Device',
#  'Type': 'Generic',
#  'User': 'domain\username'},
# {'Target': 'MicrosoftAccount:target=SSO_POP_Device',
#  'Type': 'Generic',
#  'User': 'username token'},
# {'Target': 'MicrosoftAccount:target=SSO_POP_Device', 'Type': 'Generic'},
# {'Target': 'MicrosoftAccount:target=SSO_POP_Device',
#  'Type': 'Generic',
#  'User': 'username'},
# {'Target': 'MicrosoftAccount:target=SSO_POP_Device',
#  'Type': 'Generic',
#  'User': 'username'},
# {'Target': 'MicrosoftAccount:target=SSO_POP_Device',
#  'Type': 'Generic',
#  'User': 'domain\username'},
# {'Target': 'MicrosoftAccount:target=SSO_POP_Device',
#  'Type': 'Generic',
#  'User': 'email address'},
# {'Target': 'MicrosoftAccount:target=SSO_POP_Device',
#  'Type': 'Generic Certificate',
#  'User': '<Certificate>'},
# {'Target': 'MicrosoftAccount:target=SSO_POP_Device', 'Type': 'Generic'},
# {'Target': 'MicrosoftAccount:target=SSO_POP_Device', 'Type': 'Generic'}]