최적화 챌린지에 잘 오셨습니다 왜 그렇게 부르는지 잠시 후 알게 될 겁니다
네 늘 그렇듯 목표는 혼자 작업하면서 최대한 많은 도전 바이너리를 제거하는 겁니다
네 네 힌트를 너무 주저하지 마시고 사용하시면
좋을 것 같아요 하지만 그 순간에 확실하게 보여 드리겠습니다
도전을 즐기시길 바랍니다
살펴볼 수 있습니다 도전 최적화 디렉터리로 가시면 도전 이진법과 함께 pwntools 템플릿 스크립트가
있습니다 ,
체스크씨는 기존에 활성화되어 있던 착취 완화 기능과 글립코 버전 2가 문제점이라고
밝혔습니다 26살요
GDB에 로딩해서 실행하면 메뉴가 나타납니다.
옵션 1을 이용하면 합쳐서 5개의 덩어리를 요청할 수 있습니다
한 페이지나 0x1000 바이트보다 작아요
0x250 크기의 이 덩어리는 tcache입니다 글리벡 2에서 소개된 건 기억하실 겁니다 26살요
2번은 할당된 덩어리를 자유롭게 합니다
옵션 3은 할당된 덩어리를 임의의 데이터로 수정합니다
아직까진 별다른 게 없어요 그럼 4번 옵션이 남죠 '최적화'라고 이상하게 붙은 거요 선택하면 '최대 패스트 청크
사이즈'라는 프롬프트가 나와요
상황을 파악할 때까지 소액만 보내죠
값을 입력하면 방금 일어난 일에 대한 정보를 볼 수 있습니다 연결됐습니다 우리 가치는 M_MXFast
매개 변수와 함께 글리브의 맬롭트에 전달됐고 호출은 성공적이었던 것 같습니다
네 맬롭트를 본 적이 있습니다 2부에서는 맬록의 행동에 영향을 주는 환경 변수를 알아보기 위해
맨페이지를 검색했습니다
맬롭트는 프로그램 안에서 같은 행동을 통제하는 방법일 뿐이에요
두 개의 인수가 필요해요 매개 변수와 값이요
M_MXFAST 매개 변수를 예로 들어보죠
네 네 부식의 집을 배우다가 오염된 거예요 , 부식의
집
네 아이디어는 개발자로서 사용 가능한 패스트빈 수를 바꾸면 프로그램이 더 잘
작동한다는 걸 알게 되면 맬롭트와 M_MXFAST 매개 변수를 써서 이 범위 어딘가에 값을
전달해 최적화할 수 있다는 거죠
원한다면 패스트빈을 완전히 해제해도 돼요
네 네 도전의 4번 옵션은 맬롭트를 호출합니다 첫 번째 인수로 M_XFST 매개 변수를
하드코딩하고 우리가 두 번째로 준 값을 통과시킵니다
네 네 비록 보다시피 몇몇 반동이 발생하긴 했지만요
,
37을 입력했는데 글로벌_맥스_패스트는 32로 설정됐어요
디폴트 값이 0x80 혹은 128이라는 것을 기억하실 겁니다
그 전에 영상을 멈추고 프로그램에서 버그를 찾아주세요
섬광 보트 기능은 아직 걱정 마세요
어떻게 작동하는지는 잠시 후에 알아보겠습니다
우리에게 익숙한 고성능 버그를 찾는 데 집중하세요 더블
프리 같은 거요
10분 이상 할애하지 말고 성공하든 실패하든 여기로 돌아와요
멈춘 후에 봐요
도청기는 찾았어요?
간단한 검사를 해 보죠
실험용으로 최소 크기의 덩어리를 요청할게요
편집 옵션에서 오버플로를 확인하면서 시작하겠습니다
버그는 없어요
더블 프리 어때요?
프로그램은 불평하지만 오류 메시지는 믿을 수 없죠
쓰레기통은 손상되지 않았어요 한 덩어리만 분리했죠
두 배로 안전한 벌레는 없군요
네 좋아요 사용 후 무료가 있을 거예요 무료로 편집 옵션에 글을 써볼게요 ? 네
버그 무료 사용도 안 돼요 읽기 옵션이 없으니 무료 사용도 안 되고요
이 쌍성에 일반적인 버그는 없는 것 같습니다
프로그램 최적화 옵션에 문제가 있나 봐요
확인해 보죠
m_xfast 매개 변수 네 이 값을 통한 0은 x64 아키텍처를
다루고 있기 때문에 160이나 0xa0입니다
제로의 의미가 분명한 것 같아서 나중에 조사할 겁니다
가장 먼저 떠오르는 질문은 이겁니다 우리가 이 한계를 넘어서 글로벌_max_f스트를
막대한 값으로 올리는 걸 막는 게 뭘까요? 부식의 원흉을 만드는 거죠
네 네 우리가 설정할 수 있는 최대치는 채무 한계인 160을
훨씬 초과합니다
한번 해 보죠
맬롭트가 실패했군요
하지만 말씀드렸듯이 오류 메시지는 믿지 마세요
global_max_ Fast 변수를 확인해 보죠
여전히 0x80, 디폴트 패스트 청크 사이즈로 읽습니다
관련 소스 코드를 네 "가치" global_max_ast를
와일드 값으로 설정할 순 없어요 프로그램이 허락해도요
문제는 챌린지 최적화 바이너리에 버그가 하나도 없다는 겁니다
이제 다 끝난 건가요?
그걸 이용하려면 목표 프로그램에 버그가 필요할까요?
아니면 libc의 벌레만 믿을 수 있을까요?
화면 정지하면 글리벡 버그를 찾아서 도움이 될 만한 걸 찾아봐요 지금은 맬롭트가 사용하는 set_max_f스트
매크로에 집중하세요
x64 시스템의 SMallBIN_Width는 16입니다.
사이즈_SZ는 8
멀록_정렬 마스크는 15
네 맬롭트를 더 자유롭게 실험하고 싶다면 맬롭트 메뉴를 시험대에 추가했어요
M_MXFAST 매개 변수를 선택해 이 도전 바이너리를 에뮬레이트하세요
패스트빈에서 이 매개 변수를 바꾸는 게 더 쉬울지도 몰라요 글립벡
2와 비교해보세요 26번 tcache가 고장 났어요
그러면 패스트빈을 조작하려고 계속 뚜껑을 채웠다가 비울 필요가 없어요
글립코 2와 2진법이 연관된 걸 기억하세요 tcache가 활성화된
26개 버전으로 5개만 할당 가능합니다
set_ max_ Fast macro에서 의도치 않은 행동을
찾아보세요
네 그 자체로는 중요하지 않아 보여도 일단 손에 넣었다고 생각하면 영상을 멈춰 주세요 그럼
조사를 계속하겠습니다
set_max_fast macro에서 이상한 행동 발견하셨어요?
약하게 표현됐으니 걱정 마세요
set_max_ft에는 두 가지 문제가 있습니다
제가 말한 행동을 재현할 수 있는지 보죠
좋아요 맬롭트에서 수표가 나오면 0에서 160 사이의 값만 넘기면_max_ft를 설정할 수 있어요
0은 특별한 경우고 곧 다시 얘기하겠습니다
네 0이 아닌 값엔 8이 더해져 그럼 덜 중요한
나비는 마스크를 쓰고 결과 값은 global_max_f fast에 복사되죠 ????
예를 들어 0x3b를 프로그램 최적화 옵션으로 set_max_ast에 입력하면 0이 아니기
때문에 8을 더하면 0x43이 되지 그럼 덜
중요한 나비가 죽고 0x40이...
글로벌_맥스_패스트가 그 비율에 맞춰 매입됐죠
네 할당 시 배분 기간에는
,
기억하십시오. 일반적인 요청은 가장 가까운 크기의 한 덩어리로 모은 것이라는 것을요.
7바이트 요청이면 0x20의 nb가 나오죠
그런 점을 고려하면 이 숫자가 이상할 수도 있습니다
말로크 측에 요청하면 0x3b 바이트를 배분해야 해요 0x40이 아니라요
네 이게 첫 번째 문제인데 울리히 드레퍼가 말하는 이 대사는 실수예요
원래는 이런 모습이었죠
네 현재 방법 대신 request2size macro가 우리 값을 유효한 덩어리로 바꿔 줄 거예요
말로크가 nb 값을 생성할 때 쓰는 것과 같은 거죠 ?
처음에는 이상해 보이죠 값을 160이나 0xa0으로 보낼 수 있으니까요 그러면 global_max_ast가
0xb0으로 설정되겠죠
하지만 괜찮아요
현대 경기장에 여전히 접근하기 힘든 0xb0 패스트빈이 있는 이유죠
울리히가 왜 마음을 바꿨는지는 저도 모릅니다
네 착수 메시지에는 자세한 내용이 없지만 착수 몇 달 후 마이클 케리스크가 도청 장치를 발견하고
신고했습니다
두 사람의 대화가 재미있어서 말씀드리는 겁니다
네 네 더그 리의 말록에서 들여온 인터페이스를 8년 넘게 바꾸지
않고 그대로 유지해 왔음에도 불구하고요
2009년 글리벡 보고서에 묘사된 이런 정서는 그런 태도 때문일 겁니다
그래도 고쳤잖아요
네 인터페이스에 대한 이 주석은 마이클 케리스크에게 가는 게 아니라면 재미없을 겁니다 Linux
프로그래밍 인터페이스에 대해 책을 쓴 사람이니까요
케리스크는 리눅스 맨페이지의 프로젝트를 관리합니다
그리고 버그 보고서가 조치가 안 되자 대신 맬롭트 맨페이지에 추가했고 오늘날까지
거기 있습니다
좋아요, 그럼 이제 재밌긴 하지만 혼란스러운
인터페이스와 접근 불가능한 0xb0 패스트빈은 우리가 관심 있는 게
아니에요 ? 네
두 번째는 0이라는 특별한 경우입니다
이 댓글은 그 이유를 설명하지 못합니다
네 하지만 우리가_max_ft를 설정하기 위해 0을 넘기면
global_max_ft는 SMallBIN_WIDTH로 설정됩니다 앞서 말했듯이 우리 아키텍처에서는 16이나 0x10이 일시
정지예요
네 네 맨페이지 기준에 따라 패스트빈을 무력화합니다 말로크의 nb
값은 0x20
이하로 떨어지지 않기 때문이죠 ,
그럴 땐 global_max_est를 0으로 설정하면 되잖아요 시작할게요 아까 3부에서 했듯이 글라이브 소스
검색 메서드를 골라 다음 질문에 답해 보세요 global_max_ft가 0으로
설정되면 어떻게 될까요? ?
get_max_ftro를 검색함으로써 글로벌_max_ft가 쿼리된 모든 위치를
찾을 수 있습니다
말로크 수색을 제한하세요 c, 글립벡
2도 꼭 확인하세요 26개부터요
좋아요, 지금 비디오를 멈추고 답을 알게 되면 취약점을 이용하거나 여기로 돌아와서 다시
재생하세요 그다음에 더 설명할게요
set_max_ast macro가 왜 global_max_fast를 0으로 안 하려고 하는지 알아냈어요?
네 부디 검색으로 멀록_통일 함수를 찾았길 바라요 힙랩에서 잘 다뤘던
거죠 2부요 토끼의 집 기법을 배웠을 때요
여러분 경기장 패스트빈에 있는 덩어리를 뭉쳐서 무정돈 상태에 버리는 데 쓰이는
거 기억하시죠?
글리벡 2호실요 26살 이상 그 이전 하지만 멀록_콘솔리데이트는 두 번째 목적도 있습니다 아레나 초기화죠
말록이 사용되기 전까진 프로그램이 배급되지 않아요
주 경기장이 채워지고 힙 메모리가 요청됩니다
바로... 네 말록훅이라는 이름을 처음 부르면 이 기능은
말록훅을 무효화해서 말록이 사용될
때마다 초기화되는 걸 막습니다 , ptmalloc_init이라는
함수를 호출해 초기화를 하고 맬록으로 리디렉션합니다
pt말록_init이 가사를 담당하고 그 결과 메인 경기장에서 맬록_colidate를 호출합니다
물론 지금으로선 확답할 방법이 없습니다 말로크를
세우는 중이니까요
하지만 말록이 미확인 상태인 걸 감지하면 말록 통합을 통해 말록 상태라는 다른 함수를
호출해요
그 기능은 이 댓글을 보면 맬록_consolidate 내에서 그 기능을 호출할 수 있는 정당성을 제공합니다
네 모든 malloc_init_state는 Arena에서 반복적으로 이동하며 링크 리스트를
설정하고 문제의 해당 아레나를 global_max_ fast로 초기화합니다
마지막으로 윗부분에 뿔을 꽂습니다
네 네 , 네
이렇게 하면 새로 만든 경기장에서 가장 큰 덩어리가 0이 되도록 할 수 있습니다
네 경기장이 말로크_주에서 초기화됐다면 말로크_인터넷이 초기화됐는지
어떻게 알 수 있죠?
네 결국 초기화 후 어느 시점에서든 다시 호출될 수 있고 Arena를 다시 초기화하는 건 위험하거나
최소한 메모리 낭비를 초래할 수 있습니다
네 맬록 초기화의 척도가 하나 나왔는데 글로벌_맥스_패스트가 0이래요
글로벌 맥스_패스트는 먼저 멀록_상태가
나오거든요 따라서 멀록_상태가 0이면 아직 호출 안 한 거죠
맬롭트 맬롭트 시작 부분에서 이 선들을 봤다면 헷갈릴 만도 하죠
네 맬롭트는 미리 호출될 수 있으니까요 프로그램에는 한 무더기가
있어요 맬록의 변수를 조정하기 전에 주 경기장을 초기화해야 하죠
네 보시다시피 변수 이름을 malloc_initialize로 가끔 이름을 바꾸기도 해서 이미
사용된 적이 있는지 확인합니다
네 특별한 변수가 있는데 왜 글로벌_맥스_파스트로 같은 정보를
확인하죠?
언록 초기화 변수는 글립코에 오래전부터 있었어요
하지만 2002년에 더그 리의 말록이 dl말록으로 알려진 말록이 거의 대량으로 글리브 말록에 포섭됐어요
네 네 dlmalloc은 global_max_ Fast heurist를 사용했는데 16년 동안 두 개의 수표는 나란히 존재해서 아무도 몰랐을 거예요
글로벌_max_ Fast 수표는 글로벌_max 2에서 드디어 제거됐죠
네
27. 그 체크가 원흉이었습니다. set_max_ Fast macro도 dlmalloc에서 불러오긴 했지만 global_max_ast를
0으로 설정하지 못했습니다.
말록이 초기화되지 않았다고 착각했을 거예요
맞아요 울리히 드레퍼의 패치 전에 set_max_ast가 요청2size를 이용해 global_max_f스트
값을 계산했죠
네 이 말은 특별한 0을 제외하고 1부터 160까지의 값은 0x20
이상 크기로 전환된다는 거죠
하지만 새 알고리즘에는 '공간'이라는 게 있어요
0을 넣으려고 하면 global_max_ast는 의도대로 안전값으로 설정될 겁니다
하지만 1부터 7 사이의 어떤 값이라도 보내면 계산이 0을 잃게 돼요
해 보죠
네 글로벌_맥스 속도는 0으로 설정했습니다 말로크가 이미 초기화됐는데도요 ? 네
잠시 영상을 멈추고 지금 맬록_콘올리드에 전화하면 어떻게 될지 생각해 봐요
그 행동을 이용할 방법을 최선을 다해 찾아봐요
네 물론 libc 주소는 아직 안 흘렸으니 막히면 다시 와서 재생하세요 ?
곧 봐요
네 중단하기 전에 버그를 발견해서 글로벌_맥스_패스트 변수를 0으로
설정했어요 맬록이 초기화된 후에요 ?
도전 이진법과 비교하면 어떨지 보죠
미숙성 청새리상어로 덩어리는 안 먹겠다고 했어요 global_max_ast는 현재 0입니다
말로크가 준비하도록 일부를 요청해요
이렇게 global_max_ast가 기본값으로 설정된 것이 0x80입니다
네 네 '최적화' 옵션을 통해 1부터 7까지의 어떤 값이든 전달합니다 포함되어
있죠
네 말록은 물론 초기화 중이지만 글로벌_맥스_패스트는 이제 0이에요 말록_통합 함수가
초기화되지 않았다는 증거죠 , 말록_통합
네 파트 2에서 토끼의 집 기술을 다루면서 맬록_consolidate를 간접적으로
촉발하는 다양한 방법이 있다는 걸 배웠습니다 큰 요청을 하거나 큰 덩어리를 풀어주는 게 가장 쉽죠
이런 경우에는 더 쉬운 방법이 있어요 맬롭트를 다시 부르는 거죠
네 '최적화' 메뉴 옵션으로 멀롭트를 호출해서 그걸 실행하세요
네 맬록_colidate는 전에 호출돼요 맬롭트는 뭐든 작동하니까 글로벌_max_fast는 원하는 값으로
설정해도 안전해요
원래 값으로 되돌려 놓겠습니다
네 중단점이 발동하면 멀록_통신에서
멀록 초기화 확인을 해야 합니다 실행합니다 네 0을 발견하면 통합 코드를 건너뛰고 malloc_init_state를
호출해 미증식된 주요 아레나라고 추정되는 걸 초기화합니다 ????
malloc_init_state로 들어가려면 GDB의 스텝 명령 명령을 사용하세요
그다음은 다음
bin 초기화 루프가 나옵니다
상자가 다 비어서 루프가 안 통해요
257개 내에서 건너뛰죠 좀
긴 루프예요
우리가 관심 있는 건 마지막 문장이에요
주요 경기장의 꼭대기 지점에 자리 잡고 있죠
네 네 맨 위의 청크 포인터는 자신을 가리키게 됩니다 무체계화 빈 fd 전에 16바이트에
있기 때문입니다 안 됩니다, 이 상태라면 경기장의 마지막 남은
필드는 제일 큰 덩어리가 될 겁니다
앞서 말씀 드렸듯이 네 그리고 sy스말록 함수가 커널에서 메모리를
요청해 힙을 형성하도록 유도합니다 , 말로록에 첫 요청이 있을
때요
네 지금 위쪽 포인터는 활성화된 위쪽 포인터의 주소를 갖고 있어요 아까 요청한 대로요
위에 있는 덩어리를 다음으로 초기화 코드를 실행합니다
맞아요, 소스 코드는 우리가 거꾸로 한 것처럼
보이게 하지만 컴파일러 최적화의 결과일 뿐이에요
여기서 주목할 점은 경기장의 꼭대기 지점이 자기 자리를 가리킨다는 겁니다
보안 측면에서 보면 좋지 않아요
계속... 계속 진행하면 프로그램이 안정적임을 알 수 있고 이 상황을 이용할 가능성이
있습니다
정지 화면이 나타날 때 이 시나리오에서 가능한 게 뭔지 시간을 들여 알아보세요
주 경기장에 배치할 수 있어요?
그렇다면 그걸 어떻게 이용해 libc를 유출할 거죠?
이번에도 최대한 진전을 보이고 아이디어가 바닥났을 때만 돌아와요
네
"톱 청크는 메인 아레나에 있다"는 상황에서 뭘 할 수 있었죠?
주 경기장에 배치할 수 있었나요?
그렇다면 수고하셨어요
이 부분은 넘어가도 돼요
이미 한 걸 정확히 설명할 거예요
그렇지 않다면, 메인 아레나에 어떻게 할당할지 살펴보겠습니다 재설정했습니다
네 바로 한 덩어리를 요청하면 이런 상황이 됩니다 말로크가 그냥 더미를
확장하는 거죠 크기가 큰 걸로 알 수 있습니다 ? 네
네 1부에서 오렌지 하우스 기법을 배웠을 때 말록이 요청을
하나 받았는데 맨 위 칸에 할당된 분량입니다 맨 위 칸이 너무 작으면
말록이 요청을 연장하려 하죠 ,
이 사건이 바로 그겁니다
네 마지막 주문을 취소하죠 메인 아레나의 상단부를 메인 아레나에 다시 넣겠습니다
멈춘 상태였던 것처럼요 ? 네
왜냐하면 Last_remainter는 맨 위에 있는 청크 크기 필드인데 요청을 수행할 만큼
크지 않아서 맬록이 sbrk를 이용해 힙을 확장했고 맨 위에 있는 청크 포인터는 커널이 새로
할당받은 메모리로 이동했습니다 ,
주요 경기장에 성공적으로 분배하려면 우선 맨 위에 있는 덩어리를
포인터 형태로 공급해야 합니다
그렇군요 힙랩 PDF를 보면 경기장의 마지막_재분기 필드를 빨리 채우는 방법은 빈맵 검색에서
일부를 다시 채우는 겁니다
자, 이건 전에 챌린지에서 했던 거니까 이번엔 자세히 설명하지 않겠지만
PDF의 '다시 쓰기' 섹션이나 1부의 다시 쓰기 강의를 참고해 주세요
화면에 pwntools 템플릿을 제공해 놨으니 템플릿_2로 다운로드 받으실
수 있습니다
네 신청자 5명 중 3명을 메인 경기장의 마지막 남은 필드를 채우죠 무정체 상태에
일부를 풀어 작은 부분을 요청합니다
네 그 후에는 그 후에 안 돼요
GDB와 ASLR 옵션 없이 스크립트를 실행해 맬록 상태를 보죠
해산
메인 아레나도 점검하고요
. 마지막_rema 필드는 이전엔 null이었는데 이젠 힙 주소가 채워집니다 구체적으로 남아있는 remainter_me
청크죠 ?
저희 스크립트가 set_max_ Fast bug를 통해 이 경기장을 다시 초기화했거든요 위쪽 포인터가
가리키죠
이번엔 힙 주소 형태로 0이 아닌 크기 필드를 갖습니다
네 이 세트의 경우 더미를 새로 만들고 위쪽을 옮기는
대신 주 경기장에 있는 실제 있는 위쪽을 사용합니다
그래서 Last_remainter 필드를 설정하고 메인 아레나를 다시 초기화함으로써 거기에 할당할
수 있어요
잠시 후 또 다른 화면 정지 화면이 나옵니다 비디오를 정지할 때 이 기능을 어떻게 활용할지 고려하세요
메인 아레나에 할당하기 위해서요
마지막이에요 네 남은 건 2개예요 libc 주소를 유출하고 껍데기를 버리는
거죠 안 돼요
왜냐하면 이 쌍성을 악용하기 위해 여러분이 만들어낸 흥미로운 착취 벡터를 읽는 게
재미있거든요 그러니
힌트 없이 다음 단계를 시도하길 권합니다
그건 그렇지만 libc 주소를 유출하려면 우리가 모르는 기술을 적용해야 해요
힌트를 원하신다면 다음을 단말기에 입력하세요
좋아요, 더 직접적인 지시를 원한다면 비디오를 다시 돌리고 libc 유출을 같이 꾸며요 거나요,
마지막 알림까지 준비했으니 이제 두 가지 요구 사항만 남았습니다
우리도 부식의 이진법의 집과 비슷한 상황에 처해 있습니다 강하고 원시적인 메시지를 만들었지만
수하물에서 읽을 수 있는 선택권이 없죠
네 제한된 요청으로 유출되지 않는 길은 못 가요 libc 주소를 유출하는
게 최선이에요
네 제가 멈춘 동안 힌트를 보셨다면 파일 스트림을 타깃으로 한다는
걸 이미 아실 겁니다
우리가 쓸 기술은 말로크의 달인인 엔젤보이가 고안했죠
강의 자료에서 업무 설명에 사용된 슬라이드 덱 링크를 이용하실 수 있습니다
우리가 관심 있는 부분은 60번 슬라이드에서 시작합니다
이 프레젠테이션은 네 운영 방법을
제시한 것입니다 네 임의로 해석하는 방식은 데이터가 파일 스트림으로
작성될 때 버퍼는 _IO_write_base에서 시작해 _IO_write_ptr에서
끝납니다
네 이 포인터를 수정한다면 파일 스트림 버퍼 주변의 데이터를 파일
설명에 쓸 수 있을 겁니다
네 이 공격으로 목표 바이너리가 이미 자주 사용 중이니 겨냥할 수
있습니다
정말 편리해요 유출된 데이터는 단말기에 출력만 하면 되고 폰툴로 처리하면
되니까요
네 스트림에 다른 파일 스트림을 쓰는 경우 stdout이 아닌 파일 스트림을 변경해서
stdout이나 원격 바이너리와 통신하기 위해 사용하는 소켓에 맞출 수 있습니다 등등
민감한 출력물의 리다이렉션도 제공합니다
엔젤보이의 메서드로 바이너리 최적화에서 libc 주소를 빼돌리죠
template_2를 시작점으로 사용할 수 있습니다
좋아요, 다음 요청은 맨 위 청크가 서비스할 겁니다 지금쯤 메인 아레나에 자리하고 있죠 last_remainter가
사이즈 필드로 제공됩니다 네, 맞아요
이제 아시겠죠 스트더와 스트러드 파일 하천은 주 경기장에서 조금 떨어진
곳에 있습니다 하지만 그 사이에는
손상시키면 문제가 될 데이터가 있죠
그 이유는 호기심 많은 이들이 알아내도록 하죠
네 가장 좋은 방법은 큰 투우장과 큰 투우장 사이를 메울 수 있는 걸 찾는 거예요
그리고 큰 투우장을 겹치게 하는 거죠
그럼 허용된 요청 다섯 개에 도달할 테니 남은 착취 작업을 더 하지 않고 할 수
있도록 준비해야 해요
네 네 안 돼! 안 돼!
우선 목표물에서 현재 꼭대기 지점까지의 거리를 계산합니다
그리고 목표물에서 약간 벗어나도록 충분히 빼는 거죠 이런 경우에는 가장 가까운 숫자를 고릅니다
그러면 되겠네요
네 다음 다음 요청은 겹치게 돼 있어요 그 요청에 서술적인 의미를
부여해 보죠
이 덩어리가 _IO_FILE 구조와 겹쳐지도록 합니다 이유는 나중에 나옵니다 0x100이나 그 이상의 크기면
될 거예요
아... 계산이 맞는지 확인하기
위해서 스트라우츠_플래그 들판을 쉽게 알아볼 수 있는 값으로 덮어쓸게요 ?????
글리벡에서 스트라우트는 16바이트 경계에서 시작합니다
하지만 상단 트렁크의 초기화가 8바이트로 잘못됐기 때문에 늦기 전에 안쪽 네 글자가
필요해요
준비가 되면 GDB와 NOASLR 옵션으로 스크립트를 실행하세요
해산
그리고 거머리도요
네 네 육각 분포로 나타내니 우리 계산이 옳았고 이제 스트라우트 파일
스트림을 조작할 수 있습니다 , 이 파일은
설명할게요 _IO_writ_base와 _ptr 필드에 관심이 있어요 그 사이의 메모리가 가리키는 곳이니까요
우리 프로그램이 단말기에 뭔가를 인쇄할 때마다
스트라우트 파일에 쓰여요 안 그러면
네 기본적으로 스트라우트는 라인 버퍼가 돼 있어요 스트림의 쓰기 버퍼 내용물이
뉴라인 캐릭터가 나타날 때만 씻겨 내려간다는 뜻이죠
네 스트림이 이렇게 버퍼링되면 저장되지 않은 데이터를 저장할 공간을 할당받습니다
보통 이 필드는 힙 주소를 갖습니다
네 하이랩 바이너리 하지만 라인 버퍼링을 해제해야 해요 그래서 이 필드에 libc
주소가 모든 예시에 있는 거죠 언부스터 스트림은 힙 버퍼 대신 단일 문자_쇼트부프 필드를 사용합니다
네 네 초기 코스에서는 라인 버퍼를 해제했어요 버퍼가 장애물을
만들거든요 그래서 착지에 영향을 주지 않았다고 설명해야 했죠
일관성을 위해 나머지 코스에서는 얌전히 굴었어요
그렇죠 하지만 _쇼트부프와 힙 버퍼는 유용한 데이터를 유출할 기회를
줍니다 libc 주소도 노출될 게 뻔하니까요
네 버퍼 필드를 손댈 땐 조심해야 해요 libc를 아직 유출 안 했고
부식 하우스
강의에서 배웠듯이 중요하지 않은 12개 이하의 것은 모두 ASLR의
대상이거든요 ?
그럼... 가장 좋은 방법은 바이트가 덜 큰 _IO_write_base만 수정하는 거예요 더 이상은요 아웃 오브 바운드와 세그폴팅을
읽는 위험을 감수해야 해요
네 바이트의 가치를 줄이면 _쇼트부프 필드 전에 스트라우트 파일 스트림을
포함하여 쓰기 버퍼를 넓힐 수 있습니다
네 스트라우트가 라인 버퍼를 썼다면 그 전에 일부를 썼을 거예요
그렇군요 어쨌든 libc 주소가 그 범위 안에 있길 바라야죠 이 경우에는 그래요
네 다른 완충지대가 누출되는 것 외에 스트딘의 주소가 적힌 _체인 포인터는
잘 작동할 거예요 ,
네 이 글립코 빌드에서 가장 덜 중요한 바이트는 0x88이에요 그래서 가장
덜 중요한 바이트를 같은 값으로 덮어쓰기만 하면 돼요 , _IO_write_base
네 잠시 후 pwntools 스크립트로 돌아와 가비지 3개 쿼드를 추가합니다 _flags 필드와 _IO_write_base
사이의 거리를 커버하기 위해서요 ????
그럼 0x88 바이트만 쓸 수 있죠
변화를 줄 수 있도록 GDB를 닫습니다
네 쓰레기 데이터를 0x88 바이트로 편집 헬퍼 함수에 추가하면 일반적인
옵션으로 스크립트를 다시 실행합니다
스트러드 망원경_IO_베이스필드
이제 스트딘의 주소를 가리키는 걸 알 수 있어요
맞아요 프로그램이 거머리 완충기를 씻어내게 하면 주소를 읽을 수 있어요
libc
유출
일단 터미널에서 진행 상황을 보고 인쇄가 되도록 하죠
계속해요
프로그램 창으로 전환한 다음 메뉴 출력을 눌러 이 거머리 버퍼를 씻어냅니다
아무 일도 없어요
GDB 창으로 돌아가서 다시 깨고 문제를 추적합니다.
이 문제를 네 ???? 네
2진법은 주로 글리벡의 푸트를 사용합니다
하지만 이 함수를 중단하면 온종일 여기 있어야 해요
글리벡은 간접적이고 효과적인 방법으로 겉으로 보기엔 단순한 추적 과정이 사실 꽤 힘든
과정임을 보여 줍니다
예를 들어보죠
그 시작은 네 _IO_file_xsputn 함수를 가리키죠 _GI_IO_filexsputn
또는 그냥 _IO_filexsputn입니다 ,
이 기능을 네 다른 두 이름으로 stout 버퍼를 씻어냅니다 ????????
_IO_new_do_write가 처리하는데 new_do_write가 호출합니다
new_dowrite 콜 _IO_new_file_write
그다음에는 쓰기라고 부르는데 이 역시 여러 이름으로 불리죠 그리고 마지막으로 시스칼이라고 부릅니다
네 이런 간접적인 걸 설명하기보다 중요한 코드로 바로 들어가보죠
에인절보이 슬라이드를 자세히 봤다면 파일 스트림의 플래그가 중요한 역할을
한다는 걸 알 거예요
네 당연하죠 지금은 쓰레기니까요 첫 번째 문제는 _IO_new_file_오버플로 기능입니다
브레이크 포인트를 설정하세요
계속하세요, 그런 다음 프로그램 창으로 가서 메뉴 프린트 리턴을 누르세요
GDB로 돌아가니 문제가 바로 보입니다
_IO_NO_WRITES 플래그가 설정되면 _IO_new_file_오버플로가 일찍 돌아옵니다
네 놀랍지도 않네요 _IO_NO_Rite 파일 스트림을 받아쓰면 안 된다는 걸 고려하면 안
되죠
네 이 깃발에 주목하세요 gdb 설정 명령으로 정리하고 계속 실수를 찾습니다 ? 네
다음 순서는 깃발 확인입니다
여기 여기요 _IO_write_base가 유출된 주소지만 _IO_CURNETING 플래그가 설정되었는지 확인해야
합니다 다음 코드를 피하기 위해서요 그렇지 않으면 _IO_write_base가 공격받을 겁니다
다시 깃발을 보세요
이미 설정됐기에 다음 5개 명령을 발령해 프린팅 코드의 마지막 중요한 부분에 도달합니다
,
여기 _IO_do_write가 호출되고 있네요
_IO_write_base와 _IO_write_ptr 사이의 모든 것을 플러시할 거예요
간접적인 건 생략하고 new_do_write에 중단점을 설정하고 계속합니다
마지막 점검이에요 마지막 점검이죠 목록을 보고 조정해야 해요
네 조기 귀환을 피하려면 두 가지 방법이 있어요 stdout _IO_read_end 필드를 많이 _IO_write_base로
설정하는 건 어렵습니다 _IO_write_base의 전체 값을 아직 모르기 때문입니다 아니면 그냥
_IO_ISAPPENDING 플래그를 설정합니다
네 이유는 모르겠지만 슬라이드에 후자는 안 나왔지만 현재로선 그 방법뿐이니 그렇게
하죠 ? 네
네 0xdeadbeef 플래그 값은 set_IO_IS_APPENDING 비트예요 이 플래그를 인식한
후 다음 3은 조기 반환 건너뛰고 코드로 넘어옵니다 ??
지금까지 실행하려고 노력했잖아요
맞습니다, _IO_SYSWRITE는 파일 스트림의 쓰기 엔트리를 호출하는 마크로 _IO_new_file_write를 가리킵니다 _IO_write
알았어요 이제 메모리를 단말기에 전송하는 걸 막을 수 있는 건 아무것도 없으니 중단점을
비워둬요
계속하고 프로그램 창으로 바꾸세요
네 도전 항목은 평소처럼 메뉴를 출력했지만 미리 무작위로 표시된 글자가 있습니다
스트라우트 파일 스트림에서 유출된 바이트예요
pwntools를 이용해 해석할
수 있습니다 GDB를 닫고 에디터로 돌아갑니다
마지막 가사는 지저분한 파일 스트림의 일부를 덮어쓰는 거였죠
가장 중요한 건 _flag 필드와 _IO_write_base 필드의 바이트입니다
네 이제 우리는 정확한 깃발 조합을 설정하고 비워내야 한다는 걸 압니다 그래야 데이터가 유출될 테니까요
제일 먼저 문제가 된 게 _IO_NO_쓰기였어요
명확해야 기본 파일 설명을 쓸 수 있습니다
네 다음 중요한 깃발은 _IO_PUTING입니다 네, 다음 깃발은 _IO_PUTING입니다 안 그러면 수정된 _IO_write_base
포인터를 방해할 코드를 실행하지 않도록 설정해야 한다는 걸 배웠죠
마지막으로 _IOISAPPENDING 플래그 역시 조기 반환을 피하기 위해 설정해야 합니다
네 자리 표시자 0xdeadbeef 플래그를 제거하고 현재 _IO_PUTING과 _IO_APPENING으로
대체합니다 _IO_NO_쓰기 기본값은 깨끗합니다
격식을 차리고 싶다면 플래그의 마법 값을 포함할 수도 있지만 이건 필수는 아니에요
올바른 플래그를 추가하고 나면 편집 메뉴 옵션을 호출하는 방법을 바꿔야 합니다
보통 스크립트 도우미 기능은 프로그램 출력 대부분을 버립니다 유출된 데이터도 잃게
됩니다
그래서 이 도전만을 위해 "취소" 논쟁을 도우미 편집 함수에 추가했습니다
이 호출에서 우리가 할 일은 그 인수를 거짓으로 설정하는 거죠
이 주장을 추가하고 나면 이 데이터 누출을 신속히 테스트해보죠 생산 조건에서 취약 스크립트를
실행해서요
데이터를 유출하고 있으니 pwntools에서 캡처해 제대로 됐는지 보죠
이전 챌린지에서 했던 내용이지만 다시 간단하게 설명드리겠습니다
이오 recv는 다음 8바이트의 프로그램 출력을 읽습니다
네 주소는 stdin이길 바랍니다 stdouts_IO_write_base를 _chain 포인터에
표시했거든요 stdin의 주소를 갖고 있죠 , 맞아요 pwntools 언팩트 함수는 유출된 주소를 정수로
변환합니다
네 네 그런 다음 libc 이진법 내 stdin의 오프셋을 빼 libc 로드 주소를
주고 libc 오브젝트를 채워 적절한 심볼 조회도 가능하게 합니다
네 그다음에 재발신 요청을 추가해서 남은 출력을 폐기하면 돼요 유출된
libc 부하 주소를 단말기에 기록해요
좋아요, 이 대사를 스크립트에 추가했으니 GDB 옵션으로 실행하세요 하지만 ASLR은 켜두세요 요행으로
누출된 게 아니니까요 ,
crl+c로 브레이크 libc 로드 주소를 보세요 제 것과 다를 겁니다 aslr이 활성화됐으니까요
프로그램 창으로 변경해서 취약점 스크립트로 출력된 주소와 비교해 보세요
일치하면 축하드려요 버그가 없는 프로그램에서 libc 주소를 유출한
건 물론이고 읽지도 못하게 하는 프로그램이에요
해방군 주소를 알았으니 곧 폭탄을 투하할 겁니다
네 요청 다섯 개를 다 들어줬지만 아직 조작할 수 있는 파일 스트림이 있어요
네, 맞아요
네 원하시면 지금까지 다룬 내용과 명확한 해설이 있는 다른 템플릿
스크립트를 다운로드 받을 수 있습니다
양식 번호 3번이라고 적혀 있어요
마지막으로 영상을 멈추고 껍데기가 나오는지 봐요
나중에 여기서 봐요
조개껍데기 받았어요?
그렇다면 잘했어요
안 그래도 돼요
같이 해결해요 지금 화면에 챌린지
최적화 솔루션이 있습니다
우리와 같은 단계를 거치는 것으로 시작돼요 초기화하고 메인 아레나로 할당해서 엔젤보이
방식으로 libc를 유출하는 거죠
마무리로 폰툴의 파일 구조 클래스를 보여드리고 싶습니다 파일 스트림 착취를 돕기 위해 특별히
디자인된 거죠
네 이전에는 가짜 파일 스트림을 수동으로 만들었습니다 그리고 파일 스트림 구조에 대해
배우게 해주긴 했지만 이제 할 수 있는 건 힘든 과정입니다
네 가짜 파일 스트림을 만들고 있어요 스카이사이드 기법으로 셸을 투하할
거예요 부식 착취용
주택에서 썼던 기법이죠
네 포인터를 설치해 메뉴가 인쇄되는 동안 스트라우트의 xsputn에 리디렉션되게
합니다 익숙한 _IO_str_O버플로 기능으로요
생략한 필드는 모두 무의미해요
네 네 _IO_write_ptr과 _IO_write_base의 차이는 _IO_buf_end와 _IO_buf_base의
차이와 같습니다
네 기억하시죠? 지난번에 이 기술을 썼을 때 이 제약이 충족돼야 했어요
가짜 파일 스트림에 추가된 것은 _IO_str_O버플로가 호출할 함수 포인터입니다 네 libc가 유출됐으니 쓸 만한
장치를 하나 찾아서 주소를 적어 뒀어요
이 시나리오와 부식 착취가 일어나는 집의 가장 큰 차이점은 이 시나리오에서는
모든 오염 물질을 공격한다는 거예요
네 _lock는 원래 온전한 필드인데 파일 스트림이 사용 중인지 알려주는
값을 가리키죠
_lock은 재생되어 뒤링에게 쓰입니다 파일 스트림에 쓰죠
네 보통 쓰기 가능한 메모리의 주소를 포함해야 하는데 파일 스트림이 풀렸다는 의미의 null
사변어면 더 좋죠
네 사소한 거지만 말이에요 libc 누출 및 통제 스트라우트의 _록 필드가
있거든요 더 간단한 메서드는 제가 본 적 없는 건데 _IO_USER_LOCK 락 플래그를 설정해
잠금을 해제하는 겁니다
네 다행히 다행히 사용할 수 있습니다
,
pwntools의 파일 구조 클래스에 대해 더 알고 싶다면 pwntools 문서들에 더 자세한 것들이
있습니다.
좋아요, 이 마지막 줄에 이 마지막
줄에서 , 좋아요,
네 그 후 프로그램이 자동으로 메뉴를 출력해 파일 스트림을 촉진하고 셸을 제거합니다
생산 조건에서 착취를 실행하면 다 해결될지 보죠
그리고 등딱지를 얻었죠
말록 5마리만 유출하면 libc는 포지션 독립 바이너리의 껍데기가 되죠 nx,
스택 카나리아스, 렐로로요
게다가 챌린지 최적화 바이너리에 버그도 없고 힙을 읽을 옵션도 없어요
우리가 이용한 글립벡 버그는 버전 2에서 실수로 고쳤어요 글로벌_맥스_패스트는 맬록 초기화
확인에 더 이상 사용되지 않습니다
네 set_max_bug 버그 리포트를 제출해서 패치는 됐는데 여전히 계산이 틀려서
0xb0 패스트빈 접근이 안 돼요
네 우리가 의존한 맬롭트 기능은 흔히 사용되지 않지만 null 바이트 하나로 글로벌_max_fast를
덮어쓸 수 있습니다
그 전에 이번 작전을 간단히 요약해 드리죠
네 네 목표 바이너리로 글로벌_맥스_파스트를 수정했어요 M_XFAST 매개 변수를 글로브의 맬롭트 함수에
전달해서요
맬롭트는 글로벌_맥스_패스트를 제한 범위 밖으로 못 트게 해요
몇 년 전에 글리벡 버그가 도입돼서 0으로 설정할 수 있어요
네 패스트빈에는 영향이 없지만 말록 초기화에 실수가 있었으니 말록_콘올리드메이트를 호출해서
주 경기장을 다시 초기화할 수 있어요 ,
아레나 초기화에서 포인터는 자신을 가리킵니다
네 이걸 이용할 수 있었죠 마지막_재분자 필드를 설정해 상부 청크
크기 필드가 됐어요
위쪽의 포인터가 주 경기장을 가리키고 있고 유효한 크기의 경기장이 있어서
우리가 주 경기장에 배치할 수 있었죠
네 네 스트로드를 조작해서 스트딘의 주소가 터미널에
인쇄됐어요 ? 네, 맞아요
네 네 앤젤보이의 방법을 이용해 특정 신호를 설정하거나 지우고
중요하지 않은 바이트를 덮어씌워 자체의 _채인 필드를 가리켰죠
이 부분은 버퍼를 확대했습니다 민감한 데이터를 포함해 씻겨나가야 할
부분이었죠
이 경우에는 스트딘의 주소입니다
우리는... 리bc 연설을 유출하고 같은 전략을 사용했습니다 부식의 집 강의에서
배운 거죠 포탄을 투하하는 겁니다 안 돼요!
제 주석형 솔루션 스크립트는 강의 리소스에서 다운로드 가능합니다
맬롭트 기능과 여러 변수를 실험해 보고 싶다면 맬롭트 메뉴도
선택할 수 있습니다
파일 스트림을 통해 임의로 읽기를 하고 기억을 새로 고침하고 싶다면 pdf가 알아서 해 줄 겁니다 비네시 라오 a의 블로그
포스트 링크도 포함해 뒀습니다 케이 a 쉘벡 셸벡은 제가 처음 배우던
엔젤보이의 기술을 이해하게 해줬죠
그건 그렇고 비네시가 폰툴의 파일 구조 코드도 작성했어요, 감사해야죠
그럼... 넘어가기 전에 다음 단계로
넘어가기 전에 안 돼요
부식 방지 기법보다 훨씬 간단한 대안이죠
네 다음 영상에서는 글리벡의 최근 금고에 관해 알아보겠습니다 금고를 완화하는 방법과 우회하는 방법도 함께
알아보겠습니다