Leaking libc address with ROP
Last updated
Last updated
AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE) GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE)
오버플로우 오프셋 찾기
POP_RDI
가젯, PUTS_PLT
및 MAIN
가젯 찾기
이전 가젯을 사용하여 puts 또는 다른 libc 함수의 메모리 주소를 유출하고 libc 버전 찾기 (다운로드하기)
라이브러리를 사용하여 ROP를 계산하고 이를 이용해 공격하기
이 튜토리얼은 다음 튜토리얼에서 제안된 코드/바이너리를 이용해 공격할 것입니다: https://tasteofsecurity.com/security/ret2libc-unknown-libc/ 또 다른 유용한 튜토리얼: https://made0x78.com/bseries-ret2libc/, https://guyinatuxedo.github.io/08-bof_dynamic/csaw19_babyboi/index.html
파일 이름: vuln.c
익스플로잇을 다운로드하고 취약한 바이너리와 동일한 디렉토리에 배치한 후 스크립트에 필요한 데이터를 제공합니다:
Leaking libc - template템플릿은 익스플로잇을 계속 진행하기 전에 오프셋이 필요합니다. 제공된 경우, 필요한 코드를 실행하여 오프셋을 찾습니다 (기본값 OFFSET = ""
):
실행 python template.py
하면 프로그램이 충돌하는 GDB 콘솔이 열립니다. 그 GDB 콘솔 안에서 x/wx $rsp
를 실행하여 RIP를 덮어쓸 바이트를 가져옵니다. 마지막으로 파이썬 콘솔을 사용하여 오프셋을 가져옵니다:
오프셋(이 경우 40)을 찾은 후, 해당 값을 사용하여 템플릿 내의 OFFSET 변수를 변경합니다.
OFFSET = "A" * 40
또 다른 방법은: pattern create 1000
-- ret까지 실행 -- pattern seach $rsp
를 GEF에서 사용하는 것입니다.
이제 바이너리 내에서 ROP 가젯을 찾아야 합니다. 이 ROP 가젯은 puts
를 호출하여 사용 중인 libc를 찾고, 나중에 최종 익스플로잇을 실행하는 데 유용합니다.
PUTS_PLT
는 함수 puts를 호출하는 데 필요합니다.
MAIN_PLT
는 오버플로우를 다시 이용하기 위해 한 번의 상호작용 후에 main 함수를 다시 호출하는 데 필요합니다 (무한한 공격 라운드). 각 ROP의 끝에서 프로그램을 다시 호출하는 데 사용됩니다.
POP_RDI는 호출된 함수에 매개변수를 전달하기 위해 필요합니다.
이 단계에서는 pwntools가 실행 중에 모든 것을 찾기 때문에 아무것도 실행할 필요가 없습니다.
이제 어떤 버전의 libc 라이브러리가 사용되고 있는지 찾을 시간입니다. 그렇게 하기 위해 우리는 함수 puts
의 메모리 내 주소를 leak한 다음, 해당 주소에서 puts 버전이 포함된 라이브러리 버전을 검색할 것입니다.
이렇게 하려면 실행된 코드에서 가장 중요한 줄은:
이것은 RIP를 덮어쓰기할 수 있을 때까지 몇 바이트를 전송할 것입니다: OFFSET
.
그런 다음, RDI 레지스터에 다음 주소(FUNC_GOT
)가 저장되도록 POP_RDI
가젯의 주소를 설정합니다. 이는 우리가 puts를 호출하고 PUTS_GOT
의 주소를 전달하기를 원하기 때문입니다. puts
함수의 메모리 주소는 PUTS_GOT
가 가리키는 주소에 저장됩니다.
그 후, PUTS_PLT
가 호출될 것이며(여기서 RDI 안에 PUTS_GOT
가 있습니다) puts는 PUTS_GOT
안의 내용을 읽고 (메모리에서 puts 함수의 주소) 출력할 것입니다.
마지막으로, main 함수가 다시 호출되어 우리는 오버플로우를 다시 이용할 수 있습니다.
이렇게 우리는 puts 함수를 속여서 메모리에서 puts 함수의 주소를 출력하게 했습니다(이는 libc 라이브러리 안에 있습니다). 이제 그 주소를 알았으니 어떤 libc 버전이 사용되고 있는지 검색할 수 있습니다.
우리가 로컬 바이너리를 악용하고 있기 때문에 어떤 버전의 libc가 사용되고 있는지 알아낼 필요는 없습니다(단지 /lib/x86_64-linux-gnu/libc.so.6
에서 라이브러리를 찾으면 됩니다).
하지만 원격 익스플로잇의 경우, 여기서 어떻게 찾을 수 있는지 설명하겠습니다:
웹 페이지에서 어떤 라이브러리가 사용되고 있는지 검색할 수 있습니다: https://libc.blukat.me/ 이 사이트는 발견된 libc 버전을 다운로드할 수 있도록 해줍니다.
다음과 같이 할 수도 있습니다:
$ git clone https://github.com/niklasb/libc-database.git
$ cd libc-database
$ ./get
이 작업은 시간이 걸릴 수 있으니 인내심을 가지세요. 이 작업이 작동하려면 다음이 필요합니다:
Libc 심볼 이름: puts
유출된 libc 주소: 0x7ff629878690
우리는 어떤 libc가 사용되고 있는지 알아낼 수 있습니다.
We get 2 matches (you should try the second one if the first one is not working). Download the first one: 우리는 2개의 일치를 얻습니다(첫 번째가 작동하지 않으면 두 번째를 시도해야 합니다). 첫 번째 것을 다운로드하세요:
libs/libc6_2.23-0ubuntu10_amd64/libc-2.23.so
에서 libc를 복사하여 작업 디렉토리에 저장합니다.
이 시점에서 우리는 사용된 libc 라이브러리를 알아야 합니다. 로컬 바이너리를 익스플로잇하고 있으므로 나는 단지:/lib/x86_64-linux-gnu/libc.so.6
를 사용할 것입니다.
따라서 template.py
의 시작 부분에서 libc 변수를 다음으로 변경하십시오: libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") #Set library path when know it
libc 라이브러리에 경로를 제공하면 나머지 익스플로잇이 자동으로 계산될 것입니다.
get_addr
함수 내에서 libc의 기본 주소가 계산될 것입니다:
최종 libc 기본 주소는 00으로 끝나야 합니다. 그렇지 않은 경우 잘못된 라이브러리를 유출했을 수 있습니다.
그런 다음, 함수 system
의 주소와 문자열 _"/bin/sh"_의 주소는 libc의 기본 주소에서 계산됩니다. 그리고 libc 라이브러리가 제공됩니다.
마지막으로, /bin/sh 실행 익스플로잇이 준비될 것입니다:
Let's explain this final ROP.
마지막 ROP(rop1
)은 다시 main 함수를 호출하며 끝났습니다. 그러므로 우리는 다시 이용할 수 있습니다 오버플로우(그래서 OFFSET
이 여기 다시 있는 것입니다). 그런 다음, 우리는 POP_RDI
를 호출하여 주소를 "/bin/sh"(BINSH
)로 지정하고 system 함수(SYSTEM
)를 호출하고자 합니다. 왜냐하면 _"/bin/sh"_의 주소가 매개변수로 전달될 것이기 때문입니다.
마지막으로, exit 함수의 주소가 호출되어 프로세스가 정상적으로 종료되고 어떤 경고도 생성되지 않습니다.
이렇게 하면 익스플로잇이 _/bin/sh_** 셸을 실행합니다.**
대신 system과 **"/bin/sh"**를 사용하는 대신 ONE_GADGET를 사용하여 셸을 얻을 수도 있습니다. ONE_GADGET은 libc 라이브러리 내에서 단 하나의 ROP 주소만으로 셸을 얻는 방법을 찾습니다.
그러나 일반적으로 몇 가지 제약이 있으며, 가장 일반적이고 피하기 쉬운 것은 [rsp+0x30] == NULL
입니다. RSP 내부의 값을 제어하므로 제약을 피하기 위해 추가적인 NULL 값을 보내기만 하면 됩니다.
이 취약점을 악용하기 위한 템플릿은 여기에서 찾을 수 있습니다:
Leaking libc - template"main" 심볼이 존재하지 않는 경우, 메인 코드가 어디에 있는지 찾을 수 있습니다:
그리고 주소를 수동으로 설정합니다:
이진 파일이 Puts를 사용하지 않는 경우 다음을 확인해야 합니다.
sh: 1: %s%s%s%s%s%s%s%s: not found
모든 익스플로잇을 생성한 후 이 오류를 발견하면: sh: 1: %s%s%s%s%s%s%s%s: not found
"/bin/sh"의 주소에서 64 바이트를 빼보세요:
AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE) GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE)