미역줄기의 이모저모
pwnable.kr leg 풀이 본문
int main(){
int key=0;
printf("Daddy has very strong arm! : ");
scanf("%d", &key);
풀이를 시작하기에 앞서,, 저는 시스템 해킹에 대한 지식이 많지 않아서 틀린 생각을 갖고 풀 수 있습니다
혹시 풀이 과정중에 잘못된 개념이 있다면,, 알려주시면 정말 감사하겠습니다
두개의 다운로드 파일은 설치합니다
$ wget http://pwnable.kr/bin/leg.c
$ wget http://pwnable.kr/bin/leg.asm
$ cat leg.c
leg.c 코드 확인!
#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;
}
key1(), key2(), key3()의 함수를 실행 한 뒤 각각의 return 값을 더해 key 값과 비교 하는군요
key1(), key2(), key3()를 인라인 어셈블리어로 작성을 했네요
그렇다면 일반적으로 우리가 보아온 intel 계열이 아니라 ARM 계열의 어셈블리어!!
leg.asm을 확인해봅시당
$ cat leg.asm
main, key1, key2, key3별로 나눠서 보겠습니다.
main이 꽤 긴데 key1,2,3과 관련된 부분만 보면,
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
순서대로,
- bl 0x8cd4 <key1>: bl은 분기 명령어로, 0x8cd4 주소에 있는 key1 함수를 호출
- mov r4, r0: key1 함수의 반환값(레지스터 r0에 저장됨)을 r4 레지스터로 복사
- bl 0x8cf0 <key2>: 0x8cf0 주소에 있는 key2 함수를 호출
- mov r3, r0: key2 함수의 반환값을 r3 레지스터로 복사
- add r4, r4, r3: r4에는 이전에 계산한 key1의 결과와 key2의 결과를 더한 값이 저장
- bl 0x8d20 <key3>: 0x8d20 주소에 있는 key3 함수를 호출
- mov r3, r0: key3 함수의 반환값을 r3 레지스터로 복사
- add r2, r4, r3: r2에는 이전에 계산한 결과(key1와 key2의 합)와 key3의 결과를 더한 값이 저장
- ldr r3, [r11, #-16]: r11 레지스터에서 오프셋 -16에 있는 값을 r3 레지스터에 로드
- cmp r2, r3: r2와 r3을 비교
최종적으로 더한 값은 r2에 있겠네요
이제 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.
1.0x00008cdc <+8>: mov r3, pc: pc라는 값을 r3에 넣고
2. 0x00008ce0 <+12>: mov r0, r3: r3를 r0에 넣었습니다.
그러면 pc라는 값이 key1의 값이 되겠네요.
pc는,, 다다음번째 명령어의 주소를 담고있다고 합니다. (자세한 개념은 따로 정리해서 업로드할 예정)
그럼 지금 실행중인 주소는 뭐지?
int key1(){
asm("mov r3, pc\n");
}
0x00008cdc <+8>: mov r3, pc !! 0x00008cdc가 현재 수행중인 주소구나
그럼 다다음 주소는 0x00008ce4가 되겠네요
그럼 key1의 값은 0x00008ce4
이제 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.
0x00008d04 <+20>: mov r3, pc: pc를 r3에 복사!
0x00008d06 <+22>: adds r3, #4: r3에 4를 더하기
0x00008d10 <+32>: mov r0, r3: r3를 r0에 복사!
pc를 구해보자!
-- 뇌피셜 시작(고수님들이 보기에 틀렸다면 제발 알려주세요) --
밑에서부터 보면 r0에 r3의 값이 들어가고, r3의 값에 4가 더해졌고,
결국 r3는 PC(0x8d08)의 값이다..!
근데 여기에 4를 더했으니 key2는 0x8d08 + 4 = 0x8d0c
거의 다 왔다...! 이제 key3을 구해봅시다
int key3(){
asm("mov r3, lr\n");
}
(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에, r3의 값을 r0 넣고 리턴! lr을 구하면 되겠네요
lr은 무엇이냐! 바로 함수가 끝나면 리턴되는 주소를 말합니다. 그럼 main으로 다시 가봐야겠네요!
0x00008d7c <+64>: bl 0x8d20 <key3>
0x00008d80 <+68>: mov r3, r0
0x00008d84 <+72>: add r2, r4, r3
그럼 key3가 호출된 명령어 다음 주소인 0x8d80이 되겠네요. 와 진짜 어렵다
key3의 값은 0x8d80
다 구했습니다.
key1 | 0x8ce4
key2 | 0x8d0c
key3 | 0x8d80
다 더하면! 0x1a770입니다. 이제 입력 해보실까 ㅋ
flag: I have string leg :P
인줄 알았으나...!!!!
int main(){
int key=0;
printf("Daddy has very strong arm! : ");
scanf("%d", &key);
정수형으로 입력해야 하네요!!
그렇다면 108400으로 입력하겠습니다
flag: My daddy has a lot of ARMv5te muscle!
감사합니다.
'Hacking > 포너블.kr 문제풀이' 카테고리의 다른 글
pwnable.kr cmd1 풀이 (1) | 2024.02.02 |
---|---|
pwnable.kr lotto 풀이 (0) | 2024.02.01 |
pwnable.kr blackjack 풀이 (0) | 2024.02.01 |
pwnable.kr shellshock 풀이 (0) | 2024.02.01 |
pwnable.kr mistake 풀이 (0) | 2024.02.01 |