
Cisco RV110w UPnP स्टैक ओवरफ़्लो
हाल ही में UPnP काफी चर्चा में है। संयोग से मेरे पास एक Cisco RV110W है। अगस्त 2021 में सिस्को ने आधिकारिक रूप से Cisco RV श्रृंखला में UPnP से संबंधित एक 0day घोषित किया था, लेकिन विशिष्ट विवरण सार्वजनिक नहीं किए गए। इसलिए मैं अपने पास मौजूद डिवाइस का उपयोग करके इस कमजोरी को डीबग करके खोजना चाहता था। इस कमजोरी की घोषणा आधिकारिक वेबसाइट पर देखी जा सकती है।
सबसे पहले फर्मवेयर को नवीनतम संस्करण 1.2.2.8 में अपडेट करें। इसके बाद सामने आने वाली समस्या यह है कि कमजोरी को कैसे डीबग करें और उसका पता कैसे लगाएं। पहले डीबगिंग की समस्या का समाधान करते हैं। डीबगिंग का सबसे पहला काम डिवाइस का शेल प्राप्त करना है, लेकिन नवीनतम फर्मवेयर कोई डीबग इंटरफ़ेस प्रदान नहीं करता है। मैंने यहाँ UART सीरियल पोर्ट के माध्यम से और फर्मवेयर पैकेज को संशोधित करके नवीनतम फर्मवेयर के लिए डीबगिंग अनुमति प्राप्त की। विशिष्ट विधि के लिए पहले लिखा गया लेख राउटर डीबगिंग: getshell देखें।
Cisco RV110W mipsel आर्किटेक्चर पर आधारित है, इसलिए पहले एक संगत gdb-server खोजना आवश्यक है। आप इसे स्वयं क्रॉस-कंपाइल कर सकते हैं या किसी और द्वारा संकलित का उपयोग कर सकते हैं। यहाँ gdb-static-cross अनुशंसित है।
आधिकारिक घोषणा में बताया गया है कि कमजोरी UPnP सेवा में मौजूद है। सबसे पहले एडमिन पैनल में जाएं, और FireWall की Basic Settings में UPnP कॉन्फ़िगरेशन चालू करें।

फिर nmap से पोर्ट स्कैन करने पर UPnP का पोर्ट नहीं मिला, लेकिन परीक्षण से पता चला कि UPnP वास्तव में चालू है।

यहाँ मैं कमजोरी के परीक्षण और शोषण के लिए UPnPy का उपयोग करता हूँ।
import socket
msg = \
b'M-SEARCH * HTTP/1.1\r\n' \
b'HOST:239.255.255.250:1900\r\n' \
b'ST:upnp:rootdevice\r\n' \
b'MX:2\r\n' \
b'MAN:"ssdp:discover"\r\n' \
b'\r\n'
# Set up UDP socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
s.bind((b"192.168.2.100",23333)) #本机IP
s.settimeout(2)
s.sendto(msg, (b'239.255.255.250', 1900))
addr = ('192.168.2.1', 1900) # 网关IP
try:
while True:
data, addr = s.recvfrom(65507)
print(addr,data)
except socket.timeout:
pass
यह पाया गया कि वास्तव में UPnP से प्रतिक्रिया प्राप्त हुई, और डिवाइस की प्रक्रियाओं में संबंधित UPnP प्रक्रिया भी मौजूद है।

UPnP एक सामान्य प्रोटोकॉल मानक है; अधिकांश निर्माता मानक के अनुसार ही कार्यान्वयन करते हैं, अर्थात कई action समान होते हैं। लेकिन कमजोरी का पता लगाने और शोषण को सुगम बनाने के लिए डिवाइस द्वारा प्रदान की गई सेवाओं का विश्लेषण करना भी आवश्यक है। सूचना एकत्र करने के लिए भी UPnPy का उपयोग किया जाता है।
import upnpy
import socket
import requests
from upnpy.ssdp.SSDPDevice import SSDPDevice
msg = \
b'M-SEARCH * HTTP/1.1\r\n' \
b'HOST:239.255.255.250:1900\r\n' \
b'ST:upnp:rootdevice\r\n' \
b'MX:2\r\n' \
b'MAN:"ssdp:discover"\r\n' \
b'\r\n'
# Set up UDP socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
s.bind((b"192.168.2.100",23333))
s.settimeout(2)
s.sendto(msg, (b'239.255.255.250', 1900))
addr = ('192.168.2.1', 1900)
data = b""
try:
while True:
data, addr = s.recvfrom(65507)
print(addr,data)
except socket.timeout:
pass
# data = b'HTTP/1.1 200 OK\r\nCache-Control: max-age=120\r\nDate: Fri, 01 Jan 2010 00:44:16 GMT\r\nExt: \r\nLocation: http://192.168.2.1:1780/InternetGatewayDevice.xml\r\nServer: POSIX UPnP/1.0 linux/5.70.48.16\r\nST: upnp:rootdevice\r\nUSN: uuid:31474a87-67ea-dae4-2f73-f157fb06d22b::upnp:rootdevice\r\n\r\n'
# data = b'HTTP/1.1 200 OK\r\nCache-Control: max-age=3600\r\nST: upnp:rootdevice\r\nUSN: uuid:824ff22b-8c7d-41c5-a131-8c3bad401726::upnp:rootdevice\r\nEXT:\r\nServer: Unspecified, UPnP/1.0, Unspecified\r\nLocation: http://192.168.3.1:56688/rootDesc.xml\r\n\r\n'
device = SSDPDevice(addr, data.decode())
services = device.get_services()
services_id = [services[i].id.split(":")[-1] for i in range(len(services))]
for id in services_id:
service = device[id]
actions = service.get_actions()
for action in actions:
for argument in action.arguments:
print(id,action.name,argument.name)
कई सेवा जानकारियाँ प्राप्त की जा सकती हैं, जिनमें से कुछ निम्नलिखित हैं:
WANIPConn1 AddPortMapping NewRemoteHost
WANIPConn1 AddPortMapping NewExternalPort
WANIPConn1 AddPortMapping NewProtocol
WANIPConn1 AddPortMapping NewInternalPort
WANIPConn1 AddPortMapping NewInternalClient
WANIPConn1 AddPortMapping NewEnabled
WANIPConn1 AddPortMapping NewPortMappingDescription
WANIPConn1 AddPortMapping NewLeaseDuration
WANIPConn1 DeletePortMapping NewRemoteHost
WANIPConn1 DeletePortMapping NewExternalPort
WANIPConn1 DeletePortMapping NewProtocol
WANIPConn1 GetExternalIPAddress NewExternalIPAddress
इन सेवाओं को मोटे तौर पर get श्रेणी, set श्रेणी और कुछ delete श्रेणी की सेवाओं में विभाजित किया जा सकता है। चूँकि UPnP का एक मुख्य उद्देश्य आंतरिक नेटवर्क के डिवाइसों को सार्वजनिक नेटवर्क के डिवाइसों के लिए उजागर करना है, इसके लिए कुछ कॉन्फ़िगरेशन (पोर्ट मैपिंग आदि) की आवश्यकता होती है। चूँकि कॉन्फ़िगरेशन आवश्यक है, इसलिए कॉन्फ़िगरेशन के पैरामीटर और जानकारी अनिवार्य हैं, और ये पैरामीटर वास्तव में set श्रेणी की सेवाओं के पैरामीटर हैं।
चूँकि निर्माता ने सभी सेवाओं को कार्यान्वित नहीं किया है, इसलिए फर्मवेयर को स्वयं रिवर्स करना आवश्यक है। सबसे पहले upnp_mainloop का पता लगाएं।

सभी प्रोसेसिंग तर्क upnp_dispatch में कार्यान्वित हैं। आगे विश्लेषण करने पर ssdp और http के अनुरोध प्रोसेसिंग भाग पाए गए।

ssdp_process एड्रेसिंग के दौरान M-Search अनुरोध से संबंधित है, और upnp_http_process http अनुरोधों के प्रोसेसिंग से संबंधित है। चूँकि सामान्य सेवा कॉल http अनुरोध होते हैं, इसलिए अनुमान लगाया गया कि upnp_http_process में कमजोरी हो सकती है। सेवा कॉल का उदाहरण नीचे दिए गए चित्र में दिखाया गया है।

upnp_http_process में आगे upnp_http_fsm_emgine को कॉल किया जाता है।

आगे विश्लेषण करने पर पता चला कि off_45ab80 पर स्थित कई फ़ंक्शन निष्पादित होते हैं।

इन फ़ंक्शनों में प्रोटोकॉल हेडर को इनिशियलाइज़ करने और पार्स करने की कार्यक्षमता शामिल है। अंतिम फ़ंक्शन upnp_http_fsm_dispatch है, जिसके बारे में अनुमान है कि यह संबंधित सेवा फ़ंक्शन को निष्पादित करता है।

upnp_http_fsm_dispatch में आगे जाने पर पता चला कि यह वास्तव में फ़ंक्शन विधियों को कॉल करता है, लेकिन यह a1 और a2 के आधार पर किया गया फ़ंक्शन कॉल है, इसलिए विशिष्ट कॉल किए गए फ़ंक्शन का निर्धारण नहीं किया जा सकता; गतिशील डीबगिंग की आवश्यकता है।

यदि यह एक सामान्य ssdp एड्रेसिंग अनुरोध है, तो SUB_405B34 और description_process को कॉल किया जाएगा। यदि यह एक सेवा-संबंधित अनुरोध है, तो soap_process को कॉल किया जाएगा। soap_process में अनुरोध हेडर जानकारी के आधार पर query_process या action_process को कॉल किया जाता है।
मुख्य रूप से action_process पर ध्यान केंद्रित करें। सेवा कॉल के अनुरोध हेडर के अनुसार, अनुमान है कि action_process में स्थित soap_control सेवा कॉल से संबंधित है।

soap_control में विशिष्ट फ़ंक्शन जानकारी की पुष्टि के लिए अभी भी गतिशील डीबगिंग की आवश्यकता है।

अंततः गतिशील डीबगिंग के माध्यम से यह निर्धारित किया गया कि sub_414C28 AddPortMapping action से संबंधित है। इसकी फ़ंक्शन कॉल श्रृंखला निम्नलिखित है:
sub_414c28->upnp_portmap_add->upnp_osl_nat_config->strcpy(stack overflow)
हालाँकि, upnp_portmap_add में स्थानीय मशीन के WAN पोर्ट पते की जाँच की गई। चूँकि परीक्षण के दौरान मैंने WAN पोर्ट कॉन्फ़िगर नहीं किया था, इसलिए सीधे nvram से WAN पोर्ट IP सेट कर दिया।

स्टैक ओवरफ्लो के समय प्रोग्राम फ्लो को लाल बॉक्स की ओर नियंत्रित करना आवश्यक है, क्योंकि नीले बॉक्स का फ़ंक्शन ओवरफ्लो हुए स्टैक तक पहुँच जाता है, जिससे RCE से पहले ही प्रोग्राम क्रैश हो जाता है। इसलिए *(a2+11) के मान को 0 पर नियंत्रित करना आवश्यक है। सौभाग्य से, यहाँ का मान नियंत्रणीय है।

चूँकि नवीनतम फर्मवेयर में telnetd उपलब्ध नहीं है, इसलिए रिवर्स शेल प्राप्त करके स्वयं utelnetd अपलोड किया जा सकता है, और फिर telnet सक्षम किया जा सकता है।

देखें: रिवर्स शेल के तरीके