package de.tudarmstadt.informatik.hostage.protocol; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import de.tudarmstadt.informatik.hostage.wrapper.ByteArray; public class MySQL implements Protocol{ private enum STATE { NONE, CONNECTED, LOGIN_INFO, AUTHENTICATE, LOGGED_IN, CLOSED } private STATE state = STATE.NONE; private byte[] request; @Override public List processMessage(ByteArray request) { List response = new ArrayList(); if(request != null) { this.request = request.get(); } switch(state) { case NONE: response.add(new ByteArray(greeting())); state = STATE.CONNECTED; break; case CONNECTED: response.add(new ByteArray(responseOK())); state = STATE.LOGIN_INFO; break; case LOGIN_INFO: if(this.request[4] == 0x01) { response = null; state = STATE.CLOSED; } else if(this.request[4] == 0x03) { response.add(new ByteArray(response())); } else { response.add(new ByteArray(responseError())); } break; case AUTHENTICATE: break; case LOGGED_IN: break; default: state = STATE.CLOSED; break; } return response; } @Override public TALK_FIRST whoTalksFirst() { return TALK_FIRST.SERVER; } @Override public String toString(){ return "MySQL"; } @Override public int getPort() { return 3306; } @Override public boolean isClosed() { return state == STATE.CLOSED; } private byte[] wrapPckt(byte[] pckt) { byte[] buff = ByteBuffer.allocate(4).putInt(pckt.length).array(); byte[] pcktLength = {buff[3], buff[2], buff[1]}; byte[] pcktNumber = new byte[1]; if(request != null) pcktNumber[0] = (byte) (request[3] + 1); else pcktNumber[0] = 0x00; byte[] response = concat(pcktLength, pcktNumber, pckt); return response; } private byte[] greeting() { byte[] protocol = {0x0a}; String version = "5.5.31-0+wheezy1"; byte[] versionFin = {0x00}; byte[] thread = {0x2a, 0x00, 0x00, 0x00}; byte[] salt = {0x44, 0x64, 0x49, 0x7e, 0x60, 0x48, 0x25, 0x7e, 0x00}; byte[] capabilities = {(byte) 0xff, (byte) 0xf7}; byte[] language = {0x08}; byte[] status = {0x02, 0x00}; byte[] unused = {0x0f, (byte) 0x80, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; byte[] salt2 = {0x6c, 0x26, 0x71, 0x2c, 0x25, 0x72, 0x31, 0x3d, 0x7d, 0x21, 0x26, 0x3b, 0x00}; String payload = "mysql_native_password"; byte[] fin = {0x00}; byte[] response = concat(protocol, version.getBytes(),versionFin, thread, salt, capabilities, language, status, unused, salt2, payload.getBytes(), fin); return wrapPckt(response); } private byte[] responseOK() { byte[] affectedRows = {0x00, 0x00, 0x00}; byte[] status = {0x02, 0x00}; byte[] warnings = {0x00, 0x00}; byte[] response = concat(affectedRows, status, warnings); return wrapPckt(response); } private byte[] response() { // 4 packets to respond byte[] pckt0 = {0x01, 0x00, 0x00, 0x01, 0x01}; byte[] pckt1 = {0x27, 0x00, 0x00, 0x02, 0x03, 0x64, 0x65, 0x66, 0x00, 0x00, 0x00, 0x11, 0x40, 0x40, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x0c, 0x21, 0x00, 0x18, 0x00, 0x00, 0x00, (byte) 0xfd, 0x00, 0x00, 0x1f, 0x00, 0x00}; byte[] pckt2 = {0x05, 0x00, 0x00, 0x03, (byte) 0xfe, 0x00, 0x00, 0x02, 0x00}; byte[] pckt3 = {0x09, 0x00, 0x00, 0x04, 0x08, 0x28, 0x44, 0x65, 0x62, 0x69, 0x61, 0x6e, 0x29}; byte[] pckt4 = {0x05, 0x00, 0x00, 0x05, (byte) 0xfe, 0x00, 0x00, 0x02, 0x00}; byte[] response = concat(pckt0, pckt1, pckt2, pckt3, pckt4); return response; //no wrapPckt() needed, because packets already have length and number } private byte[] responseError() { byte[] fill1 = {(byte) 0xff}; byte[] code = {0x17, 0x04}; byte[] fill2 = {0x23}; String state = "08S01"; String msg = "Unknown command"; byte[] response = concat(fill1, code, fill2, state.getBytes(), msg.getBytes()); return wrapPckt(response); } private byte[] concat(byte[]...bytes) { int newSize = 0; for(byte[] b: bytes) newSize += b.length; //get total new size byte[] dst = new byte[newSize]; //create new array with new size int currentPos = 0; int newPos; for(byte[] b:bytes) { //for each elem b out of bytes newPos = b.length; //get b.length and new position System.arraycopy(b, 0, dst, currentPos, newPos); //copy b in dst from currentPos to newPos currentPos += newPos; //increase currentPos to newPos + currentPos } return dst; } @Override public boolean isSecure() { return false; } @Override public Class getType() { return ByteArray.class; } }