본문 바로가기

3. Pwnable (포너블)

[2022.11.12] 포시즌 - 포너블팀 활동보고

1. 해커 지망자들이 알아야 할 Buffer Overflow Attack의 기초 By 달고나 문서 정리

p.12~27.

 

프로그램이 시작되면 EIP 레지스터(CPU가 수행할 명령이 있는 레지스터)는 main()함수가 시작되는 코드를 가리키고 있음

여기서 main()함수의 시작점은 0x80482fc임.

 

- EIP : main0 함수의 시작점
- ESP: 스택의 꼭대기
- ebp를 저장하는 이유: 이전에 수행했던 함수의 데이터를 보존하기 위해서
- 함수 프롤로그 과정: 함수가 시작될 때 stack pointer와 base pointer를 새로 지정하는 것

- push %ebp
이 코드를 수행하여 이전 함수의 base pointer를 저장하면 stack pointer는 4바이트 아래인 0xbffffa78을 가리게 됨.
- mov %esp, %ebp
이 코드를 수행하여 ESP 값을 EBP에 복사함.
- sub $0x8, %esp
ESP에서 8을 빼는 명령으로 ESP는 8바이트 아래 지점을 가리키게 되고 스텍에 8바이트의 공간이 생기게 됨.

- and $Oxfffffff0, %esp
ESP와 11111111 11111111 11111111 11110000 과 AND 연산을 함.

- mov $0x0, %eax
EAX 레지스터에 0을 넣음.
- sub %eax, %esp
ESP에 들어 있는 값에서 EAX에 들어 있는 값만큼 뺌

- sub $Ox4, %esp
스텍을 4바이트 확장함. 따라서 ESP에 들어있는 값은 OXbffffa6C 가 됨.

- 다음으로
push $0x03
push $0x02
push $0x01
를 수행함.

이는 function(1,2, 3)을 수행하기 위해 인자값 1,2. 3을 차례로 넣어줌.

 

- callOx8048214
이 명령은 0x80482f4에 있는 명령을 수행하라는 것임. 

 

 

이제 EP는 function() 함수의 시작점을 가리키고 있으며 스택에는 main0 함수에서 넣었던 값이 쌓여있음.
push %ebp 

mov %esp, %ebp
function()함수에서도 마찬가지로 함수 프롤로그가 수행됨.  main()함수에서 사용하던 base pointer가 저장되고 stack pointer를 function()함수의 base pointer로 삼음.

 

- sub $Ox28, %esp
스텍을 40바이트 확장함. buffer1 [15]를 위해서 16바이트가 할당되고 buffer2 [10]을 위해서 16바이트가 할당됨. 그리고 추가로 8바이트의 dummy가 들어가 충 40바이트의 스텍이 확장된 것임.

- leave instruction

함수 프롤로그 작업을 되돌리는 일을 함.

- ret
이 명령을 수행하고 나면 return address는 POP되어 EIP에 저장되고 stack pointer는 1 word 위로 올라감.
- add $0x10, %esp
는 스텍을 16바이트 줄임.

- leave
  ret
를 수행하게 되면 각 레지 스터들의 값은 main()함수 프롤로그 작업을 되돌리고 main()함수 이전으로 돌아가게 됨.

 

 

 

 

2. Dreamhack Wargame 문제풀기

 basic_exploitation_000

1) 소스코드 분석

💡main 함수

  • buf 배열에 0x80만큼 할당(여기서 0x80은 10진수로 128)
  • printf 함수를 통해 buf 배열 주소 반환
  • scanf 함수를 통해 141byte만큼 문자열을 입력 받아 buf 배열에 저장

💡 buf의 크기는 128(0x80)byte가 할당되는데  scanf() 함수로 141byte까지 입력 받을 수 있기 때문에 버퍼 오버플로우(BOF)가 발생할 수 있음

 

💡스택의 기본 구조: Buffer + SFP (4Byte) + RET (4Byte)
buf 의 크기는 128 Byte 이고 SFP 의 크기는 4 Byte 이므로 RET 전까지 바이트 수는 132 바이트라는 것을 알 수 있음.
즉, 132 바이트에 쉘 코드를 채운 후 RET 에 침범하여, buf 주소 값을 넣어주면 buf 로 돌아가서 쉘 코드를 실행시켜서 권한을 탈취할 수 있음.

 

 

 

 

2) shellcode

scanf로 입력받았기 때문에 26바이트 shellcode를 입력함.

 

💡 여기서 일반적으로 사용하는 25바이트 쉘 코드를 사용하지 않는 이유는 scanf 함수에 있음.

scanf 함수의 경우 \x09, \x0a, \x0b, \x0c, \x0d, \x20를 읽지 못하는데 25바이트 쉘 코드에 포함되어 있기 때문임.

 

\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x31\xc9\x31\xd2\xb0\x08\x40\x40\x40\xcd\x80

 

 

 

3) pwntools로 exploit code 작성

 

💡payload 구성
buf~EBP ← shellcode[26] + NOP[106]
RET ← buf_address[4]

 

buf(128) + sfp(4) = 132바이트 에서 shellcode의 26바이트를 빼면 106바이트임.

26바이트 쉘 코드를 작성했으니, 132 - 26 = 106 남은 106 바이트는 아무 문자로 채워 넣음.

RET 전까지 바이트가 채워지면, buf 의 주소 값을 32 비트 리틀엔디안 패킹 방식으로 넣어줌.

 

 

 

 

 

트러블 슈팅

💡이슈 No.1

pwntools 설치 시 pip 설치에 실패하여 팀 활동 시 실습을 마무리 하지 못하였음.

다음시간까지 각자 문제를 풀어보고 풀이방법을 공유하기로 함.

 

💡해결 

아래 명령어로 pip 설치하는 코드 받아오기

sudo wget https://bootstrap.pypa.io/pip/2.7/get-pip.py