class renaming은 class의 이름를 "Base64Coder"처럼 식별할 수 있는 문자대신, "pabd63bb"와 같이 무슨 의미인지 알 수 없게 바꾸어 준다. 따라서 역공학으로 해당 파일을 보더라도 무슨 역할을 하는 지 알아차리기 힘들어 역공학을 방해한다. [1]
처음에 메소드의 끝을 가리키는 goto가 있고, 메소드 끝에 메소드의 처음을 가리키는 goto가 추가되어 bytecode 흐름이 달라졌다.
백신탐지 비교시
(왼쪽 : 기존앱, 오른쪽 : Goto옵션 적용)
Goto 옵션을 적용한 경우에 백신 탐지가 덜 되는 것을 알 수 있다.
3.2. Reorder
Reorder는 역공학하여 분석하기 어렵도록, 메소드의 명령어 흐름을 복잡하게 한다. 왼쪽의 그림이 Reorder된 app_3의 BandManager.smali이다. [2] 오른쪽의 기존과 method와 다르게 추가된 내용도 생기고 흐름도 goto문이 생기는 등 복잡하게 바뀐 것을 알 수 있다.
왼쪽의 Nop 옵션이 적용된 app_2/smali/c/ca/a.smali 파일을 보면 오른쪽의 기존 파일과 다르게 nop 명령어들이 추가된 것을 알 수 있다.
[그림] "smali/c/ca/a.smali"비교
백신탐지 비교 시
(왼쪽 : 기존앱, 오른쪽 : nop 옵션 적용)
nop 옵션을 적용한 경우에 백신 탐지가 덜 되는 것을 알 수 있다.
3.4.ArithmeticBranch
ArithmetiBranch 옵션은 의미 없는 코드를 삽입하여 명령어 흐름을 복잡하게 만들다. 따라서 역공학시 분석을 하기 어렵게 한다. [2] 왼쪽의 ArithmeticBranch 옵션이 적용된 app_4/smali/com/example/eroplayer/MainActivity을 보면 오른쪽의 기존 파일과 다르게 junk code가 삽입된 것을 알 수 있다.
[그림] “smali/com/example/eroplayer/MainActivity.smali" 비교
백신 탐지 비교 시
ArithmetiBranch 옵션을 적용한 경우에 백신 탐지가 덜 되는 것을 알 수 있다.
일반적인 개발자의 입장에선, 안드로이드 난독화는 역공학을 어렵게하여, 개발자가 만든 소스코드, 파일 등을 보호할 수 있게 해주는 좋은 수단이다.
[1] 난독화에 강인한 안드로이드 앱 버스마킹 기법 김 동 진 , 조 성 제° , 정 영 기* , 우 진 운**, 고 정 욱***, 양 수 미**** Android App Birthmarking Technique Resilient to Code Obfuscation Dongjin Kim , Seong-je Cho° , Youngki Chung* , Jinwoon Woo**, Jeonguk Ko***, Soo-mi Yang****
[2] 안드로이드 어플리케이션 역공학 보호기법 하 동 수*, 이 강 효*, 오 희 국*
[3] Android Code Protection via Obfuscation Techniques: Past, Present and Future Directions Parvez Faruki, Malaviya National Institute of Technology Jaipur, India Hossein Fereidooni, University of Padua, Italy Vijay Laxmi, Malaviya National Institute of Technology Jaipur, India Mauro Conti, University of Padua, Italy Manoj Gaur, Malaviya National Institute of Technology Jaipur, India
[4] APK에 적용된 난독화 기법 역난독화 방안 연구 및 자동화 분석 도구 구현* 이 세 영,† 박 진 형, 박 문 찬, 석 재 혁, 이 동 훈‡ 고려대학교 정보보호대학원
메모리 버퍼의 경계가 있는데 경계와 관련된 연산에 대한 제한, 제약을 적절히 처리하지 못할때 생길 수 있는 약점
어떤 소프트웨어는 메모리 버퍼와 관련된 연산을 할 수 있다.
하지만 그 연산은 버퍼의 의도된 경계 바깥쪽의 영역을 read/wrtie할 수 있음
연산의 제약조건은 버퍼의 의도된 경계내에서 연산해야
버퍼의 경계내의 메모리를 읽고 쓰기 해야됨
어떤 언어는 직접적으로 메모리 위치를 참조하는데 그 위치가 실제로 유효한지 아닌지 확인 하지 않음
프로그램이 참조할 수 있는 유효한 주소인지 체크하지 않아 다른 변수나 자료구조 내부 프로그램 메모리 영역을 읽거나 쓸 수 있음 = >연산 제약을 제대로 처리 하지 않았기 때문에
공격으로 연결되면 임의의 코드를 실행할 수 있고 임의의 제어흐름으로 변조, 민감한 정보 읽기, 시스템이 망가짐
cwe 119 = > 버퍼 오버플로우라고도 함
버퍼 오버플로우는 사람마다 다른 의미로 사용가능
어떤 도구는 버퍼의끝을 넘어서서 write하는것
다른 개발자는 버퍼의 경계밖(버퍼의 시작점, 끝 밖의 공간)에서 읽거나 쓰는것.
또 어떤 사람들은 버퍼의 끝 이후에 어떠한 행동을 하는 것(읽기, 쓰기 가능)
사람마다 다르기때문에 혼란스러운 용어임
따라서 메모리 경계에서 부적절한 연산 제한이 올바른 표현이다.'
이러한 약점의 결과는 CIA가 깨짐
인가되지 않은 코드,명령실행, 메모리 변조 가능
한바이트만 조작할 수 있음
가용성, 기밀성
어떤 메모리를 읽을수 잇고 시스템이 비정상적으로 종료될수 잇음 (dos) cpu같은 자원을 소모(메모리도 가능)
메모리 경계를 넘어서면 메모리의 붕괴를 가져와 시스템이 붕괴됨
해당 프로그램이 공격을 받아서 무한루프상태로 갈수도 있다.
기밀성
read memory
주어진 자료구조 범위를 넘어서서 읽으면 민감한 정보를 읽을 수도 잇다.
메모리의 현재 버퍼의 위치와 같은 정보
어떻게 완화??
소프트웨어 보안은 개발생명 전 주기에서 고려
각 단계에서 취약점을 완화할 숭 ㅣㅆ다
요구사항분석 => 언어선택을 잘 해야. cwe119에 강한 언어를 사용하며 ㄴ좋다, c보단 자바와 같은 언어(자체적으로 메모리 관리를 함) ada나 c#은 오버플로우 보호기법을 적용하고 잇음
그렇지만 이러한 언어들은 binary가 아님 실제 실행시 native코드로 변환 되어야함. 따라서 native code와 상호작용하는 인터페이스는 오버플로우 약점에 취약(자바 가상머신은 c로 만들어져잇음)
언어를 윗단에서 좋은 언어를 사용하더라도 완전하게 해결하는 것은 아님
아키텍쳐및 설계
라이브러리나 프레임워크를 잘 사용
검증이된 라이브러리나 프레임 워크 사용 => safe c String 라이브러리, strsafe.h
string 관련 오버플로우 문제를 해결 => 완벽X
많은 오버플로우는 string고 ㅏ연관 없음, 하지만 string관련 문제를 해결가능
cwe119취약점을 방어할 숭 ㅣㅆ다.
빌드 컴파일 단계
컴파일 할때 최신 컴파일러사용, 컴파일 옵션을 버퍼 오버플로우를 탐지할 수 잇게 사용
MS visual studio 에선 GS flag, Fedora/red hat에선 fortify source gcc flag사용
공격이나 취약점을 조기에 탐지할 숭 ㅣㅆ음
하지만 완변하지 ㄴ않음
구현단계
자신이 작성중인 버퍼가 원하는 대로 작동하는지 두번이상 확인
strcpy -> strncpy
gets->fgets
memcpy보다 안전한 것 사용
안전한 라이브러리 함수 사용
운영단계
운영 환경을 좀더 안전하게 만들어라
관리자는 aslr , position-independent executable (pie)와 같은 기능을 사용해서 특정한 주소를 공격자가 예측하지 못하게 해라
공격자는 버퍼의 주소를 예측하기 어려움
NX비트 활용 (hw기법)
임의의 코드가 스택이나 데이터 세그먼트에 들어갈 확률이 높은데, data execution protection(nx) 를 하면 코드 세그먼트가 아닌 스택이나 데이터 세그먼트 코드는 실행하기 못하게함.기본적으로 프로세스의 메모리 레이아웃에서는 코드, 텍스트 세그먼트의 코드만 실행해야함. 공격자들은 자기가 실행하고 싶은 코드를 스택이나 ㄴ=데이터 세그먼트에 넣음,
jadx로 같은 파일을 확인하면, class의 이름이 Base64Coder에서 pabd63bb로 바뀐 것을 알 수 있다.
class renaming은 class의 이름를 "Base64Coder"처럼 식별할 수 있는 문자대신, "pabd63bb"와 같이 무슨 의미인지 알 수 없게 바꾸어준다. 따라서 역공학으로 해당 파일을 보더라도 무슨 역할을 하는 지 알아차리기 힘들어 역공학을 방해한다. [1]
처음에 메소드의 끝을 가리키는 goto가 있고, 메소드 끝에 메소드의 처음을 가리키는 goto가 추가되었다.
백신탐지 비교
(왼쪽 : 기존앱, 오른쪽 : Goto옵션 적용)
- Reorder
Reorder는 역공학하여 분석하기 어렵도록, 메소드의 명령어 흐름을 복잡하게 한다. 왼쪽의 그림이 Reorder된 app_3의 BandManager.smali이다. [2] 오른쪽의 기존과 method와 다르게 추가된 내용도 생기고 흐름도 goto문이 생기는 등 복잡하게 바뀐 것을 알 수 있다.
왼쪽의 Nop 옵션이 적용된 app_2/smali/c/ca/a.smali 파일을 보면 오른쪽의 기존 파일과 다르게 nop 명령어들이 추가된 것을 알 수 있다.
백신탐지 비교
(왼쪽 : 기존앱, 오른쪽 : nop 옵션 적용)
- ArithmeticBranch
ArithmetiBranch 옵션은 의미 없는 코드를 삽입하여 명령어 흐름을 복잡하게 만들다. 따라서 역공학시 분석을 하기 어렵게 한다. [2] 왼쪽의 ArithmeticBranch 옵션이 적용된 app_4/smali/com/example/eroplayer/MainActivity을 보면 오른쪽의 기존 파일과 다르게 junk code가 삽입된 것을 알 수 있다.
이번 과제를 하면서, 개발자의 자산을 보호하는 것도 중요하지만, 악성코드를 탐지를 위해 난독화를 탐지하는 기술도 중요하다고 느꼈다.
참고논문
[1] 난독화에 강인한 안드로이드 앱 버스마킹 기법 김 동 진 , 조 성 제° , 정 영 기* , 우 진 운**, 고 정 욱***, 양 수 미**** Android App Birthmarking Technique Resilient to Code Obfuscation Dongjin Kim , Seong-je Cho° , Youngki Chung* , Jinwoon Woo**, Jeonguk Ko***, Soo-mi Yang****
[2] 안드로이드 어플리케이션 역공학 보호기법 하 동 수*, 이 강 효*, 오 희 국*
[4] Android Code Protection via Obfuscation Techniques: Past, Present and Future Directions Parvez Faruki, Malaviya National Institute of Technology Jaipur, India Hossein Fereidooni, University of Padua, Italy Vijay Laxmi, Malaviya National Institute of Technology Jaipur, India Mauro Conti, University of Padua, Italy Manoj Gaur, Malaviya National Institute of Technology Jaipur, India
* de-obfuscator : 난독화된 악성코드를 분석시 사용, 난독화를 해제시켜주는 도구
분석 지연
난독화
클래스, 메소드, 변수명 등을 의미 없는 문자나 식별할 수 없는 문자로 치환, 제어흐름 난독화
암호화
문자열, 리소스 등 암호화
코드 분리
핵심 로직이 담긴 코드를 분리하고 실행 중에 동적으로 적재
환경 탐지
디버거 탐지
프로세스 ID 확인, 디버깅 탐지 API 결과 값 반환
에뮬레이터 탐지
단말 ID, 전화번호, 빌드 값, IP 조사
플랫폼 해킹 탐지
OS 해킹 여부 확인
앱 변조 탐지
앱 위변조 여부, 앱 서명 값 확인
코드 난독화 기법 분류
- 레이아웃 난독화
예시) 식별자 난독화 (identifier renaming)
package iAmDriving{
public class LetsNavigate{...}
}
pacakge iAmConnecting {
public class MyBluetoothHandle{...}
}
pacakge userIsActive{
public class MainActivity{...}
}
|
V
package a{
public class a{...}
}
pacakge b {
public class b{...}
}
pacakge c{
public class c{...}
}
Mono Runtime 가상머신에서 사용하는 중간 언어인 CIL이 있는 dll파일들을 디컴파일하였다.
Assembly-CSharp.dll 파일이 C# 개발자 코드의 컴파일 결과이므로 dnSpy 프로그램을 사용하여 Assembly-CSharp.dll을 수정하였다.
먼저 CompleteProject 파일 안의 정보들을 보고 “Player~~~~” 관련 코드가 플레이어와 관련된 코드라 추측을 하였다. 그리고 각각 “Movement”, “Shooting”, “ScoreManager” 코드에서 변수 이름으로 관련 변수들이 의미하는 것을 추측하였다.
그 후 해당 변수에 들어가 있는 값들을 수정해 주었으나, 실제 게임 구동 시 적용이 되질 않았다.
ctrl+shift+R 키를 통하여 해당 변수가 사용되는 함수들을 찾아보고 해당 함수안에서 변수에 곱을 하여 값을 조작하여 Damage, Speed, Score, Heath를 조절하였다.
- Damage 조절
- Speed 조절
- startHealth 조절
- Score 조절
실행 결과
[방어 방법]
이러한 해킹을 막기위해선 ProGuard나 DexGuard와 같은 소스코드 난독화 도구를 사용하여 소스코드를 난독화한다. Renaming(클래스 및 메소드 이름 변경), Control Flow(제어 흐름 변환), String Encryption(문자열 암호화), API Hiding(API 은닉), Class Encryption(파일 내용 전체를 암호화하였다가 동적으로 복호화), Dex Encription(Dalvik Executable 파일 암호화)같은 기법을 사용하여 APK파일을 디컴파일하더라도 코드를 읽기 난해하게하여 공격을 어렵게 만든다.
원본 apk파일의 해쉬값을 서버에 저장하여 설치된 apk의 해쉬값과 비교하여 동일한지 판단하여 유효성을 체크한다.
앱에 서명을 하여 원본 서명과 설치된 앱 간의 서명을 비교하여 위변조한 앱인지 체크한다.
Apk 파일에 META-INF는 apk 배포시 서명한 내용이 들어가는데 파일을 변조할 경우 패키지 손상오류가 뜨며 기기에 설치되지 않는다. apk파일을 리패키징할 때 서명을 해주지 않아 설치가 되지 않는다.
에뮬레이터의 경우 root권한이 설정되어 있어 이를 우회하는 것으로 생각하였으나, root권한을 끈 경우에도 설치가 되는 것으로 보아 에뮬레이터는 앱의 서명을 확인하지 않는 것으로 생각된다.
인터넷 검색을 통하여 앱 서명이 이루어지지않은 앱을 구하여 테스트를 해보았다.
서명을 하지 않은 앱들은 실기기(galaxy note5 Android 7.0)에서 “패키지가 손상된 것 같습니다”라는 에러가 뜨면서 설치가 되지 않는다.
Exploit.c에서 badfile에 buffer를 쓴다. 그리고 stack.c에서 badfile를 열고 str에 읽는다. Badfile의 값이 써진 str을 bof의 인자로 넘겨준다.
Stack.c에서 bof 함수는 인자로 받은 str을 buffer에 복사한다. 하지만 strcpy는 NULL을 만나기 전까지의 문자열을 복사하고 복사할 문자열의 길이는 검사하지 않는다. 따라서 buffer의 크기가 24이고, str의 길이는 517이므로 buffer의 스택을 넘어선다.
이때 bof 함수의 return address에 shellcode의 주소를 넣어 shellcode가 실행되게 한다.
Gdb를 통해 strcpy가 실행되는 곳에 break를 하였고, bof함수를 disas하여 strcpy에 0x20크기의 buffer인자가 전달되는 것을 알 수 있다.
따라서 buffer의 크기는 32byte임을 알 수 있다.
gdb를 통하여 ebp가 0xbfffeab8임을 알 수 있고, ebp의 주소에서 0x20만큼 빼주어 buffer의 시작 위치를 알 수 있다. 그리고 이를 토대로 bof의 return address가 실제와 일치하는지 disas main을 하여 비교를 하면 0x08048574로 같음을 알 수 있다.
Buffer의 크기는 32이고 saved edp for bof의 크기는 4이므로 buffer[36]부터가 return address of bof임을 알 수 있다. Exploit.c에서 “memcpy(buffer+sizeof(buffer)-sizeof(shellcode), shellcode, sizeof(shellcode));”를 하여, buffer의 맨 끝에 shellcode를 넣었다.
따라서 정확한 shellcode의 주소를 몰라도 return address 이후와 buffer 이전의 아무 주소 값이나 return address of bof에 넣어준다면 shellcode는 buffer의 맨 끝에 있으므로 실행이 될 것이다.
시스템이 Little endian이므로
주소값을 반대로 넣어준다. Buffer의 크기는 32byte이고 saved ebp or bof 는 4byte이므로 *(buffer +36)이 return address를 가리키므로, *(buffer +36)부터 차례로 주소를 넣어준다.
이것을 실행하면 원하는 shellcode가 동작하는 것을 볼 수 있다.
[취약점 메모리 구조]
Bof 함수의 strcpy(buffer, str)이 취약점이다. 먼저 bof 함수 인자인 str이 쌓이고 그 다음에 Return Address of bof, Saved ebp of bof, buffer가 쌓인다. Buffer는 32byte이고 saved ebp of bof는 4byte, return address of bof 4byte, str 517bye이다.
Str의 크기가 buffer보다 크고, strcpy는 문자열의 길이를 체크하지 않으므로 str의 값들이 buffer스택 위로 덮어쓰여진다.
- Exploit 실행 후 메모리 구조
Exploit이 실행되면, overflow로 인하여 bof의 return address에 0xbfffeb68(return address 위의 랜덤주소, buffer의 마지막에 shellcode가 있다)이 들어간다.
그리고 NOP 명령어가 실행되다가 buffer의 끝에 있는 shellcode를 실행한다.
[취약점 보완]
프로그래머가 스택의 다른 영역을 침범하지 않게 코드상으로 영역을 명확히 명시하거나 입력 받는 데이터의 크기를 확인하거나 buffer overflow에 취약한 함수를 사용하지 못하게 한다.
Buffer overflow에 취약하지 않은 함수를 사용한다. Strcpy(buffer, str)을 strncpy(buffer, str, sizeof(buffer)-1)함수로 대체 사용하여 복사할 크기를 지정하여 overflow가 생기지 않도록 한다.
Strncpy를 사용하여 복사할 크기를 지정해주었을 때 공격이 실패하고 정상적으로 “Returned Properly”가 수행되는 것을 알 수 있다.
또는 sizeof(buffer)을 BUF_SIZE이나 24로 명확하게 적어준다.
인자로 받는 데이터의 크기를 체크한다. bof함수의 인자로 int size값을 받아 str의 크기를 체크하여 오버플로우를 방지한다. Bof(char*str, int size)의 형태로 받는다.
크기가 buffer보다 클 때 warning을 출력하고 exit한다.
스택 쉴드 기법을 사용하여 함수가 호출될 때 그 함수의 Return Address를 특수 스택에 저장을 하고 함수 종료 시 저장해둔 Return Addresss와 비교를 하여 값이 다르면 프로그램을 종료시킨다.
해제한 ASLR(Address Space Layout Randomize)기법을 다시 사용하여 각 프로세스 안의 스택이 임의의 주소에 위치하도록 한다.
위 property외에 usim 관련, 네트워크 관련 property들은 공통적인 이름을 가지고 있으면서 다른 값을 가지는 것을 확인하였다.
[gsm.sim.state]: [NOT_READY] - LDplayer
[gsm.sim.state]: [LOADED] – s10
[gsm.sim.state]: [LOADED] – s9
[gsm.sim.state]: [READY] – note 3
[gsm.sim.state]: [ABSENT] – Xperia z3 compact
컴퓨터 A
컴퓨터 B
Galaxy Note 3
[dhcp.eth0.gateway]: [172.16.2.2]
[dhcp.eth0.ipaddress]: [172.16.2.15]
[dhcp.eth0.leasetime]: [86400]
[dhcp.eth0.mask]: [255.255.255.0]
[dhcp.eth0.mtu]: []
[dhcp.eth0.pid]: [1735]
[dhcp.eth0.reason]: [REBOOT]
[dhcp.eth0.result]: [failed]
[dhcp.eth0.server]: [172.16.2.2]
[dhcp.eth0.gateway]: [172.16.2.2]
[dhcp.eth0.ipaddress]: [172.16.2.15]
[dhcp.eth0.leasetime]: [86400]
[dhcp.eth0.mask]: [255.255.255.0]
[dhcp.eth0.mtu]: []
[dhcp.eth0.pid]: [1689]
[dhcp.eth0.reason]: [REBOOT]
[dhcp.eth0.result]: [failed]
[dhcp.eth0.server]: [172.16.2.2]
[dhcp.wlan0.gateway]: [192.168.0.1]
[dhcp.wlan0.ipaddress]: [192.168.0.18]
[dhcp.wlan0.leasetime]: [7200]
[dhcp.wlan0.mask]: [255.255.255.0]
[dhcp.wlan0.mtu]: []
[dhcp.wlan0.pid]: [25465]
Real Device는 대부분 무선 인터넷환경(wlan)을 이용하니 이 부분을 확인하면 좀 더 쉽게 emulator를 탐지할 수 있을 거라 생각한다. 그리고 LDplayer의 경우 eth0을 사용하고, 다른 컴퓨터 환경에서도 같은 gateway, ipaddress를 가지는 등 이 정보를 가지고도 판단할 수 있을 거라 생각한다.
하지만 해당 정보들 모두 최신 emulator에서값을 조정할 수 있기 때문에, 완벽한 방법은 아니다.
(adb shell getprop를 하였을 때 수업시간에 배운 selinux가 실제 안드로이드 디바이스에 적용이 되있음을 알 수 있었다.)
- 해당 사건은 마이이더월렛의 DNS 서버를 해킹하여 사용자들이 해커가 만든 가짜 사이트로 접속하였다.
공격과정은 다음과 같다.
해커들은 BGP(Border Gateway Protocol) 메시지를 위조하여 DNS를 하이재킹하였다. 따라서 특정 도메인(마이이더월렛)에 연결되는 IP주소를 다른 주소(가짜 사이트)로 변경시켜 정상적인 사용자들이 마이이더월렛에 접속 요청시 가짜사이트로 연결되었다.
해커들은 ISP업체를 해킹하여 Amazon Cloud 서비스로 가는 IP 트래픽을 가로챈다.
MyEtherWallet.com은 AWS DNS 서버 중Route 53을 사용하고 있었으므로, 해커는 해당 IP 트래픽이 AWS에서 서비스하는 DNS서버가 아닌 가짜 DNS서버로 보내어지게 하였다.
그리고 해커들은 가짜 DNS서버를 해킹하여 피싱사이트로 연결되게 하였다.
정상적인 사용자들은 가짜 DNS 서버에서 제공하는 IP주소로 피싱사이트를 접속하였다. 정상사이트라고 생각한 사용자들은 로그인하기 위해 지갑의 개인키를 입력하여 해커는 다른 사용자들의 지갑 개인키를 획득한다. 획득한 개인키로 지갑안의 암호화폐를 훔친다.
해당 사고 사례는 이웃에 있는 BGP peer들이 보내는 IP prefix정보를 무조건 신뢰하는 BGP프로토콜의 취약점을 이용하였다.
AS 10297을 가진 ISP인 eNet을 해킹하여 AWS에 속한 IP Prefix (205.251.192.0/24 205.251.193.0/24, 205.251.195.0/24, 205.251.197.0/24, 205.251.199.0/24)를 AS 10297에 속한 prefix로 announce하여 eNet의 BGP peer에 해당 IP주소가 왔을 때, 가짜 DNS로 연결하고 피싱사이트로 연결되게 되었다.
BGP, DNS hijacking을 하여 정상적인 DNS 서버인 척 가장하였으므로 Spoofing 공격으로 분류할 수 있다. 그리고 ISP eNet의 AS(Autonomous System)에 속하지 않는 IP Prefix를 속하게 수정하였으므로 Tampering 공격으로도 분류할 수 있을 것이다.
(임시적인 정수승격 : 일반적으로 CPU가 처리하기에 가장 적합한 크기의 정수 자료형은 int형이다. 즉, int형 연산의 속도가 다른 자료형의 연산속도에 비해서 동일하거나 더 빠르다. 따라서, int보다 작은 크기의 정수형 데이터는 int형 데이터로 형 변환이 되어서 연산된다.)
계산이 끝난뒤에 값이 잘리게 된다.
따라서 c1+c2+c3는 70이된다.
char 범위는 -128~127이므로 70이 출력된다.
short s1 = 32000;
short s2 =1500;
s1 = s1 + s2;
printf("%h, %d\n", s1, s1);
changmin@ubuntu:~/Desktop/c$ ./e %, -32036
(%h =>short형으로 출력, invalid conversion specifier -Wformat-invalid-specifier 라고 되는데 %h 형식을 지원하지 않는듯 하다..... short형은 %hd를 사용해야하는 것 같다.)
32000+1500은 short범위를 벗어나므로 오버플로우가 발생한다.
(out-of-bounds write)
배열의 크기를 벗어나거나
memcpy시 마지막 인자가 unsigned int형으로 변환되면서 언더플로우가 발생될 수 있다.
(returnChunckSize(desBuf)의 반환값이 -1일때 -1-1은 -2가 되고 unsigned int로 변환시 언더플로우발생으로 매우 큰수가 된다.)
changmin@ubuntu:~/Documents$ ./test3 1 AAAA the number is:1=4 the buffer is: AAAA�vbV
=> 1 AAAA를 입력하면,
i는 1이되고 i*sizeof(int)는 4가된다.
"�vbV"는 memcpy가 null을 추가하지 않고 복사하기때문에 그런것같다.
----------------------------------------------------------------------------------------- changmin@ubuntu:~/Documents$ ./test3 111 AAAA the number is:111=444 the buffer is: AAAA *** stack smashing detected ***: <unknown> terminated
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char buf[20];
int i = atoi(argv[1]);
//atoi는 아스키를 int로 바꾸어준다.
memcpy (buf, argv[2], i*sizeof(int));
printf("the number is:%d=%d\n",i, i*sizeof(int));
printf("the buffer is: %s\n",buf);
}
(파이썬을 설치하지 않아 A 44번 B 4번을 일일이 입력했다...)
(gdb) r 12 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB Starting program: /home/changmin/Documents/test3gdb 12 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB the number is:12=48 the buffer is: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB *** stack smashing detected ***: <unknown> terminated
Program received signal SIGABRT, Aborted. 0xf7fd5059 in __kernel_vsyscall ()
=> argv[0]에 12, argv[1]에 A*44+B*4를 입력하였다.
=>buf의 크기는 20인데 memcpy에서 12*4(i*sizeof(int))를 하여 48크기만큼 memcpy하려하여 버퍼가 넘치는 버퍼 오버플로우가 발생한다.
이번엔 argv[0]에 -1073741810을 입력하였다.
(gdb) r -1073741810 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /home/changmin/Documents/test3gdb -1073741810 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB the number is:-1073741810=56 the buffer is: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB *** stack smashing detected ***: <unknown> terminated
Program received signal SIGABRT, Aborted. 0xf7fd5059 in __kernel_vsyscall ()
=> -1073741810 * 4 (i*sizeof(int))값이 memcpy의 인자로 들어가는데 usigned int로 바뀌면서 값이 56으로 변환이 된다. 따라서 버퍼의 크기 20을 넘게된다.
* CWE-195의 부호변환 에러
=> readdata함수는 unsigend int형을 반환한다.
=> 함수 안에서 if문을 보면, 조건 만족시 amount에 -1을 넣고 그 값을 반환한다.
=> usigned int 형으로 바뀌어 반환되므로 언더플로우가 발생한다.
=> 이 경우 또한 usigned int형을 반환하는데 amount가 음수값이 된다면 언더플로우가 발생할 것이다.
=> if문에서 numHeaders가 100보다 큰지 체크한다.
=> 하지만 int형이 numHeaders가 INT_MAX보다 큰값이 된다면 오버플로우로 음수가 될 것이다.
=> 따라서 ExitError를 실행하지 않고 malloc을 한다.
=> 하지만 malloc에서 unsigned int형으로 바뀌면서 언더 플로우가 발생된다.
#include <stdio.h>
int main(void){
unsigned int num = 0xffffffff;
printf("num = %u (0x%x)\n", num, num);
printf("num + 1 = 0x%x\n", num + 1);
return 0;
}
/* EOF */
The output of this program looks
like this:
num = 4294967295 (0xffffffff)
num + 1 = 0x0
num은 INT_MAX이다.
%u = unsigned int이므로 num = 4294967295 (0xffffffff)
num+1은 INT_MAX 범위를 벗어나므로 0x 1 0000 0000 => 0x 0000 0000 => 0x0이 된다.
#include <stdio.h>
int main(void) {
int n;
n = 0x7fffffff;
printf(“n = %d (0x%x)\n", n, n);
printf(“n + 1 = %d (0x%x)\n", n + 1 , n + 1);
return 0;
}
/* EOF */
The output of which is:
n = 2147483647 (0x7fffffff)
n + 1 = -2147483648 (0x80000000)
n은 signed int에서 MAX 양수이다.
%d => 2147483647 (0x7fffffff)
n + 1 => 0x8000 0000가 된다. 이진수로 변환하면 1000 0000 000000000000000000000000(2)이므로
2의 보수 표현으로 -2147483648이 된다.
- 더하기/빼기/곱에서도 발생함
#include <limits.h>
unsigned int ui1, ui2 , usum ;
/∗ Initialize ui1 and ui2 ∗/
usum = ui1 + ui2 ;
/* ui1 = 0x7FFFFFF2
ui2 = 0x6FFFAAAA */
0x7FFF FFF2 + 0x6FFF AAAA를 덧셈하면 INT범위를 벗어나 오버플로우 발생
signed int si1, si2, result;
/* initialize si1 and si2 */
result = si1 – si2;
/* si1 = 0xFFFFBEEF
si2 = 0x6ABCCAFE */
0xFFFF BEEF - 0x6ABC CAFE를 하면 음수 - (양수)로 언더플로우가 발생한다.
(0xF = 1111(2) = 15)
signed int si1 , si2 , result;
/∗ Initialize si1 and si2 ∗/
result = si1 * si2 ;
[3]경우 len1 + len2가 값이 커서 오버플로우가 발생하면 if문을 통과하고 밑의 memcpy를 수행한다.
buf1에서 len1크기만큼 mybuf로 복사하므로 버퍼 오버플로우가 발생할 수 있다.
첫번째 memcpy를 통과하더라도 두번째 memcpy에서도 위에서 설명한 것처럼 문제가 발생할 수 있다.
만약 len1이 0x0000 0002이고 len2가 0xffff ffff라면
첫번째 memcpy는 통과하지만 두번째 memcpy에선 len2가 unsigned int로 바뀌면서 큰값이 되어 버퍼 오버플로우가 발생할 수 있다.
* Integer Overflow를 막는 방법 예시
(자바 코드)
int sum(int a, int b) {
int c = a + b;
if (a > 0 && b > 0 && c < 0)
throw new MyOverfowException(a, b);
return c;
}
int prod(int a, int b) {
int c = a * b;
if (a > 0 && b > 0 && c < 0)
throw new MyOverfowException(a, b);
return c;
}
c = a+b 연산을 한 후
a>0, b>0이고 c<0이면 오버플로우가 발생한 경우므로 예외 처리한다.
밑의 곱의 경우도 마찬가지이다.
static void update_value(char op) {
if (op == '+') {
if (value + 1 > value) value ++;
else printf (“too big! \n”);
} else {
if (value - 1 < value) value --;
else printf(“too small! \n”);
}
}
int addOvf(int* result, int a, int b) {
if( a > INT_MAX - b) return -1;
else {
*result = a + b;
return 0;
}
}
-덧셈 연산을 한 후 오버플로우가 발생하는지 체크한다.
if (value + 1 > value)
value ++;
-덧셈 연산전 오버플로우가 발생하는지 확인한다.
a > INT_MAX - b 이면 오버플로우이다.
(max값에서 b를 뺀값보다 a가 크다면 a와 b를 더하면 max값 보다 클것이다.
즉, 현실세계에서 보면 a+b > INT_MAX 이므로, 합이 MAX값을 넘어서 컴퓨터에선 오버플로우가 발생)
(INT_MAX는 limit.h에 선언되어 있다.)
if( a > INT_MAX - b)
return -1;
다른 방법으로 SW개발 전 단계에서 고려하는 것이다.
-요구사항 분석 : 안전한 언어나 안전한 컴파일러를 사용한다.
-설계 : 안전한 라이브러리나 프레임워크를 사용한다(SafeInt or IntegerLib)
-구현 : 사용하는 범수가 범위내에 있는지 확인한다. 최대값과 최소값 범위를 체크한다.
#include <stdio.h> /* ex2.c ʹ loss of precision */
int main(void) {
int m;
short s;
char c;
m = 0xcafe76ef;
s = m;
c = m;
printf("l = 0x%x (%d bits)\n", m, sizeof(m) * 8);
printf("s = 0x%x (%d bits)\n", s, sizeof(s) * 8);
printf("c = 0x%x (%d bits)\n", c, sizeof(c) * 8);
return 0;
}
changmin@ubuntu:~/Desktop/c$ ./aaa l = 0xcafe76ef (32 bits) s = 0x76ef (16 bits) c = 0xffffffef (8 bits)
s는 16bit=2byte만을 표현할 수 있고, 0xcafe 76ef가 4byte=32bit이므로 상단 16bit가 날라가고 0x76ef가 남는다.
0x7 => 0111(2)이므로 최상단 비트가 1이 아니여서 양수이다. 따라서 앞자리는 모두 0이된다. (%x시 32비트로 출력이된다. => 이부분은 아직 잘 이해하지 못하엿다....)
따라서 0x000076ef
c는 8bit=1byte를 표현할 수 있으므로 0xef만 남게된다.
0xe = 14 = 1110(2)로 최상단 비트가 1이므로 음수이다.
0xe는 음수임을 나타내므로 결과 값의 나머지 앞 부분도 음수 표시위해 1, 즉 모두 f가 된다.
Information Technology : 데이터나 정보를 처리하거나 배포하기위해서 컴퓨터 시스템이나 네트워크를 개발하거나 사용하는 기술
SW Engineer 컴퓨터 소프트웨어에 대해서 설계하고 개발하고 테스트, 유지보수하는 일을 함, 이러한 원칙들을 적용함 전체 과정에 참여 => 주로 팀단위 활동 HW 시스템의 구성요소를 알 필요가 있음 => ex) hdd인지 ssd인지 ...등 SW 개발시 필요한 도구를 만듦 큰 규모에 관련된 이슈를 해결할 필요가 있음 => 전체과정을 관여하기 때문에
SW Developer 다양한 유형의 컴퓨터에 소프트웨어를 빌드함 전체 과정중에서 한 부분에서 관여함(주로 구현부분) => 주로 개별활동 완전한 프로그램을 작성 만들어진 도구를 사용(편집기 컴파일러 디버거...등) 제한된 규모에 관여를 함 => 한 부분에 관여하므로
Information System Hardware, Software, Networks, Data, People, Processes의 집합 <-> Information Technoloy : HW, SW, Networks, Data
Data를 가공하면 정보가됨 => 회사의 절차나 정책은 정보를 어떻게 처리, 배포할것인지 관련됨 따라서 데이터와 정보가 중요함
Security?? 위협, 위험, 취약점이 없는 안전한 상태, 공격자가 존재하는 상황에서도 원하는 특성을 만족하는 것.
Interception : 중간에 가로챔(도청)
Interruption : 중간에 막음
Modification : 중간에 데이터를 변조함
Fabrication : 제 3자가 송신자인척 보냄 (위조) => 인증이 필요 => id/pw, 공인인증서, 생채 인증 등..
기밀성 : 권한을 가진 사람만 정보 접근 => 도청 방지 => 비인가적인 읽기 막아야
무결성 : 인가된 사람만 수정가능, 정보의 출발지 확인(위조 방지) => 비인가적인 쓰기 막아야 =>정보의 정확성, 안정성 보장
가용성 : 인가된 사용자는 그 정보에 항상 접근할 수 있음 => DDoS 방지 => 데이터는 정상적인 사용자가 필요로할때 언제든 이용가능해야한다.
=> 공격자가 존재하는 상황에서 C.I.A를 집행함
cia로만 충분하지 않음 => 인증필요
네트워크 보안도 중요 => 네트워크 프로토콜(보안 강화된) 중요, 암호알고리즘
인증되었어도 허가된 행동만 수행하도록 해야함 => 인가 (authorization)
멀티 유저 시스템에서 인가가 필요함(root, suepr user, normal user, guest)
부인방지 You did that => 하지 않았다고 부인하는것을 방지
책임 추적성(Accountability) who, when, where, why, how, what 모든 transcation에 대해 기록하고 제공해야함 행동들이 추적간능해야한다.
Information Security 인가되지 않은 접근, 기록, 수정, 변조, 파괴 등으로부터 정보를 보호 => 허가되지 않은 공격으로부터 정보를 보호 (Destruction : 일부 삭제 or 교체)
Computer Security 적대적인 환경으로부터 컴퓨터 시스템을 보호하는 것 (계획된 사용은 허용, 불법적인 사용을 막음) 컴퓨터 시스템 자신과 컴퓨터 시스템이 저장하거나 접근하는 데이터를 보호하는 것.
컴퓨터 보안과 정보보안의 차이 컴퓨터보안 : 디지털 형태로 된 데이터나 정보에 초점을 두고 보호, 디지털로 된 정보, 시스템, 네트워크 디지털을 다루는 시스템이나 네트워크를 보호하는 것 정보보안 : 아날로그, 디지털 정보를 보호, 디지털로된 정보, 디지털로된 시스템 네트워크뿐만아니라 아날로그로 된 정보까지도 보호대상임
공격, 위협으로부터 보호
공통점 : 컴퓨터 시스템이나 네트워크를 보호,
Software Security 악의적인 공격하에서도 SW기능이 정상적으로 동작하도록 설계,개발, 테스팅하는 개념 취약점을 차단하는것과 다름 => 취약점 : 보안상의 허점 뚫리고 난 후 사후대책을 하는 것은 아님(reacting)안전한 SW를 개발하는 모든 것 보안을 위해서 SW를 설계 구현 테스트하는 과정 Pro-Active, 능동적인 접근 방식 : 미리 예방함 => SW를 구성할때 보안을 내재화(각 개발 단계마다, 만들때부터 보안 고려)
Security engineering과 관련있음 => 모든 과정에 관련, 시스템 설계시 보안 측면에 초점을 둔 엔지니어링의 특별한 분야 보안 요소 : 문제의 요소가 되는 것을 처리하는데 필요한 보안요소들 => 자연적인 재해, 악의적 공격 등
SW에 의해서 유발되는 보안 위험을 이해하고 예방하고 보완하는 것임
Microsoft Security Development Lifecycle 보안에 관련된 설계 결함, 코딩 단계의 결함을 줄이는 것 => 취약점, 해커에 의해서 악용될 수 있는 취약점을 줄이는것 (* 공격자가 방어자보다 유리함, 공격자는 취약한 점 하나만 찾으면 되지만 방어는 모든 취약점을 찾아서 막아야함)=> 취약점을 제거, 제거하지 못한다면 심각도를 줄임-Secure by Default 공격에 문제가 없는 시스템을 만듦
-Secure in Deployment and Communication 배치, 설치, 통신시 안전하게 함
-Secure by Design 설계시부터 보안 고려
남아있는 취약점들의 심각도를 줄임
SDL은 SW 개발 주기에 보안에 관련된 점검과 대책을 추가함 전 과정에서 보안을 고려 + 보안 교육
Software Security != Security Software Software Security => 어떤 sw를 개발/구현 할 때 모든 단계에서 보안을 내재화 Security Software => SW로 개발된 보안 도구, 보안제품/서비스가 sw로 개발됨
Types of Cybersecurity attacks -Phising 범죄자가 희생자를 믿게만들고 범죄를 수행함(주로 링크 클릭) -Pharming 정상사이트를 위조하여 가짜 사이트를 만듦 -중간자 공격 송신자가 보낸 내용을 가로채서 변조함, 네트워크 통신을 조작하여 통신 내용을 도청하거나 조작하는 공격기법 -Drive by download attack 희생자 모르게 어떤 악의적인 프로그램이 설치되게함(동의없이 다운 or 설치) -Malvertising 인터넷 광고로 위장하여 악성코드를 설치함(광고를 보면 악성코드가 설치됨) malware + advertising -Rogue antiviurs 백신 프로그램을 사칭하여 결제를 유도함
정리) What is the difference between information security and computer security?
=> information security : 어떤 형태의 정보든지에 상관없이 관련된것
computer security => 디지털 형태의 정보만 관심을 가짐
What is the difference between software security and security software?
software security => 개발 단계에서부터 보안을 신경써서 소프트웨어를 개발하는것
security software=> 악성코드를 탐지하는 소프트웨어
What is malvertising?
=>광고처럼 보이는 공격
What is rogue software?
=>악성코드가 있는것 처럼 속이고 결제를 요구하는 소프트웨어(가짜백신)
Good Security Standards follow the 90/10 rule 보안 문제의 10%는 기술적으로 해결가능하지만, 90%sms 사용자에게 달려있다. 보안 문제는 모든사람의 책임이라는 의미이다.
암호알고리즘, 프로토콜, 접근제어는 소프트웨어로 구현이됨 따라서 소프트웨어가 만약에 문제가 생기면 보안취약점으로 연결이되어 보안사고를 유발함
데이터 기밀성을 보장하는 법?
암호기법 AES(대칭키), RSA(비대칭키)
강한 접근제어사용 Never access(중요데이터, 관리자가 아닌경우), No read, No view
중요한 데이터가 임의의 장소에서 나타나지 않게 함
데이터 무결성을 보장하는 법?
documenting system activity 로그로 남김
강한 access control no write , no append or reald only
암호학적 해쉬함수 mac, sha-256, md5 => one-way 함수 (역으로 계산 불가) => 해쉬값으로 입력을 찾기 어려움 출력값의 길이는 같음 => 고정된 길이 출력 입력의 미세한 변경이 출력에 큰 변화를 끼침
가용성 보장?
anti-DDoS system Content Delivery Networks(CDNs) -> 컨텐츠를 효율적으로 전달하기 위해서 여러 노드를 가진 네트워크에 데이터를 저장하여 제공함 인터넷 서비스 제공자에 직접연결되어 데이터를 전송하기 때문에 컨텐츠에 대한 병목을 줄일수 있음(분산저장) Scrubbing center (scrub => 불순물 제거) -> 네트워크 트래픽을 분석하여 악의적인 트래픽을 제거
백업 절차를 잘 만듦 데이터 삭제 공격을 막기 위해
Security Threat
회사나 개인의 자산을 임의로 노출시키거나 변조, 손상, 이용할 수 없게 하는 행동이나 방치해 두는 것
보안 위협의 요소
target : 데이터, 정보, sw, hw ... (취약한 자산)
agent :의도를 가지고 위협유발 or 비의도적 위협유발을 하는 사람
event : 타겟의 취약점을 악용하는 행위 (정보 파괴, 변조, 오남용 등) => 악의적, 우연적
취약점 계산 로직의 약점, 코드의 약점, 하드웨어 내의 로직 약점 => 악용시 기밀, 무결, 가용성에 영향을 미침 약점이 발현되면 취약점임
=> 취약점이 제거되면 위협이 없어짐
passive and active attack
Passive attack => interception 시스템 자원에 영향을 주지 않으므로 알아차리기 힘듬 기밀성 깨짐
Active attack => 시스템 자원을 변경시킴 따라서 탐지하기 용이한 편 변조, 조작 => 무결성 가용성 깨짐
Security Threat Model 보안 운영을 계획하고 최적화 하는 방법 => 조직에서 위협들을 방어하기 위한 방법 보안 위협(취약한 자산이 타겟)을 없애기 위해서 목적을 제시하고 방어계획을 설계해야함어떤 위협이 있는지, 취약한 자산은 무엇이 있는지 그 위혐들에 대해서 어떻게 우리가 대응할 것인지 이러한 것들을 전반적으로 생각하여 최적화 시키는 것임 => 위협을 방어하기 위해서 사용할 수 있는 방식이나 수단
위협 멀웨어 => 바이러스, 스파이웨어, 애드워어 제로데이 취약점 => 아직 패치가 나오지 않은 새로 발견된 취약점 DDoS 공격 Phising
보안 위협 구성요소
타겟
agent
event
조직이 균형잡힌 방어기법, 끊임없이 진화하느 ㄴ방어기법을 구축할 수 있게 도와줌
-해커들의 창은 기업 및 기관의 방패보다 항상 빠르게 진화하므로 피해를 최소화하기 위해서 모의훈련으로 대비를 해야한다. => 모의훈련 (공격자처럼 생각 = 예방을 잘 할 수 있고 취약점을 잘 찾을 수 있다.)
주체가 객체를 어떻게 접근(권한)할 수 있는지 정의하는 것이 접근제어이다. (active한 객체가 passive한 객체를 어떤 형태로 접근하는지 통제하는 기능)
Subject ----> Object ^ | Access
Subject : active한 entity 로 객체나 객체안의 데이터에 대한 접근을 요청함 (유저, 그룹, 프로그램, 컴퓨터..)
Object : passive한 entity로 정보를 포함하고 있다. (파일, 디렉토리 메모리, IPC ...)
Access right : operation(read, write, append ....) = Permission
|참고|
파일의 정보는 inode에서 관리함
하나의 파일에는 최소 하나의 inode가 존재하며, 하나의 inode가 여러개 이름이 연결되면 Hard link(바로가기 유사)이다.
active한 inode는 하나의 파일만 연결되어있다.
파일이 많은 경우 디렉토리로 관리한다. => 같은 부류의 파일들을 같은 디렉토리로 구분하고 어떤 사람이 접근할 수 없는 디렉토리를 만들 수 있음.
SetGID
해당 파일의 소유자의 그룹의 권한으로 실행함.
Sticky bit
설정된 디렉토리 밑에 누구나 파일 생성이 가능함.
해당 파일을 이름을 바꾸거나 이동하거나 삭제하는것은 소유자나 root만 설정 가능하다.
Super user
접근 제어에 대한 제약이 없다.
자원에 대한 인가되지 않은 사용을 막는다.
|-------------------------Auditing(기록 남김)-------------------------------| User ---> Authentication function ---> Access Control Function ---> Resource ^ ^ | | 인증 접근 제어 (id/pw , 공인인증서 등)
Access control은 사용자가 본인이라고 가정한다.
인증 과정은 접근제어 앞단에서 필요하다.
Authorization : 주체가 접근제어 정책에 따라 자원에 접근할 수 있는지에 대한 판단
Access : 주체와 객체 사이의 정보의 흐름
Access control이 필요한 이유?
기밀성, 무결성을 지키기 위해서
사용자가 비의도적으로 중요한 시스템 파일을 일거나 변경 하지 못하게 해주거나
사용자가 비의도적으로 중요한 개인 파일에 대한 변경을 막아줌
기밀성 = no read
무결성 = no write
Access Control Requirements
신뢰되는 입력 접근 시스템 앞단에 인증 기법이 필요하다. 인증 기법(사용자 인증)을 통과한 주체만이 접근제어의 대상이 된다.
fine, coarse specifications 지원 coarse => 크기가 큰 단위로 접근제어 수행 (초기 리눅스는 r/w/x) fine => 크기가 작은 단위로 접근제어 수행
least privilege 최소권한 업무를 하는데 필요한 최소권한만을 준다.
일을 하는데 필요한 권한만 가저야한다. Ring구조는 HW적으로 최소권한을 제공해준다.
SetUID 프로그램들을 적게 만들어야한다. SetUID 프로글매이 취약시 문제가 커진다.
Need to know 주체가 일을 하는데 객체에 대한 접근이 필요없다면 권한이 없어야한다. 만약 append를 해야한다면 write권한이 아닌 append 권한만 주어야한다. => fine specification
Separation of duty 중요 업무를 처리하는 절차를 여러 단계들로 나누고, 각 단계를 서로 다른 주체가 자신의 권한으로 책임지게 한다
거짓행위나 오류를 방어하는것이 목적
open and closed policies closed policy : default 접근 허용하지 않고 명시된 접근만 허용한다.명단에 적힌 주체만 허용한다. open policy : default는 접근 허용 단 명시된 접근은 불허(블랙리스트와 유사)
policy combinations and confilct resolution 여러개의 접근 저책이 하나의 자원에 적용될 수 있음. 한 자원에 대한 접근 권한 충돌이 날 수도 있음. 따라서 충돌이 발생되지 않게 해야함.
관리적 정책 보통 super user만이 가능하며, 어떤 주체가 어떤 규칙을 만들거나 삭제, 수정가능한지 명시
dual control 일을 할때 둘 이상의 주체가 동시게 관여해야한다(특히 중요한일)
SOD = 2개 이상의 서로 다른 step에 대해 각각 다른사람이 수행
dual control = 한 step에 대해 2 사람 이상이 관여
BSD에선 root 계정을 가지게 된다면 1. root 비밀번호를 알고 있으며, 2. wheelgroup(GID = 0)이어여 한다.
=> 접근제어는 어떤 주체가 어떤자원, 어떤객체를 접근할 수 있는지 나타낸 것이다.
-> 비인가 사용자의 자원에 대한 접근을 막는다.
-> 적법한 사용자가 비인가된 방법으로 자원에 대해 접근하는 것을 막는다.
Access Control Models
DAC : 임의 접근 제어 owner가 알아서 함. 임의로 권한을 주었다 뺏었다 가능
MAC : 강제 접근 제어 관리자나 super user가 제어 통제한다. (e.g 군대 행정병(ovwner)이 문서를 썻다고 해도 마음대로 하지 못한다.)
RBAC : 역할 기반 접근 제어 역할에 따라 접근 제어 (e.g 사원, 대리, 과장)
DAC
Discerionary Access Control
자원의 소유주가 주체들이 객체에 접근할 수 있는지 임의대로 정한다. 객체의 owner가 객체에 대한 허가를 가진다. => UID 기반으로 접근에 대한 허가, 일반적인 사용자가 접근제어 정책을 조정할 수 있음.
사용자 신원과 객체의 소유권, 권한 위임에 기반하여 접근제어를 강제한다.
DAC는 security(인터넷이 연결되고 악의적 공격에 방어)보다 protection(멀티유저 - 비의도적 문제방어)에 집중
사용자들은 악의적이지 않고 프로세스(악의적인 프로세스가 아님)는 신뢰한다고 가정함.
DAC Model = Access Matrix Mdel = Access control Matrix Model
(* 디렉토리 read = 접근 가능(들어감), execute = 검색 가능)
Access Matrix는 빈공간이 많을 수 잇으므로 리스트 형태나 희소행렬 형태 등으로 나타낸다.
1. Access Control List => ACL : 객체 중심
- 접근 할 수 있는 사람을 지정 \=> 새로운 사람 추가, 권한 위임 다른 사람에게 불가능, 사람 인증해야함
- 장점 : 접근 가능한 객체 집합의 경계가 지정되지 않음. => object가 새로 생기면 이름을 붙이고 권한을 지정해줌.
- 단점 : 웜, 바이러스 백도어, 스택 오버플로우, 큰 ACL을 사용할 경우 overhead가 큼, 분산환경에서 확장하기 어려움( 사진=>그룹의 사용자 수가 적고, permission bit 가 작으면 ACL이 편리
2. Capability List : 주체 중심
- 키를 나누어 키를 가진 사람이 접근 할 수 있게 함 => 새로운 사람 추가는 키를 나누어주면됨, 키를 주면 다른사람에게 권한이 위임됨, 키를 돌려받기 어렵고 복제할 수 있음 - 장점 : 최소 권한 원칙지키기 쉬움 =>주체가 접근할 수 있는 객체들만 나열해서 관리, 확장하기 쉬움(티켓만 확인) => 분산 환경에서 쓰기 좋음(분산환경은 한번만 인증하고 여러 서버에서 접근함) - 단점 : 접근 가능한 객체 집합의 경계가 지정됨. => 통제됨
3. Authorizaion Table - DB에서 많이 씀
4. Protection Domains - 주체 중심으로 봄, 주로 프로세스 - 어떤 프로세스가 어떤 객체를 어떻게 접근할 수 있는지 표현한 집합 - 어떤 프로세스가 어떤 일을 요청할때마다 관리해야할 정보의 양을 줄일 수 있음 => 상속을 하므로 (fork - 부모가 연 파일을 자식이 상속받아 사용가능) - 역할 기반으로 protection domain 사용 가능 - 어떤 프로세스가 접근할 수 있는 자원들의 집합 - access matrix에선 하나의 행이 protection domain을 정의함 - capability와 연결되면 protection domain 개념과 가까움(ACL보다 capability가 protection domain 개념에 가까움) - 사용자는 프로세스를 생성 하는데, 새 프로세스는 사용자가 갖는 권한의 부분집합을 가지게 됨, 하나의 protectino domain이 생김 => 어떤 프로세스가 접근할 수 있는 자원들의 집합이기 때문에 - 프로세스가 사용자 모드일 경우 => 일반 명령어(자원 제한) - 프로세스가 특권 모드 => 특권 명령어(자원 제한 x)
5. Extended ACL - user/group/others 에 named user와 named group을 도입 - named user와 group을 통제하기 위해 mask entry가 필요하다. - mask entry : named user, group이 가질 수 있는 최대 permission - 새로운 명령어들을 지원함. - getfacl : 확장된 ACL 정보를 가져온다. - setfacl : named user, group에 대한 ACL을 수정하거나 추가 => permission 추가 - chacl : change acl of file or directory
- 임의의 수 naemd user, group이 하나의 파일과 연결될 수 있음. 따라서 추가적인 protection bit가 사용됨 => 세분화 시켜서 특정인에게 named user라는 권한을 주고, group이 아닌 일반 특정인한테 특정 permission을 줌
- 다양한 class => named user, group 추가됨
- ACE => user나 group을 위해서 permission을 정의하는 entry들의 집합
- ACL Caching을 하여 속도를 높이기도 함
- 접근 체크 1. 객체 중심으로 체크 => 소유주 인가? named user인가? 그룹인가? others인가? 체크 2. 그 후 권한 할당
* 장점
사용자/소유주가 스스로 접근 권한을 설정할 수 있어서 시스템 관리자의 부담이 작음
개별 사용자의 접근제어, 그룹 단위의 접근 제어도 제공한다.
권한 변경 쉬움 => chmod, setfacl, chacl
새로운 권한 설정도 쉬움
단점
소유주가 파일에 대해 전체적인 권한을 가짐 => 사용자를 절대적으로 신뢰
사용자가 실행시킨 프로세스는 사용자의 권한을 가진다. (기본적으로 사용자의 EUID로 실행한다.)
만약 사용자가 실행시킨 프로세스가 악성코드에 감염이 되어있으면 문제가 생긴다. 따라서 권한을 분리해야한다.
SetUID root 프로그램이 취약점이 있으면 문제가 생긴다.
12개의 bit로 permission 관리시 문제가 있을 수 있다. 따라서 세분화 해야함.
전역적인 접근제어 정책이 있다면, 그 전역적인 접근제어 정책에 대해서 일관성을 유지하는 것이 어렵다. => 병원 에서 환자리스트를 주치의만 접근가능하게 했지만, 다른 의사에게 위임이 가능하다. 따라서 전역적인 접근제어 정책 유지가 어렵다.
정보가 한 객체로부터 다른 객체로 임의로 복사 할 수 있다. =>원본객체 소유자가 자신이 소유한 객체에 대해서 복제되지 않는 것을 원하지만, 소유자의 동의없이 임의로 복제가 발생할 수있다.
정보흐름 정채긍ㄹ 정확하게 원하는 방향대로 집행하는데 적합하지 않다.
주로 군에서 문제가 발생한다.
========================================================================= 만약 파일 A => a가 소유하고 b가 읽을 수 있음 파일 B => b가 쓸 수 있고, c가 읽을 수 있음 => a는 c가 파일 A를 읽지 못하게 함. 이러한 상황일때 b가 나쁜맘을 먹고 파일 A를 읽고 파일 B에 쓸 수있다. 그러면 c는 A의 내용을 읽을 수 있게 된다.
파일 A => a가 소유하고 b가 읽을 수 있음 파일 B => b가 쓸 수 있고, c가 읽을 수 있음 트로이 목마 => b가 실행할 수 있다. c가 r/w/x 가능
b가 나쁜맘을 먹지 않아도, c가 트로이 목마를 만들어 b에게 주면 b가 자신의 권한으로 트로이 목마르 실행하게 되고 A의 내용을 읽어서 B에 쓰도록 트로이 목마가 작동하면 c가 내용을 알 수 있다.
이전 return to libc 공격에서는 System함수와 exit함수를 사용하였다. 하지만 System 함수가 라이브러리에 없을 경우에는 어떻게 공격을 하는가? 요즘 시스템들은 취약한 함수들을 제거하기 시작했다. 따라서 code chunk들을 연결하여 원하는 동작을 수행 할 수 있도록 잘 엮어서 공격을 할 수 있다.
Chanining Function Calls (WITHOUT ARGUMENT)
(함수 인자가 없는 경우를 다루겠다. 인자가 있는 경우는 너무 복잡하다.)
아래의 그림과 같이 함수들을 배치해주면 된다.
그러면 어떻게 원하는 동작을 하도록 하게 할까?
return to libc 공격에서는 공격자가 system함수가 수행되길 원한다. 하지만 위험한 함수들은 제거되므로 code chunk를 엮어서 사용하여야 한다.
위 그림과 같이 원하는 글자를 가져와 조합하면 원하는 문장을 만들 수 있다. 이와 같이, 이미 존재하는 코드 조각들을 맞추면 즉, 이미 있는 명령어들의 조각을 찾아서 조합하면 system이나 execve과 같이 구성을 할 수 있다.
따라서
- 코드 주입이 필요없다.
- libc 함수를 호출할 필요가 없다.
- 원래코드를 수정할 필요가 없다.
먼저 명령어들의 조각들을 조합하여 합치기전 instruction sequences와 gadget을 알아야한다.
- intstruction sequences는 작은 명령들의 순차이다. 명령어 순차는 2~5개의 명령으로 구성되어 있다.
- instruction sequences는 반드시 return으로 끝나야한다.
- gadget은 순차들을 체인으로 연결한 것이다.
- 하나의 gadget은 특정한 업무를 수행한다. ( load, store, xor, branch와 같은)
이러한 가젯들을 연결하여 원하는 행동을 할 수 있다. 그리고 또한 ROP역시 Code Reuse Attack이다.
valid한 명령어의 중간 부분에 있는 주소로 점프하게 만들면 의도하지 않은 명령어 순차가 실행되게 된다.
의도되지 않은 명령 순차들이 x86 아키텍쳐에서 가능한 이유는
명령어는 가변이다. (CISC)
unaligned memory access
N으로 나누어 떨어 지지 않고 임의의 주소로부터 읽기가 가능하다.
e.g)
b8, 13, 00, 00, 00 중 아무곳부터 읽기가 가능하다.
위의 그림을 보면 mov와 jmp 명령어가 다음과 같은 Byte values를 가지는 것을 알 수 있다. 하지만 여기서 정상적으로 b8부터 읽는 대신에 첫번째 00으로 점프하게 하거나, return을 00으로 한다면 [b8 13] , [00 00], [00 e9]와 같이 되며, add %al, (%eax)와 같이 다른 명령어가 된다.
처음 의도한 move, jump 명령어가 add, add, return으로 바뀌게 된다.
Gadget 예시
0x8010ABCD 주소안의 0xDEADBEEF를 eax 레지스터에 로드하려고 할때.
먼저 가젯을 구성하고, 버퍼 오버플로우를 일으킨뒤 Sequence 1을 가르켜 실행되게 한다.
위와 같이 payload를 구성해야한다. 패턴1(버퍼) + 패턴2(saved Ebp) + ret_addr_1 + "\x8D\xAB\x10\x80" + ret_addr_2
리틀 엔디안이므로 주소를 반대로 적고 movl 64(%eax), %eax이므로
eax 주소에서 64만큼 더해서 그곳에 있는 값을 eax로 가져오므로
원하는 DEADBEEF가 있는 주소 0x8010ABCD 에서 64만큼 뺀 주소를 넣어야한다.
순차적으로 실행이 되며 최종적으로 eax레지스터에 DEADBEEF가 들어가게 된다.
ROP 공격은 NX bit(Non executable stack)을 우회할 수 있다.
하지만 이러한 공격을 하기위해 프로그램 언어와 컴퓨터 구조, 함수 동작원리 등을 이해하고 있어야한다.
이러한 공격을 막기위해선, 가젯 Free Code를 사용하여 가젯 구성을 막아 공격을 막을 수 있다.
control flow 프로그램이 여러개의 문장 또는 명령어로 되어있는데, 프로그램에 있는 문장, 명령어, 함수 호출들이 실행되는 순서를 의미한다.
Control Hijacking Attacks 프로그램의 에러를 활용한다. 메모리조작 취약점을 사용한다.(메모리를 깨뜨리는 취약점) runtime때 의도된 제어프름을 덮어쓴다.
control Hijacking Attacks = Control-flow hijacking attacks control flow을 바꾼다. code pointer의 위치가 바뀌어진다. => PC(program counter)에 영향을 주는 값이 code pointer이다. 따라서 다음에 실행될 명령어가 달라진다. 접근하지 못하는 메모리 영역을 바꾼다. => 변조되지 않아야할 영역까지도 달라질 수 있다.
주로
code injection attack
code reuser attack 이 있다.
Control Flow Graphs
프로그램들은 basic block들로 구성되어 있다. CFG는 basic block들이 어떤 순서대로 흘러가는지 보여준다.
basic block 프로그램의 일부로, 실행되는 코드영역이다. 차례차례 실행되는 프로그램 영역이다.
하나의 진입점이 있으면 진출점도 하나밖에 없다.
basic block 안에서는 모든 명령들이 순차적으로 실행된다.
control flow graph 방향이 있으며 노드는 basic block을 가리키고 엣지는 control flow path를 가리킨다.
Code Injection Attack & Code Reuse Attack
Code injection attack 일반적인 방식
공격자는 새로운 basic block을 추가하고 취약한 노드의 제어흐름을 조작한다.
Code reuse attack 일반적인 방식
공격자가 새로 추가하는 노드는 없다. 노드의 취약점으로 본래의 다른 노드로 가게 흐름을 바꾼다.
Code Injection Attack
control hijacking 중 하나이며 흐름이 주입된 코드로 덮여쓰여진다.
일반적으로 shell code를 주입한다.
shell code는 주로 버퍼에 저장되며 제어 흐름을 shell로 이동시켜주는 역할을 한다.(새로운 shell이 만들어짐)
shell code는 기계어로써, 프로세서와 운영체제에 따라 다르게 작성되어야한다.
Code Reuse Attack
원래 프로그램 코드를 의도하지 않은 방향으로 조작한다.
일반적으로 실행가능한 코드는 code segment와 library에 존재한다.
예시로 Ret2Libc, Rop, Jop가 있다.
Return-to-libc Attacks
Non executable Stack 우회 가능
const char code는 전역변수이다. 전역변수는 Data segment에 위치한다.
((void(*)()))buffer)()로 함수포인터로 cast한다.
지역변수 buffer의 주소로 함수를 호출한다.
buffer가 지역변수이기 때문에 실행되진 않는다.(non executable stack)
하지만 code를 직접실행하면 된다.
** 함수포인터?
어떻게 non executable stack을 우회할 것인가?
libc => c는 common으로 모든 프로그램에 연결되는 공통 라이브러리를 뜻한다.
libc 안의 "system" 함수의 취약점을 사용한다.
system함수는 인자로 들어오는 명령어들을 실행해준다.
return address를 system함수가 있는 위치로 가게하고 인자로 원하는 명령어를 준다면 공격이 성공할 것이다.
그림의 경우 버퍼의 크기는 100바이트 이다.
정상적이라면 왼쪽 그림과 같은 상황인데, 여기서 버퍼를 넘치게하여 리턴 주소와 함수 인자를 조작하여야한다.
일반적으로 함수가 호출될때 리턴 주소위에 인자가 있다.
따라서 이점을 이용한다면 system함수를 호출하고 인자로 원하는 명령어를 넣을 수 있다.
1. return address에 system의 주소를 가리키게한다.
2. saved ebp는 아무값이나 주어도된다.
3. system함수의 인자로 /bin/sh의 주소를 준다. => /bin/sh이 있는 환경변수의 위치가 주소일것이다.
4. crash가 나지 않게하기위해 exit를 넣어준다. => 왜냐하면 인자 밑이 리턴주소인데, system 함수 인자인 /bin/sh의 주소 밑이 return address가 되므로 exit가 return address가 된다.
일종의 system 이라는 것이 call 되는 것이고, 시스템 함수가 call 되면 arg가 쌓이고 return address가 쌓인다.
따라서 exit가 return address가 된다.
-------------------
| arg = bin/sh |
-------------------
| ret = exit |
-------------------
| addr(system) |
-------------------
따라서 여기서 버퍼의 크기는 80바이트이다. 공격을 위해선 saved ebp, ret(addr(system)), exit, addr(shellcode) 4가지가 필요하므로
32bit 컴퓨터라 가정시 버퍼에 총 96바이트가 들어가야한다.
따라서 원래 버퍼에 80바이트 만큼 A를 넣어준다. 그리고 saved ebp에 4바이트의 B를 넣고, system이 있는 곳 0x40058ae0을, 위의 예시에선 exit를 넣어주지 않고 아무값이나 넣었다. addr(shellcode) = system함수의 인자에는 /bin/sh이 있는 곳 환경변수의 주소를 넣었다.
하지만 일반 유저들이 그들의 비밀번호를 바꿀때 어떻게 바꿀 수 있을까? 특권 프로그램을 이용해서 바꾼다
일반적으로 운영체제 내에서 세부적으로 접근 제어를 하는 것은 굉장히 복잡하다. rwx 3가지 권한을 세부적으로 할 경우 write를 1. 앞에 2. 중간에 3. 뒤에 와 같이 3가지로 나눌 수 있다. 하지만 복잡해진다.
따라서 rwx + 3bits 총 12비트로 permission을 나타낸다. (확장, fine-grained access control을 위해 3bits를 추가한다.)
일반적으로 OS가 제공하는 접근제어를 바로 사용가능하지만 (e.g system call) 특별한 경우(e.g root가 가진 파일 수정)는 특권 프로그램이 필요하다! => setUID가 설정된 프로그램이 필요하다! 혹은 daemons (관리자(super user)를 믿는다고 가정한다. 일반 사용자들은 특권 프로그램을 이용해서 바꿀 수 있다)
Different Type of Privileged Programs
Daemons in Linux (MS Windows 에서는 services) 백그라운드에서 계속 수행된다. 따라서 키보드로 부터 입력을 받을 수 없다. root나 특권을 가진 유저의 권한으로 실행해야한다.
만약 daemon에게 요청을 하고 요청이 타당하면 daemon이 수행한다. (특히 Network는 Service를 위해 daemon들을 많이 사용한다. ps - af, ef, af 등을 통하여 모든 프로세스들을 보면 d로 끝나는 것들이 있다. Network daemon을 뜻한다. => 중요한 일을 하므로 root의 권한을 주던지 어떤 특권이 있는 사용자의 권한으로 돌아간다. 중요한 일을 하므로 daemon을 임의로 만들지 못한다.
Set-UID Programs Unix 시스템에서 사용된다. 특정한 비트가 표시되어있는 프로그램이다.
Set-UID Concept
superman story
Power suit 1.0 Super man은 자신의 모든 권한을 superpeople 준다. 문제점 : superpeople중 나쁜 사람이 있을 수 있다.
Power Suit 2.0 주어진 일만 가능하게 한다. 특정한 일을 위한 컴퓨터 칩을 같이 내장한다. => chip에서 시킨 일만 함 미리 프로그래밍이 되어 있어 프로그래밍된 일만 한다.
일반 프로그램이 실행되었을때 RUID와 EUID는 같지만, setUID 가 실행되었을때는 다르다.
mycat의 owner를 root로 변경하였다.
mycat으로 /etc/shadow를 보려하면 권한이 없는 것을 볼 수 있다.
chmod로 "4"775로 setUID를 설정하였다. (setUID bit 설정)
그러자 /etc/shadow를 볼 수 있다.
setUID bit를 설정하였을 때, euid가 root가 됨을 알 수 있다.
exec전에는 RUID=EUID=25
exec을 하면서 owner가 17이고 setUID가 설정된 program을 실행함.
그러면 EUID가 17로 변경이 됨
i=getruid => ruid를 가져와서
setuidI(i) => euid를 이전의 상태로 돌림
Unix setuid그림을 보면
setuid bit가 0, 1일때 각각 euid를 보면 201, 100인 것을 볼 수있다.
pid1 = 모든 사용자 프로세스의 조상 (처음에 만들어지고 1번으로 계속 남아있음)
pid 523 ruid 0 euid 0 => pid 523 ruid 42 euid 42
setgroups, setgid, setuid를 실행하면 변경됨을 알 수 있다.
다시한번 예시를 보면
setUID bit를 설정해주면 일시적 권한 상승으로 소유자 권한으로 실행되는 것을 볼 수 있다.
setUID 보안?
일반 유저들에게 권한을 상승시켜준다.
슈퍼맨의 컴퓨터 칩처럼 행동이 제한되어있다.
setUID 내 포함된 행위만 가능하다
sudo command와 달리 직접 권한을 주는것은 아니다. (sudo => 1. root의 pw 아는 경우
2. 다른 user(권한이 있는) pw 아는 경우
3. /etc/shadow file에 사용자가 등록되어 있는 경우
)
만약 superman이 "북쪽으로 가서 왼쪽으로 틀고 성벽을 부셔라"라는 명령을 할때, 만약 명령을 받는 Mallory가 지구 반대편에 있고, 성벽의 반대쪽에 은행이 있다고 할 경우, Mallory의 기준에서 북쪽으로 가서 왼쪽으로 틀면 은행이 나올것이다. 그러면 Mallory는 은행을 털 수 있다. 따라서 chip안의 SW구현도 중요하다!
Attack Surfave of Set-UID Programs
사용자의 입력으로 부터
사용자가 제어할 수 있는 시스템 입력을 통해서
환경변수
사용자에 의해 제어되는 비특권 프로세스 이용
1. 사용자의 입력
버퍼 오버플로우
Format String Vulerability ( string형태로 유저입력을 받았을 때 프로그램을 바꿈)
chsh 명령어
default shell을 바꾸는 명령(setUID 프로그램이다)
shell 프로그램은 /etc/passwd 파일의 마지막 filed에 표시되어 있음.
입력값은 두개의 줄을 포함할 수 있다. 따라서 첫번재 라인은 정상적이고 두번째 라인에 root 계정을 만들도록 할 수 있다.
혹은 만약 공격자가 3, 4번째 필드(UID, GID)에 0을 넣는다면 root 계정을 만들 수 잇다.
시스템 inputs (사용자가 통제 가능한 시스템 input을 통해서도 setUID 프로그램 공격이 가능하다.) 경쟁 조건
2. 환경변수
환경 변수를 사용해서 setUID 프로그램 공격이 가능하다.
환경 변수는 printenv나 env명령어를 통해 확인 가능하다.
등호 앞에 있는 것이 환경변수이고 오른쪽이 환경변수에 들어있는 값이다. (PWD = /home/scho)
일반적으로 파일의 경로를 지정할때 절대 경로나 상대 경로를 지정할 수 있다. 모든 명령들은 어떠한 폴더 아래에 존재한다.
system("/bin/sh") => 값을 입력받아 명령을 수행함을 알 수 있다. system(ls)를 할 경우 운영체제가 알아서 경로를 찾아서 ls를 실행한다. 이때 환경변수를 사용하여 알아서 경로를 찾음 echo path를 하면 :로 경로가 구분되어있고 처음 경로부터 해당 경로에 파일이 있는지 찾는다. path라는 환경변수에 등록된 경로들 순서대로 명령을 찾는다.
cd /home/attacker vi attack.c gcc -o ls attack.c export PATH=/home/attacker/:$PATH:/home/user1/bin
이러한 상황에서 공격자가 home 밑의 attack 파일을 만든다. 그리고 실행파일을 ls로 하고 환경변수를 바꾼다. 그러면 ls를 명령으로 입력하였을때 /bin/ls가 아닌 /home/attacker/ls가 실행된다.
Capability Leaking
자격 유출 어떤 특권 프로그램은 실행 중에 자기 자신의 권한을 다운그레이드한다. 대표적으로 su라는 명령어는 switch user로 사용자를 바꾸는 명령어다. setUID프로그램이다.
예시로 user1에서 user2로 바꿀때, EUID는 root이고 RUID는 user1이다. 그리고 비밀번호가 확인되었을때 RUID와 EUID는 동일하다. 그리고 EUID는 root에서 user2로 내려간다.
<set UID 프로그램의 소스>
/etc/zzz의 owner는 root이고 root만 writable하다.
fd 0은 표준입력 , 1은 표준 출력, 2는 표준에러이고 프로세스가 생성되자마자 default로 open된다.
따라서 open성공시 fd는 3이된다.
setuid(getuid()) => real uid를 가져와서 euid로 설정한다. (실행하는 사람은 root가 아님)
새로운 shell을 실행한다. 그 프로세스는 이전에 open된 파일을 그래도 상속한다. (fd 0, 1, 2, 3)
cap_leak을 owner를 root로 하고 setUID bit를 설정한다.
/etc/zzz에 쓰기를 할 수없다.
하지만 cap_leak을 실행하면 파일의 owner인 root의 권한으로 상승되고, fd를 상속받았으므로 fd 3이 open된 /etc/zzz이고 그곳에 ccccccccccc가 적혀진다.
그리고 새로운 쉘을 빠져나오면 ccccccccccccccc가 쓰여진 것을 알 수 있다.
높은 권한을 가진 EUID가 중요한 파일을 open한 상태로 새로운 shell이 상속받아 문제가 발생하였다.
getuid : real user ID
geteuid : effective user ID
setuid : set effecitive user ID
3. Invoking Programs
하나의 프로그램 내에서 외부 명령어 수행
외부 명령어가 setUID 내에서 실행된다면 안전하지 않거나 엉뚱한 결과를 보여줌
공격 : 사용자는 명령에 대한 입력 데이터를 줌, 명령이 제대로 호줄 되지 않으면 유저 입력 데이터는 명령어 이름으로 될 수 있음.
system은 외부 명령어를 호출하는 함수이다.
root소유 setUID프로그램이다. 따라서 프로그램은 모든 파일을 볼 수 있지만 쓰기는 하지 못한다.
실행권한이 마지막 r-x이므로 누구나 실행이 가능하다.
';'은 shell에 두개 이상의 명령어를 줄 수 있게 한다. 예시) ls;ps ls;cp a b
(root가 owner인 setUId프로그램이기 때문에 shell이 뜰때 root shell이 뜬다. => $가 아니라 #)