왜 소프트웨어 보안이 중요한가?
모든 정보 보안은 소프트웨어로 구현되기 때문이다. 소프트웨어 자체가 가지고 있는 결함이 공격을 받게 되면 결국에는 그 보안 체계는 무너지게 된다. 아무리 암호화 체계가 강하고 엑세스 컨트롤이 강하고 프로토콜이 정도에 관계없이 일단 소프트 자체가 공격을 받게 되면 보안이 무너질 수 있는 그런 단점이 있다. 소프트웨어 자체는 보안에 대해서는 열악한 기반을 제공한다.
나쁜 소프트웨어의 예
- 나사 화성 착륙선 : 화성에서 추락했다. 영어 변환과 측정 단위 변환 오류때문에 문제가 발생했따.
- 덴버 공항 사태 : 수화물 처리 시스템 소프트웨에 오류가 있어가지고 11개월 동안 개항이 연기되었다.
- 군용 항공기 : 소프트웨어 결함으로 인해 추락
일반 사용자와 공격자의 소프트웨어 결함에 대한 입장 차이
- 일반 사용자 : 우연히 버그와 결함을 찾고, 문제가 있는 소프트웨어를 싫어함.
- 공격자 : 능동적으로 버그와 결함을 찾고 문제가 있는 소프트를 좋아함.
Complexity
코드의 복잡도는 LOC(Lines of Code)로 평가한다.
- 군용 소프트웨어나 비행기 소프트웨어 같은 미션 크리티컬 소프트웨어들은 결함이 발생하면 재앙이 일어날 수도 있기 때문에, 복잡도를 최소화하기 위해 코드 수를 단순하고 적게 만든다.
- 1000개의 LOC당 5개의 버그가 있다고 본다. 일반적인 컴퓨터에는 3천개의 실행파일이 존재하고, 한 실행파일당 만개의 LOC가 존재한다.
- 즉 한 개의 실행파일당 50개의 버그가 존재한다. 계산하면 한 컴퓨터당 3000 * 50 = 15만개의 버그가 존재한다.
- 네트워크 상 3만개의 노드가 연결되어 있는 경우, 4.5빌리언의 버그가 존재한다. 이중 10%가 보안적으로 크리티컬하고, 그 중 10%만 원격으로 조종할 수 있다면 45밀리언의 크리티컬한 보안적 결함이 존재한다고 추측할 수 있다.
Software flows
소프트웨어 플로우는 크게 두가지 타입으로 나눌 수 있다.
Program flaws (unintentional)
악의적인게 아니라 선한 의도로 디자인 되었지만 결함을 가지고 있는 경우.
- 버퍼 오버 플로우
- imcompelete medation
- Race condition
Malicious software (intentional)
악의적으로 만들어진 소프트웨어
- 바이러스
- 웜
- 그 외 말웨어들
Program Flaws
- 에러 : 프로그래밍 실수로 발생하는 것.
- falut : 에러로 인해서 부정확한 상태에 빠지는 것
에러는 사람에 의해서 발생한다. fault는 프로그램의 내부적인 상태로, 원래 의도하지 않았던 상태로 빠지게 되는 것이다. fault는 궁극적으로 특정 Failure에 향하게 되는데, failure 는 외부에서도 보이는 오류이다.
결국 사람이 발생시킨 Error -> (내부) fault -> (외부) failure의 순으로 향하게 된다.
소프트웨어 공학의 목적 : 하나의 프로그램으로 하여금 원래 의도된 대로 잘 만들어지고 잘 동작하게끔 하는 것.
보안 소프트웨어 공학의 목적 : 원래 소프트웨어가 의도했던 대로만 동작하도록 하도록, 다른 것을 하지 못하도록 하는 것.
- Program flaws는 의도된것이 아니다. 하지만 보안적인 위험성을 지니고 있다.
Buffer Overflow
- 버퍼 : 메모리 상의 임시 저장 공간.
- 버퍼 오버 플로우 : 프로그래머가 지정한 곳 외에 데이터가 저장되거나, 프로그램이 실행되거나 하는 현상.
ex) 저장되어야 하는 특정한 공간을 벗어나 다른곳에 데이터를 저장하게끔 만들어, 메모리를 덮어 씌운다. 원래 저장되어 있던 중요한 데이터를 잃게 된다. 프로그램이 오작동하게 만든다.
버퍼 오버플로우의 예시
- 웹 폼에 데이터를 입력한다.
- 웹 폼이 서버에 데이터를 전송한다.
- 서버가 데이터의 길이를 체크하지 않고 버퍼에 저장한다.
- 버퍼에 데이터 오버플로우가 발생한다.
중요한 데이터를 갈비지 데이터로 덮어 씌워지는 경우, 중요한 데이터를 의도한 악의적인 데이터로 덮어 씌워지는 경우, 두가지 경우가 발생할 수 있다.
int main(){
int buffer[10];
buffer[20] = 37;
}
원래 의도는 버퍼로 10칸을 사용하는 것이지만, 전혀 다른 주소인 buffer[20]에 해당하는 곳에 데이터가 덮어 씌워지게 된다.
극단적인 경우, 버퍼 오버플로우가 발생해 boolean flag를 덮어 씌울 수 있다. 값이 항상 true가 되어, 어느 누구라도 true로 인증이 되게 된다.
데이터가 덮어짐으로서 발생하는 문제도 있지만, 컴퓨터의 특수 권한을 가져와서 원치 않는 동작을 수행하게 할 수도 있다.
함수를 실행하고 다시 리턴하는 리턴 주소가 저장되어 있는 공간을 덮어 씌운다. 원래 복귀 주소가 아닌 원치 않는 다른 주소가 들어가게 된다. 이를 통해 원하지 않는 프로그램을 실행시키게 만들 수 있다.
- 아예 덮어 씌워서 그 자체만으로도 원하지 않는 공격을 하게 만듦.
- 데이터 복귀 주소를 가지고 다른 동작을 하게끔 유도함.
- 이를 막기 위한 방법 : 비주얼 스튜디오의 scanf_s - 문자열의 크기를 체크하고 입력을 받아서 버퍼 오버플로우를 방지함.
메모리 상에서 스택은 높은 주소에서 낮은 주소로 역방향으로 쌓이게 된다.
(그림 상 윗 부분이 낮은 주소이다.)
버퍼는 반환주소의 바로 위에 위치하게 된다.
버퍼 오버플로우가 발생하면, 버퍼와 리턴 주소 공간이 붙어 있기 때문에, 1차적으로 리턴 주소값이 덮어지게 된다. 함수의 실행이 끝났음에도 불구하고 원하는 곳으로 리턴하지 못하게 된다. 이것만으로도 공격이 될 수 있지만, 여기서 한 단계 더 하여 코드 인젝션을 수행할 수 있다. 앞의 경우 리턴 주소를 망쳐서 크래쉬를 일으키는 공격이었지만, 코드 인젝션의 경우 리턴 주소가 담겨 있는 공간에 악의적인 코드를 삽입한다. 무조건적으로 실행되기 때문에 악성코드가 동작되게 된다.
코드 인젝션의 경우, 공격자는 리턴주소 공간이 메모리 상 어디에 존재하는지 알지 못한다.
두 가지 방법을 사용해 코드 인젝션을 수행한다.
- 랜딩 패드 : NOP코드를 쭉 넣고, evil 코드를 넣어서 결국에는 evil 코드에 도달하게 한다. NOP->NOP->NOP->..->evil code.
- 똑같은 반환 주소를 반복적으로 집어 넣는다. (하나는 걸리겠지 방법.)
위와 같은 공격을 Stack smashing 이라고 한다. 모든 버퍼 오버 플로우가 exploitable 하지는 않다. trial and error 방식을 사용해서 공격을 실행한다.
실제 예시) 시리얼 넘버
공격자는 소스 코드를 모르고 실행 파일(바이너리 파일)만 가지고 있는 상황.
trial and error 방식으로 이것저것 경우의 수를 넣어보면서 버퍼 오버플로우를 발생시킨다.
instruction at "0x00004141" -> 리턴주소가 aa로 덮어 씌워졌다. 이 영역을 공격해야 된다는 것을 깨닫게 됨.
실행파일을 디스어셈블을 해서 진행하면 명령어들을 확인할 수 있다. 시리얼 넘버가 맞다고 하는 파트, 401034으로 무조건 분기하도록 한다. 401034은 아스키코드로 @^P4이다. X86 프로세스는 little endian한 방식이기 때문에 거꾸로 집어넣어줘요. 그래서 34 10 40으로 넣어줘야 한다. 즉, 4^P@로 주입한다. 그 결과 입력값이 엉망진창이어도 무조건 시리얼 넘버가 정확하다는 출력을 가지게 된다. 성공.
Stack Smashing을 막는 방법
- 버퍼 오버플로우를 제거하는 방법
- 버퍼 오버플로우 발생시 방지하는 방법
- 스택상에서 코드가 실행되는 것을 막는 방법이 있다.
- 비실행형 스택. 데이터가 저장되는 영역(스택, 힙과 같은 영역)안에서는 코드 실행 권한을 주지 않는다. NX bit 사용.
- 안전한 언어를 사용한다. (C#, JAVA와 같이 런타임 때 메모리에 대한 접근을 검사하는 언어 -> 성능 저하가 발생할 수 있다.)
- 안전한 C언어 함수를 사용한다. (strcpy 대신에 strncpy를 사용한다. scanf 대신에 scanf_s를 사용한다.)
- 카나리 방법 : 버퍼 밑에 카나코드를 넣어 그 밑으로 (리턴주소 공간)을 덮어 씌우지 못하게 한다. -> 카나리아 상에서 종료가 된다.
마이크로소프트에서는 이런 버퍼 보안 검사 기능을 gs 컴파일러라는 flag로 제공을 하고 있다. 카나리아가 죽었을 때에는 사용자가 제공한 어떤 핸들러 함수로 다시 넘어가게끔 이런 식으로 구현을 할 수가 있습니다. 그러나 핸들러 함수 자체가 또 공격을 받을 수가 있고 사용자 지정 핸들러 함수기 때문에 그 자체를 공격자가 건드린다든가 하는 공격을 할 수 있다.
버퍼 오버플로우는 10년동안 계속 공격되었다,, 본질적으로 사라질 수 없는 공격이다,,
Incomplete mediation (불완전 중재)
애초에 버퍼오버플로우가 발생하기 전, 입력으로 들어온 값들의 범위를 검사하지 않아서 위험이 발생하는 것이 불완전 중재 상황이다.
즉 데이터 자체를 정확히 체크하지 않음으로써 생기는 문제를 나타내는 상황이다. 사실 버퍼 오버플로우와 맞닿아 있다.
불완전 중재의 예시
- 소프트웨어가 인풋의 크기, 데이터를 미리 체크하지 않음. (버퍼 오버플로우, 쇼핑몰의 가격 205->25)
꼼꼼하게 소프트웨어를 설계하지 않아 발생한다고 볼 수 있다.
리눅스 커널에서도 불완전 중재 때문에 버퍼 오버플로우가 발생한다. 즉, 주위에 엄청많은 불완전 중재 상황이 있다.
Race condition (경주 상태)
먼저 실행되지 않아야 될, 먼저 저장되지 말아야 될 것들이 순서를 어기고 수행되는 상황.
- 일반적으로 보안 프로세스, 프로그래밍은 아토믹하게 처리되어야 한다. One and once. 한 번에 모두 실행이 돼야 된다. 중간에 끼어들 수 있는 상황을 최소화 시켜야 한다.
- race condition은 중요한 보안 프로세스가 단계적으로 실행할 때 발생한다. 공격자들은 이 사이에 끼어들고, 관계들 사이에 변화를 발생시킴으로써 보안을 침해할 수 있다.
ex) mkdir : 생성 후 디렉토리의 소유권을 인가해야 하는데 atomic 하지 않고 단계적으로 이루어진다. 소유권이 전달 되기전에 끼어들어서 문제를 발생시킬 수 잇다. 타이밍이 중요하다.
ex) 안드로이드의 인텐트가 비동기화 시스템이기 때문에 발생하는 경주상황.
race condition은 상당히 흔하고, 이론적으로 취약점이 많은데, 아주 찰나의 시간에 끼어들어야 하기 때문에 실제로는 뚫기가 쉽지 않다.
Malware
Malicious Software
최초의 말웨어는 1980년의 fred cohen의 바이러스이다. MLS 시스템의 보안 취약점을 보여주기 위해 만들어 졌다.
virus, worm, trojan horse, trapdoor, rabbit 등 다양한 종류의 말웨어가 존재한다. 상호 배타적이지 않다.
- virus : 수동적인 형태로, 이메일에 첨부되든지 프로그램을 통해서라든지, 전달되는 말웨어(외부의 도움이 필요).
- worm : 외부의 도움 없이 자가 복제를 통해 전달하는 경우.
- Trojan horse - 정상적으로 보이지만 백그라운드에서는 악의적인 일을 수행
- Trapdoor/backdoor - 인가되지 않은 액세스를 허용
- Rabbit - 시스템 자원을 고갈 시킴.
말웨어의 흐름
- 코헨의 바이러스 (1980년 초반)
- brain virus (1986)
- morris worm (1988)
- code red worm (2001)
- SQL slammer worm (2004)
바이러스는 어디에 존재할까?
- 부트 섹터 : 부팅 프로세스를 제어할 수 있기 때문에 본인을 숨길 수 있다. 가장 최악의 경우.
- 메모리 : 재부팅하면 바이러스가 삭제된다.
- 애플리케이션, 매크로, 데이터, 라이브러리, 컴파일러, 디버거 등.
- 컴파일러나 디버거의 경우 상당히 크리티컬하다. 만들던 간에 다 심어지기 때문에. 결론적으로 바이러스는 어디에든 존재할 수 있다.
Brain virus
- 1986년에 등장
- 바이러스의 프로토타입 모형, 초기모형이 됐다.
- 부트섹터에 위치해서 탐지 스캔을 막기위해서 디스크 호출을 방지했다. 각 디스크를 읽고 수행할 때마다 부트섹터가 제대로 감염됐는지 검사를 했다. 안됐을 경우 다시 감염시키는 등 끊임 없이 부트섹터에 대해 감염을 시도하는 형태이다.
- 실제로 나쁜 짓을 하진 않았다.
Morris worm
-1988년에 등장. 6천개가 가감염되고 1000만 달러가 넘는 피해액이 발생했다.
-최초로 웜에 대한 인식을 일깨워 주었다.
- 시스템 자원을 고갈 시키는 형태(래빗과 같은 형태)로 동작하였다.
- 사용자의 암호를 추측하고, fingerd로 버퍼 오버플로우를 사용하고 센드메일을 이용해 트랩도어를 이용했다.
- 암호 공격의 경우 dictionary attack을 이용해 암호를 알아냈다.
- fingerd의 버퍼를 덮어씌워서 원하는 동작을 수행하게 끔 했다.
- 머신에서 액세스가 확보가 되면 bootstrap loader를 보낸다. (c언어로 된 99라인 코드), 머신은 코드를 컴파일 하고 실행한다. bootstrap loader가 남은 나머지 웜을 가져와서 실행하고, 머신은 공격자에게 인가된다.
- Bootstrap loader로 들어가서 웜의 전송을 수행하는데, 차단될 경우 흔적을 아예 남기지 않고 모두 삭제 시킨다. 또한 코드를 다운 받을 때 암호화 시키는 방식을 사용했다. 다운로드 후 복호화 시키고 컴파일 후 동작시킨 다음 코드를 삭제시켜 반복적인 동작을 수행하게 했다. 실행 과정에서 스스로의 프로세스 이름과 pid를 변경해 탐지되는 것을 막았다.
- CERT라고 하는 컴퓨터 침해 사고 대응 기관이 만들어졌다.
이제부터 콘셉트 : 얼마나 빠르게 얼마나 많이 퍼뜨리는가!
Code Red Worm
- 15시간동안 25만개의 시스템을 감염시킬 수 있다.
- 마이크로 소프트의 서버 시스템에 존재하는 버퍼 오버플로우를 이용했다.
- 다음 타겟을 찾기 위해서 80번 포트에 이상이 있는 트래픽을 모니터링하고, 취약할 시 감염을 시키는 방식으로 동작을 했다.
- 1일
19일까지는 감염을 퍼뜨리고, 2027일 부터는 백악관 사이트에 DDOS 어택을 수행했다.
SQL Slammer Worm
- 10분동안 25만 시스템을 감염시켰다.
- 특정 포트를 이용해서 DB 서버(my sql 서버)를 공격하는 형태의 웜이다.
- SQL 서버의 버퍼 오버플로우 결함을 이용해서 감염시켰다.
- SQL 서버끼리 사용하는 프로토콜에 패킷을 속여 잠입하는 방식으로 공격을 했다.
- 무작위로 ip주소를 찾은 다음 타겟으로 패킷을 전하는 방식으로 감염을 시켰다.
- 랜덤으로 ip를 계산하는데 리소스(대역폭)를 너무 많이 써버려서 다운되어 버렸다. (너무 빨라서 문제!)
- 전체 웜의 크기를 UDP 패킷의 크기인 376바이트로 맞췄다. 방화벽은 1차적으로 크기를 보고 말웨어를 필터링하는데, 기존의 말웨어보다 데이터의 크기가 작았기 때문에 통과되었다. 그래서 더 잘 동작할 수 있었다.
Trojan Horse
-원래의 기능을 하고, 예상하지 않은 다른 기능을 하는 것이 트로이 목마이다.
Malware Detection
- 시그니처 탐지
- 변화 탐지
- 비정상 탐지
Signature Detection
- 악성 코드를 나타내는 문자열을 가지고 있는지 탐색한다. 우연히 같은 문자열을 가지고 있을 수 있기 때문에 항상 옳은 것은 아니다. 추가적인 검사가 필요하다.
- 이미 알려져 있는 말웨어에 대해서 효과적이다.
- 시그니처 파일을 계속해서 최신파일로 업데이트해야되고, 그 크기가 계속 커지기 때문에 스캔 동작이 느려진다는 단점이 있다.
- 또한 알려지지 않은 타입에 대해서 탐지하지 못한다.
- 가장 많이 쓰이는 보편적인 방법이다.
Change Detection
- 해시값이 변화할 경우 감지하는 방법. 특정 소프트웨어가 변경하면 감염됐다고 전제하고 검사를 한다.
- false negative가 존재하지 않는다. 실제로 양성인데 음성이라고 나오는 경우는 없다.
- 알려지지 않은 말웨어도 탐지할 수 있다.
- false positive, false alarms가 발생한다. 사용에 의해서 발생한 변경인데도 경보가 발생한다.
- 다른 탐지 방법을 추가적으로 수행해야 한다.
anomaly detection
- 정상을 정의해야 되고 정상은 끊임없이 변경될 수 있다.
- 알려지지 않은 말웨어를 찾을 수 있다.
- 다른 탐지 방법을 추가적으로 수행해야 한다.
- IDS에서 인기있는 방법이다.
Future malware
- Polymorphic malware
- Metamorphic malware
- Warhol worm : 15분 내에 전체 인터넷을 감염 시킨다는 컨셉. 슬래머 웜의 문제를 해결하기 위해서 취약한 Ip주소를 담고 있는 리스트를 사용한다. 즉 무작위로 찾지 않고 정해진 곳에만 공격을 수행한다.
- Flash worm : 워홀 웜보다 더 빠르게 감염시킨다는 컨셉. 복제가 관건. 모든 취약한 ip주소를 미리 결정한다. 복제할 때마다 내장되어 잇는 주소 목록을 분할해서 본다. 점점 갈수록 리스트는 작게 분할되고 빠르게 수행될 수 있다. (이진 트리 형태). 15초 이내에 모든 인터넷을 감염시킬 수 있다. 개별 IDS를 구현해서 막을 수 있다(비정상 감지 됐을 때 모니터링하다가 일부만 블락시킨 후 이상이 발생할 경우 전체 블락시킴)
컴퓨터와 생물학적 질병에는 일부 유사성이 있다. 이를 통해서 Insight를 얻을 수 있다.
- 생물학적 질병 : 랜덤성이 있다.
- 컴퓨터의 질병 : 랜덤성이 없다. (취약한 ip를 공격하기 때문에, 완전한 랜덤이라고 보기 힘들다.)
Miscellaneous Attacks
- salami attack
- linearization attack
- time bomb
salami attack
살라미 햄처럼 얇게, 티가 안나게 공격을 수행한다. 안보이기 때문에 크리티컬하다. 티끌 모아 태산!
ex) 은행에서 이자를 계산할 때 10원 단위로 횡령한다.
- 내부자에 의해서 가능하다.
linearization attack
- 시리얼 넘버를 검사할 때, 올바른 문자열이 틀렸을 때 보다 더 많은 시간이 걸리는 것을 이용한다.
- 문자별로 입력했을 때, 반응하는 시간을 체크해 문자를 하나씩 유추해내는 방법이다.
- 빨리 찾을 수 있다는 장점이 있다.
8개의 암호를 찾는 경우, 128개의 8승, 즉 2의 56을 찾으면 된다. 2의 보수법을 적용할 경우 2의 55승만 찾으면 된다. 선형공격의 경우, 둘씩 비교해서 가장 긴것만 찾으면 되기 때문에 8*(128/2) = 2의 9승번만 수행하면 찾을 수 있다. - 실제 적용사례로는 TENEX가 있다. (암호를 한문자씩 검사하는 방식의 운영체제)
Time Bomb
- 벌레슨이라는 사람이 1986년에 한 공격.
- 일정 시간 있다가 동작을 하게 만들어서 데이터를 다 지워버리는 방식.
- 컴퓨터 범죄를 판례에서 다루는 첫 사례가 되었다.
이런 상황에서 우리는 소프트웨어를 신뢰할 수 있는가?
NO... 말웨어들을 근본적으로 해결하는 것은 쉽지 않다. 더불어 살아가야 한다..^^~
'ETC > 네트워크 보안' 카테고리의 다른 글
네트워크 보안 Ch.번외 (0) | 2023.04.10 |
---|---|
네트워크 보안 Ch.11 Software Security (1) | 2023.04.10 |
네트워크 보안 Ch.9 Network Security (1) | 2023.04.10 |
네트워크 보안 Ch.8 Network Security (0) | 2023.04.10 |
네트워크 보안 Ch.7 Authorization (0) | 2023.04.10 |