
호스트, 서비스 및 콘텐츠에 대한 패턴 인식
# Recog: 인식 프레임워크
[](https://github.com/rapid7/recog/actions/workflows/ci.yml)
[](https://github.com/rapid7/recog/actions/workflows/verify.yml)
Recog는 다양한 네트워크 프로브가 반환한 데이터에 지문을 매칭하여 제품, 서비스, 운영 체제 및 하드웨어를 식별하는 프레임워크입니다. Recog를 사용하면 웹 서버 배너, SNMP 시스템 설명 필드 등에서 유용한 정보를 간단하게 추출할 수 있습니다.
Recog는 오픈 소스입니다. 자세한 내용은 [LICENSE](https://github.com/rapid7/recog/blob/main/LICENSE) 파일을 참조하십시오.
## 목차
1. [저장소 분리](#repository-split)
1. [기본 브랜치 이름 변경](#default-branch-rename)
1. [Recog 라이브러리 언어 구현](#recog-library-language-implementations)
1. [기능 동등성](#feature-parity)
1. [설치](#installation)
1. [성숙도](#maturity)
1. [지문](#fingerprints)
1. [매칭 테스트](#testing-matches)
1. [ftp_banners](#ftp_banners)
1. [http_cookies](#http_cookies)
1. [http_servers](#http_servers)
1. [favicons](#favicons)
1. [http_wwwauth](#http_wwwauth)
1. [tls_jarm](#tls_jarm)
1. [기여](#contributing)
## 저장소 분리
2022년 3월 31일, Recog 콘텐츠(XML 지문 파일 및 유틸리티)가 Recog 프레임워크 라이브러리 구현에서 분리되었습니다. 원래 [Recog](https://github.com/rapid7/recog) 저장소에는 이제 Recog 콘텐츠가 포함되어 있으며, [Recog-Ruby](https://github.com/rapid7/recog-ruby) 저장소에는 Ruby 언어 구현이 포함되어 있습니다. Recog 콘텐츠는 git 서브모듈로 Recog-Ruby에 포함되며 `recog` 디렉터리 아래에 중첩되어 있습니다. 분리 이후의 Recog gem 버전 3.0.0 이상은: 1. `recog` 디렉터리 아래에 XML 지문 디렉터리를 포함하고, 2. 다른 도구들은 지문 관리에 중점을 두므로 `recog_match` 도구만 포함합니다.
[^맨 위로](#recog-a-recognition-framework)
### 기본 브랜치 이름 변경
저장소 분리와 함께 기본 브랜치 이름이 `master`에서 `main`으로 변경되었습니다. 이러한 변경 이전에 생성된 클론은 로컬 환경에서 수동으로 업데이트해야 합니다. 포크가 있는 경우 포크의 설정으로 이동하여 [브랜치 이름 변경](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-branches-in-your-repository/renaming-a-branch) 지침에 따라 기본 브랜치를 `main`으로 변경하십시오.
```
git branch -m master main
git fetch origin
git branch -u origin/main main
git remote set-head origin -a
```
선택적으로, 다음 명령을 실행하여 이전 브랜치 이름에 대한 추적 참조를 제거할 수 있습니다.
```
# dry-run to confirm stale references that will be deleted before proceeding
git remote prune origin --dry-run
git remote prune origin
```
이전에 업스트림 추적 브랜치 `upstream-master`를 사용했다면 다음 명령을 실행하여 이전 브랜치를 제거하고 새 업스트림 추적 브랜치를 생성하십시오.
```
git branch -d upstream-master
git checkout -b upstream-main --track upstream/main
```
선택적으로, 다음 명령을 실행하여 이전 업스트림 브랜치 이름에 대한 추적 참조를 제거할 수 있습니다.
```
# dry-run to confirm stale references that will be deleted before proceeding
git remote prune upstream --dry-run
git remote prune upstream
```
[^맨 위로](#recog-a-recognition-framework)
## Recog 라이브러리 언어 구현
* Ruby: [rapid7/recog-ruby](https://github.com/rapid7/recog-ruby)
* Java: [rapid7/recog-java](https://github.com/rapid7/recog-java)
* Go: [runZeroInc/recog-go](https://github.com/runZeroInc/recog-go)
[^맨 위로](#recog-a-recognition-framework)
### 기능 동등성
| 기능 :sparkles: | rapid7/recog-ruby | rapid7/recog-java | runZeroInc/recog-go |
|---------------------------------------------|:------------------:|:------------------:|:-------------------:|
| 지문 검증 CLI 도구 | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| 지문 매칭 CLI 도구 | :white_check_mark: | | :white_check_mark: |
| base64 인코딩 예제 지원 | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| 파일 시스템 기반 외부 예제 지원 | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| 지문 매칭 CPE 매개변수 보간 | :white_check_mark: | :white_check_mark: | :white_check_mark: |
[^맨 위로](#recog-a-recognition-framework)
## 설치
Recog는 XML 지문 파일과, 주로 Ruby로 작성된, 포함된 지문을 쉽게 개발·테스트·사용할 수 있게 해주는 다양한 코드로 구성됩니다. 포함된 Ruby 코드를 사용하려면 최신 버전의 Ruby(2.31+)와 Rubygems 및 `bundler` gem이 필요합니다. 이러한 종속성이 준비되면 다음 명령을 사용하여 최신 소스 코드를 가져오고 추가 종속성을 설치하십시오.
```shell
$ git clone [email protected]:rapid7/recog.git
$ cd recog
$ bundle install
```
[^맨 위로](#recog-a-recognition-framework)
## 성숙도
XML 지문 자체는 상당히 안정적이고 잘 테스트되어 있지만, Ruby 코드베이스는 아직 상당히 새롭고 빠르게 변경될 수 있다는 점에 유의하십시오. 프로덕션 프로젝트에서 Recog 코드를 사용하기 전에 저희에게 연락해 주십시오 (research[at]rapid7.com).
[^맨 위로](#recog-a-recognition-framework)
## 지문
Recog 내의 지문은 XML 파일에 저장되며, 각 파일은 특정 프로토콜 응답 문자열 또는 필드를 매칭하도록 설계되었습니다. 예를 들어, [ssh_banners.xml](https://github.com/rapid7/recog/blob/main/xml/ssh_banners.xml) 파일은 초기 SSH 데몬 배너 문자열을 매칭하여 OS, 공급업체, 때로는 하드웨어 제품을 알아낼 수 있습니다.
지문 파일은 다음과 같은 XML 문서로 구성됩니다:
```xml
<fingerprints matches="ssh.banner">
<fingerprint pattern="^RomSShell_([\d\.]+)$">
<description>Allegro RomSShell SSH</description>
<example service.version="4.62">RomSShell_4.62</example>
<param pos="0" name="service.vendor" value="Allegro"/>
<param pos="0" name="service.product" value="RomSShell"/>
<param pos="1" name="service.version"/>
</fingerprint>
</fingerprints>
```
첫 번째 줄은 항상 XML 버전 선언으로 구성되어야 합니다. 첫 번째 요소는 항상 `matches` 속성이 있는 `fingerprints` 블록이어야 하며, 이 속성은 이 지문 파일이 매칭해야 할 데이터를 나타냅니다. `matches` 속성은 일반적으로 `protocol.field` 형식입니다.
`fingerprints` 요소 안에는 하나 이상의 `fingerprint` 요소가 있어야 합니다. 모든 `fingerprint`는 데이터를 매칭하는 데 사용할 정규 표현식이 포함된 `pattern` 속성을 반드시 포함해야 합니다. 정규 표현식을 해석하는 방법을 제어하기 위해 선택적으로 `flags` 속성을 지정할 수 있습니다. 자세한 내용은 [`FLAG_MAP`에 대한 Recog 문서](http://www.rubydoc.info/gems/recog/Recog/Fingerprint/RegexpFactory#FLAG_MAP-constant)를 참조하십시오.
지문 내부에서 `description` 요소는 이 지문을 설명하는 사람이 읽을 수 있는 문자열을 포함해야 합니다.
최소한 하나의 `example` 요소가 있어야 하지만, 여러 개의 `example` 요소가 권장됩니다. 이 요소들은 제공된 데이터가 지정된 정규 표현식과 일치하는지 검증하는 `rspec` 테스트 커버리지의 일부로 사용됩니다. 또한, 지문이 데이터에서 필드 값을 추출하기 위해 `param` 요소를 사용하는 경우(다음에 설명), 이 예상 추출 결과를 `example` 요소의 속성으로 추가할 수 있습니다. 위 예제에서 다음은:
```xml
<example service.version="4.62">RomSShell_4.62</example>
```
`RomSShell_4.62`가 제공된 정규 표현식과 일치하는지, 그리고 `service.version`의 값이 4.62인지 테스트합니다.
`example` 문자열은 인쇄할 수 없는 문자를 허용하기 위해 base64로 인코딩할 수 있습니다. 이를 Recog에 알리기 위해 `example` 요소에 `base64` 값을 가진 `_encoding` 속성이 추가됩니다. 80자보다 긴 base64 인코딩 텍스트는 가독성을 돕기 위해 아래와 같이 줄바꿈으로 감쌀 수 있습니다.
```xml
<example _encoding="base64">
dGllczGEAAAAlQQWMS4yLjg0MC4xMTM1NTYuMS40LjgwMAQuZGF0YS5yZW1vdmVkLjCEAAAAK
AQdZG9tYWluQ29udHJvbGxlckZ1bmN0aW9uYWxpdHkxhAAAAAMEATc=
</example>
```
또한, 예제는 XML 파일과 동일한 디렉터리 안에 XML 파일과 같은 기본 이름을 가진 디렉터리에 배치할 수 있습니다:
```
xml/services.xml
xml/services/file1
xml/services/file2
...
```
그런 다음 `_filename` 속성을 사용하여 로드할 수 있습니다:
```xml
<example _filename="file1"/>
```
이는 긴 예제에 유용합니다.
`param` 요소에는 `pattern`에서 추출할 캡처 필드를 나타내는 `pos` 속성이 포함되며, 정적 문자열의 경우 `0`을 사용합니다. `name` 속성은 매칭에 성공할 때 보고되는 키이며, `value`는 `pos` 값이 `0`인 경우 정적 문자열이 되거나, 값이 없으면 캡처된 필드에서 가져옵니다.
`value` 속성은 다른 필드의 데이터 보간을 지원합니다. 이는 정규 표현식을 통해 `hw.product` 값을 캡처하고 이 값을 `os.product`에서 재사용할 때 유용합니다.
다음은 `hw.product`가 캡처되어 재사용되는 `http_servers.xml`의 예입니다.
```xml
<fingerprint pattern="^Eltex (TAU-\d+[A-Z]*(?:\.IP)?)$">
<description>Eltex TAU model VoIP gateway</description>
<example hw.product="TAU-72">Eltex TAU-72</example>
<example hw.product="TAU-1.IP">Eltex TAU-1.IP</example>
<param pos="0" name="os.vendor" value="Eltex"/>
<param pos="0" name="os.product" value="{hw.product} Firmware"/>
<param pos="0" name="os.device" value="VoIP Gateway"/>
<param pos="0" name="hw.vendor" value="Eltex"/>
<param pos="1" name="hw.product"/>
<param pos="0" name="hw.device" value="VoIP Gateway"/>
</fingerprint>
```
이름이 `_tmp.`로 시작하는 임시 속성에는 특별한 처리가 적용됩니다. 이러한 속성은 보간에는 사용할 수 있지만 출력에는 포함되지 않습니다. 이는 특정 제품 이름이 여러 배너, 공급업체 마케팅 자료, 또는 CPE 생성 시 NIST 값과 일치하지 않을 때 유용합니다. 이러한 경우 배너의 유용한 부분을 추출하여 매칭 결과로 출력되는 데이터를 복잡하게 만들지 않으면서 새 값을 만들 수 있습니다.
```xml
<fingerprint pattern="^foo baz switchThing-(\d{4})$">
<description>NetCorp NX series switches</description>
<example hw.product="NX8200">foo baz switchThing-8200</example>
<param pos="0" name="hw.vendor" value="NetCorp"/>
<param pos="0" name="hw.product" value="NX{_tmp.001}"/>
<param pos="2" name="_tmp.001"/>
</fingerprint>
```
이러한 임시 속성은 `identifiers/fields.txt`에서 추적되지 않습니다.
[^맨 위로](#recog-a-recognition-framework)
### 매칭 테스트
다음 예제들은 Recog의 지문 데이터를 사용하는 간단한 Ruby 명령줄 도구인 `bin/recog_match`를 사용합니다. Recog를 실행하기 전에 일반적으로 전처리가 필요합니다(예: HTTP 헤더 값 추출 등). 모든 지문 데이터는 `xml/*.xml`에서 찾을 수 있습니다.
#### ftp_banners
연결 후 서버의 배너 응답을 기반으로 FTP 서버를 지문 식별합니다:
```
# Example plaintext input
echo -n '220 Microsoft FTP Service' | bin/recog_match xml/ftp_banners.xml -
# Example command using nmap
nmap -sV -script=banner -p 21 192.168.123.13 | grep --color=never '_banner' | cut -d: -f2- | bin/recog_match xml/ftp_banners.xml -
# Example output
MATCH: {"matched"=>"Microsoft FTP Server on Windows XP, 2003 or later without version", "service.vendor"=>"Microsoft", "service.product"=>"IIS", "service.family"=>"IIS", "service.cpe23"=>"cpe:/a:microsoft:iis:-", "os.vendor"=>"Microsoft", "os.family"=>"Windows", "os.product"=>"Windows", "os.cpe23"=>"cpe:/o:microsoft:windows:-", "host.name"=>"220", "service.protocol"=>"ftp", "fingerprint_db"=>"ftp.banner", "data"=>"220 Microsoft FTP Service"}
```
#### http_cookies
HTTP `Set-Cookie` 헤더 값을 사용하여 HTTP 서버를 지문 식별합니다:
```
# Example plaintext input
echo 'laravel_session=eyJ...etc..etc...%3D; expires=Mon, 13-Mar-2023 16:48:58 GMT; Max-Age=7200; path=/; httponly; samesite=lax' | bin/recog_match xml/http_cookies.xml -
# Example cURL command
curl --silent -I http://localhost:9001 | grep --color=never -i '^Set-Cookie:' | cut -d: -f2- | bin/recog_match xml/http_cookies.xml -
# Example output
MATCH: {"matched"=>"Laravel PHP web application framework", "service.vendor"=>"Laravel", "service.product"=>"Laravel", "service.cpe23"=>"cpe:/a:laravel:laravel:-", "service.protocol"=>"http", "fingerprint_db"=>"http_header.cookie", "data"=>"laravel_session=eyJ...etc..etc...%3D; expires=Mon, 13-Mar-2023 16:48:58 GMT; Max-Age=7200; path=/; httponly; samesite=lax"}
```
#### http_servers
HTTP `Server` 헤더 값을 사용하여 HTTP 서버를 지문 식별합니다:
```
# Example plaintext input
echo -n 'Apache/2.4.38 (Debian)' | bin/recog_match xml/http_servers.xml -
# Example cURL command
curl --silent -I http://localhost:9001 | grep --color=never -i '^Server:' | cut -d: -f2- | bin/recog_match xml/http_servers.xml -
# Example output
MATCH: {"matched"=>"Apache", "service.vendor"=>"Apache", "service.product"=>"HTTPD", "service.family"=>"Apache", "service.version"=>"2.4.38", "service.cpe23"=>"cpe:/a:apache:http_server:2.4.38", "apache.info"=>"(Debian)", "service.protocol"=>"http", "fingerprint_db"=>"http_header.server", "data"=>"Apache/2.4.38 (Debian)"}
```
#### favicons
파비콘의 md5sum을 사용하여 실행 중인 서비스를 식별합니다:
```
# Example plaintext input
echo -n fe22dd2bb09daccf58256611ac491469 | bin/recog_match xml/favicons.xml -
# Example cURL command
curl --silent http://localhost:8000/favicon.ico | md5sum | awk '{ print $1 }' | bin/recog_match xml/favicons.xml -
# Example output
MATCH: {"matched"=>"Drupal CMS", "service.vendor"=>"Drupal", "service.product"=>"CMS", "service.certainty"=>"0.5", "service.cpe23"=>"cpe:/a:drupal:drupal:-", "service.protocol"=>"", "fingerprint_db"=>"favicon.md5", "data"=>"fe22dd2bb09daccf58256611ac491469"}
```
#### http_wwwauth
HTTP `WWW-Authenticate` 헤더 값을 사용하여 HTTP 서버를 지문 식별합니다:
```
# Example plaintext input
echo -n 'Basic realm="monit"' | bin/recog_match xml/http_wwwauth.xml -
# Example cURL command
curl --silent -I http://localhost:9001 | grep --color=never -i '^WWW-Authenticate:' | cut -d: -f2- | bin/recog_match xml/http_wwwauth.xml -
# Example output
MATCH: {"matched"=>"Minot", "service.vendor"=>"Tildeslash", "service.product"=>"Monit", "service.cpe23"=>"cpe:/a:tildeslash:monit:-", "service.protocol"=>"http", "fingerprint_db"=>"http_header.wwwauth", "data"=>"Basic realm=\"monit\""}
```
#### tls_jarm
10개의 TLS Client Hello 패킷에 대한 서버의 응답을 기반으로 TLS 서버를 지문 식별합니다. https://github.com/salesforce/jarm 기반 지문
```
# Example plaintext input
echo -n 07d14d16d21d21d07c42d43d000000f50d155305214cf247147c43c0f1a823 | bin/recog_match xml/jarm.xml -
# Example command using Salesforce's JARM against a running Metasploit listener
python3 $code/jarm/jarm.py -p 8443 192.168.123.1 | grep --color=never 'JARM: ' | awk -F: '{ print $2 }' | bin/recog_match xml/tls_jarm.xml -
# Example output
MATCH: {"matched"=>"Metasploit listener", "service.vendor"=>"Rapid7", "service.product"=>"Metasploit", "service.cpe23"=>"cpe:/a:rapid7:metasploit:-", "service.protocol"=>"tls", "fingerprint_db"=>"tls.jarm", "data"=>"07d14d16d21d21d07c42d43d000000f50d155305214cf247147c43c0f1a823"}
```
## 기여
Recog의 사용자와 유지관리자는 프로젝트에 대한 어떤 기여도 크게 환영합니다. 지침과 안내는 [CONTRIBUTING.MD](https://github.com/rapid7/recog/blob/main/CONTRIBUTING.md)를 참조하십시오.
[^맨 위로](#recog-a-recognition-framework)