payload 구성단계에 있어서 도저히 이해가 안돼서 질문을 남깁니다ㅠ
설명을 정리하자면 exploit 단계는 다음과 같음을 이해했습니다.
write(1, read_got, ...);
으로read
의 실제 주소를 구해libc base
를 찾는다.libc base
를 구했으니 라이브러리에서의 함수들의 실제 주소를 구할 수 있다. 따라서system
함수의 주소를 구한다.read(1, read_got, ...);
에system
함수의 주소를 보내read_got
을 system 함수 주소로 overwrite한다.read("/bin/sh");
으로system("/bin/sh");
를 실행한다.read_got
이system
이므로read
가 아닌system
이 실행된다.
그러나 payload를 구성하면 왜 위 단계의 마지막인 4단계까지 한번에 구성해서 보내는지 이해가 잘 안됩니다.
# 1번 write(1, read_got, ---)
payload += p64(pop_rdi) + p64(1)
payload += p64(pop_rsi_r15) + p64(read_got) + p64(0)
payload += p64(write_plt)
# 2번 read(0, read_got, ---)
payload += p64(pop_rdi) + p64(0)
payload += p64(pop_rsi_r15) + p64(read_got) + p64(0)
payload += p64(read_plt)
# 3번 read("/bin/sh") = system("/bin/sh")
payload += p64(pop_rdi)
payload += p64(read_got + 0x8)
payload += p64(ret)
payload += p64(read_plt)
canary 우회 이후에 왜 read(0, read_got, ---)가 있는지 모르겠고, 그 밑에는 왜 이것이 system으로 대체되는지 모르겠습니다.
write에서 read_got를 알아낸 것을 알겠는데 실제로 libc_base를 계산하는 과정은 위 payload 구성 후 buf로 보내고 난 후에 받은 6바이트+ '\x00'*2 를 통해 구하는 것으로 코드가 작성되어있습니다. payload로 이미 보내서 실행이 쭉 될텐데 어떻게 system을 덮을 수 있는건가요?
p.send(p64(system) + b'/bin/sh\x00')
맨 마지막에 이것을 보냄으로써 exploit이 완성되는데 이것도 왜 이렇게 되는지 궁금합니다! system의 주소를 보내는것과 /bin/sh을 보내는게 따로 아닌가요? 두개를 합쳐서 보내는데도 exploit이 되는데 그 이유가 궁금합니다.
질문 정리
- payload가 길게 보내져도 1번 write가 먼저 실행되면서 여기서 read의 주소가 노출되고 이것을 통해 system의 주소를 구하는게 맞나요?
- 맞다면 이후 2번 과정인 read(0, read_got, --)는 무슨 과정을 의미하는건가요? read_got가 있는 주소값에 입력받을 값을 쓰겠다고 이해하는게 맞나요?
- 위가 맞다면 3번이 더더욱 이해가 가지 않습니다. pop_rdi 이후 read_got + 0x8 을 rdi 값에 넣는데 이건 rdi값에 저것을 넣는 이유가 무엇인가요? read_got+0x8이 의미하는게 무엇인지도 궁금합니다
- 3번에서 ret은 왜 들어가는 것인가요?
- read_plt를 마지막에 호출하는데 이게 read를 실제로 system으로 덮은 이후에 호출하는게 맞나요? 역할이 무엇인지 궁금합니다.
- 마지막으로
p.send(p64(system) + b'/bin/sh\x00')
로 보내면 exploit이 왜 되는지 궁금합니다. system주소값과 /bin/sh을 합쳐서 보내는데 이것이 read_got와 read_got+0x8에 각각 들어가는 것으로 이해하는게 맞나요? 만약 그렇다면 system과 '/bin/sh'를 넣은 값을 보냈을 때 이게 어떤 레지스터에 들어가서 어떻게 작동하는지 궁금합니다!
질문이 많아졌네요ㅠㅠㅠ 이해가 너무 힘들어서 질문드립니다!! 부탁드려요ㅠㅠ
최대한 답변을 해드리겠습니다.
-
payload가 길게 보내져도 1번 write가 먼저 실행되면서 여기서 read의 주소가 노출되고 이것을 통해 system의 주소를 구하는게 맞나요?
-> 넵 맞습니다. -
맞다면 이후 2번 과정인 read(0, read_got, --)는 무슨 과정을 의미하는건가요? read_got가 있는 주소값에 입력받을 값을 쓰겠다고 이해하는게 맞나요?
-> read의 got에 system 함수의 주소를 Overwrite 하기 위해, ROP를 통해 입력을 한번 더 할 수 있도록 페이로드를 구성하는 것입니다. -
위가 맞다면 3번이 더더욱 이해가 가지 않습니다. pop_rdi 이후 read_got + 0x8 을 rdi 값에 넣는데 이건 rdi값에 저것을 넣는 이유가 무엇인가요? read_got+0x8이 의미하는게 무엇인지도 궁금합니다
-> read(0, read_got, --)로 입력을 한 번 더 받을 수 있는 실행흐름이 되었다면, 두번째 입력에서는 p64(system) + b"/bin/sh\x00"을 입력할 것입니다. 이때 read_got에 입력을 받으므로, system 주소는 8바이트이므로, read_got + 0x8에는 b"/bin/sh\x00" 문자열이 쓰여져있습니다. 그리고 이 문자열을 pop rdi를 통해 rdi 레지스터가 가리키고도록 하는 것입니다. -
3번에서 ret은 왜 들어가는 것인가요?
-> system 함수 내부에서 movaps 라는 명령어가 실행되는데 이 명령어는 x64 환경에서 스택이 0x10 바이트 단위로 정렬되어있지 않으면, 에러가 발생하기때문에 ret 명령어를 하나 넣어줌으로써 ret 명령어 내부에서는 pop rip를 하기때문에, rsp가 8 증가하면서 0x10으로 정렬할 수 있습니다. -
read_plt를 마지막에 호출하는데 이게 read를 실제로 system으로 덮은 이후에 호출하는게 맞나요? 역할이 무엇인지 궁금합니다.
-> 넵 맞습니다.# 3번 read("/bin/sh") = system("/bin/sh") payload += p64(pop_rdi) payload += p64(read_got + 0x8) payload += p64(ret) payload += p64(read_plt)
위 페이로드 이전에 read(0, read_got, --)을 통해서 read_got를 system 함수의 주소로 덮었기때문에, read@plt를 호출하면 got에는 system 함수가 덮혀져있으므로, 최종적으로 system 함수가 호출됩니다.
-
마지막으로 p.send(p64(system) + b'/bin/sh\x00') 로 보내면 exploit이 왜 되는지 궁금합니다. system주소값과 /bin/sh을 합쳐서 보내는데 이것이 read_got와 read_got+0x8에 각각 들어가는 것으로 이해하는게 맞나요? 만약 그렇다면 system과 '/bin/sh'를 넣은 값을 보냈을 때 이게 어떤 레지스터에 들어가서 어떻게 작동하는지 궁금합니다!
-> 넵 이해하신게 맞습니다. system의 주소와 "/bin/sh\x00"이라는 문자열을 read_got에 Write한 것뿐입니다. 이게 어떤 레지스터에 들어가서 어떻게 작동할지는 정확히 알 수 없습니다.
Yangın Bapsı Kanadı ve kasası arasında açılıp - kapanma sürecinin kabahatsiz şekilde yerine getirilmesini sağlayıcı mekanizmalara Yangın Bapsı Menteşesi denir. https://www.worldescortshub.com