소탕꾼들의 격투기 강연에 잘 오셨습니다
해리 포터를 인용한 거예요
네 아내가 이 기술을 뭐라고 부를지 생각해 달라고 했더니 지어낸 이름이에요
'집'이라는 화려한 이름은 없으니까요
맥스웰 둘린에게 '하우스 오브 뮤니'를 안 써서 미안해요
이게 더 좋아서요
어쨌든 상관없어요 이 무명 기술은 최근 퀘일스가 이용했는데 메일에서 수리되지 않은 오래된 버그를
이용했죠
확인해 보죠
그리고 marauders_mmap 디렉터리를 검색하면 데모 바이너리와 취약한 바이너리와 pwntools
템플릿 스크립트가 있습니다
네 체스섹을 보니 머로더스_mmap 바이너리는 대부분 보호 장치가 돼
있어요 렐로 부분만 빼고요 렐로의
전신을 보는 게 익숙하죠
네 앞서 렐로의 부분적인 기능에 대해 간단히 얘기했었는데요 라이브러리 함수 주소를 요약하자면 이 바이너리
사용은 프로그램 초기화 때보다는 처음 호출됐을 때 결론이 납니다
바이너리요 곳 plt 섹션은 프로그램의 평생 동안 쓰일 수 있습니다
하지만 이 기회를 이용하진 않을 겁니다
네 렐로 일부가 전보다 덜하긴 하지만 프로그램 로드 시간을 단축해 주니까 여전히 마주칠
수 있어요 ,
이 2진법은 글리벡 버전 2와 연결되어 있어요 안전 연결을
강화할 겁니다
머로더스_mmap이 어떻게 하는지 보죠
바로... 평소와 똑같습니다 큰 물고기까지 세 마리뿐이고 그 외에도 무료로 편집할 수
있습니다 안 돼요
영상을 멈추고 프로그램에 익숙해진 다음 버그를 찾아요
화면 일시 정지는 안 보여드릴게요 그냥 지금 하세요
버그를 쉽게 찾았길 바라요
이중 비자나 사후 비자 같은 건 없어요
네, 이 오류 메시지를 믿을 겁니다 간결성을 위해서요
하지만 물이 넘칩니다
편집을 할 때는 사용자 데이터의 최대 24바이트까지 기록할 수 있습니다
바이트 하나가 넘친 것만큼 교묘하진 않지만 터무니없는 것도 없어요
네 초과된 양을 시각화하기 위해 덤프 4글자를 사용했어요 시야가 위에서 자동으로 멈추거든요
이 넘치는 물을 어떻게 활용할까요?
네 진행에 가장 큰 장애물은 프로그램에서 주소를 유출하는 게 힘들다는 겁니다
네 네 금붕어 세 마리 예산으로 안전
연결을 유지해야 하니까요
네 한 가지 다행인 건 꽤 큰 덩어리를 요청할 수 있다는 겁니다 큰 덩어리가 아니라 말록의 행동을
바꿀 만큼요
네 힙랩 2부에서는
말록이 큰 덩어리를 처리하는 걸 보고 토끼의 집 기술을 배웠습니다
네 네 mmap로 서비스될 겁니다
네 지금까지는 mmapped 청크를 피했죠 링크 목록에 저장되지 않았으니까요 풀려나면 지도에
표시되지 않아서 우리한테 조작할 만한 멀록 메타데이터가 거의 없어요 ?
하지만 개발 개발 관점에서 볼 때 mma 용해 청크와 흥미를 유발하는 일반 청크 사이엔 두 가지
핵심 차이가 있습니다
첫 번째는 결정론적 방식으로 매핑이 된다는 겁니다 공유 라이브러리와 같은 ASLR 지역으로요
네 그럼 libc 같은 중요한 공동 대상에 관련해 그들의 입지를 바꿀 수 있다는
뜻이죠
두 번째 차이점은 mmapped 청크는 우리가 늘 다루던 착취 완화 정책에 적용되지 않는다는
겁니다
특기 개발에 앞서 mmapped 청크에 대해 더 알아보겠습니다 데모 바이너리로 디버깅
세션을 시작합니다
시작 명령을 내리세요 pwndbg 버전이 제 것과 다르면 start는
깨질 수 있어요 그 경우엔 그냥 break main을 쓰고 대신 run을 쓰면 되죠
네 vmmap 또는 lm 명령을 발행해 프로세스의 가상 메모리 맵을 시각화합니다 데모 바이너리는
같은 버전의 글리벡과 연결되어 있습니다 머로더스_mmap 바이너리와요
mmap가 null인 addr 인수로 호출되면 커널로 내려가 메모리에 매핑된 가상 주소를
고릅니다 ???
네 맬록의 sysmalloc 기능은 경기장에서는 수행할 수 없는 서비스 요청이 null
addr 인수로 mmap를 호출하는 역할을 합니다 ????
궁금하신
분들을 위해 이 보호 깃발은 메모리 태깅 확장판의 일부입니다 혹은 mte 지원으로 glibc
2에서 소개되었습니다 , 33살요 네 기록할 때는 MTE는 특정 ARM 프로세서만 구현되고 Intel이
언제 구현할지 확실하지 않습니다 가능하다면요 네
네 네 어디로 매핑할지 어떻게 정할까요? 안 됩니다,
네 네 이 과정에 대해 제가 아는 건 mmap 소스 코드의 일부를 읽고 Linux
데스크톱 운영 체제의 제한된 하위 집합을 관찰함으로써 얻은 거라고 고지하겠습니다
제 의견을 근거로 해서 직접 시험해 보세요
네 mmap 위치는 커널 버전과 구조에 의존하지만
일반적으로 하향식 접근을 합니다 무작위 오프셋에서 시작해 최저 스택 주소로 이동합니다
동적 로더는 높은 경계에서 매핑되는 경향이 있습니다 낮은 주소의 다른 라이브러리가 뒤따릅니다 ,
대부분 모든 게 딱 맞게 연결되어 있고 사이에 공간이 없어요
하지만 초기화 과정에서 한두 개의 구멍이 남기도 해요
네 재향 군인부 공간에 구멍이 있고 크기가 달라요 특히 다른 배선을
쓴다면요
약간씩 다릅니다 ASLR이 활성화됐는지와 다른 요소들에 따라서요 OS가 VM에서 실행되는지
완전 백업에서 실행되는지
같은 거요
엔트로피가 많은 것 같네요 대상 OS를 확신하지 못한다면 활용이 어려워질 수
있습니다
하지만 구멍 크기는 그대로일 겁니다 프로그램이 몇 번 실행되든 시스템이 재부팅되든
상관없죠
항상 불변의 가치가 있는 거죠
네 말씀드렸다시피 mmap가 이 구멍을 메울 거예요 상층부터 하층까지요 제 경우에는 이 공간에
들어가는 모든 덩어리가 저기로 매핑될 거예요
데모 바이너리가 그걸 할 겁니다
A라고 적힌 0x21000 크기의 덩어리를 요청합니다
네 mmap 가동하세요 요구한 용량은 mmap 허용치를 초과할 뿐 아니라
경기장에서 할당하기엔 너무 커야 합니다 이 OS의 맨 위 덩어리는 0x21000입니다
네 이것보다 적은 요청은 괜찮아요 울타리와 퇴비 조각만 고려하면요
하지만 mmm은 메모리를 책장 크기의 배분만 하니까 반올림하는 게 좋겠어요
네 시작과 끝 주소를 기록해 두세요 크기도요 그래야 첫 번째 할당 이후 비교할
수 있으니까요
다음 명령을 내리고 무엇이 바뀌었는지 메모리 맵을 다시 살펴봅니다
가장 명백한 차이점은 기본 힙이 있다는 것입니다 할당된 tcache 외에는 아무것도
없습니다
이 매핑의 크기는 증가했습니다 하지만 end 주소는 변하지 않았지만 시작 주소는
훨씬 낮아졌습니다
mmap가 기존 매핑 메모리 앞에 우리 청크를 할당했어요
네 헤더 때문에 a-16 주소를 인쇄할게요 새로 확장한 지도의 시작 주소와 일치해요
네, 맞아요
메모리를 그 장소에 놓으면 우리가 일반적으로 기대하는 것이 보입니다 prev_size 필드 사이즈
필드 그리고 사용자 데이터입니다
네 유일한 차이점은 prev_inuse 플래그가 설정되지 않았다는 겁니다 mmapped 청크는 통합되지 않았고
is_MAPPED 플래그가 설정됐으니까요 ???
네 덩어리가 좀 커요 하지만 0x21000 정도 크기를 기대했는데 a는
그보다 한 페이지나 커요
이것은 mmapped 청크스가 기존 청크스에 비해 사용자 데이터가 1사분자 적기 때문입니다 왜냐하면 다음 청크의 prev_size
필드를 보장하지 않기 때문입니다
그렇군요 말록이 다음 덩어리로 넘어가고 그다음 페이지 크기로 넘어가죠
익숙해지려면 시간이 좀 걸리겠어요 명심하세요 한 가지 명심할 건 mmap로 특정 크기의 덩어리를
나누려면 원하는
크기에서 24를 빼야 한다는 겁니다
데모 바이너리가 이걸 할 거예요
0x21000 사이즈로 요청합니다 B 덩어리에 0x21fe8 바이트를 요청합니다
다음을 이용해 이 줄을 실행합니다
네 기억 지도를 살펴보니 A가 표시한 지역이 더 낮은 주소로 확장됐어요
네 새 지도가 완성되면 B 청크는 그 시작점에 자리 잡습니다 이번에는 0x21000 사이즈로 만들 겁니다 계획대로요
네 a가 b로 옮겨갑니다 다시 앞으로요 힙이 더 높은 주소로 커지면서 청크를
할당받는 것에 익숙해졌죠
이것도 mmapped 청크를 다룰 때 익숙해져야 해요
이제 덩어리를 풀면 어떻게 되는지 보죠 공짜 청크 A 옆에 쓰세요
기억 지도예요 기억 지도를 살펴보니 지도에 표시된 바는 없고 그 앞에 있는 것과 그 뒤에 있는 익명의
지도만 있어요
네 지표 해제 작업은 문맵 기능으로 하는데 사실상 청크는 존재하지 않아요
접근을 시도하면 세그폴트를 사용하게 됩니다
하우스 오브 래빗 2에서 mmap 한계점보다 큰 걸 풀어주면 그 크기에 대한 한계점이
증가한다는 걸 기억하실 겁니다 이제 mmap 한계치가 A컵 크기로 설정된
걸 볼 수 있습니다
네 다른 mp_스트럭트 값이 변하는 걸 보셨을 텐데요 지금은 상관없습니다
네 0x22000 이하의 덩어리를 더 입히면 a 덩어리가 남긴 틈에 매핑이 될
거예요
그보다는 이 둘 사이에 안 들어가는 큰 덩어리를 잘라내죠
데모 바이너리가 0x200000 크기의 덩어리를 요청할 거예요
다음과 lm을 두고 보죠
네 주소 c를 출력했더니 가장 높은 주소에서 지도에 표시된 곳이 여기예요 mmap도
가능해요
청크 C의 끝 주소와 libc 공유 객체의 시작 주소가 같다는 걸 보세요
이게 아까 말씀드린 라이브러리와 관련 있는 행동입니다
네 무슨 생각 하시는지
알아요 aslr이 꺼져서 그럴 거예요 그럼 aslr을 켜고 프로그램을 다시 시작하죠
다음 4를 이용해 같은 지점까지 실행하고 메모리 맵을 다시 검사합니다
네 다시 한번 c 청크는 libc가 공유하는 개체 직전에 할당됐고 그 사이에는 틈이 없습니다
aslr이 활동 중인데도요
자 mmapped 청크를 어떻게 활용할지 고민하기 전에 배운 걸 정리해 보죠
말록 경기장에서 치료하기엔 너무 큰 요청이 들어오면
시스몰록 기능이 책임져야 합니다 ,
요청이 mmap 한계치에 도달하거나 이를 시 sysmalloc이 mmap를 통해 서비스합니다
mmap는 공유 라이브러리에 사용되는 같은 ASLR 지역에서 메모리를 할당합니다
네 하향식 할당이에요 mmap가 맞출 수 있는 가장 높은 곳에
할당된다는 뜻이죠
mmapped 청크는 힙바운드 상대보다 사용자 데이터가 1사분수 적습니다 특정 크기를 쉽게 할당하는
방법은 원하는 크기에서 24를 빼면
됩니다 mmapped 청크는 명확한 pre_inuse 플래그를 갖고 있고 집합은_MAPPED 플래그입니다
set_MAPPED 플래그가 풀리면
간단히 매핑이 해제되죠 남겨진 공간은 앞으로 mmap 호출에 재사용할 수 있습니다
그래서... 그 차이가 현재 mmap 한계점보다 크면 그 기준에 맞게 문턱이 조정됩니다
네 그 외에도 데모 바이너리를 관찰하면서 명확하지 않은 게 몇 가지 있습니다
첫 번째는 용량 제한이 풀린 청크의 크기에 따라 메모리를 얼마나 풀어야 할지 결정합니다
두 번째는 mmapped 청크의 prev_size 필드가 사용됩니다 정렬 세분성은 전체
페이지에서 더 작은 스케일이어야 하니까요 이 두 가지 사실을 잘 활용할 겁니다
네 마지막으로 mmapped 청크는 단일한 진실성을 지녀야 합니다 페이지 정렬을 확인한 후 지도를
푸세요 ,
약탈자 약탈자_mmap 바이너리를 이용하기 전에 이 기회를 이용해서 말록 실험대에서
mmap 처리된 덩어리를 실험해 보세요 , 원리가 익숙해질 때까지요
참고 자료를 원하시면 PDF에 잡동사니 섹션이 있어요
천천히 하시고 준비되면 다시 오세요
자 자, 이제 mmapped 청크도 익숙해졌으니까 가해자가 어떻게 이용하는지 한번 보도록 하겠습니다
pwntools 템플릿 스크립트를 복사해 여러분이 선택한 편집기에서 여세요
맬록을 감싸주는 일반적인 도우미 함수가 있어요 무료, 편집 메뉴 옵션이죠
투표에 관한 메모입니다 머로더스_mmap 프로그램이 많은 양의 데이터를 읽기 위해 사용했기 때문입니다
네 해킹엔 영향이
없을 거예요 다만 디버깅할 때 평소보다 읽어야 할 전화가 많을 거예요
말록 도우미에게 전화하는 두 번이 대본 하단에 있어요
오타가 아니에요
'뽕'이란 단어가 큰 덩어리를 재미있게 묘사하는 것 같아요
각각 0x200000 사이즈 청크를 요청합니다 데모 바이너리의 청크 C와 같은 크기죠
네 이 요청들은 메인 아레나의 mmap 한계점과 사용 가능한 공간을 넘어선 것이므로 mmap로
서비스하겠습니다
네 이 덩어리가 공유 라이브러리 바로 전에 매핑되도록 하는 게 핵심이죠 그러니 라이브러리의 어떤
틈보다 커야 합니다 ASLR 지역
편집 헬퍼에 몇 개의 호출을 추가해 이런 덩어리들을 표시해 뭐가 뭔지 알 수 있습니다
다 됐습니다 이제 gdb 옵션으로 이 템플릿을 실행합니다 NOASLR 옵션을 생략하세요 메모리
공백의 크기를 잘못 인식시킬 수 있으니까요 ,
달팽이로 재향군인회 공간을 부수고 조사해요
이 지역이 괜찮아 보여요
네 네 우리 경우엔 libc죠
네, 맞아요
네 제 OS는 0x200000보다 페이지가 짧아요 그래서 작은 덩어리를 요청해도
괜찮았지만 0x200000으로 충분했으면 좋겠어요
그렇지 않으면 편집기로 돌아가 청크 크기를 늘립니다 제 것과 같은
곳에 할당될 때까지요
원하는 크기에서 24개만 빼면 돼요
네 다른 방법으로 mmapped 덩어리로 틈새를 메우는 겁니다
하지만 머로더스_mmap 이진법으로 제한된 항목은 3개뿐이라 이 방법이 더 효율적입니다
네 큰 지도의 시작 부분에서
예상하는 크기의 땅이 드러납니다
0x42는 청크 B를 표시할 때 쓴
대문자 B예요
이걸 한 이유는 이 덩어리들이 메모리에서 정렬됐다는 걸 잊기 쉽기 때문이에요 요청한
역순으로요
B 덩어리 다음에 메모리를 버리면 A 덩어리의 헤더와 사용자 데이터의 시작을 볼 수 있죠
덩어리 A가 libc 공유 객체의 시작 직후라 엘프 헤더를 알아볼 수 있을 겁니다
좋아요, 공유 라이브러리 앞에 mmaped 청크 2개를 할당했으니 오버플로 버그를 활용할
거예요 ,
물론 청크 A에서 공유 물체로 흘러넘쳐 봐야 소용없죠
우리가 흘러들어 간 부위는 쓰기와 안 맞아서 세그폴트를 촉발할 뿐이에요
다른 방법은 B에서 A의 헤더로 물이 넘치게 하는 거죠
이 부분에서 용량이 좀 헷갈릴 수 있어요
말로크로 0x1fffe8 바이트 메모리를 요청해서 0x200000 사이즈로 저장했습니다
네 이 덩어리는 말록의 사용 가능한_크기를 보면 () 함수에는 우리가 요청한 것보다 8바이트 많은 사용자
데이터가 들어
있어요 mmapped를 얻기 위해 최대한 많은 사용자 데이터를 요청했는데도요
네 왜냐하면 매핑의 마지막 4문자는 다음 크기로 분류되는데 사용자 데이터로
간주되거든요 다른 것엔 사용될 수 없기 때문이죠
이 네 글자는 요청할 때 고려되지 않아요 말록이 우리 요청을 이미 적당한
보통 크기로 축소했거든요 시스말록이 그걸 손에 넣기 전에요
나도 이해하는 데 시간이
걸렸어요 당신도 같은 생각이라면 맬록 실험실로 돌아가서 만족할 때까지
계속 약을 먹어 봐요
이 네 글자를 더 올린 이유는 초과 인원이 도달하는 범위에 영향을 주기 때문입니다
네 이 바이너리에 16바이트만 주고 싶었어요 기술적으로 다음 덩어리에 도달할
수 있으니까요
하지만 맬록_usable_size를 생산에서 사용하는 건 좋은 연습으로 간주되지 않아서 24바이트 오버플로를
계속 사용했습니다
네 이게 사용자 데이터의 마지막 네 글자입니다 마지막 기술적 네 글자도 있어요
그 다음에는 청크 A의 prev_ize 필드가 오고 크기 필드가 옵니다
네 네 머로더스_mmap 바이너리는 요청한 만큼만 데이터를 작성할 수 있습니다 mmapped에
대해 배운 것을 정확하게 파악하기 위해서죠
즉, 24바이트의 오버플로가 있어야 청크 A의 크기를 덮어쓸 수 있습니다
왜 청크 A의 크기에 신경 쓰죠?
네 그게 아까 말씀드렸죠 mmapped 청크가 풀렸거나 풀리지 않았을 때 맬록이 기억력을
알려면 청크의 크기를 읽어야 해요
네 청크 A의 크기 영역을 건드리면 추가 메모리를 임의로 풀 수 있어요 그럼 풀
수 있죠
스크립트로 돌아가서 할 수 있는지 보죠
네 a를 잘라낸 줄부터 삭제하는 게 좋겠어요 이걸 위해 아무것도 쓸 필요가
없어요
다음, B 덩어리에 쓰레기 데이터를 채우고 추가 4음절을 잊지 마세요
다음 16 바이트는 헤더로 흘러 넘칩니다
몇 가지 변수를 추가해 뭘 덮어쓰고 있었는지 추적할 수 있어요
prev_size 필드를 이용하세요
네 그리고 크기 필드를 원래 크기로 설정하고 추가 메모리를 추가로
설정합니다
작은 값을 쓰시길 권합니다 페이지 크기 증가를 이용하세요 페이지 정렬 확인에
실패하지 않으려면요
네 가짜 사이즈 필드에 IS_MAPPED 플래그를 설정해야
해요 안 그러면 보통 크기로 처리되죠
청크를 수동으로 분리해서 재향군인회 공간을 앞뒤로 검사할 거예요
오버플로가 준비되면 GDB
옵션으로 스크립트를 실행합니다
스크립트가 많은 데이터를 작성해서 완료될 때까지 기다려야 할 수도 있어요
인터랙티브 프롬프트가 뜨면 재향 군인회 공간을 살펴보세요
아까랑 거의 비슷해요
덩어리 B와 A예요
판드버그의 명령에 따르면 송출은 성공적이었습니다 청크 A의 크기 필드는 이제 원래
가치보다 커졌습니다
첫 번째 지도의 크기와 시작 주소를 보세요
계속해요
프로그램 창으로 가서 인덱스 0의 A 덩어리를 무료로 얻으세요
GDB로 다시 돌아가 재향 군인회를 다시 조사하세요
네 B는 그대로 있어요 하지만 A는 지도에 안 나와 있고 libc 지도도 일부 사라졌어요 안
돼요
네 네 ? 네
'오셋' 필드는 우리가 훔친 메모리를 알려주는 좋은 지표예요
lm의 마지막 호출로 스크롤을 올릴 수 있습니다 이전과 이후의 매핑을 비교하고 싶다면요
네 청크의 크기 영역을 건드려서 풀어 주면 필요 이상으로
많은 메모리를 풀 수 있어요 맞아요 그리고 또 mmapped 파일을 공유 라이브러리 바로
앞에서 확보할
수 있죠 프리미티브는 라이브러리의 주요 페이지를 제거할 수 있어요
이 자체로는 별 쓸모가 없어요
네 커널이 이제 미래의 mmap 요청을 위해 방금 맵핑
해제한 라이브러리 메모리를 고려한다는 거죠 사라진 라이브러리 데이터를 우리 것으로 대체할
수 있다는 겁니다
어떤 데이터를 대체하죠?
우리가 리브를 먹었다고 생각하는 건 용서하세요 or 문자로요 plt 섹션은
실행 파일이 매핑돼 있어요 하지만 이 바이너리를 만들었던 오래된 빌드 체인은
기억 보호에 있어서는 게으릅니다
여러분 리눅스 프로그램을 디버깅할 때 이런 VA 공간 레이아웃을 보셨을 겁니다 각 바이너리는 실행이
불가능한 매핑으로 시작되죠
더 최근에 네 잠재적인 ROP 장치의 수를 최소화합니다
???????????
네 일관성을 위해 모든 쌍성에 대해 동일한 빌드 체인을 사용했습니다
약간 구식이긴 하지만요
네 메모리 레이아웃의 차이는 우리가 배운 다른 기술에는 영향을 주지 않지만
다른 덩어리를 사용해야 할 수도 있습니다
네 현재로선 초기 버전을 개발 중이란 것만 이해하면 되죠 실행이 불가능한 섹션을 주도하는
라이브러리들을 재조립할 수 있도록요
그 비검출 부분이 중요해요 libc 지도는 안 나왔지만요 네 텍스트 섹션 mmap에서 받게 될 매핑이
겹칩니다 실행 가능한 허가가 없어요
그래서 새 코드를 실행하려 할
때 세그폴팅으로 끝나게 됩니다
힌트를 드리죠 libc 섹션을 계속 재조립하는 우리 능력을 어떻게 이용할지에 대해서요
프로그램 창으로 가서 '포기'를 선택하세요
GDB로 다시 전환하면 do_lookup_x라는 함수에서 세그폴트가 발생했다고 나오죠
네 네 libc 메모리를 읽으려다가 방금
지도를 풀었습니다
?
앞으로 어떻게 할지 아직 확실하지 않다면
설명해 드리죠
네 포기 옵션을 선택하면 머로더스_mmap 프로그램이 글리벡의 퇴장을 알립니다
네 네 먼저 주소를 해결해야
합니다
,
기호 해상도에 결정적인 것은 기호 테이블입니다
DSO라고 하는 모든 동적 공유 물체는 하나씩 라벨을 붙여 보관합니다 이 테이블은 스트럭츠의 집합으로
우리 아키텍처에서 이렇게 생겼죠
네 네 그리고 검색 절차에 사용되는 정보를 갖고
있죠
가장 흥미로운 건 기호의 가치를 지닌 st_value 필드입니다
값은 자세하지 않아요
무공해 총탄과 상징이 상쇄된 상태죠
매핑을 풀면 라이브러리의 매핑을 다시 매핑해요 dnysym 섹션을 이용하고 적절한 기호 테이블 엔트리의 st_value
필드를 바꾸면 실행 흐름을 리디렉션할 수 있습니다
네 예를 들어 글리벡의 exit 함수가 offset 0x1122부터 libc
바이너리 시작이라고 해 볼게요 오프셋은 exit 기호 테이블 엔트리에 저장됩니다 st_value 필드에요
네 처음으로 exit이 호출되면 검색 절차가 이 항목을 찾을 겁니다 그런 다음
st_value 필드를 libc load 주소에 추가해 exit의 가상 주소를 엽니다 ?
프로그램의 퇴장자 명단요 곳 plt 섹션에 맞는 주소가 업데이트되고 출구가
마침내 호출됩니다
네 하지만 exit의 st_value 필드를 시스템 오프셋으로 교체하면 exit이
처음 호출됐을 때 실행이 시스템으로 리디렉션됩니다
간단하죠
이 기술이 효과적인 이유는 절대 주소를 다룰 필요가 없기 때문이죠
오프셋만요 인포리크가 필요 없죠
이게 흔한 매개체가 아닌 이유는 DSO 급사 덕분이죠 다이심 섹션은 항상 작성 불가능으로 매핑됩니다
내용이 바뀌지 않기 때문이죠
그래서 우리가 유리하죠 착취 원시성은 이 부분을
쓰기 가능하게 다시 매핑할 수 있게 해줍니다 그 후 기호 테이블 엔트리를 모두 대체할
수 있죠
그럼… 일단 mmap
한계점이 방금 꺼낸 인공적으로 커진 부분과 맞먹는 크기로 올라갔어요
이 점을 고려해야 합니다
GDB를 닫고 pwntools_template_2 스크립트를 다운로드하세요
지금 화면에 뜨는 거요
이 템플릿은 우리가 이미 얻은 것에 기반해 다시 매핑하고 exit 함수의 기호를 수정합니다 테이블 엔트리
네 전에 했던 두 개의 청크를 요청합니다 그런 다음 오버플로 버그를 이용해 청크 a의 prev_ize와 사이즈
필드를 덮어 씁니다 ???
네 보시면 아까는 0으로 남겨뒀던 prev_size 필드가 이제 1페이지로 설정된 걸 보실 수 있습니다
네 아까 아까 짧게 말씀드렸었죠
가끔 말로크가 사용자 데이터를 페이지가 아닌 다른 것에 정렬해야 할 때도 있어요
네 mmap는 페이지 정렬 메모리만 반환할 수 있기 때문에 맬록은 청크의 prev_size 필드를 이용해
지도의 시작과 청크의 시작 사이의 오프셋을 저장합니다
네 mmapped 청크가 풀리면 크기 필드로 결정되는 청크 헤더 이후의 지역과 그 전 지역 prev_size
필드로 결정되는 지역은 매핑이 해제됩니다
한 덩어리씩 제거한 후 임의의 메모리를 풀 수 있다는 뜻이죠
맞아요 꼭 이럴 필요는 없지만 청크 A를 잡기 전에 공간을 확보해야
해요
기억나세요? 네 0x201000 크기로 설정돼 있었잖아요
안 그래요?
아, 예 mmap 한계치를 낮출 방법이 없으니까 mmap를 더 올리려면 새로운 mmap 한계치를
맞추거나 넘어서야 합니다 , 그 용량이
그렇지 않으면 기본 설정 힙에 할당될 것입니다
네 문제는 데모에서 보셨듯이 이진법 요청은 정상화된 후에야 mmap 임계값과
비교된다는 겁니다
네 네 그래서 0x201000 용량을 요청하면 반올림해서 한 페이지
더 큰 mmapped 용량으로 올라가 b와 libc의 간격에 들어가지
않습니다 , 이건
네 네 해결책은 페이지를 늘리거나 B를 풀어주거나 우리 스크립트대로
프리v_사이즈 필드를 이용해 이전의 추가 메모리를 푸는 겁니다
후자가 됩니다. prev_size 필드는 업데이트된 mmap 임계값에 포함되지 않았기 때문입니다. 그 메모리는
기술적으로 포함되지 않았기 때문입니다.
네 이 방법 중 하나를 선택하는 건 자유지만 실제로 b 덩어리나 비슷한 걸
못 꺼낼 수도 있어요 그러니 다른 방법이 있다는 걸 기억해 두세요
이전 스크립트에서 두 번째로 바뀐 건 추가 메모리의 양이에요 A 부분 다음에 매핑을 해제하죠
네 원래는 테스트 목적으로 한 페이지만 사용했지만 이 템플릿은 exit 함수의 기호에 도달하기
위해 필요한 메모리를 사용합니다 테이블 엔트리 ?
그 계산이 여기서 끝납니다
엘프툴 도서관의 도움을 받아 폰툴이 수입하죠
우선 리bc를 확보해요 기호 테이블을 갖는 다이심 섹션입니다
기호 테이블 엔트리와 인덱스를 추출합니다
이 라인은 불분명하다는 것을 알고 있습니다 하지만 엘프툴은 이것을 쉽게 만들지 않습니다 그래서 저는 짧은 스크립트를 우선시하고
있습니다 엘프툴을 어떻게 사용하는지 배우기 위해서입니다
이 선으로 비중을 더해주죠 dnysym 섹션 libc 바이너리 시작부터 exit
기호 테이블 오프셋까지 기호 테이블 내의 엔트리
그럼 리브의 시작과 상쇄되는 거죠
네, 마법의 숫자죠 우리 아키텍처에서
기호 테이블 입장 크기입니다
네 솔직히 솔직히
,
계산된 오프셋을 폰툴의 정렬로 가장 가까운 페이지로 모읍니다
네 이제 매듭을 풀기 전에 초과된 양의 원금 가치를 원래 크기로 되돌릴 겁니다
이렇게 이렇게 하면 리bc의 출구 표시를 찾을 만큼 메모리를 확보하지 않았다는
걸 알 수 있어요 테이블 입장 호기심 많은 사람은 5페이지로 끝나죠
청크 A를 풀어줬으니 이전 각본과 같은 단계에 왔어요 dso의 지도를 푼 거죠 이번에는 조금
더 풀었지만요 이제 시작이에요 , 좋아요
이제 동일한 메모리를 컨트롤의 형태로 다시 매핑합니다
커널이 다음 mmap 요청을 라이브러리 최상위 주소 aslr 지역에서 서비스한다는
걸 압니다
네 네 지도에 표시되지 않은 libc 메모리로
정보가 전달될 거예요
?
네 아까도 말했지만 이 요청은 현재 mmap 한계치에 맞거나 초과해야 합니다 지도화하지
않은 libc 메모리 양에 부합해야 하죠
네 우리가 원하는 것보다 한 페이지 더 커질 테니 24를 빼지 않는 걸 고려할 수
있어요 특정 mmapd 사이즈 요청 규칙이죠 ?
네 네 안 돼요
이 덩어리가 여전히 불편하다면 실험용으로 이 템플릿을 복사해서 왜 더 작은
덩어리를 요청할 수 없는지 알아보시길 권합니다
네 이 "오버랩"을 매핑하면 우리가 매핑하지 않은 libc 메모리를 기술적으로 겹치게
하는 것 같거든요 완전히 대체하긴 하지만∙∙∙ 기호
테이블 엔트리를 위조할 수 있어요
네 들판을 간략하게 보여 드릴게요 스트럭츠의 장관을 보고 싶으시다면 글립크의
엘프에 나와 있어요 h 파일
첫 번째 필드는 st_name입니다
무공해의 끈 테이블에 고정돼 있죠
이 오프셋은 정확해야 합니다 왜냐하면 검색하는 프로그램의 기호 이름이 문자열 테이블에서
오프셋과 대조될 테니까요
일치하지 않으면 기호 해상도가 안 맞아요
이런 일이 없도록 오리지널 st_name 필드를 사용합니다
네 다음 st_info 필드입니다 두 개의 하위 필드로 나뉘어 있죠 기호 보고, 바인딩
그리고 형식입니다 ? 이 분야의 잠재적 가치는 elf에서도 찾아볼 수 있습니다 네 h 저는 이 그림이
특히 흥미로워요 이 그림 자체가 기호 해상 기능으로 다뤄지거든요
이건 호출이 먼저 온다는 뜻이죠 곳 plt 섹션이 업데이트돼서 해결 과정을 가로챌
기회가 생겼습니다
네 몇 가지 변형을 적용할 수 있지만 성공을 보장하기 위해 기존의 값을
유지합니다
이것도 마법의 숫자인데 엘프툴은 이걸 문자열로만 표현해요
다음은 st_other, 기호의 가시성을 결정합니다
여기선 STV_DEFAULT나 STV_PROTED를 쓸 수 있죠
템플릿은 원래 기본값 0을 사용합니다
그 후 st_인덱스 필드가 나와요 dso에서 그 기호의 어느 부분이 해당하는지 알려 주죠
맞아요 네 출구 상징이 libc에 있다는 뜻이죠
"출구 상징" 텍스트 섹션, 설치된 경우 readelf 같은 것으로 확인 가능합니다
네 네 그래서 여기선 거의 어떤 값도 사용할
수 있어요 하지만 0과 0xfff1은 피하는 게 중요해요 , 0xf1은…
0이면 결의안이 깨져요
0xfff1에 따르면 인접한 st_value 필드가 절대 주소로 취급돼야 해요
우리는... 이런 행동은 원치 않습니다 정보가 새지 않기 때문에 절대적인 의견을 제시할 수 없습니다
네 이대로 두면 st_value는 dso를 시작한 직후의 상쇄로 처리됩니다 훨씬 작업하기 쉽죠
, 하지만 이건 아닙니다
st_value 얘기가 나와서 말인데 실행 흐름을 장악하는 열쇠예요
우리 템플릿 스크립트는 글리벡 시스템 기능의 상쇄에 맞춰져 있어요
libc를 사용하세요 libc에 수익을 제공하지 않고요 주소는 가상 주소 대신 오프셋을
반환합니다
네 기호 테이블의 마지막 필드는 st_size로 바이트로 기호 크기를 알려줍니다 안 그러면 기호 크기를
내가 아는 한 상징 해결에는 아무 역할도 안 해요
하지만 완전성을 위해 여기에 포함한 겁니다
원래 값은 26이에요 출구 함수가 26바이트라는 뜻이죠
이상으로 가짜 기호 테이블 출석을 마칩니다
대본 마지막 줄은 가비지 데이터를 리bc에 적는 거예요 출구가 있어야 할 오프셋까지
다이심으로 연결됩니다
그럼 가짜 기록이 남죠
네 이 대본에 많은 일이 일어나는 것 같지만 여기서 가장 복잡한 건 줄을 맞추고
엘프툴 라이브러리와의 전투를 하는 거예요 libc의 관점에선 하나의 st_value
필드를 수정했을 뿐입니다
네 중단 메뉴 옵션을 선택할 때 머로더스_mmap 프로그램이 exit
함수 주소를 보고 위조된 기호를 이용해 테이블 엔트리가 시스템에 있는 것으로 결론짓게
됩니다
GDB 옵션으로 스크립트를 실행해 보겠습니다
네 데이터를 더 작성할 거니까 완성할 시간을 좀 주세요 gdb에 들어가서 VA 공간을 조사할
거예요 ? 네
상반된 열에 따르면 우리가 성공적으로 dso의 주요 인물 다섯 명의 지도를 풀었습니다
이 지역은 청크 B입니다 그다음이 겹치는 청크죠 보다시피 5개의 libc 페이지가 방금 한
것과 같은 가상 메모리를 차지합니다
가짜 기호 테이블 엔트리가 지금은 제대로 도착했다고 가정하고 계속하기 전에 시스템에 중단점을
설정하죠
프로그램 창으로 가서 exit 기호의 해상도를 트리거하기 위해 stop 옵션을 선택합니다
다시 GDB 쇼로 전환합니다 불행히도 이 프로그램은 시스템을 호출하지 않고 세그폴팅합니다
저장소가 다 소진된 것 같거든요
기호 테이블 입구를 찾는 건 처음 생각했던 것보다 더 어렵네요
편집자한테 가서 더 자세히 설명할게요
특정 기호 테이블 엔트리는 해시 테이블을 통해 이뤄집니다
이 테이블을 구현하는 방법은 두 가지입니다 이전 방식과 새로운 방식이죠 요즘에 더 널리 퍼진 새로운 길을
보여드리겠습니다
D.S.O.의 마리화나 테이블은 이름 붙은 구역에 있습니다 그누 해시는 일반적으로 그 전에 존재하죠 다이심 섹션
매핑을 풀 수밖에 없었어요 그누 해시 섹션에서 기호 테이블로 갑니다
하지만 공격하기 전에 복구해야 합니다
리bc부터 시작하죠 그누 해시 섹션은 우리가 그걸 한 방법과 같죠 다이심 섹션
이 섹션에서 세 개만 복구하면 돼요
그리고 이 세 가지 값을 수술로 대체할
수 있는 공격성을 만들 수도 있지만 엘프툴은 계산을 쉽게 하지 않습니다 스크립트는 필요
이상으로 복잡해집니다
그래서 그냥 통째로 버릴 거예요 그누 해시 섹션은 libc에 넣고요
DSO가 시작된 시점부터 끝날
때까지의 쓰레기 데이터를 기록하겠습니다 그누 해시 섹션
이걸 따라가죠 그누 해시 섹션 자체요
젠장 다이심 섹션은 . 그누 네 해시 섹션 이 값을 exit 기호에 도달하는
데 필요한 padding 양으로 바꾸기만 하면 돼요 테이블 엔트리
이러한 변화가 있었으니 GDB 옵션으로 다시 한번 취약점 스크립트를 실행해 보겠습니다
스크립트를 다 썼다면 중단점을 설정합니다 동적 링커의
do_lookup_x 함수 상에서요 , 이 스크립트는
해시 테이블과 기호
테이블의 관계를 이해하기 위해 조회 프로시저를 추적해 보도록 하겠습니다
이런 건 몰라도 돼요
관심 없으면 안 가도 돼요
네 함께하고 싶다면 계속하세요 프로그램 창으로 가서 포기를 선택하세요 ??
Do_lookup_x 브레이크포인트가 실행된 GDB로 돌아가죠
바로... 백트레이스 패널을 한 번 보면
기호 해상도가 복잡하다는 걸 알 수 있어요
이미 네 가지 기능을 할 만큼 했으니 수리한 부품에만 집중할 거예요 그누 해시 섹션도 연관돼 있어요
네 동적 링커는 기호를 찾을 때 두 가지
중요한 정보를 사용합니다 그들의 이름이죠 이 경우엔 '엑시트' 그리고 그 이름의 해시죠
해시를 생성하는 알고리즘은 중요하지 않아요
네 더 깊이 알고 싶다면 플랩갠에 올라온
글을 보면 이 강의 자료에서 유용한 정보를 찾을 수 있어요
다음 44형은 우리가 처음 수리한 곳에 도착합니다 그누 해시 섹션이 쿼리되었습니다
이 줄은 exit 해시를 이용해 '비트마스크'라는 걸 회수합니다
신포 측에서 libc 자료가 아닌 우리 자료를 이용했어요
비트마스크는 제가 언급한 세 가지 중요한
가치 중 첫 번째입니다
다음은 비트마스크_단어 변수를 청크에서 회수합니다
버튼 하워드 블룸처럼 블룸 필터를 사용했어요 블룸 필터는
집합에 속하는 것들을 확인하는데 사용됩니다 이 경우에는 exit 해시가 집합이고 집합은
libc 함수의 해시인 것이죠 해시는 2000개가 넘습니다 ? ?
아니... 블룸 필터의 원리는 모르지만 여기서 쓰는 건 우리가 찾는 기호가 dso 안에 있는지 확인하는 데 쓰일 거야 공동 도서관에
있는 모든 기호를 수색하는 것보다 빠르지 안 돼요, 그건 너무 빨라요
프로세스가 로드되었습니다
다음 4번 개화 필터가 libc에 출구 표시가 있다는 걸 확인한
지점이에요 '개화'라고 한 이유는 개화 필터는 거짓
양성을 만들어 내거든요 우린 그렇지 않다는 걸 알지만요
exit 해시가 값 추출에 사용됩니다 그누 해시 섹션에 이번엔 '버킷'을 넣어요
여기서의 발상은 모든 libc 기호의 해시가 소위 체인이라는 배열에 저장되고 이 버킷 값이 체인을 찾는 데 사용된다는
거죠 해시가 사는 곳이죠
체인은 여기서 체인은 일련의 해시입니다 중요하지 않은 해시가 체인의
마지막인지 아닌지 나타내기 위해 희생되는 거죠
축소된 예제입니다
우리의 해시는 6비트 길이라고 상상해 보세요 이게 우리의 출구 해시입니다
네 해방군 해시 테이블을 보면
이런 게 나올지도 몰라요 우리가 보는 해시 전후로 수백 개의 해시가 있는 거죠
가장 덜 중요한 해시가 굳으면 그게 마지막이 되죠 해시가 3개인 체인이 만들어집니다 해시 체인이
하나인 거죠
방금 버킷 가치를 회복했어요 그누 해시 섹션은 우리가 찾는 해시를
포함하는 체인을 가리킵니다
확인만 하면 출구 해시와 체인점의 해시를 끝까지 비교할 수 있어요 맞아요 끝까지 일치하는 걸 못
찾으면 꽃 필터가
가짜 양성을 줬거나 기호가 없는 거예요
첫 번째 해시 포인트를 확인하죠
일치하는 사람이 없어요
두 번째는요? 성냥갑! 가장 덜 중요한 건 버리는 거예요
일치하는 해시의 인덱스는 중요한 정보입니다
기호 테이블의 출구 함수 엔트리의 색인은 같죠
GDB에서 볼 수 있어요
다음 5번으로 가면 첫 번째 해시가 확인됩니다
우리가 확인할 해시시예요
출구 해시입니다
아쉽지만 틀렸어요
다음 두 명은 다음 해시로 진출합니다
사소한 건 둘째 치고 일치하는 게 있어요
네 이제 exit 해시를 찾았으니 기호를 찾기 위해 해시 테이블에서 인덱스를 사용합니다 테이블 엔트리 ?
Next 5를 치고 sy미트x 변수를 검사합니다 방금 찾은 해시의 인덱스를요
기호 테이블 네 그 기호의 이름과 버전을 확인함으로써
해시 충돌이 없다는 걸 확인하는 거죠
Next 3을 입력하고 check_match가 반환한 기호를 검사합니다
이건 가짜 표식 테이블이에요
네 st_name 필드는 올바른 인덱스를 문자열 테이블에 갖고 있죠 귀찮은
방법으로 libc load 주소를
찾는데 원하면 입력할 필요도 없죠 st_value 필드는 시스템 함수의 오프셋을 갖고 있어요 ?
그 3가지 정보∙∙∙ 블룸 필터에 사용되는
비트마스크 버킷 번호, 그리고 해결되는 함수의 이름 해시를 제공함으로써
우린 성공적으로 기호 해상 프로시저를 가짜 기호 테이블 엔트로 안내했습니다
마지막 단계가 계획대로 진행되는지 확인하죠 시스템에 중단점을 설정하고 계속합니다
좋아요
시스템뿐 아니라 프로그램의 종료 장면에도 연락했습니다 곳 plt 구역이 시스템 주소로 업데이트됐어요
잠재적으로 여러 번 호출할 수 있다는 의미죠
실행의 흐름을 임의의 libc 주소로 재조정할 수 있는 것 같네요
세 마리밖에 안 잡았는데 주소 하나 안 새고 나쁘지 않네요
게다가 추측할 필요도 없으니 매번 성공해야 해요
좋습니다 개발 스크립트로 돌아가죠 프로그램 메뉴에서 중단 옵션을
고르는 라인을 추가하겠습니다 아까 수동으로 한 것처럼요
자... 어떤 분들은 그냥 기술을 익히고 넘어가고 싶어 하지만 껍데기를
원한다면 아직 할 일이 남았어요
이 전화 시스템은 특별히 유용하지 않아요 전달된 인수를 제어할 수 없으니까요
한 가지 장비가 더 적절할 것 같군요
우리가 할 일은 가짜 기호 테이블 출력의 st_value 필드를 바꾸는 것뿐입니다
네 아시다시피 전 마지막에 반전을
주는 걸 좋아하는데요 그렇게 간단하지 않을 겁니다
마지막 부분을 도전으로 간주하시면 잠시 후 화면 정지 기능을 보여드리겠습니다
그 후, 이 바이너리의 껍질을 벗기는 몇 가지 방법을 살펴볼 겁니다
마지막으로 지금까지 배운 걸 요약해 보죠
멈춘 후에 봐요
머로더스_mmap 바이너리를 위한 솔루션 스크립트입니다
우리 강의 자료에서 복사본을 다운로드할 수 있어요
레이아웃을 약간 바꾸고 주석을 추가했어요 하지만 정지 전 위치에서 유일한 기능적 차이는
가짜 기호 테이블 엔트리의 st_value 필드입니다 ???
좋아 1개 장치를 실험해 왔다면 어쩌면_script_exeror를
알아볼 거야 "() 함수 셸을 호출해 파일을 스크립트로 해석하고
글립벡 2에서 유일한 장치를 포함합니다 가젯 툴에 따르면 33번째 빌드입니다
네 이 사진을 보면 r12와 r13 등록기는 둘 다 null이거나 포인트 투 null이에요
네 One-gadget의
출력만으로는 명확하지 않습니다 리다이렉션한 주소가 약간 다릅니다 아주 약간은 다르지만요
마지막 중단을 선택했다면 GDB 옵션에 있는 스크립트를 실행합니다 exit을 호출하기 전에 제 하나의
도구에 중단점을 설정할 수 있습니다
r12는 준비가 됐지만 r13은 아직 안 됐어요
네 네 함수에 들어간 값이
그 함수에서 돌아오기 전에 복원된다는 뜻입니다 ? 네, 그렇습니다
그래서 바꾸기 힘들 수 있어요
그 주식은 여전히 argc와 맞먹습니다
도구가 제시한 한 가지 장치는 여기 _script_exevelop+143에 있어요 네 컨벤션에 호출하는 x64
리눅스를 잘 아신다면 r13이 execve의 argv
배열을 포인터링하는 역할을 한다는 것을 아실 겁니다
1편에서 이것이 얼마나 깨지기 쉬운지 보셨죠
대시 셸의 argv는 가독 가능한 주소를 갖고 있어야 합니다 현재 그 제약 조건은 충족되지 않았죠
네 알고 보니 이 단일 도구는
강력하지만 제약을 바꿀 기회는 전혀 없었습니다
네 주의하세요 여러분의 툴이 제가 보여드릴 장치를 찾았다면 david942j가 업그레이드했어요
제가 이걸 썼거든요
네 찾을 필요가 없어요 가젯의 제약 조건을 바꿀 코드를 찾기까지요 아마도 _script_ex텝+175에서 위조된 st_value
필드의 오프셋을 찾을 수 있어요
설명서를 잠깐 읽어 보시면 스택에 arv 배열을 준비하고 있는 걸 알
수 있습니다 r13을 가리키죠 방금 본 장치로 넘어가서
여기서 중요한 차이는 rdi 등록이 argv1로 사용된다는 거예요
이 도구의 제약 조건을 "r12와 rdi, 포인트 투 null"로 변경합니다
네 다행히 rdi는 출구로 가는 코드 즉, 0입니다 프로그램이 오류 없이 종료됐기 때문이죠 ?
네 계속하겠습니다 프로그램 창으로 변경하면 약간
긴 이 장비가 작동하는 걸 확인합니다
네 네 최종 개발을 시험하고
옵션 없이 개발 스크립트를 실행하겠습니다
아직 작동해요
핵폭탄을 터뜨릴 수 있는 믿을 만한 기술이 생겼어요
네 이 바이너리에
대한 대안도 썼어요 이 장비의 원조 도구를 사용하는 거죠
일부러 수표를 안 쓰는 것 같은 재미있는 기능도 있죠
이 기술을 확장할 방법을 배우고 싶다면 한번 보세요 pwntools_halution_2
라벨로 붙여진 리소스에서 다운로드 받을 수 있습니다
네 두 가지 중 아무것도 못 찾았어도 걱정 마세요 각각
몇 시간씩 걸려서 생각해냈고 취약한 2진법을 썼어요
첫 번째 것을 포함한 이유는 자동화 툴이 항상 믿을 수 있는 것은 아니라는 것을 보여주기 위해서입니다
네 어떻게 리디렉션할
수 있는지에 대한 예입니다
하지만 혼자서도 껍질을 떨어뜨리다니 정말
대단해요
다른 해결책을 생각해 냈다면 꼭 듣고 싶네요
다음 수업을 진행하기 전에 이 방법을 정리해 볼게요 취약한 머로더스_mmap
바이너리는 NXStackcaaries position-indepence와
연계됐고 글립코 버전 2와 연결됐습니다 33년, 녹음 당시 최신 버전이죠
하지만 이번에는 일부만 시행했습니다
네 즉 libc와 같은 외부
라이브러리 기능의 주소는 함수가 처음 호출됐을 때만 해결된다는 겁니다
네 전체 렐로가 예전보다 흔해졌지만 일부 개발자들은 부분적으로만
렐로를 선호할 거예요
예를 들어 이 프로그램이 많은 기능을 수입하고 반복적으로 실행될
것으로 예상되면 부분 렐로의 성능이 향상될 수 있습니다
말록은 세 마리밖에 없었어요 둘은 libc 바이너리 앞에서 mmapped
덩어리를 할당했죠
24바이트가 넘쳐 났어요
청크의 크기를 조절하는 데 사용했어요 몇 페이지를 늘렸죠
그 후에 변형된 크기로 제거했어요
지도를 풀었는데 libc 바이너리에 대한 여분의 기억과 함께요
네 지도에서 뗀 blic 페이지에는 해시 테이블과 기호
테이블이 있었는데 둘 다 기호 해상 프로세스에서 사용되고 보통은 작성 불가능으로 표시됩니다
세 번째 mmapped 검사를 요청함으로써 같은 libc 페이지를 쓰기 쉽게 매핑했어요
해시 네 미해결 기호의 st_value 필드를 바꿨습니다
이 경우엔 exit이죠 실행하고자 한 libc 코드의 상반을 갖기 위해서요 안 돼요
네 마침내 미해결 심볼에 호출을 해서 위조 심볼 테이블 항목이
해상과정에 사용되게 했습니다 ????
수정된 st_value 필드로 출구가 하나뿐인 장비인 것처럼 보이게 했죠
프로그램 업데이트에 사용된 주소예요 곳 plt 섹션,
실행이 그리로 리다이렉션되어 셸을 놓습니다
맞아요 주목할 가치가 있어요 libc를 목표로 공격했지만 어떤 공유 라이브러리에든 이 기술을
이용할 수 있죠 프로그램이 상징 중 적어도 하나를 풀지 못한다면요
물론 이 기술은 렐로의 일부가 있어야 가능합니다 네 초기화 과정에서 렐로 부호가 모두 해제됩니다
실행의 흐름을 장악할 수 없죠
게다가 꽤 효과적인 기술이에요
말록 세 마리만 있으면 포탄을 구할 수 있었고 그걸로 믿을 만한 취약점을 만들었어요
주소를 유출하지 않았는데도요
생산 소프트웨어를 이용하는 데 사용됐으니 현실에서도 쓸 수 있어요
네 앞서 말씀드렸듯이 머로더스_mmap
바이너리에 대한 평가가 있는 취약점을 강의 리소스에서 다운로드할 수 있고 기술을 확장할 수 있는 두 번째 취약점도 있습니다
이 부분을 바탕으로 한 퀘일리스의 연구에 경의를 표합니다
네 리소스에 있는 블로그 게시물을 확인하면 작업에 영감을
준 사람을 언급한 게 보일 겁니다
흥미롭게도 알렉산더 페슬랴크요 케이 a 링크 해제 기술의 원조인 솔라 디자이너도 언급됩니다
더 알고 싶다면 잊지 마세요 그누 해시 섹션에 플래핀긴
블로그도 링크했어요
네 마지막으로 맥스웰 둘린에게 감사드립니다 '하우스 오브 뮤니'라는 제목으로 퀘일릿을
쓴 작가죠 거기서 이 기술을 처음 들었습니다 안 지 오래됐어요
이번 강의는 여기까지입니다
좋아요, 작별 영상을 놓치지 마세요 Linux 힙 개발의 미래에 관해 짧게 논의할 겁니다