3. 인젝션

[LDAP 인젝션]▶

O 사용자 입력 값에 비정상적인 쿼리를 포함한 후 입력을 시도하여 데이터베이스에 접근할 수 있는 취약점


O 근거 자료 

☞ 주요정보통신기반시설 기술적 취약점 분석 평가 상세 가이드(p.657)

☞ OWASP TOP10 2021


O 판단 기준

양호임의의 LDAP 쿼리 입력에 대한 검증이 이루어져 변조된 쿼리가 실행되지 않는 경우
취약임의의 LDAP 쿼리 입력에 대한 검증이 이루어지지 않아 변조된 쿼리가 실행되는 경우


O 점검 방법

-  사용자 입력 값 내에 LDAP에서 와일드 문자로 사용되는 * 기호를 입력하여 반환되는 데이터 량의 변화를 확인한다.

-  [*);cn;], [*));cn;], [*)));cn;], [*)));cn;]의 방법으로 ) 기호를 추가하여 에러가 발생하는지 확인한다.


O 조치 방법

- 입력이 LDAP 쿼리에 포함되어야 하는 경우라면, 입력한 값은 허용된 문자로만 검증이 되어야 하고, LDAP쿼리에 영향을 주는 특수문자 입력 제한

- 특수문자를 사용하여야 하는 경우 &lsquo=', '+', '<', '>' 등의 특수 문자의 경우 실행 명령이 아닌 일반 문자로 인식되도록 처리

# 필터링 대상

'"--#(
)=*//*+
<>
user_tables
user_table_columns
user_table_columns
column_name
syscolumns
union
select
insert
drop
update
and
or
if
join
substring
from
where
declare
substr
openrowset
xpsysobjectdeclare
*
from
&
|


O 시큐어 코딩(Secure Coding) 예시

# JAVA ▶ 
private void searchRecord(String userSN, String userPassword) throws NamingException {
    Hashtable env = new Hashtable();
    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
    
    try {
        DirContext dctx = new InitialDirContext(env);
        SearchControls sc = new SearchControls();
        String[] attributeFilter = {"cn", "mail" };
        sc.setReturningAttributes(attributeFilter);
        sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
        String base = "dc=example,dc=com";
        
        // userSN과 userPassword 값에서 LDAP 필터를 조작할 수 있는 문자열을 제거하고 사용
        if (!userSN.matches("[₩₩w₩₩s]*") || !userPassword.matches("[₩₩w]*")) {
            throw new IllegalArgumentException("Invalid input");
        }
        
        String filter = "(&(sn=" + userSN + ")(userPassword=" + userPassword + "))";
        NamingEnumeration<!--?--> results = dctx.search(base, filter, sc);

        while (results.hasMore()) {
            SearchResult sr = (SearchResult) results.next();
            Attributes attrs = sr.getAttributes();
            Attribute attr = attrs.get("cn");
            ......
        }

        dctx.close();
    } catch (NamingException e) {
        // 예외 처리 
    }
}


# C# ▶ 
static void SearchRecord(string userSN, string userPW){
    try {
            DirectoryEntry oDE;
            oDE = new DirectoryEntry(GetStrPath(), userSN, userPW);
            // userSN과 userPW 로 인증 후에 LDAP 쿼리를 실행
            foreach(DirectoryEntry objChildDE om oDE.Children) {
                .....
            }
    } catch (NamingException e){
        // 예외 처리 
    }
}


# C ▶ 
void LDAPInjection() {
    char *filter = getenv(“Filter”);
    int error_code; int i;
    LDAP *ld = NULL;
    LDAPMessage *result;
    
    // 정보를 알고 싶은 사용자의 이름을 고정 값으로 사용
    for(i = 0; *(filter + i) != 0; i++) {
        // 공격 가능한 문자열 검사
        switch(*(filter + i)) {
            case '*':
            case '(':
            case ')':
            .....
                return;
        }
    }
    error_code = ldap_search_ext_s(ld, FIND_DN, LDAP_SCOPE_BASE, filter, NULL, 0, NULL, NULL, LDAP_NO_LIMIT, LDAP_NO_LIMIT, &result);
}



[SQL 인젝션]▶ 

O 데이터베이스와 연동된 웹 응용프로그램에서 입력된 데이터에 대한 유효성 검증을 하지 않을 경우, 공격자가 입력 폼 및 URL 입력란에 SQL문을 삽입하여 DB로부터 정보를 열람하거나 조작할 수 있는 취약점


O 근거 자료

☞ 주요정보통신기반시설 기술적 취약점 분석 평가 상세 가이드(p.661)

☞ OWASP TOP10 2021


O 판단 기준

양호임의의 SQL 쿼리 입력에 대한 검증이 이루어져 임의의 쿼리가 실행되지 않는 경우
취약임의의 SQL 쿼리 입력에 대한 검증이 이루어지지 않는 경우


O 점검 방법

- 변수 값에 큰따옴표(“), 작은따옴표(‘), 세미콜론(;) 등을 입력한 후, DB error가 일어나는지 확인한다.

- ['and'a&rsquo='a, 'and'a&rsquo='b], [and 1=1, and 1=2]의 세트의 값을 각각 삽입하여 정상 변수 값을 보낸 화면과 [동일화면, 다른화면]의 반응이 있는지 확인한다.

- 로그인 화면의 경우 아이디나 패스워드 변수 값에 ['or 1=1 –], ['or&rdquo='] 등의 SQL 쿼리문을 입력한 후 로그인이 되는지 시도한다.


O 조치 방법

- 문자열 유효성 검증 로직 구현

# 사용자 입력 값 제한 특수 문자 (DB에 따라 문자가 달라질 수 있음)

문자설명
'문자 데이터 구분 기호
;쿼리 구분 기호
--, #해당랑인 주석 구분 기호
/*,  *//*와 */ 사이 구문 주석

- Dynamic SQL 구문 사용 금지 및 파라미터 문자열 검사 필수 적용

- 오류에 대한 예외 처리

: 공격자에게 시스템 정보 등을 제공할 수 있는 에러 메시지를 통한 정보 노출 최소화

: 에러 메시지 및 DBMS에서 제공하는 에러 코드가 노출되지 않도록 예외 처리

- 웹 방화벽을 통한 Injection 공격 차단 정책 적용

- 필터링 등 입력 값 검증 프로세스는 서버 사이드 스크립트로 구현


O 시큐어 코딩(Secure Coding) 예시 

# JAVA ▶ 
import java.util.regex.Matcher;
import java.util.regex.Pattern;

final Pattern SpecialChars = Pattern.compile("['\"\\-#,-()@=*/+]");
// 인젝션에 사용되는 특수문자 필터링
UserInput = SpecialChars.matcher(UserInput).replaceAll("");

// 인젝션에 사용되는 SQL 명령어 필터링
final String regex = "(union|select|from|where|case|then|dual|having|group by)"; 
final Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
final Matcher matcher = pattern.matcher(UserInput);

if(matcher.find()){
    out.println("");
}


# PHP ▶ 
// 인젝션에 사용되는 특수문자 필터링
$UserInput = preg_replace("/[\r\n\s\t\'\;\"\=\-\-\#\/*]+/","", $UserInput);

// 인젝션에 사용되는 SQL 명령어 필터링
if(preg_match('/(union|select|from|where)/i', $UserInput)) {
    $this–>Error_popup('No SQL-Injection');
}


# php.ini 설정 변경 ▶ 

- php.ini 설정 중 magic_quotes_gpc 값을 On으로 설정

Magic quotes
// Magic quotes for incoming GET/POST/Cookie data
// off에서 on으로 변경한다.
magic_quotes_gpc = ON ;
// Magic quotes for runtime-generated data, e.g. data from SQL, from exec(), etc.
magic_quotes_runtime = Off
// Use Sybase-style magic quotes (escape ' with " instead of \').
magic_quotes_sybase = Off



[SSI 인젝션]▶ 

O SSI(Server-Side Includes)는 HTML문서 내 변수 값으로 입력된 후, 이를 서버가 처리하게 되는데, 이 때 인젝션 명령문이 수행되어 서버 데이터 정보가 누출되는 취약점

* SSI(Server-Side Includes) : CGI 프로그램을 작성하거나 혹은 서버 사이드 스크립트를 사용하는 언어로, 웹 서버가 사용자에게 페이지를 제공하기 전에 구문을 해석하도록 지시하는 역할


O 근거 자료

☞ 주요정보통신기반시설 기술적 취약점 분석 평가 상세 가이드(p. 667)

☞ OWASP TOP10 2021


O 판단 기준

양호사용자 입력 값에 대한 검증이 이루어지는 경우
취약사용자 입력 값에 대한 검증이 이루어지지 않는 경우


O 점검 방법

- 변수 값에 <!–#echo var="DOCUMENT_ROOT" –>를 삽입하여 표시 페이지에 사이트의 홈 디렉터리가 표시되는지 확인한다.

- 변수 값에 <!–#exec cmd="ls -al" –>를 삽입하여 표시 페이지에 디렉터리의 파일 리스트가 표시되는지 확인한다.


O 조치 방법

- 사용자가 입력이 가능한 문자들을 제한하여 정해진 문자를 제외한 나머지 모든 문자에 대하여 필터링 수행

: 필터링 대상은 GET 질의 문자열, POST 데이터, 쿠키, URL, 그리고 일반적으로 브라우저와 웹 서버가 주고받는 모든 데이터를 포함

# 특수문자에 대한 Entity 형태 예시

변경 전<>"()$&
변경 후&lt;&gt;&quot;&#40;&#41;&#35;&amp



[XPath 인젝션]▶ 

O XML 문서를 조회할 경우 입력 값 조작을 통해 XQuery나 XPath와 같은 쿼리문의 구조를 임의로 변경하여 허가되지 않은 데이터를 조회하거나 인증절차를 우회할 수 있는 취약점


O 근거 자료

☞ 주요정보통신기반시설 기술적 취약점 분석 평가 상세 가이드(p.669)

☞ OWASP TOP10 2021


O 판단 기준

양호쿼리 입력 값에 대해 검증이 이루어지는 경우
취약쿼리 입력 값에 대한 검증이 이루어지지 않는 경우


O 점검 방법

- ['and' a'='a, 'and' a'='b], [ and 1=1,  and 1=2]의 세트의 값을 각각 삽입하여 정상 변수 값을 보낸 화면과 [동일화면, 다른화면]의 반응이 있는지 확인한다.

- 다음 값을 입력해서 에러가 발생하지 않는지 확인한다.

: 'or count(parent::*[position()=1])=0 or 'a'='b

: 'or count(parent::*[position()=1])>0 or 'a'='b

: 1 or count(parent::*[position()=1])=0

: 1 or count(parent::*[position()=1])>0


O 조치 방법

- XPath 쿼리에 입력 값이 입력되는 경우, ( ) = ' [ ] : , * / 등 특수문자 및 쿼리 예약어 필터링

- 특정 특수문자 뿐만 아니라 허용된 문자 이외의 모든 입력 제한


O 시큐어 코딩(Secure Coding) 예시

# JAVA (사전 XQuery 골격 생성) ▶ 
[login.xq 파일]
declare variable $loginID as xs:string external; 
declare variable $password as xs:string external;

// users/user[@loginID=$loginID and @password=$password]
// XQuery를 이용한 XPath Injection 방지
String nm = props.getProperty("name");
String pw = props.getProperty("password");
Document doc = new Builder().build("users.xml");

// 파라미터화 된 쿼리가 담겨있는 login.xq를 읽어와서 파라미터화 된 쿼리를 생성한다.
XQuery xquery = new XQueryFactory().createXQuery(new File("login.xq"));
Map vars = new HashMap();

// 검증되지 않은 외부 값인 nm, pw를 파라미터화 된 쿼리의 파라미터로 설정한다.
vars.put("loginID", nm);
vars.put("password", pw);

// 파라미터화 된 쿼리를 실행하므로 외부 값을 검증없이 사용하여도 안전하다.
Nodes results = xquery.execute(doc, null, vars).toNodes();
for (int i=0; i<results.size(); i++){
    system.out.println(results.get(i).toXML());
}


# JAVA ▶ 
// XPath 삽입을 유발할 수 있는 문자들을 입력 값에서 제거
public String XPathFilter(String input) {
    if (input != null) 
        return input.replaceAll("[',₩₩[]", ""); 
    } else { 
        return "";
    }
}

......

// 외부 입력 값에 사용
String nm = XPathFilter(props.getProperty("name")); 
String pw = XPathFilter(props.getProperty("password"));

......

XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();

......

// 외부 입력 값인 nm, pw를 검증하여 쿼리문을 생성하므로 안전하다.
XPathExpression expr = xpath.compile("//users/user[login/text()='"+nm+"' and password/text()='"+pw+"']/home_dir/text()");
카카오톡 채널 채팅하기 버튼