티스토리 툴바

달력

052012  이전 다음

  •  
  •  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  •  
  •  

Prefork 방식의 아파치 서버일 경우 한명의 client 접속시 일반적으로 5~10MB 정도의 메모리를 사용하게 된다.
-> ps aux 명령어 결과에서 RSS 크기를 참조한다. 아래 예시를 보면

# /usr/ucb/ps aux | grep apac
root 8688 0.0 0.1 5280 3936 ? S 1월 21 0:55 /home/apac
nobody 17125 0.0 0.1 5280 2536 ? S 14:02:27 0:00 /home/apac
nobody 17126 0.0 0.1 5280 2536 ? S 14:02:28 0:00 /home/apac
nobody 17127 0.0 0.1 5280 2536 ? S 14:02:28 0:00 /home/apac
nobody 17128 0.0 0.1 5280 2536 ? S 14:02:29 0:00 /home/apac
nobody 17129 0.0 0.1 5280 2536 ? S 14:02:29 0:00 /home/apac
nobody 17130 0.0 0.1 5280 2536 ? S 14:02:29 0:00 /home/apac
nobody 17131 0.0 0.1 5280 2536 ? S 14:02:29 0:00 /home/apac
root 20143 0.0 0.1 1776 1424 pts/2 S 17:55:55 0:00 grep apac

메모리가 8GB 이고, 기본적으로 OS에서 1GB 사용, DB 등 다른 S/W에서 1GB 사용하여 6GB가 여분이고, 편의상 client당 10MB 사용한다면
6GB*1024/10MB = 614.4 로 약 600여명이 동시접속 가능하게 된다.

물론, 이는 메모리만 산정할 경우를 계산한 것이다.


네트워크 밴드위스의 경우,
웹서버는 이미지 외에 크게 전송할 콘텐츠가 아니므로 보통 300KB/sec
정도면 훌륭합니다. 그러나 실제로 클라이언트 환경에 좌우되기 때문에
이 속도까지 나오지 않고 보통 10 ~ 300KB/sec 정도입니다.

여기에서는 편의상 작은 50KB/sec 으로 잡는다면
50KB/sec = 50 * 8 KBits/sec = 400Kb/sec 입니다.

10MBPS => 10Mb/sec = 10*1024Kb/sec / 400Kb/sec => 26 Clients
Posted by 불펭
1. 아파치 2.0.xx 버전

기본 동시접속자수는 최대 256명. 이를 더 많은 숫자로 변경하기 위해서는 아래 파일 수정 후 재펌파일이 필요하다.
/apache/../server/mpm/prefork/prefork.c 파일에서
#define DEFAULT_SERVER_LIMIT 256
위에서 숫자 부분을 적당하게 늘려주고

/apache/../server/mpm/worker/worker.c 파일에서
#define DEFAULT_SERVER_LIMIT 16
위에서 숫자 부분을 적당하게 늘려준다.

예를 들어 prefork.c 파일에서 1280으로 늘려주었다면, worker.c 파일은 20으로 늘려주는데, 그 이유는 아래와 같다.

worker 방식은 기본적으로 16개의 child process와 그 안에 64개의 thread를 생성가능하므로, 16*64 = 1024가 된다. 따라서 prefork.c 파일에서 1280으로 늘려주게 되면, worker.c는
1280/64 = 20이 되므로 20으로 수정해 줘야 똑같이 1280명의 동시접속자가 가능하게 된다.

컴파일은 아래와 같이 수행한다.

기존에 /usr/local/apache 로 웹서비스를 사용중이라면
/usr/local/apache 가 아닌 다른 이름으로 컴파일 설치 하면 충돌없이 컴파일이 됩니다.

configure 는 컴파일 환경을 설정 해주는 것입니다.

./configure --prefix=/usr/local/apache2/
make
make install

하면 컴파일이 되겠습니다.

컴파일 후 /usr/local/apache 에 있는 설정 파일들을 /usr/local/apache2 에 복사한 후
웹사이트를 잠시 중지 할 수 있는 시간을 이용하여 apache 를 중지하고 apache2 를 가동하여
오류 여부등을 확인한 한다음 정상적으로 웹사이트가 운영이 된다면 apache 를
삭제(백업필수) 한 뒤 디렉토리명을 apache2 에서 apache 로 변경하여 정상 운영 하면 되겠습니다.
(물론 환경설정 부분이 수정될 수 있습니다. 꼼꼼히 체크 하는 것 잊지 마세요.)



2. 아파치 1.3.xx 버전

기본 동시접속자수는 최대 256명인데, 이는 MaxClients에 입력가능한 최대치를 말합니다.
256명 이상의 동시접속을 허용하고자 할 경우에는 아파치를 다시 재 컴파일해야 합니다.
아파치 디렉토리로 이동하여 ../src/include 안의 httpd.h 에서 다음과 같은 부분을 찾아
값을 높여 주시면 됩니다.

#define HARD_SERVER_LIMIT 512

위와같이 설정 한 후 http.h 파일을 재컴파일해야 정상적으로 적용이 됩니다.

만약 클라이언트가 512명 이상의 접속을 넘어서 이루어질 경우에는 다음과 같은 메시지가
로그파일에 남게 되며, 클라이언 트는 다른 요청의 접속이 끝날 때 까지 대기하거나
또는 특정시간이 지난 후 접속이 이루어질 수 없다는 메시지를 보여주게 된답니다 .

[error] server reached MaxClients setting, consider raising the MaxClients setting.


만약, 동시접속자 수를 기본 동시접속자 최대 수인 256명 미만으로 조정하고자 한다면,
재컴파일이 필요없이 아래 파일만 수정합니다.

../conf/httpd.conf
MaxClients 150

그리고, 아파치를 리스타트 하면 됩니다.
# apachectl restart

[출처] http://kikook.tistory.com/entry/아파치-동시접속자수-변경-13xx-및-20xx-버전

Posted by 불펭

 [SIS 학습장] 윈도우 보안 - 13. Dos공격 방어

아래와 같이 웹 서버가 초당 1000개 이상의 SYN 패킷을 받고 있었다.
앞으로 이런 유형의 공격을(DoS) 방어하기 위한 레지스트리 값을 설정하여라.

C:>netstat -na | findstr ` SYN_RECEIVED`
TCP 211.241.82.71:80 6.55.194.236:51370 SYN_RECEIVED
TCP 211.241.82.71:80 16.192.252.18:22452 SYN_RECEIVED
TCP 211.241.82.71:80 49.5.243.221:52363 SYN_RECEIVED
TCP 211.241.82.71:80 50.145.99.80:46108 SYN_RECEIVED
TCP 211.241.82.71:80 51.53.109.147:28308 SYN_RECEIVED
TCP 211.241.82.71:80 61.58.85.212:52375 SYN_RECEIVED
TCP 211.241.82.71:80 63.33.85.135:32111 SYN_RECEIVED
TCP 211.241.82.71:80 67.206.19.195:28501 SYN_RECEIVED
TCP 211.241.82.71:80 68.79.239.155:42810 SYN_RECEIVED
TCP 211.241.82.71:80 221.29.79.118:36387 SYN_RECEIVED

 

TCP/IP 네트워크의 기본적인 취약점인 SYN Flooding 에 대한 문제입니다.

현재까지도 완벽한 대응법은 존재하지 않으며 다만 백로그 큐를 늘려주는 방법으로 대응하고 있습니다.

 

이 문제는 레지스트리를 변경해야 합니다.

아래 해설은 문제를 푼다기 보다 SYN 플러딩 및 DoS공격을 대응하기 위한 레지스트리 모음입니다.

(아래 대로 하시면 문제를 클리어 할 수있습니다.)

주어진 값은 예시 이고 실제 시스템의 환경에 맞게 조정해야 합니다.

 

<HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\tcpip\parameters>

 키

 값 (십진수)

 설명 

 SynAttackProtect 

 2

 TCP(Transmission Control Protocol)가 SYN-ACKS의 재전송을 조정하도록 합니다. 이 값을 구성하면 SYN 공격(서비스 거부 공격의 한 종류) 동안 연결 응답이 더 빨리 시간 초과됩니다.

 TcpMaxHalfOpen 

 100

 HalfOpen 의 최대치(?)

 TcpMaxHalfOpenRetried 

 100

 재시도된 HalfOpen 의 최대치(?)

 TcpMaxPortsExhausted 

 5

 SYN-ATTACK 보호가 작동하기 시작하는 시점을 결정합니다. 사용 가능한 연결 백로그가 0으로 설정되었기 때문에 시스템에서 TCPMaxPortsExhausted 연결 요청을 거부하면 SYN-ATTACK 보호가 작동하기 시작합니다. 이 경우 합법적인 방법으로 이를 사용하려는 서버나 시스템에는 거의 영향을 주지 않습니다.

 TcpMaxConnectResponseRetransmissions

 2

 SYN이 확인되지 않은 경우 연결 요청에 대한 응답으로 SYN-ACK가 재전송되는 횟수를 결정합니다.
이 값이 2 이상인 경우 스택은 내부적으로 SYN-ATTACK 보호를 사용합니다. 이 값이 2 미만인 경우, 스택은 SYN-ATTACK 보호를 위한 레지스트리 값을 전혀 읽지 않습니다. 이 매개 변수는 부분 공개 TCP 연결을 정리하는 데 걸리는 기본 시간을 줄입니다. 심한 공격을 받는 사이트의 경우 이 값을 1처럼 매우 낮은 값으로 설정할 수도 있습니다. 0 값도 유효합니다. 그러나 이 매개 변수를 0으로 설정하면 SYN-ACK는 전혀 재전송되지 않으며 3초 이내에 시간 초과됩니다. 이 값을 이처럼 낮게 설정하면 멀리 떨어진 클라이언트에서 합법적으로 연결을 시도해도 연결되지 않습니다

 EnableDeadGWDetect 

 0

 무반응 게이트웨이 검색이 사용 가능한 경우 TCP는 연결 수에 문제가 있을 때 백업 게이트웨이로 변경하도록 IP에 요구합니다. 이 설정을 0으로 구성하면 Windows에서는 무반응 게이트웨이를 더 이상 검색하지 못하고 자동으로 다른 게이트웨이로 전환합니다.

 EnablePMTUDiscovery 

 0

 EnablePMTUDiscovery를 1로 설정하면, TCP는 MTU(maximum transmission unit) 또는 원격 호스트 경로에서 가장 큰 패킷 크기를 찾으려고 시도합니다. TCP는 경로 MTU를 찾고 TCP 세그먼트를 이 크기로 제한하여 다른 MTU와 연결되는 경로를 따라 라우터의 조각화를 제거합니다.
조각화로 인해 TCP 처리량이 줄어들 수 있습니다. 이 값을 0으로 설정하면, 로컬 서브넷의 호스트가 아닌 모든 연결에 MTU 576바이트가 사용됩니다.

 KeepAliveTime 

 300000

 TCP가 활성 상태 패킷을 보내 유휴 연결이 그대로 있음을 확인하는 빈도를 결정합니다. 원격 컴퓨터에 여전히 연결 가능한 경우 TCP는 활성 상태 패킷을 확인합니다.
기본적으로 활성 상태 패킷은 보내지지 않습니다. 프로그램을 통해 연결 시 이 값을 구성할 수 있습니다. 이 값을 기본값인 2시간에서 5분으로 낮추면 비활성 세션의 연결이 더 빨리 끊어집니다.

 NoNameReleaseOnDemand

 1

 컴퓨터가 이름 해제 요청을 받을 때 NetBIOS 이름을 해제할지 여부를 결정합니다. 이 값은 관리자가 악의적인 이름 해제 공격으로부터 컴퓨터를 보호할 수 있도록 추가되었습니다. NoNameReleaseOnDemand 값은 1로 설정하는 것이 좋습니다.

 EnableICMPRedirects 

 0

 RRAS(라우팅 및 원격 액세스 서비스)가 ASBR(Autonomous System Boundary Router)로 구성된 경우 연결된 인터페이스 서브넷 경로를 올바로 가져올 수 없습니다. 대신 이 라우터는 OSPF(Open Shortest Path First) 경로에 호스트 경로를 삽입합니다. OSPF 라우터를 ASBR 라우터로 사용할 수 없기 때문에 연결된 인터페이스 서브넷 경로를 OSPF로 가져오면 라우팅 테이블이 이상한 라우팅 경로와 혼동됩니다.

 interfacesPerformRouterDiscovery 

 0

 네트워크 인터페이스의 라우터 찾기 수행(?)

 EnableSecurityFilters 

 0

 1로 설정하면 TCP/IP 스택이 TcpAllowedPorts와 UdpAllowedPorts에서 지정된 포트에 따라 외부로부터의 접속 요구를 걸러 줍니다.

 DisableIPSourceRouting 

 2

 IP 원본 라우팅은 데이터그램이 네트워크를 통해 취해야 할 IP 경로를 보낸 사람이 결정할 수 있도록 하는 메커니즘입니다. 이 값을 2로 설정하면 원본에서 라우팅한 모든 들어오는 패킷이 삭제됩니다.

 TcpMaxDataRetransmissions 

 3

 TCP는 각 아웃바운드 세그먼트가 IP로 전달될 때 재전송 타이머를 시작합니다. 타이머가 만료되기 전에 해당 세그먼트에서 데이터에 대한 확인이 수신되지 않은 경우 세그먼트는 세 번까지 재전송됩니다.

 TcpTimedWaitDelay 

 100

 TcpTimedWaitDelay 값은 TCP/IP가 닫힌 연결을 해제하여 자원을 다시 사용하기 전에 경과되어야 하는 시간을 결정합니다. 닫기와 해제 사이의 이 간격은 TIME_WAIT 상태 또는 최대 세그먼트 지속 시간의 두배(2MSL) 상태로 알려져 있습니다. 이 시간 동안 클라이언트 및 서버로의 연결을 다시 여는 것이 새 연결을 설정하는 것보다 비용이 적게 듭니다. 이 항목의 값을 줄이면 TCP/IP는 닫힌 연결을 더욱 빨리 해제할 수 있으며 새 연결에 더 많은 자원을 제공합니다. TIME_WAIT 상태에 있는 여러 연결로 인해 발생한 낮은 처리량 때문에 실행 중인 응용프로그램에 빠른 해제, 새 연결 작성 또는 조정이 필요할 경우 이 매개변수를 조정하십시오.

 PerformRouterDiscovery

 0

  IRDP(Internet Router Discovery Protocol)를 지원하는 Windows 2000이 컴퓨터에서 기본 게이트웨이 주소를 자동으로 검색 및 구성하지 못하도록 하기 위해 설정됩니다.

 

<HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\AFD\parameters>

 키

 값 (십진수)

 설명 

 EnableDynamicBacklog

 1

 FTP 서버 및 웹 서버와 같은 Windows 소켓 응용 프로그램의 연결 시도는 Afd.sys에 의해 처리됩니다. Afd.sys는 합법적 클라이언트에 대한 액세스를 거부하지 않고 부분 공개 상태에서 여러 번의 연결을 지원하도록 수정되었습니다.
관리자가 동적 백로그를 구성할 수 있도록 함으로써 이러한 지원이 가능해졌습니다.
DynamicBacklogGrowthDelta는 연결이 더 필요할 때 만들 사용 가능 연결 수를 결정합니다. 값이 크면 free 연결 할당이 폭주할 수 있으므로 이 값을 주의하여 설정하십시오.

 MinimumDynamicBacklog

 20

 MaximumDynamicBacklog

 1000

 DynamicBacklogGrowthDelta

 10

 

<HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NetBT\parameters>

 키

 값 (십진수)

 설명 

 NoNameReleaseOnDemand

 1

 컴퓨터가 이름 해제 요청을 받을 때 NetBIOS 이름을 해제할지 여부를 결정합니다. 이 값은 관리자가 악의적인 이름 해제 공격으로부터 컴퓨터를 보호할 수 있도록 추가되었습니다. NoNameReleaseOnDemand 값은 1로 설정하는 것이 좋습니다.

 

< 설명 출처 >

 제목

저자 

 링크

 Windows 2000 Server에서의 TCP/IP 악용 및 대책

 Microsoft

 http://www.microsoft.com/korea/technet/security/prodtech/windows2000/win2khg/05tcpip.mspx

 Windows 성능 조정

 IBM

 http://publib.boulder.ibm.com/wasce/V1.0.1/ko/Tasks/Tuning/Windows.html

 난, 레지스트리로 PC 관리한다

 이순원

 책

 

 

 


 
 

수고하셨습니다~~~~

 

-악어c

http://blog.akerc.pe.kr 

Posted by 불펭

[Window/TCP] 윈도우에서 TCP 파라미터 튜닝

2011/01/05 11:44, 글쓴이 까막군

결국 윈도우에서 TCP 연결의 개수를 최대한 늘이기 위한 방법은 TcpTimedWaitDelay, MaxUserPort, MaxFreeTcbs, MaxHashTableSize 파라미터를 늘여주는 것이다.


Windows에서 TcpTimedWaitDelay를 설정

 TCP 파라미터는 물론 플랫폼 별로 많은 파라미터가 존재하지만, Windows에서의 TcpTimedWaitDelay 와 Solaris의 tcp_time_wait_interval 은 동일한

파라미터로서, 커넥션이 종료 되었을 때 TIME_WAIT 상태로 머물게 되는 시간을 설정한다.

이 값의 디폴트는 4분으로 짧은 시간에 많은 클라이언트가 접속을 하면 네트웍(Network) 퍼포먼스에 영향을 줄 수 있기 때문에 60초로 제한을 두도록

권고한다.


   레지스트리 위치 : HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Tcpip\Parameters
   유효한 범위 : 0\30~300초
   값 이름 : TcpTimedWaitDelay
   값 종류: DWORD
   기본값: 240초
   추천 값: 60


MaxUserPort

서버에 연결되는 Port의 숫자가 5000개 이상 (Exchange 60000) 될 경우 서버에서 네트워크 장애가 발생될 수 있음.
일반적으로 WAS와 연결되는 Windows 서버나 Exchange 서버에서 주로 발생됨.

 

레지스트리 위치: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
유효한 범위: 5000~65534

값 이름 : MaxUserPort
값 종류: DWORD

기본값: 5000
추천 값: 65534


MaxFreeTcbs

 시스템이 TCP 연결 유지를 위해 생성하는 TCP Control Blocks(TCBs)의 숫자를 결정한다. 하나의 연결은 하나의 블록을 요구하기 때문에, 이 값은 TCP가 동시에 몇 개의 연결을 처리할 수 있느냐를 결정하게 된다. 모든 블록이 사용 중인 상황에서 새로운 연결이 들어오게 되면, TCP는 TIME_WAIT 상태인 연결 중에 하나를 강제로 끊어버리고, 블록을 해제한 후, 그 블록을 새로운 연결에 사용하게 된다.
 보통 TCP는 TcpTimedWaitDelay에 지정되어 있는 시간이 지나지 않은 경우, 연결을 해제하지도 않고, 그 연결에 사용된 자원을 재사용하지도 않는다. 이 시간은 보통 TIME_WAIT 또는 2MSL (2 x maximum segment lifetime) 상태라고 불린다. 하지만 시스템이 매우 많은 연결을 받아들여 자원이 바닥날 상황에 이르면, TcpTimedWaitDelay에 지정된 시간이 아직 남아있는 경우에도 연결에 할당되어 있는 자원을 해제하게 된다.
 

레지스트리 위치: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

유효한 범위: 1–0xFFFFFFFF

값 이름 : MaxFreeTcbs
값 종류: DWORD

기본값: 0x1388 (십진값으로 5000)
추천 값: 2000


MaxHashTableSize

TCP Control block이 저장되는 해쉬 테이블의 크기를 결정한다.

TCP는 컨트롤 블록들을 빠르게 검색하기 위해 해쉬 테이블에다 저장한다. 만일 시스템이 동시에 생성할 수 있는 TCB의 숫자를 변경한다면(MaxFreeTcbs 값을 변경한다면), 이 항목의 값 또한 그에 비례해서 변경해줘야한다.

이 항목의 값은 반드시 2의 승수여야한다. 만일 2의 승수를 입력하지 않는다면, 시스템은 자동으로 입력한 수보다 큰 2의 승수 중에 가장 작은 것을 찾아 사용한다.  즉 128 * (시스템 cpu 개수)의 제곱

예를 들어 cpu 4장이라면, 128 * 4^2 = 2048

 최대 값은 0x10000 (65,536)입니다. 연결 부하가 것으로 예상되는 대규모 서버에서는 최대 값을 설정하는 것이 권장됩니다. 테이블은 페이지 되는 풀을 사용하므로 서버의 가용한 페이지 되는 풀이 많지 않거나 연결 부하가 크지 않은 경우에는 값을 너무 크게 설정하면 된다는 사실을 명심하십시오.


레지스트리 위치: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

유효한 범위: 64 ~ 65536

값 이름 : MaxHashTableSize
값 종류: DWORD

기본값: 512

추천 값: 2048



KeepAliveTime

TCP-HandShake를 통해 연결이 되면 해당 세션은 연결이 유지되어집니다.

하지만, 일정 시간동안 Connection에 대해 실제 통신이 없는 경우 Session관리를 위해

특정 시간이 지나면 해당 Session을 OS에서 끊게 됩니다.


NT에서 해당 역활을 해주는 것은 KeepAliveInterval에 설정되어진 값에 의해 결정되게 됩니다.

KeepAliveTime을 통해 해당 시간만큼 ACK(응답)이 없는 경우 Session이 종료되어집니다.



레지스트리 위치: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

유효한 범위: 0x1–0xFFFFFFFF ms

값 이름 : KeepAliveTime
값 종류: DWORD

기본값: 7,200,000 ms --> 2hr

추천 값: 1800000 ms -->30분


 


참고:

윈도우에서 TCP/IP 파라미터

http://technet.microsoft.com/en-us/library/cc739819(WS.10).aspx

 

TCP 동시 연결 수를 최대한 늘이기위한 파라미터

http://lishiqiang2003.wordpress.com/2010/12/24/configure-the-max-limit-for-concurrent-tcp-connections/

Posted by 불펭

netstat를 이용한 TCP/IP 네트워크 관리

TCP/IP 소개

지금의 인터넷이 있게한 프로토콜이다. 이들에 대한 자세한 내용은 TCP/IP 미니사이트 문서를 읽어보기 바란다.

이 문서는 유닉스 환경에서 TCP/IP를 관리하기 위해서 중요하게 사용되는 툴들을 설명한다.

netstat

네트워크 연결상태를 알려준다. 이 프로그램을 통해서 알 수 있는 정보는 다음과 같다.
  1. 네트워크 연결 상태
  2. 유닉스 도메인 소켓 연결 상태
  3. 네트워크연결에 사용된 프로세스 - 리눅스 에서만 가능 -

netstat를 통해서 얻을 수 있는 가장 중요한 정보는 1번이 될 것이다. netstat를 사용하면 현재 네트워크에 연결이 되어있는 상태뿐만 아니라, TIME_WAIT와 SYN_RECV 상태까지도 얻어올 수 있다.

TIME_WAIT를 이해하기 위해서는 소켓의 종료 상태에 대해서 알고 있어야 한다. TIME_WAIT 상태는 소켓이 연결을 종료하는 과정에서 거치는 과정인데 마지막 ACK 신호를 보내지 못하는 경우가 있다. 이 경우 ACK를 재전송하기 위해서 기다리는데, 이를 TIME_WAIT 상태라고 한다.

이것은 2MSL(maximum segment life time)이라고 불리운다. 서버에서 데이터를 모두 다 보내면 연결을 닫기 위해서 close() 함수를 호출하게 된다. 그리고 서버는 ACK신호를 보내고 TIME_WAIT 상태에 들어간다. 클라이언트로 부터 ACK에 대한 응답이 있어야지만 연결이 완전히 종료가 된다. 만약 상대편 클라이언트가 ACK에 대한 응답을 보내지 않고 종료되어 버렸다면, 서버는 2MSL 시간만큼을 기다리게 된다.

TIME_WAIT는 하는 일은 없지만, 클라이언트로 부터의 종료메시지를 기다리는 상태가 되므로 다른 연결을 받아들이지 못하게 된다. 이는 TIME_WAIT 상태가 지나치게 많아지게 될 경우, 그만큼의 연결을 유지해야 하므로 서버프로그램에 문제가 생길 수 있다.

만약 다수의 SYN_RECV 가 있다면, DOS 공격을 의심할 수 있을 것이다. SYN_RECV는 클라이언트가 마지막 3번째 패킷을 서버에게 보내지 않음으로써, 불완전한 연결이 유지되게 된다. 반쪽자리 연결이라고 볼 수 있는데, 이러한 연결을 다수 생성해서 서비스가 거부되도록 공격하는 경우가 종종 발생한다.

# netstat -na : grep 80
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN
tcp 0 0 218.234.19.87:80 122.152.181.156:11962 SYN_RECV
tcp 0 0 218.234.19.87:80 122.152.181.156:47119 SYN_RECV
tcp 0 0 218.234.19.87:80 122.152.181.156:3429 SYN_RECV
tcp 0 0 218.234.19.87:80 122.152.181.156:8208 SYN_RECV
tcp 0 0 218.234.19.87:80 122.152.181.156:59406 SYN_RECV
tcp 0 0 218.234.19.87:80 122.152.181.155:40277 SYN_RECV
tcp 0 0 218.234.19.87:80 122.152.181.155:35498 SYN_RECV
tcp 0 0 218.234.19.87:80 122.152.181.156:29028 SYN_RECV
tcp 0 0 218.234.19.87:80 122.152.181.156:55652 SYN_RECV
tcp 0 0 218.234.19.87:80 122.152.181.156:42340 SYN_RECV
tcp 0 0 218.234.19.87:80 122.152.181.156:16741 SYN_RECV
tcp 0 0 218.234.19.87:80 122.152.181.155:26965 SYN_RECV
tcp 0 0 218.234.19.87:80 122.152.181.156:33807 SYN_RECV
tcp 0 0 218.234.19.87:80 122.152.181.156:50873 SYN_RECV
tcp 0 0 218.234.19.87:80 122.152.181.156:38586 SYN_RECV
tcp 0 0 218.234.19.87:80 122.152.181.156:25274 SYN_RECV
tcp 0 0 218.234.19.87:80 122.152.181.155:48810 SYN_RECV
tcp 0 0 218.234.19.87:80 122.152.181.155:1366 SYN_RECV
tcp 0 0 218.234.19.87:80 122.152.181.155:9899 SYN_RECV
tcp 0 0 218.234.19.87:80 122.152.181.156:64185 SYN_RECV
tcp 0 0 218.234.19.87:80 122.152.181.155:18432 SYN_RECV
tcp 0 0 218.234.19.87:80 122.152.181.155:31744 SYN_RECV
tcp 0 0 218.234.19.87:80 122.152.181.156:20495 SYN_RECV
tcp 0 0 218.234.19.87:80 122.152.181.155:57343 SYN_RECV
tcp 567 0 218.234.19.87:36126 121.185.96.43:80 CLOSE_WAIT
tcp 0 0 218.234.19.87:22 222.119.23.60:2801 ESTABLISHED
tcp 0 0 218.234.19.87:37489 121.185.96.48:80 ESTABLISHED
tcp 0 0 218.234.19.87:80 222.231.42.193:34267 TIME_WAIT
tcp 0 0 218.234.19.87:80 66.249.73.50:63782 ESTABLISHED
tcp 0 0 218.234.19.87:80 210.116.196.225:39776 FIN_WAIT2
tcp 0 0 218.234.19.87:80 74.6.27.107:44671 TIME_WAIT
tcp 0 18981 218.234.19.87:80 141.85.90.195:2982 FIN_WAIT1
 
이 서버는 SYN_RECV 상태의 연결이 지나치게 많다. DOS공격이 의심되는 상황이다.



출처 : http://blog.naver.com/cosmo1492?Redirect=Log&logNo=120045042065
Posted by 불펭

Samba 설정하기

서버/Linux 2011/05/13 10:22

1. 삼바 설치 확인

[root@localhost ~]# rpm -qa | grep samba
system-config-samba-1.2.39-1.el5
samba-3.0.28-0.el5.8
samba-client-3.0.28-0.el5.8
samba-common-3.0.28-0.el5.8

 

설치되어 있지 않을 경우

[root@localhost ~]# yum install -y samba

 

 

2. 삼바 환경설정

삼바 환경설정 파일인 smb.conf 파일 수정

 

[root@localhost ~]# cd /etc/samba

[root@localhost samba]# vi smb.conf

 

# ----------------------- Network Related Options -------------------------
#
# workgroup = Workgroup
#
# server string is the equivalent of the NT Description field
#
# netbios name can be used to specify a server name not tied to the hostname
#
# Interfaces lets you configure Samba to use multiple interfaces
# If you have multiple network interfaces then you can list the ones
# you want to listen on (never omit localhost)
#
# Hosts Allow/Hosts Deny lets you restrict who can connect, and you can
# specifiy it as a per share option as well
#

        unix charset = cp949
        dos charset = cp949
        display charset = cp949

        리눅스와 윈도우즈간의 언어셋 설정.

 

        workgroup = MYGROUP

        윈도우즈의 작업그룹명. ip 대역으로 접속시에는 아무거나 해도 상관없다.

        server string = Samba Server Version %v

        윈도우즈에서 접속시에 보여지는 서버이름. 

        네트워크 드라이브로 연결시에는 위의 서버명과 디렉토리명이 같이 표시되기 때문에 적절히 수정.
 
;       netbios name = local_CentOS
 
;       interfaces = lo eth0 192.168.1.2/24 192.168.2.13/24
        hosts allow = 192.168.1.5 123.45.6.

       삼바서버에 접속할 수 있는 클라이언트 IP 대역 설정.

       (위의 경우 192.168.1.5 IP와 123.45.6. IP 대역에 대해 접속을 허용)

 

 

# ----------------------- Standalone Server Options ------------------------
#
# Security can be set to user, share(deprecated) or server(deprecated)
#
# Backend to store user information in. New installations should
# use either tdbsam or ldapsam. smbpasswd is available for backwards
# compatibility. tdbsam requires no further configuration.
 
        security = user
        passdb backend = tdbsam

        security = share (삼바서버에 사용자명/패스워드 인증없이 접속 가능)

        security = user (리눅스 계정 아이디로 접속 가능)

        user로 설정했을 경우, 환경설정 저장 후 리눅스 계정 패스워드와는 별도로 삼바서버에 패스워드를 등록해야 한다.

 

 

#============================ Share Definitions ==============================
 
[homes]
        comment = Home Directories
        browseable = no
        writable = yes
;       valid users = %S
;       valid users = MYDOMAIN\%S

삼바서버에 로그인한 사용자의 홈디렉토리 설정.

security = user로 설정되어 있을 경우, 로그인한 사용자의 디렉토리가 표시된다.

 

[test1_share]
        comment = test1_share
        path = /home/test
        writable = yes
        valid users = test1

 

로그인한 사용자에게 홈디렉토리 이외에 공유할 디렉토리를 설정해줄 수 있다.

위의 경우, "test1" 사용자에게 자신의 디렉토리 이외에 "/home/test" 디렉토리도 공유할 수 있게 해준다.
 

3. 삼바 서비스 시작

[root@localhost samba]# service smb start
SMB서비스를 시작 중:                                       [  OK  ]
NMB서비스를 시작 중:                                       [  OK  ]

 

4. 윈도우즈에서 삼바 접속

시작 > 실행 > \\삼바 서버 IP

 

5. 삼바 서버에서 사용할 계정 패스워드 설정

[root@localhost samba]# smbpasswd -a test1

New SMB password:

Retype new SMB password:

Added user test1.

 

smbpasswd -a test1 : test1 사용자의 삼바용 패스워드 추가

smbpasswd -x test1 : test1 사용자의 삼바 계정 삭제

smbpasswd -d test1 : test1 사용자의 삼바 계정을 사용중지

Posted by 불펭

1. 시작하기

여러분들은 사용자가 입력한 값에대해 어느정도 검증을 하는지요?

사용자 값을 이것저것 따지고 여러가지 유효성을 체크할려면 아주 귀찮은 일이 아닐수 없습니다

그중에 하나가 웹브라우져에서 실행되는 자바스크립트로 체크하는 방법이 있는데 비지니스 로직이 조금 복잡할때는 자바스크립트로 도배를 하는 경우도 종종 있지요

유효성 검증하는일 저도 정~~말 싫어합니다 하지만 해야 합니다 ㅠ.ㅠ

그럼 어디까지 그 유효성을 체크해야 할까요? 자바스크립트로만 체크하면 될까요?

 

처음 웹프로그래밍을 할때는 저도 자바스크립트로만 입력값을 검증하면 되는줄 알았습니다

한마디로 몰랐죠

하지만 이제는 알기때문에 자바스크립트뿐만 아니라 서버쪽에서도 동일하게 체크해 주어야 합니다

사용자가 입력한 값이 얼마나 무서운지는 앞의 1탄, 2탄의 강좌를 통해 어느정도는 감을 잡으셨으리라 생각하고 이번 강좌에서는 왜 서버쪽에서도 체크해야 하는지!에 대해 간략히 알아보겠습니다

 

 

2. 자바스크립트 체크

 

입력값의 자리수가 13자리인지 체크하여 맞으면 submit을 만약 그렇지 않다면 정상적인 입력값을 요구하는 입력갑검사 로직이 있다고 가정하겠습니다 그리고 서버쪽에서는 꼭 13자리가 넘어와야 정상적인 처리를 할수 있다고 하겠습니다

그럼 아래와 같은 간단한 코드가 나올겁니다

 

http://www.jakartaproject.com/html/input.html

<script>

/* 입력한값이 13자리인지 체크 후 전송 */

function validateValue() {
    var obj = document.f.register_no;
    if (obj.value.length != 13) {
        alert('주민번호 정상적으로 입력하세요');
        return false;
    }
}

</script>

 

<form name=f method=post action=process.jsp onsubmit="return validateValue()">
주민번호 <input type=text name=register_no> <input type=submit name=btn value=submit>
</form>


 실제 웹 브라우져에서 보면 아래와 같습니다

"33" 이라는 두자리 수만 입력하니 역시나 재입력을 요구하는 alert창이 떳습니다 (가끔 깜짝깜짝 놀라죠 -,-)


 

 

그럼 정상적으로 "1111111111111" 의 입력값 13자리를 입력해 보겠습니다

 

 


 

그리고 이 값은 process.jsp 라는곳에서 파라미터로 받아 아래와 같이 처리합니다

코드는 간단하게 그 입력값과 레퍼러 값을 보여주겠습니다

 

http://www.jakartaproject.com/html/process.jsp

<%@ page contentType="text/html; charset=euc-kr" %>

 

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

 

헤더정보 <%=request.getHeader("referer")%><br><br>
주민번호 <%=register_no%>

 

request.getHeader("referer")는 헤더정보에서 referer값을 가져오는 함수로, 이전 페이지 주소값을 가져옵니다

그럼 화면은 아래와 같이 나옵니다

 

자 정상적으로 처리되었습니다

 

 

3. 자바 스크립트 우회

그럼 이제부터 자바스크립트로 입력값의 자리수 체크로직을 피해가는 방법을 알아봅시다

어떤 방법이 있을까요?

 

URL로 접근

입력값이 몇가지 되지 않는다면 아래 방법이 가장 편하겠군요

즉 브라우져 주소창에다 직접 입력 합니다

 

http://www.jakartaproject.com/html/process.jsp?register_no=2222

 

아래와 같은 화면이 나올겁니다

메쏘드정보 (request.getMethod())를 찍어보니 GET 이 나오는군요!

그렇다면 이같은 직접 URL값을 막기위해 간단히 POST만 허용하는 로직을 추가해 버립시다

 

http://www.jakartaproject.com/html/process.jsp

<%@ page contentType="text/html; charset=euc-kr" %>

 

<%
if (!"POST".equals(request.getMethod())
   return;

String register_no = request.getParameter("register_no");
%>

 

헤더정보 <%=request.getHeader("referer")%><br><br>
주민번호 <%=register_no%>

이러면 괜찮겠지 흐흐.. 라고만끝나면 안됩니다

 

로컬파일로 접근

①번의 방법은 GET방식때문에 막혔습니다 그러면 자바스크립트를 우회하면서 POST방식으로 보내는 방법은 없을까요? 물론 있습니다

웹브라우져는 "소스보기" 라는 좋은 메뉴가 있습니다 있는건 적극 활용합시다 ㅎㅎ

소스보기한 후 바탕화면에 저장하여 약간 손을 보았습니다

즉 입력값을 체크하는 자바스크립트를 무력화 시키면서, action을 수정해 주었습니다

 

C:\Documents and Settings\Administrator\바탕 화면\client.html

<script>

/* 입력한값이 13자리인지 체크 후 전송 */

function validateValue() {

    return true;
}

</script>

 

<form name=f method=post action="http://www.jakartaproject.com/html/process.jsp" onsubmit="return validateValue()">
주민번호 <input type=text name=register_no> <input type=submit name=btn value=submit>
</form>

 

 

웹화면은 다음과 같겠죠


"submit"버튼을 클릭합니다 ^^

 

역시나 자바스크립트를 거치지 않고 process.jsp에 13자리수가 아닌 "22"값을 무난히 보냈습니다


 

그럼 서버쪽에서는 "어이쿠 이런 헤더정보도 체크해야 겠군" 하고 다음 코드를 추가해 버릴겁니다

즉 레퍼러값이 null인 경우는 허용할수 없다는 것이죠

 

http://www.jakartaproject.com/html/process.jsp

<%@ page contentType="text/html; charset=euc-kr" %>

 

<%

if (!"POST".equals(request.getMethod())
   return;


if (request.getHeader("referer") == null)
   return;

String register_no = request.getParameter("register_no");
%>

 

헤더정보 <%=request.getHeader("referer")%><br><br>
주민번호 <%=register_no%>

그럼 위와같은 소스가 될것입니다

그럼 과연 위 소스가 안전할까요?

 

HEADER값 조작

그렇다면 HEADER값을 조작해 봅시다 어떻게 조작할 수 있을까요?

여러가지 프로그램들이 있지만 그중에 Achilles 라는 proxy server를 이용하여 조작해 보겠습니다

Achilles라는 proxy server는 웹브라우져와 서버간의 HTTP 세션을 중간에서 가로채어 원하는대로 수정한 후 보낼수 있도록 해주는 작으면서도 강력한 프로그램입니다

 

※ 참고

Achilles 문서를 보면 맨 첫줄에 나오는 문장입니다

"Achilles is a tool designed for testing the security of web applications"

이 프로그램은 웹어플리케이션의 보안 테스팅을 하는데 작성되었으므로 테스팅용으로만 사용합시다

 

다운로드

http://www.mavensecurity.com/achilles

 

우선 위에서 작성한 바탕화면에 저장된 C:\Documents and Settings\Administrator\바탕 화면\client.html 를 실행한 결과를 Achilles가 Intercept한 결과입니다

여러 가지 헤더정보들이 보이며 쿠키값까지 조작할수 있습니다

하지만 위의 헤더정보에는 referer값이 없습니다 그래서 referer체크에서 null이 나와 로직에 걸립니다

그렇다면 referer정보를 추가해 줍시다


파랑색으로 줄쳐진 부분을 에디팅하여 추가해주었습니다

Referer: http://www.jakartaproject.com/html/input.html

그런다음 "Send"버튼으로 전송합니다


짠~

그러면 조작된 헤더정보를 알아채지 못하고 헤더의 referer값을 가져오는군요!

 

 

4. 서버쪽 로직 추가!

위에서 자바스크립트를 우회하는 몇가지 방법들을 알아보았습니다

결론은 하나입니다 즉! 서버쪽에서도 동일하게 체크해 주어야 합니다

 

<%@ page contentType="text/html; charset=euc-kr" %>

 

<%

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

 

if (!"POST".equals(request.getMethod())
   return;


if (request.getHeader("referer") == null)
   return;

 

if (register_no.length() != 13)

   return;
%>

 

헤더정보 <%=request.getHeader("referer")%><br><br>
주민번호 <%=register_no%>

 

그렇다면 서버쪽에서만 체크하고 클라이언트에서는 체크할 필요가 없다고 생각할지도 모르지만,

그만큼 서버쪽으로 오는 request를 줄이면 더더욱 좋겠죠

자잘한것 하나때문에 서버쪽 부하를 줄수 없는 노릇아니겠습니까?

 

자 이러이러 하고 저러저러한 이유로 우리는 이제부터라도 클라이언트에서는 자바스크립트로,

서버쪽에서는 또 서버쪽 스크립트로 사용자가 입력한 값에대해 유효성을 검증해야 하는것을 알았습니다

로직이 복잡한 경우 가뜩이나 자바스크립트도 복잡한데 그 로직을 서버쪽에서 다시한번 만든다는게 힘들다는거 다들 압니다 하지만 안전한 웹페이지를 만들기 위해 다같이 노력해야 되지 않겠습니까?

 

Web Hacking 1탄 부터 이번 3탄에 이르기까지 웹 프로그래밍 하면서 반드시 필요하고 인식해야 하는 부분에 대해 논하였습니다

마지막으로 다시한번 언급하자면 우리가 잠깐 잊고 지나가거나 혹은 귀찮아서 지나치는 사소한 부분들 때문에 엄청난 결과를 가져올 수 있다는 것입니다 미리미리 예방하고 예측해서 방지하는수 밖에 없습니다 그럼 다들 건승~!~!

 

이상 GoodBug였습니다~

Posted by 불펭

1. 시작하기

해커가 하나의 웹사이트를 공격하기 위해 많은 시간을 준비한다고 했습니다

그중에 가장 먼저 하는것 중에 하나가 바로 파라미터와 그 값에대한 목록 정리 입니다

즉 타겟 웹사이트의 모든 URL 파라미터를 GET, POST등으로 정리를 합니다

 

http://xxxxxxxx.com/pds/list1.php?cnum=2

http://xxxxxxxx.com/pds/list2.php?cnum=2&snum=21

http://xxxxxxxx.com/view.php?fnum=104591

http://xxxxxxxx.com/bbs/bbs.php?table=bbs_sw_qna

http://xxxxxxxx.com/bbs/bbs.php?f=write&table=bbs_sw_qna

http://xxxxxxxx.com/bbs/bbs.php?f=view&table=bbs_sw_qna&fid=48610&num=85973

...

 

이렇게 목록화 후 분석을 해보면 해당 파라미터가 어떤 역할을 하는지 무엇을 의미하는지 80%는 파악할 수 있습니다

bbs의 f에는 write와 view 라는 값이 주어지는것을 보니 액션에 대한 글쓰기를 할것이지 아니면 글조회를 할것인지를 나타내는것으로 보이며 table이라는 컬럼은 아마도 물리적 table이름을 말하는것 같군요

cnum은 아마도 카테고리 번호를 의미하는것이고 snum은 소카테고리번호를, num은 게시물 글번호를 의미하는것으로 추정됩니다

그럼 이 프로그램들이 어떻게 돌아가는지 대강 파악이 되고 이제부터 취약점이 있는지 체크해 나가보는겁니다

 

파라미터명이나 값에대해서는 유추할수 없이 프로그램 한다면 아마도 조금은 더 보안적으로 안전할 것입니다

 

다음은 파라미터로 적절치 않은 값을 넘겨주는 예를 알아볼 것이며, 파일 업로드, 다운로드 취약점에 대해 공부해 보겠습니다 ^^

 


2. 동적 파일 로딩 취약점

동적으로 어떤 특정 파일을 열어 그 파일 내용을 웹에서 보여주는 jsp가 있다고 합시다

대량의 html이나 txt 파일들을 읽어 웹에서 보여주는 로직들이 많지요 (저도 많이 썼습니다 -_-;)

동적으로 그 파일에 대한 정보를 파라미터로 읽어온다면 어떻게 될까요?

 

<%
String param = request.getParameter("param");


File file = new File(request.getRealPath("/")+param);

 

/* 파일 내용을 읽어 buffer에 저장 */

StringBuffer buffer = new StringBuffer();
if (file.exists()) {
    FileInputStream fis = new FileInputStream(file);
    byte b[] = new byte[1024];

    int read = 0;
    while ((read = fis.read(b)) != -1) {
        buffer.append(new String(b));
        b = new byte[1024];
    }
}

%>

파일내용

<%=buffer.toString()%>;

 

다음과 같은 요청을 보낸다면..

 

http://localhost/file.jsp?param=sample.txt

 


 

/ROOT/sample.txt  파일을 정상적으로 로딩하여 보여줄겁니다

하지만 다음과 같이 값을 준다면 어떻게 될까요?

 

http://localhost/file.jsp?param=../../../WINNT/system32/drivers/etc/services

 


 

저런 --;  시스템 파일들이 몽땅 조회가 되는군요..

 

Unix 계열이라면

http://localhost/file.jsp?param=../../../../../etc/passwd   ../ 올라가 보면서 찾아보는것도 좋겠죠 -_-

상위 디렉토리로 이동하면서 크래커는 passwd file을 볼수 있습니다

앗 여기서 다들 뜨끔 하신가요? 저만 그러나 ^^;

 

그럼 어떻게 처리해야 할까요? ../ 만 막아선 될까요?

Unix에서는 ./.\. 도 상위로 가는 명령이죠

아시겠지만 cd ./.\. 하면 한단계 위로 올라간답니다

그러니 ../ 뿐만아니라 ./.\. 도 같이 막을수 있도록 파라미터 확실히 체크를 해야 합니다

 

 

3. 동적 include 파일 취약점

그럼 include는 어떨까요? 위처럼 동적으로 include 할 파일명을 받아 처리하는 구조 말이지요

 

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

 

파일내용<br>
<jsp:include page="<%=param%>" flush="true"/>

 

http://localhost/include.jsp?param=sample.txt

라고 요청을 날렸습니다

 


 

네 정상적으로 sample.txt를 가지고 왔습니다

하지만 다음과 같은 요청이 가면 어떨까요?

 


 

네 역시나 기대를 저버리지 않고 web.xml을 기냥 출력해 버리는군요 (여기서 알아보기 쉽게 <를 나타나게 하였습니다)

문제는 /WEB-INF/ 밑에 기타 중요한 properties (데이터에비스 설정 properties)가 있다면 낭패입니다

그럼 어떻게 해야 할까요? 역시나 파라미터값을 필터링 하는수 밖에 없습니다

 

그래도 이정도면 약과 입니다 -_-;

다음을 보도록 하지요

 

JSP에서 include에는 대략 4가지 방법이 있습니다

<%@ include file="sample.jsp" %>

<jsp:include page="sample.jsp" flush="true" />

③  pageContext.include("sample.jsp")

<c:import url="sample.jsp" />

 

이 4가지가 무순 차이가 있을까요?

차이점을 쓸려다 보니 이번 강좌와 좀 동떨어지는것 같아 그건 제외하고 --;

 

문제는 동적으로 페이지가 include가 가능 하냐입니다

이점에서는 ①은 동적으로 설정이 가능하지 않으므로 안전한 include입니다 (서버측 include이니 당연합니다)

그럼 ②과 ③은 어떨까요? include할 페이지 설정이 동적으로 가능합니다

그래서 위와 같은 문제점이 있지요

하지만 ②, ③은 확장자가 jsp에만 반응을 하고 확장자가 jsp가 아닐 경우에는 그냥 텍스트로 include를 처리해 버립니다

④번은 좀 특이합니다 물론 동적으로도 가능하며 리모트로도 가능하다는 것입니다

 

<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>

...

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

<c:import url="<%=param%>"/>

...

 

http://localhost/include.jsp?param=http://www.jakartaproject.com/test.jsp

 

어떻게 될까요?

그나마 다행인것이 test.jsp 파일을 가지고 와서 서버에서 실행되는 것이 아니라 리모트에서 실행된후의 html 결과물만을 가지고 오는군요 그렇지 않으면 악성 스크립트를 활용할수있는 좋은 구멍 이었을텐데 말입니다 ^^;

 

다음표로 include 4가지 특성을 정리하였습니다

 유형

동적 실행

jsp 확장자에 반응

리모트 실행여부

<%@ include=

N

확장자에 상관없이 JSP로 실행

N

<jsp:include=

Y

확장자가 JSP만 JSP로 실행

N

pageContext.include

Y

확장자가 JSP만 JSP로 실행

N

<c:import url=

Y

확장자가 JSP만 JSP로 실행

Y

 

 

 

 

 

 

 

 

 

3. 파일 업로드 취약점

해커가 가장 많이 이용하고 좋아하는 취약점이 바로 이 파일 업로드입니다

이 부분은 누차 강조되어왔던 부분이라 대부분 아실겁니다

php 서버에는 php파일이, asp서버에는 asp파일이, jsp 서버에는 jsp파일이 업로드 되어서는 안됩니다

즉 서버에서 실행 가능한 파일을 올려선 안된다는 겁니다

 

악성 스크립트 침투 시나리오

악성 jsp 코드가 들어있는 test.jsp 파일을 글쓰기 화면을 통해 첨부 파일로 업로드 합니다

업로드 디렉토리가 /upload/ 라고 가정한다면 (업로드 디렉토리를 찾는건 그리 어렵지 않습니다)

    /upload/test.jsp 파일이 첨부파일을 통해 업로드 되었습니다

URL로 그 파일을 요청합니다  http://localhost/upload/test.jsp

    그러면 악성 코드가 들어있는 첨부파일이 웹서버에서 실행되어 버립니다

    test.jsp 파일이 서버의 파일을 모두 삭제하는 스크립트라면 큰일이지요

혹은 include 취약점을 이용해서 업로드한 스크립트를 include 시켜 실행 하기도 합니다

 

 

4. 파일 다운로드 취약점

 

간단한 jsp에서 일반적으로 사용하는 파일 다운로드 코드입니다

이역시 물리적 파일명 자체를 파라미터로 전달하고 있으며 이를 받아 파일을 다운로드 시키고 있습니다

 

<%@ page import="java.io.*"%><%

 

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

File file = new File(getServletContext().getRealPath("/upload/")+param);


response.setContentType("application/smnet");
response.setHeader("Content-Disposition", "attachment;filename=다운로드;");
response.setHeader("Content-Length", String.valueOf(file.length()));
response.setHeader("Content-Transfer-Encoding", "binary;");

 

/* 파일이 존재하면 다운로드 */

if (file.exists()) {

    byte b[] = new byte[4096];
    BufferedInputStream bin = new BufferedInputStream(new FileInputStream(file));
    BufferedOutputStream outs = new BufferedOutputStream(response.getOutputStream());
    int read = 0;
    try {
        while ((read = bin.read(b)) != -1){
            outs.write(b,0,read);
        }

    } catch (Exception e) {
        System.out.println(e.getMessage());
    } finally {
        if (bin!=null) try { bin.close(); } catch (Exception sube) {}
        if (outs!=null) try { outs.close(); } catch (Exception sube) {}
    }
}

 

무엇이 잘못되었을까요?

다음과 같이 URL을 요청해 봅시다

 

http://loalhost/download.jsp?param=../WEB-INF/web.xml

 


 

그려면 요청한 web.xml 이 다운로드 됩니다

즉 이말은 웹 어플리케이션의 모든 파일(소스)을 다운로드해 볼수 있다는 것입니다

소스를 보게 된다면 웹해킹이 물론 더 쉬워지겠지요?

 

 

5. 업로드 및 다운로드 취약점 개선 시나리오

악성 jsp 코드가 들어있는 test.jsp 파일을 글쓰기 화면을 통해 첨부 파일로 업로드 합니다

/upload/test.jsp 로 업로드 후 파일명을 변경해 버립니다

    /upload/200601171137507804462_jsp 로 변경해 버립시다

    단순히 파일명만 변경해선 안됩니다 확장자도 제거해 버려야 합니다 

    업로드 후 파일의 확장자가 두개 이상이던지, "." 이 이유없이 많다던지, "/" 나 "\" 캐릭터가 파일명에 있으면 부적절한 파일로 간주하고 지워버립시다

    그리고 200601171137507804462_jsp 명과 실제 파일명을 같이 데이터베이스에 저장합니다

URL로 그 파일을 요청합니다  http://localhost/upload/test.jsp

    당연히 파일이 존재하지 않음으로 Not Found가 나올것입니다

그럼 다음 URL로 요청해 봅시다 http://localhost/upload/200601171137507804462_jsp

    어떻게 될까요?

    jsp 코드는 실행되지 않고 text로 jsp 코드를 그냥 브라우져에 뿌리게 됩니다

    즉 아무 상관이 없다는 것입니다

    200601171137507804462_jsp 도 유저에게 보여주어서는 안됩니다

    해당 URL 조차 허용하고 싶지 않다면 아래 web.xml에 security 제한을 둡시다

   

<security-constraint>
     <display-name>JSP and Upload File Protection</display-name>
     <web-resource-collection>
         <web-resource-name>SecureFile</web-resource-name>
         <url-pattern>/upload/*</url-pattern>
         <http-method>DELETE</http-method>
         <http-method>GET</http-method>
         <http-method>POST</http-method>
         <http-method>PUT</http-method>
     </web-resource-collection>
     <auth-constraint>
         <role-name>nobody</role-name>
     </auth-constraint>
</security-constraint>

 

<security-role>
    <description>Nobody should be in this role so JSP files are protected from direct access.</description>
    <role-name>nobody</role-name>
</security-role

 

    그러면 http://localhost/upload/200601171137507804462_jsp 은 다음과 같은 메세지를 뿌립니다


 

    그리고 파일 다운로드는 직접파일 링크가 아니라 response의 ouputStream을 통해 다운로드 시킵시다

   키값을 가지고 200601171137507804462_jsp 명을 얻어 다운로드 할수 있도록 프로그램 해야 합니다

   즉 다운로드 시킬때도 물리적 파일명을 파라미터로 전달하지 말고 해당 키값을 전달해서 파일명을 데이터베이스에서 얻어오도록 합니다

 

ps. 이런 취약점 때문만은 아니겠지만 업로드한 파일을 파일 시스템으로 저장하지 않고 데이터베이스에 직접 저장하기도 합니다

 

 

6. SQL Injection으로 인한 결과물을 파일로저장하여 다운받아 볼 수 있습니다

앞에서 살펴본 SQL Injection을 예를들어봅시다

아래 코드는 게시물 번호를 파라미터로 입력받아 해당 글번호를 조회하는 코드입니다

아래와 같은 코드가 있다고 한다면 UNION SQL Injection 피해를 볼수 있다고 하였습니다

 

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

rs = stmt.executeQuery("SELECT boardno, boardtitle, boardcontent FROM board_test_t WHERE boardno = "+boardno);
    if (rs.next()) {
        out.println(rs.getString(1)+"<br>");
        out.println(rs.getString(2)+"<br>");
        out.println(rs.getString(3)+"<br>");
}

 

데이터베이스가 MySQL 이라고 한다면 URL 요청이 다음과 같다면 어떻게 될까요?

 

http://localhost:8080/test.jsp?boardno=1133971825719 UNION SELECT '1', userid, userpw FROM user_t INTO OUTFILE 'C:/Tomcat/webapps/ROOT/upload/hack.txt'

 

다음과 같이 에러 메세지가 납니다 하지만.. hack.txt란 파일은 생성이 됩니다

즉 user의 모든 아아디 비밀번호를 간편하게 파일로 다운받아 보는겁니다


HTTP Status 500 -

type Exception report

message

description The server encountered an internal error () that prevented it from fulfilling this request.

exception org.apache.jasper.JasperException org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:372) org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:292) org.apache.jasper.servlet.JspServlet.service(JspServlet.java:236) javax.servlet.http.HttpServlet.service(HttpServlet.java:802) com.jakartaproject.util.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:28)

root cause java.lang.NullPointerException org.apache.jsp.test_jsp._jspService(test_jsp.java:64) org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:94) javax.servlet.http.HttpServlet.service(HttpServlet.java:802) org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:324)

 

그 다음 http://localhost:8080/upload/hack.txt 로 user_t 테이블에 있는 모든 사용자아이디와 비밀번호를 텍스트로 받아볼 수 있습니다. 아마 이방식으로 유저 아뒤/비번 많이 빼내신분들 많으실 겁니다 ㅎㅎ

 

톰캣 설치 경로는 어떻게 알까요?

톰캣설치경로 대부분 비슷할 겁니다 몇가지 해보면 금방 알수 있습니다

 

 

7. 마무리

그렇다면 어떻게 해야 이러한 피해를 최소화 할 수 있을까요? 나름데로 생각해 보았습니다

 

파라미터와 파라미터값에 대해 알아볼 수 없도록 최소한의 의미만 부여한다!!

   역시나 파라미터가 중요합니다 누구나 알아볼 수 있도록 하는 의미보다는 나름데로

   Naming rule을 정한다든지 암호화 하든지 하는것도 바람직 할 수 있다고 봅니다

 

파라미터값이 유효한 값인지 체크해 봅니다

   파라미터값을 최대값, 최소값으로 제한하고 꼭 있어야 하는 문자열이나 꼭 없어도 되는 문자열등을 체크합니다

   파라미터값 길이또한 최대, 최소값 제한을 둡니다

 

중요한 파라미터 값은 (파일명같은..)  절대로 받지 않고 다른 로직으로 생각해 봅시다

    파일명같은 중요한 값은 데이터베이스에 입력해 놓고 키값을 파라미터로 전달받아 파일명을 조회한 후 사용합니다

 

웹프로그램의 취약점 분석 툴들이 찾아보면 몇개 있습니다(대부분 유로더군요) 이를 이용하여 테스트해 봅니다

 

 

두서없이 생각나는데로 적었습니다

그나마 JSP는 다른 PHP나 ASP에 비해 상당히 보안에 안정적입니다 JDBC 마다 틀리겠지만요

해결 방법이 생각해 보면 더 많을겁니다 물론 서버단에서 막는 방법이 제일 좋겠지만요 몇가지 사례를 적어놓았으니 그다음은 응용하기에 달렸지요

방어는 이제 여러분 몫입니다 ㅡ0ㅡ; 

 

뚫느냐 뚫리느냐 그것이 문제로다~

Posted by 불펭

Web Hacking 1탄 SQL Injection

Web Hacking 2탄 파일조작

Web Hacking 3탄 구멍난 자바스크립트 

1. 시작하기

가끔 뉴스나 방송에서 xx 사이트 해킹 당했다 라고들 많이 들어보았을 겁니다

이런 뉴스를 접할때 대체 어떻게 해서 해킹이 당하는걸까? 라고들 많이 생각해 보았을 겁니다

어떻게 해킹이 일어나는지 알아야 방어도 가능하기 때문에 이번 강좌는 웹해킹에 대해 알아볼 것입니다

 

첫번재 시간으로 SQL Injection을 배울 것이며 그다음 두번째에는 파일조작으로 인한 해킹을,

그리고 마지막 시간에는 자바스크립트 조작에 대해 알아보겠습니다

 


 

도표에서도 알수 있듯이 SQL Injection으로 인한 해킹이 가장 간단하고 쉽기 때문에

이를 가장먼저 알아보겠습니다

 

SQL Injection 이란 서버나 OS의 구멍을 이용한 해킹방법이 아닌 웹 어플리케이션 자체의 버그를

이용한 새로운 형태의 웹해킹 방법입니다

 

정의를 하자면

 

SQL Injection은 웹페이지를 통해 입력된 파라미터값을 이용하여 쿼리를 재구성하는 방법이다

 

라고 할수 있습니다

 

즉 많은 웹페이지들은 사용자나 프로그램이 생성한 파라미터값을 이용해 쿼리를 만들고 실행하는데,

이때 정상적인 값이 아닌 파라미터값이 입력될 때 비정상적인 쿼리가 실행되며, 따라서

원하지 않는 결과가 나올수 있다는 것입니다

 

이해를 위해 바로 코드로 들어가 봅시다

아래 코드는 사용자가 입력한 로그인 아이디와 비밀번호로 로그인을 시도하는 로직입니다

 

// 입력받은 사용자 아이디와 비밀번호

String param1 = request.getParameter("user_id");

String param2 = request.getParameter("user_pw");

 

rs = stmt.executeQuery("SELECT count(*) FROM user_t WHERE userid = '"+param1+"' AND userpw = '"+param2+"'");

rs.next();

if (rs.getInt(1) == 1) {

   // 로그인 성공로직

} else {

   // 로그인 실패로직

}

 

 

무엇이 잘못되었을 까요?

코드상으로 보면 실행하는데 전혀 이상이 없는 코드이지만 쫌 아는사람들에게는 비밀번호 없이

아이디만 안다면 로그인을 성공할 수 있는 로직입니다

 


 

아아디가 goodbug 이고 비밀번호가 1111 인 계정이 있다고 합시다 ^^;

입력란에 googbug / 1111 을 입력하니 정상적으로 로그인이 true가 되었습니다

하지만 만약 다음과 같이 사용자가 입력한다면 어떻게 될까요?

 


 

로그인이 됩니다!

비밀번호에 상관없이 로그인이 되는군요!!

하다 더 보도록 하지요

 


 

위의 소스는 MySQL을 사용하고 있습니다

MySQL의 라인 주석처리는 # 입니다 아시죠?

 

즉 뒷부분 password를 체크하는 로직은 주석처리되어 버린겁니다 뜨아~

 

같은 의미이지만 아래처럼 여러가지 섞어서도 가능합니다


 

이게 만약 관리자 아이디였다면 문제는 더 심각해 집니다

 

이처럼 사용자의 고의로 인한 SQL을 조작하여 웹 어플리케이션 자체를 공격하는것이 SQL Injection 입니다

 

그렇다면 위의 소스를 어떻게 변경하는게 좋을까요?

 

// 입력받은 사용자 아이디와 비밀번호

String param1 = request.getParameter("user_id");

String param2 = request.getParameter("user_pw");

 

//validate 라는 함수는 아이디와 비밀번호 생성시 생성 로직에 맞게 되었는지 체크하는 함수

//만약 특수문자나 아이디 생성 규칙에 맞지 않는 값이면 exception을 throw 한다

validateID(param1); 

validatePW(param2);

 

pstmt = conn.prepareStatement("SELECT userid, userpw FROM user_t WHERE userid = ?");

pstmt.setString(1, param1);

rs = pstmt.executeQuery();

if (rs.next()) {

    // 문자를 직접 비교한다 (대소문자 구분)

    if (rs.getString(1).equals(param1) && rs.getString(2).equals(param2)) {

         // 로그인 성공로직

    } else {

        // 로그인 비밀번호 혹은 아이디 오류 로직

    }

} else {

    //로그인 부재 아이디 오류 로직

}

위처럼 하면 어느정도 되겠네요 ^^

 

 

2. SQL Injection 패턴

 

그럼 SQL Injection에 사용될만한 문자열에는 어떤것이 있을까요?

 

아래 문자들은 해당 데이터베이스에따라 달라질 수 있습니다

문자

설명

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

 

일반적으로 알려진 몇가지 패턴입니다


' or 1=1--

" or 1=1--

or 1=1--

' or 'a'='a

" or "a"="a

') or ('a'='a

' or password like '%

 

이러한 패턴들로 타겟 데이터베이스가 오라클인지 MySQL인데 혹은 M$SQL인지 확인할 필요가 있을겁니다. 왜냐하면 그것에 따라 다양한 공격 방법이 생기기 때문입니다

그럼 이러한 구분은 그럼어떻게 할까요?

 

SQL Injection을 이용하여 다음값이 true인지 false인지 확인합니다

AND 'abcd' = 'ab' + 'cd'

true 이면 오라클은 아닐겁니다 오라클은 ||을 문자열 concat 으로 사용하지요

 

AND 'abcd' = 'ab' || 'cd'

true 이면 오라클입니다

rownum 도 구분할수 있는 좋은 예입니다

 

MySQl은 라인 주석이 #입니다 다른 대부분 데이터베이스는 --를 사용하지요

#을 SQL Injection 하였을때 위의 예처럼 에러가 발생하지 않으면 MySQL입니다

또 limit 등도 도움이 될겁니다

 

이처럼 해당 데이터베이스가 고유하게 사용하는 key들을 SQL Injection하여 구분할 수 있습니다

 

 

3. UNION SQL Injection

 

위와같이 WHERE절에 SQL Injection을 사용하여 조건절을 무력화 시키는 방법도 있지만

UNION SQL Injection은 원하는 정보도 뽑아볼 수 있습니다 ^^V

 

코드로 바로 봅시다

아래 코드는 게시물번호를 파라미터로 받아 해당 게시물이 존재하면 글번호와 글제목, 글내용을 조회하는 코드입니다

 

String param1 = request.getParameter("boardno");

 

rs = stmt.executeQuery("SELECT boardno, boardtitle, boardcontent FROM board_t WHERE boardno = '"+param1+"'");

if (rs.next()) {

    out.println(rs.getString(1)+"<br>");

    out.println(rs.getString(2)+"<br>");

    out.println(rs.getString(3)+"<br>");

}

 

무엇이 잘못되었을까요?


 

글번호가 1134896409234 인 게시물은 다음과 같이 URL이 요청되어 조회가 될겁니다

요청 URL

/read.jsp?bno=1134896409234

 

하지만 위와 같이 추가적으로 UNION SQL Injection이 들어갈 수 있습니다

/read.jsp?bno=1134896409234' UNION SELECT '1', userid, userpw FROM user_t WHERE userid = 'goodbug'  ORDER BY boardno ASC #

 

그러면 goodbug라는 아이디의 비밀번호가 그만 조회되어 버립니다!!

그럼 user_t 라는 테이블과 ,userid, userpw라는 컬럼명들은 어떻게 알수 있을까요?

 

오라클 이라면 다음과 같이 알아낼 수 있습니다

/read.jsp?bno=1134896409234' UNION SELECT '1', tname, '' FROM user_tables WHERE like '%user%' ORDER BY boardno ASC --

 

테이블 명을 알아냈다면 이제 컬럼명을 알아봐야겠죠

오라클이라면 user_tab_columns view를 통해 알아볼 수 있습니다

SELECT * FROM user_tab_columns WHERE table_name = 'user_t'

 

물론 한번에 알아낼수 없으며 많은 시행착오를 겪어야 하는것은 필수입니다

그래서 제로보드나 Unicorn 같은 공개 게시판인 경우는 타겟이 되기 쉽상입니다

 

MySQl이나 Oracle JDBC에서는 다행히도 ; 문자를 이상 캐릭터로 보고 에러를 반환합니다

하지만 그렇지 않은 JDBC가 있따면 큰일입니다 아래와 같은 코드가 가능하기 때문이지요

 

/read.asp?bno=1134896409234';DELETE FROM user_t

/read.asp?bno=1134896409234';UPDATE user_t SET userpw = '1111'

 

PHP나 ASP인 경우에는 가능한 쿼리 입니다

이제 대강 SQL Injection에 대해 감이 잡히시나요?

 

 

4. 에러 메세지를 통한 정보수집

 

admin_login 이라는 관리자 테이블과 login_name이라는 컬럼을 알아 냈다고 한다면..

M$SQL인 경우를 예를 들겠습니다

 

/read.asp?id=10 UNION SELECT TOP 1 login_name FROM admin_login--

 

Output:

Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value 'goodbug' to a column of data type int.
/read.asp, line 5

라는 메세지가 나옵니다

여기서 무순 정보를 알수 있을까요? 바로 goodbug 라는 관리자 아이디가 있다는 것을 알았습니다

그럼 여참에 비밀번호까지 알아봅시다

 

/read.asp?id=10 UNION SELECT TOP 1 password FROM admin_login where login_name='goodbug'--

 

Output:

Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value '1111' to a column of data type int.
/read.asp, line 5

 

즉 nvarchar 타입의 컬럼을 int형으로 convert를 유도하면서 해당값을 에러메세지로부터 취득할 수 있습니다

 

가능하면 에러 메세지는 일반 유저에게 뿌리지 말아야 겠지요?

 

 

5. 그렇다면 막아보자 SQL Injection

 

해커라고 컴퓨터 한두번 두둘겨서 어느 한 사이트를 뚝딱 해킹하지는 못합니다

웹 해킹을 하기 위해서는 보통 짧으면 일주일에서 길면 몇달까지 해커는 치밀한 준비를 한다고 합니다

웹페이지들이 전달하는 모든 파라미터를 조사하고 반복되는 에러 화면을 보면서

여러 패턴별로 치밀하게 조사후 시행을 한다고 하네요

 

그렇다면 어떻게 이들로부터 웹 어플리케이션을 보호할 수 있을까요?

다음과 같은 원칙을 지킨다면 이러한 SQL Injection을 사전에 방지할 수 있습니다

 

프로그래머의 적극적인 의지가 있어야 합니다!

   -. 여러가지 신경써야 할곳도 많고 입력값에 대한 체크로직 또한 늘어날 것입니다

       많은 귀차니즘이 생길겁니다

       머 누가 장난치겠어? 라는 생각이 많은 빵꾸를 만듭니다

 

 사용자가 직접 입력하는 파라미터는 절대 신뢰하지 않아야 합니다!

   -.  입력값은 javascript 뿐만 아니라 서버측에서도 체크를 해야 합니다

        숫자만 받은 입력칸이면 반드시 javascript 체크와 동시에 서버측에서도 숫자만 입력되었는지 체크해야 합니다

   -. 필요하다면 특수문자는 필터링해 버립시다 ( ‘ “ / \ : ; Space < > )

   -. 또 가능하다면 SQL 명령도 필터링 해버립시다 (UNION, SELECT, DELETE, INSERT, UPDATE, DROP..)

 

사용자 입력을 받아 SQL을 작성하는 부분은 반드시 PreparedStatement를 사용하여 바인딩 처리 합니다!!

   -. PreparedStatement는 SQL Injection을 원천적으로 봉쇄합니다

   -. 꼬~옥 필요한곳만 Statement를 사용합니다

 

웹에서 사용하는 유저는 OS계정 뿐만 아니라 데이터베이스 계정또한 가능한 권한을 낮춥니다!!

 

에러 메세지를 노출하지 않습니다!! 

   -. 에러 메세지는 해커들에게 많은 정보를 제공해 줍니다

       가능하면 유저에게 알리지 말고 은밀하게 보관해야 합니다

 

동적 SQL은 가능하면 생성하지 않는다!!

   -. 가능한 동적 SQL은 지양하며, 비지니스로직상 동적 SQL이 어쩔수 없다면 파라미터 검사를 충분히 해야한다

 

많은분들이 아시는 내용이지만 처음보시는분에겐 많은 도움이 되실겁니다 ^^

Posted by 불펭

553 Could not create file.

ftp 업로드 할때 발견한 에러이다.

업로드 하려는 해당 디렉토리의 소유권과 관련된에러인데  ftp 클라이언트 측에서 접속한 ID 와

접속한 디렉토리의 소유자및 소유그룹이 다를경우 발생한다.

chown 명령을 통해 동일하게 변경하면 해결.

selinux 관련해서도 발생할수있다고하는데 selinux 는 넘 어렵다 ;;

보통 disable 해서 쓰니 패스 ㅋ

위경우에도 해결안될시

553 Could not create file.

  

# setsebool  -P ftpd_disable_trans 1

# /etc/init.d/vsftpd restart

Posted by 불펭