확인하기 위해 본인 사이트에 올라가 있는 문제를 예시로 들겠다. 문제에는 일반적인 ROP처럼 write 함수와 read 함수가 주어져있다.
1 2 3 4 5 6 7 8 9 10 11 12
[INFO] File: rtc 0x00000000004006bc: pop r12; pop r13; pop r14; pop r15; ret; 0x00000000004006be: pop r13; pop r14; pop r15; ret; 0x00000000004006c0: pop r14; pop r15; ret; 0x00000000004006c2: pop r15; ret; 0x000000000040054f: pop rbp; mov edi, 0x601048; jmp rax; 0x00000000004006bb: pop rbp; pop r12; pop r13; pop r14; pop r15; ret; 0x00000000004006bf: pop rbp; pop r14; pop r15; ret; 0x0000000000400560: pop rbp; ret; 0x00000000004006c3: pop rdi; ret; 0x00000000004006c1: pop rsi; pop r15; ret; 0x00000000004006bd: pop rsp; pop r13; pop r14; pop r15; ret;
[gadgets]
gadget 도구를 이용해서 확인해보면 rdi와 rsi를 채울 수 있을만한 gadget이 보이지 않는다. 그래도 괜찮다 우리에겐 csu가 있으니까!
_libc_csu_init 이라는 함수를 어셈블리 뷰로 확인해보자.
.text:00000000004006B6 loc_4006B6: .text:00000000004006B6 add rsp, 8 .text:00000000004006BA pop rbx .text:00000000004006BB pop rbp .text:00000000004006BC pop r12 .text:00000000004006BE pop r13 .text:00000000004006C0 pop r14 .text:00000000004006C2 pop r15 .text:00000000004006C4 retn .text:00000000004006C4 ; } // starts at 400660 .text:00000000004006C4 __libc_csu_ini
[libc_csu_init gadget1]
여기서 우리가 조작할 수 있는 주소는 rbx, rbp, r12, r13, r14, r15 이다.
첫번째, 두번째 인자값을 받는 rdi, rsi가 없는데 어떻게 할 수 있을까란 생각이 들 수 있겠지만 그 부분은 바로 아래의 코드를 확인하면 알 수 있을 것이다.
[gadget1] 코드에서 pop 해줬던 r15,r14,r13 값을 다시 edi,rsi,rdx에 셋팅한다.(보다시피 rdi가 아닌 edi라서 edi 값은 32비트 범위의 한해서만 조작이 가능하다.)
그리고는 r12+rbx*8한 값을 호출하는데 rbx 값을 0으로 셋팅해준다면 0[rbx] * 8이 돼서 최종적으로 r12의 값만 호출할 수 있게끔 한다.
rbx의 값에 1을 더하고 rbp값과 비교연산을 거친다. rbx값을 1로 셋팅해준다면 조건분기문도 성립되어 문제 없이 통과하게 된다.