이 영상에서는 로어의 집을 통해 가짜 덩어리를 라지빈에 연결하는 법을 배워보겠습니다
다시 한번 말록의 내장을 살펴볼 겁니다
이번에는 말록의 라지빈입니다
라지빈은 두 가지로 연결된 원형 목록입니다 원형의 머리는 경기장에 놓여 있죠 이 원형은
아레나 레이아웃 도표는 스몰빈 다음의 라지빈을 보여줍니다
라지빈은 64개인데 실제로 63개가 사용되고 있어요
네 덩어리는 라지빈으로 분류할 수 있습니다 정리가 안 된 크기는 0x400
이상입니다
라지빈은 다른 통들과는 다르게 행동합니다 라지빈은 크기가
제각각이죠
0x400 라지빈에는 크기가 다 달라요 0x400, 0x410 0x420,
0x430
네 네 , 크기도 있고요
라지빈은 말록의 출처 코드에 따르면 대략 로그 간격으로 큰 통에 들어갈수록
덩어리 크기가 더 넓어집니다 ? 네
예를 들어 0x5000 라빈은 0x5000부터 0x5ff0까지 크기가 다른 덩어리들을
담을 수 있습니다
0x80000개 이상의 덩어리가 들어가는 가장 큰 라지빈은 상한선이 없습니다
네 라지빈에서는 큰 것부터 작은 것까지 순서가 있습니다 쓰레기통 머리에서 큰 덩어리로
시작해서 꼬리로 갈수록 작아지죠 ? 네
그건... 순서를 지키는 건 소위 행방불명자 명단이란 걸 통해서죠 설명해 드릴 수 있어요
0x400 라지빈 예시가 있어요 네 늘 그렇듯 전 이 쓰레기장의 우두머리를 대변합니다
말록이 그렇게 다루니까요
네 네 2x410 덩어리와 0x400
덩어리요 ? 네
네 두 배로 연결된 원형 목록처럼 각 데이터의 첫 번째와 두 번째 쿼드워드도 앞뒤 포인터로
용도가 변경됐습니다
그리고 또한 그리고 ??????
이 다음의 점들이 두 배로 연결되는 원을 만듭니다 같은 라지빈 안에 있는 각 크기의 첫 번째
덩어리가 포함되죠
네 이건 스키프 리스트인데요 fd와 bk- nextsize 포인터를 포함하는 큼을
참조합니다
네 이 경우 처음 0x430은 fd_nextsize로 첫 번째 0x410을
가리키죠 0x420은 없으니까요 ? 네
네 그 0x410은 fd_next사이즈로 0x400으로 연결되고 0x400의
fd_next사이즈로 첫 번째 0x430으로 연결되죠
물론 bk_nextsize 포인터도 반대 방향에서 똑같이 합니다
네 라지빈으로 연결하면 크기가 하나뿐인 경우 스킵 덩어리가 되고 라지빈과
그 빈의 행방불명 목록에 연결됩니다
네 같은 크기의 덩어리가 추가되면 스킵 리스트를 방해하기보다 단순히 스킵 청크를
한 다음에 통에 연결됩니다
예를 들어 0x430 크기의 덩어리를 이 라지빈에 분류하면 여기에 추가되고
fd와 bk 포인터만 수신됩니다
네 0x430 크기의 할당량도 마찬가지입니다 0x430의 맨 위에 있는
것에서 가져온 것이죠 즉, 한 덩어리가 한 덩어리로 바뀌면 항상 할당되는 마지막 크기가
된다는 것입니다 ,
네 그리고 이 구역에서는 쓰레기통에 있는 0x410 덩어리를 치우고 0x400
덩어리 다음에 더 넣을 거예요
네 좋아요 현재 라빈에서 0x400이 유일한 크기이므로 다음 요청에
해당하는 0x400을 할당해 행선지 변경해야 합니다
네 0x420 크기의 덩어리를 이 라지빈으로 분류한다면 첫 번째 크기일
것이고 지난 0x430보다 더 큰 통에 저장될 뿐만 아니라 0x430과 0x410
사이의 건너뛰는 목록에 저장될 겁니다
라지빈을 실험하고 싶다면 말록 실험대가 최적의 장소입니다
히댑랩 PDF에 라지빈 섹션도 있어요
일단 이 정보를 가지고 로어 하우스를 통해 가짜 덩어리를 라지빈과
연결할 수 있는지 보죠 네 스몰빈을 수정할게요 당신도 그렇게
해요 아니면 지난 강의 솔루션 스크립트를 참고하든지요 안 돼요
네 우선 0x400 라지빈에 덩어리를 두 개 담을 겁니다 이유는 곧
알게 되겠죠
청크 A의 크기를 0x3f8 바이트의 사용자 데이터를 요청해서 0x400으로 바꾸고 청크 B도 똑같이
해 주세요
네 물론 덩어리 A와 B는 둘을 풀어주면 통합되니까 그 사이에 가드
청크를 요청해 막아야 해요
윗부분이 뭉치지 않도록 B를 더 넣습니다
네 큰 덩어리는 무정화 빈을 통해 라지빈으로 이동하니까 두 덩어리를
무정화 빈에 넣죠
네 일단 더 큰 덩어리를 요청해서 정돈되지 않은 채 수색합니다 두 덩어리를 0x400
라지빈에 분류하죠
지금은 스크립트의 나머지 부분에 해설을 달아 GDB와 NOASLR 옵션에서 실행합니다
GDB를 입력하고 '힙' 명령을 내립니다
네 네 'vis'는 사용자 데이터의 힙을 자세히 묘사하지만 다수의
큰 덩어리를 다룰 땐 '힙' 커맨드의 개요가 더 작습니다
결과물을 보면 A와 B는 주석이 부착되어 있고 라지빈에 연결돼 있습니다
'라지빈'에 확인했습니다
둘 다 400배 크기에 fd와 bk 포인터스가 두 번 연결되어 있습니다
네 A는 이제 400번 째예요 A는 B보다 먼저 풀어 줬어요 먼저 정돈되지 않은 부분에 연결됐다는 뜻이죠
목록의 마지막 부분이에요 ? 네, 맞아요 네 정화되지 않은 부분을 앞뒤로 수색합니다
0x410
크기의 덩어리를 요청하자 가장 먼저 a를 0x400 라지빈에 넣고 그다음
b를 넣습니다
네 네 여기 fd와 bk의 포인터가 보이네요 두 개의 포인터가
연결되어 있습니다 이 목록은
네 이 통에는 400개밖에 안 들었기 때문에 0x400개만 남은 걸 가리키고 있습니다 그래서 0x400개를
빼돌린 거죠
네 네 우연이 아니죠 ? 네 큰 덩어리는 무체계로 연결되면 다음
단계의 포인터가 무효화됩니다
네 매크로 또는 함수의 존재 여부를 통해 건너뛰기 목록에서 어떤 덩어리를
취소할지 결정하기 때문이죠
네 가짜 덩어리를 이 0x400 라빈에 넣고 싶다면 제대로 넣으세요 첫 번째로 우리가 대답해야 할 질문은 이
목록 중 어떤 걸 대상으로 해야 하느냐는 겁니다 건너뛰기 목록? 아니면 bin 자체?
둘 다 둘 다 아니에요 말로크를 통과하는 경로는 약간 다르지만 가짜 덩어리의
전제 조건은 같아요
스키핑 리스트를 대상으로 한다면 bk_nextize 포인터를 손상시켜야 해요
라지빈을 목표로 하려면 일반 fd를 손상시켜야 해요
우선 마약부터 좀 손봐야죠
네 백워드 포인터가 아니라 포인터를 목표로 하는 이유는 라지빈 할당 루틴에 있는
코드 조각 때문입니다
말록은 네 이 댓글에서 알 수 있듯이 말록은 스킵 덩어리를
할당하지 않으려고 하죠 하지만 스킵 덩어리는
네 두 번의 검사를 통해 다음 통에 든 덩어리가 할당 대상인지
확인합니다 먼저 말록은 통에 남은 덩어리가 마지막인지 판단합니다 통의
큰 빈을 따라가서 같은 통에 있는지 확인하죠
네 이게 마지막이 아니라면 말록은 이 덩어리의 fd를 따라가서 목적지에 도착한
덩어리가 크기와 일치하는지 확인합니다
그렇다면 다음 덩어리가 건너뛰기 대신 할당되죠 이 말은 가짜 덩어리를 이렇게 할당하려면
우리가 조작하는 것과 크기가 맞아야 한다는 거죠
네 네 라지빈 중앙에서 할당될 수 있으니까요
, 네
네 가짜는 링크를 푸는 수표를 통과해야 하는데 그건 이미 방법을
알죠
GDB를 닫고 편집장으로 돌아가세요 가짜 청크를 준비해서 0x400 라지빈에 연결할
거예요
좋아요 주석을 없애죠 버그를 활용해서 A의 메타데이터를 조작하는 거예요
시작할게요 첫 번째 null 4글자를 삭제해요 청크 a의 fd를 덮어쓰는 거죠 우리 가짜 청크의 주소로요 거기요?
네
이걸 할 때는 400블록 라빈을 빼야 한다는 걸 명심하세요
다음은 가짜 청크 메타데이터를 준비합니다
네 네 스몰빈 변형에서 나온 걸 꺼내 다음을 추가하세요
사용하지 않는 prev_size 필드를 채울 null
4워드 청크 a의 크기와 맞는 사이즈 필드요 이 경우엔 0x401이죠
네 네 깃발도요 왜냐하면 맬록은 이 비교를 위해 청크 A의 영역과 노마스크를
이용하기 때문이죠 두 영역의 어떤 부분도 가리지 않습니다
네 네 전에 이렇게 해서 양쪽을 가리켰어요
서로 다른 쪽을 가리켰죠
네 그런 수정을 하고 나면 일반적인 옵션으로 스크립트를 실행하세요 그래야 Fake 청크를 요청하기 전에 모든
걸 확인할 수 있으니까요 ,
'더미' 명령에 따라 파손하고 검사하세요
네 네 메모리를 놓으면 fd가 가짜 청크를 가리키는
걸 볼 수 있어요 ? 네
가짜 청크의 크기가 청크 A와 일치해요
그리고 단조로운 fd와 bk는 안전 연결을 끊는 수표를 전달할 겁니다
우리가 고려하지 않은 건 fake 청크의 nextsize pointers 값입니다
네 네 ?????
기억하십시오 큰 덩어리는 다음 크기 필드가 무의미합니다 정리가 안 된 빈에 연결될 때 말이죠
저희 경우엔 fake 청크의 fd_nextsize가 null이라 걱정 안 해도 됩니다
네 null 4자 말고 다른 걸 써야 한다면 Nextsize 필드 둘 다 링크를 해제하는
확인을 통과해야 합니다
넥스트사이즈 안전 언링크는 글리벡 2에서 소개됐습니다 21살요
Fake 청크를 할당하고 타깃 데이터를 덮어쓸 준비가 됐죠 0x400 사이즈 청크를 요청하면
말록이 그 창고를 수색할 거예요
스킵 리스트를 네 이 경우엔
a 청크죠
안 돼요 네 a 덩어리가 마지막이 아니므로 멀록이 부패한 포인터를
따라 가짜 덩어리를 찾아서 할당 후보인지 확인할 겁니다
가짜 청동이가 A와 일치하니까 말록이 연결을 풀고 배정할 거예요
네 GDB를 닫고 에디터로 돌아갑시다. 마지막 요청을 하고 타깃 데이터를 덮어쓰는 곳이죠.
다음 호출을 제거합니다 다음 호출은 도우미 기능을 제거하고 다음 호출은 주석 처리 해제합니다 요청
크기는 0x3f8로 바꿉니다 가짜 덩어리를
넣을 수 있을 거예요
네 마지막으로 마지막으로 , () 우리 데이터로 대상을 덮어쓰는 도우미
함수
GDB와 NOASLR 옵션 없이 생산 조건에서 착취를 실행하세요
네 메뉴 출력을 누르세요 메뉴 출력을 누르세요 4번을 선택해서 대상 데이터를 인쇄하면
로어 라지빈스 가문 변종으로 임의로 썼다는 걸 확인할 수 있다
네 다시 말하지만 무체계빈 변이보다 제약이 더 많았어요 가짜 청크를 위한 정확한
크기 필드가 필요했죠 안전한 링크 해제 확인을 통과할 수 있는 포인터와
같은 걸 하거나 null일 수 있는 Nextsize 포인터요 ?
적어도 물이 새지는 않았잖아요
네 이 예에서 라지빈에 무료로 있는 fd를 손상시켰지만 bk_nextsize
포인터를 손상시킬 수도 있었죠 , 대신에요
네 편집에 속칭 사보 단어를 3개 추가할게요 콜: 포인터를 우리 fake 청크로 옮긴다 청크
a fd에서 bk_nextsize 포인터로
네 이렇게 하면 피해자가 통에 마지막으로 남죠 그럼 다른 덩어리도 제거할 수
있어요
네 게다가 라지빈에서 할당된 할당은 가짜 덩어리를 바꾸는
암묵적인 나머지 작업이죠
0x400 라지빈에 포함되지 않는 값으로 설정할 수도 있어요
생산 조건에서 착취하면 같은 결과가 나옵니다
로어의 집을 거기에 남겨 둘 거예요 이 기술로 쇼를 망칠 수도 있지만 방금
한 걸 활용하는 게 더 좋아요 가짜 덩어리를 할당하거나 민감한 프로그램 데이터를 중복하는 거죠
?
네 2진법이 libc 주소를 흘리긴 해요 그러니 거기서 껍데기를 떨어뜨리고
싶다면 얼마든지 해 봐요 ?
네 로어 가문의 세 가지 변종에 대해 저희가 다룬 내용을 보고 싶으시다면 pdf 파일에 자료가
들어 있어요 말록
테스트베드는 말록의 활동을 관찰하고 공격성을 개발하는 데 유용합니다
주석 달린 솔루션 스크립트를 다운로드해 로어 라지빈스 프로그램을 확인할 수 있죠
네 다음은 포이즌과 널 바이트를 다루고 가장 어려운 바이너리의 껍데기를
벗길 겁니다