포너블 스터디에서 과제로 제시된 bof2 문제입니다.

위 소스코드를 분석하고 BOF를 발생시키는 exploit 코드를 작성하여 win함수를 실행시키는 문제 입니다.
먼저 코드를 함수별로 나눠 분석하겠습니다.
1. 소스코드 분석
<main 함수>

main 함수는 vuln( )함수를 실행하고 리턴 0로 종료되는 구문으로 이루어져 있습니다.
그럼 실행 구문이 적힌 vuln( ) 함수 소스를 보겠습니다.
<vuln 함수>

vuln 함수는 문자 타입인 char 타입 buf[0x20] 으로 16진수로 20 만큼의 버퍼를 만들고
input[0x100] 16진수로 100만큼의 버퍼를 선언합니다.
이후 read( ) 함수를 사용해 0부터 0x90를 입력을 받고
strcpy(buf, input) 함수를 통해
input으로 받은 문자를 buf에 복사를 수행합니다.
<setup 함수>
중간에 있는 setup( ) 함수도 소스를 보겠습니다.

setbuf함수는 필요한 크기만큼 할당해서 사용하는 것으로 위의 버퍼를 이용한 선언을 사용했기에 필요한 구문입니다.
<win 함수>
win 함수는 system(“/bin/sh’) 함수를 사용하는데

이는 시스템탈취가 가능한 구문으로 저희가 목표로 하는 함수 입니다.
<정리>
버퍼를 사용하는 소스로써 입력받은 값을 read함수 에서 0x90으로 받기에 0x100버퍼를 가지고 있는
input에서는 BOF가 발생하지 않으며 받은 0x90의 값이 strcpy( )를 통해
buf의 최대 크기인 0x20을 초과하면서
strcpy( )에서 버퍼오버플로우가 일어나게 됩니다.
이후 BOF 가 발생하며 win 함수로 넘어가 system( )함수가 실행되며
쉘과 상호작용을 일으켜 공격자의 의도대로 실행이 가능하게 됩니다.
2. 파일 분석
다음으로 bof2의 파일 분석을 하겠습니다.

bof2의 파일을 보면
ELF 64-bit를 확인하는 것으로 64비트를 사용하고, 마지막 not stripped인 것을 보아 심볼 정보 또한 남아있는 것을 확인할 수 있습니다.
다음으로 main 함수와 vuln 함수, win 함수의 시작주소와 끝주소를 분석하겠습니다.

main의 시작 주소는 0x401166, 끝 주소는 0x40117a

vuln의 시작 주소는 0x4011be, 끝 주소는 0x40122c

win의 시작 주소는 0x40122d 끝 주소는 0x401242
임을 디버그 모드로 확인 했습니다.
여기서 소스코드의 흐름으로 이해해야 하는 것은
0x90 만큼 받은 값을 0x20에 넣는 것으로 BOF를 발생시킨다는 것입니다.

위 그림과 같이 표현이 가능한데 실행시 파란색 부분에 코드를 덮어 쓴다고 볼 수 있습니다.
그러나 우리는 read함수에서 0x90으로 input함수의 0x100을 넘기지 못하기에

더미를 넣는다면 위 그림과 같이 사용하게 됩니다.
그렇다면 이를 동적 분석을 통해서 보겠습니다.

strcpy함수가 실행되는 vuln+103을 들어가 보면

vuln+110 부분이 main+14 부분으로 ret즉 리턴값을 넘겨주면서 넘어가는 흐름을 볼 수 있습니다.
그러니 win함수로 BOF를 이용해 넘어가려면 전달되는 rsp 0x7fffffffdf38부분을 오염시키면 되는 것입니다.
3. exploit 코드 작성해보기
그럼 이러한 이해를 바탕으로 exploit 코드를 작성해 보겠습니다.

위 코드는 bof1의 exploit 코드인데 bof2의 코드를 작성하는데 참고용으로 삼겠습니다.
먼저 맨 2줄은 모듈 불러오기와 pwntools 기능을 사용하는 코드이니 그대로 작성합니다.
from pwn import *
#context.log_level=’debug’
p = process(’./bof1’) 는 공격할 파일을 지정해주는 코드이므로
p = process(’./bof2’)
로 변경하겠습니다.
payload = b’A’*120은 바이트타입 A를 120만큼 더미 값을 추가해주는 구문인데
bof2에서는 input[0x100] read(0, input, 0x90)이 다시 strcpy(buf, input)으로 전달됩니다.
즉, read에서는 BOF가 불가하기에 strcpy에서 buf를 넘는 값을 전달해 BOF를 일으켜야 합니다.
buf의 0x20 = 32바이트를 넘으면서
64비트를 사용하는 파일이므로 8바이트 단위로 끊어주는 값을 사용해야 합니다.
그러므로 아래와 같이 작성하겠습니다
payload = b’A’ * 40
payload += p64(0x4011fe)는 더미 값으로 버퍼오버플로우를 일으키고 난뒤 win 함수를 실행시키기 위해 win 함수의 시작주소로 덮어쓰기를 하는 구문입니다.
또한 p64는 우리가 64비트 파일을 사용하므로 8바이트 형태의 주소로 변환시켜주는 역할을 합니다.
위에 분석으로 win 시작주소를 찾았으니 변경하겠습니다.
payload += p64(0x40122d)
p.sendlineafter(’what\’s your name?:’, payload)는
앞에나온 문자열을 받게되면 payload값을 넘겨주는 것
이전 구문에서 payload에 더미 값을 넣었으므로
우리가 원하는 위치에 더미 값을 넘겨주는 구문이라고 할 수 있습니다.
bof2 소스에서 값을 받는 구문의 위치는
read( )함수의 바로 전 printf문 Do you know read?: 이므로 변경하겠습니다.
p.sendlineafter(’Do you know read?:’, payload)
마지막으로 쉘과 상호작용을 위한 필수 코드를 그대로 작성해주겠습니다.
p.interactive( )
정리하면
from pwn import *
#context.log_level=’debug’
p = process(’./bof2’)
payload = b’A’ * 40
payload += p64(0x40122d)
p.sendlineafter(’Do you know read?:’, payload)
p.interactive( )
코드로 실행해보겠습니다.

쉘 탈취에 성공하여 쉘 명령어인 ls를 사용하여 현 디렉토리의 파일 리스트를 확인이 가능해졌습니다!
BOF에 성공하여 win함수 실행 성공
'Reference > Pwnable_Study' 카테고리의 다른 글
NOP Sled(NOP Slide) (0) | 2022.09.30 |
---|---|
Mprotect - ROP (0) | 2022.09.30 |
FSB(포맷 스트링 버그) fsb2예제 (0) | 2022.07.11 |
32bit와 64bit의 함수 인자전달 방식(FSB) (0) | 2022.07.10 |
bof1 exploit 코드 분석 (0) | 2022.05.23 |