可乐博客

CIA机密文档追踪工具Scribbles详细分析

参考地址
维基泄密 vault7 Scribbles
CIA机密文档追踪工具Scribbles详细分析

Scribbles,涂鸦,office文档指纹原理,ppt有警告

在word2007上的.docx插入一张图片 解压后
word/document.xml代码如下

<a:blip r:embed="rId4" cstate="print"/>
改为
<a:blip r:link="rId8" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"/>

在word/_rels文件夹document.xml.rels中加入指向地址

<Relationship Id="rId8" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="http://52spider.com/u/?url=https://i.ytimg.com/vi/NemvyCnUZiM/hqdefault.jpg" TargetMode="External"/>

重新zip打包成docx后 打开文档会默认请求地址,无任何提示,excel异同
在excel2007上的.xlsx插入一张图片 解压后
xl/drawingsdocument.xml代码如下

<a:blip r:embed="rId4" cstate="print"/>
改为
<a:blip r:link="rId8" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"/>

在xl/drawings/_rels文件夹drawing1.xml.rels中加入指向地址

<Relationship Id="rId8" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="http://52spider.com/u/?url=https://i.ytimg.com/vi/NemvyCnUZiM/hqdefault.jpg" TargetMode="External"/>

Scribbles水印的参数为
url_Scheme:协议类型,可为HTTP和HTTPS
hostServerName:发起请求的域名
hostRootPath:发起请求的域的根路径
hostSubDirs:发起请求的域的子路径
hostFileName:发起请求的文件名
hostFileExtList:发起请求的文件类型后缀
output_Directory:已嵌入水印的文件输出路径
output_WatermarkLog:输出构造水印日志

这个地址可以是文件名、文件备注、发起人、时间做的一个哈希映射地址

图片可以加载文档页眉1像素隐藏

可以在一定程度上防止文件泄露、钓鱼获取目标人ip、阅后即焚文档

以下是请求ua

Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; MSOffice 12)

分析ua
浏览器名称 IE
浏览器版本号 7.0
渲染引擎 Trident 4.0
操作系统 Windows 7

python实现参考,不保证代码可用,原理就是解压添加,不使用openxml

# main.py
import os
from util import ziper
from Scr_xlsx import Scr_xlsx
from Scr_docx import Scr_docx

class Scrice():
    url='https://www.baidu.com'
    resources='resources'

    def bute(self):
        ext=os.path.splitext(self.name)[1]
        if ext == '.xlsx':
            Scr_xlsx(self.url,self.name,self.name1,self.resources)
        if ext == '.docx':
            Scr_docx(self.url,self.name,self.name1,self.resources)

    def build(self,name,name1):
        self.name=name
        self.name1=name1
        ziper(name)
        self.bute()
        ziper(name,name1,False)

if __name__ == '__main__': 
    s=Scrice()
    s.url='http://www.eooall.io'
    s.build('Book2.xlsx','Book3.xlsx')
    # s.build('Doc1.docx','Doc2.docx')
# Scr_docx.py
import os,shutil
from util import copytree
from fleader import fleader as rq
from bs4 import BeautifulSoup

class Scr_docx():
    def __init__(self,url,name,name1,resources):
        self.url=url
        self.name=name
        self.name1=name1
        self.resources=resources
        self.path=os.path.splitext(name)[0]
        copytree(r'./'+self.resources+'/word/word/drawings',self.path+'/word/drawings')
        self.hook_Content_Types_xml()
        self.hook_xl_worksheets_sheet1_xml()
        self.hook_xl_worksheets__rels_sheet1_xml_rels()
        self.hook_xl_drawings__rels_drawing1_xml_rels()

    def hook_Content_Types_xml(self):
        f=self.path+'/[Content_Types].xml'
        rt=rq.rw(f)
        soup = BeautifulSoup(rt,'xml')
        soup.find('Types').append(soup.new_tag("Override", PartName="/word/drawings/drawing1.xml",ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"))
        rq.rw(f,str(soup),aw='w')

    def hook_xl_worksheets_sheet1_xml(self):
        f=self.path+'/word/document.xml'
        rt=rq.rw(f)
        soup = BeautifulSoup(rt,'xml')
        s=soup.new_tag("drawing")
        s['r:id'] = 'rId10'
        soup.find('w:document').append(s)
        rq.rw(f,str(soup),aw='w')

    def hook_xl_worksheets__rels_sheet1_xml_rels(self):
        f=self.path+'/word/_rels/document.xml.rels'
        if os.path.isfile(f):
            rt=rq.rw(f)
            soup = BeautifulSoup(rt,'xml')
            soup.find('Relationships').append(soup.new_tag("Relationship",Id="rId10",Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing",Target="../drawings/drawing1.xml"))
            rq.rw(f,str(soup),aw='w')


    def hook_xl_drawings__rels_drawing1_xml_rels(self):
        f=self.path+'/word/drawings/_rels/drawing1.xml.rels'
        rt=rq.rw(f)
        soup = BeautifulSoup(rt,'xml')
        soup.find('Relationship')['Target'] = self.url
        rq.rw(f,str(soup),aw='w')
# Scr_xlsx.py
import os,shutil
from util import copytree
from fleader import fleader as rq
from bs4 import BeautifulSoup

class Scr_xlsx():
    def __init__(self,url,name,name1,resources):
        self.url=url
        self.name=name
        self.name1=name1
        self.resources=resources
        self.path=os.path.splitext(name)[0]
        copytree(r'./'+self.resources+'/excel/xl/drawings',self.path+'/xl/drawings')
        self.hook_Content_Types_xml()
        self.hook_xl_worksheets_sheet1_xml()
        self.hook_xl_worksheets__rels_sheet1_xml_rels()
        self.hook_xl_drawings__rels_drawing1_xml_rels()

    def hook_Content_Types_xml(self):
        f=self.path+'/[Content_Types].xml'
        rt=rq.rw(f)
        soup = BeautifulSoup(rt,'xml')
        soup.find('Types').append(soup.new_tag("Override", PartName="/xl/drawings/drawing1.xml",ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"))
        rq.rw(f,str(soup),aw='w')

    def hook_xl_worksheets_sheet1_xml(self):
        f=self.path+'/xl/worksheets/sheet1.xml'
        rt=rq.rw(f)
        soup = BeautifulSoup(rt,'xml')
        soup.find('worksheet').append(soup.new_tag("drawing"))
        soup.find('drawing')['r:id'] = 'rId2'
        rq.rw(f,str(soup),aw='w')

    def hook_xl_worksheets__rels_sheet1_xml_rels(self):
        f=self.path+'/xl/worksheets/_rels/sheet1.xml.rels'
        if not os.path.isfile(f):
            f_rels=self.path+'/xl/worksheets/_rels'
            if not os.path.isdir(f_rels):
                os.mkdir(f_rels)
            shutil.copyfile(r'./'+self.resources+'/excel/xl/worksheets/_rels/sheet1.xml.rels',f)
        else:
            pass

    def hook_xl_drawings__rels_drawing1_xml_rels(self):
        f=self.path+'/xl/drawings/_rels/drawing1.xml.rels'
        rt=rq.rw(f)
        soup = BeautifulSoup(rt,'xml')
        soup.find('Relationship')['Target'] = self.url
        rq.rw(f,str(soup),aw='w')
# util.py
import os,shutil,zipfile

def md5(*arg):
    import hashlib   
    hl = hashlib.md5()
    line=''.join(list(map(lambda x:str(x),arg)))
    hl.update(line.encode(encoding='utf-8'))    
    return hl.hexdigest()

def ziper(name,name1='',rm=True,rp=True):
    if name1=='':
        rw='r'
    else:
        rw='w'
    if rw=='r':
        path=os.path.splitext(name)[0]
        if os.path.isdir(path):
            shutil.rmtree(path)
        z = zipfile.ZipFile(name)
        path=os.path.splitext(name)[0]
        z.extractall(path=path)
        z.close()
    if rw=='w':
        path=os.path.splitext(name)[0]
        namemd5=md5(name)
        if os.path.isdir(path):
            if os.path.isdir(namemd5):
                shutil.rmtree(md5(name))
            shutil.move(path,namemd5)
        z = zipfile.ZipFile(name1,'w')
        for root, dirs, fs in os.walk(namemd5):
            for f in fs:
                if rp:
                    rpath=root.replace(namemd5,'')
                else:
                    rpath=root.replace(namemd5,path)
                pt=os.path.join(root,f)
                pt1=os.path.join(rpath,f)
                z.write(pt,pt1)
        z.close()
        if rm:
            shutil.rmtree(md5(name))
        else:
            shutil.move(namemd5,path) 

def copytree(src, dst, symlinks=False):
    names = os.listdir(src)
    if not os.path.isdir(dst):
        os.makedirs(dst)
          
    errors = []
    for name in names:
        srcname = os.path.join(src, name)
        dstname = os.path.join(dst, name)
        try:
            if symlinks and os.path.islink(srcname):
                linkto = os.readlink(srcname)
                os.symlink(linkto, dstname)
            elif os.path.isdir(srcname):
                copytree(srcname, dstname, symlinks)
            else:
                if os.path.isdir(dstname):
                    os.rmdir(dstname)
                elif os.path.isfile(dstname):
                    os.remove(dstname)
                shutil.copy2(srcname, dstname)
            # XXX What about devices, sockets etc.?
        except (IOError, os.error) as why:
            errors.append((srcname, dstname, str(why)))
        # catch the Error from the recursive copytree so that we can
        # continue with other files
        except OSError as err:
            errors.extend(err.args[0])
随笔