Leaking libc address with ROP
빠른 요약
오버플로우 오프셋 찾기
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
ROP - LIBC 주소 노출 템플릿
해킹 도구를 다운로드하고 취약한 이진 파일과 동일한 디렉토리에 넣은 후 스크립트에 필요한 데이터를 제공하십시오:
pageLeaking libc - template1- 오프셋 찾기
템플릿은 공격을 계속하기 전에 오프셋이 필요합니다. 제공된 경우 필요한 코드를 실행하여 오프셋을 찾습니다 (기본값은 OFFSET = ""
):
실행 python template.py
를 하면 프로그램이 충돌한 상태로 GDB 콘솔이 열립니다. 해당 GDB 콘솔에서 x/wx $rsp
를 실행하여 RIP를 덮어쓸 바이트를 얻습니다. 마지막으로 파이썬 콘솔을 사용하여 오프셋을 구합니다:
오프셋을 찾은 후 (이 경우 40) 해당 값을 사용하여 템플릿 내의 OFFSET 변수를 변경합니다.
OFFSET = "A" * 40
다른 방법은 pattern create 1000
을 사용하는 것입니다. -- ret까지 실행 -- GEF에서 pattern search $rsp
를 사용합니다.
2- 가젯 찾기
이제 이진 파일 내에서 ROP 가젯을 찾아야 합니다. 이 ROP 가젯은 사용 중인 libc를 찾기 위해 puts
를 호출하는 데 유용하며, 나중에 최종 공격을 실행하는 데 사용될 것입니다.
PUTS_PLT
는 puts 함수를 호출하기 위해 필요합니다.
MAIN_PLT
는 exploit을 다시 사용하여 overflow를 다시 호출하기 위해 main 함수를 호출해야 합니다 (exploitation의 무한 라운드). 각 ROP의 끝에서 프로그램을 다시 호출하는 데 사용됩니다.
POP_RDI는 호출된 함수에 매개변수를 전달하기 위해 필요합니다.
이 단계에서는 실행할 필요가 없습니다. 모든 것은 실행 중에 pwntools에 의해 찾아질 것입니다.
3- libc 라이브러리 찾기
이제 사용 중인 libc 라이브러리 버전을 찾을 시간입니다. 이를 위해 메모리에서 puts 함수의 주소를 leak하고, 그 주소에 있는 puts 버전이 있는 라이브러리 버전을 검색할 것입니다.
이를 위해 실행된 코드의 가장 중요한 줄은 다음과 같습니다:
이는 RIP를 덮어쓸 수 있는 바이트를 보내게 됩니다: OFFSET
.
그런 다음, POP_RDI
가젯의 주소를 설정하여 다음 주소(FUNC_GOT
)가 RDI 레지스터에 저장됩니다. 이는 PUTS_GOT
의 주소를 전달하기 위해 puts를 호출하려고 하기 때문입니다. 메모리 주소에 있는 puts 함수의 주소가 PUTS_GOT
가 가리키는 주소에 저장되어 있기 때문입니다.
이후, PUTS_PLT
가 호출될 것입니다 (PUTS_GOT
이 RDI 안에 있음) 따라서 puts는 PUTS_GOT
안에 있는 내용(메모리에 있는 puts 함수의 주소)을 읽고 출력할 것입니다.
마지막으로, main 함수가 다시 호출되므로 우리는 다시 오버플로우를 이용할 수 있습니다.
이렇게 함으로써 우리는 puts 함수를 속이고 메모리에 있는 puts 함수의 주소를 출력하게 했습니다(이는 libc 라이브러리 내부에 있습니다). 이제 해당 주소를 통해 어떤 libc 버전이 사용 중인지 찾을 수 있습니다.
우리는 로컬 바이너리를 exploiting 하고 있기 때문에 libc의 어떤 버전이 사용 중인지 알 필요가 없습니다(/lib/x86_64-linux-gnu/libc.so.6
에서 라이브러리를 찾기만 하면 됩니다).
그러나 원격 exploit 경우에는 어떻게 찾을 수 있는지 여기서 설명하겠습니다:
3.1- libc 버전 검색 (1)
다음 웹페이지에서 사용 중인 라이브러리를 검색할 수 있습니다: https://libc.blukat.me/ 이는 발견된 libc 버전을 다운로드할 수 있게 해줍니다
3.2- libc 버전 검색 (2)
또한 다음을 수행할 수 있습니다:
$ git clone https://github.com/niklasb/libc-database.git
$ cd libc-database
$ ./get
이 작업에는 시간이 걸릴 수 있으니 기다려 주세요. 이 작업을 위해 필요한 것은:
Libc 심볼 이름:
puts
누출된 libc 주소:
0x7ff629878690
가장 가능성이 높은 libc를 알 수 있습니다.
우리는 2개의 매치를 얻었습니다 (첫 번째가 작동하지 않으면 두 번째를 시도해보세요). 첫 번째 것을 다운로드하세요:
3.3- 릭을 위한 다른 함수들
libs/libc6_2.23-0ubuntu10_amd64/libc-2.23.so
에서 libc를 우리 작업 디렉토리로 복사합니다.
4- 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 라이브러리의 경로를 제공하면 나머지 exploit은 자동으로 계산될 것입니다.
get_addr
함수 내에서 libc의 베이스 주소가 계산될 것입니다:
최종 libc 기본 주소는 반드시 00으로 끝나야 합니다. 그렇지 않은 경우 잘못된 라이브러리를 노출할 수 있습니다.
그런 다음 system
함수의 주소와 "/bin/sh" 문자열의 주소는 libc의 기본 주소에서 계산되며 주어진 libc 라이브러리를 사용합니다.
마침내, /bin/sh 실행 exploit이 준비되어 전송될 것입니다:
최종 ROP 설명
마지막 ROP(rop1
)은 다시 main 함수를 호출하여 다시 exploit할 수 있습니다(그래서 OFFSET
이 다시 나타납니다). 그런 다음, _"/bin/sh"_의 주소(BINSH
)를 가리키는 POP_RDI
를 호출하고 system 함수(SYSTEM
)를 호출하여 _"/bin/sh"_의 주소가 매개변수로 전달되도록 합니다.
마지막으로 exit 함수의 주소가 호출되어 프로세스가 잘 종료되고 어떤 경고도 발생하지 않습니다.
이렇게 하면 exploit이 _/bin/sh_** 쉘을 실행**합니다.**
4(2)- ONE_GADGET 사용
ONE_GADGET을 사용하여 system 및 "/bin/sh" 대신 쉘을 얻을 수도 있습니다. ONE_GADGET은 libc 라이브러리 내에서 하나의 ROP 주소만 사용하여 쉘을 얻는 방법을 찾아줍니다.
그러나 일반적으로 [rsp+0x30] == NULL
와 같은 제약 조건이 있습니다. RSP 내의 값을 제어할 수 있기 때문에 더 많은 NULL 값을 보내 제약 조건을 피할 수 있습니다.
EXPLOIT FILE
이 취약점을 악용하는 템플릿을 다음에서 찾을 수 있습니다:
pageLeaking libc - template일반적인 문제
MAIN_PLT = elf.symbols['main']를 찾을 수 없음
"main" 심볼이 존재하지 않는 경우. 그럼 main 코드가 어디에 있는지 찾을 수 있습니다:
그리고 주소를 수동으로 설정하십시오:
Puts를 찾을 수 없음
만약 이진 파일이 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
모든 exploit을 생성한 후에 이 에러를 발견한다면: sh: 1: %s%s%s%s%s%s%s%s: not found
"/bin/sh" 주소에서 64바이트를 빼보세요:
Last updated