ret의 주소와 gadget의 개념에 관해 질문 있습니다.

ret 주소와 gadget의 개념에 대해 질문이 있습니다.

  1. 리턴 가젯은 ret 명령어로 끝나는 어셈블리 코드 조각을 의미한다고 하였는데, pop rdi; ret의 경우 pop rdi가 실행된 후, ret 가 실행된다는 뜻의 2단계 코드 조각을 말하는 것인가요?? 아니라면 무슨 의미인가요?

  2. ROPgadget --binary rtl 명령어의 결과가 아래의 사진과 같은데, 여기서 어떤 가젯을 사용 하는 지는 어떻게 정하나요?? 그냥 아무 가젯이나 사용해도 되나요? 풀이에서 왜 ret를 사용했는지 궁금합니다.
    image.png

  3. 세 번째로는 이 문제에서 의미없는 문자열로 57byte만큼 채운 후, canary를 leak하고, 다시 의미 없는 문자열로 8byte를 덮은 다음, 원래는 main 함수의 ret 하는 코드가 있지만, ROPgadget --binary rtl에서 찾은 코드로 덮어버렸고 그 후 pop rdi/bin/sh의 주소를 rdi에 넣고 system 함수를 실행시켜서 shell을 획득하는 것으로 이해를 했는데 image.png 여기서 pop rdi; ret가 아니라 pop rdi, /bin/sh의 주소, system 함수 호출 이렇게 3단계로 진행되어야 하는 거 아닌가요?? 왜 pop rdi가 아니라 pop rdi; ret인지 궁금합니다. pop rdi를 한 후, ret를 해버리면 system 함수를 호출할 수 없는 것 아닌가요??

#pwnable
작성자 정보
답변 2
avatar
wyv3rn
무플 방지 위원회장
  1. 맞습니다. 가젯은 바이너리 내의 ret이나 jmp 로 끝나는 연속된 명령어를 이야기합니다.
  2. 용도에 맞게 사용합니다. 언급하신 pop rdi, ret을 통해 첫번째 인자에 binsh를 넣고 시스템 함수를 실행하거나 pop rdi, pop rsi, pop rdx, ret(실제로는 없지만)을 통해 3개의 인자가 요구되는 함수를 실행하는 것 처럼요.
  3. pop rdi로 스택의 값을 rdi에 넣으면 rsp에 8이 더해지고 그 다음 스택의 값으로 ret 합니다. 즉 쉘을 실행시키는거죠
2023.08.08. 22:35
코준
대표 업적 없음

pop rdi -> 스택의 최상단 (rsp가 가리키는 곳)의 값을 rdi에 저장하고 rsp에 8을 더해준다
ret -> ret 명령어는 다음과 같이 기능을 합니다 : pop rip, jmp rip -> 역시 스택 최상단의 값을 rip에 넣은 후 그 값이 가리키는 곳으로 jmp하죠.

이제 오버플로우를 일으킨 상황의 스택을 보면 다음과 같습니다.

<main 함수의 ret 실행 전>
원래 main의 ret주소 (ROP 가젯의 주소가 적혀있게 되죠) -- 0 (rsp)
"/bin/sh" -- +8
system@plt의 주소 -- +16

rsp는 현재 main의 리턴 주소를 가리키고 있고, main 함수에서 ret명령어가 실행되면 이 주소가 rip에 저장되며 점프합니다.
이때 그 주소가 ROP 가젯의 주소기 때문에 ROP 가젯의 주소로 jmp하게 됩니다.
ret 명령어는 pop이 있기 때문에 rsp가 가리키는 값은 rsp+8이 되게 됩니다.

<main 함수의 ret 실행 후>
원래 main의 ret주소 (ROP 가젯의 주소가 적혀있게 되죠) -- 0
"/bin/sh" -- +8 (rsp)
system@plt의 주소 -- +16

현재 프로그램의 흐름은 ROP 가젯의 pop rdi;ret 으로 되어있습니다.
따라서 pop rdi를 실행시키면 현재 rsp가 가리키는 값인 "/bin/sh"가 rdi에 저장이 되고, rsp값은 다시 8증가하게 됩니다.

<ROP 가젯의 pop rdi 실행 후>
원래 main의 ret주소 (ROP 가젯의 주소가 적혀있게 되죠) -- 0
"/bin/sh" -- +8
system@plt의 주소 -- +16 (rsp)

현재 rdi에는 system의 인자로 쓰기 위한 "/bin/sh"가 저장되었고, 이제 ROP 가젯의 ret 명령어가 실행됩니다.
역시 현재 rsp가 가리키는 값인 system@plt의 주소가 rip에 저장이 되고 jmp rip를 하여 system@plt로 흐름을 옮기게 됩니다.
이후 system함수가 호출되고 인자로 rdi가 들어가 있음을 알 수 있습니다.

이처럼 ROP 가젯을 이용하면 pop을 통해 인자로 넣고 ret을 통해 흐름을 연속적으로 바꿀 수 있습니다.
rsp의 위치와 pop, ret등의 명령어의 작동방식을 잘 생각해보시면 도움이 많이 될 것 같습니다.

2023.08.09. 17:34
질문에 대한 답을 알고 계신가요?
지식을 나누고 포인트를 획득해보세요.
답변하고 포인트 받기