Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
o365enum — ActiveSync, Autodiscover v1 또는 office.com 로그인 페이지를 사용하여 Office 365에서 유효한 사용자 이름을 열거합니다. | Kitploit
도구/GitHubGitHub/gremwell/o365enum
OSINT (Open Source Intelligence)ReconnaissanceInformation GatheringWeb Security
GitHubgremwell/o365enum

o365enum

ActiveSync, Autodiscover v1 또는 office.com 로그인 페이지를 사용하여 Office 365에서 유효한 사용자 이름을 열거합니다.

저장소 보기웹사이트
301432년 전Kitploit 검토 완료

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

Office 365 사용자 열거

ActiveSync, Autodiscover 또는 office.com 로그인 페이지를 사용하여 Office 365에서 유효한 사용자 이름을 열거합니다.

사용법

o365enum은 첫 번째 매개변수로 제공된 파일에서 사용자 이름을 읽습니다. 파일은 한 줄에 하나의 사용자 이름을 포함해야 합니다. 출력은 CSV 기반으로 구문 분석이 쉽습니다. 유효 상태는 0(유효하지 않은 사용자), 1(유효한 사용자), 2(유효한 사용자 및 유효한 암호)일 수 있습니다.

root@kitploit:~
python3.6 o365enum.py -h
usage: o365enum.py [-h] -u USERLIST [-p PASSWORD] [-n NUM] [-v]
                   [-m {activesync,autodiscover,office.com}]

Office365 User Enumeration Script

optional arguments:
  -h, --help            도움말 메시지 표시 및 종료
  -u USERLIST, --userlist USERLIST
                        사용자 이름 목록, 한 줄에 하나씩 (기본값: None)
  -p PASSWORD, --password PASSWORD
                        시도할 암호 (기본값: Password1)
  -n NUM, --num NUM     거짓 음성(false negative)을 제거하기 위한 재시도 횟수 (기본값: 3)
  -v, --verbose         urllib 수준에서 상세 출력 활성화 (기본값: False)
  -m {activesync,autodiscover,office.com}, --method {activesync,autodiscover,office.com}
                        사용할 방법 (기본값: activesync)

실행 예시:

root@kitploit:~
./o365enum.py -u users.txt -p Password2 -n 1 -m activesync
username,valid
[email protected],0
[email protected],1

열거 방법

ActiveSync 열거

이 방법은 grimhacker의 방법을 기반으로 ActiveSync 엔드포인트에 Basic HTTP 인증 요청을 보냅니다. 그러나 상태 코드만 확인하는 것은 더 이상 작동하지 않습니다. Office 365는 사용자 존재 여부와 관계없이 401을 반환하기 때문입니다.

대신, 동일한 요청을 보내지만 사용자 정의 HTTP 응답 헤더(X-MailboxGuid)의 존재 여부를 확인하여 사용자 이름이 유효한지 여부를 식별합니다.

존재하는 계정

아래 요청에는 Authorization 헤더에 Base64로 인코딩된 다음 자격 증명이 포함되어 있습니다: [email protected]:Password1

root@kitploit:~
OPTIONS /Microsoft-Server-ActiveSync HTTP/1.1
Host: outlook.office365.com
Connection: close
MS-ASProtocolVersion: 14.0
Content-Length: 0
Authorization: Basic dmFsaWRfdXNlckBjb250b3NvLmNvbTpQYXNzd29yZDE=

그러면 다음 응답("401 Unauthorized")이 반환되며, X-MailboxGuid 헤더가 설정되어 사용자 이름은 유효하지만 암호는 유효하지 않음을 나타냅니다:

root@kitploit:~
Date: Fri, 31 Jan 2020 13:02:46 GMT
Connection: close
HTTP/1.1 401 Unauthorized
Content-Length: 1293
Content-Type: text/html
Server: Microsoft-IIS/10.0
request-id: d494a4bc-3867-436a-93ef-737f9e0522eb
X-CalculatedBETarget: AM0PR09MB2882.eurprd09.prod.outlook.com
X-BackEndHttpStatus: 401
X-RUM-Validated: 1
X-MailboxGuid: aadaf467-cd08-4a23-909b-9702eca5b845 <--- 이 헤더가 계정 상태(존재)를 유출합니다
X-DiagInfo: AM0PR09MB2882
X-BEServer: AM0PR09MB2882
X-Proxy-RoutingCorrectness: 1
X-Proxy-BackendServerStatus: 401
X-Powered-By: ASP.NET
X-FEServer: AM0PR06CA0096
WWW-Authenticate: Basic Realm="",Negotiate
Date: Fri, 31 Jan 2020 13:02:46 GMT
Connection: close

--snip--

존재하지 않는 계정

아래 요청에는 Authorization 헤더에 Base64로 인코딩된 다음 자격 증명이 포함되어 있습니다: [email protected]:Password1

root@kitploit:~
OPTIONS /Microsoft-Server-ActiveSync HTTP/1.1
Host: outlook.office365.com
Connection: close
MS-ASProtocolVersion: 14.0
Content-Length: 2
Authorization: Basic aW52YWxpZF91c2VyQGNvbnRvc28uY29tOlBhc3N3b3JkMQ==

그러면 다음 응답("401 Unauthorized")이 반환되지만 이번에는 X-MailboxGuid 헤더가 없어 사용자 이름이 유효하지 않음을 나타냅니다:

root@kitploit:~
HTTP/1.1 401 Unauthorized
Content-Length: 1293
Content-Type: text/html
Server: Microsoft-IIS/10.0
request-id: 2944dbfc-8a1e-4759-a8a2-e4568950601d
X-CalculatedFETarget: DB3PR0102CU001.internal.outlook.com
X-BackEndHttpStatus: 401
WWW-Authenticate: Basic Realm="",Negotiate
X-FEProxyInfo: DB3PR0102CA0017.EURPRD01.PROD.EXCHANGELABS.COM
X-CalculatedBETarget: DB7PR04MB5452.eurprd04.prod.outlook.com
X-BackEndHttpStatus: 401
X-RUM-Validated: 1
X-DiagInfo: DB7PR04MB5452
X-BEServer: DB7PR04MB5452
X-Proxy-RoutingCorrectness: 1
X-Proxy-BackendServerStatus: 401
X-FEServer: DB3PR0102CA0017
X-Powered-By: ASP.NET
X-FEServer: AM0PR04CA0024
Date: Fri, 31 Jan 2020 16:19:11 GMT
Connection: close

--snip--

Autodiscover 열거

Autodiscover 엔드포인트를 사용하면 인증 시도 없이 사용자 열거가 가능합니다. 엔드포인트는 사용자가 존재하면 200 상태 코드를 반환하고, 존재하지 않으면 302를 반환합니다(리디렉션이 온프레미스 Exchange 서버로 이루어지지 않는 경우).

존재하는 사용자

root@kitploit:~
GET /autodiscover/autodiscover.json/v1.0/[email protected]?Protocol=Autodiscoverv1 HTTP/1.1
Host: outlook.office365.com
User-Agent: Microsoft Office/16.0 (Windows NT 10.0; Microsoft Outlook 16.0.12026; Pro
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
MS-ASProtocolVersion: 14.0
root@kitploit:~
HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 97
Content-Type: application/json; charset=utf-8
Vary: Accept-Encoding
Server: Microsoft-IIS/10.0
request-id: fee7f899-7115-43da-9d34-d3ee19920a89
X-CalculatedBETarget: AM0PR09MB2882.eurprd09.prod.outlook.com
X-BackEndHttpStatus: 200
X-RUM-Validated: 1
X-AspNet-Version: 4.0.30319
X-DiagInfo: AM0PR09MB2882
X-BEServer: AM0PR09MB2882
X-Proxy-RoutingCorrectness: 1
X-Proxy-BackendServerStatus: 200
X-Powered-By: ASP.NET
X-FEServer: AM0PR0202CA0008
Date: Mon, 02 Mar 2020 12:50:48 GMT
Connection: close

{"Protocol":"Autodiscoverv1","Url":"https://outlook.office365.com/autodiscover/autodiscover.xml"}

존재하지 않는 사용자

root@kitploit:~
GET /autodiscover/autodiscover.json/v1.0/[email protected]?Protocol=Autodiscoverv1 HTTP/1.1
Host: outlook.office365.com
User-Agent: Microsoft Office/16.0 (Windows NT 10.0; Microsoft Outlook 16.0.12026; Pro
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
MS-ASProtocolVersion: 14.0
root@kitploit:~
HTTP/1.1 302 Found
Cache-Control: private
Content-Length: 277
Content-Type: text/html; charset=utf-8
Location: https://outlook.office365.com/autodiscover/autodiscover.json?Email=nonexistent%40contoso.com&Protocol=Autodiscoverv1&RedirectCount=1
Server: Microsoft-IIS/10.0
request-id: 1c50adeb-53ac-41b9-9c34-7045cffbae45
X-CalculatedBETarget: DB6PR0202MB2568.eurprd02.prod.outlook.com
X-BackEndHttpStatus: 302
X-RUM-Validated: 1
X-AspNet-Version: 4.0.30319
X-DiagInfo: DB6PR0202MB2568
X-BEServer: DB6PR0202MB2568
X-Proxy-RoutingCorrectness: 1
X-Proxy-BackendServerStatus: 302
X-Powered-By: ASP.NET
X-FEServer: AM0PR0202CA0013
Date: Mon, 02 Mar 2020 12:50:50 GMT
Connection: close

<html><head><title>Object moved</title></head><body>
<h2>Object moved to <a href="https://outlook.office365.com/autodiscover/autodiscover.json?Email=nonexistent%40contoso.com&amp;Protocol=Autodiscoverv1&amp;RedirectCount=1">here</a>.</h2>
</body></html>

Office.com 열거

경고: 이 방법은 Exchange Online을 구독 중이며 온프레미스 또는 하이브리드 Exchange 서버 배포가 없는 조직에서만 작동합니다.

온프레미스 Exchange 서버 또는 일부 하이브리드 배포를 사용하고, 아직 식별하지 못한 일부 구성에 따라 서버가 모든 사용자 이름 값에 대해 사용자가 존재한다는 값을 반환할 수 있습니다.

이 방법은 'Password1'로 인증 시도를 낭비하고 싶지 않을 때 유용합니다. :)

사용자 존재 여부 확인

IfExistsResult 속성은 계정이 존재하는지와 그 방식을 설명하는 데 사용됩니다. 이 RSM 블로그 기사에서 논의된 바와 같이 값은 다음과 같습니다:

존재하는 사용자

계정이 존재할 때 IfExistsResult는 위에 언급된 정수 중 하나로 설정되며, 일반적으로 0입니다.

root@kitploit:~
POST /common/GetCredentialType?mkt=en-US HTTP/1.1
Host: login.microsoftonline.com
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36
Accept: application/json
Connection: close
client-request-id: 4345a7b9-9a63-4910-a426-35363201d503
hpgrequestid: 23975ac9-f51c-443a-8318-db006fd83100
Referer: https://login.microsoftonline.com/common/oauth2/authorize
canary: --snip--
hpgact: 1800
hpgid: 1104
Origin: https://login.microsoftonline.com
Cookie: --snip--
Content-Length: 1255
Content-Type: application/json

{
    "checkPhones": false,
    "isOtherIdpSupported": true,
    "isRemoteNGCSupported": true,
    "federationFlags": 0,
    "isCookieBannerShown": false,
    "isRemoteConnectSupported": false,
    "isSignup": false,
    "originalRequest": "rQIIA--snip--YWSO2",
    "isAccessPassSupported": true,
    "isFidoSupported": false,
    "isExternalFederationDisallowed": false,
    "username": "[email protected]",
    "forceotclogin": false
}
root@kitploit:~
HTTP/1.1 200 OK
Cache-Control: no-cache, no-store
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
client-request-id: 177110da-7ce4-4880-b856-be6326078046
x-ms-request-id: c708b83f-4167-4b4c-a1db-d2011ecb3200
x-ms-ests-server: 2.1.9966.8 - AMS2 ProdSlices
Referrer-Policy: strict-origin-when-cross-origin
P3P: CP="DSP CUR OTPi IND OTRi ONL FIN"
Set-Cookie: fpc=ArU-Dva0f59Eg4t_V3VsX_TsYIXWAQAAAFRGxtUOAAAA; expires=Sun, 01-Mar-2020 16:01:26 GMT; path=/; secure; HttpOnly; SameSite=None
Set-Cookie: x-ms-gateway-slice=prod; path=/; SameSite=None; secure; HttpOnly
Set-Cookie: stsservicecookie=ests; path=/; secure; HttpOnly; SameSite=None
Date: Fri, 31 Jan 2020 16:01:26 GMT
Connection: close
Content-Length: 587

{
    "Username":"[email protected]",
    "Display":"[email protected]",
    "IfExistsResult":0,
    "ThrottleStatus":0,
    "Credentials":{
        "PrefCredential":1,
        "HasPassword":true,
        "RemoteNgcParams":null,
        "FidoParams":null,
        "SasParams":null
    },
    "EstsProperties":{
        "UserTenantBranding":null,
        "DomainType":3
    },
    "IsSignupDisallowed":true,
    "apiCanary":"--snip--"
}
존재하지 않는 사용자

계정이 존재하지 않을 때 IfExistsResult는 1로 설정됩니다.

root@kitploit:~
POST /common/GetCredentialType?mkt=en-US HTTP/1.1
Host: login.microsoftonline.com
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36
Accept: application/json
Connection: close
client-request-id: 4345a7b9-9a63-4910-a426-35363201d503
hpgrequestid: 23975ac9-f51c-443a-8318-db006fd83100
Referer: https://login.microsoftonline.com/common/oauth2/authorize
canary: --snip--
hpgact: 1800
hpgid: 1104
Origin: https://login.microsoftonline.com
Cookie: --snip--
Content-Length: 1255
Content-Type: application/json

{
    "checkPhones": false,
    "isOtherIdpSupported": true,
    "isRemoteNGCSupported": true,
    "federationFlags": 0,
    "isCookieBannerShown": false,
    "isRemoteConnectSupported": false,
    "isSignup": false,
    "originalRequest": "rQIIA--snip--YWSO2",
    "isAccessPassSupported": true,
    "isFidoSupported": false,
    "isExternalFederationDisallowed": false,
    "username": "[email protected]",
    "forceotclogin": false
}
root@kitploit:~
HTTP/1.1 200 OK
Cache-Control: no-cache, no-store
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
client-request-id: 95bba645-c3b0-4566-b0f4-237bd3df2ca7
x-ms-request-id: fea01b74-7a60-4142-a54d-7aa8f6471c00
x-ms-ests-server: 2.1.9987.14 - WEULR2 ProdSlices
Referrer-Policy: strict-origin-when-cross-origin
P3P: CP="DSP CUR OTPi IND OTRi ONL FIN"
Set-Cookie: fpc=Ai0TKYuyz3BCp7OL29pUnG7sYIXWAQAAABsDztUOAAAA; expires=Sat, 07-Mar-2020 12:57:44 GMT; path=/; secure; HttpOnly; SameSite=None
Set-Cookie: x-ms-gateway-slice=estsfd; path=/; SameSite=None; secure; HttpOnly
Set-Cookie: stsservicecookie=ests; path=/; secure; HttpOnly; SameSite=None
Date: Thu, 06 Feb 2020 12:57:43 GMT
Connection: close
Content-Length: 579


{
    "ThrottleStatus": 0,
    "apiCanary": "--snip--",
    "Username": "[email protected]",
    "IfExistsResult": 1,
    "EstsProperties": {
        "UserTenantBranding": null,
        "DomainType": 3
    },
    "Credentials": {
        "PrefCredential": 1,
        "FidoParams": null,
        "RemoteNgcParams": null,
        "SasParams": null,
        "HasPassword": true
    },
    "IsSignupDisallowed": true,
    "Display": "[email protected]"
}

기여자

  • @jenic - 인수 구문 분석 및 거짓 음성(false negative) 감소.
  • @Mike-Crowley - IfExistsResult 설명 수정.
도구 다운로드
항목값
-1알 수 없는 오류
0계정이 존재하며 해당 도메인을 인증에 사용함
1계정이 존재하지 않음
2응답이 제한됨
4일부 서버 오류
5계정이 존재하지만 다른 ID 공급자로 인증하도록 설정됨. 이는 계정이 개인 계정으로만 사용됨을 나타낼 수 있음
6계정이 존재하며 도메인과 다른 ID 공급자를 모두 사용하도록 설정됨