
Linux ELF x32/x64 ASLR DEP/NX 우회 익스플로잇 with 스택 스프레이
스택 스프레이를 이용한 Linux ELF x32/x64 ASLR DEP/NX 우회 익스플로잇

속성:
의존성:
제한 사항:
Heap Spraying 공격에 대해 들어보셨나요? Stack Spraying도 유사하지만, 대부분의 경우, 특히 x86-64의 ASLR에서는 실용적이지 않은 것으로 간주되었습니다.
제 연구는 그 반대를 증명할 것입니다.
32비트의 경우 이론적으로 2^32 (4,294,967,296) 개의 주소가 있지만, 커널은 가상화된 메모리에서 실행을 위해 약 절반의 비트(2^(32/2) = 65,536)만 제어할 수 있도록 허용합니다. 즉, 스택에서 50,000개 이상의 문자를 제어한다면, 커널 리디렉션 및 재변환 덕분에 주소에 관계없이 거의 확실히 셸코드를 가리킬 수 있습니다. 제 테스트에 따르면, 호출된 함수에 다른 변수 생성이 없으면 100자 또는 10자만으로도 충분하며, 이는 ROP 스타일 공격을 가능하게 합니다.
이는 셸 변수를 사용하여 달성할 수 있습니다. 셸 변수는 특정 길이로 제한되지 않지만, 실제 제한은 약 10만 자 정도이며, 그 이상이면 TTY가 포화 상태가 됩니다.
따라서 임의의 셸코드로 성공적으로 익스플로잇하려면, 셸 변수에 셸코드와 함께 NOP sled를 넣고 임의의 주소로 바이너리를 익스플로잇하기만 하면 됩니다. NOP sled는 필수는 아니며, 익스플로잇을 일반화하기 위한 것입니다.
64비트 시스템에서는 상황이 다르지만, 제가 발견한 바에 따르면 그리 다르지 않습니다.
물론 2^64 모든 가능성을 다룰 필요는 없습니다. 실제로 커널은 48비트만 허용하며, 그중 일부는 예측 가능하고 정적이므로 약 2^(4x8+5) (137,438,953,472) 가지 가능성이 남습니다.
셸 변수 크기 제한에 대해 언급했지만, 개수 제한도 있으며 약 10개로 보입니다. 따라서 1,000,000자 길이의 셸코드를 저장할 수 있으며, 빠르고 자동으로 테스트할 수 있는 몇 만 가지 가능성만 남게 됩니다. 하지만 이번에는 무차별 대입(bruteforce)을 사용하고 NOP 슬레드를 사용하여 속도를 높여야 합니다.
즉, 32비트와 64비트 모두의 ASLR은 몇 분 안에, 몇 줄의 셸 코드로 쉽게 우회할 수 있습니다.
한편, DEP/NX는 x32에서 return-to-libc 기술을 사용하여 다양한 OS의 통계 연구, 특히 ASLR 제한 및 구현과 결합함으로써 우회할 수 있으며, 이는 두 가지 이유로 성공적인 익스플로잇으로 이어질 수 있습니다. 첫째는 ASLR이 선택에 있어 그다지 무작위적이지 않고 일부 상수와 낮은 엔트로피를 가진다는 점입니다(libC 주소를 추측하기 쉽고 각 OS마다 고유한 상수가 있습니다). 둘째는 libC의 셸 인수를 환경에 스프레이한다는 점입니다(환경에서 쉽게 찾아서 libC에 전달할 수 있습니다).
결론적으로, 32비트의 DEP/NX는 ASLR 때문에 약화됩니다.
더 자세한 설명은 Hakin9-12-14 호에서 확인할 수 있습니다.
버퍼 오버플로우를 한 번이라도 익스플로잇해본 적이 있다면 건너뛰어도 됩니다. 하지만 혹시 모르니:
apt install gcc libc6-dev-i386 || kill -9 $$
chmod u+x ASLRay.sh
sudo gcc -z execstack test.c -o test
sudo gcc -m32 -z execstack test.c -o test32
sudo chmod +s test test32
source ASLRay.sh test32 1024
source ASLRay.sh test 1024
source ASLRay.sh test 1024 \x31\x80...your_shellcode_here
sudo gcc -m32 test.c -o test32x
sudo chmod +s test test32
source ASLRay.sh test32x 1024
Debian x32에서 NOP 슬레드가 필요하지 않음을 증명:
!!! 경고 !!! 이 작업은 /etc/passwd를 수정하고 /etc/shadow의 권한을 변경합니다. 가상 머신에서 실행하는 것을 권장합니다.
chmod u+x PoC.sh
source PoC.sh
grep ALI /etc/passwd
그래도 작동하지 않으면 처음에 NOP(\x90)를 몇 개 추가하십시오.
Debian x32에서 환경 변수조차 필요하지 않음을 증명:
chmod u+x PoC2.sh
source PoC2.sh
따라서 셸코드를 변수에 넣고 ASLR 상태에서 레지스터에 임의의 주소를 지정하여 셸을 얻을 수 있습니다. 이는 함수에 하나의 변수만 있고 그 변수가 덮어쓰여지기 때문에 특정 컨텍스트에서 발생하며, 따라서 스택이 우리의 셸코드로 EIP에 팝(pop)됩니다. 이는 ROP 공격에 더 가깝습니다.
Arch/Ubuntu의 경우 스택 스매싱 보호를 비활성화해야 하며, 무차별 대입에 더 오랜 시간이 걸릴 수 있습니다(실행 지연, 아마도 brk(NULL/0) syscall 또는 canary 때문):
sudo gcc -z execstack -fno-stack-protector test.c -o test
sudo gcc -m32 -z execstack -fno-stack-protector test.c -o test32
sudo gcc -m32 -fno-stack-protector test.c -o test32x
Debian 10에서는 특히 AppArmor로 인해 이 문제가 부분적으로 패치되었습니다.
항상 단일 보호가 아닌 여러 보호에 의존하십시오.
새로운 시스템 보안 메커니즘이 필요합니다.
"우리가 서 있는 곳에서 비는 무작위적으로 보인다. 만약 우리가 다른 곳에 서 있다면, 그 안의 질서를 볼 수 있을 것이다."
토니 힐러먼, 코요테는 기다린다