본문 바로가기
포너블(pwn)

rtl x86, rop x86

by lolchangilsang 2022. 2. 25.

드림핵에는 64bit만 나와있어서 따로 찾아보게 됬고 이번에 배운 것에 대하여 쓸려고 한다

 

!위에 사진에 문제가 있네요 3번째 그림에서 맨 왼쪽 한칸이 없다고 생각해야합니다!

 

bof가 터진다는 가정 하에 첫번째 그림처럼 덮어준다면 두번째 그림처럼 되게 된다

 

그 이유는 ret자리에 system함수의 주소를 덮어준다면 call을 통해 인자를 스택에 쌓고 호출하는 것이 아닌

 

RET의 POP EIP, JMP EIP를 통해 call없이 넘어가지만 함수에서는 당연히 call을 통해 인자를 스택에 쌓고 부른 줄 알고

 

PUSH EBP / MOV EBP, ESP가 실행되고 sfp(ebp)+8번 부터 인자를 가져올 것이기에 system함수가 호출된 후에 RET자리

 

가 될 곳에 dummy를 넣어준 후 인자(/bin/sh)을 넣어주게 되는 것이다

 

 

ropx86은 rtl코드 부분 중 dummy에 적절한 코드 가젯을 넣어주어 스택을 정리하게 해서 연속으로 함수를 호출할 수 있게 하는 것이다

 

먼저 예제로 설명을 해보겠다

puts = puts함수의 주소
read = read함수의 주소
pr = pop edi; ret;
ppr = pop esi; pop edx; ret;
pppr = pop ecx; pop edx; pop esi; ret; 

payload = dummy #sfp까지 덮어주는거
#첫번째 cycle
payload += p32(puts)
payload += p32(pr)
payload += p32(raedableadr)  => puts(raedableadr) 실행

#두번째 cycle
payload += p32(read)
payload += dummy #다음으로 실행할 함수가 없으니 스택을 정리하지 않아도 됨
payload += p32(0)
payload += p32(writeableadr)
payload += p32(100)  => read(0,writeableadr,100) 실행

puts에서 ret부분에 pop edi; ret;가젯을 넣어주었는데

 

그 이유는 puts의 인자는 readableadr로 스택에 남아있기에 pop edi;로 없애준다음 ret로 다음 함수 read를 실행시켜주었다 

 

이 때 꼭 edi여야하는 것은 아니고 아무 레지스터든 상관이 없다 (그냥 스택에서 빼는거임)

 

puts다음 read함수는 ret자리에 dummy를 넣었는데, 그 이유는 마지막 사이클이기에 스택을 정리할 필요가 없기 때문이다

 

만약 read다음에 새로운 함수를 호출해야 한다면 dummy부분에 pppr(pop 레지스터; pop 레지스터; pop 레지스터; ret)

를 넣어 인자 세 개만큼 스택을 정리해줘야한다 (인자가 한개면 pr, 인자가 두 개면 ppr, 인자가 세 개면 pppr)