이 영상은 좀 이상하죠
새로운 기술을 가르치거나 말록의 내장을 치료하진 못해요
하지만 우리가 배울 건 여전히 중요하다고 생각해요
네 소위 중력 풍수를 살펴볼 텐데요 알렉산더 소티로프가 2007년 블랙하트
유럽에서 착취 개발 중 중 중력 배열의 목적적 구조를 설명하는 용어로
네 위키백과에 따르면 역사적으로 풍수는 건물을 유리하게 만드는 데 쓰였다고
합니다 하지만 개발 공동체 내에서 융 융이라는 명칭이 굳어졌습니다
네 이미 제한된 풍수지리를 활용했어요 1_독극물_null 도전 이바이트를
이용해서요 전략적으로 청크를 배분해 넘치고 겹치는 경로에 배치했죠
네 이제 한 단계 더 나아가서 다른 곳에는 없는 기술을 선보일 겁니다
네 우리 솜씨에 맥락을 더하기 위해 토끼의 집을 변형한 버전을 활용할 겁니다
아직 기억이 생생할 때요
네 검색해 보세요 래빗_nastory로 가면 수정된 이진법과 pwntools 템플릿 스크립트가
있습니다
Checksec 출력은 이전과
같습니다 GDB 아래에서 바이너를 실행해 뭐가 바뀌었는지 보죠
네 메뉴는 비슷합니다 눈에 보이는 차이는 청크를 13개까지 요청할 수 있다는 것뿐이죠 아까보다
4개 더요
네 하지만 옵션 1을 요청했을
때 규칙이 바뀐 게 분명합니다 빠른 크기의 덩어리를 요청할 수 없습니다 0x78바이트
이하의 요청은 무시될 것입니다
이번엔 0x90 이상 크기로 한정돼 있어요
토끼의 집에서는 큰 문제가 아니에요
대부분의 기술은 큰 요청을 통해 메타데이터를 조작합니다
하지만 패스트 덩어리에 대한 제한 때문에 첫 단계가 더 어려워져요 패스트빈에 가짜 쓰레기를
연결하는 거죠
네 원래는 패스트빈 둡으로 해결했어요 똑같은 크기의 청크 두 개를 요청해서
하나씩 분리하면 패스트빈 더블 프리 완화 절차를 우회하고 복제된 청크를 요청해서
패스트빈 메타데이터를 조작할 수 있어요 ?
네 그래도 페이크 청크를 패스트빈에 연결하는 것부터 할 거예요 결국 얘기했듯이
가장 쉬운 상자니까요
네 하지만 실제로 큰 덩어리를 요청하지 않고 해야 합니다 그래서
풍수지리를 더하는 거죠
네 패스트빈에 연결된 덩어리와 포워드 포인터만 있으면 됩니다
물론 그러려면 버그를 이용해야 할 거예요 기존의 토끼 하우스 바이너리에 대항해
더블프리를 이용할 거고요
먼저 약간 다른 관점에서 더블 프리 버그를 이해하겠습니다
마이터사의 CWE 즉, 공통 약점 열거는 일반 사용 후 무료라는 꼬리표입니다
그리고 둘 다 '기한 지난 포인터 퇴치' 범주에 들어가요 '대기 걸린 포인터'라고도
하죠
더블프리를 매달린 포인터로 취급하면 응용 프로그램을 확장할 수 있습니다
네 지금까지 지금까지 ????
네, 맞아요
하지만 프리 덩어리가 통합되고 재정비될 수 있으니 이렇게 생각해
봐요 더블 프리로
전화하면 프리로 전화할 수 있어요
네 이제 우리는 운영할 크기 필드만 있으면 된다는 걸 압니다 패스트 청크는 무료로 통합되지
않고 적절한 패스트빈에 직접 연결됩니다
네 패스트빈에 연결하고 싶으면 그냥 한 덩어리를 빼서 매달린 포인터를 설정하고
재정렬하면 매달린 포인터가 빠른 사이즈로 가리키죠, 0x20 0x30 기타
등등
매달린 포인터를 풀어줍니다
복잡하게 들린다면 걱정 마세요 제가 차근차근 설명해 드릴게요
GDB를 닫고 pwntools_template를 복사하는 것으로 시작하겠습니다 pi 대본
편집기에서 복사본을 열고 아래로 스크롤을 내립니다
네 이 스크립트 견본은 원작에서 사용한 것과 차이가 없습니다
다만 가짜 덩어리는 이미 크기가 1로 설정됐죠
네 다른 단계들은 아직 걱정하지 마세요 이 최소의 틀부터 시작할 거예요 네, 좋아요
그래야 검사할 때 문제가 없는지 알 수 있죠
나중에 원래 취약점으로부터 많은 코드를 복사/붙여넣을 수 있어요
현재 상태로는 0x90 크기의 두 덩어리를 A&B로 나눠서 자유롭게 해 주면 됩니다
네 GDB와 NOASLR로 스크립트를 실행하세요 그럼 보여드리겠습니다 더블 프리란 말뜻은 달랑거리는
포인터로 보일 수 있다는 거죠
GDB를 ctrl+c로 분해합니다 그런 다음 pwndbg의 'vis' 커맨드로 힙을 검사합니다
보세요 보시다시피 두 덩어리가 맨 위와 합병되어 할당된 덩어리도
없고 남은 덩어리도 없습니다
네 제일 위쪽을 보죠 메모리와 'dq'를 떼고 메인 경기장의 'top' 필드를 이용하면 이 작업을
할 수 있습니다 38개 단어만 버려요
잘 알잖아요 그 공간은 가끔 말로크 메타데이터로 용도 변경되는 것 말고는 승인되지 않았어요
메모리가 할당된 칼로스에 0이 되더라도 무료로는 0이 되지 않습니다
위쪽에는 여전히 음식 찌꺼기가 남아 있어요
사용자 데이터가 여기서 시작되고 매달린 포인터가 가리키는 곳이죠
앞으로 언제든 이 주소로 무료로 전화할 수 있어요
이게 얼마나 유용할지 예를 들어볼게요
주소 기억해요, 0x6030a0
계속 GDB에서 프로그램 창으로 가서 두 덩어리를 요청합니다 첫 번째는 다시 0x90 사이즈로 하고
두 번째는 0x100
사이즈로 만들 거예요
GDB로 돌아가 'vis'로 다시 검사하겠습니다
최근 두 개의 덩어리가 있습니다 매달린 포인터의 주소를 기억하세요 0x6030a0입니다
사용자 데이터는 크기가 다른 0x100입니다
네 더 중요한 것은 제작 프로그램에서 이 덩어리는 매달린 포인터를 생성했던 덩어리와는
전혀 다른 것에 할당되었을 수도 있습니다 ?? 네
이게 미칠 영향을 생각해 보세요 0x100 cunk은 프로그램의 전혀 다른 부분에 속할 수 있습니다
다른 스레드가 같은 아레나를 공유할 수도 있죠
버기 코드로 풀면 버기가 없는 코드는 더블이나 애프터 비가 됩니다
네 이런 걸 이용해서 창의력을 발휘할 수 있어요 그래서 제가 좋아하죠
다행히 우리 상황은 십자선보다 간단해요
이제 떼어낼 덩어리의 크기를 패스트 사이즈로 바꾸면 돼요
네 이것도 쉽진 않아요 빠른 덩어리를 요청할 수 없으니 빠른 덩어리 크기의
필드를 어떻게든 수거해야 해요
사이즈 필드를 작성할 수도 있어요 청크 사용자 데이터에요
저는 그건 너무 간단하다고 생각했거든요 어쨌든 16부터
8까지의 사용자 데이터는 바이트 단위로 제한했습니다
청크부터 그리고 사용자 데이터는 항상 16바이트 정렬에서 시작합니다 8바이트 크기를 필드와
맞출 수는 없죠 그래서 좀 더 복잡한 방법을 써야 합니다 ? 네
우리의 오랜 친구 재고 관리를 이용할
수도 있습니다 GDB를 닫고 편집기로 돌아가 더 생각해보죠
네 지금 스크립트가 하는 일은 달랑거리는 포인터를 설정하는 겁니다 그렇게 레이블하죠 ,
"chunk_B" 변수 이름을 좀 더 서술적인 것으로 바꾸세요
빠른 청크 크기의 들판을 이미 매달려 있는 포인터가 차지했던 공간에 집어넣고
싶어요
목표 크기로 0x20을 써서 작게 유지하죠
저희가 요구할 수 있는 최소 사이즈 0x90 플러스 0x20이 0xb0입니다
네 따라서 0xb0을 0x90으로 요청하면 0x20의 잔량이 나와야 합니다
0xb0 크기의 덩어리를 요청하고
위에 통합 가드를 달겠습니다
0xb0 덩어리를 빼죠
그다음에는 0x90 사이즈로 해서 0xb0을 남겨야 해요
네 GDB와 NOASLR 옵션으로 스크립트를 실행하세요 그리고 힙 상태를 확인하세요 중단한 다음 배급하는
'vis' 명령을요
성공이에요! 네 네 힙은 안정된 상태입니다 아직 어떠한 부패나
버그를 야기하지 않았다는 것을 기억하세요 매달린 포인터 덩어리 크기의 영역이 있던 곳에 0x20
크기의 영역이 있습니다
두 번 없는 버그를 이용해 네 안 그러면
아직 시기상조지만 이유를 알아내기 위해 할 겁니다
'기록'을 발령하세요
네 "녹화" "gdb가 모든 지시를 기록해" 실수를 되돌릴 수 있습니다
네 '녹음'이 안 먹혀도 걱정하지 마세요 필수적인 건 아니니까요 수업
중에 많이 쓰지도 않을 거고요
네 네 암호를 푸는 데 어려움을 겪는 것 같습니다 이에 대응하려면 put 함수에 중단점을
설정하세요 프로그램은 메뉴 일부를 인쇄하는 데 사용합니다
이 0x20 덩어리를 떼어내고 GDB를 계속 진행한 다음 프로그램 창으로 넘어갑니다
메뉴 프린트 반환을 누르지 마세요 그럼 put가 작동될 겁니다 옵션 2가 무료인 거 아니까
블라인드로 쓸게요
인덱스 1에서 청크를 꺼내요
네 프로그램이 입력에 도달하면 중단점에서 멈춥니다 gdb로 돌아가서 힙을 다시 검사합니다
네 여기 보시면 0x20 크기의 이 덩어리는 무체중 패스트빈과 0x20 패스트빈으로 연결되어
있습니다
이 자체만으로도 흥미롭습니다 본질적으로 더블 프리 완화 바이패스니까요
맞아요 중요한 건 힙 풍수를 이용해서 빠른 크기의 덩어리를
패스트빈에 연결했다는 거예요
네 이제 남은 건 패스트 청크의 fd에 손대기만 하면 돼요 바이너리 데이터 섹션의 가짜
청크를 가리키죠 토끼의 집이 제자리로 돌아갈 거야
0x20에 fd가 겹치는 구역을 요청해야 해요 0x20 덩어리는 요청할 수 없으니까
일단
통합을 해야겠죠
네 생각보다 어렵네요 0x20 청크의 언소티드빈 fd가 null인 빠른 bin
fd에게 막혔습니다 네
0x90 크기의 덩어리를 꺼내려면 연결을 끊는 세그폴트가 통합 과정에서 널 포인터를
제거하려는 거시적인 시도입니다
네 아무래도 더블 프리 일정을 미뤄야겠네요 이 난장판을 정리할 때까지요 이래서 'record'
명령을 쓴 거야 네 기록 모드가 활성화되면 앞으로
나아갈 뿐 아니라 뒤로도 갈 수 있습니다 GDB 명령에 '거꾸로' 접두사를 추가하면서요 "거꾸로"
이 기능이 강력한 이유는 중단점은 반대로 실행될 때도 작동하기 때문입니다 GDB는 사용자
입력을 기록하고 실행이 앞으로 진행될 때 다시 재생됩니다
네 녹음 모드는 버그를 찾는 데 아주 유용합니다 실수를 해서 프로그램을 다시 시작하는
걸 막을 수 있죠
하지만 처음 보는 걸 수도 있으니 짚고 넘어가고 싶었어요
네 반대로 하는 대신 바로 녹음 시작 부분으로 넘어가서 '고토 비긴'을 쓸게요 ,
'고토 비긴'
네 더미를 다시 살펴보니 0x20 덩어리를 너무 일찍 빼서 실수를 만회했습니다
계획을 다시 시작할 필요 없이 다른 길을 찾을 수 있게 됐죠
네 계속하기 전에 GDB가 사용자 입력을 재생한다고 말씀드렸죠 앞으로 계속 실행하면요
안 돼요
이를 방지하기 위해 '기록 삭제'로 실행 로그를 삭제합니다
이제 다음 0x90 청크를 분리해 보겠습니다
계속하세요 프로그램 창으로 전환하세요 어떤 덩어리를 빼낼지 프롬프트가 이미 나와
있죠
3번을 선택하고 GDB 창으로 돌아갑니다.
네 더미에서 검사한 결과 이 방법은 안 됩니다 0x90 덩어리가 윗부분과 0x20
덩어리로 합쳐져서 우리가 힘들게 만든 0x20 크기가 무너졌습니다
네 그다음은 앞에 있는 0x90 청크를 먼저 떼는 거예요 그러면 크기장에 영향을 주지 않고
0x20 청크와 결합할 수 있죠
네 이렇게 한 다음 나머지 0x90 덩어리를 떼어 내면 위쪽 덩어리가 다른 부분과 잘 결합해서
원래 상태로 돌아갑니다 ? 네
한 번 더 돌려서 기록 삭제해요
네 이 테스트가 마지막이니까 '녹음 중단'으로 녹음을 중단하면 됩니다
다음. 계속하기 전에 중단점 1을 무시하라고 gdb에 알려주세요. 다음 4번의 중단점이요.
그럼 메뉴를 이용해 멈추지 않고 두 번째 덩어리를 얻을 수 있죠
이 부분은 faff인 걸 알지만 이 중단점만 필요했죠 제가 아까 말씀드린 GDB 문제 때문에요
계속하고 프로그램 창으로 가서 마지막 이론을 시험해 보죠
인덱스 4에서 분리하고 인덱스 3에서도 분리해요
네 지수 계산 안 해도 돼요 스크립트는 왜 있는데요? 이건 실험이잖아요
이 덩어리들을 해방하고 나면 GDB로 돌아가서 'vis'로 힙을 검사합니다
네 다시 말하지만 맨 위만 남았고 통엔 아무것도 없어요 그래서 아까 사용한 'dq' 명령을
지정했죠 맨 위 안에 뭐가 있는지 보려고요
네 결과를 보니 흔적 속 0x20 크기 필드는 아직 온전합니다 매달린 포인터를 통해
풀어도 원하는 효과를 낼 수 있다는 뜻이죠
네 이번에는 0x20 패스트빈 fd가 안정성을 유지하면서 활성화된 무체계 메타데이터를 격파하지 않습니다
네 그리고 0x20을 겹쳐서 배분할 공간도 충분해서 fd를
손볼 수 있어요
0x20 덩어리를 너무 일찍 꺼냈을 때보다 상황이 훨씬 좋아졌어요
거의 다 됐습니다 이제 최선의 길을 찾았으니 공격 스크립트에 우리 동작을 추가할 수
있습니다 gdb를 닫고 에디터로 돌아갑니다
네 다시 그 전이죠 뭐든 풀었으니 e 덩어리를 풀도록 선을
하나 더 넣어요 우리가 만든 0x20 덩어리 바로 전이죠
그러고 나서 0x20 덩어리 다음에 d 덩어리를 빼 주는 선을 넣어 줄게요
네 gdb에서 마지막으로 본 상태로 힙을 떠날 거예요 그래서 매달린 포인터를
풀어주는 줄을 스크립트 끝에 추가해 단조된 0x20 덩어리를 패스트빈에 연결합니다
이제 알겠어요 이쯤 되니 상황이 좀 복잡해졌죠? 명확히 하고 싶은
게 있다면 지금까지 영상을 다시 보세요
네 그다음 0x90 크기의 덩어리를 요청합니다 이 시나리오에서 가장 작은 덩어리를 위에서
할당받을 거예요
네 이 위에 있는 0x20을 깔끔하게 겹쳐 줘야 하니까 0x90을
하나 더 얹고 0x20 패스트빈 fd를 조작해서 가짜를 패스트빈에 연결해서
목표를 달성할 거예요
대사를 추가하고 나서 평상시 옵션으로 취약점 스크립트를 실행합니다
차를 부수고 조사해요
최종 설계는 단순합니다 0x90 크기의 토막 두 개로 구성되죠 네 두 번째 청크는 0x20 패스트빈에 연결됩니다
fd는 데이터 섹션에 있는 가짜 청크와 연결되죠 패스트빈의 명령으로 이 프로그램의
데이터입니다
이렇게 세 번째 0x90 덩어리와 20 덩어리가 완벽하게 겹쳐야 했기 때문에 크기를
변경하게 되었습니다
네 전통적인 방식으로 이 패스트빈 둡을 이용하면 문제가 생기겠지만
토끼의 집을 시도하는 거니까 문제가 안 될 거예요
글리벡 2에서 멀록 통합에서 건더기 크기는
금방 확인 못 해요
네 전통적인 패스트빈 둡을 원한다면 크기 조절을 할 방법이 있지만
그건 여러분 시간에 하도록 하죠
맞아요 물론 사용자 데이터의 첫 4분의 1 이상을 통제한다면 위조품
크기도 만들 수 있을 거예요
여러 가능성이 있어요
학습 목적으로 좀 더 제한적인 시나리오를 다루고 있습니다
지금까지 우리가 얻은 결과는 토끼의 집 때 패스트빈 둡과 거의 비슷합니다
네 인정합니다 이번에는 요청을 4번
더 받았어요 하지만 중요한 건 풍수지리의 마법으로 패스트빈 둡을 할 수 있었고
패스트빈에 가짜 덩어리를 연결할 수 있었어요 빠른 크기의 덩어리를 요청하지 않고요 ?
요약하자면 타깃 바이너리는 버그가 두 번 없는 것으로 저희가 이해한 바로는 그냥 매달린
포인터 형태입니다
이 버그를 이용해서 네 자유와 남은 덩어리를 할당했어요 그리고 말록을 조종해서
그 자리에 덩어리를 적었죠 , 아주 작은 덩어리를요 달랑거리는 포인터가 가리키는
건
그리고 더블 없는 버그를 이용해 할당되지 않은 덩어리를 빼낸 다음 겹치게 하고 패스트빈
fd를 조작해서 가짜 덩어리를 패스트빈에 연결했습니다
네 '힙 풍수'라고도 하죠 불가능한 상황을 착취 수단으로
바꾸는 방법입니다
우리 계획이 효과가 있는지 증명하기 위해 토끼의 집을 허물어 버릴 겁니다 이 집을 허물어
버릴 거예요
원래 취약점에 있던 대부분의 코드는 여기에 복사 붙여넣기만 하면 돼요
좋아 메인 경기장 시스템 가치를 높여야 해요 가짜 덩어리를 정돈되지 않은
곳에 옮긴 다음 126번 쓰레기통에 분류해요
성공하려면 두 가지를 살짝 손봐야 한다는 걸 명심하세요 네 미니 챌린지로 취급하고
싶다면 잠시 영상을 멈추고 그 셸을 얻을 수 있는지 보세요
네 중간에 막히면 장애물을 하나 더 통과해야 해요 다시 작동시켜야죠
힌트 드릴게요 한 번 더 기회를 드릴 테니 혼자 해결하세요
잘 돌아왔어요
지금 화면에 보이는 게 제가 이 토끼 집을 변형한 첫 번째 판독법입니다
네 더 알고 싶으신 분들은 저희 강의에서 복사본을 다운로드하세요 템플릿 2라고
적혀 있어요
네 여러분도 아시겠지만 이전 토끼의 집에서 착취한 관련 선들을 복사/붙여 붙였어요
네 초기 가짜 크기 필드는 이 템플릿에서 이미 처리됐고요 메인 Arena의 system_mem
값을 증가시키기 위해 사용한 3줄도 복사했습니다 , 네 풍수지리적 차이 때문에
패스트빈 둡 코드를 풍수적으로 바꿔서 그건 생략했어요
네 네 이 다음에 울록합성을 촉진해야 한다는 걸 기억하시길 바랍니다 가짜 덩어리를
패스트빈에서 가장 큰 라빈으로 이동시켜 방향 감각 없는 통에 담습니다
네 원래는 이렇게 했어요 바로 누른 다음 윗부분과 경계를 이루는 거죠 ?
네
네 네 맬록_consolidate에 호출을
, 네
이 방법이 우리 회사에도 적용되지만 프로그램에 부과된 총 할당량 한도를 고려하면 좀
더 효율적이어야 합니다
하우스 오브 래빗 비디오에서 간단히 언급했었는데요 0x60000 크기의 덩어리를
떼어낼 수 있다고요 system_mem을 증가시켰는데 여기서도 그렇게 한 겁니다
그 후 착취는 이전 시도와 거의 동일합니다
네 짝퉁 덩어리를 분류하면 126번 상자에 들어갈 크기로 바꾸는 거예요
더 큰 덩어리를 요청해서 분류하면
네 가짜 덩어리를 다시 조정합니다 가짜 덩어리와 표적 사이의
거리로 조정하는데 여전히 자유로운 훅이고 중복되는 할당을 만들 수 있습니다
페이크 청크와 프리 훅 사이의 간격을 큰 요청으로 메웁니다
그리고 고리를 겹치는 부분을 할당해서 덧씌웁니다
프리 후크는 16바이트 경계선이 아니란 걸 명심해요
네 물론 컴파일러가 중요하지만 글립벡의 현재 버전은
모두 해당해요
왜냐하면 가짜는 16바이트가 일치하니까요 하지만
하지만 일치시킬 수는 없어요
물론 가짜 덩어리를 잘못 배치할 수도 있지만 이 시나리오에선 그건 선택 사항이 아닙니다
네 이전의 토끼 바이너리로 문제가 되지 않았습니다 16바이트까지 사용자 데이터를
쓸 수 있기 때문이죠 지금 마지막 줄이 그렇습니다 가비지 1사분어드를 쓰고 그 다음에 글립벡
시스템 주소를 씁니다() 함수
네 이 2진법에는 안타깝게도 추가적인 어려움을 주기 위해 사용자 데이터를
바이트 단위로 나누었습니다
변화의 효과를 볼 수 있습니다 GDB와 NOASLR 옵션과 함께 템플릿 스크립트를 실행하면요
메모리를 던져서 빼요
네 바늘이 겹치는 크기로 봐서 지금까지는 성공적이었다는 뜻이죠
네 네 ,
이게 프리 훅이에요
얼핏 보면 성공한 것 같아요 libc 주소처럼 보이네요
하지만 프리 훅이 가리키는 메모리의 지시를 해체하면 메인 아레나를 가리키고
있습니다
프리 훅은 여전히 재투입 과정에서 뒤 포인터를 고정하고 있습니다
이유는 간단합니다 8바이트짜리
사용자 데이터가 프리 후크에 도달하지 못하는 거죠
정렬에 문제가 있어서 다른 표적을 골라야 해요
자 이제 영상에서 여기까지 나오려면 말록 후크를 적어도 써 봐야 해요 16바이트나
연결됐죠
그리고 네 따라서 나머지인 fake
덩어리를 정렬해야 하죠 사용자 데이터의 첫 4분의
1이 대상에 겹치게요 , 그래서...
네 네 나머지는 정리가 안 된 통에 연결되면 우리 데이터로
덮어쓰기 전에 훅을 대체합니다 안 그러면 훅이 사라지죠
네 네 거긴 실행 불가라고 표시돼 있어서 세그폴트를 유발합니다 네
여러분 이번 공격에서 말록 갈고리를 안 써 봤다면 제 말은 믿지 마세요 한번 해 보세요
네 스스로 막다른 길이라고 확신하고 나면 대안을 생각해
보세요
잠깐 잠시 후 영상을 다시 멈추고 이 악기를 직접 마무리해 보세요
전제는 같아요 말똥가리 갈고리를 덮어씌워서 방향을 바꿔서 포탄을
떨어뜨리는 거죠
네 미끼는 이미 써봤습니다 미끼용 바늘과 말록 바늘은 이미 써봤지만 다른 것도 있습니다
네 'nm'을 써서 검색할 수 있어요 이미 설치된 기호를 나열하는 도구죠
우리가 관심 있는 글립벡으로 경로를 전달합니다 'one_gadget' 툴에 전달한
것과 같은 방법으로 할 수 있습니다
한 줄짜리 농담 까먹으면 PDF 파일 부록에서 찾을 수 있어요
아직 안 하셨다면 좀 더 편하게 셸 기능에 바인딩을
하면 됩니다
네 어쨌든 libc 이진법을 'nm'으로
보내고 d 선택권을 따르게 이건 동적 물체니까
네 이것만으로도 글립코 이진법에 해당하는 동적 기호 목록을 출력합니다
기호가 많죠
'그렙'을 사용할 수 있는 기호들로 좁혀 볼게요
분석 결과 말똥가리는 총 6마리인데 우리가 시도한 건 2개뿐입니다
7번째도 명명 규칙을 따르지 않죠
이 시나리오에서 0이 나오면 누구든 만만한 상대예요
보세요 후크 오프셋이 8로 끝나죠 16바이트를 임의로 써서 확인할 수 없어요
안 돼요
네 '전후'라고도 합니다 '전후'는 '전후'라고 하고요 sbrk로
추가 기억 요청
네 즉, 주 투기장의 상단부를 소진하면 안정적으로 작동할 수 있다는 거죠 정확한
논거를 전달하긴 어렵지만요
공짜 바늘과 말록 바늘은 이미 익숙하죠 '레알록_훅'은 물론 '레알록'이 호출됐을
때 사용됩니다
네 '_memalign_hook'은 메모리를 요청할 때 사용되는데 우리가 'malloc_initialize_hook'를
제대로 사용할 기회를 놓친 것 같아요
네 바늘이 언제 사용되는지 알고 싶다면 쉽게 알아낼 방법을 알려 드리죠 말록 바늘을
예로 들어 볼게요
GDB와 NOASLR 옵션으로 템플릿 스크립트를 실행하겠습니다
그런 다음 ctrl+c로 깨요
아시다시피 말똥가리는 갈고리로 기능의 좌표를 얻습니다
GDB에서 함수 포인터는 불편할 수 있습니다 왜냐하면 거기에 중단점을 설정할 수 없기 때문입니다
네 보통은 평소에는 말록 갈고리는 런타임에 아무
소용이 없어서 이 접근법이 무용지물이 됩니다 ?
이를 극복하는 한 가지 방법은 하드웨어 워치포인트를 이용하는 것입니다
네 네 "오전 10시"
계속하면 프로그램 창으로 가서 청크를 요청하면 프로그램이
멈춥니다
네 다시 GDB로 바꾸면 소스 패널이 말똥가리가 바늘을 확인해서 사람이 있는지
확인하는 지점을 보여줍니다
이 경우에는 여전히 무효니까 말록은 정상으로 돌아갈 거예요
감시점으로 네 잠재적으로 취소해서 부를 수 있는지
알 수 있습니다
이 정보를 이용해서 집행의 흐름을 장악할 수 있는지 봐요
이제 영상을 멈추고 최선을 다해 이 토끼 집을 분석해 보세요
조개껍데기 받았어요?
그렇다면 잘했어요 아니면 같이 방법을 생각해 봐요
말록 바늘을 강탈할 건지 정하고 있었으니
범위를 좁혀 보죠
네 후크의 가상 주소가 8로 끝나서 16바이트나 겹치는 범위를 벗어났어요
임의로
쓴 거죠 ?
실물 훅도 같은 문제가 있으니 그것도 빼요
네 네 통제된 데이터로 덮어쓰려 할 때 세그폴트가
발생했어요
네 메말린 훅은 작동이 어렵고 말록_일립라이즈 훅은 역시나 말록 초기화에만
사용됩니다
모어코어와 애프터_모어코어 훅만 남습니다 개발자들이 자신의 시스템 메모리 요청 루틴에 패치할
수 있도록 하는 거죠
네 워치포인트나 맬록 소스 코드를 검색해 보셨다면 기본 힙이
확장될 때 두 훅 모두 사용된다는 걸 아실 겁니다
작동하는지 보죠
우리가 아까 사용하던 템플릿 스크립트를 실행하고 GDB와 NOASLR 옵션을 넘깁니다
브레이크 앤 세트 읽기 워치포인트는 모어코어와 애프터코어 훅에 적용됩니다
계속 진행한 다음 프로그램 창으로 갑니다
네 기본값 힙을 확장하려면 어떤 빈에서도 서비스할 수 없고 맨 위 것보다 큰 요청을
해야 합니다 ,
mmap 기준치를 넘지 않아야 mmap로 할당받지 않습니다
네 네 , 라지빈에 맨 위의 부분은 약 0x21000 바이트
mmap 임계값은 0x61000 바이트
그러면 0x60010에서 0x60ff0 사이의 크기가 상단부를 늘릴 수
있어요
그 범위 어딘가에 큰 걸 요청하고
GDB로 다시 전환합니다
백추적 패널로 분석해 보니 중심부에서 메모리를 요청하는 역할을 합니다
우리가 윗부분을 성공적으로 촉발했다는 뜻이죠 ? 네
워치포인트를 공격하면 다음 지시에서 실행이 중단됩니다
함수 안에 들어온 걸 확인했습니다
모어코어 훅이 가리키는 곳은 sbrk 주변 얇은 포장지입니다
네 이제 참다랑어 바늘을 통해 확실히 촉발음을 낼 수 있다는 걸 확인했으니 포탄을 투하할
수 있는지 보죠
CPU 등록 콘텐츠를 버리도록 '규제' 명령을 발령하세요
우리는 64 비트 Linux 컨벤션을 호출하면 함수의 첫 번째 인수가 rdi 등록에 저장된다는 것을 알고
있습니다 이 경우에는 0x60000이라는 값을 가지고 있습니다
이건... 우리 요청 크기가 아니에요 일반적인 요청 크기도 아니고요 말록이 요청한 양이에요 ?
말록이 요청한 양이에요
네 이 값은 페이지 크기로만 증가할 겁니다 정확한 값은 전달할 수 없다는 거죠 가령, "bin/sh" 문자열
주소를 morecore 훅 함수에 전달할 수 없어요 ??
하나만 써야 할 테니 글리벡 작업에 뭐가 있는지 보죠
네 물론 zsh를 사용하지 않으면 "zsh"를 "bash"로 바꿔야 합니다 그리고 libc를 사용하려면 ()
아까 만든 이런 새 셸 함수를 여러분의 여러분의 "####에 추가해야
바샤르크나 그 비슷한 거요
네 'one_gadget' 툴은 상대적으로 간단한 세 가지 옵션을 제시합니다 raxStack pointer
플러스 0x30 또는 0x50은 null이어야 합니다
네 명백히 확실히 슬프게도 요구되는 스택 오프셋도요 거기서
네 이런 제약이 보기만큼 엄격하진 않다는 걸 알지만 기억하세요 첫 번째 오프셋의 값은
최소한 가독 가능한 주소여야 합니다 하나의 가젯이 작동하려면요
모어코어 훅은 못 쓸 것 같아요 글리벡 작업에서는요
GDB에서 계속하면서 애프터_모어코어 훅 감시점이 발동되길 기다리죠
그럼 등록기와 스택을 확인해 보죠
rax는 null이 아니지만 스택 포인터 플러스 0x30은 null입니다
잠깐... 잠깐만요 이게 통할 거라고 생각하는 건 이해하지만 아직
훅에 연결할 코드가 없어요
네 워치포인트는 갈고리가 언제 사용되는지 알 수 있지만 한 가지 장치로도
사용할 수 있는지 알려면 갈고리를 손상시킨 다음 갈고리가 호출되는 바로 그 순간에 실행이
멈출 때를 기다려야 합니다
이 시나리오가 그걸 완벽하게 보여주죠 소스 패널을 보면 애프터_모어코어 후크가
방금 읽혔는데 그것과 후크라고 실제로 불리는 줄 사이에 체크가 있어요
물론 여기선 훅이 호출되지 않죠 null이니까요
하지만 rsi 등록기를 채우면 이 시점에서 애프터_모어코어 훅 값을 유지해야 하죠 훅이 실제로
채워진 것처럼 계속할 수 있어요
분해 칸에 있는 지시 사항을 잘 보세요
다음 지시 xor는 eax가 스스로 등록합니다 사실상 0을 입력하죠
그렇군요 흥미롭게도 32비트 레지스터 x86_64 연산에서 64비트 레지스터의 가장 중요한 비트를
지웁니다
만약 이 지시를 수행할 때 명령어를 '시'로 줄이면
모든 병균이 0이 됩니다
락스 = 널 제약 조건 하나가 가능해졌다는 뜻이죠
분해 패널로 돌아가서 애프터_모어코어 후크 호출을 볼 수 있습니다 rsi는 이 시점에서 고리 내용물을
갖고 있어요
하지만 아직 실행할 코드가 더 있습니다 1단계 'si 2'로 지시하는 거죠
소스 패널이 완전히 다른 코드를 보여주는 걸 보세요
네 이건 최적화의 부작용입니다 능률은 중요하거든요 일반 라이브러리처럼 어디에나
적용되는 것에서요 글립벡 바이너리는 최적화로 구성되어 있습니다
이로 인해 소스 코드에 나와 있는 것과 다른 순서로 작업이 수행될 수 있습니다
런타임 효율에는 좋지만 디버깅을 좀 어렵게 만들죠
하지만... 안타깝게도 안타깝게도
안 돼!
2단계 지시를 내려서 더미를 살펴보면 손상 정도를
알 수 있습니다
다행히 랙스는 쓸모없으니
쓸 수 있는 장치가 하나 있죠 맞아요 물론 이 모든 걸 피할 수 있었죠 우리가 타깃
고리를 손상시키고 프로그램이 중단되게 한 다음 사후에 등록기와 스택 상태를 검사했다면요
그래도 제가 여러분을 이 과정에 끌어들였으니 뭔가 배우셨을 겁니다 감시점을 믿지 않아서인지도
모르죠 개발에 있어서는 세부 사항에 대한 관심이 중요할지도요
이제... 말록새 낚시 모험이 끝났으니 등딱지를 가져올 만한 후보를 골랐으니
이제 마무리하죠 , 뭐
편집자 앞으로 돌아가세요
기존의 선 3개만 수정하고 4개만 더 수정하면 완성입니다
시작할게요 네 가짜 훅과 임의로 쓰는 표적 사이의
거리를 계산해 보죠
네 이 변화를 설명하기 위해 가짜 덩어리에 추가할 크기도 약간 수정해야 합니다
네 메모리를 잘 확보해야 해요 0x90 크기의 고리를
넣을 공간이 충분해야 하니까요
프리 훅을 덮어쓰는 데 사용된 라인에 두 번째 팩을 제거하고 첫 번째 팩의 null을
호출해서 교체한다 우리가 고른 장치의 주소로 rax = null이라는
제약 조건은
오프셋을 까먹으셨다면 이걸 복사하시면 됩니다
끝 마지막으로 마지막으로 안
됩니다,
최종 변경을 마치면 생산 조건에서 착취를 실행하세요
껍데기도 하나 사요
이번 영상에서 다룬 내용을 정리해 보죠
네 네 저희 바이너리는 변형된 하우스_rabbit pnable로 제한이 추가돼 있어 빠른
덩어리를 요청할 수 없고 사용자 데이터에 대한 컨트롤이 1사분수 줄었습니다
네 도청기는 이중으로 제거됐고 이전 토끼 집과 같은 패턴이었습니다 우리가 이용했던 것처럼요 안
돼!
네 주요 목표는 빠른 요청을 못 하는 걸 극복하는 거였어요 소위 말하는
임시 풍수지리를 이용해서요 공격의 이 부분을 이미 요약했습니다 빠른 크기의 덩어리를
만드는 거죠 말록에게 건 전화만 이용해서요 무료로요 말록에게 건 전화만 이용해 공짜 덩어리를 만들었던
것과 그리 다르지 않습니다 오렌지 하우스 공격 1부에서
네 두 번째 목표는 데이터 제어를 덜 하는 것이었습니다 그래서 맬록 훅을 선택해서 강탈할
방법을 다시 생각해 봤죠
네 그리고 더코어와 그 후의 바늘을 작동시킬 수 있다는 걸 알았어요 말록이 기본값으로 둔 곳의 맨 윗부분을
늘리면요
그 과정에서 워치포인트와 레코드 모드와 같은 유용한 GDB 기능을 활용했습니다 워치포인트는 훌륭합니다 아마 전에
보신 적이 있을 겁니다
그리고 레코드 모드는 덜 알려져서 한계가
있어요 특정 지시를 안 따르고
하드웨어 워치포인트를 무시하며 원격 디버깅에 문제가 있어요
그렇습니다 하지만 전체 프로세스를 재시작하는 걸 피하려고 취했던 행동을 되돌리거나 파악하기 힘든
버그를 추적하는 걸 도우면 좀 더 쉬워질 수 있습니다
네 늘 그렇듯 이 섹션 리소스에서 다운로드 가능한 주석이 있는 개발자 스크립트가 있습니다
다음 영상에서는 말록의 새로운 내장과 활용 기술을 배워 봅니다 특히
트셰이치 둡 기술이죠
거기서 봐요