동작 자체에 여러 의문점들이 있어서 질문합니다.
buf = b'A'*0x48
# write(1, read_got, 8)
buf += p64(pop_rdi) + p64(1)
buf += p64(pop_rsi_r15) + p64(read_got) + p64(8)
buf += p64(write_plt)
buf += p64(main) #? 와이
- 위 상황에서 main을 payload 구성 후에 등록하면 ret 값으로 왜 main으로 돌아가는가
- main으로 돌아가는 것을 발견했는데 그러면 write는 하는게 없는가? (write가 buf출력인 것 같긴 함)
- 위 질문이 맞다면 write가 다 끝난 후에 main으로 돌아가는 과정인 것인가? 그럼 write는 어떻게 실행된거고 그 후 main으로 다시 돌아가는건 어떻게 보장되는 것인가
payload = b'A'*0x48
payload += p64(pop_rdi) + p64(binsh)
payload += p64(system)
p.send(payload)
p.recvuntil(b'A'*0x40)
- 다시 payload를 구성해서 system과 binsh을 보냈을 때 왜 b’A’*0x40까지 받고 난 후에 interactive를 진행하는가?
payload 구성 단계 및 동작과정에서 이해가 잘 되지 않아 의문점들을 적어두었던 것을 질문하게 되었습니다! 도와주세요ㅠㅠ
1. 위 상황에서 main을 payload 구성 후에 등록하면 ret 값으로 왜 main으로 돌아가는가
write 함수 마지막에는 ret 명령어가 존재합니다.
ret 명령어 실행 시 스택에서 8바이트 값을 pop한 뒤에 해당 주소로 프로그램 흐름이 이동합니다.
payload에 의하면 write 함수가 종료되어 ret 명령어가 실행될 때 스택 최상단에 main 함수 주소가 들어있게 됩니다.
따라서 write 함수 내 ret 명령어가 실행되면서 main 함수가 실행됩니다.
2. main으로 돌아가는 것을 발견했는데 그러면 write는 하는게 없는가? (write가 buf출력인 것 같긴 함)
write 함수가 먼저 실행되고 난 뒤에 main 함수가 실행됩니다.
write 함수의 첫 번째 인자로 1(stdout, 표준 출력)을 넣어주었기 때문에,
write 함수는 read_got 값을 출력하는 역할을 합니다.
3. 위 질문이 맞다면 write가 다 끝난 후에 main으로 돌아가는 과정인 것인가? 그럼 write는 어떻게 실행된거고 그 후 main으로 다시 돌아가는건 어떻게 보장되는 것인가
버퍼오버플로우를 통해 RET 값을 write plt 주소로 덮어씌운 것으로 보입니다.
따라서 함수가 종료되어 ret 명령어 실행 시 스택에서 8바이트 값(&write@plt)을 꺼내면서 write 함수가 실행됩니다.
또한, write 함수가 종료되는 경우 역시 ret 명령이 실행됩니다.
따라서 ret 명령어 실행 시 스택에서 8바이트 값(&main)을 꺼내면서 main 함수가 실행됩니다.
4. 다시 payload를 구성해서 system과 binsh을 보냈을 때 왜 b'A'*0x40까지 받고 난 후에 interactive를 진행하는가?
제가 공격 코드만 보고서 답변을 드리자면, "p.recvuntil(b'A'*0x40)"은 단순히 프로그램 로직상 0x40 바이트가 출력되어 이를 명시적으로 받은 것으로 보입니다.
원격 공격의 경우 데이터 송수신에 지연이 발생함에도 이를 무시하고 코드를 무작정 실행하면 프로그램이 정상 동작하지 않을 우려가 있습니다.
따라서 프로그램 로직상 0x40 바이트가 출력되는 부분이 있고 이후에 함수가 종료되면서 ret 명령어 실행으로 공격 페이로드가 작동하는 경우,
0x40 바이트 출력이 다 되고 난 이후에 셸 접속이 되도록 분명히 한 것으로 보입니다.