힌트가 연산자 우선순위란다.



들어가보자.





이전에 풀었던 문제와 유형은 같은 것 같다.


mistake를 실행해서 flag를 출력시키기


mistake.c를 살펴보자





password 파일을 열고 PW_LEN(10bytes)만큼 읽어온다.


그리고 사용자한트 password를 입력받고 이 값의 각 문자를 1과 xor 연산을 한 결과를


password 파일에서 읽은 값과 비교하고 일치하면 플래그를 출력한다.



처음엔 코드상으로 뭐가 문제인지 모르겠어서 일단 실행을 해봤다.





뭘까..  'do not bruteforce...'가 출력된 이후에 사용자의 입력이 들어가는 부분이 있다..


입력을 한 이후에 'input password :'가 출력된다.


다시 코드를 보자




자세히 살펴보니 네모 부분에서 문제가 있었는데..


힌트에서 언급한 연산 우선순위에 의해서 발생하는 문제였다






이부분을 보면 개발자의 의도는


open 함수가 반환한 fd(file descriptor)를 fd 변수에 담을 생각이었을 것이다.


open 함수는 열기에 실패할 경우 -1을 반환하기 때문에  


' < 0 ' 이 부분으로 예외처리를 하려고 했을 것인데..


연산 우선순위를 고려하면 이렇게 하면 안된다..






연산 우선순위다.


할당(assignment) 연산의 우선순위는 17위다. 반면에 비교 연산의 우선순위는 9위.


따라서 할당과 비교가 같이 오면 비교를 먼저 한다는 뜻이다.




따라서 네모친 부분이 먼저 실행되는 것이고


반환된 password 파일에 대한 fd의 값은 실패하지 않을 경우는 양수가 반환되므로 당연히 저 부분은 false.


비교 연산은 True면 1, False면 0을 반환하므로


fd에는 결국 0이 할당되게 되는 것이다.


그럼 fd는 표준 입력과 같게 되고




여기서 fd로부터 10 글자 읽어오는 구문은


표준 입력으로 10 글자를 읽어오는 것이다.


따라서 우리가 입력한 10 글자의 문자와


이후 scanf로 입력하는 password의 각 문자를 xor 1 한 값과 일치하면 플래그가 출력되는 것이다.









pwntools


1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import *
 
id   = 'mistake'
host = 'pwnable.kr'
port = 2222
pw   = 'guest'
= ssh(id, host, port=port, password=pw)
 
res = s.run('./mistake')
res.sendline('1111111111')
res.recvuntil(':')
res.sendline('0000000000')
res.interactive()             
cs


'CTF 공부 > Pwnable.kr' 카테고리의 다른 글

11. coin1  (0) 2018.10.01
10. shellshock  (0) 2018.09.26
8. leg  (0) 2018.09.25
7. input  (0) 2018.09.25
6. random  (0) 2018.09.16


이번 문제는 arm 어셈블리 관련 문제이다.


URL에서 소스코드와 어셈블리 코드를 다운받고 열어봤다.




leg.c 파일이다.


key를 입력받고 key1, key2, key3 함수를 호출한 반환 값들을 모두 더하고 key와 비교한다.


key가 일치하면 플래그가 출력되므로 우리는 key1, key2, key3 함수의 반한 값을 알아내면 된다.





key1 함수의 어셈블리 코드이다.


arm에서는 함수를 호출할 때 레지스터를 이용하고


r0~r3 레지스트리가 파라미터 패싱에 사용된 것으로 기억한다. 


예를들면

printf("%d", 3);


이런 코드를 컴파일하면 ia-32 어셈블리에서는 스택을 이용해서 파라미터 패싱을 한다.


esp로 스택의 공간을 벌리고 "%d"에 해당하는 문자열을 push, 3을 push, 함수의 반환 주소를 push


그러나 arm에서는


r0 레지스터에 "%d", r1 레지스터에 3을 넣고 함수를 호출한다. 함수의 반환 주소는 lr 레지스터에 저장된다.


함수의 반환 값은 r0 레지스터에 담고 함수가 종료된다.



0x0008ce0 주소의 명령어


 mov  r0, r3


여기서 r0 레지스터에 r3의 값을 담게되고


이후 r0에는 어떠한 값을 넣지 않으므로 결과적으로 r3의 값이 함수의 반환 값이다.


r3에서는 바로 위에서 pc(program counter)의 값을 담았다.


pc는 다음 실행할 명령어의 주소를 갖고있으므로 0x0008cdc의 다음 명령어의 주소인 0x0008ce0가 r0에 들어갈 것이다.




일단 key1의 반환 값은 "0x0008ce0"





key2 함수이다.


마찬가지로 가장 마지막으로 r0 레지스터를 건드는 것부터 역추적을 해보면


0x0008d10에서 mov  r0, r3 명령어로 r3의 값을 r0로 옮긴다.


r3에는 무엇이 있는지 올라가보면


0x0008d04에서  mov r3, pc 명령어로 pc의 값을 r3에 옮기고 바로 다음에


0x0008d06에서  adds r3, #4 명령어로 r3에 4를 더한 값을 다시 저장한다.


그 이후는 r3의 값을 변경하지 않는다.


즉 r3에는


0x0008d04에서의 pc이므로 0x0008d06와 4를 더한 값인 0x0008d0a가 담겨있을 것이다.



key2의 반환 값은 "0x0008d0a"





key3 함수이다.


여기서는 0x0008d28에서  mov  r3, lr 명령어를 수행하고 이 r3의 값이 다음 명령어에서 r0에 담기고 함는 종료된다.


lr 레지스터는 앞서 말했듯이 함수의 반환 주소를 담고있으므로 main으로 돌아가 함수의 반환 주소를 확인해보면


lr 레지스터의 값을 알 수 있다.





main 함수의 어셈블리 코드이다.


key3를 호출하는 부분


0x00008d7c에서 key3가 호출되므로 lr 레지스터의 값은 그 다음 명령어인


0x00008d80일 것이다



key3의 반환 값 "0x00008d80"




key1 + key2 + key3 =  0x0008ce0 + 0x0008d0a + 0x00008d80







이제 공격을 해보자.




안된다.


처음엔 계산을 잘못한 줄 알고 다시했는데.. 그래도 안된다.



이유는 친절하게 여기서 알아볼 수 있다.



http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0084f/ch01s01s01.html






몰랐는데.. ARM은 3-stage pipeline이란 걸 사용하는데 쉽게 설명하면 명령어를 실행할 때


Fetch -> Decode -> Execute 단계를 거친단다.


즉 명령어를 실행할 땐 이미 세 번째 단계인 것이고


다음 명령어는 Decode 단계


그 다음 명령어는 Fetch 단계이다.


즉 PC 계산이 잘못된 것인데.. 이걸 적용해서 PC를 다시 계산해보면





PC를 사용했던 key1 함수에서


네모로 표시된 명령어를 수행할 때 PC는 다음 다음 명령어(화살표)를 가리킨다.


따라서 r3에 들어간 pc의 값은 0x0008ce4이다.




마찬가지로 key2 함수에서


네모로 표시된 명령어를 수행할 때 pc는 화살표 부분이고


따라서 네모 부분에서 r3에 들어간 pc의 값은 0x0008d08이고 여기서 4 더한 값인


0x0008d0c가 key2의 반환 값이 된다.



다시 계산을 해보면


key1 + key2 + key3 = 0x0008ce4 + 0x0008d0c + 0x0008d80









'CTF 공부 > Pwnable.kr' 카테고리의 다른 글

10. shellshock  (0) 2018.09.26
9. mistake  (0) 2018.09.26
7. input  (0) 2018.09.25
6. random  (0) 2018.09.16
5. passcode  (0) 2018.09.15


'CTF 공부 > Pwnable.kr' 카테고리의 다른 글

9. mistake  (0) 2018.09.26
8. leg  (0) 2018.09.25
6. random  (0) 2018.09.16
5. passcode  (0) 2018.09.15
4. flag  (0) 2018.09.13

+ Recent posts