일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 정보보안기사
- webhacking
- Shell code
- 정보처리기사 실기
- 워게임
- webhacking.kr
- Buffer Overflow
- Payload
- System
- Spring Framework
- PWN
- Pwnable.kr
- Spring MVC
- pwnable
- 해킹
- BOF
- system hacking
- 운영체제
- Spring
- SQL
- hacking
- OS
- Lord of BOF
- stack overflow
- Operating System
- 웹해킹
- 네트워크
- wargame
- LOB
- 정보보안기사 실기
- Today
- Total
DongDD's IT
[pwnable.kr] leg 본문
[pwnable.kr] leg
Problem
arm에 대한 것을 배웠다고 되어있었다.
arm에 관련된 문제인 것 같았고 leg.c 파일과 leg.asm파일을 다운받을 수 있게 되어있었다.
먼저 ssh를 통해 접속해보았다.
ssh를 통해 접속하니 부트하는 것 같은 메시지들이 떴고 최종 부팅 후에는 다음과 같은 파일들을 볼 수 있었다.
leg라는 실행 파일이 있었고 먼저 소스 코드를 확인해보았다.
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 |
먼저 메인에서는 key라는 값을 사용자에게 입력 받고 이 값이 key1()함수와 key2()함수, key3()함수 return값을 더한 값과 일치하면 flag를 출력하게 되어있었다.
각 함수는 어셈블리 코드로 작성되어 있었다.
key1()함수는 "mov r3,pc" 명령어로 구성되어있었고 key2()함수는 복잡해 보이는 코드들로 구성되어 있었다.
key3()함수는 "mov r3, lr" 명령어로 구성되어있었다.
Solution
c코드만으로는 정답을 해결하는 것이 어려워 보여 주어진 asm파일을 분석해보았다.
asm 파일은 크게 main, key1, key2, key3 함수 4개로 구성되어 있었다.
main
먼저 main()함수에서는 key1()함수, key2() 함수, key3() 함수를 호출한다. 함수 호출 이후 'mov r4, r0'와 'mov r4, r0'가 있는 것으로 보아 함수들의 return 값이 r0에 저장되는 것을 알 수 있다.
먼저 key1()함수의 return값이 r4에 저장되고 key2()함수의 return값이 r3에 저장된 후 r4에 더해진다.
key3()함수의 return값이 r3에 저장되고 r4와 함께 더해져 r2에 저장되고 사용자가 입력한 값을 r3로 불러와 r2와 r3를 비교하는 형식으로 되어있다.
key1()
key1()함수에서는 pc값을 r3에 저장하고 r0로 mov해준다.
즉, pc값이 key1()함수의 return값인 것을 알 수 있다.
처음에는 단순히 pc라 해서 return값에 다음 명령어의 실행 주소인 0x8ce0을 넣어주고 다른 return값들을 모두 더해서 시도했지만 실패했다.
arm에 대한 것을 찾아보다가 일반적인 intel과는 달리 fetch -> decode -> execute 과정을 거치게 되어 pc값이 다르다는 것을 알게 되었다.
즉, "mov r3, pc"가 decode될 때는 0x8ce0의 명령어가 fetch되고 있지만 "mov r3, pc"가 execute될 때, "sub sp, r11, #0"이 fetch되고 있으므로 해당 명령어 이후의 두번째 명령의 주소(0x8ce4)가 pc값으로 설정된다는 것이다.
pc : 0x8ce4
key1() return 값 : 0x8ce4
key2()
key2() 함수에서는 pc값을 r3에 넣어주고 4를 더해준 후 r3를 r0로 mov해준다.
여기서도 key1()함수와 마찬가지로 "mov r3, pc" 명령이 execute될 때의 fetch 하는 명령어의 주소가 pc값으로 설정된다.
"mov r3, pc" 명령이 execute될 때, "push {r3}" 명령이 fetch 되므로 pc에는 0x8d08값이 들어간다.
그 이후에 add명령을 통해 4를 더해준다.
pc : 0x8d08
key2() return 값 : 0x8d0c(0x8d08+4)
key3()
key3() 함수에서 lr 레지스터의 값을 r3에 넣어주고 r0로 mov해준다.
lr 레지스터에 대해서 찾아보니 함수 복귀 주소가 담긴 레지스터라고 한다.
즉, main()함수에서 key3()함수를 호출하고 난 후의 주소를 담고 있다.
lr : 0x8d80
key3() return 값 : 0x8d80
************** Answer & Flag **************
key1() : 0x8ce4(36068)
key2() : 0x8d0c(36108)
key3() : 0x8d80(36224)
key1()+key2()+key3() : 108400
Flag : My daddy has a lot of ARMv5te muscle!
'Wargame > pwnable.kr' 카테고리의 다른 글
[pwnable.kr] shellshock (0) | 2018.06.18 |
---|---|
[pwnable.kr] mistake (0) | 2018.06.14 |
[pwnable.kr] input (0) | 2018.04.19 |
[pwnable.kr] random (0) | 2018.04.02 |
[pwnable.kr]passcode (0) | 2018.03.28 |