미역줄기의 이모저모

pwnable.kr leg 풀이 본문

Hacking/포너블.kr 문제풀이

pwnable.kr leg 풀이

미역줄기줄기 2024. 2. 1. 18:27
728x90
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

 

 

순서대로,

  1. bl 0x8cd4 <key1>: bl은 분기 명령어로, 0x8cd4 주소에 있는 key1 함수를 호출
  2. mov r4, r0: key1 함수의 반환값(레지스터 r0에 저장됨)을 r4 레지스터로 복사
  3. bl 0x8cf0 <key2>: 0x8cf0 주소에 있는 key2 함수를 호출
  4. mov r3, r0: key2 함수의 반환값을 r3 레지스터로 복사
  5. add r4, r4, r3: r4에는 이전에 계산한 key1의 결과와 key2의 결과를 더한 값이 저장
  6. bl 0x8d20 <key3>: 0x8d20 주소에 있는 key3 함수를 호출
  7. mov r3, r0: key3 함수의 반환값을 r3 레지스터로 복사
  8. add r2, r4, r3: r2에는 이전에 계산한 결과(key1와 key2의 합)와 key3의 결과를 더한 값이 저장
  9. ldr r3, [r11, #-16]: r11 레지스터에서 오프셋 -16에 있는 값을 r3 레지스터에 로드
  10. 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