[문제]

 


[풀이]

소스코드 분석 - leg.c

#include <stdio.h>
#include <fcntl.h>
int key1(){
	asm("mov r3, pc\\n"); //pc 값을 r3에 저장
}
int key2(){
	asm(
	"push	{r6}\\n" 
	"add	r6, pc, $1\\n" //pc 값에 1더해서 r6에 저장
	"bx	r6\\n" //r6으로 분기
	".code   16\\n" //r6 == 16?
	"mov	r3, pc\\n" //pc 값을 r3에 저장
	"add	r3, $0x4\\n" //r3 + 0x4한 값을 r3에 저장
	"push	{r3}\\n" //r3 push
	"pop	{pc}\\n" //pc pop
	".code	32\\n" //r3 == 32?
	"pop	{r6}\\n" //r6 pop
	);
}
int key3(){
	asm("mov r3, lr\\n"); //lr 값을 r3에 저장(되돌아갈 주소 값)
}
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-3은 ARM 어셈블리로 작성된 것으로 보임
  • main 함수에서 key1-3 함수 호출 후 반환된 값을 합한 값을 사용자가 입력해주면(10진수로) flag를 출력함

 

소스코드 분석 - .asm(main)

(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.
  • 각 함수를 호출한 반환 값은 각각 main+48, main+56, main+68에서 레지스터로 옮겨짐
  • 공통적으로 반환 값은 r0에 담김

 

Exploit Algorithm

💡 c소스코드에서 분석한 내용과 어셈블리 코드를 비교하여 r0 레지스터의 흐름을 따라가면 될 것

 

소스코드 분석 - .asm(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.
  • 분석
    • key1+4: sp 값을 r11에 저장
    • key1+8: pc 값을 r3에 저장
    • key1+12: r3 값을 r0에 저장
    • key1+16: r11 값을 sp에 저장
    • key1+20: r11 pop
    • key1+24: lr로 분기(main 함수로 돌아가는 듯)
  • r0에 담기는 값은 pc 값임을 알 수 있음
  • pc(Program Counter)는 다음으로 실행할 코드 주소를 담고 있는데 0x4만큼 자동적으로 증가되게 설계되어 있음
    • 즉, key1+8에서의 pc 값은 0x8ce0일 것으로 보이나 +0x4하여 0x8ce4로 생각해야 함

 

소스코드 분석 - .asm(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.
  • 분석
    • key2+4: sp 값을 r11에 저장
    • key2+8: r6 push
    • key2+12: pc에 1 더해서 r6에 저장
    • key2+16: r6으로 분기
    • key2+20: pc 값을 r3에 저장
    • key2+22: r3에 4더해서 저장
    • key2+24: r3 push
    • key2+26: pc pop
    • key2+28: r6 pop
    • key2+32: r3 값을 r0에 저장
    • key2+36: r11 값을 sp에 저장
    • key2+40: r11 pop
    • key2+44: lr로 분기(main 함수로 돌아가는 듯)
  • r0에 담기는 값은 r3로, 이는 pc+4임
    • 즉, 0x8d08+4한 0x8d0c가 반환되는 값임!

 

소스코드 분석 - .asm(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.
  • 분석
    • key3+4: sp 값을 r11에 저장
    • key3+8: 리턴할 값을 r3에 저장
    • key3+12: r3 값을 r0에 저장
    • key3+16: r11 값을 sp에 저장
    • key3+20: r11 pop
    • key3+24: lr로 분기(main 함수로 돌아가는 듯)
  • r0에 저장되는 값은 main 함수로 리턴할 주소 값을 의미함
    • 즉, key3 호출 후 main+68로 돌아가야 하는데, 해당 주소인 0x8d80을 의미!

 

문제 해결

💡 0x8ce4+0x8d0c+0x8d80 = 0x1a770(108400)

→ scanf에서 %d로 사용자 입력을 받고 있으므로 10진수인 108400을 입력해주면 됨!

 

핵심

 💡 ARM에서의 PC값은 다음 주소에서 +4 해야한다!

flag

🍒 My daddy has a lot of ARMv5te muscle!

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

[Pwnable.kr] shellshock  (0) 2022.10.15
[Pwnable.kr] mistake  (2) 2022.10.15
[Pwnable.kr] input  (2) 2022.10.15
[Pwnable.kr] random  (0) 2022.10.14
[Pwnable.kr] passcode  (0) 2022.10.14

+ Recent posts