Last updated at Fri, 07 Apr 2023 20:33:03 GMT
I don't know about you, but in the past few weeks, my news feed has been abuzz with unicode domain names as phishing URLs. The use of unicode domain names is a version of a homograph attack applied using International Domain Names (IDN).
The underlying problem is that it’s difficult to visually distinguish some unicode characters from ASCII ones. Luckily, Chrome and Firefox have stopped converting domain names to unicode in the browser. But for those not on an updated browser, how will they avoid this trap? And will your security team catch this clever phishing trick?
Teams today analyze domain names all the time, but can they tell the difference between https://www.еріс.com for https://www.epic.com? Which one is the unicode domain and which is the ASCII? (Hint: the first url translates to https://www.еріс.com) This is a mistake made by even the most seasoned professionals, and can be costly.
To help our customers, and our own security team, we came up with a solution in Komand to facilitate the discovery of unicode phishing domains. This example will highlight just how fast and easy it is to build a plugin, and create an automated workflow.
Writing the IDNA Plugin to Translate Unicode Domains
Before we can even hop into Komand to build a workflow, we need a way to convert characters to and from punycode. Let’s write a plugin to do this!
First, we start with our plugin specification:
plugin_spec_version: v1
name: idna
title: "IDNA"
description: "Internationalized domain names for applications"
version: 1.0.0
vendor: komand
tags: ["idna", "domain", "punycode", "unicode"]
language: go
help: |
## About
IDNA handles converting between ASCII (punycode) and unicode domain names.
## Actions
### To Punycode
This action is used to convert a unicode domain name to ASCII (punycode).
#### Input
|Name|Type|Default|Required|Description|Enum|
|----|----|-------|--------|-----------|----|
|domain|string|None|True|Unicode domain name|None|
#### Output
|Name|Type|Required|Description|
|----|----|--------|-----------|
|domain|string|True|ASCII (punycode) domain name|
### To Unicode
This action is used to convert an ASCII (punycode) domain to unicode.
#### Input
|Name|Type|Default|Required|Description|Enum|
|----|----|-------|--------|-----------|----|
|domain|string|None|True|ASCII (punycode) domain name|None|
#### Output
|Name|Type|Required|Description|
|----|----|--------|-----------|
|domain|string|True|Unicode domain name|
## Triggers
There are no triggers associated with this plugin.
## Connection
There is no connection associated with this plugin.
## Troubleshooting
This plugin does not contain any troubleshooting information.
## References
* [Unicode IDN Utility](http://unicode.org/cldr/utility/idna.jsp)
* [Go IDNA Package](https://godoc.org/golang.org/x/net/idna)
actions:
to_ascii:
name: "To ASCII"
description: "To ASCII (punycode)"
input:
domain:
type: string
description: "Unicode domain name"
required: true
output:
domain:
type: string
description: "ASCII (punycode) domain name"
required: true
to_unicode:
description: "To Unicode"
input:
domain:
type: string
required: true
description: "ASCII (punycode) domain name"
output:
domain:
type: string
required: true
description: "Unicode domain name"
Next, we generate our plugin using the command:
./plugin-sdk-go --spec=specs/plugin.spec.idna.yaml --package=github.com/komand/plugins/idna
This will generate a directory structure like below:
├── Dockerfile
├── Makefile
├── actions
│ ├── to_ascii.go
│ ├── to_ascii_custom.go
│ ├── to_unicode.go
│ └── to_unicode_custom.go
├── cmd
│ └── main.go
├── connection
│ ├── cache.go
│ ├── connection.go
│ └── connection_custom.go
├── plugin.spec.yaml
├── server
│ └── http
│ ├── server.go
│ ├── to_ascii.go
│ └── to_unicode.go
├── types
│ └── sdk_file.go
Now we can fill out our actions. Since we are using Go, we will use the convenient idna package, and import it in our to_ascii_custom.go and to_unicode_custom.go files:
import "golang.org/x/net/idna"
In to_unicode_custom.go, we fill out our first run action. It calls ToUnicode
from the idna package and returns the resulting string. If it fails for some reason, we will return the error instead.
// Run will run the action with the given input over the given connection
func (a *ToUnicodeAction) Run(conn *connection.Connection, input *ToUnicodeInput, log plog.Logger) (*ToUnicodeOutput, error) {
domain, err := idna.ToUnicode(input.Domain)
if err != nil {
return nil, err
}
return &ToUnicodeOutput{
Domain: domain,
}, nil
}
In to_ascii_custom.go, we fill out our second run action, using the ToASCII
function from the idna package and returns the resulting string. If it fails for some reason, we will return the error instead.
// Run will run the action with the given input over the given connection
func (a *ToASCIIAction) Run(conn *connection.Connection, input *ToASCIIInput, log plog.Logger) (*ToASCIIOutput, error) {
domain, err := idna.ToASCII(input.Domain)
if err != nil {
return nil, err
}
return &ToASCIIOutput{
Domain: domain,
}, nil
}
Save both these files, and our newly minted plugin is ready to be imported into Komand! You can see the plugin here on Komunity. Now onto the next phase: adding a unicode enrichment step in our workflows.
Automating Unicode Domain Enrichment in Komand
A common use case for this plugin would be during a phishing email investigation. Security teams already investigate a slew of supsicious emails and links, and with our new IDNA plugin, we can add another enrichment step to be automated. Let's take a look at what that looks like below.
STEP 1 Adding a Loop
Because we will be passing over a list of domains, we'll want to create a loop to repeat over every item within the list. In this step, we select the variable Enrich URLs.urls
to repeat over. This will create an $item
variable to represent each individual item in the array that we'll use in our loop.
STEP 2 Translating to ASCII
Now comes the fun part: adding the step to translate any domains to ASCII. We will select IDNA as our plugin, and we will configure input of this step using our [Loop over URLs].$item
variable from the loop.
STEP 3 Creating Artifacts
Once we translate any domains, we'll want to create artifacts to show a nice, formatted view of the previous step's output(s). We'll use the [Loop over URLs].$item.domain
variable within the output. This will generate a single markdown artifact card for each translated domain.
STEP 4 Testing Our Workflow
Now that we've got the enrichment step in place, and an artifact(s) in place to generate, we can move into testing. In this example, I simply used a unicode domain and an ASCII domain as test data. As you'll see below, while they visually look the same in the right panel, the artifacts on the left tell a different story.
Conclusion
You’ll never know when clever attacks like these will arise, so it’s crucial to be able to prevent, detect, or launch a response as soon as possible. With Komand, I was able to write a plugin, add a few steps to a workflow, and test everything in 20 minutes. This solution can also be applied to other use cases, furthering the flexibility and power of the plugin we created in no time flat.
If you're interested in seeing Komand in action, you can download a recording from our recent demo webinar. Download here.