VirusTotalのAPIでファイルをスキャンする

# なんのため？
Windows上でファイルをダウンロードすると、インストール済みのウィルス対策ソフトやWindows Security (Windows Defender)等にウィルスとして検知し、ダウンロードしたてのファイルを削除されてしまうことがあります。

本当にウィルスの可能性も十分にあるため、基本的にはそのファイルには触れないほうが良いとは思いますが、誤検知の可能性や、ウィルスの詳細を確認したいケースもあります。

怪しげなファイルがウィルスかどうか判定するにはVirus Totalを使って複数のアンチウィルスエンジンで検査してもらうのが便利です。

しかし、ウィルス対策ソフトはファイルを検疫フォルダに移したり、削除したりといった対策を取るため、そのままWindows PCを使ってVirus Totalにアップロードことはできません。

したがって、ウィルス対策ソフトがウィルスと判定したファイルを削除しないようにホワイトリストするような操作をする必要がありますが、この操作をすると怪しげなファイルの実体が手元に残ることになり、万一実行するだけで問題を引き起こすようなファイルの場合、誤操作のリスクが伴います。

AWSのCloudShellなどの環境からVirus Totalで検査することで、Windows PC上でウィルスの恐れがあるファイルを扱うリスクを軽減しようという試みです。

# 方法


## 1. CloudShellを起動する
自分用のLinuxのサーバがあればその環境でも問題ないですが、怪しげなファイルを一時的にせよ配置するのはちょっと気が引けるところがあります。

AWSのCloudShellを使うことで、安全に作業できる気がします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85204/2b7fba9c-d3ea-942a-2e3b-51f672a0be32.png)

## 2. VirusTotalのAPIキーを取得する
VirusTotalのアカウントを作りhttps://www.virustotal.com/gui/my-apikey からAPI Keyの値を取得します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85204/e06e3406-21db-8939-e9c5-517a18723eb2.png)

毎回キーを入力するのは面倒なので、CloudShellの環境変数に入れておきます。
```bash
$ VIRUSTOTAL_API_KEY=0d...c7
```

## 3. CloudShell上にファイルをダウンロードする
Windows上でファイルのダウンロードURLを取得し、CloudShell上でダウンロードします。
```bash
[cloudshell-user@ip-10-6-98-128 ~]$ wget http://g.xuanfang.co/XFZX/XFZX.zip
--2023-01-23 15:41:18--  http://g.xuanfang.co/XFZX/XFZX.zip
```
```
Resolving g.xuanfang.co (g.xuanfang.co)... 47.88.54.184
Connecting to g.xuanfang.co (g.xuanfang.co)|47.88.54.184|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 10434703 (10.0M) [application/zip]
Saving to: ‘XFZX.zip’

100%[================================================================================================================================================>] 10,434,703   557KB/s   in 19s    

2023-01-23 15:41:38 (536 KB/s) - ‘XFZX.zip’ saved [10434703/10434703]
```

## 4. ファイルのチェックサムを作る
怪しげなファイルはたいていすでにVirusTotalで検査済みのため、ファイルの実体をアップロードしなくても、チェックサムからVirusTotalの過去の検査結果を確認することができます。ひとまずは過去の検査結果を確認するため、チェックサムを生成します。

```bash
$ sha256sum XFZX.zip 
347d46ffa3b3562fb5056fa04bf90453af7e1ab6c7fd6025c31ba376e268318f  XFZX.zip
```

## 5. 過去の検査結果を確認する
チェックサムを使って、`files`APIを`GET`し、過去の検査結果を取得します。
```bash
curl --request GET \
     --url https://www.virustotal.com/api/v3/files/347d46ffa3b3562fb5056fa04bf90453af7e1ab6c7fd6025c31ba376e268318f \
     --header 'accept: application/json' \
     --header "x-apikey: $VIRUSTOTAL_API_KEY"
```
結果は結構長いので、どのエンジンがどう判定したかなど、全部見たい場合はCloudShellならインストール済みのjqを使って、minifyすると簡単にローカルに持ち帰れると思います。
```bash
curl --request GET \
     --url https://www.virustotal.com/api/v3/files/347d46ffa3b3562fb5056fa04bf90453af7e1ab6c7fd6025c31ba376e268318f \
     --header 'accept: application/json' \
     --header "x-apikey: $VIRUSTOTAL_API_KEY"\
| jq -c
```
もしくは、まとめのフィールドだけ確認します。
```bash
curl -s --request GET \
     --url https://www.virustotal.com/api/v3/files/347d46ffa3b3562fb5056fa04bf90453af7e1ab6c7fd6025c31ba376e268318f \
     --header 'accept: application/json' \
     --header "x-apikey: $VIRUSTOTAL_API_KEY" \
| jq \
.data.attributes.last_analysis_date,\
.data.attributes.last_analysis_stats
```
こんな感じの結果が得られるはずです。結果が出ない場合は後述。
```json
{
  "harmless": 0,
  "type-unsupported": 9,
  "suspicious": 0,
  "confirmed-timeout": 0,
  "timeout": 0,
  "failure": 0,
  "malicious": 12,
  "undetected": 54
}
1672675609
```

## 6. 再検査させる
一番下に検査日がUnixtimeで表示されているので、どれくらい前なのか確認します。
```
$ date -d @1672675609
Mon Jan  2 16:06:49 UTC 2023
```
執筆時点で1月24日なので、ちょっと古かったです。この場合、`files`APIに`POST`し、再検査を要求します。
```bash
curl --request POST \
     --url https://www.virustotal.com/api/v3/files/347d46ffa3b3562fb5056fa04bf90453af7e1ab6c7fd6025c31ba376e268318f/analyse \
     --header 'accept: application/json' \
     --header "x-apikey: $VIRUSTOTAL_API_KEY"
```
しばらく待ってから再度上のリクエストをすることで、新しい結果のレポートが得られるはずです。

## 7. 新しいファイルを検査する
そもそもファイルがVirusTotalにアップロードされたことがない場合、チェックサムからの検査結果が得られません。
```bash
$ curl --request GET \
>      --url https://www.virustotal.com/api/v3/files/3d4a587b5988a2902ad116c27ea5ba9d726b6a06508bc48550576c2490ce1e35 \
>      --header 'accept: application/json' \
>      --header "x-apikey: $VIRUSTOTAL_API_KEY"
```
こんな感じのレスポンスになります
```json
{
    "error": {
        "message": "File \"3d4a587b5988a2902ad116c27ea5ba9d726b6a06508bc48550576c2490ce1e35\" not found",
        "code": "NotFoundError"
    }
}
```

この場合、ファイルをアップロードする`POST`の`files`APIがあります。
```bash
$ curl --request POST \
>      --url https://www.virustotal.com/api/v3/files \
>      --header 'accept: application/json' \
>      --header 'content-type: multipart/form-data' \
>      --header "x-apikey: $VIRUSTOTAL_API_KEY"\
>      -F file=@malicious.zip
```
結果にBase64っぽい検査IDが返ってきます
```json
{
    "data": {
        "type": "analysis",
        "id": "YjM3YjRkNGRiZTU1Y2Q2MjhkNTIyYjVmZGFmZDljMTI6MTY3NDQ5MTMzNQ=="
    }
}
```

余談ですが、Base64のなかみはファイルのmd5sumとタイムスタンプのようでした。
```bash
$ echo -ne "YjM3YjRkNGRiZTU1Y2Q2MjhkNTIyYjVmZGFmZDljMTI6MTY3NDQ5MTMzNQ==" | base64 -d
b37b4d4dbe55cd628d522b5fdafd9c12:1674491335
```

## 8. 新しいファイルの検査結果を確認する
`analyses`APIで結果を取得します。
```
curl --request GET \
     --url https://www.virustotal.com/api/v3/analyses/YjM3YjRkNGRiZTU1Y2Q2MjhkNTIyYjVmZGFmZDljMTI6MTY3NDQ5MTMzNQ== \
     --header 'accept: application/json' \
     --header "x-apikey: $VIRUSTOTAL_API_KEY"
```

# まとめ
怪しげなファイルの実体が手元にある状況はリスクが伴いますが、CloudShell環境とVirusTotalのAPIを使うことで、割と安全にファイルの状況を確認できました。