일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
- 프로젝트
- Social Network in Game
- Kublet
- airdecap-ng
- AttackGraph
- 보안
- cgroups
- Chrome 작업관리자
- decap
- SecurityMetric
- 계정 탈취
- 강의
- Mimikatz
- OIDC
- 대학원
- 화이트해커
- 액티브스캐닝
- ip forwarding
- dnsenum
- 넷크래프트
- 무선채널
- NMAP
- OpenID Connect
- 패시브스캐닝
- Container
- Shift + ESC
- Mac
- 공격그래프
- recon-ng
- davtest
- Today
- Total
네른
[dreamhack] RTL(Return To Library) 본문
1. RTL
- NX를 우회하는 대표적인 기법.
- 라이브러리에는 system, execve등 공격에 용이한 다양한 함수들이 있음
- NX로 인해서 코드를 실행할 수 없으니, "실행 권한이 있는" 코드 영역으로 Return address를 덮자.
// Name: rtl.c
// Compile: gcc -o rtl rtl.c -fno-PIE -no-pie
#include <stdio.h>
#include <unistd.h>
const char* binsh = "/bin/sh";
int main() {
char buf[0x30];
setvbuf(stdin, 0, _IONBF, 0);
setvbuf(stdout, 0, _IONBF, 0);
// Add system function to plt's entry
system("echo 'system@plt'");
// Leak canary
printf("[1] Leak Canary\n");
printf("Buf: ");
read(0, buf, 0x100);
printf("Buf: %s\n", buf);
// Overwrite return address
printf("[2] Overwrite return address\n");
printf("Buf: ");
read(0, buf, 0x100);
return 0;
}
이러한 예제함수가 있을때를 생각해보자.
우선 /bin/sh라는 문자열이 코드섹션에 추가되었다. 코드 섹션에 추가되었으므로 이를 잘 활용할 수 있을 것으로 생각된다.
- why? 코드 섹션의 주소는 고정되므로. (PIE라는 보호기법이 없다면!)
system 함수가 호출되었기 때문에 PLT에서 resolve되었을 것!!
- PLT 또한 PIE가 없다면 주소가 고정된다!!!
이후 코드들로 카나리값을 유출하고 리턴 주소를 system 함수쪽으로 덮어씌우면? system 함수가 호출될 것
익스플로잇은 어떻게 짤까
1. 이전과 동일하게 데이터 길이를 길게해서 카나리를 유출시킨다.
2. system 호출을 위해 rdi 값을 /bin/sh라는 문자열의 주소로 설정한다.
3. system 함수의 PLT 주소로 return address를 덮어씌우고 호출!
근데 여기서 rdi값을 /bin/sh로 어떻게 바꾸지?
- gadget을 이어서 만들자
- ret을 pop rdi; ret의 주소로
- ret + 0x08을 /bin/sh의 주소로
- ret + 0x10을 system 함수의 주소로
이 코드의 이해
ret 부분이 pop rdi; ret으로 바뀌게 됨
-> 저쪽으로 점프를 함.
-> /bin/sh의 주소를 pop해서 rdi에 넣음
-> ret 실행(pop rip; jmp rip)
-> system 함수의 주소를 가져와서 거기로 점프
그런데, 이 코드를 그대로 사용하면 segfault가 발생한다.
이유는 다음과 같다.
system함수 내에 MOVAPS라는 인스트럭션이 존재함
해당 인스트럭셔는 사용하는 값(operand)이 16-byte로 정렬되어있어야 함
그런데 우리가 코드를 짜면 8byte 단위로 구성이 되기 때문에, 실제 코드를 수행하면 16byte 단위로 정렬이 안된상태이다!
이를 해결하기 위해 pop rdi 앞에 임의의 8byte(NOP)를 채워주어야 한다
여기서 이 부분은 RET를 사용해서 NOP을 채워야 한다.
WHY? RET은 스택에서 하날 뽑고 거기로 점프하는 코드. 즉 pop rdi; ret의 주소가 있으면 그걸 뽑아서 호출할 것이기 때문.
-> 아무의미없이 한줄이 추가된것
-> 여기서 막 AAAA 이런거로 채우면 안된다. 고장나지
'강의 정리 > 드림핵 정리' 카테고리의 다른 글
[dreamhack] 라이브러리 (Static Link, Dynamic Link) (0) | 2022.03.02 |
---|---|
NX & ASLR (0) | 2022.03.02 |
Stack Canary (0) | 2022.02.17 |
Stack Buffer Overflow (0) | 2022.02.15 |
Calling Convention (0) | 2022.02.15 |