ZGrab 개요
- ZGrab은 고속의, 모듈러방식의 어플리케이션 레이어 취약점 스캐너이다.
- ZMap 프로젝트의 일부이다.
- 아이콘이 카메라이고, 설명이 A Banner Grabber 였던 것을 보아, 원래는 웹 어플리케이션의 톱 페이지 등을 간단하게 확인하는 용도였던 것 같다.
- ZGrab과 ZGrab2가 있다. ZGrab2가 기존의 ZGrab을 대체하므로 ZGrab2 사용이 추천된다(Zgrab은 DEPRECATED 상태이다).
- Turbo Intruder 연구중에 하나의 취약점 체크 페이로드를 대량의 서버를 대상으로 체크하고 싶을 때는 ZGrab 사용을 추천한다는 내용을 보았다.
- (반대로 하나의 서버를 대상으로 대량의 페이로드를 체크하고 싶을 때는 Burp Suite 의 확장 프로그램인 Turbo Intruder를 추천한다고 한다)
- 실제로 사용해보면 속도가 무지하게 빠르다. 수만개 정도의 요청이라면 수분내에 끝난다.
ZGrab 설치
- ZGrab은 대부분 Go언어로 개발되었다. (일부분은 Python으로 개발된 것 같다.)
- 따라서 Go실행 환경을 먼저 설치할 필요가 있다.
- 설치는 여기 포스트 를 참고로 했다.
- 리눅스 환경에서 yum을 이용해 설치하였다.
sudo su
yum install epel-release
yum install -y golang
# Go 버전체크
go version
# go 버전이 18이상이면 go get 을 못쓴다고 하는 것 같다. 대신에 go install 커맨드를 사용해서 설치했다.
go install github.com/zmap/ZGrab2@latest
# cd $GOPATH/src/github.com/zmap/ZGrab2
# go install 로 하면 설치 폴더도 달라지는 것 같다. 아래 디렉토리로 이동해서 make 를 실시했다. => 실패했다.
cd /root/go/pkg/mod/github.com/zmap/zgrab2@v0.1.7
make
# testify 라이브러리를 설치한 후, 다시 make 를 시도해서 성공하였다.
go mod download github.com/stretchr/testify
make
# cmd/ZGrab2/ZGrab2에 실행 바이너리가 생성된다. 이 경로를 PATH에 추가해둔다. (.bashrc, .bash_profile)
ZGrab 사용법
기본 커맨드
zgrab2 를 실행하면 다음과 같이 추가 커맨드(모듈)를 함께 지정하라고 나온다.
zgrab2
Please specify one command of: bacnet, banner, dnp3, fox, ftp, http, imap, ipp, modbus, mongodb, mssql, multiple, mysql, ntp, oracle, pop3, postgres, redis, siemens, smb, smtp, ssh, telnet or tls
FATA[0000] could not parse flags: Please specify one command of: bacnet, banner, dnp3, fox, ftp, http, imap, ipp, modbus, mongodb, mssql, multiple, mysql, ntp, oracle, pop3, postgres, redis, siemens, smb, smtp, ssh, telnet or tls
- 다음 처럼 모듈을 지정하고 -h 옵션을 붙이면 상세한 사용법을 알려준다.
- 모듈마다 사용가능한 옵션이 상이하다.
- 예를들면 http 모듈은 heartbleed 취약점을 체크할 수 있는 옵션이 있다. (–heartbleed)
zgrab2 [모듈명] -h
사용가능한 모듈
- 사용가능한 모듈은 여러가지가 있다. 주로 프로토콜에 따라 구분되는 것 같다.
- 영문설명은
zgrab2 모듈명 -h커맨드 실행 결과를 참고하였다.
| 모듈명 | 영문설명 | 한글번역/비고 |
|---|---|---|
| bacnet | Probe for devices that speak Bacnet, commonly used for HVAC control. | BACnet은 빌딩 자동제어 및 제어 네트워크의 표준 프로토콜 |
| banner | Fetch a raw banner by sending a static probe and checking the result against a regular expression | 배너를 읽는다 |
| dnp3 | RProbe for DNP3, a SCADA protocol | SCADA 프로토콜 |
| fox | Probe for Tridium Fox | |
| ftp | Grab an FTP banner | 파일공유 프로토콜 |
| http | Send an HTTP request and read the response, optionally following redirects. | |
| imap | Fetch an IMAP banner, optionally over TLS | |
| ipp | Probe for printers via IPP | |
| modbus | Probe for Modbus devices, usually PLCs as part of a SCADA system | |
| mongodb | Perform a handshake with a MongoDB server | MongoDB서버 |
| mssql | Perform a handshake for MSSQL databases | MsSQL DB서버 |
| multiple | Multiple module actions | |
| mysql | Perform a handshake with a MySQL database | MySQL DB서버 |
| ntp | Scan for NTP | NTP는 시간정보 동기화 프로토콜 |
| oracle | Perform a handshake with Oracle database servers | 오라클 DB서버 |
| pop3 | Fetch POP3 banners, optionally over TLS | 메일 서버 pop3관련 |
| postgres | Perform a handshake with a PostgreSQL server | postgres DB서버 |
| redis | Probe for Redis | Redis(원격 딕셔너리 자료구조)서버 |
| siemens | Probe for Siemens S7 devices | |
| smb | Probe for SMB servers (Windows filesharing / SAMBA) | SMB는 네트워크 상 존재하는 노드들 간에 자원을 공유할 수 있도록 설계된 프로토콜 |
| smtp | Fetch an SMTP server banner, optionally over TLS | 메일서버 SMTP관련 |
| ssh | Fetch an SSH server banner and collect key exchange information | SSH |
| telnet | Fetch a telnet banner | 텔넷 |
| tls | Perform a TLS handshake | TLS핸드셰이크 수행 |
HTTP 모듈
주로 HTTP 모듈을 사용하게 될 것 같다.
다음 옵션이 사용가능하다.
--method플래그로 GET이외의 POST와 같은 메소드도 설정가능하다.
# zgrab2 http -h
Usage:
zgrab2 [OPTIONS] http [http-OPTIONS]
Send an HTTP request and read the response, optionally following redirects.
Application Options:
-o, --output-file= Output filename, use - for stdout (default: -)
-f, --input-file= Input filename, use - for stdin (default: -)
-m, --metadata-file= Metadata filename, use - for stderr (default: -)
-l, --log-file= Log filename, use - for stderr (default: -)
--source-ip= Local source IP address to use for making connections
-s, --senders= Number of send goroutines to use (default: 1000)
--debug Include debug fields in the output.
--gomaxprocs= Set GOMAXPROCS (default: 0)
--connections-per-host= Number of times to connect to each host (results in more output) (default: 1)
--read-limit-per-host= Maximum total kilobytes to read for a single host (default 96kb) (default: 96)
--prometheus= Address to use for Prometheus server (e.g. localhost:8080). If empty, Prometheus is disabled.
Help Options:
-h, --help Show this help message
[http command options]
-p, --port= Specify port to grab on (default: 80)
-n, --name= Specify name for output json, only necessary if scanning multiple modules (default: http)
-t, --timeout= Set connection timeout (0 = no timeout) (default: 10s)
-g, --trigger= Invoke only on targets with specified tag
-m, --maxbytes= Maximum byte read limit per scan (0 = defaults)
--heartbleed Check if server is vulnerable to Heartbleed
--session-ticket Send support for TLS Session Tickets and output ticket if presented
--extended-master-secret Offer RFC 7627 Extended Master Secret extension
--extended-random Send TLS Extended Random Extension
--no-sni Do not send domain name in TLS Handshake regardless of whether known
--sct Request Signed Certificate Timestamps during TLS Handshake
--keep-client-logs Include the client-side logs in the TLS handshake
--time= Explicit request time to use, instead of clock. YYYYMMDDhhmmss format.
--certificates= Set of certificates to present to the server
--certificate-map= A file mapping server names to certificates
--root-cas= Set of certificates to use when verifying server certificates
--next-protos= A list of supported application-level protocols
--server-name= Server name used for certificate verification and (optionally) SNI
--verify-server-certificate If set, the scan will fail if the server certificate does not match the server-name, or does not
chain to a trusted root.
--cipher-suite= A comma-delimited list of hex cipher suites to advertise.
--min-version= The minimum SSL/TLS version that is acceptable. 0 means that SSLv3 is the minimum.
--max-version= The maximum SSL/TLS version that is acceptable. 0 means use the highest supported value.
--curve-preferences= A list of elliptic curves used in an ECDHE handshake, in order of preference.
--no-ecdhe Do not allow ECDHE handshakes
--signature-algorithms= Signature and hash algorithms that are acceptable
--heartbeat-enabled If set, include the heartbeat extension
--dsa-enabled Accept server DSA keys
--client-random= Set an explicit Client Random (base64 encoded)
--client-hello= Set an explicit ClientHello (base64 encoded)
--method= Set HTTP request method type (default: GET)
--endpoint= Send an HTTP request to an endpoint (default: /)
--user-agent= Set a custom user agent (default: Mozilla/5.0 zgrab/0.x)
--retry-https If the initial request fails, reconnect and try with HTTPS.
--max-size= Max kilobytes to read in response to an HTTP request (default: 256)
--max-redirects= Max number of redirects to follow (default: 0)
--follow-localhost-redirects Follow HTTP redirects to localhost
--use-https Perform an HTTPS connection on the initial host
--redirects-succeed Redirects are always a success, even if max-redirects is exceeded
--override-sig-hash Override the default SignatureAndHashes TLS option with more expansive default
스캔 대상 지정하는 법
- CSV 파일로 스캔 대상을 설정한다.
- 콤마로 구분한다.
- 한줄에 하나의 스캔 대상을 설정한다.
- 다음 세가지 필드를 입력할 수 있다.
- IP 나 DOMAIN 둘 중에 하나는 필수이다.
IP, DOMAIN, TAG
- 다음은 모두 문제없는 입력이다.
10.0.0.1
domain.com
10.0.0.1, domain.com
10.0.0.1, domain.com, tag
10.0.0.1, , tag
, domain.com, tag
192.168.0.0/24, , tag
커맨드 예제
Zgrab2
아마 특정 경로가 존재하는지와 같은 테스트를 가장 많이 할 것 같다.
- 먼저 스캔 대상을 target.csv로 준비해둔다.
- 타임아웃을 5초로 하고 대상포트는 443으로 지정한다.
--endpoint에 체크하고 싶은 엔드포인트를 지정한다.
sudo su
$ zgrab2 http -f targets.csv -o result.json -l log.txt -p 443 -t 5 --endpoint=/test
Zgrab1
ZGrab 에서 사용가능한 커맨드이지만 ZGrab2에서는 사용할 수 없을 것 같다.
- 다음과 같은 식으로 다른 Zmap 프로젝트의 프로그램과 연동해서 사용하는 것 같다.
- zmap 으로 포트스캔을 수행한 후, 그 결과을 ztee를 이용해서 csv 파일형식으로 변환해서 zgrab으로 어플리케이션 레이어의 스캔을 수행한다.
$ zmap -p 443 --output-fields=* | ztee results.csv | zgrab --port 443 --tls --http="/" --output-file=banners.json
특정 HTTP 페이로드로 테스트하는 방법
- 특정 페이로드는 설정할 수 있는 옵션이 없다.
- 그렇게 하고 싶으면 자기가 모듈을 개발해야 할 것 같다.
커스텀 모듈 개발하는 방법
TODO. 언젠가 조사해보자.
Rate Limit 제한
- 기본 설정이면 상당한 리소스를 사용하는 것 같다.
- 스캔 결과에 error: socket: too many open files 등의 메세지가 보이면 Rate Limit 제한을 검토해야 한다.
- https://github.com/zmap/zgrab2/issues/221
ulimit
- ulimit는 한번에 몇 개의 파일을 열 수 있는가와 관련된 수치
- too many open files 는 이 수치를 넘었다는 것
- 이 포스트 의 도움을 받았다.
- 현재 수치는
ulimit -n로 확인가능하다. 1024인 경우가 많은 것 같다. - 변경하려면 먼저 시스템에서 설정가능한 최대치를 확인한 후
cat /proc/sys/fs/file-max
- 그 수치를 넘지않게 변경하고자 하는 값을 설정한다.
vi /etc/security/limits.conf
root hard nofile 100000
root soft nofile 100000
결과 파싱 및 필터링
- ZGrab 결과는 기본적으로 Json 형식으로 저장된다.
- 따라서 jq 명령어와 조합하면 궁합이 좋다.
- 다음 필터링 형식은 자주 쓰일 것 같다.
- http 응답 코드와 http 응답 보디에 특정 문자열이 포함되어 있는 것을 찾는다.
cat {결과파일명} | jq '.data .http .result .response | select( .status_code == 응답코드번호) | (select(.body | contains("{찾고싶은문자열}")))'
cat {결과파일명} | jq '.data .http .result .response | select( .status_code == 200) | (select(.body))'
참고 URL
- https://github.com/zmap/zgrab2/wiki/HTTP
- https://github.com/zmap/zgrab2
- https://cmpxchg16.medium.com/scan-the-whole-internet-while-drinking-coffee-9c4085539594