21 9월

find 명령으로 오래된 파일찾기

find 명령으로 오래된 파일을 찾아본다

현재위치에서 *.txt파일중 30일이 지난 파일을 출력

# find . -name “*.txt” -type f  -ctime +30 -print

현재위치에서 30일이 지난 모든 파일을 삭제

# find . -type f -ctime +30 | xargs rm

현재위치에서 30일이 지난 모든 디렉토리를 삭제

# find . -type d -ctime +30 | xargs rm -rf

현재 위치에서 7일안에 생성된 파일을 출력

# find . -type f -ctime -7 -print

 

옵션설명

-type f(파일) d(디렉토리) l(링크)

-ctime : 생성시간

-mtime : 수정시간

-atime : 접근시간

 

100kb이상인 파일을 출력

# find . type f -size +100k -print

12 9월

fail2ban – 워드프레스 로그인 차단 (wp-login.php)

워드프레스 악의적인 로그인 차단

fail2ban 을 이용하여 워드프레스(https://wordpress.org/) 로그인 페이지를 안전하게 해보자

1

어느날 갑자기 무차별대입공격(brute force attack)으로 로그가 엄청나게 늘어나 버렸다.

워드프레스에 Wordfence 플러그인이 설치되어 있었지만 차단해주지는 못했다.

때문에 로그파일을 읽어 방화벽(iptables)에 등록해주는 fail2ban 을 이용하여 직접 방어해본다.

 

기본환경

ubuntu 14.04에 apache2가 설치되어 있다.

 

fail2ban 설치하기

fail2ban은 지정된 로그파일을 모니터링하면서 정규식을 이용, 특정패턴을 읽는다. 패턴이 일정이상 반복되면 bantime (초) 만큼 방화벽에 아이피를 등록하여 차단한다.

우분투 패키지매니저를 통한 설치

#sudo apt-get install fail2ban

소스설치

https://github.com/fail2ban/fail2ban 에서 소스파일을 다운로드한다.

로그파일 확인

워드프레스의 로그인 파일(wp-login.php)에 접근한 로그를 확인하기 위해 아파치 로그폴더를 확인해 본다

# cat /var/log/apache2/access.log | grep wp-login.php

91.200.12.42 – – [12/Sep/2016:02:02:49 +0900] “POST /wp-login.php HTTP/1.1” 200 5527 “http://jongwan.com/wp-login.php” “Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; 125LA; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)”
91.200.12.42 – – [12/Sep/2016:02:03:07 +0900] “POST /wp-login.php HTTP/1.1” 200 5527 “http://jongwan.com/wp-login.php” “Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; 125LA; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)”
91.200.12.42 – – [12/Sep/2016:02:03:14 +0900] “POST /wp-login.php HTTP/1.1” 200 5527 “http://jongwan.com/wp-login.php” “Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; 125LA; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)”
91.200.12.42 – – [12/Sep/2016:02:03:25 +0900] “POST /wp-login.php HTTP/1.1” 200 5527 “http://jongwan.com/wp-login.php” “Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; 125LA; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)”
91.200.12.42 – – [12/Sep/2016:02:03:37 +0900] “POST /wp-login.php HTTP/1.1” 200 5527 “http://jongwan.com/wp-login.php” “Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; 125LA; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)”

wp-login.php 파일에 수초간격으로 계속 접근을 시도한 것을 확인할 수 있다.

 

fail2ban 룰 작성

fail2ban에서 사용하는 failregex 라는 룰을 작성한다. 로그파일을 확인해 보면 아래와 같이 작성할 수 있다.

^<HOST> .* “POST /wp-login.php

 

룰 파일을 생성

fail2ban 은 기본적으로 /etc/fail2ban 에 설치된다.

# vim /etc/fail2ban/filter.d/wordpress-login.php

파일 내용은 아래와 같다


[Definition]
failregex = ^<HOST> .* "POST /wp-login.php
ignoreregex =

 

jail.conf 에 룰을 등록

룰을 생성했드면 jail.conf 에 해당 룰을 등록해 줄 수 있다. /etc/fail2ban/jail.conf 파일을 열어 마지막줄에 아래 내용을 추가해준다.

# vim /etc/fail2ban/jail.conf


[wp-auth]
enabled = true
filter = wordpress-login
action = iptables-multiport[name=NoAuthFailures, port="http,https"]
logpath = /var/log/apache2/*access*.log
bantime = 1200
maxretry = 8

fail2ban 룰 테스트

fail2ban은 아래와 같은 명령을 이용해서 룰을 확인할 수 있다.

#fail2ban-regex /var/log/apache2/access.log /etc/fail2ban/filter.d/wordpress-login.conf

 

fail2ban 재시작

#service fail2ban restart

07 9월

NCDU – 리눅스에서 폴더별 용량 확인

NCDU

우분투에서 폴더의 사용량을 확인하기 위해 항상 du 명령어를 사용했었다.

간단하게 사용이 가능하지만 한눈에 알아보기 힘든 UI로 인해서 고민하다 비주얼하게 출력해주는 프로그램을 하나 만들어 볼까?? 하던차에 구글링을 해보니, 이미 많이 사용되는 프로그램이 있어 소개해본다

일단 콘솔에서 확인해야 하기에 바오밥(https://en.wikipedia.org/wiki/Disk_Usage_Analyzer) 의 경우 X윈도우가 필요하니 패스~

NCDU 설치방법

NCDU를 사용하기 위해서 우분투기준 아래와 같이 설치를 진행한다

#apt-get install ncdu
#ncdu /

실행하고 한참 탐색을 진행하다 마치면 아래와 같은 화면이 나온다. 폴더별로 사용량이 깔끔하게 출력된다.

NCDU 스크린샷1

NCDU 스크린샷2

 

02 9월

jquery datepicker 한글화

<link rel="stylesheet" href="http://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="http://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<script>
jQuery(function($) {
  $.datepicker.regional['ko'] = {
    closeText : '닫기',
    prevText : '이전달',
    nextText : '다음달',
    currentText : '오늘',
    monthNames : ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'],
    monthNamesShort : ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'],
    dayNames : ['일', '월', '화', '수', '목', '금', '토'],
    dayNamesShort : ['일', '월', '화', '수', '목', '금', '토'],
    dayNamesMin : ['일', '월', '화', '수', '목', '금', '토'],
    weekHeader : 'Wk',
    dateFormat : 'yy-mm-dd (DD)',
    firstDay : 0,
    isRTL : false,
    showMonthAfterYear : true,
    yearSuffix : '년'
  };

  $.datepicker.setDefaults($.datepicker.regional['ko']);
});

$(document).ready(function(){
  $(".datepicker").datepicker();
});
</script>

 

03 8월

업로드 디렉토리에서 웹쉘 php 실행 방지(webshell)

업로드 디렉토리에서 아래 명령을 실행

# find . -type f | xargs grep -n “eval(”

웹쉘파일

파일은 gif형식인데 내용에는 php 코드가 들어있다.

POST로 데이터를 전송하면 eval() 명령으로 실행이 된다.

위와 같은 상황처럼 이미지에 들어있는 php코드가 실행이 되는 것을 방지하지 위해서

아예 업로드 디렉토리는 php파싱을 하지 않도록 하는 방법을 안내한다

 

/etc/httpd/conf/httpd.conf


<VirtualHost *:80>

...

<Directory /home/web/public_html/data>
php_admin_value engine Off
</Directory>

...

</VirtualHost>

18 7월

Solr 검색엔진을 데몬으로 등록 (update-rc.d)

Apache Solr 를 사용하는중에 시스템이 재부팅되면 다시 시작하는게 귀찮아서

구글링을 해보니 데몬으로 등록하는 방법이 있어 스크랩한다.

 

데몬설치

# sudo su

# apt-get install daemon

 

시작스크립트 생성

# cd /etc/init.d/

# cat > solr

#!/bin/sh

# Prerequisites:
# 1. Solr needs to be installed at /usr/local/solr/example
# 2. daemon needs to be installed
# 3. Script needs to be executed by root

# This script will launch Solr in a mode that will automatically respawn if it
# crashes. Output will be sent to /var/log/solr/solr.log. A pid file will be 
# created in the standard location.

start () {
    echo -n "Starting solr..."

    # start daemon
    daemon --chdir='/usr/local/solr/example' --command "java -jar start.jar" --respawn --output=/var/log/solr/solr.log --name=solr --verbose

    RETVAL=$?
    if [ $RETVAL = 0 ]
    then
        echo "done."
    else
        echo "failed. See error code for more information."
    fi
    return $RETVAL
}

stop () {
    # stop daemon
    echo -n "Stopping solr..."

    daemon --stop --name=solr  --verbose
    RETVAL=$?

    if [ $RETVAL = 0 ]
    then
        echo "done."
    else
        echo "failed. See error code for more information."
    fi
    return $RETVAL
}


restart () {
    daemon --restart --name=solr  --verbose
}


status () {
    # report on the status of the daemon
    daemon --running --verbose --name=solr
    return $?
}


case "$1" in
    start)
        start
    ;;
    status)
        status
    ;;
    stop)
        stop
    ;;
    restart)
        restart
    ;;
    *)
        echo $"Usage: solr {start|status|stop|restart}"
        exit 3
    ;;
esac

exit $RETVAL

# update-rc.d solr defaults

중간에 solr가 설치되어 있는 폴더를 변경해줘야 한다.

 

logrotate 등록

# cd /etc/logrotate.d
# cat > solr

/var/log/solr/*.log {
  weekly
  rotate 12
  compress
  delaycompress
  create 640 root root
  postrotate
    /etc/init.d/solr restart
  endscript
}

 

17 11월

윈도우 방화벽 규칙 추가/삭제 – C#

방화벽 관련해서 참고는 구글링 웹문서들과 mdsn
https://msdn.microsoft.com/ko-kr/library/windows/desktop/aa365344(v=vs.85).aspx
https://msdn.microsoft.com/en-us/library/windows/desktop/ff956124(v=vs.85).aspx

c#에서 방화벽에 규칙을 추가하는 방법을 찾던중에
쉽게 할 수 있는 방법이 있어 해당 코드를 안내합니다.

참조추가
FirewallAPI.dll 파일을 참조로 추가합니다.

규칙추가

INetFwRule firewallRule = (INetFwRule)Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FWRule"));
firewallRule.Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW;
firewallRule.Description = "방화벽 규칙에 대한 설명을 입력합니다";
firewallRule.Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN;
firewallRule.ApplicationName = Application.ExecutablePath + @"\app.exe";
firewallRule.InterfaceTypes = "All";
firewallRule.Name = "Rule name"; // 방화벽 규칙을 구분하는 이름, 삭제시에도 사용됩니다
firewallRule.Enabled = true;

INetFwPolicy2 firewallPolicy = (INetFwPolicy2)Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FwPolicy2"));
firewallPolicy.Rules.Add(firewallRule);

규칙삭제

INetFwPolicy2 firewallPolicy = (INetFwPolicy2)Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FwPolicy2"));
firewallPolicy.Rules.Remove("Rule name");

기존에 추가된 방화벽 규칙을 확인

INetFwPolicy2 firewallPolicy = (INetFwPolicy2)Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FwPolicy2"));
foreach(INetFwRule rule in firewallPolicy.Rules)
{				
	Console.WriteLine(rule.Name);
}
23 7월

C#, PHP – RIJNDAEL 256bit 암/복호화

C#과 php간에 데이터를 주고 받아야 하는데
평문으로 통신하기에 무리가 있던 도중
기존에 사용하던 php 암호화 라이브러리와 연동되는 c# 코드를 발견~
살짝 수정해서 사용하는데 무리가 없음

기본은 128bit지만 256bit로 변경했음
php의 경우 블록에서 남는 부분을 zero로 채워넣기 때문에
c#에서 PaddingMode.Zeros를 설정해야 정상적으로 동작합니다.

Encryption.cs

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace TestClass
{
    class Encryption
    {
        private static byte[] rijnKey = Encoding.UTF8.GetBytes("abcdefg_abcdefg_");
        private static byte[] rijnIV = Encoding.UTF8.GetBytes("abcdefg_");

        public static String EncryptIt(String s)
        {
            String result;
            RijndaelManaged rijn = new RijndaelManaged();
            rijn.Mode = CipherMode.ECB;
            rijn.Padding = PaddingMode.Zeros; // php와의 연동에서 꼭 확인
            rijn.BlockSize = 256;

            using (MemoryStream msEncrypt = new MemoryStream())
            {
                using (ICryptoTransform encryptor = rijn.CreateEncryptor(rijnKey, rijnIV))
                {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                        {
                            swEncrypt.Write(s);
                        }
                    }
                }
                result = Convert.ToBase64String(msEncrypt.ToArray());
            }
            rijn.Clear();

			result = Base64UrlEncode(result);

			return result;
        }

        public static String DecryptIt(String s)
        {
            String result;
            RijndaelManaged rijn = new RijndaelManaged();
            rijn.Mode = CipherMode.ECB;
            rijn.Padding = PaddingMode.Zeros;
            rijn.BlockSize = 256;

            s = Base64UrlDecode(s);

            using (MemoryStream msDecrypt = new MemoryStream(Convert.FromBase64String(s)))
            {
                using (ICryptoTransform decryptor = rijn.CreateDecryptor(rijnKey, rijnIV))
                {
                    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader swDecrypt = new StreamReader(csDecrypt))
                        {
                            result = swDecrypt.ReadToEnd();
                        }
                    }
                }
            }
            rijn.Clear();

            return result;
        }

        public static string Base64UrlEncode(string arg)
        {
            arg = arg.Split('=')[0]; // Remove any trailing '='s
            arg = arg.Replace('+', '-'); // 62nd char of encoding
            arg = arg.Replace('/', '_'); // 63rd char of encoding
            return arg;
        }

        public static string Base64UrlDecode(string arg)
        {
            string s = arg;
            s = s.Replace('-', '+'); // 62nd char of encoding
            s = s.Replace('_', '/'); // 63rd char of encoding
            switch (s.Length % 4) // Pad with trailing '='s
            {
                case 0: break; // No pad chars in this case
                case 2: s += "=="; break; // Two pad chars
                case 3: s += "="; break; // One pad char
                default:
                    throw new System.Exception("Illegal base64url string!");
            }
            return s;
        }
    }
}

test.php

&amp;lt;?php
//Encryption function
function encryption($encrypt, $key, $iv)
{
    $td = mcrypt_module_open(MCRYPT_RIJNDAEL_256, '', MCRYPT_MODE_ECB, '');
    mcrypt_generic_init($td, $key, $iv);
    $encrypted = mcrypt_generic($td, $encrypt);
    $encode = base64_encode($encrypted);
    mcrypt_generic_deinit($td);
    mcrypt_module_close($td);

	return $encode;
}


//Decryption function
function decryption($decrypt, $key, $iv)
{
    $decoded = base64safeDecode($decrypt);
    $decoded = base64_decode($decoded);
    $td = mcrypt_module_open(MCRYPT_RIJNDAEL_256, '', MCRYPT_MODE_ECB, '');
    mcrypt_generic_init($td, $key, $iv);
    $decrypted = mdecrypt_generic($td, $decoded);
    mcrypt_generic_deinit($td);
    mcrypt_module_close($td);

    return trim($decrypted);
}

function base64safeDecode($data) {
	$data = str_replace("-", "+", $data);
	$data = str_replace("_", "/", $data);

	switch (strlen($data) % 4) {
		case 0: break;
		case 1: $data .= "=="; break;
		case 2: $data .= "="; break;
	}

	return $data;
}

$key = "abcdefg_abcdefg_";
$iv = "abcdefg_";

echo encryption("Hello world!", $key, $iv);
echo decryption("1ERpu8RaiyMqsXdjhCEu9IVMyQlz/A3fBR6vGbNxaVs=", $key, $iv);
?&amp;gt;
13 4월

tcpdump

tcpdump

# tcpdump [ -AdDefIKlLnNOpqRStuUvxX ][ -B buffer_size ][ -c count ][ -C file_size ][ -G rotate_seconds ][ -F file ][ -i interface ][ -m module ][ -M secret ][ -r file ][ -s snaplen ][ -T type ][ -w file ][ -W filecount ][ -E spi@ipaddr algo:secret,… ][ -y datalinktype ][ -z postrotate-command ][ -Z user ]

# tcpdump -i eth0=> 인터페이스 eth0 을 보여줌

# tcpdump -w tcpdump.log=> 결과를 파일로 저장, txt 가 아닌 bin 형식으로 저장됨

# tcpdump -r tcpdump.log=> 저장한 파일을 읽음

# tcpdump -i eth0 -c 10=> 카운터 10개만 보여줌

# tcpdump -i eth0 tcp port 80=> tcp 80 포트로 통신하는 패킷 보여줌

# tcpdump -i eth0 tcp port 80=> tcp 80 포트로 통신하는 패킷 보여줌

# tcpdump -i eth0 src 192.168.0.1=> source ip 가 이것인 패킷 보여줌

# tcpdump -i eth0 dst 192.168.0.1=> dest ip 가 이것인 패킷 보여줌

 

and 옵션으로 여러가지 조건의 조합 가능

# tcpdump -i eth0 src 192.168.0.1 and tcp port 80=> source ip 가 이것이면서 tcp port 80 인 패킷 보여줌

# tcpdump -i eth0 dst 192.168.0.1=> dest ip 가 이것인 패킷 보여줌

# tcpdump host 192.168.0.1=> host 를 지정하면, 이 ip 로 들어오거가 나가는 양방향 패킷 모두 보여줌

# tcpdump src 192.168.0.1=> host 중에서 src 가 이것인것 만 지정

# tcpdump dst 192.168.0.1=> host 중에서 dst 가 이것인것 만 지정

# tcpdump net 192.168.0.1/24=> CIDR 포맷으로 지정할 수 있다.

# tcpdump tcp=> TCP 인것만

# tcpdump udp=> UDP 인것만

# tcpdump port 3389=> 포트 양뱡항으로 이것인것.

# tcpdump src port 3389=> src 포트가 이것인것.

# tcpdump dst port 3389=> dst 포트가 이것인것.

 

combine : and ( && ) , or ( || ) , not ( ! ) 으로 여러가지를 조합해서 사용 가능

# tcpdump udp and src port 53=> UDP 이고 src 포트가 53 인 것

# tcpdump src x.x.x.x and not dst port 22=> src ip 가 x.x.x.x 이고 dst 포트가 22 가 아닌 것

 

grouping : ( )

# tcpdump ‘src x.x.x.x and ( dst port 3389 or 22 )’=> src ip 가 x.x.x.x 이고 ( dst 포트가 3389 또는 22 ) 인 것  ==> 여기서는 ‘ ‘ 가 반드시 있어야 한다.

12 3월

screw 로 php 소스코드 암호화

php_screw 설치

php_screw 설치하기를 참고하여 php_screw.so를 익스텐션에 올린다

 

screw 컴파일

php_screw 소스를 압축해제한 디렉토리에 tools가 있다
cd tools
make

screw 컴파일

실행파일을 접근가능한 디렉토리로 복사해준다. 여기서는 /usr/bin/ 으로 복사했다
cp screw /usr/bin

 

php 파일 암호화

테스트할 파일을 만든다
echo "" > phpinfo.php

암호화한다
screw phpinfo.php

php_screw

위에처럼 phpinfo.php, phpinfo.php.screw 파일이 생성된다
phpinfo.php 는 암호화 되었고
phpinfo.php.screw 는 원본파일이다