본문 바로가기
웹 해킹

Ch 06 소스코드 취약점 분석(+실습)

by plum06 2023. 2. 8.

*틀린 내용이 있을 경우 댓글로 알려주신다면 감사하겠습니다!

 

 

웹 애플리케이션의 보안 취약점 찾기

1) Black Box Testing

: 소스코드를 보지 않고 웹 애플리케이션의 외부 인터페이스나 구조를 분석해 취약점을 분석하는 방식입니다. 내부 구조나 작동원리를 모르는 채로 입력값과 결과에만 초점을 맞춰 검사합니다. White Box Testing에 비해 취약점 찾는 속도가 빠르고 다양한 취약점을 찾는 시도를 할 수 있습니다. 아래는 해당 방식이 사용하는 검사 기법입니다.

  • Equivalence Class Testing – 프로그램이 특정 값의 입력에 대해 동일한 결과를 생성하는 클래스를 식별하고 해당 클래스에서 하나의 값을 가지고 검사.
  • Boundary Value Evaluation – 입력 조건의 중간 값보다 경계 값에서 에러가 발생될 확률이 더 높음. 이를 이용해 테스트 케이스 생성.
  • Decision Table Testing – 논리적 조건이나 상황에서 입력 조건과 결과를 참, 거짓으로 표현하여 조합을 만들고 테스트 케이스 작성. 각 조합이 유효한지 확인
  • State Transition Evaluation – 애플리케이션 로그인 시 몇 회 이상 실패할 경우 로그인 할 수 없게 되는 것 같이 특정 조건에 따라 상태가 바뀌는 상황을 식별하고 유효한지 확인.
  • Error Checking – 개발자가 프로그램 개발 시 발생 가능한 일반적인 오류를 확인. 특정 값을 입력하면 정상적으로 처리되는지, 이름 입력할 때 문자 및 기호를 어느 정도로 제한했는지 등을 확인 가능.

2) White Box Testing

: 개발된 소스코드를 확인하여 보안 취약점이 존재하는지 여부를 확인하는 방식입니다. 내부 구조와 동작 원리를 세밀하게 검사합니다. 내부 소스코드를 보는 방식이기 때문에 보안 취약점 존재 여부를 보다 확실히 알 수 있으나 최근에 개발된 웹 애플리케이션의 소스코드는 수백, 수천 개나 되기에 일일이 검토하면서 보안 취약점을 찾기에는 시간이 너무 많이 소요됩니다. 아래는 해당 방식이 사용하는 검사 기법입니다. 

  • Statement Coverage – 프로그램의 모든 문장을 적어도 한 번씩 검증되도록 하는 기준
  • Branch Coverage – if나 while 같은 식에서 조건에 따라 다른 결과가 나올 수 있으니 해당 문장 내 조건식 검사.
  • Path Coverage – 수행 가능한 모든 경로 검사

3) Gray Box Testing

: Black Box Testing White Box Testing 각각의 장점을 혼합한 방식입니다. 웹 애플리케이션 외부에서 보이는 취약점을 진단하여 확인하고 소스코드에서 접근 통제, 입력값 검증, 세션 처리 문제 등을 같이 살펴보며 취약점을 조사합니다. 아래는 해당 방식이 사용하는 검사 기법입니다.

  • Matrix Testing – 변수에 초점을 맞춰 변수가 정확하고 효율적으로 사용되는지 확인.
  • Regression Testing – 코드는 나중에 수정될 수 있는데 해당 애플리케이션이 수정된 이후로도 테스트를 통과할 수 있는지 확인.
  • Pattern Testing – 애플리케이션의 과거를 살펴 결함이 있었는지 확인하고 나중에 똑같은 경우가 생길 수 있는지 확인.
  • Orthogonal Array Testing – 몇 가지 복잡한 입력값을 사용하는 애플리케이션을 대상으로 함.

출처) https://www.checkpoint.com/cyber-hub/cyber-security/what-is-penetration-testing/what-is-black-box-testing/

https://www.checkpoint.com/cyber-hub/cyber-security/what-is-white-box-testing/

https://www.checkpoint.com/cyber-hub/cyber-security/what-is-gray-box-testing/

 

참고) Black Box Testing vs White Box Testing

Black Box Testing는 사용자 관점에서 인터페이스와 성능 오류를 확인하는 방식. 어떤 언어로 개발되고 어떤 플랫폼을 이용하고 있는지에 상관없이 진행 가능. 하지만 내부 구조에 대한 지식 없이 진행하기에 찾지 못한 취약점이 있을 수 있음.

White Box Testing은 개발자의 관점에서 소스코드의 논리상 오류를 확인하는 방식. 프로그래밍 언어 전문 지식이 필요함.

 

 

소스코드 취약점 유형

아래 표는 행정안전부와 한국인터넷진흥원에서 배포한 소프트웨어 개발 보안 가이드와 2021년에 발표된 OWASP Top 10 항목을 비교한 것입니다. 보면 대부분의 항목이 '입력 데이터 검증 및 표현'과 '보안 기능'에 모여 있는 것을 알 수 있습니다.

행정안전부 소프트웨어 개발 보안 가이드(2021) OWASP Top 10 (2021)
유형  내용  
입력 데이터 검증 및 표현 프로그램 입력값에 대한 검증 누락 또는 부적절한 검증, 데이터의 잘못된 형식지정, 일관되지 않은 언어셋 사용 등으로 발생되는 보안 약점.
=>SQL 인젝션, XSS 공격
A3 인젝션
A10 서버 사이트 요청 변조
A4 안전하지 않은 설계
보안 기능 보안기능(인증, 접근제어, 기밀성, 암호화, 권한권리 등)을 부적절하게 구현 시 발생할 수 있는 보안 약점.
ex) 적절한 인증 없는 중요기능 허용, 부적절한 인
A1 잘못된 접근 통제
A5 보안 설정 오류
A7 식별 및 인증 실패
A8 소프트웨어와 데이터 무결성 실패
A9 보안 로그 및 모니터링 실패
시간 및 상태 동시 또는 거의 동시 수행을 지원하는 병렬 시스템이나 하나 이상의 프로세스가 동작되는 환경에서 시간 및 상태를 부적절하게 관리하여 발생할 수 있는 보안 약점. 해당사항 없음
에러 처리 에러를 처리하지 않거나, 불충분하게 처리하여 에러 정보에 중요정보(시스템 내부정보 등)가 포함될 때, 발생할 수 있는 취약점으로 에러를 부적절하게 처리하여 발생하는 보안 약점. 해당사항 없음
코드 오류 타입 변환 오류, 자원(메모리 등)의 부적절한 반환 등과 같이 개발자가 범할 수 있는 코딩오류로 인해 유발되는 보안 약점. 해당사항 없음
캡슐화* 중요한 데이터 또는 가능성을 불충분하게 캡슐화하거나 잘못 사용함으로써 발생하는 보안 약점.
=> 정보노출, 권한문제
A2 암호화 오류
API* 오용 의도된 사용에 반하는 방법으로 API를 사용하거나, 보안에 취약한 API를 사용하여 발생할 수 있는 보안 약점. A6 취약하거나 오래된 컴포넌트

참고) *캡슐화

: 객체 지향 프로그래밍의 특징 중 하나로 클래스 안에 서로 연관있는 속성과 기능들을 하나의 캡슐로 만들어 데이터를 외부로부터 보호하는 것. 데이터의 보호 혹은 은닉(외부에 필요한 부분만 노출)을 위해서 사용됨.

*API

: 정의 및 프로토콜 집합을 사용해 두 소프트웨어 구성 요소가 서로 통신할 수 있게 하는 메커니즘.

 

 

소스코드 취약점 분석

○ 입력값 검증 취약점

: 프로그램 입력값에 대한 검증 누락 또는 부적절한 검증, 데이터의 잘못된 형식 지정, 일관되지 않은 언어셋 사용 등으로 인해 발생되는 보안 약점입니다. 예로 SQL 인젝션, 크로스 사이트 스크립팅, 위험한 형식의 파일 업로드, 디렉터리 경로 조작 등이 있습니다.

 

● SQL 인젝션 취약점

- 취약한 웹 응용프로그램에서는 사용자가 입력한 값을 필터링 없이 그대로 동적 쿼리를 생성하여 개발자가 의도하지 않은 쿼리가 생성되어 정보 유출로 이어질 수 있습니다. 

이에 대한 대책으로 PreparedStatement 객체 등을 사용하는 것입니다. 그러면 데이터베이스 쿼리에 사용되는 외부 입력값에 대해 특수문자 및 쿼리 예약어를 필터링할 수 있게 됩니다.

 

실습 1) SQL 인젝션 취약점 코드 살펴보기

WebGoat가 설치된 폴더에서 LoginSqlInjection.java 파일을 찾아서 엽니다.

사진 속 붉은 테두리 안을 살펴보면 userIdpassword에 사용자가 입력한 아이디와 패스워드가 저장되고 SELECT 문장을 만들어 executeQuery 함수를 통해 실행되는 것을 확인할 수 있습니다. 여기서 사용자가 입력한 값이 아무런 필터링 없이그대로 데이터베이스 쿼리문에 들어갑니다. , 입력값에 제한이 없기 때문에 쉽게 공격 쿼리문을 만들어낼 수 있습니다.

그러므로 해당 취약점 검증할 때 소스코드에서 쿼리문에 사용자 입력값에 대한 필터링 규칙이 들어있는지 확인해야 합니다.

 

● 크로스 사이트 스크립팅 취약점

- 웹 페이지에 악의적인 스크립트를 포함시켜 사용자 측에서 실행되게 유도하는 공격이 크로스 사이트 스크립팅이었습니다. 해당 공격의 취약점에 대한 대책으로 외부 입력값 또는 출력값에 스크립트가 삽입되지 못하도록 문자열 치환 함수를 사용하거나 크로스 사이트 스크립트 방지 라이브러리를 활용하는 것입니다. 

 

실습 2) 크로스 사이트 스크립팅 취약점 코드 살펴보기

WebGoat가 설치된 폴더 내에서 StoredXss.java 파일을 엽니다.

사용자가 입력한 titlemessagegetRawParameter 함수를 통해 받아들여집니다. 입력된 값이 인코딩되어 컴퓨터가 인식할 수 있게 변환되지만 필터링 되지 않고 그대로 데이터베이스 쿼리문에 들어가 저장됩니다.

 

● 위험한 형식의 파일 업로드 취약점

- 파일을 업로드할 수 있는 자료실 등에서 파일 확장자에 대한 필터링을 수행하지 않는 경우에 발생할 수 있는 취약점입니다.

서버 측에서 실행될 수 있는 스크립트 파일(asp, jsp, php 파일 등)이 업로드 가능하고, 이 파일을 공격자가 웹으로 직접 수행시킬 수 있다면 시스템 내부명령을 실행하거나 외부와 연결해 시스템을 제어할 수 있게 됩니다. 이에 대한 대책으로 업로드 되는 파일을 저장할 때 파일명과 확장자를 외부사용자가 추측할 수 없는 문자열로 변경해 공격자가 웹으로 직접 접근할 수 없는 위치에 저장시킵니다.

 

실습 3) 위험한 형식의 파일 업로드 취약점 코드 살펴보기

WebGoat 설치된 폴더 내의 MaliciousFileExecution.java 파일을 엽니다.

getUserName으로 파일명을 가져와 처리되는데 여기서 파일명과 확장자에 대한 필터링이 없습니다. 파일명 및 확장자에 대한 필터링을 하지 않으면 공격자가 jspasp 등의 웹 프로그래밍 파일로 변경해 악성 스크립트를 실행할 수 있습니다.

 

● 디렉터리 경로 조작

- 위험한 형식의 파일 업로드와 유사한 취약점입니다. 입력된 파일명을 처리할 때 파일명에 대한 필터링이 없을 경우 공격자는 디렉터리 경로를 조작하여 상위 디렉터리에 있는 임의의 파일에 접근할 수 있습니다.

이에 대한 대책으로는 경로순회 공격* 위험이 있는 문자(" / \... 등)를 제거할 수 있는 필터를 이용해 검증하는 방법이 있습니다.

아래 코드들은 소프트웨어 개발 보안 가이드에서 가져온 예시입니다.

//안전하지 않은 코드

//외부로부터 입력받은 값을 검증 없이 사용할 경우 안전하지 않다.
String fileName=request.getParameter("P");
BufferedInputStream bis=null;
BufferedOutputStream bis=null;
FileInputStream fis=null;
try{
	response setHeader("Content-Disposition", "attachment;filename="+fileName+";");
    .......
    // 외부로부터 입력받은 값이 검증 또는 처리 없이 파일 처리에 수행되었다.
    fis=new FileInputStream("C:/datas/"+fileName);
    bis = new BufferedInputStream(fis);
    bos=new BufferedOutputStream(response.getOutputStream());

 

//안전한 코드

String fileName=request.getParameter("P");
BufferedInputStream bis=null;
BufferedOutputStream bos=null;
FileInputStream fis=null;
try{
	response.setHeader("Content-Disposition", "attachment;filename="+fileName+";");
	......
    // 외부 입력받은 값을 경로순회 문자열(./\)을 제거하고 사용해야 한다.
    filename=filename.replaceAll("\\.","").replaceAll("/","").replaceAll("\\\\","");
    fis=new FileInputStream("C:/datas/"+fileName);
    bis=new BufferedInputStream(fis);
    bos=new BufferedOutputStream(response.getOutputStream());
    int read;
   while((read=bis.read(buffer, 0, 1024))!=-1){
   bos.write(buffer,0,read);
   }
   }

참고) 경로순회 공격(Directory traversal, File path traversal)

: 공격자가 응용 프로그램을 실행하는 서버에서 임의의 파일을 읽는 걸 허용하는 보안 취약점. 상대경로 참조 방식("./, ".../" 등)을 이용해 다른 디렉토리의 중요파일에 접근. 서버의 임의 파일에 접근해 응용 프로그램 데이터를 수정하거나 더 나아가 서버를 장악할 수 있음.

 

 

○ 세션 처리 및 접근 통제 취약점

: 개발 단계에서 사용자 권한에 대한 검증을 적절하게 수행하지 않았을 때 주로 발생합니다. 공격자는 해당 취약점을 이용하여 매개변수 조작이나 강제 브라우저 접근 등을 통해 다른 사용자 혹은 관리자의 정보 확인이 가능합니다.

 

매개변수와 쿠키 조작

- 매개변수 조작은 URL에서 변수 또는 POST 형태*로 전송되는 매개변숫값을 조작해 자신이 소유한 것 외의 권한을 획득하는 공격 기법입니다. 매개변수 조작 취약점의 존재 여부를 확인하기 위해서는 사용자 권한이 필요한 페이지에 접근할 때 세션 처리를 하는 코드가 포함되어 있는지 살피는 것입니다. 예시로는 사용자가 입력한 매개변숫값을 쿠키에 저장해 그걸로 인증하는 경우를 의미합니다. 아래 코드는 브라우저 쿠키 값을 통해 사용자 권한을 부여하는 코드 예시입니다.

Cookie[]=cookies=request.getCookes();
for(int i=0; i<cookies.length; i++)
{
	Cookie c=cookies[i];
    if(c.getName().equeals("role")){
    	userRole=c.getValue();
        }
}

쿠키 값은 쉽게 조작할 수 있기에 쿠키 값으로 인증하는 코드는 안전하지 않습니다. 

해당 취약점 소스코드를 살필 때는 getCookie처럼 쿠키를 입력받아 처리하는 부분을 확인해야 합니다.

 

참고) *POST

: 서버에 전송할 데이터를 URL 끝이 아닌 http 메시지 body에 담아서 전송하는 방식. 보안에 유리하며 전송 데이터 용량이 무제한.

 

● 강제 브라우징

- 권한이 필요한 페이지에 권한 체크 코드가 누락되었을 때 발생합니다 예시로는 관리자 페이지 중에서 일부 메뉴에 대한 세션 체크 하는 코드 누락된 경우가 있습니다. 관리자 디렉터리를 운영할 경우 관리자 디렉터리 내의 소스코드 중 세션 처리 등의 코드가 존재하는지 확인해야 합니다.

 

 

○ 코드 내 중요 정보 노출 취약점

: 아이디, 패스워드, 주민등록번호와 같이 중요한 정보를 HTTPS와 같은 암호화된 채널을 통해 전달하는데 암호화되지 않은 상태로 전달되면 공격자가 스니핑 같은 공격 기법을 가지고 정보를 탈취할 수 있습니다.

 

중요 정보 평문 전송

- 중요한 정보를 암호화하지 않고 평문으로 전송할 때 발생하는 취약점입니다. 로그인 페이지처럼 사용자의 중요 정보를 전송하는 페이지가 암호화된 채널로 통신하는지, 소스코드 내 중요 정보를 암호화 함수를 통해 전송하는지 살펴야 합니다. 또한 암호화 하더라도 클라이언트 측에서 복호화하는 함수를 쉽게 분석할 수 있으면 안 됩니다.

아래 두 개의 자바 코드는 소프트웨어 개발 보안 가이드에서 가져온 것입니다.

//안전하지 않은 코드의 예

try{
	Socket s=new Socket("taranis", 4444);
    PrintWriter o= new PrintWriter(s.getOutputStream(), true);
    // 패스워드를 평문으로 전송하여 안전하지 않다.
    String password=getPassword();
    o.write(password);
    }catch(FileNotFoundException e){
    ......

 

//안전한 코드의 예

//패스워드를 암호화 하여 전송
try{
	Socket s= new Socket("taranis", 4444);
    PrintStream o=new PrintStream(s.getOutputStream(), true);
    // 패스워드를 강력한 AES 암호화 알고리즘으로 전송하여 사용한다.
    Cipher c=Cipher.getInstance("AES/CBC/PKCS5Padding");
    
    String password=getPassword();
    byte[] encPassword=c.update(password.getBytes());
    o.write(encPassword, 0, encPassword.length);
    } catch(FileNotFoundException e){
    ......

안전하지 않은 코드의 경우 패스워드를 평문 그대로 전송하기 때문에 패킷 스니핑 같은 공격으로 패스워드가 노출될 수 있습니다. 하지만 안전한 코드를 보면 전송하기 전 AES 암호 알고리즘을 사용하기 때문에 패스워드가 쉽게 알려지지 않습니다.

 

● 하드 코딩된 패스워드

- 하드 코딩은 패스워드 및 시스템 접속 정보와 같이 민감한 정보가 소스코드 내에 그대로 노출되어 있는 경우를 의미합니다. 소스코드 내부의 하드 코딩된 패스워드를 가지고 내부 인증에 사용되어 중요한 정보가 유출될 수 있습니다.

이에 대한 대책으로는 패스워드를 암호화 하여 별도의 파일에 저장해서 사용하는 것입니다. 이때 암호화 키로 상수를 사용하지 않아야 하고 소스코드 내부에 저장되어서는 안 됩니다. 

다음 자바 코드들은 소프트웨어 개발 보안 가이드에서 가져온 것입니다.

//안전하지 않은 코드

public class MemberDAO{
	private static final String DRIVER = "oracle.jdbc.driver.OracleDriver";
    private static final String URL = "jdbc:oracle:thin:@192.168.0.3:1521:ORCL";
    private static final String USER = "SCOTT"; //DB ID;
    //DB 패스워드가 소스코드에 평문으로 저장되어 있다.
    private static final String PASS ="SCOTT"; //DB PW;
    ........
    public Connection getConn(){
    Connection con=null;
    try{
    	Class.forName(DRIVER);
        con=DriverManager.getConnection(URL, USER, PASS);
        .......

 

//안전한 코드

public class MemberDAO{
	private static final String DRIVER="oracle.jdbc.driver.OracleDriver";
    private static final String URL="jdbc:oracle:thin:@192.168.0.3:1521:ORCL";
    private static final String USER="SCOTT"; //DB ID
    ........
    public Connection getConn(){
    	Connection con=null;
        try{
        	Class.forName(DRIVER);
        //암호화된 패스워드를 프로퍼티에서 읽어들여 복호화해서 사용해야 한다.
        	String PASS=props.getProperty("EncryptedPswd");
            byte[] decryptedPswd=cipher.doFinal(PASS.getBytes());
            PASS=new String(decryptedPswd);
            con=DriverManager.getConnection(URL, USER, PASS);
            ........

 참고) 프로퍼티

: 특정 값을 정의하는 데에 사용되는 변수로 메서드 또는 생성자에 전달 가능.

 

● 주석 처리된 중요 정보

- 개발자가 애플리케이션 개발 단계에서 수정이 발생한 소스코드를 삭제하지 않고 주석처리를 한 경우가 생길 수 있습니다. 거기에 중요한 내용이 들어있는지 확인해야 합니다.

 

 

참고 및 출처) 행정안전부, 한국인터넷진흥원 소프트웨어 개발 보안 가이드

다운로드 https://www.kisa.or.kr/2060204/form?postSeq=5&lang_type=KO&page=1

'웹 해킹' 카테고리의 다른 글

Ch 07 웹 해커의 도구(+실습)  (0) 2023.02.15
Ch 05 XSS 공격(실습)  (0) 2023.02.01
Ch 05 XSS 공격  (0) 2023.02.01
Ch 04 SQL 인젝션 공격(실습)  (0) 2023.01.25
Ch 04 SQL 인젝션 공격  (0) 2023.01.25