링크를 끊는 건 알렉산더 페슬랴크가 2000년에 개발한 글립크 더프 조작법입니다
케이 a 솔라
디자이너는 원래 힙 오버플로를 통해 넷스케이프 브라우저를 고정하는 데 사용됐습니다
맞아요 그다음 해에 '부도 말록
트릭'이라는 프랙 기사에도 사용됐어요
네 솔라 디자이너를 모르신다면 그는 최초의 더프 개발 기술로 유명할 뿐
아니라 ROP라고도 하는 복귀 프로그램의 아버지이기도 합니다
네 1997년 알레폰이 '재미와 이익을 위해 더미를 부수자'를 발표한 후 그는 리투리브c의
첫 공격을 개발해 잘 알려지지 않은 더미를 우회했습니다 ,
NX가 흔해지기 전에 사용했을 뿐만 아니라 그걸 우회하려고 ROP를 개발했어요
그리고 패치를 위한 바이패스용 패치를 개발했는데 이 패치는 Null 바이트 주소로 라이브러리
매핑이 포함돼 있었습니다 ROP 사용을 완화하려고요 불안정한 문자열 기능과 함께요
네 흥미로운
사람이에요 더 알고 싶다면 프라랙이 2016년에 멋진 인터뷰를
했으니 링크 해제술에 대해 알아보죠
먼저 취약한 '위험 언링크' 2진법부터 조사하겠습니다 어떤 보안 기능이 활성화됐는지 확인하려면 checksec를
사용하세요
이 바이너리와 이전의 가장 큰 차이점은 NX로 컴파일되지 않았다는 겁니다
여러분 이전 영상에서 말씀드렸듯이 링크 해제 기술이 처음 구상한 위험한 2000년으로
돌아가 보겠습니다
네 NX가 비활성화될 때 얻는 장점은 메모리에 셸코드를 쓸 수 있다는 거죠 달리
실행될 수 없는 메모리에요 실행합니다
네 그리고 이 바이너리는 특수 버전의 글립벡과 연결되어 있습니다 이 기술이
적용된 버전과 비슷하게
패치되어 있죠
이제 GDB에 이 바이너리를 로드하고 실행시킵니다.
리bc와 유출된 양을 제공받고 익숙한 번호 메뉴도 제공받죠
옵션 1은 두 덩어리를 요청할 수 있는데 '작은' 덩어리로 분류됩니다
네 네 0x20부터 0x80까지 빠른 크기를
포함해서 작은 덩어리라고 합니다
이 경우에는 패스트 레인지를 제외하고는 조금밖에 못 넣기 때문에
0x90부터 0x3f0까지를 만들어 볼 거예요
일부 쌍성은 불필요하게 제한적인 것 같습니다 더미에서 하는 일에 있어서요
하지만 그렇게 설계됐습니다 눈앞의 기술에 집중하기 위해서죠
최대한 작게 해달라고 요청할게요
네 이번엔 데이터를 안 받습니다 별도의 메뉴 옵션을 통해 할당과 쓰기를 합니다
제작 환경에서 그렇습니다
때때로 프로그램은 개체에 공간을 요청한 직후에
개체의 필드를 채우기도 합니다 어떤 때는 나중에
쓰도록 지연시키기도 합니다
옵션 2는 데이터를 인덱스에 따라 덩어리로 쓸 수 있습니다
인덱스 0의 0x90에 쓰레기 데이터를 적습니다
네 분석을 해 보니 예상대로 이 크기는 0x90 바이트예요 136 바이트 메모리를
위한 거죠 프로그램은 가비지 데이터를 이
청크의 사용자 데이터에 적었어요
옵션 3은 인덱스로 덩어리를 자유롭게 합니다
우선 0x90 크기의 덩어리를 더 요청하죠 첫 번째 덩어리가 제일 큰 것과 합병되는
걸 막으려고요 첫 번째 덩어리를 꺼내고 더미를 보시죠
데모 바이너리에서 봤던 것과 같은 변화를 볼 수 있습니다
네 다음 화면은 사용 전 단계 표시가 제거됐어요 이전 화면은 더 이상 사용되지 않는다는
뜻이죠
네 네 안개와 바람의
방향이
마지막으로 무료는 정돈되지 않은 데이터에 연결되어 있습니다 사용자 데이터의
첫 4괄호를 주석으로 달아놓았습니다 포인터로 변경되었고 '정돈되지 않은' 명령으로 확인되었습니다
명령은 무의미한 정보를 프린트합니다 프린트하는 메모리의 특성 때문에 read+write+exeruct
헷갈리니까요 걱정 마세요
네 작은 덩어리를 요청해 원할 때 데이터를 쓰고 그걸 풀어주면
돼요
네 이 프로그램에서 버그를 찾을 기회입니다 영상을
멈추고 버그를 찾으면 돌아오세요
도청기는 찾았어요?
안 되면 프로그램을 재시작해서 보여 드릴게요
0x90 사이즈로 136바이트 이상의 데이터를 입력할 거예요
분석해 보니 이 프로그램에는 넘치는 버그가 있습니다 그 포스 바이너리와 유사합니다
네 하지만 이번엔 맨 위 덩어리에만 국한되지 않습니다 다른
덩어리에 속한 크기도 공략할 수 있죠
0x90 사이즈로 하나 더 요청하죠 네 검사 결과 0x90
사이즈 두 개가 나왔습니다 그리고 오염된 제일 윗부분이 나옵니다
계속할게요 네 안쪽에 있는 청크도
GDB를 검색합니다
힙을 조사하려면 'dq' 명령을 사용해야 해요 손상된 크기 필드가 'vis' 명령을 혼란스럽게
하거든요 "dq"
네 'mp_스트럭트'는 멀록이 소량의 매개 변수 데이터를 담는 데 사용합니다 나중에
더 보여드리죠
네 지금은 'sbrk_base' 멤버를 기본값 힙의 시작으로 사용하겠습니다 38 쿼드워드
메모리를 프린트할 겁니다
네 네 ? 네, 맞아요
네 상단 손상 사이즈 필드도 볼 수 있습니다 두 번째 사용자 데이터 마지막에요
네 그럼 이렇게 넘치면 가장 큰 밭을 오염시킬 수는 있지만 기공술은
여기선 안 통해요
충분한 메모리나 덩어리를 요청할 수 없어요
'평범한' 청크를 오염시키면 도움이 될 거예요
크기를 바꿀 수 있어요 그럼 무료로
해 주죠 하지만 그걸 이용하려면 청크를 다시 요청해야 해요 이 프로그램이 부과한
요청 한도 때문에 그건 불가능하죠
크기는 그대로 두고 깃발만 바꾸면 어떨까요?
두 번째 청크의 사용
전 깃발을 지우면 어떻게 될까요?
여러분 맬록은 이전의 배설물이 통합될지 판단할 때
사용합니다 네 그렇다면 두
번째 덩어리를 없애면 말로크 말로는 두 번째 덩어리를 풀어 주면
잘 통합될 거라고 생각할 거예요
네 네 하지만 그 부분은 무료가 아니죠 그래서 무료 리스트에
연결되어 있지 않습니다
따라서 앞뒤 포인터가 없습니다 ,
하지만 이건 우리가 그들에게 제공할 기회이자 기억할 것은 공격자 조종 표지를 위험하게 해제하면
원시적인
기사가 나온다는 겁니다
GDB를 닫습니다 Pwntools_template
Python 스크립트를 복사한 다음 여러분이 선택한 편집기에서 엽니다
아래로 스크롤을 내려서 헬퍼 함수의 사용 예제를 볼 수 있습니다
이번엔 요청 크기 논쟁만
하면 됩니다 편집이 있어요 편집 함수가 있는데 편집하고 싶은 첫 번째 인수의 색인을
취하고 두 번째 인수로 쓰고 싶은 데이터를 취해요
마지막으로 색인 인수를 갖는 free() 함수가 있습니다
네 네 또한 execve("bin/sh"를 갖는 셸코드
변수도 있습니다 나중에 써먹자
시작하겠습니다 전에 제안했던 것으로 시작해보죠 사용 전 깃발을 제거해 청크의 크기를
변경합니다
셸코드만 빼고 네 어떤 사이즈든 괜찮아요 ,
프로그램상으로는 덩어리에 A와 B를 붙일게요
기억하세요 네 그래서 전 0x88을 요청하죠
, 크기는...
GDB와 NOASLR 옵션으로 스크립트를 실행해
모든 게 예상대로인지 확인하세요 네 시각 자료를 보면 '0x90
사이즈 토막'이 두 개 있어요 둘 다 미리 플래그 세트를 갖고
있죠
편집장에게 돌아가세요 이제 버그를
이용해서 청크 B의 크기 필드를 덮어쓸 거예요
크기는 동일하게 유지하되
사용 전 깃발은 확실히 해야죠 네 네 사용자 데이터이기 때문입니다 우선 많은 바이트의
가비지를 입력해야 합니다 ? 네, 그렇습니다
첫 번째 덩어리에 담긴 사용자 데이터는 몇 바이트나 돼요
그리고 다음 덩어리의 크기를 바꿀게요 제 경우에는 0x91이므로 0x90
값을 넣어야 합니다 크기는 그대로 유지하면서 prev_inuse 깃발도 지워야 하죠
두 번째 청크 사이즈에도 같은 변화를 줘야
합니다
스크립트를 실행하고 디버깅 옵션과 더미 검사를 하면 의도한
효과를 얻었다는 걸 알 수 있습니다 맞습니다 네 사용자 데이터의 마지막
네 글자는 B로 분류되는데
prev_size 필드입니다 예를 들어 프리v_size
필드요
지금 B 덩어리를 풀어주면 어떻게 될까요?
네 그럼 맬록이 사용 전 깃발을 확인해서
깨끗한지 확인하고 검블 B와 검블 A를 구분해 봐요 네 청크 A의 시작점을 찾으려면 말록이 청크 B의 프리v_사이즈
필드를 이용해야 하는데 지금은 그 필드에 쓰레기가
가득하니 말록은 분명히 세그폴트를 일으켜서 마이너스 0x5959의 메모리에
접근하려 할 겁니다 ? 기타 등등
편집기로 돌아가서 몇 가지 수정을 해보죠
미리 변수를 준비해 두죠 그래야 편하니까요
네 이제 반사된 글자를 위해 앞뒤 포인트를 만들어야 해요
이제 자리를 만들어야죠
네 말록이 청크 A로 향하도록 사전 크기를 설정해야 해요 제 경우에는
0x90이에요 청크 a를 풀어 줬다면 이렇게 나왔겠죠
첫 번째 덩어리의 크기를 이용하세요 명확하게 하기 위해 FakeSty
필드를 변수로 바꿔보죠
좋아요 네 prev_size 필드로 갈 만큼 쓰레기를 모아야
해요 ? 네
이걸 쓰면 네 메모리 덤프를
볼 때 좀 더 깔끔하게요
? 네, 맞아요
prev_size 필드와 fake 사이즈 필드를 추가합니다
그런 수정을 하고 나면 스크립트를 일반적인 옵션으로 실행하고 힙을 검사합니다
네 여기 보면 단조된 fd와 bk가 청크 A의 시작점에 있고 청크 B는 사용 전 깃발을 지웠어요 이제 멀록이
사용할 수 있는 온전한 예비 크기 들판이 생겼죠
네 자 우리가 B 덩어리를 풀어 주면 말로크가 사용 전 깃발을 확인해서
문제가 없는지 확인하겠죠 ? 청크 B와 청크
A를 결합합니다 위조된 prev_size 필드를 읽고 청크 B 주소에서 그걸 빼면 청크 A가 시작하는 곳을
찾을 수 있습니다
다음으로 무료 목록에서 A를 링크 해제하려 합니다
네 이 시점에서 말로크가 fd와 bk의 연결을 끊으면 반사된
원시적인 글자가 나옵니다 말록이 fd를 따라 다른 땅이라고 믿는
곳으로 가서
그 땅을 우리 bk로 덮어씌울 거예요 그럼 말록은 bk를 따라 또 다른 덩어리가 있다고 믿는 곳으로
가서 그 덩어리를 우리 fd로 덮어쓸 거예요
네 이게 성공하려면 두 주소 모두 쓰기 가능한 기억을 가리켜야 해요 즉, 무료
후크를 덮어쓰려 하면 시스템 주소와 함께 예를 들어 나머지 반은 시스템에 무료
후크의 주소를 쓰려고 시도할 겁니다 쓰기가 불가능한 기억에 쓰려 할 때 세그폴트를
작동시키죠 , 그 기능은
다행히 지금은 2000년이고 쓰기 메모리도 실행 가능합니다
네 렐로는 아직 전면 집행 중이지만
공격을 성공하려면 청둥오리 갈고리를 노려야 합니다
누출이 있어서 셸코드를 실행 가능한 힙에 쓸 수 있습니다
반영된 후크를 이용해 우리 셸코드의 주소로 덮어쓰기를 못 할 이유가 뭐가 있을까요?
해 보죠
에디터로 돌아가서
가장 먼저 할 일은 셸코드를 청크 A에 쓰는 것입니다
A에 쓴 쓰레기 양을 수정하는 거 잊지 마세요 셸코드 때문에요
좋아요 다음은 fd점과 0x18을 더해서 bk가 반사되는
부분의 전반부에 집중합니다
네 bk를 셸코드의 주소에 설정해보죠 위조된 fd와 bk 바로
다음 첫 번째 부분에서요 힙
플러스 0x20
네 이 bk를 프리 훅에 복사할
거예요 그럼 링크를 푼 후 다른 부분을 풀려고 할 때 셸코드가
실행되겠죠
좋아요 무료 후크 마이너스 0x18에서 fd를 언급해 보죠 멀록은
fd가 가리키는 걸 청크로 처리하고 bk를 덧씌울 거예요
청크를 시작하고 24 또는 0x18 바이트죠
네 이제 스크립트를 디버깅 옵션으로 실행합니다
힙을 살펴보죠 여기 보면 forged fd와 bk가 청크 A의 시작점에
있습니다 네
네 ? 네
링크 해제 공격을 일으키려면 B 덩어리를
풀어주기만 하면 돼요 좋아요, 말록이 사용
전 깃발을 확인할 거예요 버그로 지웠으니 청크 A로 통합해야죠
이 화면은 네 이 화면은 링크를 해제하는 과정을
거치게 됩니다
네 네 ? 네
그럼... 계속하죠 창문을 색인 1의
무료 b 프로그램으로 바꾸면 링크가 해제될 겁니다 다시 gdb로
돌아가 힙을 검사합니다
두 덩어리 중 맨 위만 남은 것 같아요
기억하실 겁니다 네 상단과도 통합될 수 있다는
걸요 , 맞아요 네 처음엔 청크
A와 통합됐고 그 후에 윗부분으로 통합됐어요 ? 네
하지만 안전하지 않은 연결이 실패했다는 뜻은 아닙니다
네 던지기 무료 고리가 가리키는 메모리는 셸코드를 가리키고 있다는 걸 보여줍니다
좋아요!
다음에 한 덩어리를 풀면 셸코드가 실행될 거예요
네 한 가지 빠트린 게 있어요 링크 해제 절차의 두 번째 부분입니다
bk가 따라왔고 fd가 목적지에서 fd를 복사했어요
그 과정을 여기서 확인할 수 있어요 fd가 셸 코드 중간에 쓰여 있는
거죠
이렇게 하면 16바이트의 셸코드만 남습니다
네 다행히 셸코드의 첫 부분을 u 커맨드로 해체함으로써 이와
관련하여 셸코드는 두 바이트를 사용해 손상 부분을 건너뛰었습니다 실제 셸코드는
그 이후에 시작되죠
네 이제 남은 건 링크를 해제하는 한 줄로 b를 풀어주고 그 후에 다른
한 줄로 후크를 통해 셸코드를 실행하는 거예요
편집기로 돌아가서 최종 수정을 하겠습니다 네 그걸 하는 동안 셸코드의 'jmp
지시 사항'을 보세요 링크 해제의 부작용을 다뤘죠 안 돼요!
네 준비되면 착취 스크립트를 실행하세요 제작 조건에서요 그럼 셸이 생길 겁니다
링크 해제 기술을 위험하게 이용했어요
네 요약하자면 두 개의 청크를 요청했습니다 a와 b 힙 오버플로를 이용해 청크 B에 prev_inuse
플래그를 지웠습니다 , 안 그러면 설정되어 있어야 할 것이죠
이 경우 넘쳐난다는 것이 전체 4글자였는데 한 바이트였을 수도 있고
혹은 한 바이트일 수도 있습니다 필드의 크기가 이미 0이었다면 말이죠 ,
맞아 부패한 b 덩어리를 풀어 줬을 때 멀록은 이전의 사용 경로가 명확해졌으니
통합할 수 있다고 판단했어요
합병은 자유 목록에서 후보나 피해자 부분을 풀고 그 부분을 풀린 부분에 크기를
더하는 겁니다
청크 말록을 찾기 위해 풀린 청크의 예비 크기를 이용합니다
prev_size 필드는 이전 부분에 포함된 사용자 데이터의 마지막 4괄호에서 형성됩니다
네 우리는 청크 B의 prev_size 필드를 정확하게 채울 수 있었습니다. 왜냐하면 a는 무료가 아니었기 때문에 사용자
데이터를 컨트롤 할 수 있었습니다. ? ?
네 다음 말록이 링크를 해제하려
했어요 사용자 데이터를 제어해야 해서 위조된 fd와 bk 포인터를 제공해 링크 해제
과정을 진행했어요
네 우리는 fd를 프리 훅 24에 놓고 셸코드를
몇 개 붙여 놨어요 언링크는 fd를 따라 프리 훅 위에 bk를 복사했어요
그리고 bk를 따라 fd 16 바이트를 셸코드에 복사했습니다 'jmp' 명령을
제공해 뛰어넘어야 했죠
네 마침내 드디어 셸코드를 얻었습니다
,
셸코드를 이렇게 사용할 수 있었던 건 지금이 2000년이기 때문이란 걸 잊지 마세요
어쨌든 IoT나 엠베디드 디바이스를 다루면 NX가 활성화되어 있지 않은 걸 알 수 있죠
현재에도요
네 네 평소처럼 코멘트가 있는 개발자 스크립트를 다운로드할 수 있어요 이 구역 리소스에서요
네 링크 해제 과정을 다시 한번 상기시켜 드리고 싶다면 pdf의 '링크 해제' 부분을 참조하시면
됩니다
네 네 포인팅된 fd와 bk는 풀린 덩어리 뒤에
있는 덩어리에 고정돼 있죠
네 이 기술에는 '앞으로 통합'된 변형이 존재합니다 단조된 fd와 bk가 다음
부분에 자리하죠
2001년 스도 바이너리를 이용한 변종입니다
2000년대 초반의 삶이 지겨우시다면 다음 영상으로 함께해 주세요 현대로
돌아와 이 기술을 현대판 글립코에 어떻게 적용할 수 있는지 보여 드리겠습니다