완료됨
5 코인 payload 중 read를 system으로 덮는 과정

payload 구성단계에 있어서 도저히 이해가 안돼서 질문을 남깁니다ㅠ
설명을 정리하자면 exploit 단계는 다음과 같음을 이해했습니다.

  1. write(1, read_got, ...); 으로 read의 실제 주소를 구해 libc base를 찾는다.
  2. libc base를 구했으니 라이브러리에서의 함수들의 실제 주소를 구할 수 있다. 따라서 system 함수의 주소를 구한다.
  3. read(1, read_got, ...); 에 system함수의 주소를 보내 read_got을 system 함수 주소로 overwrite한다.
  4. 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이 되는데 그 이유가 궁금합니다.

질문 정리

  1. payload가 길게 보내져도 1번 write가 먼저 실행되면서 여기서 read의 주소가 노출되고 이것을 통해 system의 주소를 구하는게 맞나요?
  2. 맞다면 이후 2번 과정인 read(0, read_got, --)는 무슨 과정을 의미하는건가요? read_got가 있는 주소값에 입력받을 값을 쓰겠다고 이해하는게 맞나요?
  3. 위가 맞다면 3번이 더더욱 이해가 가지 않습니다. pop_rdi 이후 read_got + 0x8 을 rdi 값에 넣는데 이건 rdi값에 저것을 넣는 이유가 무엇인가요? read_got+0x8이 의미하는게 무엇인지도 궁금합니다
  4. 3번에서 ret은 왜 들어가는 것인가요?
  5. read_plt를 마지막에 호출하는데 이게 read를 실제로 system으로 덮은 이후에 호출하는게 맞나요? 역할이 무엇인지 궁금합니다.
  6. 마지막으로 p.send(p64(system) + b'/bin/sh\x00') 로 보내면 exploit이 왜 되는지 궁금합니다. system주소값과 /bin/sh을 합쳐서 보내는데 이것이 read_got와 read_got+0x8에 각각 들어가는 것으로 이해하는게 맞나요? 만약 그렇다면 system과 '/bin/sh'를 넣은 값을 보냈을 때 이게 어떤 레지스터에 들어가서 어떻게 작동하는지 궁금합니다!

질문이 많아졌네요ㅠㅠㅠ 이해가 너무 힘들어서 질문드립니다!! 부탁드려요ㅠㅠ

#pwnable
작성자 정보
더 깊이 있는 답변이 필요할 때
드림핵 팀과 멘토에게 직접 문의해 보세요!
답변 2

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

2024.09.19. 23:11
질문자가 채택한 답변입니다. 좋은 지식을 공유해줘서 고마워요!

최대한 답변을 해드리겠습니다.

  1. payload가 길게 보내져도 1번 write가 먼저 실행되면서 여기서 read의 주소가 노출되고 이것을 통해 system의 주소를 구하는게 맞나요?
    -> 넵 맞습니다.

  2. 맞다면 이후 2번 과정인 read(0, read_got, --)는 무슨 과정을 의미하는건가요? read_got가 있는 주소값에 입력받을 값을 쓰겠다고 이해하는게 맞나요?
    -> read의 got에 system 함수의 주소를 Overwrite 하기 위해, ROP를 통해 입력을 한번 더 할 수 있도록 페이로드를 구성하는 것입니다.

  3. 위가 맞다면 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 레지스터가 가리키고도록 하는 것입니다.

  4. 3번에서 ret은 왜 들어가는 것인가요?
    -> system 함수 내부에서 movaps 라는 명령어가 실행되는데 이 명령어는 x64 환경에서 스택이 0x10 바이트 단위로 정렬되어있지 않으면, 에러가 발생하기때문에 ret 명령어를 하나 넣어줌으로써 ret 명령어 내부에서는 pop rip를 하기때문에, rsp가 8 증가하면서 0x10으로 정렬할 수 있습니다.

  5. 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 함수가 호출됩니다.

  6. 마지막으로 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한 것뿐입니다. 이게 어떤 레지스터에 들어가서 어떻게 작동할지는 정확히 알 수 없습니다.

2024.09.12. 09:56