System&Write up/Pwnable.kr

[pwnable.kr] Toddler's Bottle - leg

Jubil 2018. 1. 15. 17:46
반응형

[pwnable.kr] Toddler’s Bottle – leg

 


 


 

 

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

int main(){

    int key=0;

    printf("Daddy has very strong arm! : ");

    scanf("%d"&key);

    if( (key1()+key2()+key3()) == key ){

        printf("Congratz!\n");

        int fd = open("flag", O_RDONLY);

        char buf[100];

        int r = read(fd, buf, 100);

        write(0, buf, r);

    }

    else{

        printf("I have strong leg :P\n");

    }

    return 0;

}

Colored by Color Scripter

cs

 

 

code를 보면 key를 입력 받고, key1, key2, key3 세 함수의 반환 값과 같다면 flag를 출력하는 것 같습니다.

 

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

(gdb) disass key1

Dump of assembler code for function key1:

   0x00008cd4 <+0>:    push    {r11}        ; (str r11, [sp, #-4]!)

   0x00008cd8 <+4>:    add    r11, sp, #0

   0x00008cdc <+8>:    mov    r3, pc

   0x00008ce0 <+12>:    mov    r0, r3

   0x00008ce4 <+16>:    sub    sp, r11, #0

   0x00008ce8 <+20>:    pop    {r11}        ; (ldr r11, [sp], #4)

   0x00008cec <+24>:    bx    lr

End of assembler dump.

(gdb) disass key2

Dump of assembler code for function key2:

   0x00008cf0 <+0>:    push    {r11}        ; (str r11, [sp, #-4]!)

   0x00008cf4 <+4>:    add    r11, sp, #0

   0x00008cf8 <+8>:    push    {r6}        ; (str r6, [sp, #-4]!)

   0x00008cfc <+12>:    add    r6, pc, #1

   0x00008d00 <+16>:    bx    r6

   0x00008d04 <+20>:    mov    r3, pc

   0x00008d06 <+22>:    adds    r3, #4

   0x00008d08 <+24>:    push    {r3}

   0x00008d0a <+26>:    pop    {pc}

   0x00008d0c <+28>:    pop    {r6}        ; (ldr r6, [sp], #4)

   0x00008d10 <+32>:    mov    r0, r3

   0x00008d14 <+36>:    sub    sp, r11, #0

   0x00008d18 <+40>:    pop    {r11}        ; (ldr r11, [sp], #4)

   0x00008d1c <+44>:    bx    lr

End of assembler dump.

(gdb) disass key3

Dump of assembler code for function key3:

   0x00008d20 <+0>:    push    {r11}        ; (str r11, [sp, #-4]!)

   0x00008d24 <+4>:    add    r11, sp, #0

   0x00008d28 <+8>:    mov    r3, lr

   0x00008d2c <+12>:    mov    r0, r3

   0x00008d30 <+16>:    sub    sp, r11, #0

   0x00008d34 <+20>:    pop    {r11}        ; (ldr r11, [sp], #4)

   0x00008d38 <+24>:    bx    lr

End of assembler dump.

Colored by Color Scripter

cs

 

 

 

r11ebp의 역할인 것 같습니다.

r0은 함수가 끝날 때마다 넣어주는 걸 보니 함수의 반환 값을 저장하는 것 같습니다.

 

key1 함수에서는,

pcr3에 넣고, r3 r0에 넣습니다. pc 값을 알면 될 것 같습니다.

 

key2 함수에서는,

pcr3에 넣고, r34를 더합니다. 그리고 r3r0에 넣습니다. pc + 4의 값이 되겠네요.

 

key3 함수에서는,

lrr3에 넣고, r3r0에 넣습니다. lr 값을 알면 될 것 같습니다.

 

 

그렇다면 pclr을 알아야합니다.

 

우선 cpu에는 명령 주기가 있습니다. fetch -> decode -> execute 이게 반복적으로 이뤄집니다. 예전에는 하나의 명령이 저 주기를 다 거친 후에 다음 명령을 실행했지만, 지금은 pre-fetch라고 해서, fetch 후에 다음 명령 fetch가 바로 실행됩니다.

 

참고로 fetch는 다음과 같이 이뤄집니다.

 

MAR <- [PC]

PC  <- [PC] + 1 ; MDR <- [Memory] address

CIR  <- [MDR]

 

그리고 decode되고 execute가 일어나는데, 그동안 fetch도 같이 진행되어 pc <- [pc] +1가 두 번 더 실행됩니다. (두 번 더 실행되지만, pcexecute할 때 시작된 fetch를 가리키고 있어서 다다음 명령을 가리킴.)

 

그래서 명령이 execute될 때에, pc 레지스터는 다다음 명령을 가리키게 됩니다.

 


 

이렇게 말입니다.

https://youtu.be/jFDMZpkUWCw

 

 

lr 레지스터는 return address라고 생각하면 될 것 같습니다.

 

 

이제 문제를 풀도록 하겠습니다.

 

1

2

3

0x00008cdc <+8>:    mov    r3, pc

0x00008ce0 <+12>:    mov    r0, r3

0x00008ce4 <+16>:    sub    sp, r11, #0

cs

 

key1 함수에서 0x8cdc에서 mov 명령이 실행되므로 pc 값은 3번째 라인 0x8ce4 = 36068.

 

 

1

2

3

0x00008d04 <+20>:    mov    r3, pc

0x00008d06 <+22>:    adds    r3, #4

0x00008d08 <+24>:    push    {r3}

cs

 

key2 함수에서 0x8d04에서 mov 명령을 실행했으니 pc 값은 3번째 라인 0x8d08 = 36104.

여기에 4을 더하니 36108가 됩니다.

 

 

1

2

0x00008d7c <+64>:    bl    0x8d20 <key3>

0x00008d80 <+68>:    mov    r3, r0

cs

 

main 함수에서 key3을 호출하는 부분입니다.

return address2번째 라인 0x8d80 = 36224가 됩니다.

 

다 더하면 36068 + 36108 + 36224 = 108400입니다.

 

 


 

감사합니다.

반응형