이 영상에서는 또 다른 연약한 쌍성을 상대로 두
번째 기술을 배워 보겠습니다 패스트빈 둡입니다
칭찬할 건 칭찬하고 싶지만 그 기원은 확실하지 않아요
그렇군요 최근 기법이에요 이른 2014년에 '패스트빈 공격'이라고
기록된 걸 봤어요 하지만
더 오래된 것 같아요
어느 쪽이든 이 기술을 취약한 쌍성을 살펴보죠
패스트빈_dup 디렉터리에서 패스트빈_dup 이진법을 GDB에 로드하세요
이것도 C로 작성된 CTF 스타일 이진법으로 다른 레벨의 버그가 적용됐습니다
gdb 내에서 checksec를 실행하면 전체 RELOW 스택과 카나리아, NX가 활성화되어 있는 것을 볼 수 있습니다.
2진법은 위치 독립이 아니고 글립코 버전 2와 연결되어
있어요 30회
컴파일
중단점 설정 없이 프로그램을 돌려요 libc 주소가 유출됐는데 이번엔 힙
주소는 없어요 안 돼요 사용자 이름 프롬프트됩니다
지금은 쓰레기 데이터를 입력하죠
이제 익숙한 숫자가 적힌 메뉴가 나옵니다
네 옵션 1은 7개의 덩어리를 요청할 수 있습니다 마찬가지로 요청 사이즈를 제시해 주지만 0x20부터
0x80까지 패스트빈 사이즈로만 네, 제한이 되어 있습니다
0x80 크기의 청량에는 120바이트의 데이터가 들어있습니다
가장 큰 요청이죠
0x30 사이즈로 주세요
네 특정 크기를 요청하는 방법은 원하는 크기를 선택하는 겁니다
이 경우는 0x30이고
8을 빼면 0x28이 됩니다 이 정도 크기에 사용자 데이터가 들어 있는 거죠
그리고 쓰고 싶은 데이터가 요청됩니다 가비지 데이터를
더 보내겠습니다
GDB에 들어가 예상대로 모든 걸 확인하기 위해 'vis'로 힙을 검사합니다
이건 0x30 크기의 데이터죠 가비지 데이터를 사용자 데이터에 입력한 다음
상단에 올립니다
계속하고 메뉴 프린트 리턴을 다시 누릅니다
네 옵션 2는 0에서 인덱스로 시작해 덩어리를 자유롭게 할 수 있습니다 0에서
0x30 덩어리를 자유롭게 해봅시다 ? 네
폐차장과 차량 모두 검사해 주세요
네 0x30 크기의 덩어리가 0x30 패스트빈에 연결됐습니다 사용자 데이터의
첫 번째 4글자는 포워드 포인터로 변경됐죠 null이에요 bin에 처음 연결됐거든요
, 첫 번째예요
계속한 다음 반환을 누르면 옵션 3이 타겟을 출력하는 걸 볼 수 있죠 맞습니다 다시 말씀드리지만 우리의 첫 번째
목표는 목표 데이터를 덮어쓰기해서 패스트빈 둡 기법을 임의로 쓸 수 있다는 걸 증명하는
겁니다
네 네 앞서 말한 사용자 이름을 갖고 있죠 , 네
다시 'user' 스트럭트를 출력해 확인하겠습니다
더 자세히 살펴볼 수 있습니다 스트럭트에 대한 정보를 얻기 위해 GDB의 'ptype' 커맨드를 이용합니다 '유저자'
스트럭트에는 16바이트의 사용자 이름이 있고 target이 있습니다
이 레이아웃을 기억하려면 'dq'를 쓰세요 암퍼샌드를 잊지 마시고요
여기에 사용자 이름과 타깃 데이터가 있습니다
네 잠시만요 이 영상에서 잠시 멈추고 패스트빈_덥 바이너리에 익숙해져서 버그가
있는지 확인해 주세요
네 다시 말하지만 조회를 할 필요는
없어요 프로그램 메뉴를 가지고 놀면서 고장 나거나 이상한 행동을 하는지 봐요
이제 멈추세요
네 버그를 찾았다면
잘했어요 못 찾았다면 이 이진법에는 더블 프리 버그가 있어요 ?
더블 프리요 프로그램이 이미 공짜인 걸 공짜로 주는 거예요 괜찮은 것 같지만 어떤
영향을 미칠지 생각해 보죠 네 0x30 덩어리를 두 번 풀면 0x30
패스트빈에 두 번 연결됩니다 즉, 두 가지 다른 일에 동시에 할당된다는 거죠
, 이 두 가지에
예를 들어 관리자 암호 해시처럼 민감한 데이터를 가지기 위해 할당을 받고 사용자 통제 데이터를
가지기 위해 같은 패스트빈에서 다시 할당을 받죠 이건 사용자가 그 민감한 데이터를 읽거나 덮어쓰도록
유도할 수 있습니다
더블프리 0x30 덩어리를 만들어 보죠
여러분의 프로그램을 GDB에서 실행하여 제 프로그램과 같은 상태로 되돌립니다 0x30 사이즈
청크를 요청하는 사용자 이름을 설정하고 풀어줍니다
'계속'으로 돌아가서 둘
다 '자유'를 선택하는 거예요
0x30 청크는 인덱스 0에 있죠 이미 한 번 풀었으니
두 번째도 풀어줄게요
뭔가 잘못됐어요
GDB가 멈췄어요 프로그램의
마지막 결과로 스크롤을 올리면 중단 신호를 받은 걸 볼 수 있죠 ? 네 네 프로세이지는 자주 중단하지
않아요 중단하면
글리벡의 착취 완화를
촉발하는 거예요
어떤 완화 조치가 발동됐는지 더 자세히
알아보려면 'frame' 명령을 사용합니다 'f'로 줄일 수 있죠 _int_프리 () 함수 내 프레임 4로 전환합니다
이는 무거운 짐을 들어주는 무료 시술의 일부분일 뿐입니다 "컨텍스트
코드" 네 ()"
네 그 점을 참작해 주세요 이 댓글에 설명이 있어요 '쓰레기통 맨 위가 기록이 아니라는 걸 확인하세요'
i e 더블 프리
네 글립코 해킹을 완화한 많은 사례 중 하나입니다 대부분의 리눅스 메모리 할당기는 거의 이런 완화
사례가 없습니다 하지만
글립코는 오랫동안 존재해 왔고 잘 보호된 실행 방식을 갖고 있습니다
네 이런 조치를 취하는 이유는 같은 덩어리가 두 번이나 패스트빈에 실리는 걸 막기 위해서죠
트리거되면 이 오류 메시지가 인쇄되고 프로세스는 중단 신호를 받습니다
하지만 우린 개발자들을
착취해요 정상 참작이 되면 우회할 방법을 찾죠
패스트빈에서 더블 프리 완화 검사는 왜 하는 거죠?
코멘트에 따르면 맨 위 칸이 아레나에 있는 패스트빈 슬롯의 값이
레코드가 추가된 값과 같대요 즉, 프리라는 거죠 더블 프리로 바뀌면
중단해야 해요 ? 네 네 'x30' 패스트빈
위에 있는 걸 확인했습니다 두 번째로 풀려고
했을 때요
하지만 더블프리를 시도했을 때 0x30 패스트빈의 윗부분이나 윗부분에 다른 덩어리가
있었다면 어떨까요?
경감법에 그런 내용은 없는 것 같습니다
그럼 해 보죠 Pwntools_template
Python 스크립트를 복사해 에디터에서 여세요
아래로 스크롤을 내리고 다시 말하지만 우리는 점선 사이에 있는 것에만 관심이 있어요
네 이 스크립트가 제일 먼저 하는 일은 사용자 이름 프롬프트를 처리하고 나중에 바꿀 수 있는 "George"란 사용자 이름을
설정합니다
그다음은 맬록 기능을 사용합니다 House of Force 스크립트와 같은 방식으로 작동하죠
0x30 크기의 덩어리 두 개를 요청하고 쓰레기 데이터로 채웁니다
음 MARoc helper 함수는 요청된 덩어리의 색인을 반환합니다
이렇게 하면 'chunk_a'나 'chunk_b' 같은 변수를 사용해서 인덱스를 기억하지 않고도 덩어리를 추적할 수 있습니다
네 네 안 돼요!
네
말록처럼요 도우미 기능은 바이너리의 '자유' 옵션의
포장일 뿐이고 스크립트는 여기서 덩어리 A와 B를 자유롭게 해요
좋아요, 이 스크립트를 GDB와 NOASLR 옵션과 실행하죠 ctrl+c로
중단하고 힙을 'vis'와 ' Fastbins'로 검사합니다 , "#"
보세요 덩어리가 대문자로 채워진 A와 B A와 B가 보이죠 둘
다 0x30 패스트빈으로 이동했습니다 ? 네
B 덩어리는 맨 위에 있어요 마지막으로 꺼낸 거니까요
B는 포인터를 갖고 있는데 그게 A를 가리키고 fd는 null이에요
지금 A를 풀어주면 어떻게 되죠?
네 네 이미 0x30 패스트빈에 연결되어
있어서 더블 프리예요 하지만 통 위에 있지 않죠 b 덩어리예요
한번 해 보죠
계속합니다 gdb에서
계속합니다 프로그램 창으로 가서 반환을 누르고 인덱스 0의 공짜 덩어리 a를 두 번째로 누릅니다 ,
먼저, 프로그램이 전처럼 중단되지 않는다는 걸
알 수 있죠
GDB로 돌아가 '비스'와
'패스트빈'으로 다시 검사하세요
네 네 포워드 포인터는 여전히 A를 가리킵니다
네, 포워드 포인트예요
네 네 0x30 패스트빈에 두 번 연결됐어요
네 성공입니다 글립벡 패스트빈의 더블 프리 완화법을 무시하고 같은 통에 두
번이나 넣었습니다
패스트빈 둡이라고도 하죠
네 네 그런데 아까 말씀드린 것처럼 두 가지 목적을 위해 중복된 청크를 요청하는 예는
여기선 적용되지 않아요
관리자 암호 해시가 없어요
게다가 임의로 써야 하죠
이렇게 생각해
보세요 만약 패스트빈덥 수술을 마쳤으니 0x30 크기의 덩어리를 더 요청하면 어떨까요?
패스트빈이 우선순위인 걸 아니까 청크 A를 할당할게요
그리고 우리가 사용자 데이터를 관리하게 됩니다 우리에게
할당됐으니까요
하지만 그 데이터의 첫 네 글자는 여전히 0x30 패스트빈의 포워드
포인터로 사용되고 있었죠 그럼 fd를 조작할 수 있어요 표적을 겹치는 가짜 덩어리를 패스트빈에
연결하는 거죠
Fake 청크를 요청해 타깃 데이터를 덮어쓸 수 있죠
한 단계씩
차근차근 해 보죠 편집자 앞으로 돌아가세요
네 네 그런 다음 제일 먼저
무료 () 도우미 기능을 이용해 두 배 무료 A를 얻습니다 조금 전에 수동으로
한 것처럼요 , 네
패스트빈 둡이 완성됐습니다
다음으로 0x30 크기의 덩어리를 더 요청합니다
마음대로 이름 붙여요 난 '바보'라고 붙일게요
말록이 이 요청을 들어줄 겁니다 말록은 패스트빈 꼭대기에 있거든요
자... 네 패스트빈 포인터로 취급될 겁니다
A는 이제 우리 몫이자 동시에 공짜니까요
네 네 타깃 데이터와 겹치는 가짜 덩어리를 0x30 패스트빈에
연결할 수 있어요 ?
네 일반적인 옵션으로 스크립트를 실행해보죠
GDB로 들어가서 'vis'와 'f스트빈'으로 어디까지 했는지 보죠 , "btsb"
네 이 덩어리는 패스트빈의 첫 번째 덩어리고 그다음이 a예요 'a'의 fd는 '유저 스트럭트'를
가리키죠 0x30
크기의 덩어리를 요청하면 b가 나오고 그다음 a가 나오고 세 번째
덩어리는 목표 데이터와 겹쳐요
스크립트에 이 요청들을 추가해 보겠습니다 gdb를 닫고 에디터로 돌아갑니다
0x30 크기의 덩어리를 두 개 추가하고 세 번째를 추가합니다
목표 데이터와 겹치게 할 거예요
원하는 대로 대상을 덮어쓰고 일반적인
옵션으로 스크립트를 실행합니다
네 문제가 생겼습니다
GDB가 즉시 멈췄고 백트레이스
패널에서 abort() 함수가 다시 호출된 걸 볼 수 있습니다 ???
'frame' 명령을 이용해 _int_malloc 내 프레임 4로 전환 () 기능 네 _int_프리처럼요 ()
메모리 할당을 대부분 해줍니다
'컨텍스트 코드' 명령을 내려라 '인트멀록에서 마지막으로 건 전화를' '소스 라인을 인쇄하라'
그리고 오류 메시지가 있어요 이번엔 훨씬
더 아리송하죠 '기억의 부패'
네 네 이건 댓글이 안 달렸고 청크얼록의 크기가 할당된 패스트빈의
크기와 같은지 확인하네요
네 결국 0x90 크기의 덩어리가 0x30 패스트빈으로 들어간다는 건 말이 안 되죠
0x30 패스트빈은 0x30 크기의 덩어리밖에 안 들어가니까요 ?
네 네 가짜 청크의 사이즈가 0인 걸 알 수 있어요 그래서 크기 확인에
실패하는 거죠 ?
'프티프'는 우리가 사용자 이름으로 메모리를 제어한다는 걸 상기시켜 줍니다
가짜 크기의 필드를 설치하면 어떨까요?
한번 해 보죠
편집기로 돌아가 사용자 이름을 8바이트 가비지로 변경합니다
이 프로그램은 null 쿼드를 쓰고 거기에 가짜 0x31 크기를 더합니다 () 함수를 이용해서요
평소 옵션으로 취약점 스크립트를
실행하면 이번에는 괜찮아 보입니다 네 프로그램 창으로 가서 메뉴에서 '타겟' 옵션을 선택합니다 모든 게 계획대로
되면 타깃 데이터 대신 여러분 데이터가 프린트되는 걸 보실 수 있죠 GDB로 돌아가 'dq'를
이용해 타깃 주변의 메모리를 조사합니다
패스트빈 크기를 속이려고 가짜 크기를 표시해 놨어요
멋져요!
패스트빈 둡 기법을 이용해서 임의로 쓸 수 있어요
요약하자면 이 바이너리에 더블 프리 버그가 있는데 같은 패스트빈에 두 번 연결했어요
네 네 피해자가 패스트빈 꼭대기에
안 올라가게 했죠
그리고 복제된 청크를 요청하고 fake 청크에 포인터를 써서 타깃 메모리를 겹치게 했어요
사용자 데이터의 첫 번째 사분어드에 넣었습니다 네 복제된 청크는 이걸 할 때 패스트빈에 연결돼
있었거든요 사용자 데이터의
첫 4문자는 포워드 포인터로 사용됐습니다
이로 인해 가짜 덩어리가 패스트빈에 연결됐어요
패스트빈에 가짜 덩어리를 요청해서 타깃 데이터를 덮어썼어요
네 네 표적 근처의 데이터를 조작해서 가짜 크기 필드를
만들었죠
네 늘 그렇듯 이 섹션 리소스에서 다운로드 가능한 솔루션 스크립트가 있어요 안 돼요!
네 패스트빈덥 기법 개요와 지금까지 다룬 말록 내부가 있어요 , pdf
파일에 다 나와 있죠
네 '감형' 코너도 있어요 글리지브 관련 정보가 다 나와 있죠
네 다음 영상에서는 경찰청에서 했던 것처럼 이 임의대로 쓴 내용을 코드 실행으로 바꿀 겁니다
안 돼!