아빠는 나에게 arm을 공부하라고 했는데 난 leg가 더 좋아~!~! 라는 문제이다.... 뭐 어쩌라는건지는 잘 모르겠지만 일단 leg.c와 leg.asm을 다운받아봤다.

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
38
#include <stdio.h>
#include <fcntl.h>
int key1(){
    asm("mov r3, pc\n");
}
int key2(){
    asm(
    "push    {r6}\n"
    "add    r6, pc, $1\n"
    "bx    r6\n"
    ".code   16\n"
    "mov    r3, pc\n"
    "add    r3, $0x4\n"
    "push    {r3}\n"
    "pop    {pc}\n"
    ".code    32\n"
    "pop    {r6}\n"
    );
}
int key3(){
    asm("mov r3, lr\n");
}
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;
}
cs

<leg.c>

(gdb) disass main

Dump of assembler code for function main:

   0x00008d3c <+0>: push {r4, r11, lr}

   0x00008d40 <+4>: add r11, sp, #8

   0x00008d44 <+8>: sub sp, sp, #12

   0x00008d48 <+12>: mov r3, #0

   0x00008d4c <+16>: str r3, [r11, #-16]

   0x00008d50 <+20>: ldr r0, [pc, #104] ; 0x8dc0 <main+132>

   0x00008d54 <+24>: bl 0xfb6c <printf>

   0x00008d58 <+28>: sub r3, r11, #16

   0x00008d5c <+32>: ldr r0, [pc, #96] ; 0x8dc4 <main+136>

   0x00008d60 <+36>: mov r1, r3

   0x00008d64 <+40>: bl 0xfbd8 <__isoc99_scanf>

   0x00008d68 <+44>: bl 0x8cd4 <key1>

   0x00008d6c <+48>: mov r4, r0

   0x00008d70 <+52>: bl 0x8cf0 <key2>

   0x00008d74 <+56>: mov r3, r0

   0x00008d78 <+60>: add r4, r4, r3

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

   0x00008d80 <+68>: mov r3, r0

   0x00008d84 <+72>: add r2, r4, r3

   0x00008d88 <+76>: ldr r3, [r11, #-16]

   0x00008d8c <+80>: cmp r2, r3

   0x00008d90 <+84>: bne 0x8da8 <main+108>

   0x00008d94 <+88>: ldr r0, [pc, #44] ; 0x8dc8 <main+140>

   0x00008d98 <+92>: bl 0x1050c <puts>

   0x00008d9c <+96>: ldr r0, [pc, #40] ; 0x8dcc <main+144>

   0x00008da0 <+100>: bl 0xf89c <system>

   0x00008da4 <+104>: b 0x8db0 <main+116>

   0x00008da8 <+108>: ldr r0, [pc, #32] ; 0x8dd0 <main+148>

   0x00008dac <+112>: bl 0x1050c <puts>

   0x00008db0 <+116>: mov r3, #0

   0x00008db4 <+120>: mov r0, r3

   0x00008db8 <+124>: sub sp, r11, #8

   0x00008dbc <+128>: pop {r4, r11, pc}

   0x00008dc0 <+132>: andeq r10, r6, r12, lsl #9

   0x00008dc4 <+136>: andeq r10, r6, r12, lsr #9

   0x00008dc8 <+140>: ; <UNDEFINED> instruction: 0x0006a4b0

   0x00008dcc <+144>: ; <UNDEFINED> instruction: 0x0006a4bc

   0x00008dd0 <+148>: andeq r10, r6, r4, asr #9

End of assembler dump.

(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.

(gdb)

<leg.asm>


어셈블리 코드를 보니까 그동안 봤던 intel문법이 아닌 조금 생소한 문법이였다. 이게 ARM어셈블리어라고 한다. 그래서 문제에서 arm leg라는 말장난을 친 듯 하다..


일단 c코드 먼저 확인해보자.

key1, key2, key3은 어셈블리어로 되어있으니까 넘기고 main부분을 살펴보면


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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;
}
 
cs


key에다가 정수를 입력받고 key1()+key2()+key3()한 것이 key와 같으면 플래그가 나오는 형식이다.

그리고 main의 arm어셈블리어를 확인해보면


(gdb) disass main

Dump of assembler code for function main:

   0x00008d3c <+0>: push {r4, r11, lr}

   0x00008d40 <+4>: add r11, sp, #8

   0x00008d44 <+8>: sub sp, sp, #12

   0x00008d48 <+12>: mov r3, #0

   0x00008d4c <+16>: str r3, [r11, #-16]

   0x00008d50 <+20>: ldr r0, [pc, #104] ; 0x8dc0 <main+132>

   0x00008d54 <+24>: bl 0xfb6c <printf>

   0x00008d58 <+28>: sub r3, r11, #16

   0x00008d5c <+32>: ldr r0, [pc, #96] ; 0x8dc4 <main+136>

   0x00008d60 <+36>: mov r1, r3

   0x00008d64 <+40>: bl 0xfbd8 <__isoc99_scanf>

   0x00008d68 <+44>: bl 0x8cd4 <key1>

   0x00008d6c <+48>: mov r4, r0

   0x00008d70 <+52>: bl 0x8cf0 <key2>

   0x00008d74 <+56>: mov r3, r0

   0x00008d78 <+60>: add r4, r4, r3

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

   0x00008d80 <+68>: mov r3, r0

   0x00008d84 <+72>: add r2, r4, r3

   0x00008d88 <+76>: ldr r3, [r11, #-16]

   0x00008d8c <+80>: cmp r2, r3


이런식으로 되어있는데 main<+44>부분쯤에 key1 key2 key3을 호출하는 부분을 보면 세 함수 모두 반환값이 r0에 저장되는 것으로 보인다.


이제 key1부터 분석을 해보자. key1의 어셈블리어를 확인해보면


(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.


pc값을 r3에 넣고 그걸 다시 r0에 넣어준다. arm어셈블리어에서 pc란 program counter로 eip와 같은 역할을 한다고 생각하면 된다. 대신 pc레지스터는 현재 실행되는 명령어가 담겨있는 eip와는 달리 다음 실행될 명령어의 주소가 담겨있다고 한다.

그러면 다음명령어가 담겨있는 주소인 8ce0이 key1의 값이 된다.

key1 = 0x8ce0


key2도 확인해보자


(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.


pc값을 r3에 넣고 4를 더한다음에 r3값을 r0에 넣어준다. 여기서의 pc값은 key2+20다음인 8d06일테니 key2값은 8d06+4인 8d0a이다.

key2 = 0x8d0a


마지막 key3을 보자.

(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.


새로운 레지스터인 lr이 보인다. r3에다가 lr의 값을 집어넣고 다시 r0에다가 넣어준다.

lr은 주소를 점프했을 때 다시 돌아와서 실행할 주소를 가르킨다. 간단히 리턴할 주소를 보관하는 레지스터라고 생각하면 될 것 같다. 

main함수의 어셈블리를 확인하면 key3이 호출되고 돌아간 주소를 확인할 수 있다. main+68로 돌아가니까 key3의 값은 8d80이다.

key3 = 0x8d80


이 key값들을 전부 더해주면 0x8ce0 + 0x8d0a + 0x8d80 = 0x1a76a = 108394이다.




아니라고한다...


http://recipes.egloos.com/4982170


이 블로그에서 본 바로는 arm은 명령을 실행할 때

1. fetch

2. decode

3. execute

4. write

와 같은 단계로 이루어져 있는데 pc는 여기서 fetch단계를 거치고 있는 명령어의 주소를 저장하고 있다.

만약 어떤 명령어가 3단계인 실행단계에 있다면 다음 명령어는 2단계인 decode단계에 있고 그 다음명령어가 fetch단계에 존재하는 것이다.


그러므로 key1과 key2의 값들의 pc값을 각각 수정해주면 key1의 pc값은 0x8ce4고 key2의 pc값은 0x8d0c가 된다.

그렇게 하면 key = 108400


플래그가 나왔다~

'pwnable > pwnable.kr' 카테고리의 다른 글

[pwnable.kr] shellshock  (0) 2019.02.27
[pwnable.kr] mistake  (0) 2019.02.24
[pwnable.kr] input  (0) 2019.02.18
[pwnable.kr] random  (0) 2019.01.15
[pwnable.kr] passcode  (0) 2019.01.13

+ Recent posts