[목차]
공격 프로그램 만들때 주로 사용되는 함수
변수의 메모리 위치 확인
gdb 사용법
공격 프로그램 만들때 주로 사용 되는 함수
* sprintf() : 단순한 단어일 경우 이걸 쓰고
* strcpy()/strcat() : BOF 등 입력값이 많을 경우,
변하는 부분과 변하지 않는 부분을 쪼개 스트링 카피에 넣고
스트링 캣으로 붙여 넣는 방식을 사용한다.
*system() 함수
* echo mate | /bin/level7 === (printf mate; cat) | /bin/level7
=> 일반적인 공격 구문 : (echo mate; cat) | /bin/level7
(선수지식 1) (printf mate; cat) | /bin/level7 => 공격 명령 형식
[참고] printf 명령어 (공격코드는 echo를 안쓰고 printf를 쓴다)
# printf mate : 개행문자 없어서 줄바꿈 없이 값을 리턴
# printf "mate\n" : 그래서 보통 항상 개행문자 넣어준다.
# printf mate | /bin/level7 : 이 경우 인자값으로 넘겨야 할때는 동작 안함
# (printf mate; cat) | /bin/level7 : cat을 통해 mate와 enter를 구분해서 넘기게 됨.
범용으로 공격할때는 (printf % ; cat). 내가 줄려는 값하고 enter를 분리해 입력하려고 할 때
쓰고 항상 성공하는 방식. echo는 enter가 자동 포함되어 있어서 문제가 생기는 경우가 많기 때문에 안쓴다.enter 없이 내가 원하는 것만 입력되야 하는데 자동 개행문자가 들어가 있으면 다른 값으로 인식되는 경우가 많기 때문. cat은 enter를 치면 enter를 리턴한다. 내가 원하는 값만 입력할 수 있음! *echo는 개행문자(\n)를 포함하고 있고 printf는 포함 안하고 있다.
/* Header Files */
/* Global Variable */
/* Function */
int binToInt(char *bin)
{
int i=0;
int count=0;
while (bin[count])
i=(i << 1) | (bin[count++] - '0');
return i;
}
/* Main Function */
int main()
{
char *bin="--_--_- --____- ---_-__ --__-_-"; //*=pointer
//char bin[]="--_--_- --____- ---_-__ --__-_-";
int i;
char *ptr=bin;
char dec[32];
char decimal[4];
char cmd[5]={"\n"};
/*(1) Reserve signals */
printf("Reserved signals : %s\n", bin); // bin=address
/*(2) Change binary */
for(i=0; i<strlen(bin); i++) {
// printf("%s\n", ptr); getchar();
if (*ptr == '-') dec[i]='1';
if (*ptr == '_') dec[i]='0';
if (*ptr == ' ') dec[i]='\0';
ptr++;
}
dec[i]='\0'; //string read until null '\0\'
printf("Changed binary : %s %s %s %s\n", &dec[0], &dec[8], &dec[16], &dec[24]);
/*(3) Change decimal */
for(i=0; i<4; i++)
decimal[i]=binToInt(&dec[i*8]);
printf("Changed decimal : %d %d %d %d\n", decimal[0], decimal[1], decimal[2], decimal[3]);
/*(4) Change Hexadecimal*/
printf("Changed hexdecimal: %x %x %x %x\n", decimal[0], decimal[1], decimal[2], decimal[3]);
/*(5) Change ASCII*/
printf("Changed ASCII : %c %c %c %c\n", decimal[0], decimal[1], decimal[2], decimal[3]);
/*(6) Attack Code */
sprintf(cmd, "(printf \"%c%c%c%c\"; cat)|/bin/level7", decimal[0], decimal[1], decimal[2], decimal[3]);
system(cmd);
return 0;
}
변수의 메모리 배치 확인
변수의 메모리 배치를 확인하기 위해서 프로그램을 만들어 보자.
[level9@ftz level9]$ ls -l
합계 12 -rw-r--r-- 1 root root 391 11월 13 2002 hint drwxr-xr-x 2 root level9 4096 2월 24 2002 public_html drwxrwxr-x 2 root level9 4096 1월 16 2009 tmp |
[level9@ftz level9]$ cd tmp
[level9@ftz level9]$ vi distance.c 더미공간 계산 코드
#include <stdio.h>
int main() { char AA; char strAA[1]; char strBB[2]; char strCC[3]; char strDD[5]; char strEE[9]; char strFF[17];
printf("AA's address: 0x%x, sizeof: 0x%x\n", &AA, sizeof(AA)); printf("strAA[1]'s address: 0x%x, sizeof: 0x%x, distance: 0x%x\n", strAA, sizeof(strAA), &AA - strAA); printf("strBB[2]'s address: 0x%x, sizeof: 0x%x, distance: 0x%x\n", strBB, sizeof(strBB), strAA - strBB); printf("strCC[3]'s address: 0x%x, sizeof: 0x%x, distance: 0x%x\n", strCC, sizeof(strCC), strBB - strCC); printf("strDD[5]'s address: 0x%x, sizeof: 0x%x, distance: 0x%x\n", strDD, sizeof(strDD), strCC - strDD); printf(" strEE[9]'s address: 0x%x, sizeof: 0x%x, distance: 0x%x\n", strEE, sizeof(strEE), strDD - strEE); printf("strFF[17]'s address: 0x%x, sizeof: 0x%x, distance: 0x%x\n", strFF, sizeof(strFF), strEE - strFF);
return 0; } |
[예상] 스택의 구조가 아래와 같이 할당되는가?
<-- 낮은주소(0x00000000) 높은주소(0xFFFFFFFF) -->
+------+---------+--------+--------+--------+--------+--------+--+-------+
|......|strFF[17]|strEE[9]|strDD[5]|strCC[3]|strBB[2]|strAA[1]|AA|.......|
+------+---------+--------+--------+--------+--------+--------+--+-------+
주소1 주소2 주소3 주소4 주소5 주소6 주소7
printf
("strAA[1]'s address: 0x%x, sizeof: 0x%x, distance: 0x%x\n", strAA, sizeof(strAA), &AA - strAA);
[level9@ftz tmp]$ gcc -o distance distance.c
[level9@ftz tmp]$ ./distance
AA's address: 0xbfffe2ef, sizeof: 0x1 strAA[1]'s address: 0xbfffe2ee, sizeof: 0x1, distance: 0x1 /* &AA - strAA */ strBB[2]'s address: 0xbfffe2ec, sizeof: 0x2, distance: 0x2 /* strAA - strBB */ strCC[3]'s address: 0xbfffe2d0, sizeof: 0x3, distance: 0x1c /* strBB - strCC */ strDD[5]'s address: 0xbfffe2c0, sizeof: 0x5, distance: 0x10 /* strCC - strDD */ strEE[9]'s address: 0xbfffe2b0, sizeof: 0x9, distance: 0x10(16) /* strDD - strEE */ strFF[17]'s address: 0xbfffe290, sizeof: 0x11, distance: 0x20(32) /* strEE - strFF */ |
====================================================================
메모리주소 변수명 변수의크기 메모리공간
====================================================================
0xbfffe6ee strAA[1] 0x1 (1 bytes) 0x1 (1 bytes) /* &AA - strAA */
0xbfffe6ec strBB[2] 0x2 (2 bytes) 0x2 (2 bytes) /* strAA - strBB */
0xbfffe6d0 strCC[3] 0x3 (3 bytes) 0x1c(28 bytes) /* strBB - strCC */
0xbfffe6c0 strDD[5] 0x5 (5 bytes) 0x10(16 bytes) /* strCC - strDD */
0xbfffe6b0 strEE[9] 0x9 (9 bytes) 0x10(16 bytes) /* strDD - strEE */
0xbfffe690 strFF[17] 0x11(17bytes) 0x20(32 bytes) /* strEE - strFF */
====================================================================
-> 실제 메모리 공간은 2의 배수 형태로 운영체제와 컴파일러마다 최고의 성능을 낼수 있도록 기본 원칙을 어기지 않는 범위 안에서 약간의 변형을 가한다.
(예상)
<-- 낮은주소(0x00000000) 높은주소(0xFFFFFFFF) -->
+------+---------+--------+--------+--------+--------+--------+--+-------+
|......|strFF[17]|strEE[9]|strDD[5]|strCC[3]|strBB[2]|strAA[1]|AA|.......|
+------+---------+--------+--------+--------+--------+--------+--+-------+
주소1 주소2 주소3 주소4 주소5 주소6 주소7
(실제)
+------+---------+--------+--------+--------+---+--------+--------+--+-------+
|......|strFF[17]|strEE[9]|strDD[5]|strCC[3]|25 |strBB[2]|strAA[1]|AA|.......|
+------+---------+--------+--------+--------+---+--------+--------+--+-------+
주소1 주소2 주소3 주소4 주소5 주소6 주소7
gdb 사용법
■ 분석 방법의 종류(분류 기준: 코드를 분석하는 과정)
- 정적분석 : 프로그램을 실행시키지 않고 disassemble한 것으로 분석하는 것.
(전체 윤곽보기 좋지만 메모리상의 변화를 보기엔 좋지 않다.
- 동적분석 : 프로그램을 실행한 상태로 분석하는 것.
버퍼 레지스터 스택에 들어있는 것들을 정확히 볼 수 있다. BOF는 정적분석으 로는 못한다. overflow가 일어나는 것 보지 못하기 때문.
■ 많이 사용되는 gdb command 모음
http://visualgdb.com/gdbreference/commands/
■ gdb 사용법
명령어 |
설명 |
gdb <파일이름> |
지정된 파일을 gdb로 열기 |
list |
gcc 컴파일시 -ggdb 옵션을 지정한 경우 소스 확인 가능 (EX: gcc -g -o test test.c) "set listsize 20"과 같이 한번에 출력할 수 있는 행의 개수를 20으로 늘릴수 있음 (약자) l |
disassemble 주소/함수명 |
지정된 함수를 디스어셈블해 코드를 보여줌 (약자) disas |
run |
현재 프로그램을 실행 "run arg1 arg2"과 같이 인자를 주어 사용 가능 (EX: run helo world) (약자) r |
continue |
브레이크 걸린 상태에서 계속 진행 (약자) c, cont |
break 주소/함수명/라벨 |
주소나 함수에 브레이크 포인터를 걸기, (EX: break *0x8049000) (EX: break func) (EX: break *main+38) info breakpoints 사용하면 break 걸린 정보들을 확인할 수 있다. break <함수명>을 사용하면 함수의 시작 부분에서 프로그램 (약자) b |
x/32x 주소 |
주소에서 32개를 16진수로 출력(x/32s는 문자열) (EX: x/32x 0xbfffed60) 다음은 출력형식에 대한 다양한 예이다. x/4d 주소 : 주소에서 4개를 10진수로 출력 x/4x 주소 : 주소에서 4개를 16진수로 출력 x/4s 주소 : 주소에서 4개를 문자열로 출력 |
info registers |
레지스터(CPU안에 존재하는 저장 장치)의 값을 출력 (약자) i reg info all-registers |
info functions |
현재 디버깅하고 있는 프로그램의 함수 리스트 확인 |
nexti |
함수 내부로 들어가지 않고 한 라인 실행 (약자) ni |
stepi |
함수 내부로 들어가면서 한 라인 실행 (약자) si |
help |
도움말 출력 |
backtrace |
프로그램 실행의 스택 추적 결과 출력 break를 건 후 프로그램을 실행하고 나서 스택의 내용을 볼수 있는 명령어 (약자) bt |
quit |
gdb 종료 <CTRL + D> 키로도 종료가 가능 |
<ENTER> |
마지막 명령어를 다시 수행 |
[출처]
솔데스크 백승찬 강사님
'정보보안공부 > 정보보안전문과정' 카테고리의 다른 글
정보보안 과정 Day 68 : 리버싱 6 (FSB / BOF) (0) | 2020.12.14 |
---|---|
정보보안 과정 Day 67 : 리버싱 5 (공유 메모리) (0) | 2020.12.10 |
정보보안 과정 Day 66 : 의사코드 복원 실습 (0) | 2020.12.09 |
정보보안 과정 Day65 : Reverse Engineering 3 (0) | 2020.12.08 |
정보보안 과정 Day64 : Reverse Engineering 2 (0) | 2020.12.07 |