Talos Vulnerability Report

TALOS-2019-0938

Moxa AWK-3131A ServiceAgent denial-of-service vulnerability

February 24, 2020
CVE Number

CVE-2019-5148

Summary

An exploitable denial-of-service vulnerability exists in ServiceAgent functionality of the Moxa AWK-3131A, firmware version 1.13. A specially crafted packet can cause an integer underflow, triggering a large memcpy that will access unmapped or out-of-bounds memory. An attacker can send this packet while unauthenticated to trigger this vulnerability.

Tested Versions

Moxa AWK-3131A Firmware version 1.13

Product URLs

http://www.moxa.com/product/AWK-3131A.htm

CVSSv3 Score

7.5 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

CWE

CWE-125: Out-of-bounds Read

Details

The Moxa AWK-3131A Industrial IEEE 802.11a/b/g/n wireless AP/bridge/client is a wireless networking appliance intended for use in industrial environments. It is designed to provide wireless communication capabilities to the environments in which it is deployed. Communication with the device is possible using HTTP, Telnet and SSH.

This denial-of-service vulnerability is caused by an out-of-bounds memory access which causes the ServiceAgent binary to crash. This out-of-bounds memory access can be a SIGSEGV (out-of-bounds access) or a SIGBUS (unmapped memory), but the root cause is the same. When a packet is sent to the ServiceAgent, a single ServiceAgent bundle is removed via the parseRecvData function. This function types byte 4-7 (the length of the bundle) and adds 0x24 (length of header). Once that is parsed, if it has not reached the end of the packet, it will attempt to copy the remaining data to a structure to be processed later, the length of the copy is directly taken from the packet, exactly where the next ServiceAgent bundle’s length field would be, add 0x24 for header length, and then copy to a buffer for later processing. The total length of the packet received is not checked when the length of the bundle is calculated which causes an integer underflow making for a very long memcpy, finally resulting in a src out-of-bounds read, causing a SIGSEGV.

00404e94  8fc20030   lw      $v0, 0x30($fp) {var_18}
00404e98  2442000c   addiu   $v0, $v0, 0xc {Session::sockAddr}
00404e9c  8fc30024   lw      $v1, 0x24($fp) {var_24}
00404ea0  afa30010   sw      $v1, 0x10($sp) {var_38_2}
00404ea4  8fc40048   lw      $a0, 0x48($fp) {arg_0}
00404ea8  00402821   move    $a1, $v0
00404eac  8f8680f8   lw      $a2, -0x7f08($gp)  {dispatchServiceHandle}  {0x439828}
00404eb0  8fc70020   lw      $a3, 0x20($fp) {var_28}
00404eb4  8f8280fc   lw      $v0, -0x7f04($gp)  {parseRecvData}  {0x43982c}
00404eb8  0040c821   move    $t9, $v0  {parseRecvData}
00404ebc  04114729   bal     parseRecvData  // Parse out a single package from the received packet
00404ec0  00000000   nop     
00404ec4  8fdc0018   lw      $gp, 0x18($fp) {var_30}  {0x441730}
00404ec8  8fc20038   lw      $v0, 0x38($fp) {var_10_4}
00404ecc  1040000f   beqz    $v0, 0x404f0c
00404ed0  00000000   nop     
00404ed4  8fc30028   lw      $v1, 0x28($fp) {remainingData_underflowBug}
00404ed8  8fc20024   lw      $v0, 0x24($fp) {var_24}
00404edc  00621023   subu    $v0, $v1, $v0  // Underflow occurs here due to lack of checks
00404ee0  afc20028   sw      $v0, 0x28($fp) {remainingData_underflowBug}
00404ee4  00000000   nop     
...
00404f0c  00000000   nop     
00404f10  8fc40030   lw      $a0, 0x30($fp) {var_18}
00404f14  8fc50020   lw      $a1, 0x20($fp) {var_28}
00404f18  8fc60028   lw      $a2, 0x28($fp) {remainingData_underflowBug}  // This is the bug
00404f1c  0c1012d4   jal     copyRemainingData  // This is essentially a memcpy where $a2 is the length of the copy
00404f20  00000000   nop     
00404f24  8fdc0018   lw      $gp, 0x18($fp) {var_30}  {0x441730}
00404f28  0810145a   j       0x405168
00404f2c  00000000   nop     

Crash Information

[ Legend: Modified register | Code | Heap | Stack | String ]
───────────────────────────────────────── registers ────
$zero: 0x0       
$at  : 0x1       
$v0  : 0x2cc00008  →  0x00000000
$v1  : 0x2cc00008  →  0x00000000
$a0  : 0x2d281248  →  0x00000000
$a1  : 0x2c2fffca  →  0x00000000
$a2  : 0xe7e8ff  
$a3  : 0x2da7e8c8  →  0x00000000
$t0  : 0x0       
$t1  : 0x0       
$t2  : 0x0       
$t3  : 0x0       
$t4  : 0x0       
$t5  : 0x0       
$t6  : 0x0       
$t7  : 0x0       
$s0  : 0x0       
$s1  : 0x2caff4b0  →  0x00000001
$s2  : 0x0       
$s3  : 0x2acf97e4  →  0x00000000
$s4  : 0xffffffff
$s5  : 0x1000    
$s6  : 0x2ba00608  →  0x00000000
$s7  : 0xf       
$t8  : 0x3f      
$t9  : 0x2ae82ee0  →  <memcpy+0> slti t2, a2, 8
$k0  : 0x802     
$k1  : 0x0       
$s8  : 0x2cafd490  →  0x2bc7ed8a  →  0x00000000
$pc  : 0x2ae83160  →  <memcpy+640> lwr t5, 55(a1)
$sp  : 0x2cafd490  →  0x2bc7ed8a  →  0x00000000
$hi  : 0x6       
$lo  : 0x1c      
$fir : 0x0       
$ra  : 0x00404c78  →   lw gp, 16(s8)
$gp  : 0x00441730  →  0x00000000
───────────────────────────────────────────── stack ────
0x2cafd490│+0x0000: 0x2bc7ed8a  →  0x00000000	 ← $s8, $sp
0x2cafd494│+0x0004: 0x00000000
0x2cafd498│+0x0008: 0x00000000
0x2cafd49c│+0x000c: 0x00400000  →  0x7f454c46
0x2cafd4a0│+0x0010: 0x00441730  →  0x00000000
0x2cafd4a4│+0x0014: 0x00000000
0x2cafd4a8│+0x0018: 0x2cafd4b0  →  0x2ba00468  →  0x00000005
0x2cafd4ac│+0x001c: 0x00404f24  →   lw gp, 24(s8)
────────────────────────────────── code:mips:MIPS32 ────
0x2ae83154 <memcpy+628>     lwl    t4, 48(a1)
0x2ae83158 <memcpy+632>     lwr    t4, 51(a1)
0x2ae8315c <memcpy+636>     lwl    t5, 52(a1)
→ 0x2ae83160 <memcpy+640>     lwr    t5, 55(a1)
0x2ae83164 <memcpy+644>     lwl    t6, 56(a1)
0x2ae83168 <memcpy+648>     lwr    t6, 59(a1)
0x2ae8316c <memcpy+652>     lwl    t7, 60(a1)
0x2ae83170 <memcpy+656>     lwr    t7, 63(a1)
0x2ae83174 <memcpy+660>     pref   0x4, 160(a1)
─────────────────────────────────────────── threads ────
[#0] Id 1, Name: "", stopped, reason: SIGSEGV
[#1] Id 2, Name: "", stopped, reason: SIGSEGV
[#2] Id 4, Name: "", stopped, reason: SIGSEGV
───────────────────────────────────────────── trace ────
[#0] 0x2ae83160 → memcpy()
[#1] 0x404c78 → lw gp, 16(s8)
────────────────────────────────────────────────────────

Timeline

2019-10-23 - Vendor Disclosure
2020-02-24 - Public Release

Credit

Discovered by Carl Hurd of Cisco Talos.