학습 기록일지

Dreamhack - off_bye_one_000 본문

워게임/포너블

Dreamhack - off_bye_one_000

KRMP 2021. 6. 10. 19:53

드디어 포너블 레벨2로 넘어옴

checksec

checksec 명령어로 확인시 NX bit와 RELRO Partial 보호기법이 걸려있는걸 확인할 수 있음

off_by_one.c

문제의 C언어 소스이다. 2레벨로 넘어오자마자 코드가 길어진 기분이든다. 소스를 분석해보자

Line 7 : 전역 cp_name을 256크기로 설정
Line 9 ~ 12 : 전편과 마찬가지로 쉘에 접근할 수 있는 get_shell 함수 존재
Line 14 ~ 27 : 기본 세팅값. 일정시간이 지나면 연결종료
Line 29 ~ 35 : 함수명 cpy. 내부에서 real_name이란 256크기의 버퍼를 세팅하고, cp_name에 있는 값을 real_name으로 복사한다. 리턴.
Line 36 ~ 47 : 진입하자마자 알람설정. 최대 cp_name 의 크기만큼(256) 값을 입력받아 cp_name에 저장한다. 그다음 cpy 함수로 real_name에 문자열 복사. printf 함수로 입력한 값을 출력해주고 종료된다.


strcpy함수는 null까지 입력받는다는 특징이 있다.
따라서 256바이트를 채워 입력받게되면 마지막에 null이 쓰여져 1바이트 더 쓰이게 된다

 

 

구글링을 해보니 SFP와 베이스포인트는 EBP에 저장된다. 그리고 스택상에 리턴주소 바로 옆에 예전 베이스포인트 주소가 저장되게 된다.

strcpy로 저장해주는 버퍼에 지정된 크기를 넘어가게 되었을때 null이 들어가게 되고 만약 off by one 버퍼 오버플로우가 해당 스택의 바로 아래에서 일어난다면 null바이트의 버퍼를 넣을 수 있다.

 

문제의 흐름과 취약점에 대해 알았으니 본격적으로 문제를 풀어보자

 

 

1) 정상실행

정상 실행

문제를 실행하면 코드에서 봤듯이 256바이트까지 입력이 가능하다.

해당 바이트를 초과하지 않았기때문에 정상적으로 동작하는것을 확인할 수 있다.

x/120wx $esp - 정상실행(gdb)

cpy() 함수의 베이스포인트는 0x0804869e이며, main() 함수의 베이스포인트는 0xf7de8e46이다.

인자를 입력받고 strcpy함수 직전에 브레이크 포인트를 건 후 정상실행 했을 때 스택 모습이다. 

 

2) 비정상

인자를 입력받고 strcpy함수 직전에 브레이크 포인트를 건 후 스택확인
비정상 - 결과

A문자열 256자를 입력받으면 segmentation fault 를 출력한다. (255입력받아도 segmentation fault 출력하는데? null 때문에 꽉채워도 에러나나)

결과를 보면 0x41414141로 이동을 시도한다

이건 main함수쪽 ret전

다시 256바이트를 입력받고 프로그램을 실행시켰을때 별 문제가 없지만 leave를 실행시키고 난 후  cpy의 ebp가 바뀌어있다.

ebp의 위치는 (0xffffd004) 0x41414141로 이동하게끔 되어있어, 입력해준 문자열 중 이동한다는걸 알 수 있다.

따라서 오프셋을 구해서 문자열을 조작하면 되겠다.

 

cpy 함수와 main 함수 두개의 leave > ret 가 존재

 

위 main함수의 ret까지 도착했을때 esp 주소인 0xffffd004 와 real_name 버퍼의 시작주소인 0xffffcfc8 + 8 의 차이를 구하면 0x34 = 54byte 가 된다.

문자열의 52번째 자리에 CCCC를 입력하니 main 의 ret가 돌면서 지정한 값으로 이동을 시도한다.

 

 

-- 수정 --

왜인지 서버에서 안됨. 뭔가 잘못된듯

원래라면 ebp의 마지막 1바이트가 null로 덮여 ebp 변조가 가능하여 eip를 조작하는게 목적이다. 하지만 사용자의 입력 내에 어느 지점으로 ebp변조가 일어나게 될지 알 수 없기때문에 버퍼공간을 모두 리턴주소로 채워주면된다.

 

 

== 코드 ==

from pwn import *

p = remote("host1.dreamhack.games", port)

 

shell = b"\xdb\x85\x04\x08" * 64     #256byte / 4

 

p.send(shell) 

p.interactive()

========

가리키는 랜덤한 주소의 공간에 셸코드로 덮어서 결과적으로 flag를 휙득했다.

 

NOP Sled 를 시도해봤으나 잘 안되는거같다.

 

정리가 진짜 잘되있다 : https://s0ngsari.tistory.com/entry/Offbyone

FPO(Frame Pointer Overflow) : https://hackstoryadmin.tistory.com/entry/FPO-Frame-Pointer-Overflow

 

============================

대응

 

1) strcpy 대신 strncpy 사용

2) strcpy를 사용한다면 마지막 null까지 고려하여 버퍼크기 세팅

 

'워게임 > 포너블' 카테고리의 다른 글

Dreamhack - Sint  (0) 2021.06.17
Dreamhack - out_of_bound  (0) 2021.06.14
Dreamhack - basic_exploition_003  (0) 2021.06.07
Dreamhack - basic_exploitation_001  (0) 2021.05.26
Dreamhack - basic_exploitation_000  (0) 2021.05.20