-
[02-11 공부정리(Chaining RTL 정리)]공부정리 2018. 2. 11. 01:10
오늘은 protostar Stack6~7번을 풀었다.
6번은 RTL을 7번은 Chaining RTL을 이용해서 풀었다.
7번같은 경우는 ASLR이 걸려있는 상황이라면 ROP를 이용해야 하는 문제였다.
내일은 ASLR이 걸려있는 상태라고 가정하고 ROP로 문제를 풀어볼 생각이다.
자 그럼 오늘 공부한 부분들을 정리하도록 하겠다.
[Chaining RTL]
RTL공격을 할때 System( )뒤에 dummy값으로 "AAAA"를 준 적이 있다.
RTL 정리할 때도 말했지만 dummy값 부분은 의미없는 부분이 아니다.
system( )가 끝나고 복귀할 주소가 저장되어 있는 공간이다.
하지만, 우리는 /bin/sh을 따내면 그 뒤 상황은 어디로 복귀하던 상관이 없기에 "AAAA"라는 dummy값을 준 것이다.
Chaining RTL은 저 부분에 dummy값 대신 실제 함수주소를 넣어 연속적으로 RTL공격을 하는 공격기법이다.
여기서 가젯이라는 개념을 알아야 Chaining RTL공격을 할 수있다.
[Gadget이 왜 필요한가?]
우리가 연속적으로 함수를 호출한다고 해서 무작정 dummy값부분에 다음 함수주소를 넣으면 안된다.
왜 그런지 스택을 보면서 얘기해보자
buf[64]
SFP
System( )
puts( )
/bin/sh
이렇게 puts( )를 넣어버리면 puts( )에 인자값을 넘길수 없다.
스택진행 상황을 보면
1. System("/bin/sh")가 끝나면 RET에 있는 주소로 복귀한다.
2. RET은 puts( )니까 puts( )을 호출한다.
3. 인자값을 받아온다...( ? )
4. puts( )가 끝나면 RET에 있는 주소로 복귀한다....( ? )
3번과 4번을 진행할 때를 보면 어디서 인자값을 받아오며 어디로 복귀할 것인가?
3번은 /bin/sh다음 스택에 있는 dummy값이 들어갈 것이며, 4번은 /bin/sh문자열 주소로 복귀할 것이다.
맞다. 저런식으로 스택에 넣으면 우리가 원하는 방향으로 진행할 수가 없다.
따라서, 우리는 Gadget을 이용해서 스택을 /bin/sh다음으로 이동시켜줘야 하는 것이다.
[Gadget에 대해서..]
Gadget은 어셈블리에서 POP과 RET으로 구성된 것을 말한다.
항상 RET으로 끝나야하며, POP이 몇개 있느냐에 따라 [PR gadget], [PPR gadget] 이라고 부른다.
[Stack7 Gadget]
objdump로 gadget을 추출하며, 이름을 주자면 위에서부터 pppr/pr/ppppr/ppr gadget이라고 부를 수 있다.
[Chaining RTL 실습]
우리는 System( )가 끝난 뒤에 puts( )를 호출하고 싶다.
System( )의 인자값은 1개이기 때문에 PR gadget이 있으면 된다.
스택을 그려 이해를 돕자면
buf[64]
SFP
System( )
PR gadget
/bin/sh
puts( )
AAAA
D
1. System("/bin/sh")가 종료되고 RET에 있는 PR gadget주소로 복귀한다.
2. POP을 진행한다. (/bin/sh가 POP되고 ESP는 puts( )주소를 가리킨다.)
3. RET을 진행한다. (puts( )함수로 복귀한다.)
4. puts("D")가 실행되고 종료된다.
5. RET에 있는 [0x41414141]은 존재하지 않기에 프로그램은 종료된다.
이런식으로 진행된다.
물론, puts( ) RET에 다른 함수를 넣어서 추가로 연속적인 동작을 이어나갈 수 있다.
직접 실습을 통해 우리가 예상한 결과가 맞는지 확인해보자
[puts( ) "D"]
puts( )의 인자값으로 넘겨줄 D는 [0x080480e8]에 있는 D를 사용했다.
[Shell 종료 후 "D" 출력]
빨간 박스부분을 보면 exit로 Shell을 종료한 후, puts("D")가 실행되어 D가 출력되는 모습을 확인할 수 있다.
이상으로 Chaining RTL의 정리를 마치도록 한다.
[PLT & GOT]
Stack7문제를 ROP로 풀려고 공부하다가 이해가 덜 돼서 ROP공격은 못했지만
공부하면서 알게된 내용들을 간략하게나마 정리하겠다.
#함수가 CALL될 때
- 함수가 불러지기전에 PLT에서 GOT로 JMP한 후
[dl_runtime_resolve] -> [dl_fixup_] -> [dl_lookup_symbol_x] 순으로 진행되면서
함수의 실제이름이 들어있는 주소와 SYMTAB / libc 주소를 얻어 실제 함수를 구하는 과정이 진행된다.
위와 같은 복잡한 과정은 함수를 처음 호출 했을 때만 저렇고, 그 이후는 GOT에서 바로 저장되어 있던 함수주소를 넘겨준다.
"GOT에서 바로 저장되어 있던 함수주소를 넘겨준다."
이 부분을 잘 생각해보자
만약 우리가 printf("/bin/sh")라는 함수를 실행하려한다면 PLT는 GOT에게 실제 printf( )주소를 받아올 것이다.
이때 GOT에 printf( )주소가 아닌 System( )의 주소를 넣어 놓는다면?
System("/bin/sh")가 실행될 것이다.
이러한 기법을 [GOT Overwrite]라고 한다.
Stack7으로 GOT Overwrite를 실습해보도록 하자
[Stack7 getpath( )]
strdup( )는 인자값 변수안에 문자열을 그대로 출력해주는 함수이다.
Strdup( ) : IBM Knowledge Center
Stack7에서는 strdup(buf)로 선언되어 있으며, buf에 /bin/sh를 입력해줄 것이다.
그 후, strdup( )의 GOT를 System( )로 덮어쓰면 System("/bin/sh")이 실행되는 것이다.
[strdup( ) GOT]
strdup( )의 PLT를 따라가보면 [0x8049760]로 JMP한다.
저 곳에는 Global_Offset_Table 바로 strdup( )의 GOT가 있는 곳이다.
따라서, JMP하는 주소를 System( )의 주소로 바꾸면 될 것이다.
[GOT Overwrite]
set명령어로 System( )의 주소인 [0xb7ecffb0]으로 바꿔준 후, 계속 진행했더니
보는 바와같이 System("/bin/sh")이 실행되서 쉘이 획득된 모습을 볼 수 있다.
이는 당연히 Local환경이기 때문에 gdb로 가능한 것이다.
실제 Remote환경에서는 gdb로 불가능할 뿐더러, ASLR이 걸려있다면 GOT의 주소가 계속 변할 것이다.
그렇게 되면 Memory leak을 먼저 진행한 후, offset을 계산해서 공격해야 할 것이다.
이를 ROP라고 하며, 위에 정리한 RTL, Chaining RTL, GOT Overwrite 개념을 먼저 알아야 수월한 지식 습득이 가능하다.
다음에는 ROP에 대해 공부하고 정리하는 글을 쓰도록 하겠다.
'공부정리' 카테고리의 다른 글
메모리 보호기법 - PIE (1) 2019.01.12 [02-14 공부정리(FSB 정리)] (0) 2018.02.15 [02-10 공부정리] (0) 2018.02.10 [02-08 공부정리(RTL정리)] (1) 2018.02.08 [02-07 공부정리] (2) 2018.02.07 댓글