네 이 영상에서는 부식의 원시인 세 집을 결합할 겁니다 취약한 바이너리 로봇의
껍질을 벗기는 법을 배웠죠
물론 주소는 못 흘리니까 '맹목적으로' 진행해야겠죠
부식의 집입니다 부식의 집 원시적인 재료는 다용도로 쓰일 수 있고 활용법도 다양합니다
? 네
다음은 아주 제한된 환경에서 셸을 얻는 방법의 한 가지 예입니다
사용 가능한 도구를 간략히 요약해보죠
프리미티브는 자유자재로 작성되는 libc 2진법의
4괄호에 영향을 미칩니다 초기 버전에서는 해당 지역에 힙 주소를 쓸 수 있습니다
네 네 수정할 수 있고 초기 단계 3은 한 곳에서 다른 곳으로
값을 옮길 수 있어요
기억하세요 libc 주소를 수정할 때는 가장 덜 중요한 두 바이트만 정확히 변경할 수 있습니다
aslr 비트 4개를 성공적으로 맞혔다면요
그렇기 때문에 시스템 기능처럼 유용한 걸 가리키는 포인터를 찾지 못하면 창의력을
발휘해야 합니다
네 놀라실지도 모르겠지만 저희가 파일 스트림 착취를 이용해 셸을 차지할 겁니다
복잡한 여정이 될 거라고 경고합니다 하지만 착취 개발이 그럴 때도 있죠
프리미티브 1번과 2번을 다루면서 무체계빈 공격으로 _IO_List_all을
노리지 않았다고 했죠 그렇게 하려면 libc 정보 유출과 가짜 vtable 주소 둘 다 알아야 하니까요
안 돼요
그 껍데기를 얻으려면 이 두 가지 한계를 극복해야 해요 이것만 해도 힘든데 글립코
2라니요 27은 파일 스트림 돌파에 대한 두 가지 완화를 나타냅니다
첫째는 간단합니다 중단 함수는 더 이상 파일 스트림을 플러시하지 않습니다
말록의 착취 완화를 촉발하면 회복할 수 없다는 뜻이죠
두 번째는 글리벡 2에서 도입된 감형안을 개선한 버전입니다 24는 사용 전에 포인터를
확인하려고 합니다
이렇게 하는 거예요
stdio 파일 스트림 vtable 포인터가 _IO_file_jump 테이블을 가리키죠
이 테이블은 글리벡이 특별 가상 공간으로 표시한 읽기 전용 기억 구역에 자리합니다
파일 스트림의 vt 가능한 포인터를 이 지역 밖으로 겨냥한다면 예를 들어 더 탑 안으로요
하우스 오브 오렌지 착취 1부에서 그랬듯이 파일 스트림 멤버 함수가 호출되면 글리벡은
활성화 가능한 포인터가 특별한 활성화 가능한 지역으로 향하지 않는다는 걸 깨닫고 이 과정을
중단할 겁니다
글립코 버전 2가 흥미로워요 24시간에서 2시간까지요 네 네 dlopen 훅이 0 이외의 값을
갖고 있을 때 이 완화를 해제하는 안전장치 메커니즘이 있습니다
물론 정서불안 공격 같은 기술을 쓰면 악용될 수 있죠
버전 2에서요 하지만 27번 이 안전장치는 속이기 훨씬 어려운 더 튼튼한
확인 장치로 교체됐습니다
네 그래서 이 완화를 해제하기보다는 한 연구원이 설명한 기술을 쓸 거예요 스카이다이더라는
핸들이죠
강의 자료에 게시글 링크가 있어요
맞아요 글리벡이 실시간으로 이동할 수 있는 영역에 _IO 파일 점프만 있는 게 아니라
다른 것도 있어요
네 네 다른 테이블에 겨냥할 수 있어요 네, 맞아요
네 본질적으로 좀 혼란스럽네요 포인터를 제대로 작동시켜야 해요 ? 컨티넨탈 확인
흥미로운 건 _IO_str_jump라는 vtable이에요 _IO_strfile 스트럭트와 관련된 함수 포인터를 포함하고 있죠
, _IO_strfile 스트럭트요
네 _IO_strfiles C++ 호환성 레이어예요 후드 아래는 여전히
_IO_FILECT죠
하지만 _IO_strfiles에는 vtable 포인터 뒤에 추가된 데이터가 더 있습니다 이 _IO_str_필드는 오프셋 0xe0에서...
메모리 관리 루틴을 위한 한 쌍의 기능 포인터입니다
_IO_str_finish와 _IO_str_O버플로 기능 안에서 불립니다
둘 다 _IO_str_ 점프 vtable에 속해요
네 파일 스트림의 포인터를 수정해서 멤버 함수를 호출해야 할 때
두 함수 중 하나를 대신 호출하면 실행 흐름을 장악할 수 있어요 네
네 네 코드에 포인터를 놓기만 하면 됩니다 target _IO_str_필드
중에서 실행하고 싶다면요
그걸 명심하고 공격 계획을 세워 보죠
우리가 작업할 템플릿 스크립트입니다
네 강의 자료에서 복사본을 다운로드하세요 제가 추천하는 건 우리가
쓰던 스크립트보다 약간 더 복잡하다는 거예요
양식 번호 3번이라고 적혀 있어요
타자를 너무 많이 치지 않도록 이 취약점을 파악했습니다 이제 빈칸을 채울
겁니다 아시겠죠?
보세요 보시다시피 원시적인 세 가지 이식의 근원은 동일합니다 모어코어
갈고리죠
하지만 이번에는 두 번째 출처와 두 곳에 가야 합니다
같은 덩어리를 재사용하면 여러 번 이식할 수 있어요
한 번 할 때마다 조금씩 빼면 돼요
데스티네이션 1은 stderr_IO_buf_end 필드입니다
목적은 나중에 밝혀질 겁니다 stderr 파일 스트림을 노리는 이유도 밝혀지겠죠
데스티네이션 2는 stderr 더하기 0xe0입니다
네 _IO_str_필드 포인터가 있는 곳이고요 적어도 워드는요 stderr이 _IO_strfile이
아닌 _IO_FILE로 취급되면요
여러분 상상이 잘 안되시나요? 걱정 마세요 곧 GDB에서 수색할 테니까요
다음은 고정된 크기의 덩어리들입니다 무체중인 녀석은 청크와 다른 여러 개를 원시인
1, 2로 공격합니다
관련성이 생기면 하나씩 설명해 드리죠
네 이제 3단계 풍수지리를 준비할 차례입니다 이미 설명했으니 반복하지
않겠습니다
두 번째 파편은 '큰 덩어리'라고 표시해 둔 파편만 있을
뿐입니다
여기서 뭘 하는 건지 관련되면 설명드리죠
그리고 그다음에는 그 후에 부식 원시인 집이 활성화됩니다
??
이제 내가 말한 대로 스트더의 포인터를 조작할 수 있어요
왜 우리가 스타더를 노리는지 설명하기 좋은 때인 것 같아요
네 네 왜냐하면 프로세스의 공간에서 항상 이용 가능하기
때문이죠 stdin은 이진법이 아니라
글리벡의 읽기 기능을 사용합니다
맞아요 스타우트는 작동하고 있고 프로그램 결과물을 볼 필요가 없으니 파괴는
문제가 안 돼요
더 나은 제안은 취약한 프로그램이 메뉴를 출간할 때마다 더 좋은 제안이 들어올 겁니다
스타우트는 타당한 목표군요
그럼에도 불구하고 부식의 이진법으로 얼룩진 집에서 허풍 떨지 않게 해 주세요
네 덕분에 더 어려워지고 우분투의 글립크 쌍성에 관해 흥미로운 걸 배울
기회가 될 겁니다
네 네 메뉴 코드 없이 프로그램을 만들 수도 있지만 존재 자체가 디버깅과 프로그램 작동법을
훨씬 쉽게 알려줍니다
이건 역설계 수업이 아니니까요
그럼 남은 건 스트더뿐이군요 네 이 작업을 통해 스태더에 최적화하려면
멤버 함수에 전화를
걸어야 합니다
문제는 어떻게 했느냐죠 네 스트더는 활동하지 않으니 평소에는
그런 전화를 안 할 겁니다 안 하는 게 좋겠어요
맞습니다 하우스 오브 오렌지를 만들면서 _IO_flush_all_lockp 같은 기능을 이용한다는
걸 알았습니다 프로그램이 중단하거나 나갈 때 파일 스트림을 모두 플러시해 멤버 함수를 호출하는 거죠
하지만 글립코 버전 2를 기억하세요 27이 플러싱 완충기 코드를 중단시켰어요
계속 도전적으로 만들기
위해서 부식 바이너리 하우스에서 출구 옵션을 제거했습니다 ctrl+c로는 버퍼를 씻어내지
못합니다
하지만 희망이 없는 건 아닙니다
이 한계를 극복하고 글리벡을 강제로 출력할 수 있어요
정확히 어떻게 하는지는 마지막 순간에 알게 될 겁니다
당장은 스트더 vtable 포인터 개조가 필요합니다
프린팅에 파일 스트림을 사용하면 x스푸트 vtable 엔트리가 됩니다
어떤 _IO_jump 테이블의 여덟 번째 항목입니다
네 타깃 함수 _IO_str_finish나 _IO_str_O버플로우가 세 번째와 네 번째 항목을 차지합니다
각각 _IO_str_ 점프죠
좋아요, 네 그럼 stderr 글립코에 출력해서
_IO_Overflow 함수를 호출할 거예요 예를
들면요 GDB를 이용해서 계산을 할 수 있습니다
어떤 오버플로 기능을 선택할까요?
마무리가 가장 간단해요
네 작동 중인 스트럭트에 두 가지 제약만 부여합니다 _프리_버퍼 함수를 호출하기 전에요
포인터 _IO_buf_base
필드는 null이 아니고 _IO_USer_BUF 플래그는 명확하죠
이 두 제약을 1번과 2번으로 쉽게 충족할 수 있습니다
수정 가능한 부분은 이미 대본으로 다 처리했습니다
네 네 원시적인 2를 사용해 stderr의 포인터를 조정합니다 앞으로 stderr로 프린트하려는
시도가 _IO_str_finish 함수를 대신 호출하도록요
초기 단계 2가 두 번째로 사용돼 null stderr_flag 필드가 됩니다
네 너무 과한 것 같지만 깃발 하나 확인하자고
나중에 유용할 거예요
네 네 대부분의 필드는 null이 됩니다 _IO_buf_base를
포함해서요 ? 두 번째 조건을 충족하려면
원시적인 걸 사용하죠 여러분 대본에 적당한 크기의 덩어리를 준비해뒀습니다
스트더_버프바이즈라고 이름 붙였죠
이걸 풀어 원시적인 걸 작동시켜 stderr_IO_buf_base 필드에 힙 주소를 적습니다 ? 네
io를 사용했죠 상호작용을 브레이크포인트로 했었습니다. 지금 다시 해 볼게요. 네 pwntools는 일시 정지 기능을
제공합니다 같은 기능을 수행하지만 프로그램과 상호작용할 수 없습니다
스크립트를 실행하면 여기까지 옵니다 입력을 잠시 멈추고 gdb로 프로그램 상태를 검사합니다
나머지 스크립트를 실행하지 않고요 ,
원한다면 프로그램 윈도우에서 ctrl+d를 눌러서 계속 할 수 있습니다
대사를 추가했으면 GDB 옵션으로 스크립트를 실행하세요
명심해요, 링크를 풀 때 프로그램이 세그폴트를 누르면 불행히도 libc 부하 주소가 나와요
프로그램이 다운되지 않을 때까지 재도전해요
안정되면
바로 검사할 거예요
말씀드렸듯이 대부분의 필드가 null입니다 우리가 건드린 영역은 _flag입니다
스크립트가 원시적인 2로 0을 처리했죠 네 _IO_buf_base 원시적 주소와 vtable
포인터 덕분에 특수 vtable 지역 안에 머물 수 있게 위치를 바꿨어요 xsputn
엔트리에 _IO_str_finish 주소가 있어요
인쇄를 시도해서 우리 작업을 확인할 수 있어요
우리 템플릿 스크립트는 이미 적절한 함수에 중단점을 설정했어요
그래서 우리가 할 일은 fprintf 같은 걸 호출하는 거죠 "fprintf)
소스 패널을 보면 모든 게 계획대로 된다는 걸 알 수 있죠 네 stderr에 프린트하면 _IO_str_finish
호출이 발생하죠 호출돼야 할 함수 대신에요
네 네 stderr_flags 필드를 제로링하고 _IO_buf_base를 채웁니다 이 체크가 통과되면 코드에
도달합니다 _프리_버퍼 함수 포인터를 호출하죠
네 fp 이
경우 stderr은 _IO_strfile로 캐스트됩니다 기억하실 텐데요 그냥 _IO_FILE 구조죠
그 끝에 함수 포인터가 묶였고요 ?
호출하려고 하는 함수 포인터 중 하나죠
네 물론 표준 에러는 _IO_strfile이 아닙니다 함수 포인터는 stderr 파일 스트림 이후에
있는 것이면 무엇이든 중첩합니다
글리브가 작업을 시작하면 대개 스트더는 곧바로 따라옵니다
네 그리고 실제로 _프리_버퍼 함수 포인터가 stdout 파일 스트림의 두 번째 사분어드와 겹칩니다
네, 맞아요,
_IO_read_ptr 필드예요
네 계속 gdb를 하면 프로그램이 그 분야의 값으로 넘어가려 합니다 물론 실행 가능한 것으로 설정되진
않지만요 세그폴트를 유발하죠
맞아요 그럼 기본 3번으로 스트러드_IO_read_ptr 필드에 시스템 주소를
입력하면 되겠네요
결국 이 순간 rdi 등록은 우리가 제어하는 힙 메모리를 가리킵니다
네 문제가 하나 있어요 초기 단계 3단계는 이식 근원과 목적 기억
모두 작성 가능해야 해요 그래서 글리벡의 기록에 있는 코드 주소만 사용할
수 있어요 패스트빈 전에는 안 돼요 부식된 초보자는
그 이후의 기억만 손상시키니까요
이 모든 주소를 나열하는 가장 좋은 방법은 다음 농담을 사용하는 거예요
네 네 전부 없애는 겁니다 메인
아레나부터요 네 컷 우리가 관심 있는 칼럼을 추출합니다 메모리 주소와
그 값이죠
컷 커맨드의 "필드" 옵션을 변경해야 할 수도 있습니다 같은 결과를 보려면요
마지막입니다 마지막으로 ASNI 컬러 코드 레드입니다 pwndbg가 메모리 맵핑을 실행 가능으로 나타낼
때 사용하는 거죠
네 좀 허술하지만 효과는 있어요 더 나은 방법이 있으면 알려주세요
? 네
네 결과를 보면 이런 상황에서는 글립코드 작성 영역 전체에서 코드에 10가지
포인트가 있어요 ? 네
그럼... 프리미티브 3으로 이 중 하나를 스트러드_IO_read_ptr
필드에 이식해서 실행하면 됩니다
네 안타깝게도 안타깝게도 ,
하지만 바이트가 가장 작은 두 개의 표시구를 이식하면서 바꿀 수 있습니다
시스템이나 원가젯이 근처에 있는지 보죠
실행하려면 가장 중요한 여섯 바이트의 후보 연설이 목표 코드와 일치해야 합니다
후보가 열 명뿐이니 눈대중으로 판단하면 됩니다
슬프게도 시스템은 해당이 안 돼요
그럼 원-가전은요?
글리벡 글리벡 작업에는 총 3대가 사용 가능합니다 2대는 꽤 가깝게 붙어 있네요
네 이 선은 너무 걱정하지
마세요 링크 맵을 이용해 첫 번째 가제트의 주소를 프린트해 libc 공유 개체의 시작 주소를 찾겠습니다
마우스를 잡기엔 너무 귀찮거든요
이 장치는 시스템과 비슷해서 주사위는 안 떨어져요
세 번째는요?
좀 더 멀죠
슬프게도 그렇게 안 됐죠 네 후보 주소 중 어떤 것도 가장 작은 두 바이트를 변경하지
않고는 시스템이나 장치로 안전하게 변형할 수 없습니다
네 4비트가 아닌 12비트를 추가한다면 가능성이 훨씬 커지겠지만 최대한
4비트를 추가할
겁니다 4비트를 추가할 수 있다면
네 12를 추측하는 것과 4를 계산하는 건 큰 차이가 있어요 특히 환율에 제한이 있거나
ids보다 낮게 날아야 한다면요
어디서부터 잘못된 걸까요?
_IO_str_finish 함수를 오버 _IO_str_O버플로를 선택했을 때겠죠
둘 다 네 하지만 _IO_str_finish를 선택한 건 간단했기 때문이죠
몇 가지 지시 사항만 있으면 돼요 , 간단하죠
사실 필요한 건 복잡성일지도 몰라요
네 _IO_str_overflow는 더 많은 일이 벌어집니다 함수 포인터를 호출하기 전에 데이터에
유용한 일을 할 확률이 높아지죠
프로세스는 _IO_str_finish를 위해 이미 준비해둔 것과 다르지 않아요
네 이 선에 도달해야 합니다 stderr이 _IO_strfile로 캐스트되고 _allatch_버퍼
함수 포인터가 되죠
확실히 하려면 stderr 파일 스트림을 수정해야 합니다
일찍 복귀하는 건 피하고 깃발만 몇 개 뽑으면 돼요
네 이 제약을 이미 해결했어요 스크립트가 모든 _플래그 들판을 원시적인 2로 정화했거든요 ?
네 네 또한 _IO_write_ptr과 _IO_write_base의 차이점이 _IO_buf_end와
_IO_buf_base의 차이점보다 클 수도 있습니다
네 다시 다시 말하지만 ???
네 이제 초기 버전 1로 _IO_buf_base를 채울 필요가 없어요 아까처럼요 함수 포인터에 도달하려면 _iO_str_finish를
호출합니다
근데 _IO_str_O버플로는 다른 결과가 나올까요?
네 코드를 봐도 조금 전 같은 상황이 발생하지 않을 거라는 보장은
없습니다 실행 흐름을 장악할 수는 있지만
인포리크가 부족해서 유용한 실행 코드가 없습니다
이 기능이 도움이 될지 추측하기보다는 오류 분석이라는 과정을 통해 도움을
얻어보겠습니다
네 콘셉트는 간단해요 콘셉트는 단순해요 트라이톤이나 판다모어 같은 프레임워크에 사용된
오류 분석 엔진은
등록이나 기억 위치를 '오염된 곳'으로 표시할 수 있습니다 우리가 통제한다는 뜻이죠
그런 다음 함수나 프로세스 심지어 시스템 전체를 모방해서 오염된 값이 코드나 재향 군인회 공간에
얼마나 퍼지는지 판단하죠
테인트 분석 엔진을 설치하고 사용하는 건 이 코스의 범위를 벗어납니다
하지만 제가 트리톤의 뼈대를 위해 쓴 짧은 스크립트를 보여드리죠
스크립트입니다 네 몇몇 _IO_FILE 필드를 오염시켰는데 부식된 초기 설비로
잠재적으로 제어할 수 있죠
이 경우엔 _IO_buf_base & _end죠
네 트리톤의 단점은 오류가 발생하지 않는다는 겁니다 그래서 사용될 게 확실한
이 두 필드만 오염시켰을 뿐 전체 _IO_파일 스트럭트는 아닙니다
네 라벨을 붙이면 판다 프레임워크는 가능하지만 시스템 에뮬레이션에 의존합니다 단순한 필요에
과한 요구죠
맞아요 스크립트는 손상된 데이터를 작동시키는 모든 지시를 빨간색으로 인쇄해요
에뮬레이션은 컨트롤을 주는 함수 포인터 콜에 도달하면 멈춥니다
스크립트를 실행해서 결과를 볼 수 있습니다
여기 네 여기 있습니다 오염된 _IO_buf_base와 _end 값은 각각
r12와 r15 등록기로 옮기고 있습니다
_IO_buf_base는 _IO_buf_end에서 뺄 수 있습니다. 결과는 축전기에 저장됩니다.
추가 명령일 수도 있지만 축전기가 0이 된 걸 볼 수 있습니다
기억하세요 32비트 등록기에서 연산은 64비트 등록기의 상위 32비트를 지웁니다
나머지 작전은 관심 없습니다
그리고 마지막으로 함수 포인터 호출을 누릅니다 초록색으로 프린트됐죠 실행을 우리에게 넘깁니다
내 트리톤 스크립트는 마지막으로 손상된 값에 영향을 받은 등록기를 모두 출력해요
통제권을 얻는 시점까지
일반인들에게 눈짓으로 인식하는 것보다 훨씬 효과적이죠
네 r12를 예로 들죠 함수 포인터가 호출되면 우리가 쓴 값이 뭐든 담습니다 stderr_IO_buf_base
필드요 없다면요 ,
네 이 방법은 유용할 것 같습니다. 명부를 직접 관리하기 때문입니다. 하지만 주소를 유출하지
않았기 때문에 더 이상 통제할 수 없습니다.
네 우리가 찾는 건 좀 더 복잡한 거예요 애초에 _IO_str_Overflow
_IO_str_finish를 고려한 이유가 그거죠
축전기와 r15 등록기가 더 나은 것 같습니다 둘 다 차이가 나요 stderr_IO_buf_base와
_end 필드요 둘 다 부식성 물질로 통제할 수 있어요
아이오블렌 마크로의 결과로 알아볼 수 있을 겁니다
네 프림티브 3을 써서 libc 주소를 stderr_IO_buf_end 필드에 이식하면 _IO_buf_base
필드에 입력하는 모든 값이 뺀 값으로 랙스와 r15 등록기에 남아요 현재로서는 우리가 주도권을 쥐고 있어요
네 그럼 등록기에 임의로 등록된 libc 주소를 입력할 수 있는데 지금까진 불가능했어요
이건 회음 분석이 어떻게 개발에 도움이 되는지 보여주는 좋은 예입니다
일단 대본이 우리 사고 과정을 따라잡으면 이 발견을 실행에 옮길 수 있어요
다음과 같습니다 이 공격의 마지막 단계로 가기 전에 말씀드린 도구를 확인하시려면 트리톤에서 트리톤에
대해 더 많은
걸 알 수 있습니다 쿼크슬랩 c. 트라이톤
쿼크슬랩 트라이톤의
테인트 분석 엔진은 초보적이지만 그건 프레임워크의 일부에 불과합니다
개발 책임자는 조너선 살완으로 잠시 후 다시 등장할 겁니다
제가 언급한 다른 프레임워크는 Panda인데요 panda-re에서 더 자세히 배울 수 있습니다 mit요 에두 판다-레
mit요 네
네 기록 당시 트리톤보다 더 강력한 테인트 엔진을 갖추고 있었죠 안티에이션
말씀드렸듯이 작은 예시로는 과하다고 생각하지만 시간을 투자할 가치가 있습니다 나중에
더 복잡한 분석을 하고 싶다면요
스크립트로 돌아가서 배운 걸 좋은 일에 쓰죠
골내 주사부터 제거해요 상호적인 중단점은 이 선을 넘어 발전할 겁니다 다음 대본에서는요
네 _IO_str_finish를 _IO_str_O버플로로 바꾸기로 했기 때문에 양을 조정해야
합니다 스타더의 조준점을 조정하면
이 선에서 네 이 선에서 _IO_str__ 점프에서 뺀 양을 vtable 주소로
변경해 주세요
이제 프로그램이 stderr로 출력됩니다
그러나 하지만 리디렉션 될 것입니다
네 네 _IO_buf_base는 그대로 놔둘 거예요
곧 다시 돌아올 겁니다
함수 포인터가 호출되도록 한 가지 더 확인해야 합니다
네 _IO_write_ptr과 _base의 차이는 _IO_buf_end와 _base의
차이보다 커야 합니다
네 stderr_IO_write_ptr 필드에 큰 값을 적으면 확실히 그렇게
됩니다
초기 모델 2로 하면 돼요
타이핑을 절약하기 위해 이미 할당된 크기도 적절합니다
이걸 무료로 사용자 데이터에 큰 값을 적습니다
할당합니다 값을 복사해 stderr_IO_write_ptr
필드에 할당하죠 stderr 시작부터 오프셋 0x28입니다 ?????
네 이런 변화는 마지막 디버깅 세션에선 _IO_str_Overflow를 통해 _IO_str_finish
대신 갈 수 있어요
이제 오류 분석에서 배운 걸 활용할 기회입니다
네 네 libc 주소를 stderr_IO_buf_end 필드에 이식한
다음 그 주소와 우리 임의 주소의 차이점을 _IO_buf_base에
적는 거예요
네 _IO_str_O버플로 기능은 rax와 r15에 임의 libc 주소를 남길 거예요 우리가
집행의 흐름을 장악하는 거죠
이건 일부 기능이 수행하는 수학의 부작용일 뿐입니다
대본에 이미 이식 수술도 다 돼 있어요
이 줄들은 목적지 stderr_IO_buf_엔드 필드에서 이중으로 무료입니다
그런 다음 이 선들이 default_morecore 함수의 주소를 해당 목적지로 이식합니다
네 기본값_morecore 함수는 특별할 게 없어요
그냥 우리가 앞선 예제에서 이미 익숙했던 liBC 주소죠 안 그래요?
네 이식이 완료되면 실행 가능한 코드를 가리킬 필요도 없어요 libc 바이너리 내에서
위치를 정하기만 하면 되죠
여기서 잠시 멈추고 취약점 상태를 확인하겠습니다
io를 추가합니다 이식 후 양방향 중단점을 만들 거예요
좋아요 계속하기 전에 아주 복잡한 문제를 간단히 이해했어요 특히 원시적인
3번 문제요
원시적인 동물들의 세세한 부분에 너무 빠지지 않으려고 노력 중이에요
4시간은 족히 됐을 거예요
그래서 이 기술을 세 개의 강의로 나눴죠
여러분 네 혹은 지난 강의를 통해 지식을
재구성하고 싶다면요
네 지금까지 한 게 마음에 들면 초기 단계에서 실행한 줄로 스크롤을 다시 올려주세요
stderr_IO_buf_base 필드 앞에서요
같은 부분을 편집해서 default_morecore 함수의 주소와 임의의 libc
주소를 구분해요 rax와 r15로 끝내야 해요
네 이 해킹은 아직 실험 단계니까 기본값_모어코어와
글리벡의 시스템 기능을 비교해 보죠 ? 네, 네
나중에 수정하면 돼요 도움이 안 되면요
마지막으로 초기화 2를 완료하려면 stderr_bufase를
다시 요청하세요 _IO_buf_베이스 필드는 오프셋 0x38 스트더 스트럭트에 있어요
변경사항이 있다면 GDB 옵션으로 취약점 스크립트를 실행합니다
가서 확인해 봐요
_플래그 필드는 여전히 0이지만 지난번과 몇 가지 차이가 있어요
네 네 _IO_write_ptr 필드는 큰 값을 가지고 있고 xsputn vtable 엔트리는 _IO_str_Overflow
함수를 가리킵니다 _IO_start_finish 대신에요
네 네 default_모어core의 주소가 _IO_buf_end 필드와 해당
_IO_buf_base가 이식된 걸 볼 수 있습니다 그것과 시스템 주소 간 차이를요
이번엔 stderr에 프린트하면 우리 _IO_str_O버플로우 브레이크 포인트가 점화될 겁니다
이제 코드에 접근하기만 하면 돼요 _allcap_버퍼 함수 포인터를 호출하는 코드죠
stderr_flag를 0으로 하면 이런 조기 반환을 피할 수 있죠 여기 이 코드도요
네 다음 이 수표를 통과시켜야 해요 'pos'는 stderr_IO_write_ptr과 _base
필드의 차이점이에요 _IO_buf_end와 _base 필드의 차이점보다 크거나 같아야 해요 "nbc 필드"
플러시_only가 0이 됩니다
big_IO_write_ptr 값이 수표가 통과되도록 보장합니다
네 또 두 번째 조기 귀환을 피합니다 zeroed_flags 필드 덕분이죠 드디어 호출 전에 한 번 더
확인합니다 우리는
네 여기요 old_blen은 단순히 _IO_buf_end와 _IO_buf_base_base차이죠 두 배가 되어 100이 되면
새_사이즈가 나옵니다
새 크기가 올드블렌보다 작아지지 않는 한 이 조기 리턴을 피합니다 마지막 조기
리턴
그럼 우리가 접근하려던 코드가 나오겠군요 stderr은 _IO_strfile로 캐스트됐어요 _IO_strfinish에서처럼요
차이점은 포인터의 함수 이름이 _allcape_buffer라는 겁니다 _Fuffer가 아니라요
이건 _IO_read_ptr 필드가 아니라 stdoutsflag 필드와 겹칩니다
네 계속 gdb를 쓰면 프로그램이 그 _flag의 값으로 건너뛰려 하죠? 필드요 매핑된 주소가 아니라
세그폴트를 유발해요 ?
네 이 시나리오와 지난번엔 한 가지 중요한 차이가 있었어요 _IO_str_finish가
제공합니다
이건 라크스와 r15 레지스터예요
우리 오류 분석이 맞았어요
네 stderrs _IO_buf_end 필드는 우리가 이식한 libc 주소를
포함하고 있어요 거기서 통제 값을 _IO_buf_base에서 빼서 시스템 주소를 얻죠
네 이제 실행권을 얻기 전에 임의로 libc 주소를 두 개로 등록할 수
있어요
목표 처리 과정에서 바이트 하나 유출되지 않고 이 일을 해냈다는 걸 기억하세요
좋아요 이제 유용한 코드의 주소를 알았으니 실행할 방법만 찾으면 돼요
구식 3번 '락스 호출기' 같은 걸 구식 3번 스티커에 넣으면 될 거예요
편집기로 돌아가서 어떻게 할지 생각해 보죠
네 지금까지 새로운 걸 배우기 위해 취약한 프로그램은 비열하게 프린트되지 않는
척했습니다 ? 네
불행히도 우린 이제 현실을 직시해야 합니다 활동 중인 파일 스트림을 손대는 건 까다로워요
무슨 뜻인지 보여드리죠
스타우트_플래그스 들판을 개조해야 착취가 가능해요
0으로 설정해서 에뮬레이션할게요
계속 GDB로 가면 stdout을 이용해 프로그램이 메뉴를 출력할 수 있습니다.
다시 살펴보니 개조된 상태였습니다
다른 분야에서도 마찬가지고요
그래서 활성화된 파일 스트림을 안정적으로 조작하기가 아주 어렵죠
다행히 일시적으로 모드 필드를 1로 설정하면 파일 스트림을 해제할 수 있어요
그게... 프로그램은 잘 모르지만 스티어트에 인쇄하는 건 억제될 거고 그럼 깃발 밭이
공격받지 않을 겁니다 안 돼요!
네 이건 물론 부작용이 있어 프로그램 결과를 볼 수 없습니다 하지만 pwntools는
읽기 함수에 짧은 타임아웃을 설정해 해결할 수 있죠 이
과정의 악용 스크립트 대부분에서 보셨을 겁니다
속도만 늦출 뿐 멈추진 않을 겁니다
골반 제거하세요 양방향 중단점
그럼 프라이미티브 2로 stdouts_mode 필드를 1로 설정하죠 대본에는 이미 이럴 때를 위한 적당한 크기의
덩어리가 준비돼 있죠
그 덩어리를 풀면 원시적인 게 작동해요
버그를 이용해 사용자 데이터의 첫 사 자를 1로 설정합니다
네 마지막으로 마지막으로 그 다음은
기본 2.. an_IO_FILE Tile의 offset은 0xc0입니다
인터랙티브 브레이크 포인트를 추가합니다
그리고 GDB 옵션으로 스크립트를 실행합니다
프로그램 창으로 가서 리턴을 몇 번 누르세요
메뉴가 나와야 하는데 아무 일도 없네요
다시 GDB로 돌아가죠
다운되지 않은 걸 보니 우리 함정이 성공했나 봐요
스트라우트 모드 필드를 검사하니 원시적인 2가 있었어요
이 필드는 보통 0개예요
아... 네 출력은 안 나와도 카나리아 값으로 교체되지
않는지 확인하죠
전망이 밝습니다
이제 네 공격받지 않고요
'락스'를 부르는 장치가 있으면 좋겠다고 정했으니
그걸 찾아보죠
조너선 살완의 또 다른 도구 뢰파가뎃이
구조하러 옵니다
네 로퍼를 써도 되지만 녹음 당시 '거대' 옵션이 부족했어요 뢰프가트가 현명한
선택이었네요 ? 네
이건 귀환 지향적인 프로그래밍 코스가 아니니 가볍게 진행할게요
실행을 시스템으로 리디렉션하기 위해 하나의 장치를 사용할 것입니다
네 뢰가젯은 pnwdbg 내에서 rop 사령부로 호출할 수
있지만 지휘선에서 하는 게 더 쉽습니다
네 랙스와 r15 등록기에 시스템 주소가 저장돼 있지만 이 장치를 작동하면
랙스에 집중할 거예요
축전기를 이용한 지시는 보통 짧아서 발생할 가능성이 높습니다
네 실행 가능한 코드의 주소를 stdout_flag 필드에 옮기고 도중에 수정해서
합리적인 장치를 가리킬 거예요
코드에 대한 포인터에 대해서는 옵션이 제한되어 있다는 것을 기억하십시오
네 이미 default_morecore를 추출했습니다 morecore훅에서
추출했습니다 다음 이용 가능한 포인터를 이용하죠 print_and_abort 함수의 주소입니다 옵스트랙_alloc_failed_핸들러
기호죠
이 기호를 적어 두세요 장비 사냥을 가 보죠
네 뢰가뎃의 범위 옵션이 중요해요 프린트_abort 함수에서 가까운 곳에서만 가젯을
찾을 수 있거든요 ?? 네
버그 사용을 할 수 있습니다 버그 사용
후 주소를 변경할 수 있습니다 중요한 바이트가 최소 2개이기 때문에 장치의 위치는
16페이지 이내에 있습니다
네 다행히도 보셨다시피 콜랙스 장치는 암호화가 짧아서 찾기가 어렵지 않습니다
? 네
찾아볼게요 수색을 시작하기 전에 nm을 이용해서 글립코 바이너리의 프린트_앱오프를 찾아보죠
? 네
그 기능 근처를 못 찾으면 다른 옵션이 몇 개 있어요
프린트_abort 기호가 지금 우리가 상대하는 libc에 없는 것 같습니다
그래서 분리된 디버깅 기호 파일에서 찾아야 합니다
그 반경을 찾으면 뢰가뎃에게 다음 옵션을 알려줘요 프린트 앤 앱포트 양쪽으로 16페이지씩
검색합니다
네 aslr 엔트로피에 따라 너무 멀어서 유용하지 않을 수도 있지만 그래도 근처에서 뭔가 찾을
수 있길 바랍니다
모든 옵션을 추가해서 가능한 모든 랙스 호출 인스턴스를 볼 겁니다 룹의 장비 탐색자들은 기본적으로
복제품을 생략합니다
네 네 이걸 정규 표현식 옵션으로 rax 호출로 좁힐
수 있죠 안 돼요
마지막으로 바이너리 옵션으로 뢰가뎃에게 전자 기기 추적을 지시합니다
수색 결과 수많은 콜랙스 장비가 발견됐습니다
일부는 손에 닿지 않지만 대부분 원산지에 가깝다고 안심합니다
이건 꽤 비슷하니까 그걸로 할게요
네 앞으로는 다양한 자재를 원하시면 뢰가겟을 대화형 모드로 실행하는
게 더 쉬울 겁니다 콘솔을 이용해서요
네 이러한 도구들은 물론 아키텍처에 의존하죠 예를 들어 ARM을 작업한다면 접근법이
약간 다를 수 있어요
선택한 장치의 상쇄를 확인하고 편집자에게 돌아가세요
마지막 대화형 브레이크 포인트를 지우고 이 선으로 스크롤을 내립니다
네 저희 스크립트가 이미 print_abort 함수의 주소를 스트우드_flag 필드로
옮겼습니다
택시가 지나갈 때 주소를 수정할 기회죠
네 이식 후 기록 삭제 버그를 이용해 최소 바이트의 주소를 편집해서
방금 발견한 락스 호출 장치 대신 보낼 거예요
이 아래에 제공된 스크립트는 더 이상 없습니다. io를 추가할 필요가 없습니다. 양방향 중단점
준비가 되면 GDB 옵션으로 스크립트를 실행합니다
프로그램 창으로 전환하고 폰툴의 상호작용 프롬프트가 뜨길 기다립니다 네 스트라우트를 해제했기 때문에 pwntools
스크립트는 피드백을 받지 않습니다 명령어를 제때 전송할 수 없기 때문에 프로그램에
무언가를 보낸 후 짧은 타임아웃을 기다립니다
프롬프트가 나타나면 GDB 창으로 돌아가 ctrl+c로 중단합니다
트리거 스트더의 활동은 평소와 같습니다
걱정 마요, 곧 착취가 우리를 도울 거예요
다음 명령어를
사용하세요 네 실행을 통제할 수 있습니다
호출을 할 때 호출 rax 가제트가 실행되려고 합니다
한 번 더 밟으면 시스템 기능에 도달합니다
네 촉발성 stderr 활동은 잠시 후에 다루겠지만 취약점을 이용해
임의의 libc 주소로 실행 방향을 바꿀 수 있어요 ,
이 경우에는 시스템으로는 안 됩니다
네 rdi 등록에 대한 제어가 제한돼 있지만 유용한 명령 문자열을 가리킬 정도는 아니에요
네 다행히 선택할 수 있는 장치가 하나 있습니다 스택 포인터는 0으로 끝나지만
null rcx 레지스터와 스택 포인터에 0x40 또는 0x70을 더하면 null이죠
스택 포인터 플러스 0x40이나 0x48은 무효가 아닙니다
네 개인적으로 저는 rcx가 null인 게 더 좋아요 이 시점에서 rcx는 stderr_flags 필드의
사본을 갖고 있거든요 아까 null로 설정해둔 거죠
네 이렇게 하면 착취가 진행되면서 불안정해질 저장 상태에 의존하지 않아도 됩니다
_flag와 rcx 등록 사이의 연결 고리를 _IO_str_O버플로 함수의 동적 혹은
오류 분석을 통해 찾을 수도 있었습니다
네 네 stderr _IO_buf_base
필드에 입력한 값을 수정해서 시스템 함수 대신 원하는 One-가젯을 실행합니다
유일한 장치를 주목하고 편집자에게 돌아가세요
네 이 줄을 편집하면 stderr_bufbase가 나오고 시스템
주소를 가젯 주소로 바꿔요
원하시면 주석을 추가하거나 변경해서 상황을 명확히 할 수 있습니다
이거면 다음에 활동이 있을 때 탄피를 확보할 수 있어요
그렇군요 말이 나와서 말인데 이제 남은 건 이 프로그램을 아니, 글리벡을 기사로 만드는 것뿐이군요
이 부분은 재밌고 유익해요 그래서 녹슬기 쉬운 이진법으로 인쇄해도
괜찮은 척했던 거예요
좋아요 네 특이점을 이용할 겁니다
이유는 잘 모르겠지만 우분투 글리벡은 단언하는 발언으로 가득합니다
반면 데비앙 같은 디스트로는 이렇게 안 해요
네 전형적으로 문장은 디버깅을 위해 존재하고 프로덕션 빌드에서 컴파일러에 의해 제거됩니다
직접 보세요 어슈트 구문을 사용하는 프로그램을 구축하면 가능합니다
네 네 , 그게 다예요
컴파일하면 돼요
달려서 42로 패스
프로그램은 문제없이 완료됐습니다
네 42가 아닌 걸 패스하면 assert가 실패해 오류 메시지가 출력되고 그 후
프로그램이 중단됩니다 ? 이 오류 메시지는 스타더에게 인쇄됩니다
네 다시 컴파일하면 이번엔 NDEBUG를 정의합니다 gcc: 생산 바이너리를 구축해야 한다고 알려주는
거죠 문은 제거됐습니다 ,
네 제품 소프트웨어에서 강경한 주장을 고수하는 것에 대한 논쟁이 있지만 보안상 위험이 될 수 있습니다
네 프린팅은 글립카가 파일 스트림을 단축시켜 하기 때문이죠 반면 맬록_ printerr
같은 기능은 착취 완화 프린트를 사용할 때 보이는 에러 메시지를
훨씬 안전하게 생성합니다
네 우리가 의도적으로 그 발언을 실패하면 글리벡을 시켜서 스트더한테 발표하게 하고 그렇게 하면서
개조한 vtt 포인터를 보내면 돼요 , 어때요?
글록 글록에서는 이런 발언을 꽤 많이 해요 말로크에서도 제한적으로 하긴 하지만요
하지만 초기에 비체계성 빈을 손상시켜서 비체계성 빈 검색
후에 나오는 얼록 코드를 찾기 어려웠죠 라지빈이나 빈맵 시스말록
검색처럼요
네 고칠 수 있어요 하지만 이번 공격에는 혼란스러운 할당 규정에 있는
중 하나를 사용할 거예요 바로 이거죠 , 이겁니다
네 네 폐기하는 과정의 시작입니다 정확히 맞지 않는 덩어리가
적절한 소형 혹은 라지빈에 연결되죠
네 보이죠 덩어리 하나가 라지빈에 연결되면 이렇게 assert 문이 bin에서 가장
작은 덩어리가 NON_MAINA 플래그가 없는지 확인합니다
네 네 이유는 비메인 아레나의 무료 청크는 작은 것과 큰 것 모두 할당된 경우 비메인_아레나 플래그만
가질 수 있기 때문입니다
우리가 네 NON_MAIN_ARENA 깃발 설정을 하면 이
어슈서는 의도적으로 실패할 수도 있습니다 "그렇다면
저희 대본이 특별히 준비한 양입니다
0x420 사이즈로 이미 0x400 라지빈에 올려져 있죠
네 이제 tamper_large 청크를 편집하는 선만 넣으면 돼요 큰 청크 크기 필드를
겹쳐서 세 번째로 중요하지 않은 부분을 설정하는 거죠
네 대본에서 이쯤에서 0x400 라지빈에 비마인 아레나 깃발이 세트로 붙어 있어요
네 네 어서트 진술에 실패합니다 스티더에게 프린트하는 법을
배웠고 이제 껍질을 벗기면 좋겠어요
마지막으로 풀어야 할 문제는 덩어리를 분류하는 거예요
정리가 안 된 bk가 16 바이트를 가리키게 놔뒀죠 global_max_ast 변수 전에요
네 네 버려진_main_arena_ start라는 글립코 변수가
겹칩니다 보통 프로그램에는 채워지지 않죠
맞아요 하지만 초기형 2번으로 이 값을 조절할 수 있어요 가짜 크기장을 만들어서 말로크를 속여서
가짜 덩어리를 라지빈에 분류하게 하는 거죠
네 네 ???
이 덩어리를 떼고 그 후 버그를 써서 0x400 라지빈에 맞는 모든 덩어리를
적으세요
네 네 가짜 사이즈를 복사해 달라고 요청하면 버려진_main_arena_start
변수가 맬록으로 보일 거예요 메인 아레나의 마지막 크기죠
기억하실 겁니다 로어 왕가에 침입했을 때 우리가 만드는 가짜
덩어리는 일부 링크가 풀려서 쓰기 가능한 기억을 가리킬 겁니다
네 문제의 bk는 또 다른 글립코 변수와 겹칩니다 이름은 페딕틱이죠 역시나 거긴 사람이 안
살 겁니다 , 아마도요
기본으로 변수에 힙 주소를 쓰면 이 정도는 처리할 수 있어요
Fake_chunk_bk라는 이름의 덩어리를 준비해 놨습니다
Fake_chunk_bk를 자유롭게 하는 대사도 추가하세요
다 끝나면 GDB 옵션으로 취약점 스크립트를 실행합니다
네 네 안 그럼 부서질
겁니다
네 네 무체계빈 공격 목표인 global_max_ft보다
16바이트 앞에 있는 변수죠
네 방금 만든 가짜 덩어리를 살펴보면 가짜
덩어리 필드와 가짜 bv가 쓰기 가능한 메모리를 가리키죠
네 말록을 요청해서 정렬되지 않은 수색을 하게 되면 우리 요청 크기가 가짜
크기와 맞지 않으면 이 가짜 덩어리는 xx40 라지빈으로 분류됩니다
저 빈에 있는 가장 작고 유일한 덩어리는 우리가 NON_MAINAENA 깃발 꽂은 거예요
네 네 비전형적 방식 때문에 무체중 코드에 있는 이 어설트
선언은 기능합니다
이걸... 찾을 수 있어요 거기 도달하면 NON_MAIN_ARENA 깃발로 수표가 고장 나고 글리벡은
이를 알리려고 하겠죠 stderr 파일 스트림을 통해 오류 메시지를 프린트해서요
이렇게 인쇄하면 슈푸트 항목에 넣을 수 있어요
아까 우리는 부식의 집 원시적인 2를 이용해 스트더의 포인터를 개조했습니다
네 글립벡이 보호하는 거주 가능 지역 밖으로 유도하지 않으면 중단될 테니 xsputn
항목이 다른 함수 _IO_str_O버플로와 겹치게 조정했어요 ,
자, 이제 stderr 활동을 트리거하기 위한 모든 게 준비됐으니
지금까지 했던 것처럼 GDB를 속이지 않고 만들 수 있을 겁니다
그 가짜 덩어리가 해결되도록 요청만 하면 돼요
빈 트캐쉬와 일치하는 작은 덩어리를 요청하면 빠르고 작은 통이 될 겁니다 네 여기 tcache가 비었고 스몰빈과
기본 패스트빈도 비었으니 이 크기로
해 주세요
계속해요
프로그램 창으로 가서 적당한 크기를 요청하세요
물론 착취 장애가 있는 인간이라 피드백은 못 받으시겠죠
프로그램이 아직 우리 정보를 처리 중이에요
GDB 창으로 돌아갑니다. pwntools 스크립트로 _IO_str_O버플로우 브레이크포인트를 눌렀습니다.
네 우리 공격의 첫 부분이 제대로 작동한다는 걸 확인했어요 무체중 빈 공격 단계에서
libc 로드 주소 엔트로피를 정확히 추측하면 여기까지 올 거예요
네 기억하실 겁니다 _IO_str_Overflow는 _IO_strfile 구조에서 작동하도록 설계됐죠 stderr
같은 _IO_FILE_plus 구조가 아니라요
미미하지만 중요한 차이점이죠
_IO_strfiles에는 함수 포인터가 추가되어 있습니다 vtable 포인터 뒤에 추가된 것입니다
초기화 2를 이용해 네 안
그러면
다음 호출 명령으로 이동합니다 문제의 함수 포인터는 offset 0xe0에서 stderr
구조에 위치합니다 ?????
스트더는 그렇게 크지 않아요 이 오프셋은 스트우드_플래그 밭과 겹쳐요
초기 3단계로 프린트 앤 중단 기능의 약간 변경된 주소를 그 위치에
이식해서 그 주소를 공격하지 못하게 무력화했습니다
네 주소를 출력하기 위해 변경한 부분은 stderr+0xe0의
함수 포인터가 락스 가젯을 가리키죠
함수 포인터 호출로 이걸 확인할 수 있어요
이게 우리 장비예요
네 오류 분석을 이용해 실행 시점에 rax 등록기가 stderr_IO_buf_end와 _베이스
필드의 차이를 가지고 있다는 걸 확인했습니다 ??? 네 2번과 3번을 이용해서 그 밭에
libc 주소를 넣었어요 그 주소와 가젯의 차이는 각각 ?
이 장치의 제약 조건은 rcx 등록기가 null이라는 거예요 rcx가 이 시점에서 stderr_flags 필드의
값을 갖고 있기 때문에 함수 포인터 호출을 위해 의도적으로 null로 설정했습니다
이 One-gadget이 성공적으로 실행될 겁니다 ,
확인하기 위해 이걸 확인하기 위해 계속한 다음 프로그램 창으로 다시 전환합니다 거기엔 셸이 기다리고 있을 겁니다
그럼 이제 마지막으로 착취 작업을 마무리하고 생산 조건에서도 작동하는지 확인해 보죠
방금 수동으로 울린 말로크에게 마지막 신호를 보내
그럼 다른 옵션 없이 착취를 진행해요
조금만 참아요
좋아요, 7이 나타나길 기다리는 중이에요 libc 로드 주소 엔트로피에서 덜 큰 숫자 7이
나타나길요
몇 번 시도하면 껍데기를 얻을 수 있을 거예요
상황이 복잡해졌어요
네 이번 개발을 요약해 볼게요 솔직히 부식의 집을 파악하는 가장 좋은 방법은 이전 영상 두
개를 다시 보는 거예요 프리미티브 세 개에 익숙해질 때까지요 그리고 이 개발을 디버그해서 어떻게
함께 작동하는지 알아보세요
네 요약 후 계속 들으시면 이 바이너리를 이용할 몇 가지 방법을 알려드리죠 이
접근법이 마음에 안 드신다면
네 목표 바이너리에 완화 기능이 많았습니다 활성화 nx, 스택 카나리아 렐로 전체 포지션
독립
글립코 버전 2와 연관돼 있었어요 27은 요청, 무료,
그리고 10 바이트까지 큰 덩어리로 쓸 수 있습니다
네 하지만 중요한 건 프로그램을 깔끔하게 종료할 수 없어서 완충기 살포도 못 했어요
버그입니다 버그는 사용자 데이터의 시작부터 10 바이트로 쓰기 쉬운 작은 바이트였습니다
이 바이너리를 활용하기 어려운 이유는 재향 군인회 공간에서 데이터를 읽을 방법이 없기 때문입니다
주소를 유출할 수 없어서 '맹목적'이라고 써야 했죠
우선 네 글로벌맥스_패스트 변수에
대해서요
이를 위해 4개의 ASLR 엔트로피를 추측해야 했죠 가능한 최저량입니다
성공 확률은 16분의 1에 불과합니다
브루트포스치고는 나쁘지 않네요
네 글로벌_맥스_패스트가 큰 가치를 보유하자 부식 초기화 세 개를 이용해 진행할 수 있었습니다
우리 계획은 이 원시인들을 이용해서 포인터를 포함한 스트더의 밭을 개조해서
스트더의 활동을 촉발해 처형 방향을 바꾸는 거였어요
네 네 stderr에 프린트하려고 하면 _IO_str_overflow란
함수를 호출하죠 안 돼요
결국 우리가 컨트롤할 수 있는 함수 포인터라 부릅니다
네 네 함수 포인터가 호출되도록요
그 _flag 필드를 0으로 한 다음 _IO_write_ptr 필드에 큰 값을 적는 거죠
그런 다음 2, 3을 조합해서 계산대 안의 장치의 주소를 알아냈어요
실행의 흐름을 가로챈 거죠
네 네 libc 주소를 stderr_IO_buf_end 필드에 이식해서 그 주소와 적절한 One-gget의
차이를 _IO_buf_base 필드에 적었어요
실행합니다 하나의 가젯으로 실행하기 위해 장소에 있는 중급 호출 rax 가젯을
준비했습니다 _IO_str_O버플로가 곧 함수 포인터로 처리하는 곳이죠
네 stderr 활동을 촉발하기 위해 Ubuntu libc 쌍성의 특이점에 의존했습니다 특히 어세트
선언의 존재요 데비안 같은 다른 Linux 디스트로의 생산 코드에서 보통 삭제되는
것이죠
네 네 다른 덩어리는 같은
큰 통에 넣으려고요 ? 네
어슈트 함수는 stderr 파일 스트림을 이용해 오류 메시지를 프린트하기 시작했습니다 눈치채지 못하셨을 수도 있지만
부식된 이진법의 첫 번째 기능은 stderr 파일 스트림을 닫는
겁니다
네 이 기술이 효과적이란 걸 증명하려고 이 행동을 포함한 겁니다 종결됐다고 해도요
네 네 제어된 함수 포인터를 차례로 거칩니다
? 네
그 중간쯤 되는 장치가 우리가 준비한 유일한 장치인 탄피 투하로 바뀌었죠
네 마지막 공격은 꽤 복잡하지만 16번 시도할 때마다 한 번씩 껍데기를 얻어요 하지만 목표 프로그램에서
단 한 바이트도 새지 않죠
네 이번 강의를 위해 주석이 있는 솔루션 스크립트를 원하시면 이 강의 리소스에서 다운로드하세요
맞아요 효율성을 위해 약간 순서가 달라요 논리적으로
우리가 개념을 짜 맞추기 쉽게 하려고 우리를 이용하니까요 ? 네
옵션 없이 네 안 그러면
네 한 번만 개발을 시도하거나 디버깅 목적으로 한 번만 개발을 시도할 수
있습니다
네 자신만의 해결책을 쓰고 싶다면 이 바이너리를 다른 방식으로 이용해 보세요
라지빈의 단호한 발언자들만 접근이 가능한 건 아닙니다
예를 들어 tcache 코드에 실행 가능한 게 있죠
좋아요, 아까 이 영상 초반에 목표물이 안 나오는 척하라고 했죠?
난... 일을 어렵게 만들려고
그랬어요 그런 불순한 발언을 배울 기회를 주려고요
부식의 바이너리 하우스는 정말 멍청하네요 네 인정하세요 그걸 인정하면 스트더를
아예 사용하지 않는 방법을 쓸 수 있어요 공격에 실패할 필요성을 완화하고
휴대하기 쉽게 만드는 거죠
맞아요 원시적 3이 너무 복잡하다는 의견에 따라 4 대신 12비트를
추측할 의향이 있다면 이 2진법을 훨씬 더 간단하게 이용할 수 있죠
12비트 브루트포스를 사용하면 개발 성공률이 현저히 낮아집니다 하지만 생산이 가능할지도
모르죠 예를 들어
네트워크를 통해 운영하기보다 로컬로 운영하고 Python 대신 c로 개발을 작성한다면요
판정의 제한도 없습니다 네 네 하나의 도구에 직접 가리키면서요
껍데기를 얻기 위해 했던 것처럼 고리를 통과할 필요를
피해서요
이렇게 하면 네 이런 식으로 파일 스트림 악용을 무시하고 말록 바늘이나 다랑어 바늘만
노릴 수 있어요
맞아요 물론 있죠 부식 이진법의 집을 이용할 마지막 방법요 libc 주소를 흘리는
것도 포함돼요
그럼 다음 영상을 보시죠